Enhance(frontend): MFMの属性にオートコンプリートが利用できるように (#12803)
* MFMのパラメータでオートコンプリートできるように * tweak conditions & refactor * ファイル末尾の改行忘れ * remove console.log & refactor * 型付けに敗北 * fix * update CHANGELOG.md * tweak conditions * CHANGELOGの様式ミス * CHANGELOGを書く場所を間違えていたので修正 * move changelog * move changelog * typeof MFM_TAGS[number] Co-authored-by: syuilo <Syuilotan@yahoo.co.jp> * $[border.noclip ]対応 * Update const.ts --------- Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
@@ -8,13 +8,13 @@ import getCaretCoordinates from 'textarea-caret';
|
||||
import { toASCII } from 'punycode/';
|
||||
import { popup } from '@/os.js';
|
||||
|
||||
export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag';
|
||||
export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag' | 'mfmParam';
|
||||
|
||||
export class Autocomplete {
|
||||
private suggestion: {
|
||||
x: Ref<number>;
|
||||
y: Ref<number>;
|
||||
q: Ref<string | null>;
|
||||
q: Ref<any>;
|
||||
close: () => void;
|
||||
} | null;
|
||||
private textarea: HTMLInputElement | HTMLTextAreaElement;
|
||||
@@ -49,7 +49,7 @@ export class Autocomplete {
|
||||
this.textarea = textarea;
|
||||
this.textRef = textRef;
|
||||
this.opening = false;
|
||||
this.onlyType = onlyType ?? ['user', 'hashtag', 'emoji', 'mfmTag'];
|
||||
this.onlyType = onlyType ?? ['user', 'hashtag', 'emoji', 'mfmTag', 'mfmParam'];
|
||||
|
||||
this.attach();
|
||||
}
|
||||
@@ -80,6 +80,7 @@ export class Autocomplete {
|
||||
const hashtagIndex = text.lastIndexOf('#');
|
||||
const emojiIndex = text.lastIndexOf(':');
|
||||
const mfmTagIndex = text.lastIndexOf('$');
|
||||
const mfmParamIndex = text.lastIndexOf('.');
|
||||
|
||||
const max = Math.max(
|
||||
mentionIndex,
|
||||
@@ -94,7 +95,8 @@ export class Autocomplete {
|
||||
|
||||
const isMention = mentionIndex !== -1;
|
||||
const isHashtag = hashtagIndex !== -1;
|
||||
const isMfmTag = mfmTagIndex !== -1;
|
||||
const isMfmParam = mfmParamIndex !== -1 && text.split(/\$\[[a-zA-Z]+/).pop()?.includes('.');
|
||||
const isMfmTag = mfmTagIndex !== -1 && !isMfmParam;
|
||||
const isEmoji = emojiIndex !== -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':');
|
||||
|
||||
let opened = false;
|
||||
@@ -134,6 +136,17 @@ export class Autocomplete {
|
||||
}
|
||||
}
|
||||
|
||||
if (isMfmParam && !opened && this.onlyType.includes('mfmParam')) {
|
||||
const mfmParam = text.substring(mfmParamIndex + 1);
|
||||
if (!mfmParam.includes(' ')) {
|
||||
this.open('mfmParam', {
|
||||
tag: text.substring(mfmTagIndex + 2, mfmParamIndex),
|
||||
params: mfmParam.split(','),
|
||||
});
|
||||
opened = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!opened) {
|
||||
this.close();
|
||||
}
|
||||
@@ -142,7 +155,7 @@ export class Autocomplete {
|
||||
/**
|
||||
* サジェストを提示します。
|
||||
*/
|
||||
private async open(type: string, q: string | null) {
|
||||
private async open(type: string, q: any) {
|
||||
if (type !== this.currentType) {
|
||||
this.close();
|
||||
}
|
||||
@@ -280,6 +293,22 @@ export class Autocomplete {
|
||||
const pos = trimmedBefore.length + (value.length + 3);
|
||||
this.textarea.setSelectionRange(pos, pos);
|
||||
});
|
||||
} else if (type === 'mfmParam') {
|
||||
const source = this.text;
|
||||
|
||||
const before = source.substring(0, caret);
|
||||
const trimmedBefore = before.substring(0, before.lastIndexOf('.'));
|
||||
const after = source.substring(caret);
|
||||
|
||||
// 挿入
|
||||
this.text = `${trimmedBefore}.${value}${after}`;
|
||||
|
||||
// キャレットを戻す
|
||||
nextTick(() => {
|
||||
this.textarea.focus();
|
||||
const pos = trimmedBefore.length + (value.length + 1);
|
||||
this.textarea.setSelectionRange(pos, pos);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user