import {getRandom, isMobile} from "../util/functions";
import {fetchPost} from "../util/fetch";
import {hasClosestByClassName} from "../protyle/util/hasClosest";
import {Constants} from "../constants";
import {Files} from "../layout/dock/Files";
/// #if !MOBILE
import {getDockByType} from "../layout/tabUtil";
import {getAllModels} from "../layout/getAll";
/// #endif
import {setNoteBook} from "../util/pathName";
import {Dialog} from "../dialog";
import {setPosition} from "../util/setPosition";
export const getRandomEmoji = () => {
const emojis = window.siyuan.emojis[getRandom(0, window.siyuan.emojis.length - 1)];
if (typeof emojis.items[getRandom(0, emojis.items.length - 1)] === "undefined") {
return "1f600";
}
return emojis.items[getRandom(0, emojis.items.length - 1)].unicode;
};
export const unicode2Emoji = (unicode: string, className = "", needSpan = false, lazy = false) => {
if (!unicode) {
return "";
}
let emoji = "";
if (unicode.indexOf(".") > -1) {
emoji = `
`;
} else {
try {
unicode.split("-").forEach(item => {
if (item.length < 5) {
emoji += String.fromCodePoint(parseInt("0" + item, 16));
} else {
emoji += String.fromCodePoint(parseInt(item, 16));
}
});
if (needSpan) {
emoji = `${emoji}`;
}
} catch (e) {
// 自定义表情搜索报错 https://github.com/siyuan-note/siyuan/issues/5883
// 这里忽略错误不做处理
}
}
return emoji;
};
export const lazyLoadEmoji = (element: HTMLElement) => {
const emojiIntersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entrie: IntersectionObserverEntry & { target: HTMLImageElement }) => {
const index = entrie.target.getAttribute("data-index");
if ((typeof entrie.isIntersecting === "undefined" ? entrie.intersectionRatio !== 0 : entrie.isIntersecting) && index) {
let html = "";
window.siyuan.emojis[parseInt(index)].items.forEach(emoji => {
html += ``;
});
entrie.target.innerHTML = html;
entrie.target.removeAttribute("data-index");
}
});
});
element.querySelectorAll(".emojis__content").forEach((panelElement) => {
emojiIntersectionObserver.observe(panelElement);
});
};
export const lazyLoadEmojiImg = (element: Element) => {
const emojiIntersectionObserver = new IntersectionObserver((entries) => {
entries.forEach((entrie: IntersectionObserverEntry & { target: HTMLImageElement }) => {
const src = entrie.target.getAttribute("data-src");
if ((typeof entrie.isIntersecting === "undefined" ? entrie.intersectionRatio !== 0 : entrie.isIntersecting) && src) {
entrie.target.src = src;
entrie.target.removeAttribute("data-src");
}
});
});
element.querySelectorAll("img").forEach((panelElement) => {
emojiIntersectionObserver.observe(panelElement);
});
};
export const filterEmoji = (key = "", max?: number) => {
let html = "";
const recentEmojis: {
unicode: string,
description: string,
description_zh_cn: string,
keywords: string
}[] = [];
if (key) {
html = `
`;
}
let maxCount = 0;
let keyHTML = "";
const customStore: {
unicode: string,
description: string,
description_zh_cn: string,
keywords: string
}[] = [];
window.siyuan.emojis.forEach((category, index) => {
if (!key) {
html += `
${window.siyuan.config.lang === "zh_CN" ? category.title_zh_cn : category.title}
1 ? ' data-index="' + index + '"' : ""}>`;
}
if (category.items.length === 0 && index === 0 && !key) {
html += `
${window.siyuan.languages.setEmojiTip}
`;
}
category.items.forEach(emoji => {
if (key) {
if (window.siyuan.config.editor.emoji.includes(emoji.unicode) &&
(unicode2Emoji(emoji.unicode) === key || emoji.keywords.toLowerCase().indexOf(key.toLowerCase()) > -1 || emoji.description.toLowerCase().indexOf(key.toLowerCase()) > -1 || emoji.description_zh_cn.toLowerCase().indexOf(key.toLowerCase()) > -1)) {
recentEmojis.push(emoji);
}
if (max && maxCount > max) {
return;
}
if (unicode2Emoji(emoji.unicode) === key || emoji.keywords.toLowerCase().indexOf(key.toLowerCase()) > -1 || emoji.description.toLowerCase().indexOf(key.toLowerCase()) > -1 || emoji.description_zh_cn.toLowerCase().indexOf(key.toLowerCase()) > -1) {
if (category.id === "custom") {
customStore.push(emoji);
} else {
keyHTML += `
`;
}
maxCount++;
}
} else {
if (window.siyuan.config.editor.emoji.includes(emoji.unicode)) {
recentEmojis.push(emoji);
}
if (index < 2) {
html += `
`;
}
}
});
if (!key) {
html += "
";
}
});
if (key) {
customStore.sort((a, b) => {
const aKeywords = a.keywords.split("/");
const bKeywords = b.keywords.split("/");
if (aKeywords[aKeywords.length - 1].toLowerCase().indexOf(key.toLowerCase()) < bKeywords[bKeywords.length - 1].toLowerCase().indexOf(key.toLowerCase())) {
return -1;
}
return 0;
}).sort((a, b) => {
const aKeywords = a.keywords.split("/");
const bKeywords = b.keywords.split("/");
if (aKeywords[aKeywords.length - 1].toLowerCase().indexOf(key.toLowerCase()) === bKeywords[bKeywords.length - 1].toLowerCase().indexOf(key.toLowerCase()) && aKeywords[aKeywords.length - 1].length < bKeywords[bKeywords.length - 1].length) {
return -1;
}
return 0;
}).forEach(item => {
html += `
`;
});
html = html + keyHTML + "
";
}
let recentHTML = "";
if (recentEmojis.length > 0) {
recentHTML = ``;
window.siyuan.config.editor.emoji.forEach(emojiUnicode => {
const emoji = recentEmojis.filter((item) => item.unicode === emojiUnicode);
if (emoji[0]) {
recentHTML += ``;
}
});
recentHTML += "
";
}
if (recentHTML + html === "") {
return `
${filterEmoji()}
${unicode2Emoji("2b50")}
${unicode2Emoji("1f527")}
${unicode2Emoji("1f60d")}
${unicode2Emoji("1f433")}
${unicode2Emoji("1f96a")}
${unicode2Emoji("1f3a8")}
${unicode2Emoji("1f3dd-fe0f")}
${unicode2Emoji("1f52e")}
${unicode2Emoji("267e-fe0f")}
${unicode2Emoji("1f6a9")}
`
});
dialog.element.setAttribute("data-key", Constants.DIALOG_EMOJIS);
dialog.element.querySelector(".b3-dialog__container").setAttribute("data-menu", "true");
const dialogElement = dialog.element.querySelector(".b3-dialog") as HTMLElement;
dialogElement.style.justifyContent = "inherit";
dialogElement.style.alignItems = "inherit";
setPosition(dialog.element.querySelector(".b3-dialog__container"), position.x, position.y, position.h, position.w);
dialog.element.querySelector(".emojis__item").classList.add("emojis__item--current");
const inputElement = dialog.element.querySelector(".b3-text-field") as HTMLInputElement;
const emojisContentElement = dialog.element.querySelector(".emojis__panel");
inputElement.addEventListener("compositionend", () => {
emojisContentElement.innerHTML = filterEmoji(inputElement.value);
if (inputElement.value) {
emojisContentElement.nextElementSibling.classList.add("fn__none");
} else {
emojisContentElement.nextElementSibling.classList.remove("fn__none");
}
emojisContentElement.scrollTop = 0;
dialog.element.querySelector(".emojis__item")?.classList.add("emojis__item--current");
if (inputElement.value === "") {
lazyLoadEmoji(dialog.element);
}
lazyLoadEmojiImg(dialog.element);
});
inputElement.addEventListener("input", (event: InputEvent) => {
if (event.isComposing) {
return;
}
emojisContentElement.innerHTML = filterEmoji(inputElement.value);
if (inputElement.value) {
emojisContentElement.nextElementSibling.classList.add("fn__none");
} else {
emojisContentElement.nextElementSibling.classList.remove("fn__none");
}
emojisContentElement.scrollTop = 0;
dialog.element.querySelector(".emojis__item")?.classList.add("emojis__item--current");
if (inputElement.value === "") {
lazyLoadEmoji(dialog.element);
}
lazyLoadEmojiImg(dialog.element);
});
inputElement.addEventListener("keydown", (event: KeyboardEvent) => {
if (event.isComposing) {
return;
}
if (event.key.indexOf("Arrow") === -1 && event.key !== "Enter") {
return;
}
const currentElement = dialog.element.querySelector(".emojis__item--current");
if (!currentElement) {
return;
}
if (event.key === "Enter") {
const unicode = currentElement.getAttribute("data-unicode");
if (type === "notebook") {
fetchPost("/api/notebook/setNotebookIcon", {
notebook: id,
icon: unicode
}, () => {
dialog.destroy();
addEmoji(unicode);
updateFileTreeEmoji(unicode, id, "iconFilesRoot");
});
} else if (type === "doc") {
fetchPost("/api/attr/setBlockAttrs", {
id,
attrs: {"icon": unicode}
}, () => {
dialog.destroy();
addEmoji(unicode);
updateFileTreeEmoji(unicode, id);
updateOutlineEmoji(unicode, id);
});
} else {
avCB(unicode);
}
event.preventDefault();
event.stopPropagation();
return;
}
let newCurrentElement: HTMLElement;
if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
if (currentElement.previousElementSibling) {
currentElement.classList.remove("emojis__item--current");
newCurrentElement = currentElement.previousElementSibling as HTMLElement;
event.preventDefault();
event.stopPropagation();
} else if (currentElement.parentElement.previousElementSibling?.previousElementSibling) {
currentElement.classList.remove("emojis__item--current");
newCurrentElement = currentElement.parentElement.previousElementSibling.previousElementSibling.lastElementChild as HTMLElement;
event.preventDefault();
event.stopPropagation();
}
} else if (event.key === "ArrowRight" || event.key === "ArrowDown") {
if (currentElement.nextElementSibling) {
currentElement.classList.remove("emojis__item--current");
newCurrentElement = currentElement.nextElementSibling as HTMLElement;
event.preventDefault();
event.stopPropagation();
} else if (currentElement.parentElement.nextElementSibling?.nextElementSibling) {
currentElement.classList.remove("emojis__item--current");
newCurrentElement = currentElement.parentElement.nextElementSibling.nextElementSibling.firstElementChild as HTMLElement;
event.preventDefault();
event.stopPropagation();
}
}
if (newCurrentElement) {
newCurrentElement.classList.add("emojis__item--current");
const inputHeight = inputElement.clientHeight + 6;
if (newCurrentElement.offsetTop - inputHeight < emojisContentElement.scrollTop) {
emojisContentElement.scrollTop = newCurrentElement.offsetTop - inputHeight;
} else if (newCurrentElement.offsetTop - inputHeight - emojisContentElement.clientHeight + newCurrentElement.clientHeight > emojisContentElement.scrollTop) {
emojisContentElement.scrollTop = newCurrentElement.offsetTop - inputHeight - emojisContentElement.clientHeight + newCurrentElement.clientHeight;
}
}
});
if (!isMobile()) {
inputElement.focus();
}
lazyLoadEmoji(dialog.element);
lazyLoadEmojiImg(dialog.element);
// 不能使用 getEventName 否则 https://github.com/siyuan-note/siyuan/issues/5472
dialog.element.addEventListener("click", (event) => {
const eventTarget = event.target as HTMLElement;
const typeElement = hasClosestByClassName(eventTarget, "emojis__type");
if (typeElement) {
const titleElement = emojisContentElement.querySelector(`[data-type="${typeElement.getAttribute("data-type")}"]`) as HTMLElement;
if (titleElement) {
const index = titleElement.nextElementSibling.getAttribute("data-index");
if (index) {
let html = "";
window.siyuan.emojis[parseInt(index)].items.forEach(emoji => {
html += `