aboutsummaryrefslogtreecommitdiffstats
path: root/javascript
diff options
context:
space:
mode:
Diffstat (limited to 'javascript')
-rw-r--r--javascript/aspectRatioOverlay.js2
-rw-r--r--javascript/contextMenus.js18
-rw-r--r--javascript/edit-attention.js5
-rw-r--r--javascript/extensions.js18
-rw-r--r--javascript/extraNetworks.js50
-rw-r--r--javascript/generationParams.js2
-rw-r--r--javascript/hints.js85
-rw-r--r--javascript/imageMaskFix.js2
-rw-r--r--javascript/imageviewer.js2
-rw-r--r--javascript/imageviewerGamepad.js8
-rw-r--r--javascript/notification.js2
-rw-r--r--javascript/profilerVisualization.js153
-rw-r--r--javascript/ui.js2
-rw-r--r--javascript/ui_settings_hints.js2
14 files changed, 305 insertions, 46 deletions
diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js
index 1c08a1a9..2cf2d571 100644
--- a/javascript/aspectRatioOverlay.js
+++ b/javascript/aspectRatioOverlay.js
@@ -81,7 +81,7 @@ function dimensionChange(e, is_width, is_height) {
}
-onUiUpdate(function() {
+onAfterUiUpdate(function() {
var arPreviewRect = gradioApp().querySelector('#imageARPreview');
if (arPreviewRect) {
arPreviewRect.style.display = 'none';
diff --git a/javascript/contextMenus.js b/javascript/contextMenus.js
index f14af1d4..ccae242f 100644
--- a/javascript/contextMenus.js
+++ b/javascript/contextMenus.js
@@ -148,12 +148,18 @@ var addContextMenuEventListener = initResponse[2];
500);
};
- appendContextMenuOption('#txt2img_generate', 'Generate forever', function() {
+ let generateOnRepeat_txt2img = function() {
generateOnRepeat('#txt2img_generate', '#txt2img_interrupt');
- });
- appendContextMenuOption('#img2img_generate', 'Generate forever', function() {
+ };
+
+ let generateOnRepeat_img2img = function() {
generateOnRepeat('#img2img_generate', '#img2img_interrupt');
- });
+ };
+
+ appendContextMenuOption('#txt2img_generate', 'Generate forever', generateOnRepeat_txt2img);
+ appendContextMenuOption('#txt2img_interrupt', 'Generate forever', generateOnRepeat_txt2img);
+ appendContextMenuOption('#img2img_generate', 'Generate forever', generateOnRepeat_img2img);
+ appendContextMenuOption('#img2img_interrupt', 'Generate forever', generateOnRepeat_img2img);
let cancelGenerateForever = function() {
clearInterval(window.generateOnRepeatInterval);
@@ -167,6 +173,4 @@ var addContextMenuEventListener = initResponse[2];
})();
//End example Context Menu Items
-onUiUpdate(function() {
- addContextMenuEventListener();
-});
+onAfterUiUpdate(addContextMenuEventListener);
diff --git a/javascript/edit-attention.js b/javascript/edit-attention.js
index ffa73147..8906c892 100644
--- a/javascript/edit-attention.js
+++ b/javascript/edit-attention.js
@@ -100,11 +100,12 @@ function keyupEditAttention(event) {
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);
+ var endParenPos = text.substring(selectionEnd).indexOf(')');
+ text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + endParenPos + 1);
selectionStart--;
selectionEnd--;
} else {
- text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + 1 + end - 1);
+ text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + end);
}
target.focus();
diff --git a/javascript/extensions.js b/javascript/extensions.js
index efeaf3a5..1f7254c5 100644
--- a/javascript/extensions.js
+++ b/javascript/extensions.js
@@ -72,3 +72,21 @@ function config_state_confirm_restore(_, config_state_name, config_restore_type)
}
return [confirmed, config_state_name, config_restore_type];
}
+
+function toggle_all_extensions(event) {
+ gradioApp().querySelectorAll('#extensions .extension_toggle').forEach(function(checkbox_el) {
+ checkbox_el.checked = event.target.checked;
+ });
+}
+
+function toggle_extension() {
+ let all_extensions_toggled = true;
+ for (const checkbox_el of gradioApp().querySelectorAll('#extensions .extension_toggle')) {
+ if (!checkbox_el.checked) {
+ all_extensions_toggled = false;
+ break;
+ }
+ }
+
+ gradioApp().querySelector('#extensions .all_extensions_toggle').checked = all_extensions_toggled;
+}
diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js
index aafe0a00..b87bca3e 100644
--- a/javascript/extraNetworks.js
+++ b/javascript/extraNetworks.js
@@ -3,10 +3,17 @@ function setupExtraNetworksForTab(tabname) {
var tabs = gradioApp().querySelector('#' + tabname + '_extra_tabs > div');
var search = gradioApp().querySelector('#' + tabname + '_extra_search textarea');
+ var sort = gradioApp().getElementById(tabname + '_extra_sort');
+ var sortOrder = gradioApp().getElementById(tabname + '_extra_sortorder');
var refresh = gradioApp().getElementById(tabname + '_extra_refresh');
search.classList.add('search');
+ sort.classList.add('sort');
+ sortOrder.classList.add('sortorder');
+ sort.dataset.sortkey = 'sortDefault';
tabs.appendChild(search);
+ tabs.appendChild(sort);
+ tabs.appendChild(sortOrder);
tabs.appendChild(refresh);
var applyFilter = function() {
@@ -26,8 +33,51 @@ function setupExtraNetworksForTab(tabname) {
});
};
+ var applySort = function() {
+ var reverse = sortOrder.classList.contains("sortReverse");
+ var sortKey = sort.querySelector("input").value.toLowerCase().replace("sort", "").replaceAll(" ", "_").replace(/_+$/, "").trim();
+ sortKey = sortKey ? "sort" + sortKey.charAt(0).toUpperCase() + sortKey.slice(1) : "";
+ var sortKeyStore = sortKey ? sortKey + (reverse ? "Reverse" : "") : "";
+ if (!sortKey || sortKeyStore == sort.dataset.sortkey) {
+ return;
+ }
+
+ sort.dataset.sortkey = sortKeyStore;
+
+ var cards = gradioApp().querySelectorAll('#' + tabname + '_extra_tabs div.card');
+ cards.forEach(function(card) {
+ card.originalParentElement = card.parentElement;
+ });
+ var sortedCards = Array.from(cards);
+ sortedCards.sort(function(cardA, cardB) {
+ var a = cardA.dataset[sortKey];
+ var b = cardB.dataset[sortKey];
+ if (!isNaN(a) && !isNaN(b)) {
+ return parseInt(a) - parseInt(b);
+ }
+
+ return (a < b ? -1 : (a > b ? 1 : 0));
+ });
+ if (reverse) {
+ sortedCards.reverse();
+ }
+ cards.forEach(function(card) {
+ card.remove();
+ });
+ sortedCards.forEach(function(card) {
+ card.originalParentElement.appendChild(card);
+ });
+ };
+
search.addEventListener("input", applyFilter);
applyFilter();
+ ["change", "blur", "click"].forEach(function(evt) {
+ sort.querySelector("input").addEventListener(evt, applySort);
+ });
+ sortOrder.addEventListener("click", function() {
+ sortOrder.classList.toggle("sortReverse");
+ applySort();
+ });
extraNetworksApplyFilter[tabname] = applyFilter;
}
diff --git a/javascript/generationParams.js b/javascript/generationParams.js
index a877f8a5..7c0fd221 100644
--- a/javascript/generationParams.js
+++ b/javascript/generationParams.js
@@ -1,7 +1,7 @@
// 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() {
+onAfterUiUpdate(function() {
if (!txt2img_gallery) {
txt2img_gallery = attachGalleryListeners("txt2img");
}
diff --git a/javascript/hints.js b/javascript/hints.js
index 46f342cb..dc75ce31 100644
--- a/javascript/hints.js
+++ b/javascript/hints.js
@@ -15,7 +15,7 @@ var titles = {
"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",
+ "\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomized",
"\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",
@@ -112,21 +112,29 @@ var 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 listed.",
"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."
};
-function updateTooltipForSpan(span) {
- if (span.title) return; // already has a title
+function updateTooltip(element) {
+ if (element.title) return; // already has a title
- let tooltip = localization[titles[span.textContent]] || titles[span.textContent];
+ let text = element.textContent;
+ let tooltip = localization[titles[text]] || titles[text];
if (!tooltip) {
- tooltip = localization[titles[span.value]] || titles[span.value];
+ let value = element.value;
+ if (value) tooltip = localization[titles[value]] || titles[value];
}
if (!tooltip) {
- for (const c of span.classList) {
+ // Gradio dropdown options have `data-value`.
+ let dataValue = element.dataset.value;
+ if (dataValue) tooltip = localization[titles[dataValue]] || titles[dataValue];
+ }
+
+ if (!tooltip) {
+ for (const c of element.classList) {
if (c in titles) {
tooltip = localization[titles[c]] || titles[c];
break;
@@ -135,34 +143,53 @@ function updateTooltipForSpan(span) {
}
if (tooltip) {
- span.title = tooltip;
+ element.title = tooltip;
}
}
-function updateTooltipForSelect(select) {
- if (select.onchange != null) return;
+// Nodes to check for adding tooltips.
+const tooltipCheckNodes = new Set();
+// Timer for debouncing tooltip check.
+let tooltipCheckTimer = null;
- select.onchange = function() {
- select.title = localization[titles[select.value]] || titles[select.value] || "";
- };
+function processTooltipCheckNodes() {
+ for (const node of tooltipCheckNodes) {
+ updateTooltip(node);
+ }
+ tooltipCheckNodes.clear();
}
-var observedTooltipElements = {SPAN: 1, BUTTON: 1, SELECT: 1, P: 1};
-
-onUiUpdate(function(m) {
- m.forEach(function(record) {
- record.addedNodes.forEach(function(node) {
- if (observedTooltipElements[node.tagName]) {
- updateTooltipForSpan(node);
- }
- if (node.tagName == "SELECT") {
- updateTooltipForSelect(node);
+onUiUpdate(function(mutationRecords) {
+ for (const record of mutationRecords) {
+ if (record.type === "childList" && record.target.classList.contains("options")) {
+ // This smells like a Gradio dropdown menu having changed,
+ // so let's enqueue an update for the input element that shows the current value.
+ let wrap = record.target.parentNode;
+ let input = wrap?.querySelector("input");
+ if (input) {
+ input.title = ""; // So we'll even have a chance to update it.
+ tooltipCheckNodes.add(input);
}
-
- if (node.querySelectorAll) {
- node.querySelectorAll('span, button, select, p').forEach(updateTooltipForSpan);
- node.querySelectorAll('select').forEach(updateTooltipForSelect);
+ }
+ for (const node of record.addedNodes) {
+ if (node.nodeType === Node.ELEMENT_NODE && !node.classList.contains("hide")) {
+ if (!node.title) {
+ if (
+ node.tagName === "SPAN" ||
+ node.tagName === "BUTTON" ||
+ node.tagName === "P" ||
+ node.tagName === "INPUT" ||
+ (node.tagName === "LI" && node.classList.contains("item")) // Gradio dropdown item
+ ) {
+ tooltipCheckNodes.add(node);
+ }
+ }
+ node.querySelectorAll('span, button, p').forEach(n => tooltipCheckNodes.add(n));
}
- });
- });
+ }
+ }
+ if (tooltipCheckNodes.size) {
+ clearTimeout(tooltipCheckTimer);
+ tooltipCheckTimer = setTimeout(processTooltipCheckNodes, 1000);
+ }
});
diff --git a/javascript/imageMaskFix.js b/javascript/imageMaskFix.js
index 3c9b8a6f..900c56f3 100644
--- a/javascript/imageMaskFix.js
+++ b/javascript/imageMaskFix.js
@@ -39,5 +39,5 @@ function imageMaskResize() {
});
}
-onUiUpdate(imageMaskResize);
+onAfterUiUpdate(imageMaskResize);
window.addEventListener('resize', imageMaskResize);
diff --git a/javascript/imageviewer.js b/javascript/imageviewer.js
index 78e24eb9..677e95c1 100644
--- a/javascript/imageviewer.js
+++ b/javascript/imageviewer.js
@@ -170,7 +170,7 @@ function modalTileImageToggle(event) {
event.stopPropagation();
}
-onUiUpdate(function() {
+onAfterUiUpdate(function() {
var fullImg_preview = gradioApp().querySelectorAll('.gradio-gallery > div > img');
if (fullImg_preview != null) {
fullImg_preview.forEach(setupImageForLightbox);
diff --git a/javascript/imageviewerGamepad.js b/javascript/imageviewerGamepad.js
index 31d226de..a22c7e6e 100644
--- a/javascript/imageviewerGamepad.js
+++ b/javascript/imageviewerGamepad.js
@@ -1,7 +1,9 @@
+let gamepads = [];
+
window.addEventListener('gamepadconnected', (e) => {
const index = e.gamepad.index;
let isWaiting = false;
- setInterval(async() => {
+ gamepads[index] = setInterval(async() => {
if (!opts.js_modal_lightbox_gamepad || isWaiting) return;
const gamepad = navigator.getGamepads()[index];
const xValue = gamepad.axes[0];
@@ -24,6 +26,10 @@ window.addEventListener('gamepadconnected', (e) => {
}, 10);
});
+window.addEventListener('gamepaddisconnected', (e) => {
+ clearInterval(gamepads[e.gamepad.index]);
+});
+
/*
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.
diff --git a/javascript/notification.js b/javascript/notification.js
index a68a76f2..76c5715d 100644
--- a/javascript/notification.js
+++ b/javascript/notification.js
@@ -4,7 +4,7 @@ let lastHeadImg = null;
let notificationButton = null;
-onUiUpdate(function() {
+onAfterUiUpdate(function() {
if (notificationButton == null) {
notificationButton = gradioApp().getElementById('request_notifications');
diff --git a/javascript/profilerVisualization.js b/javascript/profilerVisualization.js
new file mode 100644
index 00000000..9d8e5f42
--- /dev/null
+++ b/javascript/profilerVisualization.js
@@ -0,0 +1,153 @@
+
+function createRow(table, cellName, items) {
+ var tr = document.createElement('tr');
+ var res = [];
+
+ items.forEach(function(x, i) {
+ if (x === undefined) {
+ res.push(null);
+ return;
+ }
+
+ var td = document.createElement(cellName);
+ td.textContent = x;
+ tr.appendChild(td);
+ res.push(td);
+
+ var colspan = 1;
+ for (var n = i + 1; n < items.length; n++) {
+ if (items[n] !== undefined) {
+ break;
+ }
+
+ colspan += 1;
+ }
+
+ if (colspan > 1) {
+ td.colSpan = colspan;
+ }
+ });
+
+ table.appendChild(tr);
+
+ return res;
+}
+
+function showProfile(path, cutoff = 0.05) {
+ requestGet(path, {}, function(data) {
+ var table = document.createElement('table');
+ table.className = 'popup-table';
+
+ data.records['total'] = data.total;
+ var keys = Object.keys(data.records).sort(function(a, b) {
+ return data.records[b] - data.records[a];
+ });
+ var items = keys.map(function(x) {
+ return {key: x, parts: x.split('/'), time: data.records[x]};
+ });
+ var maxLength = items.reduce(function(a, b) {
+ return Math.max(a, b.parts.length);
+ }, 0);
+
+ var cols = createRow(table, 'th', ['record', 'seconds']);
+ cols[0].colSpan = maxLength;
+
+ function arraysEqual(a, b) {
+ return !(a < b || b < a);
+ }
+
+ var addLevel = function(level, parent, hide) {
+ var matching = items.filter(function(x) {
+ return x.parts[level] && !x.parts[level + 1] && arraysEqual(x.parts.slice(0, level), parent);
+ });
+ var sorted = matching.sort(function(a, b) {
+ return b.time - a.time;
+ });
+ var othersTime = 0;
+ var othersList = [];
+ var othersRows = [];
+ var childrenRows = [];
+ sorted.forEach(function(x) {
+ var visible = x.time >= cutoff && !hide;
+
+ var cells = [];
+ for (var i = 0; i < maxLength; i++) {
+ cells.push(x.parts[i]);
+ }
+ cells.push(x.time.toFixed(3));
+ var cols = createRow(table, 'td', cells);
+ for (i = 0; i < level; i++) {
+ cols[i].className = 'muted';
+ }
+
+ var tr = cols[0].parentNode;
+ if (!visible) {
+ tr.classList.add("hidden");
+ }
+
+ if (x.time >= cutoff) {
+ childrenRows.push(tr);
+ } else {
+ othersTime += x.time;
+ othersList.push(x.parts[level]);
+ othersRows.push(tr);
+ }
+
+ var children = addLevel(level + 1, parent.concat([x.parts[level]]), true);
+ if (children.length > 0) {
+ var cell = cols[level];
+ var onclick = function() {
+ cell.classList.remove("link");
+ cell.removeEventListener("click", onclick);
+ children.forEach(function(x) {
+ x.classList.remove("hidden");
+ });
+ };
+ cell.classList.add("link");
+ cell.addEventListener("click", onclick);
+ }
+ });
+
+ if (othersTime > 0) {
+ var cells = [];
+ for (var i = 0; i < maxLength; i++) {
+ cells.push(parent[i]);
+ }
+ cells.push(othersTime.toFixed(3));
+ cells[level] = 'others';
+ var cols = createRow(table, 'td', cells);
+ for (i = 0; i < level; i++) {
+ cols[i].className = 'muted';
+ }
+
+ var cell = cols[level];
+ var tr = cell.parentNode;
+ var onclick = function() {
+ tr.classList.add("hidden");
+ cell.classList.remove("link");
+ cell.removeEventListener("click", onclick);
+ othersRows.forEach(function(x) {
+ x.classList.remove("hidden");
+ });
+ };
+
+ cell.title = othersList.join(", ");
+ cell.classList.add("link");
+ cell.addEventListener("click", onclick);
+
+ if (hide) {
+ tr.classList.add("hidden");
+ }
+
+ childrenRows.push(tr);
+ }
+
+ return childrenRows;
+ };
+
+ addLevel(0, []);
+
+ popup(table);
+ });
+}
+
diff --git a/javascript/ui.js b/javascript/ui.js
index 800a2ae6..d70a681b 100644
--- a/javascript/ui.js
+++ b/javascript/ui.js
@@ -249,7 +249,7 @@ function confirm_clear_prompt(prompt, negative_prompt) {
var opts = {};
-onUiUpdate(function() {
+onAfterUiUpdate(function() {
if (Object.keys(opts).length != 0) return;
var json_elem = gradioApp().getElementById('settings_json');
diff --git a/javascript/ui_settings_hints.js b/javascript/ui_settings_hints.js
index e216852b..d088f949 100644
--- a/javascript/ui_settings_hints.js
+++ b/javascript/ui_settings_hints.js
@@ -42,7 +42,7 @@ onOptionsChanged(function() {
function settingsHintsShowQuicksettings() {
requestGet("./internal/quicksettings-hint", {}, function(data) {
var table = document.createElement('table');
- table.className = 'settings-value-table';
+ table.className = 'popup-table';
data.forEach(function(obj) {
var tr = document.createElement('tr');