From 65961bc15ba33151e6a2ac6da84c33e2af330af0 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 19:20:35 +0900 Subject: [PATCH] =?UTF-8?q?Refactoring=20&=20=E8=A8=AD=E5=AE=9A=E3=81=A7Tw?= =?UTF-8?q?emoji=E3=82=92=E4=BD=BF=E3=81=86=E3=81=8B=E3=81=A9=E3=81=86?= =?UTF-8?q?=E3=81=8B=E5=88=87=E3=82=8A=E6=9B=BF=E3=81=88=E3=82=89=E3=82=8C?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/ja-JP.yml | 1 + .../common/views/components/autocomplete.vue | 18 +++-- .../app/common/views/components/emoji.vue | 74 ++++++++++++------- .../components/misskey-flavored-markdown.ts | 4 +- .../common/views/directives/autocomplete.ts | 1 + .../app/desktop/views/components/settings.vue | 6 ++ .../app/mobile/views/pages/settings.vue | 6 ++ src/client/app/store.ts | 3 +- src/mfm/parse/elements/emoji.ts | 21 +++--- .../activitypub/misc/get-emoji-names.ts | 2 +- src/remote/activitypub/renderer/note.ts | 5 +- src/services/note/create.ts | 4 +- test/mfm.ts | 8 +- 13 files changed, 95 insertions(+), 58 deletions(-) diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 10d566fc3..f8298c301 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -131,6 +131,7 @@ common: show-full-acct: "ユーザー名のホストを省略しない" reduce-motion: "UIの動きを減らす" this-setting-is-this-device-only: "このデバイスのみ" + use-os-default-emojis: "OS標準の絵文字を使用" do-not-use-in-production: 'これは開発ビルドです。本番環境で使用しないでください。' diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index dff0bfd8d..4cf44a23a 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -14,7 +14,8 @@
  1. - + + {{ emoji.emoji }} ({{ emoji.aliasOf }}) @@ -33,6 +34,7 @@ type EmojiDef = { name: string; aliasOf?: string; url?: string; + isCustomEmoji?: boolean; }; const lib = Object.entries(emojilib.lib).filter((x: any) => { @@ -40,7 +42,7 @@ const lib = Object.entries(emojilib.lib).filter((x: any) => { }); const emjdb: EmojiDef[] = lib.map((x: any) => ({ - emoji: `:${x[0]}:`, + emoji: x[1].char, name: x[0], aliasOf: null, url: `https://twemoji.maxcdn.com/2/svg/${x[1].char.codePointAt(0).toString(16)}.svg` @@ -50,7 +52,7 @@ lib.forEach((x: any) => { if (x[1].keywords) { x[1].keywords.forEach(k => { emjdb.push({ - emoji: `:${x[0]}:`, + emoji: x[1].char, name: k, aliasOf: x[0], url: `https://twemoji.maxcdn.com/2/svg/${x[1].char.codePointAt(0).toString(16)}.svg` @@ -79,6 +81,10 @@ export default Vue.extend({ computed: { items(): HTMLCollection { return (this.$refs.suggests as Element).children; + }, + + useOsDefaultEmojis(): boolean { + return this.$store.state.device.useOsDefaultEmojis; } }, @@ -109,7 +115,8 @@ export default Vue.extend({ emojiDefinitions.push({ name: x.name, emoji: `:${x.name}:`, - url: x.url + url: x.url, + isCustomEmoji: true }); if (x.aliases) { @@ -118,7 +125,8 @@ export default Vue.extend({ name: alias, aliasOf: x.name, emoji: `:${x.name}:`, - url: x.url + url: x.url, + isCustomEmoji: true }); }); } diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index 7429aaaa5..a02d7b3f2 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -1,59 +1,77 @@ diff --git a/src/client/app/common/views/components/misskey-flavored-markdown.ts b/src/client/app/common/views/components/misskey-flavored-markdown.ts index b4b141ea2..dd111aba0 100644 --- a/src/client/app/common/views/components/misskey-flavored-markdown.ts +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -187,10 +187,10 @@ export default Vue.component('misskey-flavored-markdown', { } case 'emoji': { - const { emoji, raw } = token; + const { emoji, name } = token; const { customEmojis } = this; return [createElement('mk-emoji', { - attrs: { emoji, raw }, + attrs: { emoji, name }, props: { customEmojis } })]; } diff --git a/src/client/app/common/views/directives/autocomplete.ts b/src/client/app/common/views/directives/autocomplete.ts index 1a5c5daed..b91e70f90 100644 --- a/src/client/app/common/views/directives/autocomplete.ts +++ b/src/client/app/common/views/directives/autocomplete.ts @@ -145,6 +145,7 @@ class Autocomplete { } else { // サジェスト要素作成 this.suggestion = new MkAutocomplete({ + parent: this.vm, propsData: { textarea: this.textarea, complete: this.complete, diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue index 93bef0e61..97743b0bf 100644 --- a/src/client/app/desktop/views/components/settings.vue +++ b/src/client/app/desktop/views/components/settings.vue @@ -115,6 +115,7 @@ %i18n:common.reduce-motion% %i18n:@contrasted-acct% %i18n:common.show-full-acct% + %i18n:common.use-os-default-emojis% %i18n:common.i-like-sushi%
    @@ -324,6 +325,11 @@ export default Vue.extend({ }; }, computed: { + useOsDefaultEmojis: { + get() { return this.$store.state.device.useOsDefaultEmojis; }, + set(value) { this.$store.commit('device/set', { key: 'useOsDefaultEmojis', value }); } + }, + reduceMotion: { get() { return this.$store.state.device.reduceMotion; }, set(value) { this.$store.commit('device/set', { key: 'reduceMotion', value }); } diff --git a/src/client/app/mobile/views/pages/settings.vue b/src/client/app/mobile/views/pages/settings.vue index 10d13423a..0463d9b3f 100644 --- a/src/client/app/mobile/views/pages/settings.vue +++ b/src/client/app/mobile/views/pages/settings.vue @@ -23,6 +23,7 @@ %i18n:common.reduce-motion% (%i18n:common.this-setting-is-this-device-only%) %i18n:@contrasted-acct% %i18n:common.show-full-acct% + %i18n:common.use-os-default-emojis% %i18n:common.i-like-sushi% %i18n:common.disable-animated-mfm% %i18n:common.always-show-nsfw% (%i18n:common.this-setting-is-this-device-only%) @@ -199,6 +200,11 @@ export default Vue.extend({ set(value) { this.$store.commit('device/set', { key: 'darkmode', value }); } }, + useOsDefaultEmojis: { + get() { return this.$store.state.device.useOsDefaultEmojis; }, + set(value) { this.$store.commit('device/set', { key: 'useOsDefaultEmojis', value }); } + }, + reduceMotion: { get() { return this.$store.state.device.reduceMotion; }, set(value) { this.$store.commit('device/set', { key: 'reduceMotion', value }); } diff --git a/src/client/app/store.ts b/src/client/app/store.ts index 7c3a403c8..1108a1c3d 100644 --- a/src/client/app/store.ts +++ b/src/client/app/store.ts @@ -62,7 +62,8 @@ const defaultDeviceSettings = { deckColumnAlign: 'center', mobileNotificationPosition: 'bottom', deckTemporaryColumn: null, - deckDefault: false + deckDefault: false, + useOsDefaultEmojis: false }; export default (os: MiOS) => new Vuex.Store({ diff --git a/src/mfm/parse/elements/emoji.ts b/src/mfm/parse/elements/emoji.ts index 12e0a64b6..a213b2dac 100644 --- a/src/mfm/parse/elements/emoji.ts +++ b/src/mfm/parse/elements/emoji.ts @@ -8,27 +8,26 @@ export type TextElementEmoji = { type: 'emoji'; content: string; emoji?: string; - raw?: string; + name?: string; }; export default function(text: string) { const name = text.match(/^:([a-zA-Z0-9+_-]+):/); if (name) { - const [content, emoji] = name; + return { + type: 'emoji', + content: name[0], + name: name[1] + } as TextElementEmoji; + } + const unicode = text.match(emojiRegex); + if (unicode) { + const [content, emoji] = unicode; return { type: 'emoji', content, emoji } as TextElementEmoji; } - const unicode = text.match(emojiRegex); - if (unicode) { - const [content, raw] = unicode; - return { - type: 'emoji', - content, - raw - } as TextElementEmoji; - } return null; } diff --git a/src/remote/activitypub/misc/get-emoji-names.ts b/src/remote/activitypub/misc/get-emoji-names.ts index f744d02fe..7dd634a65 100644 --- a/src/remote/activitypub/misc/get-emoji-names.ts +++ b/src/remote/activitypub/misc/get-emoji-names.ts @@ -2,5 +2,5 @@ import parse from '../../../mfm/parse'; export default function(text: string) { if (!text) return []; - return parse(text).filter(t => t.type === 'emoji').map(t => (t as any).emoji); + return parse(text).filter(t => t.type === 'emoji' && t.name).map(t => (t as any).name); } diff --git a/src/remote/activitypub/renderer/note.ts b/src/remote/activitypub/renderer/note.ts index a2c591de2..b38d47130 100644 --- a/src/remote/activitypub/renderer/note.ts +++ b/src/remote/activitypub/renderer/note.ts @@ -8,9 +8,7 @@ import Note, { INote } from '../../../models/note'; import User from '../../../models/user'; import toHtml from '../misc/get-note-html'; import parseMfm from '../../../mfm/parse'; -import getEmojiNames from '../misc/get-emoji-names'; import Emoji, { IEmoji } from '../../../models/emoji'; -import { unique } from '../../../prelude/array'; export default async function renderNote(note: INote, dive = true): Promise { const promisedFiles: Promise = note.fileIds @@ -110,8 +108,7 @@ export default async function renderNote(note: INote, dive = true): Promise const content = toHtml(Object.assign({}, note, { text })); - const emojiNames = unique(getEmojiNames(content)); - const emojis = await getEmojis(emojiNames); + const emojis = await getEmojis(note.emojis); const apemojis = emojis.map(emoji => renderEmoji(emoji)); const tag = [ diff --git a/src/services/note/create.ts b/src/services/note/create.ts index ac8bcf034..b3a3e83d4 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -456,8 +456,8 @@ function extractHashtags(tokens: ReturnType): string[] { function extractEmojis(tokens: ReturnType): string[] { // Extract emojis const emojis = tokens - .filter(t => t.type == 'emoji') - .map(t => (t as TextElementEmoji).emoji) + .filter(t => t.type == 'emoji' && t.name) + .map(t => (t as TextElementEmoji).name) .filter(emoji => emoji.length <= 100); return unique(emojis); diff --git a/test/mfm.ts b/test/mfm.ts index 1aadcd21e..5103d9413 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -182,14 +182,14 @@ describe('Text', () => { it('emoji', () => { const tokens1 = analyze(':cat:'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', emoji: 'cat'} + { type: 'emoji', content: ':cat:', name: 'cat'} ], tokens1); const tokens2 = analyze(':cat::cat::cat:'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', emoji: 'cat'}, - { type: 'emoji', content: ':cat:', emoji: 'cat'}, - { type: 'emoji', content: ':cat:', emoji: 'cat'} + { type: 'emoji', content: ':cat:', name: 'cat'}, + { type: 'emoji', content: ':cat:', name: 'cat'}, + { type: 'emoji', content: ':cat:', name: 'cat'} ], tokens2); });