From 8fd20bd4c3cdd3deacf89e48b323d428de1e16e0 Mon Sep 17 00:00:00 2001 From: Aarni Koskela Date: Mon, 5 Jun 2023 10:19:06 +0300 Subject: [PATCH] Zoom and Pan: move helpers into its namespace to avoid littering global scope --- .../canvas-zoom-and-pan/javascript/zoom.js | 232 +++++++++--------- 1 file changed, 115 insertions(+), 117 deletions(-) diff --git a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js index 2a2ed999..0576c079 100644 --- a/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js +++ b/extensions-builtin/canvas-zoom-and-pan/javascript/zoom.js @@ -1,121 +1,119 @@ -// Helper functions -// Get active tab -function getActiveTab(elements, all = false) { - const tabs = elements.img2imgTabs.querySelectorAll("button"); - - if (all) return tabs; - - for (let tab of tabs) { - if (tab.classList.contains("selected")) { - return tab; - } - } -} - -// Get tab ID -function getTabId(elements, elementIDs) { - const activeTab = getActiveTab(elements); - const tabIdLookup = { - "Sketch": elementIDs.sketch, - "Inpaint sketch": elementIDs.inpaintSketch, - "Inpaint": elementIDs.inpaint - }; - return tabIdLookup[activeTab.innerText]; -} - -// Wait until opts loaded -async function waitForOpts() { - return new Promise(resolve => { - const checkInterval = setInterval(() => { - if (window.opts && Object.keys(window.opts).length !== 0) { - clearInterval(checkInterval); - resolve(window.opts); - } - }, 100); - }); -} - -// Check is hotkey valid -function isSingleLetter(value) { - return ( - typeof value === "string" && value.length === 1 && /[a-z]/i.test(value) - ); -} - -// Create hotkeyConfig from opts -function createHotkeyConfig(defaultHotkeysConfig, hotkeysConfigOpts) { - const result = {}; - const usedKeys = new Set(); - - for (const key in defaultHotkeysConfig) { - if (typeof hotkeysConfigOpts[key] === "boolean") { - result[key] = hotkeysConfigOpts[key]; - continue; - } - if ( - hotkeysConfigOpts[key] && - isSingleLetter(hotkeysConfigOpts[key]) && - !usedKeys.has(hotkeysConfigOpts[key].toUpperCase()) - ) { - // If the property passed the test and has not yet been used, add 'Key' before it and save it - result[key] = "Key" + hotkeysConfigOpts[key].toUpperCase(); - usedKeys.add(hotkeysConfigOpts[key].toUpperCase()); - } else { - // If the property does not pass the test or has already been used, we keep the default value - console.error( - `Hotkey: ${hotkeysConfigOpts[key]} for ${key} is repeated and conflicts with another hotkey or is not 1 letter. The default hotkey is used: ${defaultHotkeysConfig[key][3]}` - ); - result[key] = defaultHotkeysConfig[key]; - } - } - - return result; -} - -/** - * The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio. - * If the image display property is set to 'none', the mask breaks. To fix this, the function - * temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds - * to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on - * very long images. - */ - -function restoreImgRedMask(elements, elementIDs) { - const mainTabId = getTabId(elements, elementIDs); - - if (!mainTabId) return; - - const mainTab = gradioApp().querySelector(mainTabId); - const img = mainTab.querySelector("img"); - const imageARPreview = gradioApp().querySelector("#imageARPreview"); - - if (!img || !imageARPreview) return; - - imageARPreview.style.transform = ""; - if (parseFloat(mainTab.style.width) > 865) { - const transformString = mainTab.style.transform; - const scaleMatch = transformString.match(/scale\(([-+]?[0-9]*\.?[0-9]+)\)/); - let zoom = 1; // default zoom - - if (scaleMatch && scaleMatch[1]) { - zoom = Number(scaleMatch[1]); - } - - imageARPreview.style.transformOrigin = "0 0"; - imageARPreview.style.transform = `scale(${zoom})`; - } - - if (img.style.display !== "none") return; - - img.style.display = "block"; - - setTimeout(() => { - img.style.display = "none"; - }, 400); -} - -// Main onUiLoaded(async() => { + // Helper functions + // Get active tab + function getActiveTab(elements, all = false) { + const tabs = elements.img2imgTabs.querySelectorAll("button"); + + if (all) return tabs; + + for (let tab of tabs) { + if (tab.classList.contains("selected")) { + return tab; + } + } + } + + // Get tab ID + function getTabId(elements, elementIDs) { + const activeTab = getActiveTab(elements); + const tabIdLookup = { + "Sketch": elementIDs.sketch, + "Inpaint sketch": elementIDs.inpaintSketch, + "Inpaint": elementIDs.inpaint + }; + return tabIdLookup[activeTab.innerText]; + } + + // Wait until opts loaded + async function waitForOpts() { + return new Promise(resolve => { + const checkInterval = setInterval(() => { + if (window.opts && Object.keys(window.opts).length !== 0) { + clearInterval(checkInterval); + resolve(window.opts); + } + }, 100); + }); + } + + // Check is hotkey valid + function isSingleLetter(value) { + return ( + typeof value === "string" && value.length === 1 && /[a-z]/i.test(value) + ); + } + + // Create hotkeyConfig from opts + function createHotkeyConfig(defaultHotkeysConfig, hotkeysConfigOpts) { + const result = {}; + const usedKeys = new Set(); + + for (const key in defaultHotkeysConfig) { + if (typeof hotkeysConfigOpts[key] === "boolean") { + result[key] = hotkeysConfigOpts[key]; + continue; + } + if ( + hotkeysConfigOpts[key] && + isSingleLetter(hotkeysConfigOpts[key]) && + !usedKeys.has(hotkeysConfigOpts[key].toUpperCase()) + ) { + // If the property passed the test and has not yet been used, add 'Key' before it and save it + result[key] = "Key" + hotkeysConfigOpts[key].toUpperCase(); + usedKeys.add(hotkeysConfigOpts[key].toUpperCase()); + } else { + // If the property does not pass the test or has already been used, we keep the default value + console.error( + `Hotkey: ${hotkeysConfigOpts[key]} for ${key} is repeated and conflicts with another hotkey or is not 1 letter. The default hotkey is used: ${defaultHotkeysConfig[key][3]}` + ); + result[key] = defaultHotkeysConfig[key]; + } + } + + return result; + } + + /** + * The restoreImgRedMask function displays a red mask around an image to indicate the aspect ratio. + * If the image display property is set to 'none', the mask breaks. To fix this, the function + * temporarily sets the display property to 'block' and then hides the mask again after 300 milliseconds + * to avoid breaking the canvas. Additionally, the function adjusts the mask to work correctly on + * very long images. + */ + function restoreImgRedMask(elements, elementIDs) { + const mainTabId = getTabId(elements, elementIDs); + + if (!mainTabId) return; + + const mainTab = gradioApp().querySelector(mainTabId); + const img = mainTab.querySelector("img"); + const imageARPreview = gradioApp().querySelector("#imageARPreview"); + + if (!img || !imageARPreview) return; + + imageARPreview.style.transform = ""; + if (parseFloat(mainTab.style.width) > 865) { + const transformString = mainTab.style.transform; + const scaleMatch = transformString.match(/scale\(([-+]?[0-9]*\.?[0-9]+)\)/); + let zoom = 1; // default zoom + + if (scaleMatch && scaleMatch[1]) { + zoom = Number(scaleMatch[1]); + } + + imageARPreview.style.transformOrigin = "0 0"; + imageARPreview.style.transform = `scale(${zoom})`; + } + + if (img.style.display !== "none") return; + + img.style.display = "block"; + + setTimeout(() => { + img.style.display = "none"; + }, 400); + } + const hotkeysConfigOpts = await waitForOpts(); // Default config