diff --git a/.gitignore b/.gitignore index b1a2ad517..3382bf80d 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,9 @@ __pycache__ /webui-user.bat /webui-user.sh /javascript/themes.json +node_modules +pnpm-lock.yaml +package-lock.json venv # all models and temp files diff --git a/TODO.md b/TODO.md index b1b4f4a5c..74cd7447d 100644 --- a/TODO.md +++ b/TODO.md @@ -31,7 +31,7 @@ Stuff to be added... Stuff to be investigated... - Torch Compile -- `Torch-DirectML` +- TXT2IMG: - `TensorRT` - [Temporal Weighing](https://github.com/comfyanonymous/ComfyUI/discussions/473) diff --git a/extensions-builtin/stable-diffusion-webui-images-browser b/extensions-builtin/stable-diffusion-webui-images-browser index 05d88c780..e535ea6ae 160000 --- a/extensions-builtin/stable-diffusion-webui-images-browser +++ b/extensions-builtin/stable-diffusion-webui-images-browser @@ -1 +1 @@ -Subproject commit 05d88c7809587c45fd97d136c717af1f21d06eda +Subproject commit e535ea6aea2356a13da3e0452b92b3d68861f539 diff --git a/javascript/.eslintrc.json b/javascript/.eslintrc.json new file mode 100644 index 000000000..91408c7de --- /dev/null +++ b/javascript/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "globals": {}, + "env": { + "browser": true, + "commonjs": false, + "node": false, + "jquery": false, + "es2020": true + }, + "parserOptions": { "ecmaVersion": 2020 }, + "plugins": [], + "extends": ["eslint:recommended", "airbnb-base"], + "rules": { + "max-len": [1, 220, 3], + "camelcase":"off", + "no-unused-vars":"off", + "no-plusplus":"off", + "no-param-reassign":"off" + } +} diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js index a8278cca2..faec76d54 100644 --- a/javascript/aspectRatioOverlay.js +++ b/javascript/aspectRatioOverlay.js @@ -1,116 +1,107 @@ - let currentWidth = null; let currentHeight = null; -let arFrameTimeout = setTimeout(function(){},0); - -function dimensionChange(e, is_width, is_height){ - - if(is_width){ - currentWidth = e.target.value*1.0 - } - if(is_height){ - currentHeight = e.target.value*1.0 - } - - var inImg2img = gradioApp().querySelector("#tab_img2img").style.display == "block"; - - if(!inImg2img){ - return; - } - - var targetElement = null; - - var tabIndex = get_tab_index('mode_img2img') - if(tabIndex == 0){ // img2img - targetElement = gradioApp().querySelector('#img2img_image div[data-testid=image] img'); - } else if(tabIndex == 1){ //Sketch - targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img'); - } else if(tabIndex == 2){ // Inpaint - targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img'); - } else if(tabIndex == 3){ // Inpaint sketch - targetElement = gradioApp().querySelector('#inpaint_sketch div[data-testid=image] img'); - } - - - if(targetElement){ - - var arPreviewRect = gradioApp().querySelector('#imageARPreview'); - if(!arPreviewRect){ - arPreviewRect = document.createElement('div') - arPreviewRect.id = "imageARPreview"; - gradioApp().appendChild(arPreviewRect) - } - - +let arFrameTimeout = setTimeout(() => {}, 0); + +function dimensionChange(e, is_width, is_height) { + if (is_width) { + currentWidth = e.target.value * 1.0; + } + if (is_height) { + currentHeight = e.target.value * 1.0; + } + + const inImg2img = gradioApp().querySelector('#tab_img2img').style.display == 'block'; + + if (!inImg2img) { + return; + } + + let targetElement = null; + + const tabIndex = get_tab_index('mode_img2img'); + if (tabIndex == 0) { // img2img + targetElement = gradioApp().querySelector('#img2img_image div[data-testid=image] img'); + } else if (tabIndex == 1) { // Sketch + targetElement = gradioApp().querySelector('#img2img_sketch div[data-testid=image] img'); + } else if (tabIndex == 2) { // Inpaint + targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img'); + } else if (tabIndex == 3) { // Inpaint sketch + targetElement = gradioApp().querySelector('#inpaint_sketch div[data-testid=image] img'); + } + + if (targetElement) { + let arPreviewRect = gradioApp().querySelector('#imageARPreview'); + if (!arPreviewRect) { + arPreviewRect = document.createElement('div'); + arPreviewRect.id = 'imageARPreview'; + gradioApp().appendChild(arPreviewRect); + } - var viewportOffset = targetElement.getBoundingClientRect(); + const viewportOffset = targetElement.getBoundingClientRect(); - viewportscale = Math.min( targetElement.clientWidth/targetElement.naturalWidth, targetElement.clientHeight/targetElement.naturalHeight ) + viewportscale = Math.min(targetElement.clientWidth / targetElement.naturalWidth, targetElement.clientHeight / targetElement.naturalHeight); - scaledx = targetElement.naturalWidth*viewportscale - scaledy = targetElement.naturalHeight*viewportscale + scaledx = targetElement.naturalWidth * viewportscale; + scaledy = targetElement.naturalHeight * viewportscale; - cleintRectTop = (viewportOffset.top+window.scrollY) - cleintRectLeft = (viewportOffset.left+window.scrollX) - cleintRectCentreY = cleintRectTop + (targetElement.clientHeight/2) - cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth/2) + cleintRectTop = (viewportOffset.top + window.scrollY); + cleintRectLeft = (viewportOffset.left + window.scrollX); + cleintRectCentreY = cleintRectTop + (targetElement.clientHeight / 2); + cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth / 2); - viewRectTop = cleintRectCentreY-(scaledy/2) - viewRectLeft = cleintRectCentreX-(scaledx/2) - arRectWidth = scaledx - arRectHeight = scaledy + viewRectTop = cleintRectCentreY - (scaledy / 2); + viewRectLeft = cleintRectCentreX - (scaledx / 2); + arRectWidth = scaledx; + arRectHeight = scaledy; - arscale = Math.min( arRectWidth/currentWidth, arRectHeight/currentHeight ) - arscaledx = currentWidth*arscale - arscaledy = currentHeight*arscale + arscale = Math.min(arRectWidth / currentWidth, arRectHeight / currentHeight); + arscaledx = currentWidth * arscale; + arscaledy = currentHeight * arscale; - arRectTop = cleintRectCentreY-(arscaledy/2) - arRectLeft = cleintRectCentreX-(arscaledx/2) - arRectWidth = arscaledx - arRectHeight = arscaledy + arRectTop = cleintRectCentreY - (arscaledy / 2); + arRectLeft = cleintRectCentreX - (arscaledx / 2); + arRectWidth = arscaledx; + arRectHeight = arscaledy; - arPreviewRect.style.top = arRectTop+'px'; - arPreviewRect.style.left = arRectLeft+'px'; - arPreviewRect.style.width = arRectWidth+'px'; - arPreviewRect.style.height = arRectHeight+'px'; + arPreviewRect.style.top = `${arRectTop}px`; + arPreviewRect.style.left = `${arRectLeft}px`; + arPreviewRect.style.width = `${arRectWidth}px`; + arPreviewRect.style.height = `${arRectHeight}px`; clearTimeout(arFrameTimeout); - arFrameTimeout = setTimeout(function(){ + arFrameTimeout = setTimeout(() => { arPreviewRect.style.display = 'none'; - },2000); + }, 2000); arPreviewRect.style.display = 'block'; - - } - + } } - -onUiUpdate(function(){ - var arPreviewRect = gradioApp().querySelector('#imageARPreview'); - if(arPreviewRect){ - arPreviewRect.style.display = 'none'; - } - var tabImg2img = gradioApp().querySelector("#tab_img2img"); - if (tabImg2img) { - var inImg2img = tabImg2img.style.display == "block"; - if(inImg2img){ - let inputs = gradioApp().querySelectorAll('input'); - inputs.forEach(function(e){ - var is_width = e.parentElement.id == "img2img_width" - var is_height = e.parentElement.id == "img2img_height" - - if((is_width || is_height) && !e.classList.contains('scrollwatch')){ - e.addEventListener('input', function(e){dimensionChange(e, is_width, is_height)} ) - e.classList.add('scrollwatch') - } - if(is_width){ - currentWidth = e.value*1.0 - } - if(is_height){ - currentHeight = e.value*1.0 - } - }) +onUiUpdate(() => { + const arPreviewRect = gradioApp().querySelector('#imageARPreview'); + if (arPreviewRect) { + arPreviewRect.style.display = 'none'; + } + const tabImg2img = gradioApp().querySelector('#tab_img2img'); + if (tabImg2img) { + const inImg2img = tabImg2img.style.display == 'block'; + if (inImg2img) { + const inputs = gradioApp().querySelectorAll('input'); + inputs.forEach((e) => { + const is_width = e.parentElement.id == 'img2img_width'; + const is_height = e.parentElement.id == 'img2img_height'; + + if ((is_width || is_height) && !e.classList.contains('scrollwatch')) { + e.addEventListener('input', (e) => { dimensionChange(e, is_width, is_height); }); + e.classList.add('scrollwatch'); + } + if (is_width) { + currentWidth = e.value * 1.0; + } + if (is_height) { + currentHeight = e.value * 1.0; } + }); } + } }); diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js index 517bacac8..39d880165 100644 --- a/javascript/contextMenus.js +++ b/javascript/contextMenus.js @@ -1,178 +1,176 @@ +contextMenuInit = function () { + let eventListenerApplied = false; + const menuSpecs = new Map(); -contextMenuInit = function(){ - let eventListenerApplied=false; - let menuSpecs = new Map(); - - const uid = function(){ + const uid = function () { return Date.now().toString(36) + Math.random().toString(36).substr(2); - } + }; - function showContextMenu(event,element,menuEntries){ - let posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; - let posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; + function showContextMenu(event, element, menuEntries) { + const posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; + const posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; - let oldMenu = gradioApp().querySelector('#context-menu') - if(oldMenu){ - oldMenu.remove() + const oldMenu = gradioApp().querySelector('#context-menu'); + if (oldMenu) { + oldMenu.remove(); } - let tabButton = uiCurrentTab - let baseStyle = window.getComputedStyle(tabButton) - - const contextMenu = document.createElement('nav') - contextMenu.id = "context-menu" - contextMenu.style.background = baseStyle.background - contextMenu.style.color = baseStyle.color - contextMenu.style.fontFamily = baseStyle.fontFamily - contextMenu.style.top = posy+'px' - contextMenu.style.left = posx+'px' + const tabButton = uiCurrentTab; + const baseStyle = window.getComputedStyle(tabButton); + const contextMenu = document.createElement('nav'); + contextMenu.id = 'context-menu'; + contextMenu.style.background = baseStyle.background; + contextMenu.style.color = baseStyle.color; + contextMenu.style.fontFamily = baseStyle.fontFamily; + contextMenu.style.top = `${posy}px`; + contextMenu.style.left = `${posx}px`; - - const contextMenuList = document.createElement('ul') + const contextMenuList = document.createElement('ul'); contextMenuList.className = 'context-menu-items'; contextMenu.append(contextMenuList); - menuEntries.forEach(function(entry){ - let contextMenuEntry = document.createElement('a') - contextMenuEntry.innerHTML = entry['name'] - contextMenuEntry.addEventListener("click", function(e) { - entry['func'](); - }) + menuEntries.forEach((entry) => { + const contextMenuEntry = document.createElement('a'); + contextMenuEntry.innerHTML = entry.name; + contextMenuEntry.addEventListener('click', (e) => { + entry.func(); + }); contextMenuList.append(contextMenuEntry); + }); - }) - - gradioApp().appendChild(contextMenu) + gradioApp().appendChild(contextMenu); - let menuWidth = contextMenu.offsetWidth + 4; - let menuHeight = contextMenu.offsetHeight + 4; + const menuWidth = contextMenu.offsetWidth + 4; + const menuHeight = contextMenu.offsetHeight + 4; - let windowWidth = window.innerWidth; - let windowHeight = window.innerHeight; + const windowWidth = window.innerWidth; + const windowHeight = window.innerHeight; - if ( (windowWidth - posx) < menuWidth ) { - contextMenu.style.left = windowWidth - menuWidth + "px"; + if ((windowWidth - posx) < menuWidth) { + contextMenu.style.left = `${windowWidth - menuWidth}px`; } - if ( (windowHeight - posy) < menuHeight ) { - contextMenu.style.top = windowHeight - menuHeight + "px"; + if ((windowHeight - posy) < menuHeight) { + contextMenu.style.top = `${windowHeight - menuHeight}px`; } - } - function appendContextMenuOption(targetElementSelector,entryName,entryFunction){ - - currentItems = menuSpecs.get(targetElementSelector) + function appendContextMenuOption(targetElementSelector, entryName, entryFunction) { + currentItems = menuSpecs.get(targetElementSelector); - if(!currentItems){ - currentItems = [] - menuSpecs.set(targetElementSelector,currentItems); + if (!currentItems) { + currentItems = []; + menuSpecs.set(targetElementSelector, currentItems); } - let newItem = {'id':targetElementSelector+'_'+uid(), - 'name':entryName, - 'func':entryFunction, - 'isNew':true} - - currentItems.push(newItem) - return newItem['id'] + const newItem = { + id: `${targetElementSelector}_${uid()}`, + name: entryName, + func: entryFunction, + isNew: true, + }; + + currentItems.push(newItem); + return newItem.id; } - function removeContextMenuOption(uid){ - menuSpecs.forEach(function(v,k) { - let index = -1 - v.forEach(function(e,ei){if(e['id']==uid){index=ei}}) - if(index>=0){ + function removeContextMenuOption(uid) { + menuSpecs.forEach((v, k) => { + let index = -1; + v.forEach((e, ei) => { if (e.id == uid) { index = ei; } }); + if (index >= 0) { v.splice(index, 1); } - }) + }); } - function addContextMenuEventListener(){ - if(eventListenerApplied){ + function addContextMenuEventListener() { + if (eventListenerApplied) { return; } - gradioApp().addEventListener("click", function(e) { - let source = e.composedPath()[0] - if(source.id && source.id.indexOf('check_progress')>-1){ - return + gradioApp().addEventListener('click', (e) => { + const source = e.composedPath()[0]; + if (source.id && source.id.indexOf('check_progress') > -1) { + return; } - let oldMenu = gradioApp().querySelector('#context-menu') - if(oldMenu){ - oldMenu.remove() + const oldMenu = gradioApp().querySelector('#context-menu'); + if (oldMenu) { + oldMenu.remove(); } }); - gradioApp().addEventListener("contextmenu", function(e) { - let oldMenu = gradioApp().querySelector('#context-menu') - if(oldMenu){ - oldMenu.remove() + gradioApp().addEventListener('contextmenu', (e) => { + const oldMenu = gradioApp().querySelector('#context-menu'); + if (oldMenu) { + oldMenu.remove(); } - menuSpecs.forEach(function(v,k) { - if(e.composedPath()[0].matches(k)){ - showContextMenu(e,e.composedPath()[0],v) - e.preventDefault() - return + menuSpecs.forEach((v, k) => { + if (e.composedPath()[0].matches(k)) { + showContextMenu(e, e.composedPath()[0], v); + e.preventDefault(); } - }) + }); }); - eventListenerApplied=true - + eventListenerApplied = true; } - return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener] -} + return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener]; +}; initResponse = contextMenuInit(); -appendContextMenuOption = initResponse[0]; -removeContextMenuOption = initResponse[1]; +appendContextMenuOption = initResponse[0]; +removeContextMenuOption = initResponse[1]; addContextMenuEventListener = initResponse[2]; -(function(){ - //Start example Context Menu Items - let generateOnRepeat = function(genbuttonid,interruptbuttonid){ - let genbutton = gradioApp().querySelector(genbuttonid); - const busy = document.getElementById('progressbar')?.style.display == "block" - if(!busy){ +(function () { + // Start example Context Menu Items + const generateOnRepeat = function (genbuttonid, interruptbuttonid) { + const genbutton = gradioApp().querySelector(genbuttonid); + const busy = document.getElementById('progressbar')?.style.display == 'block'; + if (!busy) { genbutton.click(); } - clearInterval(window.generateOnRepeatInterval) - window.generateOnRepeatInterval = setInterval(function(){ - const busy = document.getElementById('progressbar')?.style.display == "block" - if(!busy){ - genbutton.click(); - } + clearInterval(window.generateOnRepeatInterval); + window.generateOnRepeatInterval = setInterval( + () => { + const busy = document.getElementById('progressbar')?.style.display == 'block'; + if (!busy) { + genbutton.click(); + } + }, + 500, + ); + }; + + appendContextMenuOption('#txt2img_generate', 'Generate forever', () => { + generateOnRepeat('#txt2img_generate', '#txt2img_interrupt'); + }); + appendContextMenuOption('#img2img_generate', 'Generate forever', () => { + generateOnRepeat('#img2img_generate', '#img2img_interrupt'); + }); + + const cancelGenerateForever = function () { + clearInterval(window.generateOnRepeatInterval); + }; + + appendContextMenuOption('#txt2img_interrupt', 'Cancel generate forever', cancelGenerateForever); + appendContextMenuOption('#txt2img_generate', 'Cancel generate forever', cancelGenerateForever); + appendContextMenuOption('#img2img_interrupt', 'Cancel generate forever', cancelGenerateForever); + appendContextMenuOption('#img2img_generate', 'Cancel generate forever', cancelGenerateForever); + + appendContextMenuOption( + '#roll', + 'Roll three', + () => { + const rollbutton = get_uiCurrentTabContent().querySelector('#roll'); + setTimeout(() => { rollbutton.click(); }, 100); + setTimeout(() => { rollbutton.click(); }, 200); + setTimeout(() => { rollbutton.click(); }, 300); }, - 500) - } - - appendContextMenuOption('#txt2img_generate','Generate forever',function(){ - generateOnRepeat('#txt2img_generate','#txt2img_interrupt'); - }) - appendContextMenuOption('#img2img_generate','Generate forever',function(){ - generateOnRepeat('#img2img_generate','#img2img_interrupt'); - }) - - let cancelGenerateForever = function(){ - clearInterval(window.generateOnRepeatInterval) - } - - appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever) - appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever) - appendContextMenuOption('#img2img_interrupt','Cancel generate forever',cancelGenerateForever) - appendContextMenuOption('#img2img_generate', 'Cancel generate forever',cancelGenerateForever) - - appendContextMenuOption('#roll','Roll three', - function(){ - let rollbutton = get_uiCurrentTabContent().querySelector('#roll'); - setTimeout(function(){rollbutton.click()},100) - setTimeout(function(){rollbutton.click()},200) - setTimeout(function(){rollbutton.click()},300) - } - ) -})(); -//End example Context Menu Items + ); +}()); +// End example Context Menu Items -onUiUpdate(function(){ - addContextMenuEventListener() +onUiUpdate(() => { + addContextMenuEventListener(); }); diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js index 9015e4bd5..27fa4341d 100644 --- a/javascript/dragdrop.js +++ b/javascript/dragdrop.js @@ -1,75 +1,75 @@ // allows drag-dropping files into gradio image elements, and also pasting images from clipboard -function isValidImageList( files ) { - return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type); +function isValidImageList(files) { + return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type); } -function dropReplaceImage( imgWrap, files ) { - if (!isValidImageList(files)) return; - const tmpFile = files[0]; - imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click(); - const callback = () => { - const fileInput = imgWrap.querySelector('input[type="file"]'); - if (fileInput) { - if (files.length === 0) { - files = new DataTransfer(); - files.items.add(tmpFile); - fileInput.files = files.files; - } else { - fileInput.files = files; - } - fileInput.dispatchEvent(new Event('change')); - } - }; - - if (imgWrap.closest('#pnginfo_image')) { - // special treatment for PNG Info tab, wait for fetch request to finish - const oldFetch = window.fetch; - window.fetch = async (input, options) => { - const response = await oldFetch(input, options); - if ( 'api/predict/' === input ) { - const content = await response.text(); - window.fetch = oldFetch; - window.requestAnimationFrame( () => callback() ); - return new Response(content, { - status: response.status, - statusText: response.statusText, - headers: response.headers - }) - } - return response; - }; - } else { - window.requestAnimationFrame(() => callback()); +function dropReplaceImage(imgWrap, files) { + if (!isValidImageList(files)) return; + const tmpFile = files[0]; + imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click(); + const callback = () => { + const fileInput = imgWrap.querySelector('input[type="file"]'); + if (fileInput) { + if (files.length === 0) { + files = new DataTransfer(); + files.items.add(tmpFile); + fileInput.files = files.files; + } else { + fileInput.files = files; + } + fileInput.dispatchEvent(new Event('change')); } + }; + + if (imgWrap.closest('#pnginfo_image')) { + // special treatment for PNG Info tab, wait for fetch request to finish + const oldFetch = window.fetch; + window.fetch = async (input, options) => { + const response = await oldFetch(input, options); + if (input === 'api/predict/') { + const content = await response.text(); + window.fetch = oldFetch; + window.requestAnimationFrame(() => callback()); + return new Response(content, { + status: response.status, + statusText: response.statusText, + headers: response.headers, + }); + } + return response; + }; + } else { + window.requestAnimationFrame(() => callback()); + } } -window.document.addEventListener('dragover', e => { - const target = e.composedPath()[0]; - const imgWrap = target.closest('[data-testid="image"]'); - if ( !imgWrap && target.placeholder && target.placeholder.indexOf("Prompt") == -1) return; - e.stopPropagation(); - e.preventDefault(); - e.dataTransfer.dropEffect = 'copy'; +window.document.addEventListener('dragover', (e) => { + const target = e.composedPath()[0]; + const imgWrap = target.closest('[data-testid="image"]'); + if (!imgWrap && target.placeholder && target.placeholder.indexOf('Prompt') == -1) return; + e.stopPropagation(); + e.preventDefault(); + e.dataTransfer.dropEffect = 'copy'; }); -window.document.addEventListener('drop', e => { - const target = e.composedPath()[0]; - if (!target.placeholder) return; - if (target.placeholder.indexOf("Prompt") == -1) return; - const imgWrap = target.closest('[data-testid="image"]'); - if (!imgWrap) return; - e.stopPropagation(); - e.preventDefault(); - const files = e.dataTransfer.files; - dropReplaceImage(imgWrap, files); +window.document.addEventListener('drop', (e) => { + const target = e.composedPath()[0]; + if (!target.placeholder) return; + if (target.placeholder.indexOf('Prompt') == -1) return; + const imgWrap = target.closest('[data-testid="image"]'); + if (!imgWrap) return; + e.stopPropagation(); + e.preventDefault(); + const { files } = e.dataTransfer; + dropReplaceImage(imgWrap, files); }); -window.addEventListener('paste', e => { - const files = e.clipboardData.files; - if ( ! isValidImageList( files ) ) return; - const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')].filter(el => uiElementIsVisible(el)); - if ( ! visibleImageFields.length ) return; - const firstFreeImageField = visibleImageFields.filter(el => el.querySelector('input[type=file]'))?.[0]; - dropReplaceImage(firstFreeImageField ? firstFreeImageField : visibleImageFields[visibleImageFields.length - 1], files); +window.addEventListener('paste', (e) => { + const { files } = e.clipboardData; + if (!isValidImageList(files)) return; + const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')].filter((el) => uiElementIsVisible(el)); + if (!visibleImageFields.length) return; + const firstFreeImageField = visibleImageFields.filter((el) => el.querySelector('input[type=file]'))?.[0]; + dropReplaceImage(firstFreeImageField || visibleImageFields[visibleImageFields.length - 1], files); }); diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js index 588c7b773..87ec52617 100644 --- a/javascript/edit-attention.js +++ b/javascript/edit-attention.js @@ -1,120 +1,119 @@ -function keyupEditAttention(event){ - let target = event.originalTarget || event.composedPath()[0]; - if (! target.matches("[id*='_toprow'] [id*='_prompt'] textarea")) return; - if (! (event.metaKey || event.ctrlKey)) return; - - let isPlus = event.key == "ArrowUp" - let isMinus = event.key == "ArrowDown" - if (!isPlus && !isMinus) return; - - let selectionStart = target.selectionStart; - let selectionEnd = target.selectionEnd; - let text = target.value; - - function selectCurrentParenthesisBlock(OPEN, CLOSE){ - if (selectionStart !== selectionEnd) return false; - - // Find opening parenthesis around current cursor - const before = text.substring(0, selectionStart); - let beforeParen = before.lastIndexOf(OPEN); - if (beforeParen == -1) return false; - let beforeParenClose = before.lastIndexOf(CLOSE); - while (beforeParenClose !== -1 && beforeParenClose > beforeParen) { - beforeParen = before.lastIndexOf(OPEN, beforeParen - 1); - beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1); - } - - // Find closing parenthesis around current cursor - const after = text.substring(selectionStart); - let afterParen = after.indexOf(CLOSE); - if (afterParen == -1) return false; - let afterParenOpen = after.indexOf(OPEN); - while (afterParenOpen !== -1 && afterParen > afterParenOpen) { - afterParen = after.indexOf(CLOSE, afterParen + 1); - afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1); - } - if (beforeParen === -1 || afterParen === -1) return false; - - // Set the selection to the text between the parenthesis - const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen); - const lastColon = parenContent.lastIndexOf(":"); - selectionStart = beforeParen + 1; - selectionEnd = selectionStart + lastColon; - target.setSelectionRange(selectionStart, selectionEnd); - return true; - } - - function selectCurrentWord(){ - if (selectionStart !== selectionEnd) return false; - const delimiters = opts.keyedit_delimiters + " \r\n\t"; - - // seek backward until to find beggining - while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) { - selectionStart--; - } - - // seek forward to find end - while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) { - selectionEnd++; - } - - target.setSelectionRange(selectionStart, selectionEnd); - return true; +function keyupEditAttention(event) { + const target = event.originalTarget || event.composedPath()[0]; + if (!target.matches("[id*='_toprow'] [id*='_prompt'] textarea")) return; + if (!(event.metaKey || event.ctrlKey)) return; + + const isPlus = event.key == 'ArrowUp'; + const isMinus = event.key == 'ArrowDown'; + if (!isPlus && !isMinus) return; + + let { selectionStart } = target; + let { selectionEnd } = target; + let text = target.value; + + function selectCurrentParenthesisBlock(OPEN, CLOSE) { + if (selectionStart !== selectionEnd) return false; + + // Find opening parenthesis around current cursor + const before = text.substring(0, selectionStart); + let beforeParen = before.lastIndexOf(OPEN); + if (beforeParen == -1) return false; + let beforeParenClose = before.lastIndexOf(CLOSE); + while (beforeParenClose !== -1 && beforeParenClose > beforeParen) { + beforeParen = before.lastIndexOf(OPEN, beforeParen - 1); + beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1); } - // If the user hasn't selected anything, let's select their current parenthesis block or word - if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) { - selectCurrentWord(); + // Find closing parenthesis around current cursor + const after = text.substring(selectionStart); + let afterParen = after.indexOf(CLOSE); + if (afterParen == -1) return false; + let afterParenOpen = after.indexOf(OPEN); + while (afterParenOpen !== -1 && afterParen > afterParenOpen) { + afterParen = after.indexOf(CLOSE, afterParen + 1); + afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1); + } + if (beforeParen === -1 || afterParen === -1) return false; + + // Set the selection to the text between the parenthesis + const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen); + const lastColon = parenContent.lastIndexOf(':'); + selectionStart = beforeParen + 1; + selectionEnd = selectionStart + lastColon; + target.setSelectionRange(selectionStart, selectionEnd); + return true; + } + + function selectCurrentWord() { + if (selectionStart !== selectionEnd) return false; + const delimiters = `${opts.keyedit_delimiters} \r\n\t`; + + // seek backward until to find beggining + while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) { + selectionStart--; } - event.preventDefault(); + // seek forward to find end + while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) { + selectionEnd++; + } - closeCharacter = ')' - delta = opts.keyedit_precision_attention + target.setSelectionRange(selectionStart, selectionEnd); + return true; + } - if (selectionStart > 0 && text[selectionStart - 1] == '<'){ - closeCharacter = '>' - delta = opts.keyedit_precision_extra - } else if (selectionStart == 0 || text[selectionStart - 1] != "(") { + // If the user hasn't selected anything, let's select their current parenthesis block or word + if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) { + selectCurrentWord(); + } - // do not include spaces at the end - while(selectionEnd > selectionStart && text[selectionEnd-1] == ' '){ - selectionEnd -= 1; - } - if(selectionStart == selectionEnd){ - return - } + event.preventDefault(); - text = text.slice(0, selectionStart) + "(" + text.slice(selectionStart, selectionEnd) + ":1.0)" + text.slice(selectionEnd); + closeCharacter = ')'; + delta = opts.keyedit_precision_attention; - selectionStart += 1; - selectionEnd += 1; + if (selectionStart > 0 && text[selectionStart - 1] == '<') { + closeCharacter = '>'; + delta = opts.keyedit_precision_extra; + } else if (selectionStart == 0 || text[selectionStart - 1] != '(') { + // do not include spaces at the end + while (selectionEnd > selectionStart && text[selectionEnd - 1] == ' ') { + selectionEnd -= 1; + } + if (selectionStart == selectionEnd) { + return; } - end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1; - weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end)); - if (isNaN(weight)) return; + text = `${text.slice(0, selectionStart)}(${text.slice(selectionStart, selectionEnd)}:1.0)${text.slice(selectionEnd)}`; - weight += isPlus ? delta : -delta; - weight = parseFloat(weight.toPrecision(12)); - if(String(weight).length == 1) weight += ".0" + selectionStart += 1; + selectionEnd += 1; + } - if (closeCharacter == ')' && weight == 1) { - text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + 5); - selectionStart--; - selectionEnd--; - } else { - text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1); - } + end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1; + weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end)); + if (isNaN(weight)) return; + + weight += isPlus ? delta : -delta; + weight = parseFloat(weight.toPrecision(12)); + if (String(weight).length == 1) weight += '.0'; + + if (closeCharacter == ')' && weight == 1) { + text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + 5); + selectionStart--; + selectionEnd--; + } else { + text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1); + } - target.focus(); - target.value = text; - target.selectionStart = selectionStart; - target.selectionEnd = selectionEnd; + target.focus(); + target.value = text; + target.selectionStart = selectionStart; + target.selectionEnd = selectionEnd; - updateInput(target) + updateInput(target); } addEventListener('keydown', (event) => { - keyupEditAttention(event); + keyupEditAttention(event); }); diff --git a/javascript/extensions.js b/javascript/extensions.js index e64a0c795..2bcaa50fc 100644 --- a/javascript/extensions.js +++ b/javascript/extensions.js @@ -1,5 +1,4 @@ - -function extensions_apply(_, _, disable_all){ +function extensions_apply(_a, _b, disable_all){ var disable = [] var update = [] gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){ diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index bff379beb..9b2a610f7 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -1,170 +1,170 @@ -function setupExtraNetworksForTab(tabname){ - gradioApp().querySelector('#'+tabname+'_extra_tabs').classList.add('extra-networks') - var tabs = gradioApp().querySelector('#'+tabname+'_extra_tabs > div') - var search = gradioApp().querySelector('#'+tabname+'_extra_search textarea') - var refresh = gradioApp().getElementById(tabname+'_extra_refresh') - var descriptInput = gradioApp().getElementById(tabname+ '_description_input') - var close = gradioApp().getElementById(tabname+'_extra_close') - search.classList.add('search') - tabs.appendChild(search) - tabs.appendChild(refresh) - tabs.appendChild(close) - tabs.appendChild(descriptInput) - search.addEventListener("input", function(evt){ - searchTerm = search.value.toLowerCase() - gradioApp().querySelectorAll('#'+tabname+'_extra_tabs div.card').forEach(function(elem){ - text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase() - elem.style.display = text.indexOf(searchTerm) == -1 ? "none" : "" - }) +function setupExtraNetworksForTab(tabname) { + gradioApp().querySelector(`#${tabname}_extra_tabs`).classList.add('extra-networks'); + const tabs = gradioApp().querySelector(`#${tabname}_extra_tabs > div`); + const search = gradioApp().querySelector(`#${tabname}_extra_search textarea`); + const refresh = gradioApp().getElementById(`${tabname}_extra_refresh`); + const descriptInput = gradioApp().getElementById(`${tabname}_description_input`); + const close = gradioApp().getElementById(`${tabname}_extra_close`); + search.classList.add('search'); + tabs.appendChild(search); + tabs.appendChild(refresh); + tabs.appendChild(close); + tabs.appendChild(descriptInput); + search.addEventListener('input', (evt) => { + searchTerm = search.value.toLowerCase(); + gradioApp().querySelectorAll(`#${tabname}_extra_tabs div.card`).forEach((elem) => { + text = `${elem.querySelector('.name').textContent.toLowerCase()} ${elem.querySelector('.search_term').textContent.toLowerCase()}`; + elem.style.display = text.indexOf(searchTerm) == -1 ? 'none' : ''; }); + }); } -var activePromptTextarea = {}; +const activePromptTextarea = {}; -function setupExtraNetworks(){ - setupExtraNetworksForTab('txt2img') - setupExtraNetworksForTab('img2img') - function registerPrompt(tabname, id){ - var textarea = gradioApp().querySelector("#" + id + " > label > textarea"); - if ( !activePromptTextarea[tabname]) activePromptTextarea[tabname] = textarea - textarea.addEventListener("focus", function(){ - activePromptTextarea[tabname] = textarea; - }); - } - registerPrompt('txt2img', 'txt2img_prompt') - registerPrompt('txt2img', 'txt2img_neg_prompt') - registerPrompt('img2img', 'img2img_prompt') - registerPrompt('img2img', 'img2img_neg_prompt') +function setupExtraNetworks() { + setupExtraNetworksForTab('txt2img'); + setupExtraNetworksForTab('img2img'); + function registerPrompt(tabname, id) { + const textarea = gradioApp().querySelector(`#${id} > label > textarea`); + if (!activePromptTextarea[tabname]) activePromptTextarea[tabname] = textarea; + textarea.addEventListener('focus', () => { + activePromptTextarea[tabname] = textarea; + }); + } + registerPrompt('txt2img', 'txt2img_prompt'); + registerPrompt('txt2img', 'txt2img_neg_prompt'); + registerPrompt('img2img', 'img2img_prompt'); + registerPrompt('img2img', 'img2img_neg_prompt'); } -onUiLoaded(setupExtraNetworks) -var re_extranet = /<([^:]+:[^:]+):[\d\.]+>/; -var re_extranet_g = /\s+<([^:]+:[^:]+):[\d\.]+>/g; +onUiLoaded(setupExtraNetworks); +const re_extranet = /<([^:]+:[^:]+):[\d\.]+>/; +const re_extranet_g = /\s+<([^:]+:[^:]+):[\d\.]+>/g; -function tryToRemoveExtraNetworkFromPrompt(textarea, text){ - var m = text.match(re_extranet) - if(! m) return false - var partToSearch = m[1] - var replaced = false - var newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, index){ - m = found.match(re_extranet); - if(m[1] == partToSearch){ - replaced = true; - return "" - } - return found; - }) - if(replaced){ - textarea.value = newTextareaText - return true; +function tryToRemoveExtraNetworkFromPrompt(textarea, text) { + let m = text.match(re_extranet); + if (!m) return false; + const partToSearch = m[1]; + let replaced = false; + const newTextareaText = textarea.value.replaceAll(re_extranet_g, (found, index) => { + m = found.match(re_extranet); + if (m[1] == partToSearch) { + replaced = true; + return ''; } - return false + return found; + }); + if (replaced) { + textarea.value = newTextareaText; + return true; + } + return false; } -function cardClicked(tabname, textToAdd, allowNegativePrompt){ - var textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector("#" + tabname + "_prompt > label > textarea") - if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd - updateInput(textarea) +function cardClicked(tabname, textToAdd, allowNegativePrompt) { + const textarea = allowNegativePrompt ? activePromptTextarea[tabname] : gradioApp().querySelector(`#${tabname}_prompt > label > textarea`); + if (!tryToRemoveExtraNetworkFromPrompt(textarea, textToAdd)) textarea.value = textarea.value + opts.extra_networks_add_text_separator + textToAdd; + updateInput(textarea); } -function saveCardPreview(event, tabname, filename){ - var textarea = gradioApp().querySelector("#" + tabname + '_preview_filename > label > textarea') - var button = gradioApp().getElementById(tabname + '_save_preview') - textarea.value = filename - updateInput(textarea) - button.click() - event.stopPropagation() - event.preventDefault() +function saveCardPreview(event, tabname, filename) { + const textarea = gradioApp().querySelector(`#${tabname}_preview_filename > label > textarea`); + const button = gradioApp().getElementById(`${tabname}_save_preview`); + textarea.value = filename; + updateInput(textarea); + button.click(); + event.stopPropagation(); + event.preventDefault(); } -function saveCardDescription(event, tabname, filename, descript){ - var textarea = gradioApp().querySelector("#" + tabname + '_description_filename > label > textarea') - var button = gradioApp().getElementById(tabname + '_save_description') - var description = gradioApp().getElementById(tabname+ '_description_input') - textarea.value = filename - description.value=descript - updateInput(textarea) - button.click() - event.stopPropagation() - event.preventDefault() +function saveCardDescription(event, tabname, filename, descript) { + const textarea = gradioApp().querySelector(`#${tabname}_description_filename > label > textarea`); + const button = gradioApp().getElementById(`${tabname}_save_description`); + const description = gradioApp().getElementById(`${tabname}_description_input`); + textarea.value = filename; + description.value = descript; + updateInput(textarea); + button.click(); + event.stopPropagation(); + event.preventDefault(); } -function readCardDescription(event, tabname, filename, descript, extraPage, cardName){ - var textarea = gradioApp().querySelector("#" + tabname + '_description_filename > label > textarea') - var description_textarea = gradioApp().querySelector("#" + tabname+ '_description_input > label > textarea') - var button = gradioApp().getElementById(tabname + '_read_description') - textarea.value = filename - description_textarea.value = descript - updateInput(textarea) - updateInput(description_textarea) - button.click() - event.stopPropagation() - event.preventDefault() +function readCardDescription(event, tabname, filename, descript, extraPage, cardName) { + const textarea = gradioApp().querySelector(`#${tabname}_description_filename > label > textarea`); + const description_textarea = gradioApp().querySelector(`#${tabname}_description_input > label > textarea`); + const button = gradioApp().getElementById(`${tabname}_read_description`); + textarea.value = filename; + description_textarea.value = descript; + updateInput(textarea); + updateInput(description_textarea); + button.click(); + event.stopPropagation(); + event.preventDefault(); } -function extraNetworksSearchButton(tabs_id, event){ - searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea') - button = event.target - text = button.classList.contains("search-all") ? "" : button.textContent.trim() - searchTextarea.value = text - updateInput(searchTextarea) +function extraNetworksSearchButton(tabs_id, event) { + searchTextarea = gradioApp().querySelector(`#${tabs_id} > div > textarea`); + button = event.target; + text = button.classList.contains('search-all') ? '' : button.textContent.trim(); + searchTextarea.value = text; + updateInput(searchTextarea); } -var globalPopup = null; -var globalPopupInner = null; -function popup(contents){ - if(! globalPopup){ - globalPopup = document.createElement('div') - globalPopup.onclick = function(){ globalPopup.style.display = "none"; }; - globalPopup.classList.add('global-popup'); - var close = document.createElement('div') - close.classList.add('global-popup-close'); - close.onclick = function(){ globalPopup.style.display = "none"; }; - close.title = "Close"; - globalPopup.appendChild(close) - globalPopupInner = document.createElement('div') - globalPopupInner.onclick = function(event){ event.stopPropagation(); return false; }; - globalPopupInner.classList.add('global-popup-inner'); - globalPopup.appendChild(globalPopupInner) - gradioApp().appendChild(globalPopup); - } - globalPopupInner.innerHTML = ''; - globalPopupInner.appendChild(contents); - globalPopup.style.display = "flex"; +let globalPopup = null; +let globalPopupInner = null; +function popup(contents) { + if (!globalPopup) { + globalPopup = document.createElement('div'); + globalPopup.onclick = function () { globalPopup.style.display = 'none'; }; + globalPopup.classList.add('global-popup'); + const close = document.createElement('div'); + close.classList.add('global-popup-close'); + close.onclick = function () { globalPopup.style.display = 'none'; }; + close.title = 'Close'; + globalPopup.appendChild(close); + globalPopupInner = document.createElement('div'); + globalPopupInner.onclick = function (event) { event.stopPropagation(); return false; }; + globalPopupInner.classList.add('global-popup-inner'); + globalPopup.appendChild(globalPopupInner); + gradioApp().appendChild(globalPopup); + } + globalPopupInner.innerHTML = ''; + globalPopupInner.appendChild(contents); + globalPopup.style.display = 'flex'; } -function readCardMetadata(event, extraPage, cardName){ - requestGet("./sd_extra_networks/metadata", {"page": extraPage, "item": cardName}, function(data){ - if (data && data.metadata){ - elem = document.createElement('pre') - elem.classList.add('popup-metadata'); - elem.textContent = data.metadata; - popup(elem); - } - }, () => {}) - event.stopPropagation() - event.preventDefault() +function readCardMetadata(event, extraPage, cardName) { + requestGet('./sd_extra_networks/metadata', { page: extraPage, item: cardName }, (data) => { + if (data && data.metadata) { + elem = document.createElement('pre'); + elem.classList.add('popup-metadata'); + elem.textContent = data.metadata; + popup(elem); + } + }, () => {}); + event.stopPropagation(); + event.preventDefault(); } -function requestGet(url, data, handler, errorHandler){ - var xhr = new XMLHttpRequest(); - var args = Object.keys(data).map(function(k){ return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]) }).join('&') - xhr.open("GET", url + "?" + args, true); - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200) { - try { - var js = JSON.parse(xhr.responseText); - handler(js) - } catch (error) { - console.error(error); - errorHandler() - } - } else{ - errorHandler() - } +function requestGet(url, data, handler, errorHandler) { + const xhr = new XMLHttpRequest(); + const args = Object.keys(data).map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`).join('&'); + xhr.open('GET', `${url}?${args}`, true); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + try { + const js = JSON.parse(xhr.responseText); + handler(js); + } catch (error) { + console.error(error); + errorHandler(); } - }; - var js = JSON.stringify(data); - xhr.send(js); + } else { + errorHandler(); + } + } + }; + const js = JSON.stringify(data); + xhr.send(js); } diff --git a/javascript/generationParams.js b/javascript/generationParams.js index 5d4f996bf..b98418406 100644 --- a/javascript/generationParams.js +++ b/javascript/generationParams.js @@ -1,30 +1,30 @@ // attaches listeners to the txt2img and img2img galleries to update displayed generation param text when the image changes -let txt2img_gallery, img2img_gallery, modal = undefined; -onUiUpdate(function(){ - if (!txt2img_gallery) txt2img_gallery = attachGalleryListeners("txt2img") - if (!img2img_gallery) img2img_gallery = attachGalleryListeners("img2img") - if (!modal) { - modal = gradioApp().getElementById('lightboxModal') - modalObserver.observe(modal, { attributes : true, attributeFilter : ['style'] }); - } +let txt2img_gallery; let img2img_gallery; let + modal; +onUiUpdate(() => { + if (!txt2img_gallery) txt2img_gallery = attachGalleryListeners('txt2img'); + if (!img2img_gallery) img2img_gallery = attachGalleryListeners('img2img'); + if (!modal) { + modal = gradioApp().getElementById('lightboxModal'); + modalObserver.observe(modal, { attributes: true, attributeFilter: ['style'] }); + } }); -let modalObserver = new MutationObserver(function(mutations) { - mutations.forEach((mutationRecord) => { - let selectedTab = gradioApp().querySelector('#tabs div button.selected')?.innerText - if (!selectedTab) selectedTab = gradioApp().querySelector('#tabs div button')?.innerText - if (mutationRecord.target.style.display === 'none' && (selectedTab === 'txt2img' || selectedTab === 'img2img')) - gradioApp().getElementById(selectedTab+"_generation_info_button")?.click() - }); +let modalObserver = new MutationObserver((mutations) => { + mutations.forEach((mutationRecord) => { + let selectedTab = gradioApp().querySelector('#tabs div button.selected')?.innerText; + if (!selectedTab) selectedTab = gradioApp().querySelector('#tabs div button')?.innerText; + if (mutationRecord.target.style.display === 'none' && (selectedTab === 'txt2img' || selectedTab === 'img2img')) { gradioApp().getElementById(`${selectedTab}_generation_info_button`)?.click(); } + }); }); function attachGalleryListeners(tab_name) { - gallery = gradioApp().querySelector('#'+tab_name+'_gallery') - gallery?.addEventListener('click', () => gradioApp().getElementById(tab_name+"_generation_info_button").click()); - gallery?.addEventListener('keydown', (e) => { - if (e.keyCode == 37 || e.keyCode == 39) // left or right arrow - gradioApp().getElementById(tab_name+"_generation_info_button").click() - }); - return gallery; + gallery = gradioApp().querySelector(`#${tab_name}_gallery`); + gallery?.addEventListener('click', () => gradioApp().getElementById(`${tab_name}_generation_info_button`).click()); + gallery?.addEventListener('keydown', (e) => { + if (e.keyCode == 37 || e.keyCode == 39) // left or right arrow + { gradioApp().getElementById(`${tab_name}_generation_info_button`).click(); } + }); + return gallery; } diff --git a/javascript/hints.js b/javascript/hints.js index f48a0eb69..61da3e357 100644 --- a/javascript/hints.js +++ b/javascript/hints.js @@ -1,147 +1,146 @@ // mouseover tooltips for various UI elements titles = { - "Sampling steps": "How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results", - "Sampling method": "Which algorithm to use to produce the image", - "GFPGAN": "Restore low quality faces using GFPGAN neural network", - "Euler a": "Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps higher than 30-40 does not help", - "DDIM": "Denoising Diffusion Implicit Models - best at inpainting", - "UniPC": "Unified Predictor-Corrector Framework for Fast Sampling of Diffusion Models", - "DPM adaptive": "Ignores step count - uses a number of steps determined by the CFG and resolution", - - "Batch count": "How many batches of images to create (has no impact on generation performance or VRAM usage)", - "Batch size": "How many image to create in a single batch (increases generation performance at cost of higher VRAM usage)", - "CFG Scale": "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results", - "Seed": "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result", - "\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time", - "\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed", - "\u2199\ufe0f": "Read generation parameters from prompt or last generation if prompt is empty into user interface.", - "\u{1f4c2}": "Open images output directory", - "\u{1f4be}": "Save style", - "\u{1f5d1}\ufe0f": "Clear prompt", - "\u{1f4cb}": "Apply selected styles to current prompt", - "\u{1f4d2}": "Paste available values into the field", - "\u{1f3b4}": "Show/hide extra networks", - - "Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt", - "SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back", - - "Just resize": "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.", - "Crop and resize": "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.", - "Resize and fill": "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.", - - "Mask blur": "How much to blur the mask before processing, in pixels.", - "Masked content": "What to put inside the masked area before processing it with Stable Diffusion.", - "fill": "fill it with colors of the image", - "original": "keep whatever was there originally", - "latent noise": "fill it with latent space noise", - "latent nothing": "fill it with latent space zeroes", - "Inpaint at full resolution": "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image", - - "Denoising strength": "Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies.", - - "Skip": "Stop processing current image and continue processing.", - "Interrupt": "Stop processing images and return any results accumulated so far.", - "Save": "Write image to a directory (default - log/images) and generation parameters into csv file.", - - "X values": "Separate values for X axis using commas.", - "Y values": "Separate values for Y axis using commas.", - - "None": "Do not do anything special", - "Prompt matrix": "Separate prompts into parts using vertical pipe character (|) and the script will create a picture for every combination of them (except for the first part, which will be present in all combinations)", - "X/Y/Z plot": "Create grid(s) where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows", - "Custom code": "Run Python code. Advanced user only. Must run program with --allow-code for this to work", - - "Prompt S/R": "Separate a list of words with commas, and the first word will be used as a keyword: script will search for this word in the prompt, and replace it with others", - "Prompt order": "Separate a list of words with commas, and the script will make a variation of prompt with those words for their every possible order", - - "Tiling": "Produce an image that can be tiled.", - "Tile overlap": "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.", - - "Variation seed": "Seed of a different picture to be mixed into the generation.", - "Variation strength": "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).", - "Resize seed from height": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution", - "Resize seed from width": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution", - - "Interrogate": "Reconstruct prompt from existing image and put it into the prompt field.", - - "Images filename pattern": "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime], [datetime