enhance(client): update emoji picker immediately on all input (#9385)

* enhance: update emoji picker immediately on all input

* refactor: remove reference to window.clipboardData

* refactor: done() receives a string

* refactor: typescript-favored `.char` access
This commit is contained in:
Kagami Sascha Rosylight 2022-12-22 14:28:13 +09:00 committed by GitHub
parent aa23dbbb8a
commit 69087f2242
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 20 additions and 9 deletions

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }"> <div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
<input ref="search" v-model.trim="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @paste.stop="paste" @keyup.enter="done()"> <input ref="search" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keyup.enter="done()">
<div ref="emojis" class="emojis"> <div ref="emojis" class="emojis">
<section class="result"> <section class="result">
<div v-if="searchResultCustom.length > 0" class="body"> <div v-if="searchResultCustom.length > 0" class="body">
@ -121,7 +121,7 @@ const width = computed(() => props.asReactionPicker ? reactionPickerWidth.value
const height = computed(() => props.asReactionPicker ? reactionPickerHeight.value : 2); const height = computed(() => props.asReactionPicker ? reactionPickerHeight.value : 2);
const customEmojiCategories = emojiCategories; const customEmojiCategories = emojiCategories;
const customEmojis = instance.emojis; const customEmojis = instance.emojis;
const q = ref<string | null>(null); const q = ref<string>('');
const searchResultCustom = ref<Misskey.entities.CustomEmoji[]>([]); const searchResultCustom = ref<Misskey.entities.CustomEmoji[]>([]);
const searchResultUnicode = ref<UnicodeEmojiDef[]>([]); const searchResultUnicode = ref<UnicodeEmojiDef[]>([]);
const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index'); const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index');
@ -129,7 +129,7 @@ const tab = ref<'index' | 'custom' | 'unicode' | 'tags'>('index');
watch(q, () => { watch(q, () => {
if (emojis.value) emojis.value.scrollTop = 0; if (emojis.value) emojis.value.scrollTop = 0;
if (q.value == null || q.value === '') { if (q.value === '') {
searchResultCustom.value = []; searchResultCustom.value = [];
searchResultUnicode.value = []; searchResultUnicode.value = [];
return; return;
@ -281,7 +281,7 @@ function reset() {
} }
function getKey(emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef): string { function getKey(emoji: string | Misskey.entities.CustomEmoji | UnicodeEmojiDef): string {
return typeof emoji === 'string' ? emoji : (emoji.char || `:${emoji.name}:`); return typeof emoji === 'string' ? emoji : 'char' in emoji ? emoji.char : `:${emoji.name}:`;
} }
function chosen(emoji: any, ev?: MouseEvent) { function chosen(emoji: any, ev?: MouseEvent) {
@ -305,14 +305,21 @@ function chosen(emoji: any, ev?: MouseEvent) {
} }
} }
function paste(event: ClipboardEvent) { function input(): void {
const paste = (event.clipboardData || window.clipboardData).getData('text'); // Using custom input event instead of v-model to respond immediately on
if (done(paste)) { // Android, where composition happens on all languages
// (v-model does not update during composition)
q.value = search.value?.value.trim() ?? '';
}
function paste(event: ClipboardEvent): void {
const pasted = event.clipboardData?.getData('text') ?? '';
if (done(pasted)) {
event.preventDefault(); event.preventDefault();
} }
} }
function done(query?: any): boolean | void { function done(query?: string): boolean | void {
if (query == null) query = q.value; if (query == null) query = q.value;
if (query == null || typeof query !== 'string') return; if (query == null || typeof query !== 'string') return;

View file

@ -16,10 +16,14 @@ export class Autocomplete {
private opening: boolean; private opening: boolean;
private get text(): string { private get text(): string {
return this.textRef.value; // Use raw .value to get the latest value
// (Because v-model does not update while composition)
return this.textarea.value;
} }
private set text(text: string) { private set text(text: string) {
// Use ref value to notify other watchers
// (Because .value setter never fires input/change events)
this.textRef.value = text; this.textRef.value = text;
} }