[Glitch] Emojis: Fix bug with search + improve custom tokenization
Port c39072ad9d2b531a04c0192f06018fbd8d737f69 to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
6dd792091d
commit
f6cf58039c
@ -1,5 +1,8 @@
|
|||||||
import type { ApiCustomEmojiJSON } from '@/flavours/glitch/api_types/custom_emoji';
|
import type { ApiCustomEmojiJSON } from '@/flavours/glitch/api_types/custom_emoji';
|
||||||
import { loadCustomEmoji } from '@/flavours/glitch/features/emoji';
|
import { loadCustomEmoji } from '@/flavours/glitch/features/emoji';
|
||||||
|
import { emojiLogger } from '@/flavours/glitch/features/emoji/utils';
|
||||||
|
|
||||||
|
const log = emojiLogger('actions');
|
||||||
|
|
||||||
export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) {
|
export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) {
|
||||||
if (emojis.length === 0) {
|
if (emojis.length === 0) {
|
||||||
@ -18,5 +21,11 @@ export async function importCustomEmoji(emojis: ApiCustomEmojiJSON[]) {
|
|||||||
if (existingEmojis.length < emojis.length) {
|
if (existingEmojis.length < emojis.length) {
|
||||||
await clearCache('custom');
|
await clearCache('custom');
|
||||||
await loadCustomEmoji();
|
await loadCustomEmoji();
|
||||||
|
|
||||||
|
const { reloadCustomEmojis } =
|
||||||
|
await import('@/flavours/glitch/features/emoji/picker');
|
||||||
|
await reloadCustomEmojis();
|
||||||
|
|
||||||
|
log('Custom emojis updated, reloaded cache and picker data.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,13 +85,16 @@ export async function search({
|
|||||||
// Only query the range for the last token to allow partial matches.
|
// Only query the range for the last token to allow partial matches.
|
||||||
const range =
|
const range =
|
||||||
i === queryTokens.length - 1
|
i === queryTokens.length - 1
|
||||||
? IDBKeyRange.bound(token, token + '\uffff')
|
? IDBKeyRange.lowerBound(token)
|
||||||
: IDBKeyRange.only(token);
|
: IDBKeyRange.only(token);
|
||||||
|
|
||||||
const [unicodeResults, customResults] = await Promise.all([
|
const [unicodeResults, customResults, shortcodeResults] = await Promise.all(
|
||||||
db.getAllFromIndex(locale, 'tokens', range),
|
[
|
||||||
db.getAllFromIndex('custom', 'tokens', range),
|
db.getAllFromIndex(locale, 'tokens', range),
|
||||||
]);
|
db.getAllFromIndex('custom', 'tokens', range),
|
||||||
|
db.getAllFromIndex('shortcodes', 'shortcodes', range),
|
||||||
|
],
|
||||||
|
);
|
||||||
const resultMap: ScoreMap = new Map();
|
const resultMap: ScoreMap = new Map();
|
||||||
for (const emoji of unicodeResults) {
|
for (const emoji of unicodeResults) {
|
||||||
const score = getScoreForEmoji(emoji, token);
|
const score = getScoreForEmoji(emoji, token);
|
||||||
@ -107,6 +110,22 @@ export async function search({
|
|||||||
}
|
}
|
||||||
resultMap.set(emoji.shortcode, { ...emoji, score });
|
resultMap.set(emoji.shortcode, { ...emoji, score });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const shortcodeResult of shortcodeResults) {
|
||||||
|
if (resultMap.has(shortcodeResult.hexcode)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const emoji = await db.get(locale, shortcodeResult.hexcode);
|
||||||
|
if (!emoji) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const score = getScoreForEmoji(emoji, token);
|
||||||
|
if (score === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
resultMap.set(emoji.hexcode, { ...emoji, score });
|
||||||
|
}
|
||||||
|
|
||||||
log('found %d results for token "%s"', resultMap.size, token);
|
log('found %d results for token "%s"', resultMap.size, token);
|
||||||
resultArrays.push(resultMap);
|
resultArrays.push(resultMap);
|
||||||
}
|
}
|
||||||
@ -147,7 +166,7 @@ function getScoreForEmoji(emoji: AnyEmojiData, query: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let index = 1;
|
let index = 1;
|
||||||
for (const token of [id, emoji.tokens]) {
|
for (const token of [id, ...emoji.tokens]) {
|
||||||
const tokenIndex = token.indexOf(query);
|
const tokenIndex = token.indexOf(query);
|
||||||
if (tokenIndex !== -1) {
|
if (tokenIndex !== -1) {
|
||||||
return index + tokenIndex / token.length;
|
return index + tokenIndex / token.length;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { initialState } from '@/flavours/glitch/initial_state';
|
|||||||
|
|
||||||
import type { EMOJI_DB_NAME_SHORTCODES } from './constants';
|
import type { EMOJI_DB_NAME_SHORTCODES } from './constants';
|
||||||
import { toSupportedLocale } from './locale';
|
import { toSupportedLocale } from './locale';
|
||||||
|
import { reloadCustomEmojis } from './picker';
|
||||||
import type { LocaleOrCustom } from './types';
|
import type { LocaleOrCustom } from './types';
|
||||||
import { emojiLogger } from './utils';
|
import { emojiLogger } from './utils';
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ export async function loadCustomEmoji() {
|
|||||||
const emojis = await importCustomEmojiData();
|
const emojis = await importCustomEmojiData();
|
||||||
if (emojis && emojis.length > 0) {
|
if (emojis && emojis.length > 0) {
|
||||||
log('loaded %d custom emojis', emojis.length);
|
log('loaded %d custom emojis', emojis.length);
|
||||||
|
await reloadCustomEmojis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import {
|
|||||||
EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE,
|
EMOJIS_REQUIRING_INVERSION_IN_DARK_MODE,
|
||||||
EMOJI_MIN_TOKEN_LENGTH,
|
EMOJI_MIN_TOKEN_LENGTH,
|
||||||
} from './constants';
|
} from './constants';
|
||||||
|
import { localeToSegmenter } from './locale';
|
||||||
import type {
|
import type {
|
||||||
CustomEmojiData,
|
CustomEmojiData,
|
||||||
CustomEmojiMapArg,
|
CustomEmojiMapArg,
|
||||||
@ -92,10 +93,11 @@ export function transformEmojiData(
|
|||||||
export function transformCustomEmojiData(
|
export function transformCustomEmojiData(
|
||||||
emoji: ApiCustomEmojiJSON,
|
emoji: ApiCustomEmojiJSON,
|
||||||
): CustomEmojiData {
|
): CustomEmojiData {
|
||||||
const tokens = emoji.shortcode
|
const tokens = extractTokens(emoji.shortcode, localeToSegmenter('en'));
|
||||||
.split('_')
|
if (!tokens.includes(emoji.shortcode)) {
|
||||||
.filter((word) => word.length >= EMOJI_MIN_TOKEN_LENGTH)
|
tokens.unshift(emoji.shortcode);
|
||||||
.map((word) => word.toLowerCase());
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...emoji,
|
...emoji,
|
||||||
tokens,
|
tokens,
|
||||||
@ -215,7 +217,9 @@ export function extractTokens(
|
|||||||
// Prefer to use Intl.Segmenter if available for better locale support.
|
// Prefer to use Intl.Segmenter if available for better locale support.
|
||||||
if (segmenter) {
|
if (segmenter) {
|
||||||
for (const { isWordLike, segment } of segmenter.segment(
|
for (const { isWordLike, segment } of segmenter.segment(
|
||||||
input.replaceAll('_', ' '), // Handle underscores from shortcodes.
|
input
|
||||||
|
.replaceAll(/[_-]+/g, ' ') // Handle underscores from shortcodes.
|
||||||
|
.replaceAll(/([a-z])([A-Z])/g, '$1 $2'), // Handle camelCase.
|
||||||
)) {
|
)) {
|
||||||
if (isWordLike && segment.length >= EMOJI_MIN_TOKEN_LENGTH) {
|
if (isWordLike && segment.length >= EMOJI_MIN_TOKEN_LENGTH) {
|
||||||
tokens.push(segment.toLowerCase());
|
tokens.push(segment.toLowerCase());
|
||||||
|
|||||||
@ -82,13 +82,22 @@ type LegacyEmoji =
|
|||||||
custom: true;
|
custom: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function reloadCustomEmojis() {
|
||||||
|
customEmojis = null;
|
||||||
|
|
||||||
|
const { loadEmojisIntoCache } =
|
||||||
|
await import('@/flavours/glitch/hooks/useCustomEmojis');
|
||||||
|
|
||||||
|
await Promise.all([fetchCustomEmojiData(), loadEmojisIntoCache()]);
|
||||||
|
}
|
||||||
|
|
||||||
// Replicates the old legacy search function.
|
// Replicates the old legacy search function.
|
||||||
export async function emojiMartSearch(
|
export async function emojiMartSearch(
|
||||||
token: string,
|
token: string,
|
||||||
locale: string,
|
locale: string,
|
||||||
limit = 5,
|
limit = 5,
|
||||||
): Promise<LegacyEmoji[]> {
|
): Promise<LegacyEmoji[]> {
|
||||||
const query = token.replace(':', '').toLowerCase().trim();
|
const query = token.replace(':', '').trim();
|
||||||
if (!query.length) {
|
if (!query.length) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ export function useCustomEmojis() {
|
|||||||
return emojis;
|
return emojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadEmojisIntoCache() {
|
export async function loadEmojisIntoCache() {
|
||||||
const { loadAllCustomEmoji } = await import('../features/emoji/database');
|
const { loadAllCustomEmoji } = await import('../features/emoji/database');
|
||||||
const emojisRaw = await loadAllCustomEmoji();
|
const emojisRaw = await loadAllCustomEmoji();
|
||||||
if (emojisRaw === null) {
|
if (emojisRaw === null) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user