Improve mfm link
This commit is contained in:
		
							parent
							
								
									8df7864064
								
							
						
					
					
						commit
						1a5f385eb5
					
				
					 2 changed files with 100 additions and 7 deletions
				
			
		
							
								
								
									
										94
									
								
								src/client/components/link.vue
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/client/components/link.vue
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
<template>
 | 
			
		||||
<component :is="hasRoute ? 'router-link' : 'a'" class="xlcxczvw _link" :[attr]="hasRoute ? url.substr(local.length) : url" :rel="rel" :target="target"
 | 
			
		||||
	@mouseover="onMouseover"
 | 
			
		||||
	@mouseleave="onMouseleave"
 | 
			
		||||
	:title="url"
 | 
			
		||||
>
 | 
			
		||||
	<slot></slot>
 | 
			
		||||
	<fa :icon="faExternalLinkSquareAlt" v-if="target === '_blank'" class="icon"/>
 | 
			
		||||
</component>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { url as local } from '../config';
 | 
			
		||||
import XUrlPreview from './url-preview-popup.vue';
 | 
			
		||||
 | 
			
		||||
export default Vue.extend({
 | 
			
		||||
	props: {
 | 
			
		||||
		url: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true,
 | 
			
		||||
		},
 | 
			
		||||
		rel: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		const isSelf = this.url.startsWith(local);
 | 
			
		||||
		const hasRoute = isSelf && (
 | 
			
		||||
			(this.url.substr(local.length) === '/') ||
 | 
			
		||||
			this.url.substr(local.length).startsWith('/@') ||
 | 
			
		||||
			this.url.substr(local.length).startsWith('/notes/') ||
 | 
			
		||||
			this.url.substr(local.length).startsWith('/tags/'));
 | 
			
		||||
		return {
 | 
			
		||||
			local,
 | 
			
		||||
			self: isSelf,
 | 
			
		||||
			hasRoute: hasRoute,
 | 
			
		||||
			attr: hasRoute ? 'to' : 'href',
 | 
			
		||||
			target: hasRoute ? null : '_blank',
 | 
			
		||||
			showTimer: null,
 | 
			
		||||
			hideTimer: null,
 | 
			
		||||
			preview: null,
 | 
			
		||||
			faExternalLinkSquareAlt
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	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();
 | 
			
		||||
 | 
			
		||||
			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>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.xlcxczvw {
 | 
			
		||||
	word-break: break-all;
 | 
			
		||||
 | 
			
		||||
	> .icon {
 | 
			
		||||
		padding-left: 2px;
 | 
			
		||||
		font-size: .9em;
 | 
			
		||||
		font-weight: 400;
 | 
			
		||||
		font-style: normal;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -2,6 +2,7 @@ import Vue, { VNode } from 'vue';
 | 
			
		|||
import { MfmForest } from '../../mfm/types';
 | 
			
		||||
import { parse, parsePlain } from '../../mfm/parse';
 | 
			
		||||
import MkUrl from './url.vue';
 | 
			
		||||
import MkLink from './link.vue';
 | 
			
		||||
import MkMention from './mention.vue';
 | 
			
		||||
import { concat } from '../../prelude/array';
 | 
			
		||||
import MkFormula from './formula.vue';
 | 
			
		||||
| 
						 | 
				
			
			@ -158,14 +159,12 @@ export default Vue.component('misskey-flavored-markdown', {
 | 
			
		|||
				}
 | 
			
		||||
 | 
			
		||||
				case 'link': {
 | 
			
		||||
					return [createElement('a', {
 | 
			
		||||
						attrs: {
 | 
			
		||||
							class: 'link _link',
 | 
			
		||||
							href: token.node.props.url,
 | 
			
		||||
					return [createElement(MkLink, {
 | 
			
		||||
						key: Math.random(),
 | 
			
		||||
						props: {
 | 
			
		||||
							url: token.node.props.url,
 | 
			
		||||
							rel: 'nofollow noopener',
 | 
			
		||||
							target: '_blank',
 | 
			
		||||
							title: token.node.props.url,
 | 
			
		||||
						}
 | 
			
		||||
						},
 | 
			
		||||
					}, genEl(token.children))];
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue