From 4e7fbd8967874e5fa27b618e9d3d7d29ac85315d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 10:42:46 +0900 Subject: [PATCH 01/19] Implement /api/v1/custom_emojis --- src/server/api/mastodon.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/server/api/mastodon.ts b/src/server/api/mastodon.ts index a5b59e2e0..33a0b4b5f 100644 --- a/src/server/api/mastodon.ts +++ b/src/server/api/mastodon.ts @@ -4,12 +4,18 @@ import { toASCII } from 'punycode'; import config from '../../config'; import Meta from '../../models/meta'; import { ObjectID } from 'bson'; +import Emoji from '../../models/emoji'; const pkg = require('../../../package.json'); // Init router const router = new Router(); -router.get('/v1/custom_emojis', async ctx => ctx.body = {}); +router.get('/v1/custom_emojis', async ctx => ctx.body = + await Emoji.find({ host: null }, { + fields: { + _id: false + } + })); router.get('/v1/instance', async ctx => { // TODO: This is a temporary implementation. Consider creating helper methods! const meta = await Meta.findOne() || {}; From 0963e6d6e14cf94af294a7ced5bbd2fbd824f95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 11:19:40 +0900 Subject: [PATCH 02/19] Use Twemoji --- .../common/views/components/autocomplete.vue | 10 +++-- .../app/common/views/components/emoji.vue | 42 +++++++++++++++++++ .../app/common/views/components/index.ts | 2 + .../components/misskey-flavored-markdown.ts | 22 ++-------- src/models/mastodon/emoji.ts | 35 ++++++++++++++++ src/server/api/mastodon.ts | 12 ++++-- 6 files changed, 98 insertions(+), 25 deletions(-) create mode 100644 src/client/app/common/views/components/emoji.vue create mode 100644 src/models/mastodon/emoji.ts diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index 3f3cd171e..dff0bfd8d 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -40,18 +40,20 @@ const lib = Object.entries(emojilib.lib).filter((x: any) => { }); const emjdb: EmojiDef[] = lib.map((x: any) => ({ - emoji: x[1].char, + emoji: `:${x[0]}:`, name: x[0], - aliasOf: null + aliasOf: null, + url: `https://twemoji.maxcdn.com/2/svg/${x[1].char.codePointAt(0).toString(16)}.svg` })); lib.forEach((x: any) => { if (x[1].keywords) { x[1].keywords.forEach(k => { emjdb.push({ - emoji: x[1].char, + emoji: `:${x[0]}:`, name: k, - aliasOf: x[0] + aliasOf: x[0], + url: `https://twemoji.maxcdn.com/2/svg/${x[1].char.codePointAt(0).toString(16)}.svg` }); }); } diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue new file mode 100644 index 000000000..2aa62de25 --- /dev/null +++ b/src/client/app/common/views/components/emoji.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 3b20d0753..5665ef88d 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -39,6 +39,7 @@ import urlPreview from './url-preview.vue'; import twitterSetting from './twitter-setting.vue'; import githubSetting from './github-setting.vue'; import fileTypeIcon from './file-type-icon.vue'; +import emoji from './emoji.vue'; import Reversi from './games/reversi/reversi.vue'; import welcomeTimeline from './welcome-timeline.vue'; import uiInput from './ui/input.vue'; @@ -93,6 +94,7 @@ Vue.component('mk-url-preview', urlPreview); Vue.component('mk-twitter-setting', twitterSetting); Vue.component('mk-github-setting', githubSetting); Vue.component('mk-file-type-icon', fileTypeIcon); +Vue.component('mk-emoji', emoji); Vue.component('mk-reversi', Reversi); Vue.component('mk-welcome-timeline', welcomeTimeline); Vue.component('ui-input', uiInput); 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 68f3aeed1..c7368ecaf 100644 --- a/src/client/app/common/views/components/misskey-flavored-markdown.ts +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -188,24 +188,10 @@ export default Vue.component('misskey-flavored-markdown', { } case 'emoji': { - //#region カスタム絵文字 - if (this.customEmojis != null) { - const customEmoji = this.customEmojis.find(e => e.name == token.emoji || (e.aliases || []).includes(token.emoji)); - if (customEmoji) { - return [createElement('img', { - attrs: { - src: customEmoji.url, - alt: token.emoji, - title: token.emoji, - style: 'height: 2.5em; vertical-align: middle;' - } - })]; - } - } - //#endregion - - const emoji = emojilib.lib[token.emoji]; - return [createElement('span', emoji ? emoji.char : token.content)]; + const { emoji } = token; + return [createElement('mk-emoji', { + attrs: { emoji } + })]; } case 'search': { diff --git a/src/models/mastodon/emoji.ts b/src/models/mastodon/emoji.ts new file mode 100644 index 000000000..df19c6e75 --- /dev/null +++ b/src/models/mastodon/emoji.ts @@ -0,0 +1,35 @@ +export type IMastodonEmoji = { + shortcode: string, + url: string, + static_url: string, + visible_in_picker: boolean +}; + +export async function toMastodonEmojis(emoji: any): Promise { + return [{ + shortcode: emoji.name, + url: emoji.url, + static_url: emoji.url, // TODO: Implement ensuring static emoji + visible_in_picker: true + }, ...(emoji.aliases as string[] || []).map(x => ({ + shortcode: x, + url: emoji.url, + static_url: emoji.url, + visible_in_picker: true + }))]; +} + +export function toMisskeyEmojiSync(emoji: IMastodonEmoji) { + return { + name: emoji.shortcode, + url: emoji.url + }; +} + +export function toMisskeyEmojiWithAliasesSync(emoji: IMastodonEmoji, ...aliases: string[]) { + return { + name: emoji.shortcode, + aliases, + url: emoji.url + }; +} diff --git a/src/server/api/mastodon.ts b/src/server/api/mastodon.ts index 33a0b4b5f..d1e1068da 100644 --- a/src/server/api/mastodon.ts +++ b/src/server/api/mastodon.ts @@ -5,17 +5,18 @@ import config from '../../config'; import Meta from '../../models/meta'; import { ObjectID } from 'bson'; import Emoji from '../../models/emoji'; +import { toMastodonEmojis } from '../../models/mastodon/emoji'; const pkg = require('../../../package.json'); // Init router const router = new Router(); router.get('/v1/custom_emojis', async ctx => ctx.body = - await Emoji.find({ host: null }, { + (await Emoji.find({ host: null }, { fields: { _id: false } - })); + })).map(toMastodonEmojis)); router.get('/v1/instance', async ctx => { // TODO: This is a temporary implementation. Consider creating helper methods! const meta = await Meta.findOne() || {}; @@ -40,6 +41,11 @@ router.get('/v1/instance', async ctx => { // TODO: This is a temporary implement notesCount: 0 }; const acct = maintainer.host ? `${maintainer.username}@${maintainer.host}` : maintainer.username; + const emojis = (await Emoji.find({ host: null }, { + fields: { + _id: false + } + })).map(toMastodonEmojis); ctx.body = { uri: config.hostname, @@ -79,7 +85,7 @@ router.get('/v1/instance', async ctx => { // TODO: This is a temporary implement followers_count: maintainer.followersCount, following_count: maintainer.followingCount, statuses_count: maintainer.notesCount, - emojis: [], + emojis: emojis, moved: null, fields: null } From dca110ebaa78f64600429f812c238a07d2f1dc1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 11:39:13 +0900 Subject: [PATCH 03/19] Separate commits Flash Back 90's --- src/server/api/mastodon.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/server/api/mastodon.ts b/src/server/api/mastodon.ts index d1e1068da..33a0b4b5f 100644 --- a/src/server/api/mastodon.ts +++ b/src/server/api/mastodon.ts @@ -5,18 +5,17 @@ import config from '../../config'; import Meta from '../../models/meta'; import { ObjectID } from 'bson'; import Emoji from '../../models/emoji'; -import { toMastodonEmojis } from '../../models/mastodon/emoji'; const pkg = require('../../../package.json'); // Init router const router = new Router(); router.get('/v1/custom_emojis', async ctx => ctx.body = - (await Emoji.find({ host: null }, { + await Emoji.find({ host: null }, { fields: { _id: false } - })).map(toMastodonEmojis)); + })); router.get('/v1/instance', async ctx => { // TODO: This is a temporary implementation. Consider creating helper methods! const meta = await Meta.findOne() || {}; @@ -41,11 +40,6 @@ router.get('/v1/instance', async ctx => { // TODO: This is a temporary implement notesCount: 0 }; const acct = maintainer.host ? `${maintainer.username}@${maintainer.host}` : maintainer.username; - const emojis = (await Emoji.find({ host: null }, { - fields: { - _id: false - } - })).map(toMastodonEmojis); ctx.body = { uri: config.hostname, @@ -85,7 +79,7 @@ router.get('/v1/instance', async ctx => { // TODO: This is a temporary implement followers_count: maintainer.followersCount, following_count: maintainer.followingCount, statuses_count: maintainer.notesCount, - emojis: emojis, + emojis: [], moved: null, fields: null } From 9719387bee40363f63a837e7ecffacf2a476c334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 11:51:14 +0900 Subject: [PATCH 04/19] Re-separate commits --- src/models/mastodon/emoji.ts | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 src/models/mastodon/emoji.ts diff --git a/src/models/mastodon/emoji.ts b/src/models/mastodon/emoji.ts deleted file mode 100644 index df19c6e75..000000000 --- a/src/models/mastodon/emoji.ts +++ /dev/null @@ -1,35 +0,0 @@ -export type IMastodonEmoji = { - shortcode: string, - url: string, - static_url: string, - visible_in_picker: boolean -}; - -export async function toMastodonEmojis(emoji: any): Promise { - return [{ - shortcode: emoji.name, - url: emoji.url, - static_url: emoji.url, // TODO: Implement ensuring static emoji - visible_in_picker: true - }, ...(emoji.aliases as string[] || []).map(x => ({ - shortcode: x, - url: emoji.url, - static_url: emoji.url, - visible_in_picker: true - }))]; -} - -export function toMisskeyEmojiSync(emoji: IMastodonEmoji) { - return { - name: emoji.shortcode, - url: emoji.url - }; -} - -export function toMisskeyEmojiWithAliasesSync(emoji: IMastodonEmoji, ...aliases: string[]) { - return { - name: emoji.shortcode, - aliases, - url: emoji.url - }; -} From b7f10fdc10214a593d7c40062bd69b1e19017027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 13:23:26 +0900 Subject: [PATCH 05/19] Fix bug refs: https://github.com/syuilo/misskey/pull/3117#discussion_r230624389 --- src/client/app/common/views/components/emoji.vue | 16 ++++++++++++---- .../components/misskey-flavored-markdown.ts | 5 +++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index 2aa62de25..9c4d0c879 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -6,7 +6,15 @@ import Vue from 'vue'; import { lib } from 'emojilib'; export default Vue.extend({ - props: ['emoji'], + props: { + emoji: { + type: String, + required: true + }, + customEmojis: { + required: false + } + }, data() { return { url: null, @@ -19,10 +27,10 @@ export default Vue.extend({ }, methods: { exec() { - const { emoji } = this; + const { emoji, customEmojis } = this; this.name = emoji; - (this as any).api('meta').then(meta => - this.url = meta && meta.emojis ? meta.emojis.find(e => e.name === emoji || e.aliases && e.aliases.includes(emoji)).url : null); + console.log(emoji, customEmojis) + this.url = customEmojis && customEmojis.length ? customEmojis.find(e => e.name === emoji || e.aliases && e.aliases.includes(emoji)).url : null; if (!this.url) { const { char } = lib[emoji] || { char: null }; if (char) { 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 c7368ecaf..1948647e9 100644 --- a/src/client/app/common/views/components/misskey-flavored-markdown.ts +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -1,5 +1,4 @@ import Vue, { VNode } from 'vue'; -import * as emojilib from 'emojilib'; import { length } from 'stringz'; import parse from '../../../../../mfm/parse'; import getAcct from '../../../../../misc/acct/render'; @@ -189,8 +188,10 @@ export default Vue.component('misskey-flavored-markdown', { case 'emoji': { const { emoji } = token; + const { customEmojis } = this; return [createElement('mk-emoji', { - attrs: { emoji } + attrs: { emoji }, + props: { customEmojis } })]; } From 200ebefe92062966cf04cc2c5fe3480e5e55dabd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 15:15:30 +0900 Subject: [PATCH 06/19] Add support for unicode emojis refs: https://github.com/syuilo/misskey/pull/3117#issuecomment-435745613 --- .../app/common/views/components/emoji.vue | 15 ++++---- .../components/misskey-flavored-markdown.ts | 4 +-- src/mfm/parse/elements/emoji.ts | 35 ++++++++++++++----- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index 9c4d0c879..2dca8fdcb 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -9,7 +9,11 @@ export default Vue.extend({ props: { emoji: { type: String, - required: true + required: false + }, + raw: { + type: String, + required: false }, customEmojis: { required: false @@ -27,12 +31,11 @@ export default Vue.extend({ }, methods: { exec() { - const { emoji, customEmojis } = this; - this.name = emoji; - console.log(emoji, customEmojis) - this.url = customEmojis && customEmojis.length ? customEmojis.find(e => e.name === emoji || e.aliases && e.aliases.includes(emoji)).url : null; + const { emoji, raw, customEmojis } = this; + this.name = emoji || raw; + this.url = !raw && customEmojis && customEmojis.length ? customEmojis.find(e => e.name === emoji || e.aliases && e.aliases.includes(emoji)).url : null; if (!this.url) { - const { char } = lib[emoji] || { char: null }; + const char = raw || lib[emoji] && lib[emoji].char; if (char) { this.url = `https://twemoji.maxcdn.com/2/svg/${char.codePointAt(0).toString(16)}.svg`; this.alt = char; 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 1948647e9..b4b141ea2 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 } = token; + const { emoji, raw } = token; const { customEmojis } = this; return [createElement('mk-emoji', { - attrs: { emoji }, + attrs: { emoji, raw }, props: { customEmojis } })]; } diff --git a/src/mfm/parse/elements/emoji.ts b/src/mfm/parse/elements/emoji.ts index 4d66d4c01..863735501 100644 --- a/src/mfm/parse/elements/emoji.ts +++ b/src/mfm/parse/elements/emoji.ts @@ -2,19 +2,36 @@ * Emoji */ +const emojis = /^((?:\ud83d[\udc68\udc69])(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddb0-\uddb3])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f)|[\u0023\u002a\u0030-\u0039]\ufe0f?\u20e3|(?:[\u00a9\u00ae\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\uddb5\uddb6\uddb8\uddb9\uddd1-\udddd]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a-\udc6d\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\udeeb\udeec\udef4-\udef9]|\ud83e[\udd10-\udd17\udd1d\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd40-\udd45\udd47-\udd70\udd73-\udd76\udd7a\udd7c-\udda2\uddb4\uddb7\uddc0-\uddc2\uddd0\uddde-\uddff]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f)/; // ?REF: https://www.unicode.org/Public/UNIDATA/EmojiSources.txt + export type TextElementEmoji = { type: 'emoji'; content: string; - emoji: string; + emoji?: string; + raw?: string; }; export default function(text: string) { - const match = text.match(/^:([a-zA-Z0-9+_-]+):/); - if (!match) return null; - const emoji = match[0]; - return { - type: 'emoji', - content: emoji, - emoji: match[1] - } as TextElementEmoji; + const name = text.match(/^:([a-zA-Z0-9+_-]+):/); + if (name) { + console.log(text, 'as name', name) + const [content, emoji] = name; + return { + type: 'emoji', + content, + emoji + } as TextElementEmoji; + } + const unicode = text.match(emojis); + if (unicode) { + console.log(text, 'as unicode', unicode) + const [content, raw] = unicode; + return { + type: 'emoji', + content, + raw + } as TextElementEmoji; + } + console.log(text, 'as null', null) + return null; } From 31b7626d018f3e241ddeac5b723c18fa41088bf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 16:19:10 +0900 Subject: [PATCH 07/19] Make code better refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171423739 refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171424596 refs: https://github.com/syuilo/misskey/pull/3117#pullrequestreview-171425303 --- src/client/app/common/views/components/emoji.vue | 8 +++++++- src/mfm/parse/elements/emoji.regex.ts | 1 + src/mfm/parse/elements/emoji.ts | 7 ++----- 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 src/mfm/parse/elements/emoji.regex.ts diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index 2dca8fdcb..6a078e023 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -5,6 +5,11 @@ 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); }); From 3abe632f0673d5be2527aa49fa63663104681e0b Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 19:29:50 +0900 Subject: [PATCH 10/19] Clean up --- src/remote/activitypub/misc/get-emoji-names.ts | 6 ------ src/remote/activitypub/renderer/note.ts | 10 ++++------ 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 src/remote/activitypub/misc/get-emoji-names.ts diff --git a/src/remote/activitypub/misc/get-emoji-names.ts b/src/remote/activitypub/misc/get-emoji-names.ts deleted file mode 100644 index 7dd634a65..000000000 --- a/src/remote/activitypub/misc/get-emoji-names.ts +++ /dev/null @@ -1,6 +0,0 @@ -import parse from '../../../mfm/parse'; - -export default function(text: string) { - if (!text) return []; - 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 b38d47130..2b834f9d2 100644 --- a/src/remote/activitypub/renderer/note.ts +++ b/src/remote/activitypub/renderer/note.ts @@ -138,12 +138,10 @@ async function getEmojis(names: string[]): Promise { if (names == null || names.length < 1) return []; const emojis = await Promise.all( - names.map(async name => { - return await Emoji.findOne({ - name, - host: null - }); - }) + names.map(name => Emoji.findOne({ + name, + host: null + })) ); return emojis.filter(emoji => emoji != null); From 3fe934ee62d9d80b48918bae8c5ac248b385005d Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 19:33:28 +0900 Subject: [PATCH 11/19] Better alt value --- src/client/app/common/views/components/emoji.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/app/common/views/components/emoji.vue b/src/client/app/common/views/components/emoji.vue index a02d7b3f2..106abecc7 100644 --- a/src/client/app/common/views/components/emoji.vue +++ b/src/client/app/common/views/components/emoji.vue @@ -35,7 +35,7 @@ export default Vue.extend({ computed: { alt(): string { - return this.customEmoji ? this.customEmoji.name : this.char; + return this.customEmoji ? `:${this.customEmoji.name}:` : this.char; }, useOsDefaultEmojis(): boolean { From b9b05a74017c37ae23986c005deac0a3465d497c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Acid=20Chicken=20=28=E7=A1=AB=E9=85=B8=E9=B6=8F=29?= Date: Mon, 5 Nov 2018 19:50:38 +0900 Subject: [PATCH 12/19] Fix test fails --- test/mfm.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/mfm.ts b/test/mfm.ts index 5103d9413..1aadcd21e 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:', name: 'cat'} + { type: 'emoji', content: ':cat:', emoji: 'cat'} ], tokens1); const tokens2 = analyze(':cat::cat::cat:'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', name: 'cat'}, - { type: 'emoji', content: ':cat:', name: 'cat'}, - { type: 'emoji', content: ':cat:', name: 'cat'} + { type: 'emoji', content: ':cat:', emoji: 'cat'}, + { type: 'emoji', content: ':cat:', emoji: 'cat'}, + { type: 'emoji', content: ':cat:', emoji: 'cat'} ], tokens2); }); From 5744c391e6f07b4f91df9097833da91aaeba11d1 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:10:00 +0900 Subject: [PATCH 13/19] Revert "Fix test fails" This reverts commit b9b05a74017c37ae23986c005deac0a3465d497c. --- test/mfm.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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); }); From 630a534cee17971ade8f54334fdbc214d5b8b831 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:10:28 +0900 Subject: [PATCH 14/19] Fix test --- test/mfm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mfm.ts b/test/mfm.ts index 5103d9413..16aafd189 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -16,7 +16,7 @@ describe('Text', () => { { type: 'text', content: ' '}, { 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: 'emoji', content: ':cat:', name: 'cat'}, { type: 'text', content: ' '}, { type: 'hashtag', content: '#yryr', hashtag: 'yryr' } ], tokens); From 389f9bfea25823024ef116e07efeb6a648e74303 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:14:49 +0900 Subject: [PATCH 15/19] Add test --- test/mfm.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/mfm.ts b/test/mfm.ts index 16aafd189..e09ec82a0 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -191,6 +191,11 @@ describe('Text', () => { { type: 'emoji', content: ':cat:', name: 'cat'}, { type: 'emoji', content: ':cat:', name: 'cat'} ], tokens2); + + const tokens3 = analyze('🍎'); + assert.deepEqual([ + { type: 'emoji', content: ':cat:', emoji: '🍎'} + ], tokens3); }); it('block code', () => { From a0b13505a0809195b245aef07c56be47b03b333e Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:15:09 +0900 Subject: [PATCH 16/19] Insert missing spaces --- test/mfm.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/mfm.ts b/test/mfm.ts index e09ec82a0..10db317ed 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -182,19 +182,19 @@ describe('Text', () => { it('emoji', () => { const tokens1 = analyze(':cat:'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', name: 'cat'} + { type: 'emoji', content: ':cat:', name: 'cat' } ], tokens1); const tokens2 = analyze(':cat::cat::cat:'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', name: 'cat'}, - { type: 'emoji', content: ':cat:', name: 'cat'}, - { type: 'emoji', content: ':cat:', name: 'cat'} + { type: 'emoji', content: ':cat:', name: 'cat' }, + { type: 'emoji', content: ':cat:', name: 'cat' }, + { type: 'emoji', content: ':cat:', name: 'cat' } ], tokens2); const tokens3 = analyze('🍎'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', emoji: '🍎'} + { type: 'emoji', content: ':cat:', emoji: '🍎' } ], tokens3); }); From e542dcac301fc0c3911067c3cefddbd06af118c4 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:40:39 +0900 Subject: [PATCH 17/19] Fix test --- test/mfm.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/mfm.ts b/test/mfm.ts index 10db317ed..30b5f0014 100644 --- a/test/mfm.ts +++ b/test/mfm.ts @@ -194,7 +194,7 @@ describe('Text', () => { const tokens3 = analyze('🍎'); assert.deepEqual([ - { type: 'emoji', content: ':cat:', emoji: '🍎' } + { type: 'emoji', content: '🍎', emoji: '🍎' } ], tokens3); }); From 3fc04fcdc536d32213407d25f6c45387f68d0070 Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:49:02 +0900 Subject: [PATCH 18/19] Improve readdability --- .../views/components/misskey-flavored-markdown.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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 dd111aba0..2a0a2b6f6 100644 --- a/src/client/app/common/views/components/misskey-flavored-markdown.ts +++ b/src/client/app/common/views/components/misskey-flavored-markdown.ts @@ -187,11 +187,14 @@ export default Vue.component('misskey-flavored-markdown', { } case 'emoji': { - const { emoji, name } = token; - const { customEmojis } = this; return [createElement('mk-emoji', { - attrs: { emoji, name }, - props: { customEmojis } + attrs: { + emoji: token.emoji, + name: token.name + }, + props: { + customEmojis: this.customEmojis + } })]; } From e4bb534f206f6081870cb8dc8165307c8ad73d1e Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 5 Nov 2018 20:49:17 +0900 Subject: [PATCH 19/19] Better emoji regexp --- src/mfm/parse/elements/emoji.regex.ts | 1 - src/mfm/parse/elements/emoji.ts | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 src/mfm/parse/elements/emoji.regex.ts diff --git a/src/mfm/parse/elements/emoji.regex.ts b/src/mfm/parse/elements/emoji.regex.ts deleted file mode 100644 index 08993ddc3..000000000 --- a/src/mfm/parse/elements/emoji.regex.ts +++ /dev/null @@ -1 +0,0 @@ -export const emojiRegex = /^((?:\ud83d[\udc68\udc69])(?:\ud83c[\udffb-\udfff])?\u200d(?:\u2695\ufe0f|\u2696\ufe0f|\u2708\ufe0f|\ud83c[\udf3e\udf73\udf93\udfa4\udfa8\udfeb\udfed]|\ud83d[\udcbb\udcbc\udd27\udd2c\ude80\ude92]|\ud83e[\uddb0-\uddb3])|(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75]|\u26f9)((?:\ud83c[\udffb-\udfff]|\ufe0f)\u200d[\u2640\u2642]\ufe0f)|(?:\ud83c[\udfc3\udfc4\udfca]|\ud83d[\udc6e\udc71\udc73\udc77\udc81\udc82\udc86\udc87\ude45-\ude47\ude4b\ude4d\ude4e\udea3\udeb4-\udeb6]|\ud83e[\udd26\udd35\udd37-\udd39\udd3d\udd3e\uddb8\uddb9\uddd6-\udddd])(?:\ud83c[\udffb-\udfff])?\u200d[\u2640\u2642]\ufe0f|(?:\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d\udc8b\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\u2764\ufe0f\u200d\ud83d\udc68|\ud83d\udc68\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc68\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc68\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\u2764\ufe0f\u200d\ud83d[\udc68\udc69]|\ud83d\udc69\u200d\ud83d\udc66\u200d\ud83d\udc66|\ud83d\udc69\u200d\ud83d\udc67\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83c\udff3\ufe0f\u200d\ud83c\udf08|\ud83c\udff4\u200d\u2620\ufe0f|\ud83d\udc41\u200d\ud83d\udde8|\ud83d\udc68\u200d\ud83d[\udc66\udc67]|\ud83d\udc69\u200d\ud83d[\udc66\udc67]|\ud83d\udc6f\u200d\u2640\ufe0f|\ud83d\udc6f\u200d\u2642\ufe0f|\ud83e\udd3c\u200d\u2640\ufe0f|\ud83e\udd3c\u200d\u2642\ufe0f|\ud83e\uddde\u200d\u2640\ufe0f|\ud83e\uddde\u200d\u2642\ufe0f|\ud83e\udddf\u200d\u2640\ufe0f|\ud83e\udddf\u200d\u2642\ufe0f)|[\u0023\u002a\u0030-\u0039]\ufe0f?\u20e3|(?:[\u00a9\u00ae\u2122\u265f]\ufe0f)|(?:\ud83c[\udc04\udd70\udd71\udd7e\udd7f\ude02\ude1a\ude2f\ude37\udf21\udf24-\udf2c\udf36\udf7d\udf96\udf97\udf99-\udf9b\udf9e\udf9f\udfcd\udfce\udfd4-\udfdf\udff3\udff5\udff7]|\ud83d[\udc3f\udc41\udcfd\udd49\udd4a\udd6f\udd70\udd73\udd76-\udd79\udd87\udd8a-\udd8d\udda5\udda8\uddb1\uddb2\uddbc\uddc2-\uddc4\uddd1-\uddd3\udddc-\uddde\udde1\udde3\udde8\uddef\uddf3\uddfa\udecb\udecd-\udecf\udee0-\udee5\udee9\udef0\udef3]|[\u203c\u2049\u2139\u2194-\u2199\u21a9\u21aa\u231a\u231b\u2328\u23cf\u23ed-\u23ef\u23f1\u23f2\u23f8-\u23fa\u24c2\u25aa\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262a\u262e\u262f\u2638-\u263a\u2640\u2642\u2648-\u2653\u2660\u2663\u2665\u2666\u2668\u267b\u267f\u2692-\u2697\u2699\u269b\u269c\u26a0\u26a1\u26aa\u26ab\u26b0\u26b1\u26bd\u26be\u26c4\u26c5\u26c8\u26cf\u26d1\u26d3\u26d4\u26e9\u26ea\u26f0-\u26f5\u26f8\u26fa\u26fd\u2702\u2708\u2709\u270f\u2712\u2714\u2716\u271d\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u2764\u27a1\u2934\u2935\u2b05-\u2b07\u2b1b\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299])(?:\ufe0f|(?!\ufe0e))|(?:(?:\ud83c[\udfcb\udfcc]|\ud83d[\udd74\udd75\udd90]|[\u261d\u26f7\u26f9\u270c\u270d])(?:\ufe0f|(?!\ufe0e))|(?:\ud83c[\udf85\udfc2-\udfc4\udfc7\udfca]|\ud83d[\udc42\udc43\udc46-\udc50\udc66-\udc69\udc6e\udc70-\udc78\udc7c\udc81-\udc83\udc85-\udc87\udcaa\udd7a\udd95\udd96\ude45-\ude47\ude4b-\ude4f\udea3\udeb4-\udeb6\udec0\udecc]|\ud83e[\udd18-\udd1c\udd1e\udd1f\udd26\udd30-\udd39\udd3d\udd3e\uddb5\uddb6\uddb8\uddb9\uddd1-\udddd]|[\u270a\u270b]))(?:\ud83c[\udffb-\udfff])?|(?:\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc73\udb40\udc63\udb40\udc74\udb40\udc7f|\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f|\ud83c\udde6\ud83c[\udde8-\uddec\uddee\uddf1\uddf2\uddf4\uddf6-\uddfa\uddfc\uddfd\uddff]|\ud83c\udde7\ud83c[\udde6\udde7\udde9-\uddef\uddf1-\uddf4\uddf6-\uddf9\uddfb\uddfc\uddfe\uddff]|\ud83c\udde8\ud83c[\udde6\udde8\udde9\uddeb-\uddee\uddf0-\uddf5\uddf7\uddfa-\uddff]|\ud83c\udde9\ud83c[\uddea\uddec\uddef\uddf0\uddf2\uddf4\uddff]|\ud83c\uddea\ud83c[\udde6\udde8\uddea\uddec\udded\uddf7-\uddfa]|\ud83c\uddeb\ud83c[\uddee-\uddf0\uddf2\uddf4\uddf7]|\ud83c\uddec\ud83c[\udde6\udde7\udde9-\uddee\uddf1-\uddf3\uddf5-\uddfa\uddfc\uddfe]|\ud83c\udded\ud83c[\uddf0\uddf2\uddf3\uddf7\uddf9\uddfa]|\ud83c\uddee\ud83c[\udde8-\uddea\uddf1-\uddf4\uddf6-\uddf9]|\ud83c\uddef\ud83c[\uddea\uddf2\uddf4\uddf5]|\ud83c\uddf0\ud83c[\uddea\uddec-\uddee\uddf2\uddf3\uddf5\uddf7\uddfc\uddfe\uddff]|\ud83c\uddf1\ud83c[\udde6-\udde8\uddee\uddf0\uddf7-\uddfb\uddfe]|\ud83c\uddf2\ud83c[\udde6\udde8-\udded\uddf0-\uddff]|\ud83c\uddf3\ud83c[\udde6\udde8\uddea-\uddec\uddee\uddf1\uddf4\uddf5\uddf7\uddfa\uddff]|\ud83c\uddf4\ud83c\uddf2|\ud83c\uddf5\ud83c[\udde6\uddea-\udded\uddf0-\uddf3\uddf7-\uddf9\uddfc\uddfe]|\ud83c\uddf6\ud83c\udde6|\ud83c\uddf7\ud83c[\uddea\uddf4\uddf8\uddfa\uddfc]|\ud83c\uddf8\ud83c[\udde6-\uddea\uddec-\uddf4\uddf7-\uddf9\uddfb\uddfd-\uddff]|\ud83c\uddf9\ud83c[\udde6\udde8\udde9\uddeb-\udded\uddef-\uddf4\uddf7\uddf9\uddfb\uddfc\uddff]|\ud83c\uddfa\ud83c[\udde6\uddec\uddf2\uddf3\uddf8\uddfe\uddff]|\ud83c\uddfb\ud83c[\udde6\udde8\uddea\uddec\uddee\uddf3\uddfa]|\ud83c\uddfc\ud83c[\uddeb\uddf8]|\ud83c\uddfd\ud83c\uddf0|\ud83c\uddfe\ud83c[\uddea\uddf9]|\ud83c\uddff\ud83c[\udde6\uddf2\uddfc]|\ud83c[\udccf\udd8e\udd91-\udd9a\udde6-\uddff\ude01\ude32-\ude36\ude38-\ude3a\ude50\ude51\udf00-\udf20\udf2d-\udf35\udf37-\udf7c\udf7e-\udf84\udf86-\udf93\udfa0-\udfc1\udfc5\udfc6\udfc8\udfc9\udfcf-\udfd3\udfe0-\udff0\udff4\udff8-\udfff]|\ud83d[\udc00-\udc3e\udc40\udc44\udc45\udc51-\udc65\udc6a-\udc6d\udc6f\udc79-\udc7b\udc7d-\udc80\udc84\udc88-\udca9\udcab-\udcfc\udcff-\udd3d\udd4b-\udd4e\udd50-\udd67\udda4\uddfb-\ude44\ude48-\ude4a\ude80-\udea2\udea4-\udeb3\udeb7-\udebf\udec1-\udec5\uded0-\uded2\udeeb\udeec\udef4-\udef9]|\ud83e[\udd10-\udd17\udd1d\udd20-\udd25\udd27-\udd2f\udd3a\udd3c\udd40-\udd45\udd47-\udd70\udd73-\udd76\udd7a\udd7c-\udda2\uddb4\uddb7\uddc0-\uddc2\uddd0\uddde-\uddff]|[\u23e9-\u23ec\u23f0\u23f3\u267e\u26ce\u2705\u2728\u274c\u274e\u2753-\u2755\u2795-\u2797\u27b0\u27bf\ue50a])|\ufe0f)/; // ?REF: https://www.unicode.org/Public/UNIDATA/EmojiSources.txt diff --git a/src/mfm/parse/elements/emoji.ts b/src/mfm/parse/elements/emoji.ts index a213b2dac..de332a706 100644 --- a/src/mfm/parse/elements/emoji.ts +++ b/src/mfm/parse/elements/emoji.ts @@ -2,8 +2,6 @@ * Emoji */ -import { emojiRegex } from "./emoji.regex"; - export type TextElementEmoji = { type: 'emoji'; content: string; @@ -11,6 +9,8 @@ export type TextElementEmoji = { name?: string; }; +const emojiRegex = /^[\u{1f300}-\u{1f5ff}\u{1f900}-\u{1f9ff}\u{1f600}-\u{1f64f}\u{1f680}-\u{1f6ff}\u{2600}-\u{26ff}\u{2700}-\u{27bf}\u{1f1e6}-\u{1f1ff}\u{1f191}-\u{1f251}\u{1f004}\u{1f0cf}\u{1f170}-\u{1f171}\u{1f17e}-\u{1f17f}\u{1f18e}\u{3030}\u{2b50}\u{2b55}\u{2934}-\u{2935}\u{2b05}-\u{2b07}\u{2b1b}-\u{2b1c}\u{3297}\u{3299}\u{303d}\u{00a9}\u{00ae}\u{2122}\u{23f3}\u{24c2}\u{23e9}-\u{23ef}\u{25b6}\u{23f8}-\u{23fa}]/ug; + export default function(text: string) { const name = text.match(/^:([a-zA-Z0-9+_-]+):/); if (name) { @@ -22,11 +22,11 @@ export default function(text: string) { } const unicode = text.match(emojiRegex); if (unicode) { - const [content, emoji] = unicode; + const [content] = unicode; return { type: 'emoji', content, - emoji + emoji: content } as TextElementEmoji; } return null;