clean up, add undo and some small changes (#1432)

This commit is contained in:
Danil Boldyrev 2023-12-16 00:27:14 +03:00 committed by GitHub
parent a7f82b2545
commit 05ef3e6861
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,18 +1,5 @@
onUiLoaded(async() => { onUiLoaded(async() => {
// Helper functions // Helper functions
// Get active tab
/**
* Waits for an element to be present in the DOM.
*/
const waitForElement = (id) => new Promise(resolve => {
const checkForElement = () => {
const element = document.querySelector(id);
if (element) return resolve(element);
setTimeout(checkForElement, 100);
};
checkForElement();
});
// Detect whether the element has a horizontal scroll bar // Detect whether the element has a horizontal scroll bar
function hasHorizontalScrollbar(element) { function hasHorizontalScrollbar(element) {
@ -33,140 +20,40 @@ onUiLoaded(async() => {
} }
} }
// Check if hotkey is valid
function isValidHotkey(value) {
const specialKeys = ["Ctrl", "Alt", "Shift", "Disable"];
return (
(typeof value === "string" &&
value.length === 1 &&
/[a-z]/i.test(value)) ||
specialKeys.includes(value)
);
}
// Normalize hotkey
function normalizeHotkey(hotkey) {
return hotkey.length === 1 ? "Key" + hotkey.toUpperCase() : hotkey;
}
// Format hotkey for display
function formatHotkeyForDisplay(hotkey) {
return hotkey.startsWith("Key") ? hotkey.slice(3) : hotkey;
}
// Create hotkey configuration with the provided options // Create hotkey configuration with the provided options
function createHotkeyConfig(defaultHotkeysConfig) { function createHotkeyConfig(defaultHotkeysConfig) {
const result = {}; // Resulting hotkey configuration const result = {}; // Resulting hotkey configuration
for (const key in defaultHotkeysConfig) { for (const key in defaultHotkeysConfig) {
result[key] = defaultHotkeysConfig[key]; result[key] = defaultHotkeysConfig[key];
} }
return result; return result;
} }
// Disables functions in the config object based on the provided list of function names
function disableFunctions(config, disabledFunctions) {
// Bind the hasOwnProperty method to the functionMap object to avoid errors
const hasOwnProperty =
Object.prototype.hasOwnProperty.bind(functionMap);
// Loop through the disabledFunctions array and disable the corresponding functions in the config object
disabledFunctions.forEach(funcName => {
if (hasOwnProperty(funcName)) {
const key = functionMap[funcName];
config[key] = "disable";
}
});
// Return the updated config object
return config;
}
/**
* 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) {
const mainTabId = getTabId(elements);
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);
}
// Default config // Default config
const defaultHotkeysConfig = { const defaultHotkeysConfig = {
canvas_hotkey_zoom: "Alt", canvas_hotkey_zoom: "Shift",
canvas_hotkey_adjust: "Ctrl", canvas_hotkey_adjust: "Ctrl",
canvas_zoom_undo_extra_key: "Ctrl",
canvas_zoom_hotkey_undo: "KeyZ",
canvas_hotkey_reset: "KeyR", canvas_hotkey_reset: "KeyR",
canvas_hotkey_fullscreen: "KeyS", canvas_hotkey_fullscreen: "KeyS",
canvas_hotkey_move: "KeyF", canvas_hotkey_move: "KeyF",
canvas_hotkey_overlap: "KeyO",
canvas_disabled_functions: [],
canvas_show_tooltip: true, canvas_show_tooltip: true,
canvas_auto_expand: true, canvas_auto_expand: true,
canvas_blur_prompt: false, canvas_blur_prompt: true,
};
const functionMap = {
"Zoom": "canvas_hotkey_zoom",
"Adjust brush size": "canvas_hotkey_adjust",
"Moving canvas": "canvas_hotkey_move",
"Fullscreen": "canvas_hotkey_fullscreen",
"Reset Zoom": "canvas_hotkey_reset",
"Overlap": "canvas_hotkey_overlap"
}; };
// Loading the configuration from opts // Loading the configuration from opts
const preHotkeysConfig = createHotkeyConfig( const hotkeysConfig = createHotkeyConfig(
defaultHotkeysConfig defaultHotkeysConfig
); );
// Disable functions that are not needed by the user
const hotkeysConfig = disableFunctions(
preHotkeysConfig,
preHotkeysConfig.canvas_disabled_functions
);
let isMoving = false; let isMoving = false;
let mouseX, mouseY;
let activeElement; let activeElement;
const elemData = {}; const elemData = {};
function applyZoomAndPan(elemId, isExtension = true) { function applyZoomAndPan(elemId) {
const targetElement = gradioApp().querySelector(elemId); const targetElement = gradioApp().querySelector(elemId);
if (!targetElement) { if (!targetElement) {
@ -181,6 +68,7 @@ onUiLoaded(async() => {
panX: 0, panX: 0,
panY: 0 panY: 0
}; };
let fullScreenMode = false; let fullScreenMode = false;
// Create tooltip // Create tooltip
@ -211,41 +99,43 @@ onUiLoaded(async() => {
action: "Adjust brush size", action: "Adjust brush size",
keySuffix: " + wheel" keySuffix: " + wheel"
}, },
{configKey: "canvas_zoom_hotkey_undo", action: "Undo last action", keyPrefix: `${hotkeysConfig.canvas_zoom_undo_extra_key} + ` },
{configKey: "canvas_hotkey_reset", action: "Reset zoom"}, {configKey: "canvas_hotkey_reset", action: "Reset zoom"},
{ {
configKey: "canvas_hotkey_fullscreen", configKey: "canvas_hotkey_fullscreen",
action: "Fullscreen mode" action: "Fullscreen mode"
}, },
{configKey: "canvas_hotkey_move", action: "Move canvas"}, {configKey: "canvas_hotkey_move", action: "Move canvas"}
{configKey: "canvas_hotkey_overlap", action: "Overlap"}
]; ];
// Create hotkeys array with disabled property based on the config values // Create hotkeys array based on the config values
const hotkeys = hotkeysInfo.map(info => { const hotkeys = hotkeysInfo.map((info) => {
const configValue = hotkeysConfig[info.configKey]; const configValue = hotkeysConfig[info.configKey];
const key = info.keySuffix ?
`${configValue}${info.keySuffix}` : let key = configValue.slice(-1);
configValue.charAt(configValue.length - 1);
if (info.keySuffix) {
key = `${configValue}${info.keySuffix}`;
}
if (info.keyPrefix && info.keyPrefix !== "None + ") {
key = `${info.keyPrefix}${configValue[3]}`;
}
return { return {
key, key,
action: info.action, action: info.action,
disabled: configValue === "disable"
}; };
}); });
for (const hotkey of hotkeys) { hotkeys
if (hotkey.disabled) { .forEach(hotkey => {
continue;
}
const p = document.createElement("p"); const p = document.createElement("p");
p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`; p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`;
tooltipContent.appendChild(p); tooltipContent.appendChild(p);
} });
// Add information and content elements to the tooltip element tooltip.append(info, tooltipContent);
tooltip.appendChild(info);
tooltip.appendChild(tooltipContent);
// Add a hint element to the target element // Add a hint element to the target element
toolTipElemnt.appendChild(tooltip); toolTipElemnt.appendChild(tooltip);
@ -264,9 +154,7 @@ onUiLoaded(async() => {
panY: 0 panY: 0
}; };
if (isExtension) {
targetElement.style.overflow = "hidden"; targetElement.style.overflow = "hidden";
}
targetElement.isZoomed = false; targetElement.isZoomed = false;
@ -284,7 +172,7 @@ onUiLoaded(async() => {
closeBtn.addEventListener("click", resetZoom); closeBtn.addEventListener("click", resetZoom);
} }
if (canvas && isExtension) { if (canvas) {
const parentElement = targetElement.closest('[id^="component-"]'); const parentElement = targetElement.closest('[id^="component-"]');
if ( if (
canvas && canvas &&
@ -297,16 +185,6 @@ onUiLoaded(async() => {
} }
if (
canvas &&
!isExtension &&
parseFloat(canvas.style.width) > 865 &&
parseFloat(targetElement.style.width) > 865
) {
fitToElement();
return;
}
targetElement.style.width = ""; targetElement.style.width = "";
} }
@ -372,11 +250,9 @@ onUiLoaded(async() => {
targetElement.style.transformOrigin = "0 0"; targetElement.style.transformOrigin = "0 0";
targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${newZoomLevel})`; targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${newZoomLevel})`;
targetElement.style.overflow = "visible";
toggleOverlap("on"); toggleOverlap("on");
if (isExtension) {
targetElement.style.overflow = "visible";
}
return newZoomLevel; return newZoomLevel;
} }
@ -388,6 +264,7 @@ onUiLoaded(async() => {
let zoomPosX, zoomPosY; let zoomPosX, zoomPosY;
let delta = 0.2; let delta = 0.2;
if (elemData[elemId].zoomLevel > 7) { if (elemData[elemId].zoomLevel > 7) {
delta = 0.9; delta = 0.9;
} else if (elemData[elemId].zoomLevel > 2) { } else if (elemData[elemId].zoomLevel > 2) {
@ -421,12 +298,7 @@ onUiLoaded(async() => {
let parentElement; let parentElement;
if (isExtension) {
parentElement = targetElement.closest('[id^="component-"]'); parentElement = targetElement.closest('[id^="component-"]');
} else {
parentElement = targetElement.parentElement;
}
// Get element and screen dimensions // Get element and screen dimensions
const elementWidth = targetElement.offsetWidth; const elementWidth = targetElement.offsetWidth;
@ -455,6 +327,26 @@ onUiLoaded(async() => {
toggleOverlap("off"); toggleOverlap("off");
} }
// Undo last action
function undoLastAction(e) {
let isCtrlPressed = isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)
const isAuxButton = e.button >= 3;
if (isAuxButton) {
isCtrlPressed = true
} else {
if (!isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)) return;
}
// Move undoBtn query outside the if statement to avoid unnecessary queries
const undoBtn = document.querySelector(`${activeElement} button[aria-label="Undo"]`);
if ((isCtrlPressed) && undoBtn ) {
e.preventDefault();
undoBtn.click();
}
}
/** /**
* This function fits the target element to the screen by calculating * This function fits the target element to the screen by calculating
* the required scale and offsets. It also updates the global variables * the required scale and offsets. It also updates the global variables
@ -469,13 +361,8 @@ onUiLoaded(async() => {
if (!canvas) return; if (!canvas) return;
if (canvas.offsetWidth > 862 || isExtension) {
targetElement.style.width = (canvas.offsetWidth + 2) + "px"; targetElement.style.width = (canvas.offsetWidth + 2) + "px";
}
if (isExtension) {
targetElement.style.overflow = "visible"; targetElement.style.overflow = "visible";
}
if (fullScreenMode) { if (fullScreenMode) {
resetZoom(); resetZoom();
@ -549,11 +436,11 @@ onUiLoaded(async() => {
} }
} }
const hotkeyActions = { const hotkeyActions = {
[hotkeysConfig.canvas_hotkey_reset]: resetZoom, [hotkeysConfig.canvas_hotkey_reset]: resetZoom,
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap, [hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen [hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen,
[hotkeysConfig.canvas_zoom_hotkey_undo]: undoLastAction,
}; };
const action = hotkeyActions[event.code]; const action = hotkeyActions[event.code];
@ -597,6 +484,7 @@ onUiLoaded(async() => {
} }
targetElement.addEventListener("mousemove", getMousePosition); targetElement.addEventListener("mousemove", getMousePosition);
targetElement.addEventListener("auxclick", undoLastAction);
//observers //observers
// Creating an observer with a callback function to handle DOM changes // Creating an observer with a callback function to handle DOM changes
@ -661,7 +549,7 @@ onUiLoaded(async() => {
function handleMoveKeyDown(e) { function handleMoveKeyDown(e) {
// Disable key locks to make pasting from the buffer work correctly // Disable key locks to make pasting from the buffer work correctly
if ((e.ctrlKey && e.code === 'KeyV') || (e.ctrlKey && event.code === 'KeyC') || e.code === "F5") { if ((e.ctrlKey && e.code === 'KeyV') || (e.ctrlKey && e.code === 'KeyC') || e.code === "F5") {
return; return;
} }
@ -713,11 +601,7 @@ onUiLoaded(async() => {
if (isMoving && elemId === activeElement) { if (isMoving && elemId === activeElement) {
updatePanPosition(e.movementX, e.movementY); updatePanPosition(e.movementX, e.movementY);
targetElement.style.pointerEvents = "none"; targetElement.style.pointerEvents = "none";
if (isExtension) {
targetElement.style.overflow = "visible"; targetElement.style.overflow = "visible";
}
} else { } else {
targetElement.style.pointerEvents = "auto"; targetElement.style.pointerEvents = "auto";
} }
@ -745,18 +629,13 @@ onUiLoaded(async() => {
} }
} }
if (isExtension) {
targetElement.addEventListener("mousemove", checkForOutBox); targetElement.addEventListener("mousemove", checkForOutBox);
}
window.addEventListener('resize', (e) => { window.addEventListener('resize', (e) => {
resetZoom(); resetZoom();
if (isExtension) {
targetElement.isExpanded = false; targetElement.isExpanded = false;
targetElement.isZoomed = false; targetElement.isZoomed = false;
}
}); });
gradioApp().addEventListener("mousemove", handleMoveByKey); gradioApp().addEventListener("mousemove", handleMoveByKey);