From c0e061503cbbac56276aa406feeef234923c7231 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Sat, 18 Nov 2023 18:08:48 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=E5=89=8D=E6=96=B9=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E3=83=BB=E9=83=A8=E5=88=86=E4=B8=80=E8=87=B4=E3=81=A7=E3=81=AA?= =?UTF-8?q?=E3=81=8F=E3=81=A6=E3=82=82=E8=BF=91=E4=BC=BC=E5=80=A4=E3=81=A7?= =?UTF-8?q?=E3=83=92=E3=83=83=E3=83=88=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/MkAutocomplete.vue | 100 ++++++++++++++---- 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 7e0c2190453e..2881c78781de 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -242,29 +242,7 @@ function exec() { return; } - const matched: EmojiDef[] = []; - const max = 30; - - emojiDb.value.some(x => { - if (x.name.startsWith(props.q ?? '') && !x.aliasOf && !matched.some(y => y.emoji === x.emoji)) matched.push(x); - return matched.length === max; - }); - - if (matched.length < max) { - emojiDb.value.some(x => { - if (x.name.startsWith(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); - return matched.length === max; - }); - } - - if (matched.length < max) { - emojiDb.value.some(x => { - if (x.name.includes(props.q ?? '') && !matched.some(y => y.emoji === x.emoji)) matched.push(x); - return matched.length === max; - }); - } - - emojis.value = matched; + emojis.value = emojiAutoComplete(props.q, emojiDb.value); } else if (props.type === 'mfmTag') { if (!props.q || props.q === '') { mfmTags.value = MFM_TAGS; @@ -275,6 +253,82 @@ function exec() { } } +type EmojiScore = { emoji: EmojiDef, score: number }; + +function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30): EmojiDef[] { + if (!query) { + return []; + } + + const matched = new Map(); + + // 前方一致(エイリアスなし) + emojiDb.some(x => { + if (x.name.startsWith(query) && !x.aliasOf) { + matched.set(x.name, { emoji: x, score: query.length }); + } + return matched.size === max; + }); + + // 前方一致(エイリアス込み) + if (matched.size < max) { + emojiDb.some(x => { + if (x.name.startsWith(query)) { + matched.set(x.name, { emoji: x, score: query.length }); + } + return matched.size === max; + }); + } + + // 部分一致(エイリアス込み) + if (matched.size < max) { + emojiDb.some(x => { + if (x.name.includes(query)) { + matched.set(x.name, { emoji: x, score: query.length }); + } + return matched.size === max; + }); + } + + // 簡易あいまい検索 + if (matched.size < max) { + const queryChars = [...query]; + const hitEmojis = new Map(); + + emojiDb.forEach(x => { + // クエリ文字列の1文字単位で絵文字名にヒットするかを見る + // ただし、過剰に検出されるのを防ぐためクエリ文字列に登場する順番で絵文字名を走査する + + let queryCharHitPos = 0; + let queryCharHitCount = 0; + for (let idx = 0; idx < queryChars.length; idx++) { + queryCharHitPos = x.name.indexOf(queryChars[idx], queryCharHitPos); + if (queryCharHitPos <= -1) { + break; + } + + queryCharHitCount++; + } + + // ヒット数が少なすぎると検索結果が汚れるので調節する + if (queryCharHitCount > 2) { + hitEmojis.set(x.name, { emoji: x, score: queryCharHitCount }); + } + }); + + // ヒットしたものを全部追加すると雑多になるので、先頭の6件程度だけにしておく(6件=オートコンプリートのポップアップのサイズ分) + [...hitEmojis.values()] + .sort((x, y) => y.score - x.score) + .slice(0, 6) + .forEach(it => matched.set(it.emoji.name, it)); + } + + return [...matched.values()] + .sort((x, y) => y.score - x.score) + .slice(0, max) + .map(it => it.emoji); +} + function onMousedown(event: Event) { if (!contains(rootEl.value, event.target) && (rootEl.value !== event.target)) props.close(); } From d20e2d1bea87715882f1d2bc2b20b7816a3b9cfa Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Sat, 18 Nov 2023 21:08:18 +0900 Subject: [PATCH 2/3] fix CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b08d12093d9..4e525d67d148 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed) ### Client -- +- Enhance: 絵文字のオートコンプリート機能強化 #12364 ### Server - From be47404bb2ebd6728d6bd9abe4fcc8e193969eb2 Mon Sep 17 00:00:00 2001 From: osamu <46447427+sam-osamu@users.noreply.github.com> Date: Wed, 22 Nov 2023 23:34:54 +0900 Subject: [PATCH 3/3] =?UTF-8?q?for=20of=20=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkAutocomplete.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 2881c78781de..a0f49611160b 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -295,7 +295,7 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30): const queryChars = [...query]; const hitEmojis = new Map(); - emojiDb.forEach(x => { + for (const x of emojiDb) { // クエリ文字列の1文字単位で絵文字名にヒットするかを見る // ただし、過剰に検出されるのを防ぐためクエリ文字列に登場する順番で絵文字名を走査する @@ -314,7 +314,7 @@ function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30): if (queryCharHitCount > 2) { hitEmojis.set(x.name, { emoji: x, score: queryCharHitCount }); } - }); + } // ヒットしたものを全部追加すると雑多になるので、先頭の6件程度だけにしておく(6件=オートコンプリートのポップアップのサイズ分) [...hitEmojis.values()]