aboutsummaryrefslogtreecommitdiff
path: root/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'javascript')
-rw-r--r--javascript/aspectRatioOverlay.js33
-rw-r--r--javascript/contextMenus.js20
-rw-r--r--javascript/edit-attention.js46
-rw-r--r--javascript/extensions.js34
-rw-r--r--javascript/extraNetworks.js18
-rw-r--r--javascript/generationParams.js8
-rw-r--r--javascript/hints.js13
-rw-r--r--javascript/hires_fix.js16
-rw-r--r--javascript/imageMaskFix.js13
-rw-r--r--javascript/imageParams.js1
-rw-r--r--javascript/imageviewer.js19
-rw-r--r--javascript/imageviewerGamepad.js36
-rw-r--r--javascript/localization.js10
-rw-r--r--javascript/notification.js6
-rw-r--r--javascript/progressbar.js11
-rw-r--r--javascript/ui.js92
16 files changed, 252 insertions, 124 deletions
diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js
index a8278cca..5160081d 100644
--- a/javascript/aspectRatioOverlay.js
+++ b/javascript/aspectRatioOverlay.js
@@ -45,29 +45,24 @@ function dimensionChange(e, is_width, is_height){
var viewportOffset = targetElement.getBoundingClientRect();
- viewportscale = Math.min( targetElement.clientWidth/targetElement.naturalWidth, targetElement.clientHeight/targetElement.naturalHeight )
+ var viewportscale = Math.min( targetElement.clientWidth/targetElement.naturalWidth, targetElement.clientHeight/targetElement.naturalHeight )
- scaledx = targetElement.naturalWidth*viewportscale
- scaledy = targetElement.naturalHeight*viewportscale
+ var scaledx = targetElement.naturalWidth*viewportscale
+ var scaledy = targetElement.naturalHeight*viewportscale
- cleintRectTop = (viewportOffset.top+window.scrollY)
- cleintRectLeft = (viewportOffset.left+window.scrollX)
- cleintRectCentreY = cleintRectTop + (targetElement.clientHeight/2)
- cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth/2)
+ var cleintRectTop = (viewportOffset.top+window.scrollY)
+ var cleintRectLeft = (viewportOffset.left+window.scrollX)
+ var cleintRectCentreY = cleintRectTop + (targetElement.clientHeight/2)
+ var cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth/2)
- viewRectTop = cleintRectCentreY-(scaledy/2)
- viewRectLeft = cleintRectCentreX-(scaledx/2)
- arRectWidth = scaledx
- arRectHeight = scaledy
+ var arscale = Math.min( scaledx/currentWidth, scaledy/currentHeight )
+ var arscaledx = currentWidth*arscale
+ var 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
+ var arRectTop = cleintRectCentreY-(arscaledy/2)
+ var arRectLeft = cleintRectCentreX-(arscaledx/2)
+ var arRectWidth = arscaledx
+ var arRectHeight = arscaledy
arPreviewRect.style.top = arRectTop+'px';
arPreviewRect.style.left = arRectLeft+'px';
diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js
index 06f505b0..42f301ab 100644
--- a/javascript/contextMenus.js
+++ b/javascript/contextMenus.js
@@ -4,7 +4,7 @@ contextMenuInit = function(){
let menuSpecs = new Map();
const uid = function(){
- return Date.now().toString(36) + Math.random().toString(36).substr(2);
+ return Date.now().toString(36) + Math.random().toString(36).substring(2);
}
function showContextMenu(event,element,menuEntries){
@@ -16,8 +16,7 @@ contextMenuInit = function(){
oldMenu.remove()
}
- let tabButton = uiCurrentTab
- let baseStyle = window.getComputedStyle(tabButton)
+ let baseStyle = window.getComputedStyle(uiCurrentTab)
const contextMenu = document.createElement('nav')
contextMenu.id = "context-menu"
@@ -36,7 +35,7 @@ contextMenuInit = function(){
menuEntries.forEach(function(entry){
let contextMenuEntry = document.createElement('a')
contextMenuEntry.innerHTML = entry['name']
- contextMenuEntry.addEventListener("click", function(e) {
+ contextMenuEntry.addEventListener("click", function() {
entry['func']();
})
contextMenuList.append(contextMenuEntry);
@@ -63,7 +62,7 @@ contextMenuInit = function(){
function appendContextMenuOption(targetElementSelector,entryName,entryFunction){
- currentItems = menuSpecs.get(targetElementSelector)
+ var currentItems = menuSpecs.get(targetElementSelector)
if(!currentItems){
currentItems = []
@@ -79,7 +78,7 @@ contextMenuInit = function(){
}
function removeContextMenuOption(uid){
- menuSpecs.forEach(function(v,k) {
+ menuSpecs.forEach(function(v) {
let index = -1
v.forEach(function(e,ei){if(e['id']==uid){index=ei}})
if(index>=0){
@@ -112,7 +111,6 @@ contextMenuInit = function(){
if(e.composedPath()[0].matches(k)){
showContextMenu(e,e.composedPath()[0],v)
e.preventDefault()
- return
}
})
});
@@ -161,14 +159,6 @@ addContextMenuEventListener = initResponse[2];
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
diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index 20a5aadf..d2c2f190 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -17,7 +17,7 @@ function keyupEditAttention(event){
// Find opening parenthesis around current cursor
const before = text.substring(0, selectionStart);
let beforeParen = before.lastIndexOf(OPEN);
- if (beforeParen == -1) return false;
+ if (beforeParen == -1) return false;
let beforeParenClose = before.lastIndexOf(CLOSE);
while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);
@@ -27,7 +27,7 @@ function keyupEditAttention(event){
// Find closing parenthesis around current cursor
const after = text.substring(selectionStart);
let afterParen = after.indexOf(CLOSE);
- if (afterParen == -1) return false;
+ if (afterParen == -1) return false;
let afterParenOpen = after.indexOf(OPEN);
while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
afterParen = after.indexOf(CLOSE, afterParen + 1);
@@ -43,16 +43,34 @@ function keyupEditAttention(event){
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++;
+ }
- // If the user hasn't selected anything, let's select their current parenthesis block
- if(! selectCurrentParenthesisBlock('<', '>')){
- selectCurrentParenthesisBlock('(', ')')
+ target.setSelectionRange(selectionStart, selectionEnd);
+ return true;
+ }
+
+ // If the user hasn't selected anything, let's select their current parenthesis block or word
+ if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) {
+ selectCurrentWord();
}
event.preventDefault();
- closeCharacter = ')'
- delta = opts.keyedit_precision_attention
+ var closeCharacter = ')'
+ var delta = opts.keyedit_precision_attention
if (selectionStart > 0 && text[selectionStart - 1] == '<'){
closeCharacter = '>'
@@ -73,15 +91,21 @@ function keyupEditAttention(event){
selectionEnd += 1;
}
- end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
- weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));
+ var end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
+ var 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"
- text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 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);
+ }
target.focus();
target.value = text;
@@ -93,4 +117,4 @@ function keyupEditAttention(event){
addEventListener('keydown', (event) => {
keyupEditAttention(event);
-}); \ No newline at end of file
+});
diff --git a/javascript/extensions.js b/javascript/extensions.js
index 72924a28..2a2d2f8e 100644
--- a/javascript/extensions.js
+++ b/javascript/extensions.js
@@ -1,14 +1,14 @@
-function extensions_apply(_, _, disable_all){
+function extensions_apply(_disabled_list, _update_list, disable_all){
var disable = []
var update = []
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
if(x.name.startsWith("enable_") && ! x.checked)
- disable.push(x.name.substr(7))
+ disable.push(x.name.substring(7))
if(x.name.startsWith("update_") && x.checked)
- update.push(x.name.substr(7))
+ update.push(x.name.substring(7))
})
restart_reload()
@@ -16,12 +16,12 @@ function extensions_apply(_, _, disable_all){
return [JSON.stringify(disable), JSON.stringify(update), disable_all]
}
-function extensions_check(_, _){
+function extensions_check(){
var disable = []
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
if(x.name.startsWith("enable_") && ! x.checked)
- disable.push(x.name.substr(7))
+ disable.push(x.name.substring(7))
})
gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
@@ -41,9 +41,31 @@ function install_extension_from_index(button, url){
button.disabled = "disabled"
button.value = "Installing..."
- textarea = gradioApp().querySelector('#extension_to_install textarea')
+ var textarea = gradioApp().querySelector('#extension_to_install textarea')
textarea.value = url
updateInput(textarea)
gradioApp().querySelector('#install_extension_button').click()
}
+
+function config_state_confirm_restore(_, config_state_name, config_restore_type) {
+ if (config_state_name == "Current") {
+ return [false, config_state_name, config_restore_type];
+ }
+ let restored = "";
+ if (config_restore_type == "extensions") {
+ restored = "all saved extension versions";
+ } else if (config_restore_type == "webui") {
+ restored = "the webui version";
+ } else {
+ restored = "the webui version and all saved extension versions";
+ }
+ let confirmed = confirm("Are you sure you want to restore from this state?\nThis will reset " + restored + ".");
+ if (confirmed) {
+ restart_reload();
+ gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
+ x.innerHTML = "Loading..."
+ })
+ }
+ return [confirmed, config_state_name, config_restore_type];
+}
diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js
index 25322138..c8f6b386 100644
--- a/javascript/extraNetworks.js
+++ b/javascript/extraNetworks.js
@@ -10,11 +10,11 @@ function setupExtraNetworksForTab(tabname){
tabs.appendChild(search)
tabs.appendChild(refresh)
- search.addEventListener("input", function(evt){
- searchTerm = search.value.toLowerCase()
+ search.addEventListener("input", function(){
+ var 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()
+ var text = elem.querySelector('.name').textContent.toLowerCase() + " " + elem.querySelector('.search_term').textContent.toLowerCase()
elem.style.display = text.indexOf(searchTerm) == -1 ? "none" : ""
})
});
@@ -55,7 +55,7 @@ function tryToRemoveExtraNetworkFromPrompt(textarea, text){
var partToSearch = m[1]
var replaced = false
- var newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found, index){
+ var newTextareaText = textarea.value.replaceAll(re_extranet_g, function(found){
m = found.match(re_extranet);
if(m[1] == partToSearch){
replaced = true;
@@ -96,9 +96,9 @@ function saveCardPreview(event, tabname, filename){
}
function extraNetworksSearchButton(tabs_id, event){
- searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea')
- button = event.target
- text = button.classList.contains("search-all") ? "" : button.textContent.trim()
+ var searchTextarea = gradioApp().querySelector("#" + tabs_id + ' > div > textarea')
+ var button = event.target
+ var text = button.classList.contains("search-all") ? "" : button.textContent.trim()
searchTextarea.value = text
updateInput(searchTextarea)
@@ -133,7 +133,7 @@ function popup(contents){
}
function extraNetworksShowMetadata(text){
- elem = document.createElement('pre')
+ var elem = document.createElement('pre')
elem.classList.add('popup-metadata');
elem.textContent = text;
@@ -165,7 +165,7 @@ function requestGet(url, data, handler, errorHandler){
}
function extraNetworksRequestMetadata(event, extraPage, cardName){
- showError = function(){ extraNetworksShowMetadata("there was an error getting metadata"); }
+ var showError = function(){ extraNetworksShowMetadata("there was an error getting metadata"); }
requestGet("./sd_extra_networks/metadata", {"page": extraPage, "item": cardName}, function(data){
if(data && data.metadata){
diff --git a/javascript/generationParams.js b/javascript/generationParams.js
index 95f05093..ef64ee2e 100644
--- a/javascript/generationParams.js
+++ b/javascript/generationParams.js
@@ -16,14 +16,14 @@ onUiUpdate(function(){
let modalObserver = new MutationObserver(function(mutations) {
mutations.forEach(function(mutationRecord) {
- let selectedTab = gradioApp().querySelector('#tabs div button.bg-white')?.innerText
- if (mutationRecord.target.style.display === 'none' && selectedTab === 'txt2img' || selectedTab === 'img2img')
- gradioApp().getElementById(selectedTab+"_generation_info_button").click()
+ let selectedTab = gradioApp().querySelector('#tabs div button.selected')?.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')
+ var 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
diff --git a/javascript/hints.js b/javascript/hints.js
index f48a0eb6..8d1967a7 100644
--- a/javascript/hints.js
+++ b/javascript/hints.js
@@ -22,6 +22,7 @@ titles = {
"\u{1f4cb}": "Apply selected styles to current prompt",
"\u{1f4d2}": "Paste available values into the field",
"\u{1f3b4}": "Show/hide extra networks",
+ "\u{1f300}": "Restore progress",
"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",
@@ -65,8 +66,8 @@ titles = {
"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<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
- "Directory name pattern": "Use following tags to define how subdirectories for images and grids 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<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
+ "Images filename pattern": "Use following tags to define how filenames for images are chosen: [steps], [cfg], [clip_skip], [batch_number], [generation_number], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp], [hasprompt<prompt1|default><prompt2>..]; leave empty for default.",
+ "Directory name pattern": "Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg], [clip_skip], [batch_number], [generation_number], [prompt_hash], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp], [hasprompt<prompt1|default><prompt2>..]; leave empty for default.",
"Max prompt words": "Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle",
"Loopback": "Performs img2img processing multiple times. Output images are used as input for the next loop.",
@@ -85,7 +86,6 @@ titles = {
"vram": "Torch active: Peak amount of VRAM used by Torch during generation, excluding cached data.\nTorch reserved: Peak amount of VRAM allocated by Torch, including all active and cached data.\nSys VRAM: Peak amount of VRAM allocation across all applications / total GPU VRAM (peak utilization%).",
"Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.",
- "Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.",
"Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.",
"Filename join string": "This string will be used to join split words into a single line if the option above is enabled.",
@@ -111,13 +111,16 @@ titles = {
"Resize height to": "Resizes image to this height. If 0, height is inferred from either of two nearby sliders.",
"Multiplier for extra networks": "When adding extra network such as Hypernetwork or Lora to prompt, use this multiplier for it.",
"Discard weights with matching name": "Regular expression; if weights's name matches it, the weights is not written to the resulting checkpoint. Use ^model_ema to discard EMA weights.",
- "Extra networks tab order": "Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited."
+ "Extra networks tab order": "Comma-separated list of tab names; tabs listed here will appear in the extra networks UI first and in order lsited.",
+ "Negative Guidance minimum sigma": "Skip negative prompt for steps where image is already mostly denoised; the higher this value, the more skips there will be; provides increased performance in exchange for minor quality reduction."
}
onUiUpdate(function(){
gradioApp().querySelectorAll('span, button, select, p').forEach(function(span){
- tooltip = titles[span.textContent];
+ if (span.title) return; // already has a title
+
+ let tooltip = titles[span.textContent];
if(!tooltip){
tooltip = titles[span.value];
diff --git a/javascript/hires_fix.js b/javascript/hires_fix.js
index 0629475f..48196be4 100644
--- a/javascript/hires_fix.js
+++ b/javascript/hires_fix.js
@@ -1,16 +1,12 @@
-function setInactive(elem, inactive){
- if(inactive){
- elem.classList.add('inactive')
- } else{
- elem.classList.remove('inactive')
+function onCalcResolutionHires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y){
+ function setInactive(elem, inactive){
+ elem.classList.toggle('inactive', !!inactive)
}
-}
-function onCalcResolutionHires(enable, width, height, hr_scale, hr_resize_x, hr_resize_y){
- hrUpscaleBy = gradioApp().getElementById('txt2img_hr_scale')
- hrResizeX = gradioApp().getElementById('txt2img_hr_resize_x')
- hrResizeY = gradioApp().getElementById('txt2img_hr_resize_y')
+ var hrUpscaleBy = gradioApp().getElementById('txt2img_hr_scale')
+ var hrResizeX = gradioApp().getElementById('txt2img_hr_resize_x')
+ var hrResizeY = gradioApp().getElementById('txt2img_hr_resize_y')
gradioApp().getElementById('txt2img_hires_fix_row2').style.display = opts.use_old_hires_fix_width_height ? "none" : ""
diff --git a/javascript/imageMaskFix.js b/javascript/imageMaskFix.js
index 9fe7a603..a612705d 100644
--- a/javascript/imageMaskFix.js
+++ b/javascript/imageMaskFix.js
@@ -2,11 +2,10 @@
* temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668
* @see https://github.com/gradio-app/gradio/issues/1721
*/
-window.addEventListener( 'resize', () => imageMaskResize());
function imageMaskResize() {
const canvases = gradioApp().querySelectorAll('#img2maskimg .touch-none canvas');
if ( ! canvases.length ) {
- canvases_fixed = false;
+ canvases_fixed = false; // TODO: this is unused..?
window.removeEventListener( 'resize', imageMaskResize );
return;
}
@@ -15,7 +14,7 @@ function imageMaskResize() {
const previewImage = wrapper.previousElementSibling;
if ( ! previewImage.complete ) {
- previewImage.addEventListener( 'load', () => imageMaskResize());
+ previewImage.addEventListener( 'load', imageMaskResize);
return;
}
@@ -24,7 +23,6 @@ function imageMaskResize() {
const nw = previewImage.naturalWidth;
const nh = previewImage.naturalHeight;
const portrait = nh > nw;
- const factor = portrait;
const wW = Math.min(w, portrait ? h/nh*nw : w/nw*nw);
const wH = Math.min(h, portrait ? h/nh*nh : w/nw*nh);
@@ -40,6 +38,7 @@ function imageMaskResize() {
c.style.maxHeight = '100%';
c.style.objectFit = 'contain';
});
- }
-
- onUiUpdate(() => imageMaskResize());
+}
+
+onUiUpdate(imageMaskResize);
+window.addEventListener( 'resize', imageMaskResize);
diff --git a/javascript/imageParams.js b/javascript/imageParams.js
index 67404a89..64aee93b 100644
--- a/javascript/imageParams.js
+++ b/javascript/imageParams.js
@@ -1,7 +1,6 @@
window.onload = (function(){
window.addEventListener('drop', e => {
const target = e.composedPath()[0];
- const idx = selected_gallery_index();
if (target.placeholder.indexOf("Prompt") == -1) return;
let prompt_target = get_tab_index('tabs') == 1 ? "img2img_prompt_image" : "txt2img_prompt_image";
diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js
index d6483562..32066ab8 100644
--- a/javascript/imageviewer.js
+++ b/javascript/imageviewer.js
@@ -57,7 +57,7 @@ function modalImageSwitch(offset) {
})
if (result != -1) {
- nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]
+ var nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]
nextButton.click()
const modalImage = gradioApp().getElementById("modalImage");
const modal = gradioApp().getElementById("lightboxModal");
@@ -144,15 +144,11 @@ function setupImageForLightbox(e) {
}
function modalZoomSet(modalImage, enable) {
- if (enable) {
- modalImage.classList.add('modalImageFullscreen');
- } else {
- modalImage.classList.remove('modalImageFullscreen');
- }
+ if(modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);
}
function modalZoomToggle(event) {
- modalImage = gradioApp().getElementById("modalImage");
+ var modalImage = gradioApp().getElementById("modalImage");
modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
event.stopPropagation()
}
@@ -179,7 +175,7 @@ function galleryImageHandler(e) {
}
onUiUpdate(function() {
- fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img')
+ var fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img')
if (fullImg_preview != null) {
fullImg_preview.forEach(setupImageForLightbox);
}
@@ -251,8 +247,11 @@ document.addEventListener("DOMContentLoaded", function() {
modal.appendChild(modalNext)
- gradioApp().appendChild(modal)
-
+ try {
+ gradioApp().appendChild(modal);
+ } catch (e) {
+ gradioApp().body.appendChild(modal);
+ }
document.body.appendChild(modal);
diff --git a/javascript/imageviewerGamepad.js b/javascript/imageviewerGamepad.js
new file mode 100644
index 00000000..29bd7140
--- /dev/null
+++ b/javascript/imageviewerGamepad.js
@@ -0,0 +1,36 @@
+ let delay = 350//ms
+ window.addEventListener('gamepadconnected', (e) => {
+ console.log("Gamepad connected!")
+ const gamepad = e.gamepad;
+ setInterval(() => {
+ const xValue = gamepad.axes[0].toFixed(2);
+ if (xValue < -0.3) {
+ modalPrevImage(e);
+ } else if (xValue > 0.3) {
+ modalNextImage(e);
+ }
+
+ }, delay);
+ });
+
+
+ /*
+ Primarily for vr controller type pointer devices.
+ I use the wheel event because there's currently no way to do it properly with web xr.
+ */
+
+ let isScrolling = false;
+ window.addEventListener('wheel', (e) => {
+ if (isScrolling) return;
+ isScrolling = true;
+
+ if (e.deltaX <= -0.6) {
+ modalPrevImage(e);
+ } else if (e.deltaX >= 0.6) {
+ modalNextImage(e);
+ }
+
+ setTimeout(() => {
+ isScrolling = false;
+ }, delay);
+ }); \ No newline at end of file
diff --git a/javascript/localization.js b/javascript/localization.js
index 1a5a1dbb..e1ffa271 100644
--- a/javascript/localization.js
+++ b/javascript/localization.js
@@ -35,11 +35,11 @@ function canBeTranslated(node, text){
if(! text) return false;
if(! node.parentElement) return false;
- parentType = node.parentElement.nodeName
+ var parentType = node.parentElement.nodeName
if(parentType=='SCRIPT' || parentType=='STYLE' || parentType=='TEXTAREA') return false;
if (parentType=='OPTION' || parentType=='SPAN'){
- pnode = node
+ var pnode = node
for(var level=0; level<4; level++){
pnode = pnode.parentElement
if(! pnode) break;
@@ -69,7 +69,7 @@ function getTranslation(text){
}
function processTextNode(node){
- text = node.textContent.trim()
+ var text = node.textContent.trim()
if(! canBeTranslated(node, text)) return
@@ -105,7 +105,7 @@ function processNode(node){
}
function dumpTranslations(){
- dumped = {}
+ var dumped = {}
if (localization.rtl) {
dumped.rtl = true
}
@@ -151,7 +151,7 @@ document.addEventListener("DOMContentLoaded", function() {
})
function download_localization() {
- text = JSON.stringify(dumpTranslations(), null, 4)
+ var text = JSON.stringify(dumpTranslations(), null, 4)
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
diff --git a/javascript/notification.js b/javascript/notification.js
index 8ddd4c5d..83fce1f8 100644
--- a/javascript/notification.js
+++ b/javascript/notification.js
@@ -2,15 +2,15 @@
let lastHeadImg = null;
-notificationButton = null
+let notificationButton = null;
onUiUpdate(function(){
if(notificationButton == null){
notificationButton = gradioApp().getElementById('request_notifications')
if(notificationButton != null){
- notificationButton.addEventListener('click', function (evt) {
- Notification.requestPermission();
+ notificationButton.addEventListener('click', () => {
+ void Notification.requestPermission();
},true);
}
}
diff --git a/javascript/progressbar.js b/javascript/progressbar.js
index 4ac9b8db..8d2c3492 100644
--- a/javascript/progressbar.js
+++ b/javascript/progressbar.js
@@ -1,16 +1,15 @@
// code related to showing and updating progressbar shown as the image is being made
-function rememberGallerySelection(id_gallery){
+function rememberGallerySelection(){
}
-function getGallerySelectedIndex(id_gallery){
+function getGallerySelectedIndex(){
}
function request(url, data, handler, errorHandler){
var xhr = new XMLHttpRequest();
- var url = url;
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = function () {
@@ -66,7 +65,7 @@ function randomId(){
// starts sending progress requests to "/internal/progress" uri, creating progressbar above progressbarContainer element and
// preview inside gallery element. Cleans up all created stuff when the task is over and calls atEnd.
// calls onProgress every time there is a progress update
-function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgress){
+function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgress, inactivityTimeout=40){
var dateStart = new Date()
var wasEverActive = false
var parentProgressbar = progressbarContainer.parentNode
@@ -107,7 +106,7 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre
divProgress.style.width = rect.width + "px";
}
- progressText = ""
+ let progressText = ""
divInner.style.width = ((res.progress || 0) * 100.0) + '%'
divInner.style.background = res.progress ? "" : "transparent"
@@ -138,7 +137,7 @@ function requestProgress(id_task, progressbarContainer, gallery, atEnd, onProgre
return
}
- if(elapsedFromStart > 5 && !res.queued && !res.active){
+ if(elapsedFromStart > inactivityTimeout && !res.queued && !res.active){
removeProgressBar()
return
}
diff --git a/javascript/ui.js b/javascript/ui.js
index 4a440193..b63b84b2 100644
--- a/javascript/ui.js
+++ b/javascript/ui.js
@@ -1,7 +1,7 @@
// various functions for interaction with ui.py not large enough to warrant putting them in separate files
function set_theme(theme){
- gradioURL = window.location.href
+ var gradioURL = window.location.href
if (!gradioURL.includes('?__theme=')) {
window.location.replace(gradioURL + '?__theme=' + theme);
}
@@ -47,7 +47,7 @@ function extract_image_from_gallery(gallery){
return [gallery[0]];
}
- index = selected_gallery_index()
+ var index = selected_gallery_index()
if (index < 0 || index >= gallery.length){
// Use the first image in the gallery as the default
@@ -58,7 +58,7 @@ function extract_image_from_gallery(gallery){
}
function args_to_array(args){
- res = []
+ var res = []
for(var i=0;i<args.length;i++){
res.push(args[i])
}
@@ -138,7 +138,7 @@ function get_img2img_tab_index() {
}
function create_submit_args(args){
- res = []
+ var res = []
for(var i=0;i<args.length;i++){
res.push(args[i])
}
@@ -159,14 +159,24 @@ function showSubmitButtons(tabname, show){
gradioApp().getElementById(tabname+'_skip').style.display = show ? "none" : "block"
}
+function showRestoreProgressButton(tabname, show){
+ var button = gradioApp().getElementById(tabname + "_restore_progress")
+ if(! button) return
+
+ button.style.display = show ? "flex" : "none"
+}
+
function submit(){
rememberGallerySelection('txt2img_gallery')
showSubmitButtons('txt2img', false)
var id = randomId()
+ localStorage.setItem("txt2img_task_id", id);
+
requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function(){
showSubmitButtons('txt2img', true)
-
+ localStorage.removeItem("txt2img_task_id")
+ showRestoreProgressButton('txt2img', false)
})
var res = create_submit_args(arguments)
@@ -181,8 +191,12 @@ function submit_img2img(){
showSubmitButtons('img2img', false)
var id = randomId()
+ localStorage.setItem("img2img_task_id", id);
+
requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function(){
showSubmitButtons('img2img', true)
+ localStorage.removeItem("img2img_task_id")
+ showRestoreProgressButton('img2img', false)
})
var res = create_submit_args(arguments)
@@ -193,6 +207,42 @@ function submit_img2img(){
return res
}
+function restoreProgressTxt2img(){
+ showRestoreProgressButton("txt2img", false)
+ var id = localStorage.getItem("txt2img_task_id")
+
+ id = localStorage.getItem("txt2img_task_id")
+
+ if(id) {
+ requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function(){
+ showSubmitButtons('txt2img', true)
+ }, null, 0)
+ }
+
+ return id
+}
+
+function restoreProgressImg2img(){
+ showRestoreProgressButton("img2img", false)
+
+ var id = localStorage.getItem("img2img_task_id")
+
+ if(id) {
+ requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function(){
+ showSubmitButtons('img2img', true)
+ }, null, 0)
+ }
+
+ return id
+}
+
+
+onUiLoaded(function () {
+ showRestoreProgressButton('txt2img', localStorage.getItem("txt2img_task_id"))
+ showRestoreProgressButton('img2img', localStorage.getItem("img2img_task_id"))
+});
+
+
function modelmerger(){
var id = randomId()
requestProgress(id, gradioApp().getElementById('modelmerger_results_panel'), null, function(){})
@@ -204,7 +254,7 @@ function modelmerger(){
function ask_for_style_name(_, prompt_text, negative_prompt_text) {
- name_ = prompt('Style name:')
+ var name_ = prompt('Style name:')
return [name_, prompt_text, negative_prompt_text]
}
@@ -239,11 +289,11 @@ function recalculate_prompts_img2img(){
}
-opts = {}
+var opts = {}
onUiUpdate(function(){
if(Object.keys(opts).length != 0) return;
- json_elem = gradioApp().getElementById('settings_json')
+ var json_elem = gradioApp().getElementById('settings_json')
if(json_elem == null) return;
var textarea = json_elem.querySelector('textarea')
@@ -292,8 +342,8 @@ onUiUpdate(function(){
registerTextarea('img2img_prompt', 'img2img_token_counter', 'img2img_token_button')
registerTextarea('img2img_neg_prompt', 'img2img_negative_token_counter', 'img2img_negative_token_button')
- show_all_pages = gradioApp().getElementById('settings_show_all_pages')
- settings_tabs = gradioApp().querySelector('#settings div')
+ var show_all_pages = gradioApp().getElementById('settings_show_all_pages')
+ var settings_tabs = gradioApp().querySelector('#settings div')
if(show_all_pages && settings_tabs){
settings_tabs.appendChild(show_all_pages)
show_all_pages.onclick = function(){
@@ -305,9 +355,9 @@ onUiUpdate(function(){
})
onOptionsChanged(function(){
- elem = gradioApp().getElementById('sd_checkpoint_hash')
- sd_checkpoint_hash = opts.sd_checkpoint_hash || ""
- shorthash = sd_checkpoint_hash.substr(0,10)
+ var elem = gradioApp().getElementById('sd_checkpoint_hash')
+ var sd_checkpoint_hash = opts.sd_checkpoint_hash || ""
+ var shorthash = sd_checkpoint_hash.substring(0,10)
if(elem && elem.textContent != shorthash){
elem.textContent = shorthash
@@ -361,3 +411,19 @@ function selectCheckpoint(name){
desiredCheckpointName = name;
gradioApp().getElementById('change_checkpoint').click()
}
+
+function currentImg2imgSourceResolution(_, _, scaleBy){
+ var img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img')
+ return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy]
+}
+
+function updateImg2imgResizeToTextAfterChangingImage(){
+ // At the time this is called from gradio, the image has no yet been replaced.
+ // There may be a better solution, but this is simple and straightforward so I'm going with it.
+
+ setTimeout(function() {
+ gradioApp().getElementById('img2img_update_resize_to').click()
+ }, 500);
+
+ return []
+}