From 892cb44d8439368fbad07e6863c157f87f6cef95 Mon Sep 17 00:00:00 2001 From: syuilo <Syuilotan@yahoo.co.jp> Date: Mon, 10 Feb 2020 02:59:00 +0900 Subject: [PATCH] Resolve #3644 --- src/client/components/url-preview-popup.vue | 55 +++++++++++++++++++++ src/client/components/url.vue | 50 ++++++++++++++++++- 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 src/client/components/url-preview-popup.vue diff --git a/src/client/components/url-preview-popup.vue b/src/client/components/url-preview-popup.vue new file mode 100644 index 0000000000..fd127c873c --- /dev/null +++ b/src/client/components/url-preview-popup.vue @@ -0,0 +1,55 @@ +<template> +<div class="fgmtyycl _panel" :style="{ top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }"> + <x-url-preview :url="url" style="width: 600px;"/> +</div> +</template> + +<script lang="ts"> +import Vue from 'vue'; +import i18n from '../i18n'; +import XUrlPreview from './url-preview.vue'; + +export default Vue.extend({ + i18n, + + components: { + XUrlPreview + }, + + props: { + url: { + type: String, + required: true + }, + source: { + required: true + } + }, + + data() { + return { + u: null, + top: 0, + left: 0, + }; + }, + + mounted() { + const rect = this.source.getBoundingClientRect(); + const x = ((rect.left + (this.source.offsetWidth / 2)) - (300 / 2)) + window.pageXOffset; + const y = rect.top + this.source.offsetHeight + window.pageYOffset; + + this.top = y; + this.left = x; + }, +}); +</script> + +<style lang="scss" scoped> +.fgmtyycl { + position: absolute; + z-index: 11000; + //width: 300px; + overflow: hidden; +} +</style> diff --git a/src/client/components/url.vue b/src/client/components/url.vue index 219921558c..b8dbacc6de 100644 --- a/src/client/components/url.vue +++ b/src/client/components/url.vue @@ -1,5 +1,8 @@ <template> -<component :is="hasRoute ? 'router-link' : 'a'" class="ieqqeuvs _link" :[attr]="hasRoute ? url.substr(local.length) : url" :rel="rel" :target="target"> +<component :is="hasRoute ? 'router-link' : 'a'" class="ieqqeuvs _link" :[attr]="hasRoute ? url.substr(local.length) : url" :rel="rel" :target="target" + @mouseover="onMouseover" + @mouseleave="onMouseleave" +> <template v-if="!self"> <span class="schema">{{ schema }}//</span> <span class="hostname">{{ hostname }}</span> @@ -20,6 +23,7 @@ import Vue from 'vue'; import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons'; import { toUnicode as decodePunycode } from 'punycode'; import { url as local } from '../config'; +import XUrlPreview from './url-preview-popup.vue'; export default Vue.extend({ props: { @@ -51,6 +55,9 @@ export default Vue.extend({ hasRoute: hasRoute, attr: hasRoute ? 'to' : 'href', target: hasRoute ? null : '_blank', + showTimer: null, + hideTimer: null, + preview: null, faExternalLinkSquareAlt }; }, @@ -62,6 +69,47 @@ export default Vue.extend({ this.pathname = decodeURIComponent(url.pathname); this.query = decodeURIComponent(url.search); this.hash = decodeURIComponent(url.hash); + }, + methods: { + showPreview() { + if (!document.body.contains(this.$el)) return; + if (this.preview) return; + + this.preview = new XUrlPreview({ + parent: this, + propsData: { + url: this.url, + source: this.$el + } + }).$mount(); + + this.preview.$on('mouseover', () => { + clearTimeout(this.hideTimer); + }); + + this.preview.$on('mouseleave', () => { + clearTimeout(this.showTimer); + this.hideTimer = setTimeout(this.closePreview, 500); + }); + + document.body.appendChild(this.preview.$el); + }, + closePreview() { + if (this.preview) { + this.preview.destroyDom(); + this.preview = null; + } + }, + onMouseover() { + clearTimeout(this.showTimer); + clearTimeout(this.hideTimer); + this.showTimer = setTimeout(this.showPreview, 500); + }, + onMouseleave() { + clearTimeout(this.showTimer); + clearTimeout(this.hideTimer); + this.hideTimer = setTimeout(this.closePreview, 500); + } } }); </script>