From 4a1356c37137a03a46c1043f6356604191288252 Mon Sep 17 00:00:00 2001 From: Aevann Date: Fri, 30 Jun 2023 20:31:42 +0300 Subject: [PATCH] Revert "Improve inline emoji modal (#159)" This reverts commit 3d5355e30fbd3de0a812ac7c31eae90df6c111ed. --- files/assets/js/emoji_modal.js | 230 ++++++++++++++++----------------- 1 file changed, 113 insertions(+), 117 deletions(-) diff --git a/files/assets/js/emoji_modal.js b/files/assets/js/emoji_modal.js index 3961eaf3c..2a017ff87 100644 --- a/files/assets/js/emoji_modal.js +++ b/files/assets/js/emoji_modal.js @@ -15,13 +15,7 @@ Copyright (C) 2022 Dr Steven Transmisia, anti-evil engineer, */ // Status -/** - * inactive - user has not tried using an emoji - * loading - user has tried to use an emoji, and the engine is initializing itself - * ready - engine can handle all emoji usage - * @type {"inactive"|"loading"|"ready"} - */ -let emojiEngineState = "inactive"; +let emojiEngineStarted = false; // DOM stuff const classesSelectorDOM = document.getElementById("emoji-modal-tabs"); @@ -152,93 +146,88 @@ const emojisSearchDictionary = { }; // get public emojis list -function fetchEmojis() { - const headers = new Headers({xhr: "xhr"}) - return fetch("/emojis", { - headers, - }) - .then(res => res.json()) - .then(emojis => { - if(! (emojis instanceof Array )) - throw new TypeError("[EMOJI DIALOG] rDrama's server should have sent a JSON-coded Array!"); +const emojiRequest = new XMLHttpRequest(); +emojiRequest.open("GET", '/emojis'); +emojiRequest.setRequestHeader('xhr', 'xhr'); +emojiRequest.onload = async () => { + let emojis = JSON.parse(emojiRequest.response); + if(! (emojis instanceof Array )) + throw new TypeError("[EMOJI DIALOG] rDrama's server should have sent a JSON-coded Array!"); - globalEmojis = emojis.map(({name, author, count}) => ({name, author, count})); + globalEmojis = emojis.map(({name, author, count}) => ({name, author, count})); - let classes = ["Marsey", "Platy", "Wolf", "Donkey Kong", "Tay", "Capy", "Carp", "Marsey Flags", "Marsey Alphabet", "Classic", "Rage", "Wojak", "Misc"] + let classes = ["Marsey", "Platy", "Wolf", "Donkey Kong", "Tay", "Capy", "Carp", "Marsey Flags", "Marsey Alphabet", "Classic", "Rage", "Wojak", "Misc"] - const bussyDOM = document.createElement("div"); + const bussyDOM = document.createElement("div"); - for(let i = 0; i < emojis.length; i++) - { - const emoji = emojis[i]; + for(let i = 0; i < emojis.length; i++) + { + const emoji = emojis[i]; - emojisSearchDictionary.updateTag(emoji.name, emoji.name); - if(emoji.author !== undefined && emoji.author !== null) - { - emojisSearchDictionary.updateTag(`@${emoji.author.toLowerCase()}`, emoji.name); - } + emojisSearchDictionary.updateTag(emoji.name, emoji.name); + if(emoji.author !== undefined && emoji.author !== null) + { + emojisSearchDictionary.updateTag(`@${emoji.author.toLowerCase()}`, emoji.name); + } - if(emoji.tags instanceof Array) - for(let i = 0; i < emoji.tags.length; i++) - emojisSearchDictionary.updateTag(emoji.tags[i], emoji.name); + if(emoji.tags instanceof Array) + for(let i = 0; i < emoji.tags.length; i++) + emojisSearchDictionary.updateTag(emoji.tags[i], emoji.name); - // Create emoji DOM - const emojiDOM = document.importNode(emojiButtonTemplateDOM.content, true).children[0]; + // Create emoji DOM + const emojiDOM = document.importNode(emojiButtonTemplateDOM.content, true).children[0]; - emojiDOM.title = emoji.name - if(emoji.author !== undefined && emoji.author !== null) - emojiDOM.title += "\nauthor\t" + emoji.author - if(emoji.count !== undefined) - emojiDOM.title += "\nused\t" + emoji.count; - emojiDOM.dataset.className = emoji.kind; - emojiDOM.dataset.emojiName = emoji.name; - emojiDOM.onclick = emojiAddToInput; - emojiDOM.hidden = true; + emojiDOM.title = emoji.name + if(emoji.author !== undefined && emoji.author !== null) + emojiDOM.title += "\nauthor\t" + emoji.author + if(emoji.count !== undefined) + emojiDOM.title += "\nused\t" + emoji.count; + emojiDOM.dataset.className = emoji.kind; + emojiDOM.dataset.emojiName = emoji.name; + emojiDOM.onclick = emojiAddToInput; + emojiDOM.hidden = true; - const emojiIMGDOM = emojiDOM.children[0]; - emojiIMGDOM.src = "/e/" + emoji.name + ".webp"; - emojiIMGDOM.alt = emoji.name; - /** Disableing lazy loading seems to reduce cpu usage somehow (?) - * idk it is difficult to benchmark */ - emojiIMGDOM.loading = "lazy"; + const emojiIMGDOM = emojiDOM.children[0]; + emojiIMGDOM.src = "/e/" + emoji.name + ".webp"; + emojiIMGDOM.alt = emoji.name; + /** Disableing lazy loading seems to reduce cpu usage somehow (?) + * idk it is difficult to benchmark */ + emojiIMGDOM.loading = "lazy"; - // Save reference - emojiDOMs[emoji.name] = emojiDOM; + // Save reference + emojiDOMs[emoji.name] = emojiDOM; - // Add to the document! - bussyDOM.appendChild(emojiDOM); - } + // Add to the document! + bussyDOM.appendChild(emojiDOM); + } - // Create header - for(let className of classes) - { - let classSelectorDOM = document.createElement("li"); - classSelectorDOM.classList.add("nav-item"); + // Create header + for(let className of classes) + { + let classSelectorDOM = document.createElement("li"); + classSelectorDOM.classList.add("nav-item"); - let classSelectorLinkDOM = document.createElement("a"); - classSelectorLinkDOM.href = "#"; - classSelectorLinkDOM.classList.add("nav-link", "emojitab"); - classSelectorLinkDOM.dataset.bsToggle = "tab"; - classSelectorLinkDOM.dataset.className = className; - classSelectorLinkDOM.innerText = className; - classSelectorLinkDOM.addEventListener('click', switchEmojiTab); + let classSelectorLinkDOM = document.createElement("a"); + classSelectorLinkDOM.href = "#"; + classSelectorLinkDOM.classList.add("nav-link", "emojitab"); + classSelectorLinkDOM.dataset.bsToggle = "tab"; + classSelectorLinkDOM.dataset.className = className; + classSelectorLinkDOM.innerText = className; + classSelectorLinkDOM.addEventListener('click', switchEmojiTab); - classSelectorDOM.appendChild(classSelectorLinkDOM); - classesSelectorDOM.appendChild(classSelectorDOM); - } + classSelectorDOM.appendChild(classSelectorLinkDOM); + classesSelectorDOM.appendChild(classSelectorDOM); + } - // Show favorite for start. - classesSelectorDOM.children[0].children[0].click(); + // Show favorite for start. + await classesSelectorDOM.children[0].children[0].click(); - // Send it to the render machine! - emojiResultsDOM.appendChild(bussyDOM); + // Send it to the render machine! + emojiResultsDOM.appendChild(bussyDOM); - emojiResultsDOM.hidden = false; - emojiWorkingDOM.hidden = true; - emojiSearchBarDOM.disabled = false; - - emojiEngineState = "ready"; - }) + emojiResultsDOM.hidden = false; + emojiWorkingDOM.hidden = true; + emojiSearchBarDOM.disabled = false; } /** @@ -408,7 +397,7 @@ function populate_speed_emoji_modal(results, textbox) emoji_option.addEventListener('click', () => { selecting = false; speed_carot_modal.style.display = "none"; - textbox.value = textbox.value.replace(new RegExp(current_word+"(?=\\s|$)", "gi"), `:${name}: `) + textbox.value = textbox.value.replace(new RegExp(current_word+"(?=\\s|$)", "g"), `:${name}: `) textbox.focus() if (document.location.pathname != '/chat'){ markdown(textbox) @@ -446,56 +435,67 @@ function update_speed_emoji_modal(event) // Get current word at string, such as ":marse" or "word" let coords = text.indexOf(' ',box_coords.pos); current_word = /:[!#a-zA-Z0-9_]+(?=\n|$)/.exec(text.slice(0, coords === -1 ? text.length : coords)); - if (current_word) current_word = current_word[0].toLowerCase(); + if (current_word) current_word = current_word.toString(); /* We could also check emoji_typing_state here, which is less accurate but more efficient. I've * kept it unless someone wants to provide an option to toggle it for performance */ if (curr_word_is_emoji() && current_word != ":") { - loadEmojis().then( () => { - let modal_pos = event.target.getBoundingClientRect(); - modal_pos.x += window.scrollX; - modal_pos.y += window.scrollY; + loadEmojis(null); + let modal_pos = event.target.getBoundingClientRect(); + modal_pos.x += window.scrollX; + modal_pos.y += window.scrollY; - speed_carot_modal.style.display = "initial"; - speed_carot_modal.style.left = box_coords.x - 35 + "px"; - speed_carot_modal.style.top = modal_pos.y + box_coords.y + 14 + "px"; + speed_carot_modal.style.display = "initial"; + speed_carot_modal.style.left = box_coords.x - 35 + "px"; + speed_carot_modal.style.top = modal_pos.y + box_coords.y + 14 + "px"; - // Do the search (and do something with it) - const resultSet = emojisSearchDictionary.completeSearch(current_word.substring(1).replace(/[#!]/g, "")); + // Do the search (and do something with it) + const resultSet = emojisSearchDictionary.completeSearch(current_word.substr(1).replace(/#/g, "").replace(/!/g, "")) - const found = globalEmojis.filter(i => resultSet.has(i.name)); + const found = globalEmojis.filter(i => resultSet.has(i.name)); + + populate_speed_emoji_modal(found, event.target); - populate_speed_emoji_modal(found, event.target); - }); } else { speed_carot_modal.style.display = "none"; } } -function speed_carot_navigate(event) +function speed_carot_navigate(e) { if (!selecting) return; let select_items = speed_carot_modal.querySelectorAll(".speed-modal-option"); if (!select_items || !curr_word_is_emoji()) return; - - const modal_keybinds = { - // go up one, wrapping around to the bottom if pressed at the top - ArrowUp: () => emoji_index = ((emoji_index - 1) + select_items.length) % select_items.length, - // go down one, wrapping around to the top if pressed at the bottom - ArrowDown: () => emoji_index = ((emoji_index + 1) + select_items.length) % select_items.length, - // select the emoji - Enter: () => select_items[emoji_index].click(), - } - if (event.key in modal_keybinds) + // Up or down arrow or enter + if (e.keyCode == 38 || e.keyCode == 40 || e.keyCode == 13) { + if (emoji_index > select_items.length) + emoji_index = select_items; + select_items[emoji_index].classList.remove("selected"); - modal_keybinds[event.key](); + switch (e.keyCode) + { + case 38: // Up arrow + if (emoji_index) + emoji_index--; + break; + + case 40: // Down arrow + if (emoji_index < select_items.length-1) emoji_index++; + break; + + case 13: + select_items[emoji_index].click(); + + default: + break; + } + select_items[emoji_index].classList.add("selected"); - select_items[emoji_index].scrollIntoView({inline: "end", block: "nearest"}); - event.preventDefault(); + e.preventDefault(); } } @@ -510,23 +510,19 @@ forms.forEach(i => { i.addEventListener('keydown', speed_carot_navigate, false); }); -function loadEmojis() +function loadEmojis(inputTargetIDName) { selecting = false; speed_carot_modal.style.display = "none"; - switch (emojiEngineState) { - case "inactive": - emojiEngineState = "loading" - return fetchEmojis(); - case "loading": - // this is a subpar solution because it means that globalEmojis won't be loaded for later keystrokes - // however, it doesn't matter because onInput only checks what the user is typing after everything is loaded - case "ready": - return Promise.resolve(); - default: - throw Error("Unknown emoji engine state"); + if(!emojiEngineStarted) + { + emojiEngineStarted = true; + emojiRequest.send(); } + + if (inputTargetIDName) + emojiInputTargetDOM = document.getElementById(inputTargetIDName); } document.getElementById('emojiModal').addEventListener('shown.bs.modal', function () {