非ASCIIなドメインへのメンションの修正 (#2903)
* punycodeでされたmentionのラベルをunicodeとして表示する * post-form mentionはpunycodeにする * mentionの表示はURLもAPI向けもunicodeにする
This commit is contained in:
		| @@ -116,16 +116,16 @@ export default Vue.component('misskey-flavored-markdown', { | ||||
| 				case 'mention': { | ||||
| 					return (createElement as any)('a', { | ||||
| 						attrs: { | ||||
| 							href: `${url}/@${getAcct(token)}`, | ||||
| 							href: `${url}/${token.canonical}`, | ||||
| 							target: '_blank', | ||||
| 							dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token), | ||||
| 							style: 'color:var(--mfmMention);' | ||||
| 						}, | ||||
| 						directives: [{ | ||||
| 							name: 'user-preview', | ||||
| 							value: token.content | ||||
| 							value: token.canonical | ||||
| 						}] | ||||
| 					}, token.content); | ||||
| 					}, token.canonical); | ||||
| 				} | ||||
|  | ||||
| 				case 'hashtag': { | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| import * as getCaretCoordinates from 'textarea-caret'; | ||||
| import MkAutocomplete from '../components/autocomplete.vue'; | ||||
| import renderAcct from '../../../../../misc/acct/render'; | ||||
| import { toASCII } from 'punycode'; | ||||
|  | ||||
| export default { | ||||
| 	bind(el, binding, vn) { | ||||
| @@ -188,7 +188,7 @@ class Autocomplete { | ||||
| 			const trimmedBefore = before.substring(0, before.lastIndexOf('@')); | ||||
| 			const after = source.substr(caret); | ||||
|  | ||||
| 			const acct = renderAcct(value); | ||||
| 			const acct = value.host === null ? value.username : `${value.username}@${toASCII(value.host)}`; | ||||
|  | ||||
| 			// 挿入 | ||||
| 			this.text = `${trimmedBefore}@${acct} ${after}`; | ||||
|   | ||||
| @@ -65,6 +65,7 @@ import { host } from '../../../config'; | ||||
| import { erase, unique } from '../../../../../prelude/array'; | ||||
| import { length } from 'stringz'; | ||||
| import parseAcct from '../../../../../misc/acct/parse'; | ||||
| import { toASCII } from 'punycode'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| @@ -158,14 +159,14 @@ export default Vue.extend({ | ||||
| 		} | ||||
|  | ||||
| 		if (this.reply && this.reply.user.host != null) { | ||||
| 			this.text = `@${this.reply.user.username}@${this.reply.user.host} `; | ||||
| 			this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `; | ||||
| 		} | ||||
|  | ||||
| 		if (this.reply && this.reply.text != null) { | ||||
| 			const ast = parse(this.reply.text); | ||||
|  | ||||
| 			ast.filter(t => t.type == 'mention').forEach(x => { | ||||
| 				const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`; | ||||
| 				const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`; | ||||
|  | ||||
| 				// 自分は除外 | ||||
| 				if (this.$store.state.i.username == x.username && x.host == null) return; | ||||
|   | ||||
| @@ -62,6 +62,7 @@ import { host } from '../../../config'; | ||||
| import { erase, unique } from '../../../../../prelude/array'; | ||||
| import { length } from 'stringz'; | ||||
| import parseAcct from '../../../../../misc/acct/parse'; | ||||
| import { toASCII } from 'punycode'; | ||||
|  | ||||
| export default Vue.extend({ | ||||
| 	components: { | ||||
| @@ -153,14 +154,14 @@ export default Vue.extend({ | ||||
| 		} | ||||
|  | ||||
| 		if (this.reply && this.reply.user.host != null) { | ||||
| 			this.text = `@${this.reply.user.username}@${this.reply.user.host} `; | ||||
| 			this.text = `@${this.reply.user.username}@${toASCII(this.reply.user.host)} `; | ||||
| 		} | ||||
|  | ||||
| 		if (this.reply && this.reply.text != null) { | ||||
| 			const ast = parse(this.reply.text); | ||||
|  | ||||
| 			ast.filter(t => t.type == 'mention').forEach(x => { | ||||
| 				const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`; | ||||
| 				const mention = x.host ? `@${x.username}@${toASCII(x.host)}` : `@${x.username}`; | ||||
|  | ||||
| 				// 自分は除外 | ||||
| 				if (this.$store.state.i.username == x.username && x.host == null) return; | ||||
|   | ||||
| @@ -2,10 +2,12 @@ | ||||
|  * Mention | ||||
|  */ | ||||
| import parseAcct from '../../../misc/acct/parse'; | ||||
| import { toUnicode } from 'punycode'; | ||||
|  | ||||
| export type TextElementMention = { | ||||
| 	type: 'mention' | ||||
| 	content: string | ||||
| 	canonical: string | ||||
| 	username: string | ||||
| 	host: string | ||||
| }; | ||||
| @@ -15,9 +17,11 @@ export default function(text: string) { | ||||
| 	if (!match) return null; | ||||
| 	const mention = match[0]; | ||||
| 	const { username, host } = parseAcct(mention.substr(1)); | ||||
| 	const canonical = host != null ? `@${username}@${toUnicode(host)}` : mention; | ||||
| 	return { | ||||
| 		type: 'mention', | ||||
| 		content: mention, | ||||
| 		canonical, | ||||
| 		username, | ||||
| 		host | ||||
| 	} as TextElementMention; | ||||
|   | ||||
							
								
								
									
										16
									
								
								test/mfm.ts
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								test/mfm.ts
									
									
									
									
									
								
							| @@ -8,9 +8,9 @@ describe('Text', () => { | ||||
| 	it('can be analyzed', () => { | ||||
| 		const tokens = analyze('@himawari @hima_sub@namori.net お腹ペコい :cat: #yryr'); | ||||
| 		assert.deepEqual([ | ||||
| 			{ type: 'mention', content: '@himawari', username: 'himawari', host: null }, | ||||
| 			{ type: 'mention', content: '@himawari', canonical: '@himawari', username: 'himawari', host: null }, | ||||
| 			{ type: 'text', content: ' '}, | ||||
| 			{ type: 'mention', content: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }, | ||||
| 			{ type: 'mention', content: '@hima_sub@namori.net', canonical: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }, | ||||
| 			{ type: 'text', content: ' お腹ペコい ' }, | ||||
| 			{ type: 'emoji', content: ':cat:', emoji: 'cat'}, | ||||
| 			{ type: 'text', content: ' '}, | ||||
| @@ -58,7 +58,7 @@ describe('Text', () => { | ||||
| 			it('local', () => { | ||||
| 				const tokens = analyze('@himawari お腹ペコい'); | ||||
| 				assert.deepEqual([ | ||||
| 					{ type: 'mention', content: '@himawari', username: 'himawari', host: null }, | ||||
| 					{ type: 'mention', content: '@himawari', canonical: '@himawari', username: 'himawari', host: null }, | ||||
| 					{ type: 'text', content: ' お腹ペコい' } | ||||
| 				], tokens); | ||||
| 			}); | ||||
| @@ -66,7 +66,15 @@ describe('Text', () => { | ||||
| 			it('remote', () => { | ||||
| 				const tokens = analyze('@hima_sub@namori.net お腹ペコい'); | ||||
| 				assert.deepEqual([ | ||||
| 					{ type: 'mention', content: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }, | ||||
| 					{ type: 'mention', content: '@hima_sub@namori.net', canonical: '@hima_sub@namori.net', username: 'hima_sub', host: 'namori.net' }, | ||||
| 					{ type: 'text', content: ' お腹ペコい' } | ||||
| 				], tokens); | ||||
| 			}); | ||||
|  | ||||
| 			it('remote punycode', () => { | ||||
| 				const tokens = analyze('@hima_sub@xn--q9j5bya.xn--zckzah お腹ペコい'); | ||||
| 				assert.deepEqual([ | ||||
| 					{ type: 'mention', content: '@hima_sub@xn--q9j5bya.xn--zckzah', canonical: '@hima_sub@なもり.テスト', username: 'hima_sub', host: 'xn--q9j5bya.xn--zckzah' }, | ||||
| 					{ type: 'text', content: ' お腹ペコい' } | ||||
| 				], tokens); | ||||
| 			}); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 MeiMei
					MeiMei