summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorかっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>2026-01-08 21:08:27 +0900
committerGitHub <noreply@github.com>2026-01-08 21:08:27 +0900
commitece4efcefedc3ef095f8683db868d64645811893 (patch)
treea5b5fe0493a714e8e0b6ccaafcf47fa22676d36a /packages
parentfix(frontend): 2月29日を誕生日に設定している場合、平年は3... (diff)
downloadmisskey-ece4efcefedc3ef095f8683db868d64645811893.tar.gz
misskey-ece4efcefedc3ef095f8683db868d64645811893.tar.bz2
misskey-ece4efcefedc3ef095f8683db868d64645811893.zip
fix(frontend): mfmFunctionPickerを使用して挿入する際のハンドリングを改善 (#17018)
* fix(frontend): mfmFunctionPickerを使用して絵文字を挿入する際のハンドリングを改善 * fix * Update MkPostForm.vue * Update Changelog --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
Diffstat (limited to 'packages')
-rw-r--r--packages/frontend/src/components/MkPostForm.vue30
-rw-r--r--packages/frontend/src/os.ts2
-rw-r--r--packages/frontend/src/utility/mfm-function-picker.ts48
3 files changed, 39 insertions, 41 deletions
diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue
index 4b027cf105..9734b51927 100644
--- a/packages/frontend/src/components/MkPostForm.vue
+++ b/packages/frontend/src/components/MkPostForm.vue
@@ -1166,17 +1166,41 @@ async function insertEmoji(ev: MouseEvent) {
},
() => {
textAreaReadOnly.value = false;
- nextTick(() => focus());
+ nextTick(() => {
+ if (textareaEl.value) {
+ textareaEl.value.focus();
+ textareaEl.value.setSelectionRange(pos, posEnd);
+ }
+ });
},
);
}
async function insertMfmFunction(ev: MouseEvent) {
if (textareaEl.value == null) return;
+ let pos = textareaEl.value.selectionStart ?? 0;
+ let posEnd = textareaEl.value.selectionEnd ?? text.value.length;
mfmFunctionPicker(
ev.currentTarget ?? ev.target,
- textareaEl.value,
- text,
+ (tag) => {
+ if (pos === posEnd) {
+ text.value = `${text.value.substring(0, pos)}$[${tag} ]${text.value.substring(pos)}`;
+ pos += tag.length + 3;
+ posEnd = pos;
+ } else {
+ text.value = `${text.value.substring(0, pos)}$[${tag} ${text.value.substring(pos, posEnd)}]${text.value.substring(posEnd)}`;
+ pos += tag.length + 3;
+ posEnd = pos;
+ }
+ },
+ () => {
+ nextTick(() => {
+ if (textareaEl.value) {
+ textareaEl.value.focus();
+ textareaEl.value.setSelectionRange(pos, posEnd);
+ }
+ });
+ },
);
}
diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts
index c1390e8274..3fb204c2b2 100644
--- a/packages/frontend/src/os.ts
+++ b/packages/frontend/src/os.ts
@@ -654,6 +654,7 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen
align?: string;
width?: number;
onClosing?: () => void;
+ onClosed?: () => void;
}): Promise<void> {
if (!(anchorElement instanceof HTMLElement)) {
anchorElement = null;
@@ -672,6 +673,7 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen
resolve();
dispose();
returnFocusTo = null;
+ options?.onClosed?.();
},
closing: () => {
options?.onClosing?.();
diff --git a/packages/frontend/src/utility/mfm-function-picker.ts b/packages/frontend/src/utility/mfm-function-picker.ts
index 09802d580b..5580435db1 100644
--- a/packages/frontend/src/utility/mfm-function-picker.ts
+++ b/packages/frontend/src/utility/mfm-function-picker.ts
@@ -3,55 +3,27 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
-import { nextTick } from 'vue';
import { MFM_TAGS } from '@@/js/const.js';
-import type { Ref } from 'vue';
-import type { MenuItem } from '@/types/menu.js';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
/**
* MFMの装飾のリストを表示する
*/
-export function mfmFunctionPicker(anchorElement: HTMLElement | EventTarget | null, textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>) {
+export function mfmFunctionPicker(anchorElement: HTMLElement | EventTarget | null, onChosen: (tag: string) => void, onClosed?: () => void) {
os.popupMenu([{
text: i18n.ts.addMfmFunction,
type: 'label',
- }, ...getFunctionList(textArea, textRef)], anchorElement);
-}
-
-function getFunctionList(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>): MenuItem[] {
- return MFM_TAGS.map(tag => ({
+ }, ...MFM_TAGS.map(tag => ({
text: tag,
icon: 'ti ti-icons',
- action: () => add(textArea, textRef, tag),
- }));
-}
-
-function add(textArea: HTMLInputElement | HTMLTextAreaElement, textRef: Ref<string>, type: string) {
- const caretStart: number = textArea.selectionStart as number;
- const caretEnd: number = textArea.selectionEnd as number;
-
- MFM_TAGS.forEach(tag => {
- if (type === tag) {
- if (caretStart === caretEnd) {
- // 単純にFunctionを追加
- const trimmedText = `${textRef.value.substring(0, caretStart)}$[${type} ]${textRef.value.substring(caretEnd)}`;
- textRef.value = trimmedText;
- } else {
- // 選択範囲を囲むようにFunctionを追加
- const trimmedText = `${textRef.value.substring(0, caretStart)}$[${type} ${textRef.value.substring(caretStart, caretEnd)}]${textRef.value.substring(caretEnd)}`;
- textRef.value = trimmedText;
- }
- }
- });
-
- const nextCaretStart: number = caretStart + 3 + type.length;
- const nextCaretEnd: number = caretEnd + 3 + type.length;
-
- // キャレットを戻す
- nextTick(() => {
- textArea.focus();
- textArea.setSelectionRange(nextCaretStart, nextCaretEnd);
+ action: () => {
+ onChosen(tag);
+ },
+ }))], anchorElement, {
+ onClosed: () => {
+ if (onClosed) onClosed();
+ },
});
}
+