diff options
| author | Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> | 2025-08-13 10:51:23 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-08-13 10:51:23 +0900 |
| commit | 7bb43329bb20ee203020634d5df9e6a896b437da (patch) | |
| tree | b918123f0829a016d69489560c878595950535e0 /packages/frontend | |
| parent | Update CHANGELOG.md (diff) | |
| download | misskey-7bb43329bb20ee203020634d5df9e6a896b437da.tar.gz misskey-7bb43329bb20ee203020634d5df9e6a896b437da.tar.bz2 misskey-7bb43329bb20ee203020634d5df9e6a896b437da.zip | |
fix(frontend): メンション補完のためのサジェストが正しく表示されない問題を修正 (#16401)
* fix(frontend): mention-syntax detection for autocomplete doesn't work properly
* docs(changelog): update changelog
Diffstat (limited to 'packages/frontend')
| -rw-r--r-- | packages/frontend/src/utility/autocomplete.ts | 36 |
1 files changed, 23 insertions, 13 deletions
diff --git a/packages/frontend/src/utility/autocomplete.ts b/packages/frontend/src/utility/autocomplete.ts index 1246c32554..82109af1a0 100644 --- a/packages/frontend/src/utility/autocomplete.ts +++ b/packages/frontend/src/utility/autocomplete.ts @@ -78,7 +78,10 @@ export class Autocomplete { const caretPos = Number(this.textarea.selectionStart); const text = this.text.substring(0, caretPos).split('\n').pop()!; - const mentionIndex = text.lastIndexOf('@'); + // メンションに含められる文字のみで構成された、最も末尾にある文字列を抽出 + const mentionCandidate = text.split(/[^a-zA-Z0-9_@.\-]+/).pop()!; + + const mentionIndex = mentionCandidate.lastIndexOf('@'); const hashtagIndex = text.lastIndexOf('#'); const emojiIndex = text.lastIndexOf(':'); const mfmTagIndex = text.lastIndexOf('$'); @@ -97,7 +100,7 @@ export class Autocomplete { const afterLastMfmParam = text.split(/\$\[[a-zA-Z]+/).pop(); - const isMention = mentionIndex !== -1; + const maybeMention = mentionIndex !== -1; const isHashtag = hashtagIndex !== -1; const isMfmParam = mfmParamIndex !== -1 && afterLastMfmParam?.includes('.') && !afterLastMfmParam.includes(' '); const isMfmTag = mfmTagIndex !== -1 && !isMfmParam; @@ -107,20 +110,27 @@ export class Autocomplete { let opened = false; - if (isMention && this.onlyType.includes('user')) { + if (maybeMention && this.onlyType.includes('user')) { // ユーザのサジェスト中に@を入力すると、その位置から新たにユーザ名を取りなおそうとしてしまう // この動きはリモートユーザのサジェストを阻害するので、@を検知したらその位置よりも前の@を探し、 // ホスト名を含むリモートのユーザ名を全て拾えるようにする - const mentionIndexAlt = text.lastIndexOf('@', mentionIndex - 1); - const username = mentionIndexAlt === -1 - ? text.substring(mentionIndex + 1) - : text.substring(mentionIndexAlt + 1); - if (username !== '' && username.match(/^[a-zA-Z0-9_@.]+$/)) { - this.open('user', username); - opened = true; - } else if (username === '') { - this.open('user', null); - opened = true; + const mentionIndexAlt = mentionCandidate.lastIndexOf('@', mentionIndex - 1); + + // @が連続している場合、1つ目を無視する + const mentionIndexLeft = (mentionIndexAlt !== -1 && mentionIndexAlt !== mentionIndex - 1) ? mentionIndexAlt : mentionIndex; + + // メンションを構成する条件を満たしているか確認する + const isMention = mentionIndexLeft === 0 || '_@.-'.includes(mentionCandidate[mentionIndexLeft - 1]); + + if (isMention) { + const username = mentionCandidate.substring(mentionIndexLeft + 1); + if (username !== '' && username.match(/^[a-zA-Z0-9_@.\-]+$/)) { + this.open('user', username); + opened = true; + } else if (username === '') { + this.open('user', null); + opened = true; + } } } |