mirror of https://github.com/zulip/zulip.git
typeahead: Add typescript type definitions for typeahead.
This allows us to import typeahead from people.ts with types. This is possible since #22586 was merged. And since "sort_emojis" is always supposed to be called with valid emoji objects that have "reaction_type" with an optional "emoji_code", we add a check before we see if the emoji is popular to avoid poking popular_set with an undefined value. Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
parent
9808bdf1d3
commit
53aa3f6c71
|
@ -28,7 +28,23 @@ export const popular_emojis = [
|
||||||
|
|
||||||
const unicode_marks = /\p{M}/gu;
|
const unicode_marks = /\p{M}/gu;
|
||||||
|
|
||||||
export function remove_diacritics(s) {
|
type Emoji =
|
||||||
|
| {
|
||||||
|
emoji_name: string;
|
||||||
|
reaction_type: "realm_emoji" | "zulip_extra_emoji";
|
||||||
|
is_realm_emoji: true;
|
||||||
|
}
|
||||||
|
| UnicodeEmoji;
|
||||||
|
|
||||||
|
// emoji_code is only available for unicode emojis.
|
||||||
|
type UnicodeEmoji = {
|
||||||
|
emoji_name: string;
|
||||||
|
emoji_code: string;
|
||||||
|
reaction_type: "unicode_emoji";
|
||||||
|
is_realm_emoji: false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function remove_diacritics(s: string): string {
|
||||||
return s.normalize("NFKD").replace(unicode_marks, "");
|
return s.normalize("NFKD").replace(unicode_marks, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +52,11 @@ export function remove_diacritics(s) {
|
||||||
// * query is the user-entered search query
|
// * query is the user-entered search query
|
||||||
// * source_str is the string we're matching in, e.g. a user's name
|
// * source_str is the string we're matching in, e.g. a user's name
|
||||||
// * split_char is the separator for this syntax (e.g. ' ').
|
// * split_char is the separator for this syntax (e.g. ' ').
|
||||||
export function query_matches_string(query, source_str, split_char) {
|
export function query_matches_string(
|
||||||
|
query: string,
|
||||||
|
source_str: string,
|
||||||
|
split_char: string,
|
||||||
|
): boolean {
|
||||||
source_str = source_str.toLowerCase();
|
source_str = source_str.toLowerCase();
|
||||||
source_str = remove_diacritics(source_str);
|
source_str = remove_diacritics(source_str);
|
||||||
|
|
||||||
|
@ -53,7 +73,7 @@ export function query_matches_string(query, source_str, split_char) {
|
||||||
return source_str.startsWith(query) || source_str.includes(split_char + query);
|
return source_str.startsWith(query) || source_str.includes(split_char + query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clean_query(query) {
|
function clean_query(query: string): string {
|
||||||
query = remove_diacritics(query);
|
query = remove_diacritics(query);
|
||||||
// When `abc ` with a space at the end is typed in a
|
// When `abc ` with a space at the end is typed in a
|
||||||
// contenteditable widget such as the composebox PM section, the
|
// contenteditable widget such as the composebox PM section, the
|
||||||
|
@ -64,19 +84,19 @@ function clean_query(query) {
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clean_query_lowercase(query) {
|
export function clean_query_lowercase(query: string): string {
|
||||||
query = query.toLowerCase();
|
query = query.toLowerCase();
|
||||||
query = clean_query(query);
|
query = clean_query(query);
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const parse_unicode_emoji_code = (code) =>
|
export const parse_unicode_emoji_code = (code: string): string =>
|
||||||
code
|
code
|
||||||
.split("-")
|
.split("-")
|
||||||
.map((hex) => String.fromCodePoint(Number.parseInt(hex, 16)))
|
.map((hex) => String.fromCodePoint(Number.parseInt(hex, 16)))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
export function get_emoji_matcher(query) {
|
export function get_emoji_matcher(query: string): (emoji: Emoji) => boolean {
|
||||||
// replace spaces with underscores for emoji matching
|
// replace spaces with underscores for emoji matching
|
||||||
query = query.replace(/ /g, "_");
|
query = query.replace(/ /g, "_");
|
||||||
query = clean_query_lowercase(query);
|
query = clean_query_lowercase(query);
|
||||||
|
@ -89,7 +109,11 @@ export function get_emoji_matcher(query) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function triage(query, objs, get_item) {
|
export function triage<T>(
|
||||||
|
query: string,
|
||||||
|
objs: T[],
|
||||||
|
get_item: (x: T) => string,
|
||||||
|
): {matches: T[]; rest: T[]} {
|
||||||
/*
|
/*
|
||||||
We split objs into four groups:
|
We split objs into four groups:
|
||||||
|
|
||||||
|
@ -128,20 +152,24 @@ export function triage(query, objs, get_item) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function sort_emojis(objs, query) {
|
export function sort_emojis<T extends Emoji>(objs: T[], query: string): T[] {
|
||||||
// replace spaces with underscores for emoji matching
|
// replace spaces with underscores for emoji matching
|
||||||
query = query.replace(/ /g, "_");
|
query = query.replace(/ /g, "_");
|
||||||
query = query.toLowerCase();
|
query = query.toLowerCase();
|
||||||
|
|
||||||
function decent_match(name) {
|
function decent_match(name: string): boolean {
|
||||||
const pieces = name.toLowerCase().split("_");
|
const pieces = name.toLowerCase().split("_");
|
||||||
return pieces.some((piece) => piece.startsWith(query));
|
return pieces.some((piece) => piece.startsWith(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
const popular_set = new Set(popular_emojis);
|
const popular_set = new Set(popular_emojis);
|
||||||
|
|
||||||
function is_popular(obj) {
|
function is_popular(obj: Emoji): boolean {
|
||||||
return popular_set.has(obj.emoji_code) && decent_match(obj.emoji_name);
|
return (
|
||||||
|
obj.reaction_type === "unicode_emoji" &&
|
||||||
|
popular_set.has(obj.emoji_code) &&
|
||||||
|
decent_match(obj.emoji_name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const realm_emoji_names = new Set(
|
const realm_emoji_names = new Set(
|
||||||
|
@ -153,7 +181,7 @@ export function sort_emojis(objs, query) {
|
||||||
|
|
||||||
const triage_results = triage(query, others, (x) => x.emoji_name);
|
const triage_results = triage(query, others, (x) => x.emoji_name);
|
||||||
|
|
||||||
function prioritise_realm_emojis(emojis) {
|
function prioritise_realm_emojis(emojis: T[]): T[] {
|
||||||
return [
|
return [
|
||||||
...emojis.filter((emoji) => emoji.is_realm_emoji),
|
...emojis.filter((emoji) => emoji.is_realm_emoji),
|
||||||
...emojis.filter((emoji) => !emoji.is_realm_emoji),
|
...emojis.filter((emoji) => !emoji.is_realm_emoji),
|
||||||
|
@ -168,7 +196,7 @@ export function sort_emojis(objs, query) {
|
||||||
// remove unicode emojis with same code but different names
|
// remove unicode emojis with same code but different names
|
||||||
// and unicode emojis overridden by realm emojis with same names
|
// and unicode emojis overridden by realm emojis with same names
|
||||||
const unicode_emoji_codes = new Set();
|
const unicode_emoji_codes = new Set();
|
||||||
const sorted_unique_results = [];
|
const sorted_unique_results: T[] = [];
|
||||||
for (const emoji of sorted_results_with_possible_duplicates) {
|
for (const emoji of sorted_results_with_possible_duplicates) {
|
||||||
if (emoji.reaction_type !== "unicode_emoji") {
|
if (emoji.reaction_type !== "unicode_emoji") {
|
||||||
sorted_unique_results.push(emoji);
|
sorted_unique_results.push(emoji);
|
Loading…
Reference in New Issue