2018-07-10 11:57:11 +00:00
|
|
|
<template>
|
2018-07-10 14:44:50 +00:00
|
|
|
<div
|
2018-07-12 14:38:35 +00:00
|
|
|
v-if="link.shown"
|
|
|
|
v-show="link.canDisplay"
|
2018-07-12 08:26:12 +00:00
|
|
|
ref="container"
|
2019-02-25 05:38:13 +00:00
|
|
|
class="preview"
|
|
|
|
>
|
2018-07-12 08:26:12 +00:00
|
|
|
<div
|
|
|
|
ref="content"
|
2019-02-25 05:38:13 +00:00
|
|
|
:class="['toggle-content', 'toggle-type-' + link.type, { opened: isContentShown }]"
|
|
|
|
>
|
2018-07-10 11:57:11 +00:00
|
|
|
<template v-if="link.type === 'link'">
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
v-if="link.thumb"
|
|
|
|
:href="link.link"
|
|
|
|
class="toggle-thumbnail"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>
|
2018-07-10 12:04:25 +00:00
|
|
|
<img
|
|
|
|
:src="link.thumb"
|
|
|
|
decoding="async"
|
|
|
|
alt=""
|
2018-07-10 14:44:50 +00:00
|
|
|
class="thumb"
|
2018-07-12 14:38:35 +00:00
|
|
|
@error="onThumbnailError"
|
|
|
|
@abort="onThumbnailError"
|
2019-02-25 05:38:13 +00:00
|
|
|
@load="onPreviewReady"
|
|
|
|
>
|
2018-07-10 11:57:11 +00:00
|
|
|
</a>
|
|
|
|
<div class="toggle-text">
|
|
|
|
<div class="head">
|
|
|
|
<div class="overflowable">
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
:href="link.link"
|
|
|
|
:title="link.head"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>{{ link.head }}</a>
|
2018-07-10 11:57:11 +00:00
|
|
|
</div>
|
|
|
|
|
2018-07-10 12:04:25 +00:00
|
|
|
<button
|
2018-07-12 08:26:12 +00:00
|
|
|
v-if="showMoreButton"
|
|
|
|
:aria-expanded="isContentShown"
|
|
|
|
:aria-label="moreButtonLabel"
|
2018-07-10 12:04:25 +00:00
|
|
|
class="more"
|
2019-02-25 05:38:13 +00:00
|
|
|
@click="onMoreClick"
|
|
|
|
><span class="more-caret" /></button>
|
2018-07-10 11:57:11 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="body overflowable">
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
:href="link.link"
|
|
|
|
:title="link.body"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>{{ link.body }}</a>
|
2018-07-10 11:57:11 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<template v-else-if="link.type === 'image'">
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
:href="link.link"
|
|
|
|
class="toggle-thumbnail"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>
|
2018-07-10 12:04:25 +00:00
|
|
|
<img
|
|
|
|
:src="link.thumb"
|
|
|
|
decoding="async"
|
2018-07-10 14:44:50 +00:00
|
|
|
alt=""
|
2019-02-25 05:38:13 +00:00
|
|
|
@load="onPreviewReady"
|
|
|
|
>
|
2018-07-10 11:57:11 +00:00
|
|
|
</a>
|
|
|
|
</template>
|
|
|
|
<template v-else-if="link.type === 'video'">
|
2018-07-10 12:04:25 +00:00
|
|
|
<video
|
|
|
|
preload="metadata"
|
2018-07-10 14:44:50 +00:00
|
|
|
controls
|
2019-02-25 05:38:13 +00:00
|
|
|
@canplay="onPreviewReady"
|
|
|
|
>
|
2018-07-10 12:04:25 +00:00
|
|
|
<source
|
|
|
|
:src="link.media"
|
2019-02-25 05:38:13 +00:00
|
|
|
:type="link.mediaType"
|
|
|
|
>
|
2018-07-10 11:57:11 +00:00
|
|
|
</video>
|
|
|
|
</template>
|
|
|
|
<template v-else-if="link.type === 'audio'">
|
2018-07-10 12:04:25 +00:00
|
|
|
<audio
|
|
|
|
controls
|
2018-07-10 14:44:50 +00:00
|
|
|
preload="metadata"
|
2019-02-25 05:38:13 +00:00
|
|
|
@canplay="onPreviewReady"
|
|
|
|
>
|
2018-07-10 12:04:25 +00:00
|
|
|
<source
|
|
|
|
:src="link.media"
|
2019-02-25 05:38:13 +00:00
|
|
|
:type="link.mediaType"
|
|
|
|
>
|
2018-07-10 11:57:11 +00:00
|
|
|
</audio>
|
|
|
|
</template>
|
|
|
|
<template v-else-if="link.type === 'error'">
|
|
|
|
<em v-if="link.error === 'image-too-big'">
|
2018-07-10 12:04:25 +00:00
|
|
|
This image is larger than {{ link.maxSize | friendlysize }} and cannot be
|
2018-07-10 11:57:11 +00:00
|
|
|
previewed.
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
:href="link.link"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>Click here</a>
|
2018-07-10 11:57:11 +00:00
|
|
|
to open it in a new window.
|
|
|
|
</em>
|
|
|
|
<template v-else-if="link.error === 'message'">
|
|
|
|
<div>
|
|
|
|
<em>
|
|
|
|
A preview could not be loaded.
|
2018-07-10 12:04:25 +00:00
|
|
|
<a
|
|
|
|
:href="link.link"
|
|
|
|
target="_blank"
|
2019-02-25 05:38:13 +00:00
|
|
|
rel="noopener"
|
|
|
|
>Click here</a>
|
2018-07-10 11:57:11 +00:00
|
|
|
to open it in a new window.
|
|
|
|
</em>
|
|
|
|
<br>
|
2018-07-10 12:04:25 +00:00
|
|
|
<pre class="prefetch-error">{{ link.message }}</pre>
|
2018-07-10 11:57:11 +00:00
|
|
|
</div>
|
|
|
|
|
2018-07-10 12:04:25 +00:00
|
|
|
<button
|
2018-07-12 08:26:12 +00:00
|
|
|
:aria-expanded="isContentShown"
|
|
|
|
:aria-label="moreButtonLabel"
|
2018-07-10 12:04:25 +00:00
|
|
|
class="more"
|
2019-02-25 05:38:13 +00:00
|
|
|
@click="onMoreClick"
|
|
|
|
><span class="more-caret" /></button>
|
2018-07-10 11:57:11 +00:00
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
|
|
|
name: "LinkPreview",
|
|
|
|
props: {
|
|
|
|
link: Object,
|
2018-07-13 10:43:11 +00:00
|
|
|
keepScrollPosition: Function,
|
2018-07-10 11:57:11 +00:00
|
|
|
},
|
2018-07-12 08:26:12 +00:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
showMoreButton: false,
|
|
|
|
isContentShown: false,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
moreButtonLabel() {
|
|
|
|
return this.isContentShown ? "Less" : "More";
|
|
|
|
},
|
|
|
|
},
|
2018-07-13 10:43:11 +00:00
|
|
|
watch: {
|
|
|
|
"link.type"() {
|
2018-10-01 14:08:46 +00:00
|
|
|
this.updateShownState();
|
2018-07-13 10:43:11 +00:00
|
|
|
this.onPreviewUpdate();
|
|
|
|
},
|
|
|
|
},
|
2018-09-24 10:39:02 +00:00
|
|
|
created() {
|
2018-10-01 14:08:46 +00:00
|
|
|
this.updateShownState();
|
2018-09-24 10:39:02 +00:00
|
|
|
},
|
2018-07-10 14:44:50 +00:00
|
|
|
mounted() {
|
2018-08-31 18:37:39 +00:00
|
|
|
this.$root.$on("resize", this.handleResize);
|
2018-08-31 18:15:46 +00:00
|
|
|
|
2018-07-13 10:43:11 +00:00
|
|
|
this.onPreviewUpdate();
|
2018-07-10 14:44:50 +00:00
|
|
|
},
|
2018-08-31 18:37:39 +00:00
|
|
|
beforeDestroy() {
|
|
|
|
this.$root.$off("resize", this.handleResize);
|
|
|
|
},
|
2018-07-13 20:03:36 +00:00
|
|
|
destroyed() {
|
|
|
|
// Let this preview go through load/canplay events again,
|
|
|
|
// Otherwise the browser can cause a resize on video elements
|
|
|
|
this.link.canDisplay = false;
|
|
|
|
},
|
2018-07-10 14:44:50 +00:00
|
|
|
methods: {
|
2018-07-13 10:43:11 +00:00
|
|
|
onPreviewUpdate() {
|
2018-09-24 10:41:56 +00:00
|
|
|
// Don't display previews while they are loading on the server
|
|
|
|
if (this.link.type === "loading") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-07-13 10:43:11 +00:00
|
|
|
// Error don't have any media to render
|
|
|
|
if (this.link.type === "error") {
|
|
|
|
this.onPreviewReady();
|
|
|
|
}
|
|
|
|
|
|
|
|
// If link doesn't have a thumbnail, render it
|
|
|
|
if (this.link.type === "link" && !this.link.thumb) {
|
|
|
|
this.onPreviewReady();
|
|
|
|
}
|
|
|
|
},
|
2018-07-10 14:44:50 +00:00
|
|
|
onPreviewReady() {
|
2018-09-24 10:39:02 +00:00
|
|
|
this.$set(this.link, "canDisplay", true);
|
2018-07-12 14:38:35 +00:00
|
|
|
|
2018-07-13 10:43:11 +00:00
|
|
|
this.keepScrollPosition();
|
2018-07-12 14:38:35 +00:00
|
|
|
|
|
|
|
if (this.link.type !== "link") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-31 18:15:46 +00:00
|
|
|
this.handleResize();
|
2018-07-12 14:38:35 +00:00
|
|
|
},
|
|
|
|
onThumbnailError() {
|
|
|
|
// If thumbnail fails to load, hide it and show the preview without it
|
|
|
|
this.link.thumb = "";
|
|
|
|
this.onPreviewReady();
|
2018-07-10 14:44:50 +00:00
|
|
|
},
|
2018-07-12 08:26:12 +00:00
|
|
|
onMoreClick() {
|
|
|
|
this.isContentShown = !this.isContentShown;
|
2018-07-25 11:04:10 +00:00
|
|
|
this.keepScrollPosition();
|
2018-07-12 08:26:12 +00:00
|
|
|
},
|
2018-08-31 18:15:46 +00:00
|
|
|
handleResize() {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
if (!this.$refs.content) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.showMoreButton = this.$refs.content.offsetWidth >= this.$refs.container.offsetWidth;
|
|
|
|
});
|
|
|
|
},
|
2018-10-01 14:08:46 +00:00
|
|
|
updateShownState() {
|
|
|
|
let defaultState = true;
|
|
|
|
|
|
|
|
switch (this.link.type) {
|
|
|
|
case "error":
|
|
|
|
defaultState = this.link.error === "image-too-big" ? this.$root.settings.media : this.$root.settings.links;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "loading":
|
|
|
|
defaultState = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case "link":
|
|
|
|
defaultState = this.$root.settings.links;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
defaultState = this.$root.settings.media;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.link.shown = this.link.shown && defaultState;
|
|
|
|
},
|
2018-07-10 14:44:50 +00:00
|
|
|
},
|
2018-07-10 11:57:11 +00:00
|
|
|
};
|
|
|
|
</script>
|