Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Add a fallback for broken provider image #1493

Merged
merged 6 commits into from
Jun 28, 2022
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 36 additions & 26 deletions src/components/VAllResultsGrid/VImageCellSquare.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
>
<figure
itemprop="image"
itemscope=""
itemscope
itemtype="https://schema.org/ImageObject"
class="aspect-square relative rounded-sm"
>
Expand All @@ -16,11 +16,11 @@
class="w-full h-full object-cover rounded-sm bg-dark-charcoal-10 text-dark-charcoal-10"
loading="lazy"
:alt="image.title"
:src="getImageUrl(image)"
:src="getImageUrl()"
:width="250"
:height="250"
itemprop="thumbnailUrl"
@error="onImageLoadError($event, image)"
@error="onImageLoadError($event)"
/>
<figcaption
class="absolute left-0 bottom-0 invisible group-hover:visible group-focus:visible bg-white p-1 text-dark-charcoal"
Expand All @@ -32,44 +32,54 @@
</VLink>
</template>

<script>
<script lang="ts">
import { defineComponent, PropType } from '@nuxtjs/composition-api'

import type { ImageDetail } from '~/models/media'

import VLink from '~/components/VLink.vue'
import VLicense from '~/components/VLicense/VLicense.vue'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const errorImage = require('~/assets/image_not_available_placeholder.png')
import errorImage from '~/assets/image_not_available_placeholder.png'

