wip
This commit is contained in:
		@@ -1,48 +0,0 @@
 | 
			
		||||
declare const _URL_: string;
 | 
			
		||||
 | 
			
		||||
import * as riot from 'riot';
 | 
			
		||||
import * as pictograph from 'pictograph';
 | 
			
		||||
 | 
			
		||||
const escape = text =>
 | 
			
		||||
	text
 | 
			
		||||
		.replace(/>/g, '>')
 | 
			
		||||
		.replace(/</g, '<');
 | 
			
		||||
 | 
			
		||||
export default (tokens, shouldBreak) => {
 | 
			
		||||
	if (shouldBreak == null) {
 | 
			
		||||
		shouldBreak = true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	const me = (riot as any).mixin('i').me;
 | 
			
		||||
 | 
			
		||||
	let text = tokens.map(token => {
 | 
			
		||||
		switch (token.type) {
 | 
			
		||||
			case 'text':
 | 
			
		||||
				return escape(token.content)
 | 
			
		||||
					.replace(/(\r\n|\n|\r)/g, shouldBreak ? '<br>' : ' ');
 | 
			
		||||
			case 'bold':
 | 
			
		||||
				return `<strong>${escape(token.bold)}</strong>`;
 | 
			
		||||
			case 'url':
 | 
			
		||||
				return `<mk-url href="${escape(token.content)}" target="_blank"></mk-url>`;
 | 
			
		||||
			case 'link':
 | 
			
		||||
				return `<a class="link" href="${escape(token.url)}" target="_blank" title="${escape(token.url)}">${escape(token.title)}</a>`;
 | 
			
		||||
			case 'mention':
 | 
			
		||||
				return `<a href="${_URL_ + '/' + escape(token.username)}" target="_blank" data-user-preview="${token.content}" ${me && me.username == token.username ? 'data-is-me' : ''}>${token.content}</a>`;
 | 
			
		||||
			case 'hashtag': // TODO
 | 
			
		||||
				return `<a>${escape(token.content)}</a>`;
 | 
			
		||||
			case 'code':
 | 
			
		||||
				return `<pre><code>${token.html}</code></pre>`;
 | 
			
		||||
			case 'inline-code':
 | 
			
		||||
				return `<code>${token.html}</code>`;
 | 
			
		||||
			case 'emoji':
 | 
			
		||||
				return pictograph.dic[token.emoji] || token.content;
 | 
			
		||||
		}
 | 
			
		||||
	}).join('');
 | 
			
		||||
 | 
			
		||||
	// Remove needless whitespaces
 | 
			
		||||
	text = text
 | 
			
		||||
		.replace(/ <code>/g, '<code>').replace(/<\/code> /g, '</code>')
 | 
			
		||||
		.replace(/<br><code><pre>/g, '<code><pre>').replace(/<\/code><\/pre><br>/g, '</code></pre>');
 | 
			
		||||
 | 
			
		||||
	return text;
 | 
			
		||||
};
 | 
			
		||||
@@ -4,8 +4,10 @@ import signin from './signin.vue';
 | 
			
		||||
import signup from './signup.vue';
 | 
			
		||||
import forkit from './forkit.vue';
 | 
			
		||||
import nav from './nav.vue';
 | 
			
		||||
import postHtml from './post-html';
 | 
			
		||||
 | 
			
		||||
Vue.component('mk-signin', signin);
 | 
			
		||||
Vue.component('mk-signup', signup);
 | 
			
		||||
Vue.component('mk-forkit', forkit);
 | 
			
		||||
Vue.component('mk-nav', nav);
 | 
			
		||||
Vue.component('mk-post-html', postHtml);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										98
									
								
								src/web/app/common/views/components/post-html.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/web/app/common/views/components/post-html.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
declare const _URL_: string;
 | 
			
		||||
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import * as pictograph from 'pictograph';
 | 
			
		||||
 | 
			
		||||
import MkUrl from './url.vue';
 | 
			
		||||
 | 
			
		||||
const escape = text =>
 | 
			
		||||
	text
 | 
			
		||||
		.replace(/>/g, '>')
 | 
			
		||||
		.replace(/</g, '<');
 | 
			
		||||
 | 
			
		||||
export default Vue.component('mk-post-html', {
 | 
			
		||||
	props: {
 | 
			
		||||
		ast: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		shouldBreak: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			default: true
 | 
			
		||||
		},
 | 
			
		||||
		i: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: null
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	render(createElement) {
 | 
			
		||||
		const els = [].concat.apply([], (this as any).ast.map(token => {
 | 
			
		||||
			switch (token.type) {
 | 
			
		||||
				case 'text':
 | 
			
		||||
					const text = escape(token.content)
 | 
			
		||||
						.replace(/(\r\n|\n|\r)/g, '\n');
 | 
			
		||||
 | 
			
		||||
					if ((this as any).shouldBreak) {
 | 
			
		||||
						return text.split('\n').map(t => [createElement('span', t), createElement('br')]);
 | 
			
		||||
					} else {
 | 
			
		||||
						return createElement('span', text.replace(/\n/g, ' '));
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
				case 'bold':
 | 
			
		||||
					return createElement('strong', escape(token.bold));
 | 
			
		||||
 | 
			
		||||
				case 'url':
 | 
			
		||||
					return createElement(MkUrl, {
 | 
			
		||||
						props: {
 | 
			
		||||
							href: escape(token.content),
 | 
			
		||||
							target: '_blank'
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
 | 
			
		||||
				case 'link':
 | 
			
		||||
					return createElement('a', {
 | 
			
		||||
						attrs: {
 | 
			
		||||
							class: 'link',
 | 
			
		||||
							href: escape(token.url),
 | 
			
		||||
							target: '_blank',
 | 
			
		||||
							title: escape(token.url)
 | 
			
		||||
						}
 | 
			
		||||
					}, escape(token.title));
 | 
			
		||||
 | 
			
		||||
				case 'mention':
 | 
			
		||||
					return (createElement as any)('a', {
 | 
			
		||||
						attrs: {
 | 
			
		||||
							href: `${_URL_}/${escape(token.username)}`,
 | 
			
		||||
							target: '_blank',
 | 
			
		||||
							dataIsMe: (this as any).i && (this as any).i.username == token.username
 | 
			
		||||
						},
 | 
			
		||||
						directives: [{
 | 
			
		||||
							name: 'user-preview',
 | 
			
		||||
							value: token.content
 | 
			
		||||
						}]
 | 
			
		||||
					}, token.content);
 | 
			
		||||
 | 
			
		||||
				case 'hashtag':
 | 
			
		||||
					return createElement('a', {
 | 
			
		||||
						attrs: {
 | 
			
		||||
							href: `${_URL_}/search?q=${escape(token.content)}`,
 | 
			
		||||
							target: '_blank'
 | 
			
		||||
						}
 | 
			
		||||
					}, escape(token.content));
 | 
			
		||||
 | 
			
		||||
				case 'code':
 | 
			
		||||
					return createElement('pre', [
 | 
			
		||||
						createElement('code', token.html)
 | 
			
		||||
					]);
 | 
			
		||||
 | 
			
		||||
				case 'inline-code':
 | 
			
		||||
					return createElement('code', token.html);
 | 
			
		||||
 | 
			
		||||
				case 'emoji':
 | 
			
		||||
					return createElement('span', pictograph.dic[token.emoji] || token.content);
 | 
			
		||||
			}
 | 
			
		||||
		}));
 | 
			
		||||
 | 
			
		||||
		return createElement('div', els);
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
				<div class="text" ref="text">
 | 
			
		||||
					<p class="channel" v-if="p.channel"><a :href="`${_CH_URL_}/${p.channel.id}`" target="_blank">{{ p.channel.title }}</a>:</p>
 | 
			
		||||
					<a class="reply" v-if="p.reply">%fa:reply%</a>
 | 
			
		||||
					<p class="dummy"></p>
 | 
			
		||||
					<mk-post-html :ast="p.ast" :i="$root.$data.os.i"/>
 | 
			
		||||
					<a class="quote" v-if="p.repost">RP:</a>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div class="media" v-if="p.media">
 | 
			
		||||
@@ -94,7 +94,7 @@ export default Vue.extend({
 | 
			
		||||
			return this.isRepost ? this.post.repost : this.post;
 | 
			
		||||
		},
 | 
			
		||||
		reactionsCount(): number {
 | 
			
		||||
			return this.p.reaction_counts ? Object.keys(this.p.reaction_counts).map(key => this.p.reaction_counts[key]).reduce((a, b) => a + b) : 0;			
 | 
			
		||||
			return this.p.reaction_counts ? Object.keys(this.p.reaction_counts).map(key => this.p.reaction_counts[key]).reduce((a, b) => a + b) : 0;
 | 
			
		||||
		},
 | 
			
		||||
		title(): string {
 | 
			
		||||
			return dateStringify(this.p.created_at);
 | 
			
		||||
@@ -117,12 +117,6 @@ export default Vue.extend({
 | 
			
		||||
		if (this.p.text) {
 | 
			
		||||
			const tokens = this.p.ast;
 | 
			
		||||
 | 
			
		||||
			this.$refs.text.innerHTML = this.$refs.text.innerHTML.replace('<p class="dummy"></p>', compile(tokens));
 | 
			
		||||
 | 
			
		||||
			Array.from(this.$refs.text.children).forEach(e => {
 | 
			
		||||
				if (e.tagName == 'MK-URL') riot.mount(e);
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			// URLをプレビュー
 | 
			
		||||
			tokens
 | 
			
		||||
			.filter(t => (t.type == 'url' || t.type == 'link') && !t.silent)
 | 
			
		||||
 
 | 
			
		||||
@@ -7,7 +7,7 @@
 | 
			
		||||
	<footer data-yield="footer">
 | 
			
		||||
		<yield from="footer"/>
 | 
			
		||||
	</footer>
 | 
			
		||||
</div>	
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
@@ -31,7 +31,7 @@ export default Vue.extend({
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		focus() {
 | 
			
		||||
			this.$refs.root.children[0].focus();
 | 
			
		||||
			(this.$refs.root as any).children[0].focus();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import Vue from 'vue';
 | 
			
		||||
import anime from 'animejs';
 | 
			
		||||
import contains from '../../common/scripts/contains';
 | 
			
		||||
import contains from '../../../common/scripts/contains';
 | 
			
		||||
 | 
			
		||||
const minHeight = 40;
 | 
			
		||||
const minWidth = 200;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user