From ae3a97a00fb57e2b47ee42ba2619c13d566a833c Mon Sep 17 00:00:00 2001 From: e218736 <147728997+e218736@users.noreply.github.com> Date: Mon, 12 Feb 2024 09:04:31 +0000 Subject: [PATCH] enable tooltips trigger on focus --- src/web/waiters/ControlsWaiter.mjs | 130 ++++++++++++++++------------- 1 file changed, 74 insertions(+), 56 deletions(-) diff --git a/src/web/waiters/ControlsWaiter.mjs b/src/web/waiters/ControlsWaiter.mjs index 6a0ef6f2..35941a13 100755 --- a/src/web/waiters/ControlsWaiter.mjs +++ b/src/web/waiters/ControlsWaiter.mjs @@ -6,12 +6,10 @@ import Utils from "../../core/Utils.mjs"; - /** * Waiter to handle events related to the CyberChef controls (i.e. Bake, Step, Save, Load etc.) */ class ControlsWaiter { - /** * ControlsWaiter constructor. * @@ -23,7 +21,6 @@ class ControlsWaiter { this.manager = manager; } - /** * Initialise Bootstrap components */ @@ -33,11 +30,10 @@ class ControlsWaiter { animation: false, container: "body", boundary: "viewport", - trigger: "hover" + trigger: "hover focus", }); } - /** * Checks or unchecks the Auto Bake checkbox based on the given value. * @@ -51,7 +47,6 @@ class ControlsWaiter { } } - /** * Handler to trigger baking. */ @@ -64,7 +59,6 @@ class ControlsWaiter { } } - /** * Handler for the 'Step through' command. Executes the next step of the recipe. */ @@ -72,7 +66,6 @@ class ControlsWaiter { this.app.step(); } - /** * Handler for changes made to the Auto Bake checkbox. */ @@ -80,7 +73,6 @@ class ControlsWaiter { this.app.autoBake_ = document.getElementById("auto-bake").checked; } - /** * Handler for the 'Clear recipe' command. Removes all operations from the recipe. */ @@ -88,7 +80,6 @@ class ControlsWaiter { this.manager.recipe.clearRecipe(); } - /** * Populates the save dialog box with a URL incorporating the recipe and input. * @@ -97,16 +88,23 @@ class ControlsWaiter { initialiseSaveLink(recipeConfig) { recipeConfig = recipeConfig || this.app.getRecipeConfig(); - const includeRecipe = document.getElementById("save-link-recipe-checkbox").checked; - const includeInput = document.getElementById("save-link-input-checkbox").checked; + const includeRecipe = document.getElementById( + "save-link-recipe-checkbox" + ).checked; + const includeInput = document.getElementById("save-link-input-checkbox") + .checked; const saveLinkEl = document.getElementById("save-link"); - const saveLink = this.generateStateUrl(includeRecipe, includeInput, null, recipeConfig); + const saveLink = this.generateStateUrl( + includeRecipe, + includeInput, + null, + recipeConfig + ); saveLinkEl.innerHTML = Utils.escapeHtml(Utils.truncate(saveLink, 120)); saveLinkEl.setAttribute("href", saveLink); } - /** * Generates a URL containing the current recipe and input state. * @@ -117,15 +115,24 @@ class ControlsWaiter { * @param {string} [baseURL] - The CyberChef URL, set to the current URL if not included * @returns {string} */ - generateStateUrl(includeRecipe, includeInput, input, recipeConfig, baseURL) { + generateStateUrl( + includeRecipe, + includeInput, + input, + recipeConfig, + baseURL + ) { recipeConfig = recipeConfig || this.app.getRecipeConfig(); - const link = baseURL || window.location.protocol + "//" + - window.location.host + - window.location.pathname; + const link = + baseURL || + window.location.protocol + + "//" + + window.location.host + + window.location.pathname; const recipeStr = Utils.generatePrettyRecipe(recipeConfig); - includeRecipe = includeRecipe && (recipeConfig.length > 0); + includeRecipe = includeRecipe && recipeConfig.length > 0; // If we don't get passed an input, get it from the current URI if (input === null && includeInput) { @@ -145,15 +152,17 @@ class ControlsWaiter { const params = [ includeRecipe ? ["recipe", recipeStr] : undefined, - includeInput && input.length ? ["input", Utils.escapeHtml(input)] : undefined, + includeInput && input.length + ? ["input", Utils.escapeHtml(input)] + : undefined, inputChrEnc !== 0 ? ["ienc", inputChrEnc] : undefined, outputChrEnc !== 0 ? ["oenc", outputChrEnc] : undefined, inputEOLSeq !== "\n" ? ["ieol", inputEOLSeq] : undefined, - outputEOLSeq !== "\n" ? ["oeol", outputEOLSeq] : undefined + outputEOLSeq !== "\n" ? ["oeol", outputEOLSeq] : undefined, ]; const hash = params - .filter(v => v) + .filter((v) => v) .map(([key, value]) => `${key}=${Utils.encodeURIFragment(value)}`) .join("&"); @@ -164,7 +173,6 @@ class ControlsWaiter { return link; } - /** * Handler for changes made to the save dialog text area. Re-initialises the save link. */ @@ -175,7 +183,6 @@ class ControlsWaiter { } catch (err) {} } - /** * Handler for the 'Save' command. Pops up the save dialog box. */ @@ -183,9 +190,15 @@ class ControlsWaiter { const recipeConfig = this.app.getRecipeConfig(); const recipeStr = JSON.stringify(recipeConfig); - document.getElementById("save-text-chef").value = Utils.generatePrettyRecipe(recipeConfig, true); - document.getElementById("save-text-clean").value = JSON.stringify(recipeConfig, null, 2) - .replace(/{\n\s+"/g, "{ \"") + document.getElementById( + "save-text-chef" + ).value = Utils.generatePrettyRecipe(recipeConfig, true); + document.getElementById("save-text-clean").value = JSON.stringify( + recipeConfig, + null, + 2 + ) + .replace(/{\n\s+"/g, '{ "') .replace(/\[\n\s{3,}/g, "[") .replace(/\n\s{3,}]/g, "]") .replace(/\s*\n\s*}/g, " }") @@ -196,7 +209,6 @@ class ControlsWaiter { $("#save-modal").modal(); } - /** * Handler for the save link recipe checkbox change event. */ @@ -204,7 +216,6 @@ class ControlsWaiter { this.initialiseSaveLink(); } - /** * Handler for the save link input checkbox change event. */ @@ -212,7 +223,6 @@ class ControlsWaiter { this.initialiseSaveLink(); } - /** * Handler for the 'Load' command. Pops up the load dialog box. */ @@ -221,7 +231,6 @@ class ControlsWaiter { $("#load-modal").modal(); } - /** * Saves the recipe specified in the save textarea to local storage. */ @@ -234,22 +243,27 @@ class ControlsWaiter { return false; } - const recipeName = Utils.escapeHtml(document.getElementById("save-name").value); - const recipeStr = document.querySelector("#save-texts .tab-pane.active textarea").value; + const recipeName = Utils.escapeHtml( + document.getElementById("save-name").value + ); + const recipeStr = document.querySelector( + "#save-texts .tab-pane.active textarea" + ).value; if (!recipeName) { this.app.alert("Please enter a recipe name", 3000); return; } - const savedRecipes = localStorage.savedRecipes ? - JSON.parse(localStorage.savedRecipes) : []; + const savedRecipes = localStorage.savedRecipes + ? JSON.parse(localStorage.savedRecipes) + : []; let recipeId = localStorage.recipeId || 0; savedRecipes.push({ id: ++recipeId, name: recipeName, - recipe: recipeStr + recipe: recipeStr, }); localStorage.savedRecipes = JSON.stringify(savedRecipes); @@ -258,7 +272,6 @@ class ControlsWaiter { this.app.alert(`Recipe saved as "${recipeName}".`, 3000); } - /** * Populates the list of saved recipes in the load dialog box from local storage. */ @@ -274,14 +287,17 @@ class ControlsWaiter { } // Add recipes to select - const savedRecipes = localStorage.savedRecipes ? - JSON.parse(localStorage.savedRecipes) : []; + const savedRecipes = localStorage.savedRecipes + ? JSON.parse(localStorage.savedRecipes) + : []; for (i = 0; i < savedRecipes.length; i++) { const opt = document.createElement("option"); opt.value = savedRecipes[i].id; // Unescape then re-escape in case localStorage has been corrupted - opt.innerHTML = Utils.escapeHtml(Utils.unescapeHtml(savedRecipes[i].name)); + opt.innerHTML = Utils.escapeHtml( + Utils.unescapeHtml(savedRecipes[i].name) + ); loadNameEl.appendChild(opt); } @@ -293,7 +309,6 @@ class ControlsWaiter { loadText.dispatchEvent(evt); } - /** * Removes the currently selected recipe from local storage. */ @@ -301,16 +316,16 @@ class ControlsWaiter { if (!this.app.isLocalStorageAvailable()) return false; const id = parseInt(document.getElementById("load-name").value, 10); - const rawSavedRecipes = localStorage.savedRecipes ? - JSON.parse(localStorage.savedRecipes) : []; + const rawSavedRecipes = localStorage.savedRecipes + ? JSON.parse(localStorage.savedRecipes) + : []; - const savedRecipes = rawSavedRecipes.filter(r => r.id !== id); + const savedRecipes = rawSavedRecipes.filter((r) => r.id !== id); localStorage.savedRecipes = JSON.stringify(savedRecipes); this.populateLoadRecipesList(); } - /** * Displays the selected recipe in the load text box. */ @@ -318,22 +333,24 @@ class ControlsWaiter { if (!this.app.isLocalStorageAvailable()) return false; const el = e.target; - const savedRecipes = localStorage.savedRecipes ? - JSON.parse(localStorage.savedRecipes) : []; + const savedRecipes = localStorage.savedRecipes + ? JSON.parse(localStorage.savedRecipes) + : []; const id = parseInt(el.value, 10); - const recipe = savedRecipes.find(r => r.id === id); + const recipe = savedRecipes.find((r) => r.id === id); document.getElementById("load-text").value = recipe.recipe; } - /** * Loads the selected recipe and populates the Recipe with its operations. */ loadButtonClick() { try { - const recipeConfig = Utils.parseRecipeConfig(document.getElementById("load-text").value); + const recipeConfig = Utils.parseRecipeConfig( + document.getElementById("load-text").value + ); this.app.setRecipeConfig(recipeConfig); this.app.autoBake(); @@ -343,7 +360,6 @@ class ControlsWaiter { } } - /** * Populates the bug report information box with useful technical info. * @@ -353,7 +369,13 @@ class ControlsWaiter { e.preventDefault(); const reportBugInfo = document.getElementById("report-bug-info"); - const saveLink = this.generateStateUrl(true, true, null, null, "https://gchq.github.io/CyberChef/"); + const saveLink = this.generateStateUrl( + true, + true, + null, + null, + "https://gchq.github.io/CyberChef/" + ); if (reportBugInfo) { reportBugInfo.innerHTML = `* Version: ${PKG_VERSION} @@ -366,7 +388,6 @@ ${navigator.userAgent} } } - /** * Shows the stale indicator to show that the input or recipe has changed * since the last bake. @@ -376,7 +397,6 @@ ${navigator.userAgent} staleIndicator.classList.remove("hidden"); } - /** * Hides the stale indicator to show that the input or recipe has not changed * since the last bake. @@ -386,7 +406,6 @@ ${navigator.userAgent} staleIndicator.classList.add("hidden"); } - /** * Switches the Bake button between 'Bake', 'Cancel' and 'Loading' functions. * @@ -429,7 +448,6 @@ ${navigator.userAgent} recList.style.bottom = controls.clientHeight + "px"; } - } export default ControlsWaiter;