const toAbsolutePath = (url, prefix = 'https://') => {
const toAbsolutePath = (url: string, prefix = 'https://') => {
if (url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0) {
return url
}
return `${prefix}${url}`
}

export default {
export default defineComponent({
name: 'VImageCell',
components: { VLink, VLicense },
props: ['image'],
methods: {
getImageUrl(image) {
if (!image) return ''
const url = image.thumbnail || image.url
return toAbsolutePath(url)
props: {
image: {
type: Object as PropType<ImageDetail>,
required: true,
},
getImageForeignUrl(image) {
return toAbsolutePath(image.foreign_landing_url)
},
onImageLoadError(event, image) {
const element = event.target
if (element.src !== image.url) {
element.src = image.url
},
setup(props) {
const getImageUrl = () => {
if (!props.image) return ''
const url = props.image.thumbnail || props.image.url
return toAbsolutePath(url)
}
const getImageForeignUrl = () =>
toAbsolutePath(props.image.foreign_landing_url)

const onImageLoadError = (event: Event) => {
const element = event.target as HTMLImageElement
if (element.src !== props.image.url) {
element.src = props.image.url
} else {
element.src = errorImage
}
},
onFocusLeave(event) {
this.$emit('focus-leave', event)
},
}
return {
getImageUrl,
getImageForeignUrl,
onImageLoadError,
}
},
}
})
</script>
187 changes: 105 additions & 82 deletions src/components/VImageGrid/VImageCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,20 @@
:href="'/image/' + image.id"
class="w-full block group relative overflow-hidden rounded-sm focus:ring-[3px] focus:ring-pink focus:ring-offset-[3px] focus:outline-none bg-dark-charcoal-10 text-dark-charcoal-10"
:aria-label="image.title"
:style="`width: ${containerAspect * widthBasis}px;flex-grow: ${
containerAspect * widthBasis
}`"
@click="onGotoDetailPage($event, image)"
:style="containerStyle"
@keydown.native.shift.tab.exact="$emit('shift-tab', $event)"
>
<figure
class="absolute w-full"
:style="`width: ${imageWidth}%; top: ${imageTop}%; left:${imageLeft}%;`"
>
<figure class="absolute w-full" :style="figureStyle">
<img
ref="img"
loading="lazy"
class="margin-auto block w-full"
:alt="image.title"
:src="getImageUrl(image)"
:src="imageUrl"
:width="imgWidth"
:height="imgHeight"
@load="getImgDimension"
@error="onImageLoadError($event, image)"
@error="onImageLoadError($event)"
/>
<figcaption
class="absolute left-0 bottom-0 invisible group-hover:visible group-focus:visible bg-white p-1 text-dark-charcoal"
Expand All @@ -35,101 +29,130 @@
</VLink>
</template>

<script>
<script lang="ts">
import {
computed,
defineComponent,
PropType,
ref,
} from '@nuxtjs/composition-api'

import type { ImageDetail } from '~/models/media'

import VLicense from '~/components/VLicense/VLicense.vue'
import VLink from '~/components/VLink.vue'

// eslint-disable-next-line @typescript-eslint/no-var-requires
const errorImage = require('~/assets/image_not_available_placeholder.png')
import errorImage from '~/assets/image_not_available_placeholder.png'

const minAspect = 3 / 4
const maxAspect = 16 / 9
const panaromaAspect = 21 / 9
const panoramaAspect = 21 / 9
const minRowWidth = 450
const widthBasis = minRowWidth / maxAspect

const toAbsolutePath = (url, prefix = 'https://') => {
const toAbsolutePath = (url: string, prefix = 'https://') => {
if (url.indexOf('http://') >= 0 || url.indexOf('https://') >= 0) {
return url
}
return `${prefix}${url}`
}

export default {
export default defineComponent({
name: 'VImageCell',
components: { VLicense, VLink },
props: ['image'],
data() {
return {
widthBasis: minRowWidth / maxAspect,
imgHeight: this.image.height || 100,
imgWidth: this.image.width || 100,
}
},
computed: {
imageAspect() {
return this.imgWidth / this.imgHeight
props: {
image: {
type: Object as PropType<ImageDetail>,
required: true,
},
containerAspect() {
if (this.imageAspect > maxAspect) return maxAspect
if (this.imageAspect < minAspect) return minAspect
return this.imageAspect
},
iPadding() {
if (this.imageAspect < minAspect) return (1 / minAspect) * 100
if (this.imageAspect > maxAspect) return (1 / maxAspect) * 100
return (1 / this.imageAspect) * 100
},
imageWidth() {
if (this.imageAspect < maxAspect) return 100
return (this.imageAspect / maxAspect) * 100
},
imageTop() {
if (this.imageAspect > minAspect) return 0
},
setup(props) {
const imgHeight = ref(props.image.height || 100)
const imgWidth = ref(props.image.width || 100)

const imageAspect = computed(() => imgWidth.value / imgHeight.value)

const containerAspect = computed(() => {
if (imageAspect.value > maxAspect) return maxAspect
if (imageAspect.value < minAspect) return minAspect
return imageAspect.value
})
const iPadding = computed(() => {
if (imageAspect.value < minAspect) return (1 / minAspect) * 100
if (imageAspect.value > maxAspect) return (1 / maxAspect) * 100
return (1 / imageAspect.value) * 100
})
const imageWidth = computed(() => {
if (imageAspect.value < maxAspect) return 100
return (imageAspect.value / maxAspect) * 100
})
const imageTop = computed(() => {
if (imageAspect.value > minAspect) return 0
return (
((minAspect - this.imageAspect) /
(this.imageAspect * minAspect * minAspect)) *
((minAspect - imageAspect.value) /
(imageAspect.value * minAspect * minAspect)) *
-50
)
},
imageLeft() {
if (this.imageAspect < maxAspect) return 0
return ((this.imageAspect - maxAspect) / maxAspect) * -50
},
},
methods: {
getImageUrl(image) {
if (!image) {
return ''
}
const url = image.thumbnail || image.url
if (this.imageAspect > panaromaAspect) return toAbsolutePath(url)
})
const imageLeft = computed(() => {
if (imageAspect.value < maxAspect) return 0
return ((imageAspect.value - maxAspect) / maxAspect) * -50
})

const imageUrl = computed(() => {
// TODO: check if we have blurry panorama thumbnails
// fix for blurry panorama thumbnails, introduced in
// https://github.com/cc-archive/cccatalog-frontend/commit/4c9bdac5
if (imageAspect.value > panoramaAspect)
return toAbsolutePath(props.image.url)
const url = props.image.thumbnail || props.image.url
return toAbsolutePath(url)
},
getImageForeignUrl(image) {
return toAbsolutePath(image.foreign_landing_url)
},
onGotoDetailPage(event, image) {
if (!event.metaKey && !event.ctrlKey) {
event.preventDefault()
const detailRoute = this.localeRoute({
name: 'PhotoDetailPage',
params: { id: image.id, location: window.scrollY },
})
this.$router.push(detailRoute)
}
},
onImageLoadError(event, image) {
const element = event.target
if (element.src !== image.url) {
element.src = image.url
})

const getImageForeignUrl = () =>
toAbsolutePath(props.image.foreign_landing_url)

/**
* If the thumbnail fails to load, try replacing it with the original image URL.
* If the original image fails, too, use the error image placeholder.
* @param event - the error event.
*/
const onImageLoadError = (event: Event) => {
const element = event.target as HTMLImageElement
if (element.src !== props.image.url) {
element.src = props.image.url
} else {
element.src = errorImage
}
},
getImgDimension(e) {
this.imgHeight = e.target.naturalHeight
this.imgWidth = e.target.naturalWidth
},
}
const getImgDimension = (event: Event) => {
const element = event.target as HTMLImageElement
imgHeight.value = element.naturalHeight
imgWidth.value = element.naturalWidth
}

const containerStyle = computed(() => {
const containerWidth = containerAspect.value * widthBasis
return `width: ${containerWidth}px;flex-grow: ${containerWidth}`
})

const figureStyle = computed(
() =>
`width: ${imageWidth.value}%; top: ${imageTop.value}%; left:${imageLeft.value}%;`
)

return {
imgHeight,
imgWidth,
containerStyle,
figureStyle,
iPadding,
imageUrl,

getImageForeignUrl,
onImageLoadError,
getImgDimension,
}
},
}
})
</script>
10 changes: 5 additions & 5 deletions src/locales/po-files/openverse.pot
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Openverse \n"
"Report-Msgid-Bugs-To: https://github.com/wordpress/openverse/issues \n"
"POT-Creation-Date: 2022-05-24T15:12:45+00:00\n"
"POT-Creation-Date: 2022-06-08T09:58:52+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
Expand Down Expand Up @@ -463,12 +463,12 @@ msgid "Genre"
msgstr ""

#. Do not translate words between ### ###.
#: src/pages/image/_id.vue:44
#: src/pages/image/_id.vue:45
msgctxt "image-details.creator"
msgid "by ###name###"
msgstr ""

#: src/pages/image/_id.vue:38
#: src/pages/image/_id.vue:39
msgctxt "image-details.weblink"
msgid "Go to image's website"
msgstr ""
Expand Down Expand Up @@ -650,7 +650,7 @@ msgid "Open form"
msgstr ""

#. Do not translate words between ### ###.
#: src/pages/image/_id.vue:54
#: src/pages/image/_id.vue:55
msgctxt "media-details.aria.creator-url"
msgid "author ###name###"
msgstr ""
Expand Down Expand Up @@ -1191,7 +1191,7 @@ msgid "An error occurred"
msgstr ""

#. Do not translate words between ### ###.
#: src/pages/image/_id.vue:196
#: src/pages/image/_id.vue:225
msgctxt "error.image-not-found"
msgid "Couldn't find image with id ###id###"
msgstr ""
Expand Down
Loading