Spaces:
Runtime error
Runtime error
Delete javascript
Browse files- javascript/contextMenus.js +0 -166
- javascript/edit-attention.js +0 -128
- javascript/imageviewer.js +0 -260
- javascript/localization.js +0 -144
- javascript/script.js +0 -215
- javascript/viewer.js +0 -88
- javascript/zoom.js +0 -645
javascript/contextMenus.js
DELETED
@@ -1,166 +0,0 @@
|
|
1 |
-
// based on https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/v1.6.0/javascript/contextMenus.js
|
2 |
-
|
3 |
-
var contextMenuInit = function() {
|
4 |
-
let eventListenerApplied = false;
|
5 |
-
let menuSpecs = new Map();
|
6 |
-
|
7 |
-
const uid = function() {
|
8 |
-
return Date.now().toString(36) + Math.random().toString(36).substring(2);
|
9 |
-
};
|
10 |
-
|
11 |
-
function showContextMenu(event, element, menuEntries) {
|
12 |
-
let posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
|
13 |
-
let posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
14 |
-
|
15 |
-
let oldMenu = gradioApp().querySelector('#context-menu');
|
16 |
-
if (oldMenu) {
|
17 |
-
oldMenu.remove();
|
18 |
-
}
|
19 |
-
|
20 |
-
let baseStyle = window.getComputedStyle(gradioApp().querySelector('button.selected'));
|
21 |
-
|
22 |
-
const contextMenu = document.createElement('nav');
|
23 |
-
contextMenu.id = "context-menu";
|
24 |
-
contextMenu.style.background = baseStyle.background;
|
25 |
-
contextMenu.style.color = baseStyle.color;
|
26 |
-
contextMenu.style.fontFamily = baseStyle.fontFamily;
|
27 |
-
contextMenu.style.top = posy + 'px';
|
28 |
-
contextMenu.style.left = posx + 'px';
|
29 |
-
|
30 |
-
const contextMenuList = document.createElement('ul');
|
31 |
-
contextMenuList.className = 'context-menu-items';
|
32 |
-
contextMenu.append(contextMenuList);
|
33 |
-
|
34 |
-
menuEntries.forEach(function(entry) {
|
35 |
-
let contextMenuEntry = document.createElement('a');
|
36 |
-
contextMenuEntry.innerHTML = entry['name'];
|
37 |
-
contextMenuEntry.addEventListener("click", function() {
|
38 |
-
entry['func']();
|
39 |
-
});
|
40 |
-
contextMenuList.append(contextMenuEntry);
|
41 |
-
|
42 |
-
});
|
43 |
-
|
44 |
-
gradioApp().appendChild(contextMenu);
|
45 |
-
|
46 |
-
let menuWidth = contextMenu.offsetWidth + 4;
|
47 |
-
let menuHeight = contextMenu.offsetHeight + 4;
|
48 |
-
|
49 |
-
let windowWidth = window.innerWidth;
|
50 |
-
let windowHeight = window.innerHeight;
|
51 |
-
|
52 |
-
if ((windowWidth - posx) < menuWidth) {
|
53 |
-
contextMenu.style.left = windowWidth - menuWidth + "px";
|
54 |
-
}
|
55 |
-
|
56 |
-
if ((windowHeight - posy) < menuHeight) {
|
57 |
-
contextMenu.style.top = windowHeight - menuHeight + "px";
|
58 |
-
}
|
59 |
-
|
60 |
-
}
|
61 |
-
|
62 |
-
function appendContextMenuOption(targetElementSelector, entryName, entryFunction) {
|
63 |
-
|
64 |
-
var currentItems = menuSpecs.get(targetElementSelector);
|
65 |
-
|
66 |
-
if (!currentItems) {
|
67 |
-
currentItems = [];
|
68 |
-
menuSpecs.set(targetElementSelector, currentItems);
|
69 |
-
}
|
70 |
-
let newItem = {
|
71 |
-
id: targetElementSelector + '_' + uid(),
|
72 |
-
name: entryName,
|
73 |
-
func: entryFunction,
|
74 |
-
isNew: true
|
75 |
-
};
|
76 |
-
|
77 |
-
currentItems.push(newItem);
|
78 |
-
return newItem['id'];
|
79 |
-
}
|
80 |
-
|
81 |
-
function removeContextMenuOption(uid) {
|
82 |
-
menuSpecs.forEach(function(v) {
|
83 |
-
let index = -1;
|
84 |
-
v.forEach(function(e, ei) {
|
85 |
-
if (e['id'] == uid) {
|
86 |
-
index = ei;
|
87 |
-
}
|
88 |
-
});
|
89 |
-
if (index >= 0) {
|
90 |
-
v.splice(index, 1);
|
91 |
-
}
|
92 |
-
});
|
93 |
-
}
|
94 |
-
|
95 |
-
function addContextMenuEventListener() {
|
96 |
-
if (eventListenerApplied) {
|
97 |
-
return;
|
98 |
-
}
|
99 |
-
gradioApp().addEventListener("click", function(e) {
|
100 |
-
if (!e.isTrusted) {
|
101 |
-
return;
|
102 |
-
}
|
103 |
-
|
104 |
-
let oldMenu = gradioApp().querySelector('#context-menu');
|
105 |
-
if (oldMenu) {
|
106 |
-
oldMenu.remove();
|
107 |
-
}
|
108 |
-
});
|
109 |
-
gradioApp().addEventListener("contextmenu", function(e) {
|
110 |
-
let oldMenu = gradioApp().querySelector('#context-menu');
|
111 |
-
if (oldMenu) {
|
112 |
-
oldMenu.remove();
|
113 |
-
}
|
114 |
-
menuSpecs.forEach(function(v, k) {
|
115 |
-
if (e.composedPath()[0].matches(k)) {
|
116 |
-
showContextMenu(e, e.composedPath()[0], v);
|
117 |
-
e.preventDefault();
|
118 |
-
}
|
119 |
-
});
|
120 |
-
});
|
121 |
-
eventListenerApplied = true;
|
122 |
-
|
123 |
-
}
|
124 |
-
|
125 |
-
return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener];
|
126 |
-
};
|
127 |
-
|
128 |
-
var initResponse = contextMenuInit();
|
129 |
-
var appendContextMenuOption = initResponse[0];
|
130 |
-
var removeContextMenuOption = initResponse[1];
|
131 |
-
var addContextMenuEventListener = initResponse[2];
|
132 |
-
|
133 |
-
let cancelGenerateForever = function() {
|
134 |
-
clearInterval(window.generateOnRepeatInterval);
|
135 |
-
};
|
136 |
-
|
137 |
-
(function() {
|
138 |
-
//Start example Context Menu Items
|
139 |
-
let generateOnRepeat = function(genbuttonid, interruptbuttonid) {
|
140 |
-
let genbutton = gradioApp().querySelector(genbuttonid);
|
141 |
-
let interruptbutton = gradioApp().querySelector(interruptbuttonid);
|
142 |
-
if (!interruptbutton.offsetParent) {
|
143 |
-
genbutton.click();
|
144 |
-
}
|
145 |
-
clearInterval(window.generateOnRepeatInterval);
|
146 |
-
window.generateOnRepeatInterval = setInterval(function() {
|
147 |
-
if (!interruptbutton.offsetParent) {
|
148 |
-
genbutton.click();
|
149 |
-
}
|
150 |
-
},
|
151 |
-
500);
|
152 |
-
};
|
153 |
-
|
154 |
-
let generateOnRepeatForButtons = function() {
|
155 |
-
generateOnRepeat('#generate_button', '#stop_button');
|
156 |
-
};
|
157 |
-
appendContextMenuOption('#generate_button', 'Generate forever', generateOnRepeatForButtons);
|
158 |
-
|
159 |
-
})();
|
160 |
-
//End example Context Menu Items
|
161 |
-
|
162 |
-
document.onreadystatechange = function () {
|
163 |
-
if (document.readyState == "complete") {
|
164 |
-
addContextMenuEventListener();
|
165 |
-
}
|
166 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/edit-attention.js
DELETED
@@ -1,128 +0,0 @@
|
|
1 |
-
function updateInput(target) {
|
2 |
-
let e = new Event("input", {bubbles: true});
|
3 |
-
Object.defineProperty(e, "target", {value: target});
|
4 |
-
target.dispatchEvent(e);
|
5 |
-
}
|
6 |
-
|
7 |
-
function keyupEditAttention(event) {
|
8 |
-
let target = event.originalTarget || event.composedPath()[0];
|
9 |
-
if (!target.matches("*:is([id*='_prompt'], .prompt) textarea")) return;
|
10 |
-
if (!(event.metaKey || event.ctrlKey)) return;
|
11 |
-
|
12 |
-
let isPlus = event.key == "ArrowUp";
|
13 |
-
let isMinus = event.key == "ArrowDown";
|
14 |
-
if (!isPlus && !isMinus) return;
|
15 |
-
|
16 |
-
let selectionStart = target.selectionStart;
|
17 |
-
let selectionEnd = target.selectionEnd;
|
18 |
-
let text = target.value;
|
19 |
-
|
20 |
-
function selectCurrentParenthesisBlock(OPEN, CLOSE) {
|
21 |
-
if (selectionStart !== selectionEnd) return false;
|
22 |
-
|
23 |
-
// Find opening parenthesis around current cursor
|
24 |
-
const before = text.substring(0, selectionStart);
|
25 |
-
let beforeParen = before.lastIndexOf(OPEN);
|
26 |
-
if (beforeParen == -1) return false;
|
27 |
-
let beforeParenClose = before.lastIndexOf(CLOSE);
|
28 |
-
while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
|
29 |
-
beforeParen = before.lastIndexOf(OPEN, beforeParen - 1);
|
30 |
-
beforeParenClose = before.lastIndexOf(CLOSE, beforeParenClose - 1);
|
31 |
-
}
|
32 |
-
|
33 |
-
// Find closing parenthesis around current cursor
|
34 |
-
const after = text.substring(selectionStart);
|
35 |
-
let afterParen = after.indexOf(CLOSE);
|
36 |
-
if (afterParen == -1) return false;
|
37 |
-
let afterParenOpen = after.indexOf(OPEN);
|
38 |
-
while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
|
39 |
-
afterParen = after.indexOf(CLOSE, afterParen + 1);
|
40 |
-
afterParenOpen = after.indexOf(OPEN, afterParenOpen + 1);
|
41 |
-
}
|
42 |
-
if (beforeParen === -1 || afterParen === -1) return false;
|
43 |
-
|
44 |
-
// Set the selection to the text between the parenthesis
|
45 |
-
const parenContent = text.substring(beforeParen + 1, selectionStart + afterParen);
|
46 |
-
const lastColon = parenContent.lastIndexOf(":");
|
47 |
-
selectionStart = beforeParen + 1;
|
48 |
-
selectionEnd = selectionStart + lastColon;
|
49 |
-
target.setSelectionRange(selectionStart, selectionEnd);
|
50 |
-
return true;
|
51 |
-
}
|
52 |
-
|
53 |
-
function selectCurrentWord() {
|
54 |
-
if (selectionStart !== selectionEnd) return false;
|
55 |
-
const delimiters = ".,\\/!?%^*;:{}=`~() \r\n\t";
|
56 |
-
|
57 |
-
// seek backward until to find beggining
|
58 |
-
while (!delimiters.includes(text[selectionStart - 1]) && selectionStart > 0) {
|
59 |
-
selectionStart--;
|
60 |
-
}
|
61 |
-
|
62 |
-
// seek forward to find end
|
63 |
-
while (!delimiters.includes(text[selectionEnd]) && selectionEnd < text.length) {
|
64 |
-
selectionEnd++;
|
65 |
-
}
|
66 |
-
|
67 |
-
target.setSelectionRange(selectionStart, selectionEnd);
|
68 |
-
return true;
|
69 |
-
}
|
70 |
-
|
71 |
-
// If the user hasn't selected anything, let's select their current parenthesis block or word
|
72 |
-
if (!selectCurrentParenthesisBlock('<', '>') && !selectCurrentParenthesisBlock('(', ')')) {
|
73 |
-
selectCurrentWord();
|
74 |
-
}
|
75 |
-
|
76 |
-
event.preventDefault();
|
77 |
-
|
78 |
-
var closeCharacter = ')';
|
79 |
-
var delta = 0.1;
|
80 |
-
|
81 |
-
if (selectionStart > 0 && text[selectionStart - 1] == '<') {
|
82 |
-
closeCharacter = '>';
|
83 |
-
delta = 0.05;
|
84 |
-
} else if (selectionStart == 0 || text[selectionStart - 1] != "(") {
|
85 |
-
|
86 |
-
// do not include spaces at the end
|
87 |
-
while (selectionEnd > selectionStart && text[selectionEnd - 1] == ' ') {
|
88 |
-
selectionEnd -= 1;
|
89 |
-
}
|
90 |
-
if (selectionStart == selectionEnd) {
|
91 |
-
return;
|
92 |
-
}
|
93 |
-
|
94 |
-
text = text.slice(0, selectionStart) + "(" + text.slice(selectionStart, selectionEnd) + ":1.0)" + text.slice(selectionEnd);
|
95 |
-
|
96 |
-
selectionStart += 1;
|
97 |
-
selectionEnd += 1;
|
98 |
-
}
|
99 |
-
|
100 |
-
var end = text.slice(selectionEnd + 1).indexOf(closeCharacter) + 1;
|
101 |
-
var weight = parseFloat(text.slice(selectionEnd + 1, selectionEnd + 1 + end));
|
102 |
-
if (isNaN(weight)) return;
|
103 |
-
|
104 |
-
weight += isPlus ? delta : -delta;
|
105 |
-
weight = parseFloat(weight.toPrecision(12));
|
106 |
-
if (String(weight).length == 1) weight += ".0";
|
107 |
-
|
108 |
-
if (closeCharacter == ')' && weight == 1) {
|
109 |
-
var endParenPos = text.substring(selectionEnd).indexOf(')');
|
110 |
-
text = text.slice(0, selectionStart - 1) + text.slice(selectionStart, selectionEnd) + text.slice(selectionEnd + endParenPos + 1);
|
111 |
-
selectionStart--;
|
112 |
-
selectionEnd--;
|
113 |
-
} else {
|
114 |
-
text = text.slice(0, selectionEnd + 1) + weight + text.slice(selectionEnd + end);
|
115 |
-
}
|
116 |
-
|
117 |
-
target.focus();
|
118 |
-
target.value = text;
|
119 |
-
target.selectionStart = selectionStart;
|
120 |
-
target.selectionEnd = selectionEnd;
|
121 |
-
|
122 |
-
updateInput(target);
|
123 |
-
|
124 |
-
}
|
125 |
-
|
126 |
-
addEventListener('keydown', (event) => {
|
127 |
-
keyupEditAttention(event);
|
128 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/imageviewer.js
DELETED
@@ -1,260 +0,0 @@
|
|
1 |
-
// From A1111
|
2 |
-
|
3 |
-
function closeModal() {
|
4 |
-
gradioApp().getElementById("lightboxModal").style.display = "none";
|
5 |
-
}
|
6 |
-
|
7 |
-
function showModal(event) {
|
8 |
-
const source = event.target || event.srcElement;
|
9 |
-
const modalImage = gradioApp().getElementById("modalImage");
|
10 |
-
const lb = gradioApp().getElementById("lightboxModal");
|
11 |
-
modalImage.src = source.src;
|
12 |
-
if (modalImage.style.display === 'none') {
|
13 |
-
lb.style.setProperty('background-image', 'url(' + source.src + ')');
|
14 |
-
}
|
15 |
-
lb.style.display = "flex";
|
16 |
-
lb.focus();
|
17 |
-
|
18 |
-
event.stopPropagation();
|
19 |
-
}
|
20 |
-
|
21 |
-
function negmod(n, m) {
|
22 |
-
return ((n % m) + m) % m;
|
23 |
-
}
|
24 |
-
|
25 |
-
function updateOnBackgroundChange() {
|
26 |
-
const modalImage = gradioApp().getElementById("modalImage");
|
27 |
-
if (modalImage && modalImage.offsetParent) {
|
28 |
-
let currentButton = selected_gallery_button();
|
29 |
-
|
30 |
-
if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
|
31 |
-
modalImage.src = currentButton.children[0].src;
|
32 |
-
if (modalImage.style.display === 'none') {
|
33 |
-
const modal = gradioApp().getElementById("lightboxModal");
|
34 |
-
modal.style.setProperty('background-image', `url(${modalImage.src})`);
|
35 |
-
}
|
36 |
-
}
|
37 |
-
}
|
38 |
-
}
|
39 |
-
|
40 |
-
function all_gallery_buttons() {
|
41 |
-
var allGalleryButtons = gradioApp().querySelectorAll('.image_gallery .thumbnails > .thumbnail-item.thumbnail-small');
|
42 |
-
var visibleGalleryButtons = [];
|
43 |
-
allGalleryButtons.forEach(function(elem) {
|
44 |
-
if (elem.parentElement.offsetParent) {
|
45 |
-
visibleGalleryButtons.push(elem);
|
46 |
-
}
|
47 |
-
});
|
48 |
-
return visibleGalleryButtons;
|
49 |
-
}
|
50 |
-
|
51 |
-
function selected_gallery_button() {
|
52 |
-
return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null;
|
53 |
-
}
|
54 |
-
|
55 |
-
function selected_gallery_index() {
|
56 |
-
return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected'));
|
57 |
-
}
|
58 |
-
|
59 |
-
function modalImageSwitch(offset) {
|
60 |
-
var galleryButtons = all_gallery_buttons();
|
61 |
-
|
62 |
-
if (galleryButtons.length > 1) {
|
63 |
-
var currentButton = selected_gallery_button();
|
64 |
-
|
65 |
-
var result = -1;
|
66 |
-
galleryButtons.forEach(function(v, i) {
|
67 |
-
if (v == currentButton) {
|
68 |
-
result = i;
|
69 |
-
}
|
70 |
-
});
|
71 |
-
|
72 |
-
if (result != -1) {
|
73 |
-
var nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)];
|
74 |
-
nextButton.click();
|
75 |
-
const modalImage = gradioApp().getElementById("modalImage");
|
76 |
-
const modal = gradioApp().getElementById("lightboxModal");
|
77 |
-
modalImage.src = nextButton.children[0].src;
|
78 |
-
if (modalImage.style.display === 'none') {
|
79 |
-
modal.style.setProperty('background-image', `url(${modalImage.src})`);
|
80 |
-
}
|
81 |
-
setTimeout(function() {
|
82 |
-
modal.focus();
|
83 |
-
}, 10);
|
84 |
-
}
|
85 |
-
}
|
86 |
-
}
|
87 |
-
|
88 |
-
function saveImage() {
|
89 |
-
|
90 |
-
}
|
91 |
-
|
92 |
-
function modalSaveImage(event) {
|
93 |
-
event.stopPropagation();
|
94 |
-
}
|
95 |
-
|
96 |
-
function modalNextImage(event) {
|
97 |
-
modalImageSwitch(1);
|
98 |
-
event.stopPropagation();
|
99 |
-
}
|
100 |
-
|
101 |
-
function modalPrevImage(event) {
|
102 |
-
modalImageSwitch(-1);
|
103 |
-
event.stopPropagation();
|
104 |
-
}
|
105 |
-
|
106 |
-
function modalKeyHandler(event) {
|
107 |
-
switch (event.key) {
|
108 |
-
case "s":
|
109 |
-
saveImage();
|
110 |
-
break;
|
111 |
-
case "ArrowLeft":
|
112 |
-
modalPrevImage(event);
|
113 |
-
break;
|
114 |
-
case "ArrowRight":
|
115 |
-
modalNextImage(event);
|
116 |
-
break;
|
117 |
-
case "Escape":
|
118 |
-
closeModal();
|
119 |
-
break;
|
120 |
-
}
|
121 |
-
}
|
122 |
-
|
123 |
-
function setupImageForLightbox(e) {
|
124 |
-
if (e.dataset.modded) {
|
125 |
-
return;
|
126 |
-
}
|
127 |
-
|
128 |
-
e.dataset.modded = true;
|
129 |
-
e.style.cursor = 'pointer';
|
130 |
-
e.style.userSelect = 'none';
|
131 |
-
|
132 |
-
var isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
133 |
-
|
134 |
-
// For Firefox, listening on click first switched to next image then shows the lightbox.
|
135 |
-
// If you know how to fix this without switching to mousedown event, please.
|
136 |
-
// For other browsers the event is click to make it possiblr to drag picture.
|
137 |
-
var event = isFirefox ? 'mousedown' : 'click';
|
138 |
-
|
139 |
-
e.addEventListener(event, function(evt) {
|
140 |
-
if (evt.button == 1) {
|
141 |
-
open(evt.target.src);
|
142 |
-
evt.preventDefault();
|
143 |
-
return;
|
144 |
-
}
|
145 |
-
if (evt.button != 0) return;
|
146 |
-
|
147 |
-
modalZoomSet(gradioApp().getElementById('modalImage'), true);
|
148 |
-
evt.preventDefault();
|
149 |
-
showModal(evt);
|
150 |
-
}, true);
|
151 |
-
|
152 |
-
}
|
153 |
-
|
154 |
-
function modalZoomSet(modalImage, enable) {
|
155 |
-
if (modalImage) modalImage.classList.toggle('modalImageFullscreen', !!enable);
|
156 |
-
}
|
157 |
-
|
158 |
-
function modalZoomToggle(event) {
|
159 |
-
var modalImage = gradioApp().getElementById("modalImage");
|
160 |
-
modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'));
|
161 |
-
event.stopPropagation();
|
162 |
-
}
|
163 |
-
|
164 |
-
function modalTileImageToggle(event) {
|
165 |
-
const modalImage = gradioApp().getElementById("modalImage");
|
166 |
-
const modal = gradioApp().getElementById("lightboxModal");
|
167 |
-
const isTiling = modalImage.style.display === 'none';
|
168 |
-
if (isTiling) {
|
169 |
-
modalImage.style.display = 'block';
|
170 |
-
modal.style.setProperty('background-image', 'none');
|
171 |
-
} else {
|
172 |
-
modalImage.style.display = 'none';
|
173 |
-
modal.style.setProperty('background-image', `url(${modalImage.src})`);
|
174 |
-
}
|
175 |
-
|
176 |
-
event.stopPropagation();
|
177 |
-
}
|
178 |
-
|
179 |
-
onAfterUiUpdate(function() {
|
180 |
-
var fullImg_preview = gradioApp().querySelectorAll('.image_gallery > div > img');
|
181 |
-
if (fullImg_preview != null) {
|
182 |
-
fullImg_preview.forEach(setupImageForLightbox);
|
183 |
-
}
|
184 |
-
updateOnBackgroundChange();
|
185 |
-
});
|
186 |
-
|
187 |
-
document.addEventListener("DOMContentLoaded", function() {
|
188 |
-
//const modalFragment = document.createDocumentFragment();
|
189 |
-
const modal = document.createElement('div');
|
190 |
-
modal.onclick = closeModal;
|
191 |
-
modal.id = "lightboxModal";
|
192 |
-
modal.tabIndex = 0;
|
193 |
-
modal.addEventListener('keydown', modalKeyHandler, true);
|
194 |
-
|
195 |
-
const modalControls = document.createElement('div');
|
196 |
-
modalControls.className = 'modalControls gradio-container';
|
197 |
-
modal.append(modalControls);
|
198 |
-
|
199 |
-
const modalZoom = document.createElement('span');
|
200 |
-
modalZoom.className = 'modalZoom cursor';
|
201 |
-
modalZoom.innerHTML = '⤡';
|
202 |
-
modalZoom.addEventListener('click', modalZoomToggle, true);
|
203 |
-
modalZoom.title = "Toggle zoomed view";
|
204 |
-
modalControls.appendChild(modalZoom);
|
205 |
-
|
206 |
-
// const modalTileImage = document.createElement('span');
|
207 |
-
// modalTileImage.className = 'modalTileImage cursor';
|
208 |
-
// modalTileImage.innerHTML = '⊞';
|
209 |
-
// modalTileImage.addEventListener('click', modalTileImageToggle, true);
|
210 |
-
// modalTileImage.title = "Preview tiling";
|
211 |
-
// modalControls.appendChild(modalTileImage);
|
212 |
-
//
|
213 |
-
// const modalSave = document.createElement("span");
|
214 |
-
// modalSave.className = "modalSave cursor";
|
215 |
-
// modalSave.id = "modal_save";
|
216 |
-
// modalSave.innerHTML = "🖫";
|
217 |
-
// modalSave.addEventListener("click", modalSaveImage, true);
|
218 |
-
// modalSave.title = "Save Image(s)";
|
219 |
-
// modalControls.appendChild(modalSave);
|
220 |
-
|
221 |
-
const modalClose = document.createElement('span');
|
222 |
-
modalClose.className = 'modalClose cursor';
|
223 |
-
modalClose.innerHTML = '×';
|
224 |
-
modalClose.onclick = closeModal;
|
225 |
-
modalClose.title = "Close image viewer";
|
226 |
-
modalControls.appendChild(modalClose);
|
227 |
-
|
228 |
-
const modalImage = document.createElement('img');
|
229 |
-
modalImage.id = 'modalImage';
|
230 |
-
modalImage.onclick = closeModal;
|
231 |
-
modalImage.tabIndex = 0;
|
232 |
-
modalImage.addEventListener('keydown', modalKeyHandler, true);
|
233 |
-
modal.appendChild(modalImage);
|
234 |
-
|
235 |
-
const modalPrev = document.createElement('a');
|
236 |
-
modalPrev.className = 'modalPrev';
|
237 |
-
modalPrev.innerHTML = '❮';
|
238 |
-
modalPrev.tabIndex = 0;
|
239 |
-
modalPrev.addEventListener('click', modalPrevImage, true);
|
240 |
-
modalPrev.addEventListener('keydown', modalKeyHandler, true);
|
241 |
-
modal.appendChild(modalPrev);
|
242 |
-
|
243 |
-
const modalNext = document.createElement('a');
|
244 |
-
modalNext.className = 'modalNext';
|
245 |
-
modalNext.innerHTML = '❯';
|
246 |
-
modalNext.tabIndex = 0;
|
247 |
-
modalNext.addEventListener('click', modalNextImage, true);
|
248 |
-
modalNext.addEventListener('keydown', modalKeyHandler, true);
|
249 |
-
|
250 |
-
modal.appendChild(modalNext);
|
251 |
-
|
252 |
-
try {
|
253 |
-
gradioApp().appendChild(modal);
|
254 |
-
} catch (e) {
|
255 |
-
gradioApp().body.appendChild(modal);
|
256 |
-
}
|
257 |
-
|
258 |
-
document.body.appendChild(modal);
|
259 |
-
|
260 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/localization.js
DELETED
@@ -1,144 +0,0 @@
|
|
1 |
-
var re_num = /^[.\d]+$/;
|
2 |
-
|
3 |
-
var original_lines = {};
|
4 |
-
var translated_lines = {};
|
5 |
-
|
6 |
-
function hasLocalization() {
|
7 |
-
return window.localization && Object.keys(window.localization).length > 0;
|
8 |
-
}
|
9 |
-
|
10 |
-
function textNodesUnder(el) {
|
11 |
-
var n, a = [], walk = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
|
12 |
-
while ((n = walk.nextNode())) a.push(n);
|
13 |
-
return a;
|
14 |
-
}
|
15 |
-
|
16 |
-
function canBeTranslated(node, text) {
|
17 |
-
if (!text) return false;
|
18 |
-
if (!node.parentElement) return false;
|
19 |
-
var parentType = node.parentElement.nodeName;
|
20 |
-
if (parentType == 'SCRIPT' || parentType == 'STYLE' || parentType == 'TEXTAREA') return false;
|
21 |
-
if (re_num.test(text)) return false;
|
22 |
-
return true;
|
23 |
-
}
|
24 |
-
|
25 |
-
function getTranslation(text) {
|
26 |
-
if (!text) return undefined;
|
27 |
-
|
28 |
-
if (translated_lines[text] === undefined) {
|
29 |
-
original_lines[text] = 1;
|
30 |
-
}
|
31 |
-
|
32 |
-
var tl = localization[text];
|
33 |
-
if (tl !== undefined) {
|
34 |
-
translated_lines[tl] = 1;
|
35 |
-
}
|
36 |
-
|
37 |
-
return tl;
|
38 |
-
}
|
39 |
-
|
40 |
-
function processTextNode(node) {
|
41 |
-
var text = node.textContent.trim();
|
42 |
-
|
43 |
-
if (!canBeTranslated(node, text)) return;
|
44 |
-
|
45 |
-
var tl = getTranslation(text);
|
46 |
-
if (tl !== undefined) {
|
47 |
-
node.textContent = tl;
|
48 |
-
if (text && node.parentElement) {
|
49 |
-
node.parentElement.setAttribute("data-original-text", text);
|
50 |
-
}
|
51 |
-
}
|
52 |
-
}
|
53 |
-
|
54 |
-
function processNode(node) {
|
55 |
-
if (node.nodeType == 3) {
|
56 |
-
processTextNode(node);
|
57 |
-
return;
|
58 |
-
}
|
59 |
-
|
60 |
-
if (node.title) {
|
61 |
-
let tl = getTranslation(node.title);
|
62 |
-
if (tl !== undefined) {
|
63 |
-
node.title = tl;
|
64 |
-
}
|
65 |
-
}
|
66 |
-
|
67 |
-
if (node.placeholder) {
|
68 |
-
let tl = getTranslation(node.placeholder);
|
69 |
-
if (tl !== undefined) {
|
70 |
-
node.placeholder = tl;
|
71 |
-
}
|
72 |
-
}
|
73 |
-
|
74 |
-
textNodesUnder(node).forEach(function(node) {
|
75 |
-
processTextNode(node);
|
76 |
-
});
|
77 |
-
}
|
78 |
-
|
79 |
-
function refresh_style_localization() {
|
80 |
-
processNode(document.querySelector('.style_selections'));
|
81 |
-
}
|
82 |
-
|
83 |
-
function localizeWholePage() {
|
84 |
-
processNode(gradioApp());
|
85 |
-
|
86 |
-
function elem(comp) {
|
87 |
-
var elem_id = comp.props.elem_id ? comp.props.elem_id : "component-" + comp.id;
|
88 |
-
return gradioApp().getElementById(elem_id);
|
89 |
-
}
|
90 |
-
|
91 |
-
for (var comp of window.gradio_config.components) {
|
92 |
-
if (comp.props.webui_tooltip) {
|
93 |
-
let e = elem(comp);
|
94 |
-
|
95 |
-
let tl = e ? getTranslation(e.title) : undefined;
|
96 |
-
if (tl !== undefined) {
|
97 |
-
e.title = tl;
|
98 |
-
}
|
99 |
-
}
|
100 |
-
if (comp.props.placeholder) {
|
101 |
-
let e = elem(comp);
|
102 |
-
let textbox = e ? e.querySelector('[placeholder]') : null;
|
103 |
-
|
104 |
-
let tl = textbox ? getTranslation(textbox.placeholder) : undefined;
|
105 |
-
if (tl !== undefined) {
|
106 |
-
textbox.placeholder = tl;
|
107 |
-
}
|
108 |
-
}
|
109 |
-
}
|
110 |
-
}
|
111 |
-
|
112 |
-
document.addEventListener("DOMContentLoaded", function() {
|
113 |
-
if (!hasLocalization()) {
|
114 |
-
return;
|
115 |
-
}
|
116 |
-
|
117 |
-
onUiUpdate(function(m) {
|
118 |
-
m.forEach(function(mutation) {
|
119 |
-
mutation.addedNodes.forEach(function(node) {
|
120 |
-
processNode(node);
|
121 |
-
});
|
122 |
-
});
|
123 |
-
});
|
124 |
-
|
125 |
-
localizeWholePage();
|
126 |
-
|
127 |
-
if (localization.rtl) { // if the language is from right to left,
|
128 |
-
(new MutationObserver((mutations, observer) => { // wait for the style to load
|
129 |
-
mutations.forEach(mutation => {
|
130 |
-
mutation.addedNodes.forEach(node => {
|
131 |
-
if (node.tagName === 'STYLE') {
|
132 |
-
observer.disconnect();
|
133 |
-
|
134 |
-
for (const x of node.sheet.rules) { // find all rtl media rules
|
135 |
-
if (Array.from(x.media || []).includes('rtl')) {
|
136 |
-
x.media.appendMedium('all'); // enable them
|
137 |
-
}
|
138 |
-
}
|
139 |
-
}
|
140 |
-
});
|
141 |
-
});
|
142 |
-
})).observe(gradioApp(), {childList: true});
|
143 |
-
}
|
144 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/script.js
DELETED
@@ -1,215 +0,0 @@
|
|
1 |
-
// based on https://github.com/AUTOMATIC1111/stable-diffusion-webui/blob/v1.6.0/script.js
|
2 |
-
function gradioApp() {
|
3 |
-
const elems = document.getElementsByTagName('gradio-app');
|
4 |
-
const elem = elems.length == 0 ? document : elems[0];
|
5 |
-
|
6 |
-
if (elem !== document) {
|
7 |
-
elem.getElementById = function(id) {
|
8 |
-
return document.getElementById(id);
|
9 |
-
};
|
10 |
-
}
|
11 |
-
return elem.shadowRoot ? elem.shadowRoot : elem;
|
12 |
-
}
|
13 |
-
|
14 |
-
/**
|
15 |
-
* Get the currently selected top-level UI tab button (e.g. the button that says "Extras").
|
16 |
-
*/
|
17 |
-
function get_uiCurrentTab() {
|
18 |
-
return gradioApp().querySelector('#tabs > .tab-nav > button.selected');
|
19 |
-
}
|
20 |
-
|
21 |
-
/**
|
22 |
-
* Get the first currently visible top-level UI tab content (e.g. the div hosting the "txt2img" UI).
|
23 |
-
*/
|
24 |
-
function get_uiCurrentTabContent() {
|
25 |
-
return gradioApp().querySelector('#tabs > .tabitem[id^=tab_]:not([style*="display: none"])');
|
26 |
-
}
|
27 |
-
|
28 |
-
var uiUpdateCallbacks = [];
|
29 |
-
var uiAfterUpdateCallbacks = [];
|
30 |
-
var uiLoadedCallbacks = [];
|
31 |
-
var uiTabChangeCallbacks = [];
|
32 |
-
var optionsChangedCallbacks = [];
|
33 |
-
var uiAfterUpdateTimeout = null;
|
34 |
-
var uiCurrentTab = null;
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Register callback to be called at each UI update.
|
38 |
-
* The callback receives an array of MutationRecords as an argument.
|
39 |
-
*/
|
40 |
-
function onUiUpdate(callback) {
|
41 |
-
uiUpdateCallbacks.push(callback);
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Register callback to be called soon after UI updates.
|
46 |
-
* The callback receives no arguments.
|
47 |
-
*
|
48 |
-
* This is preferred over `onUiUpdate` if you don't need
|
49 |
-
* access to the MutationRecords, as your function will
|
50 |
-
* not be called quite as often.
|
51 |
-
*/
|
52 |
-
function onAfterUiUpdate(callback) {
|
53 |
-
uiAfterUpdateCallbacks.push(callback);
|
54 |
-
}
|
55 |
-
|
56 |
-
/**
|
57 |
-
* Register callback to be called when the UI is loaded.
|
58 |
-
* The callback receives no arguments.
|
59 |
-
*/
|
60 |
-
function onUiLoaded(callback) {
|
61 |
-
uiLoadedCallbacks.push(callback);
|
62 |
-
}
|
63 |
-
|
64 |
-
/**
|
65 |
-
* Register callback to be called when the UI tab is changed.
|
66 |
-
* The callback receives no arguments.
|
67 |
-
*/
|
68 |
-
function onUiTabChange(callback) {
|
69 |
-
uiTabChangeCallbacks.push(callback);
|
70 |
-
}
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Register callback to be called when the options are changed.
|
74 |
-
* The callback receives no arguments.
|
75 |
-
* @param callback
|
76 |
-
*/
|
77 |
-
function onOptionsChanged(callback) {
|
78 |
-
optionsChangedCallbacks.push(callback);
|
79 |
-
}
|
80 |
-
|
81 |
-
function executeCallbacks(queue, arg) {
|
82 |
-
for (const callback of queue) {
|
83 |
-
try {
|
84 |
-
callback(arg);
|
85 |
-
} catch (e) {
|
86 |
-
console.error("error running callback", callback, ":", e);
|
87 |
-
}
|
88 |
-
}
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* Schedule the execution of the callbacks registered with onAfterUiUpdate.
|
93 |
-
* The callbacks are executed after a short while, unless another call to this function
|
94 |
-
* is made before that time. IOW, the callbacks are executed only once, even
|
95 |
-
* when there are multiple mutations observed.
|
96 |
-
*/
|
97 |
-
function scheduleAfterUiUpdateCallbacks() {
|
98 |
-
clearTimeout(uiAfterUpdateTimeout);
|
99 |
-
uiAfterUpdateTimeout = setTimeout(function() {
|
100 |
-
executeCallbacks(uiAfterUpdateCallbacks);
|
101 |
-
}, 200);
|
102 |
-
}
|
103 |
-
|
104 |
-
var executedOnLoaded = false;
|
105 |
-
|
106 |
-
document.addEventListener("DOMContentLoaded", function() {
|
107 |
-
var mutationObserver = new MutationObserver(function(m) {
|
108 |
-
if (!executedOnLoaded && gradioApp().querySelector('#generate_button')) {
|
109 |
-
executedOnLoaded = true;
|
110 |
-
executeCallbacks(uiLoadedCallbacks);
|
111 |
-
}
|
112 |
-
|
113 |
-
executeCallbacks(uiUpdateCallbacks, m);
|
114 |
-
scheduleAfterUiUpdateCallbacks();
|
115 |
-
const newTab = get_uiCurrentTab();
|
116 |
-
if (newTab && (newTab !== uiCurrentTab)) {
|
117 |
-
uiCurrentTab = newTab;
|
118 |
-
executeCallbacks(uiTabChangeCallbacks);
|
119 |
-
}
|
120 |
-
});
|
121 |
-
mutationObserver.observe(gradioApp(), {childList: true, subtree: true});
|
122 |
-
initStylePreviewOverlay();
|
123 |
-
});
|
124 |
-
|
125 |
-
/**
|
126 |
-
* Add a ctrl+enter as a shortcut to start a generation
|
127 |
-
*/
|
128 |
-
document.addEventListener('keydown', function(e) {
|
129 |
-
const isModifierKey = (e.metaKey || e.ctrlKey || e.altKey);
|
130 |
-
const isEnterKey = (e.key == "Enter" || e.keyCode == 13);
|
131 |
-
|
132 |
-
if(isModifierKey && isEnterKey) {
|
133 |
-
const generateButton = gradioApp().querySelector('button:not(.hidden)[id=generate_button]');
|
134 |
-
if (generateButton) {
|
135 |
-
generateButton.click();
|
136 |
-
e.preventDefault();
|
137 |
-
return;
|
138 |
-
}
|
139 |
-
|
140 |
-
const stopButton = gradioApp().querySelector('button:not(.hidden)[id=stop_button]')
|
141 |
-
if(stopButton) {
|
142 |
-
stopButton.click();
|
143 |
-
e.preventDefault();
|
144 |
-
return;
|
145 |
-
}
|
146 |
-
}
|
147 |
-
});
|
148 |
-
|
149 |
-
function initStylePreviewOverlay() {
|
150 |
-
let overlayVisible = false;
|
151 |
-
const samplesPath = document.querySelector("meta[name='samples-path']").getAttribute("content")
|
152 |
-
const overlay = document.createElement('div');
|
153 |
-
overlay.id = 'stylePreviewOverlay';
|
154 |
-
document.body.appendChild(overlay);
|
155 |
-
document.addEventListener('mouseover', function(e) {
|
156 |
-
const label = e.target.closest('.style_selections label');
|
157 |
-
if (!label) return;
|
158 |
-
label.removeEventListener("mouseout", onMouseLeave);
|
159 |
-
label.addEventListener("mouseout", onMouseLeave);
|
160 |
-
overlayVisible = true;
|
161 |
-
overlay.style.opacity = "1";
|
162 |
-
const originalText = label.querySelector("span").getAttribute("data-original-text");
|
163 |
-
const name = originalText || label.querySelector("span").textContent;
|
164 |
-
overlay.style.backgroundImage = `url("${samplesPath.replace(
|
165 |
-
"fooocus_v2",
|
166 |
-
name.toLowerCase().replaceAll(" ", "_")
|
167 |
-
).replaceAll("\\", "\\\\")}")`;
|
168 |
-
function onMouseLeave() {
|
169 |
-
overlayVisible = false;
|
170 |
-
overlay.style.opacity = "0";
|
171 |
-
overlay.style.backgroundImage = "";
|
172 |
-
label.removeEventListener("mouseout", onMouseLeave);
|
173 |
-
}
|
174 |
-
});
|
175 |
-
document.addEventListener('mousemove', function(e) {
|
176 |
-
if(!overlayVisible) return;
|
177 |
-
overlay.style.left = `${e.clientX}px`;
|
178 |
-
overlay.style.top = `${e.clientY}px`;
|
179 |
-
overlay.className = e.clientY > window.innerHeight / 2 ? "lower-half" : "upper-half";
|
180 |
-
});
|
181 |
-
}
|
182 |
-
|
183 |
-
/**
|
184 |
-
* checks that a UI element is not in another hidden element or tab content
|
185 |
-
*/
|
186 |
-
function uiElementIsVisible(el) {
|
187 |
-
if (el === document) {
|
188 |
-
return true;
|
189 |
-
}
|
190 |
-
|
191 |
-
const computedStyle = getComputedStyle(el);
|
192 |
-
const isVisible = computedStyle.display !== 'none';
|
193 |
-
|
194 |
-
if (!isVisible) return false;
|
195 |
-
return uiElementIsVisible(el.parentNode);
|
196 |
-
}
|
197 |
-
|
198 |
-
function uiElementInSight(el) {
|
199 |
-
const clRect = el.getBoundingClientRect();
|
200 |
-
const windowHeight = window.innerHeight;
|
201 |
-
const isOnScreen = clRect.bottom > 0 && clRect.top < windowHeight;
|
202 |
-
|
203 |
-
return isOnScreen;
|
204 |
-
}
|
205 |
-
|
206 |
-
function playNotification() {
|
207 |
-
gradioApp().querySelector('#audio_notification audio')?.play();
|
208 |
-
}
|
209 |
-
|
210 |
-
function set_theme(theme) {
|
211 |
-
var gradioURL = window.location.href;
|
212 |
-
if (!gradioURL.includes('?__theme=')) {
|
213 |
-
window.location.replace(gradioURL + '?__theme=' + theme);
|
214 |
-
}
|
215 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/viewer.js
DELETED
@@ -1,88 +0,0 @@
|
|
1 |
-
window.main_viewer_height = 512;
|
2 |
-
|
3 |
-
function refresh_grid() {
|
4 |
-
let gridContainer = document.querySelector('#final_gallery .grid-container');
|
5 |
-
let final_gallery = document.getElementById('final_gallery');
|
6 |
-
|
7 |
-
if (gridContainer) if (final_gallery) {
|
8 |
-
let rect = final_gallery.getBoundingClientRect();
|
9 |
-
let cols = Math.ceil((rect.width - 16.0) / rect.height);
|
10 |
-
if (cols < 2) cols = 2;
|
11 |
-
gridContainer.style.setProperty('--grid-cols', cols);
|
12 |
-
}
|
13 |
-
}
|
14 |
-
|
15 |
-
function refresh_grid_delayed() {
|
16 |
-
refresh_grid();
|
17 |
-
setTimeout(refresh_grid, 100);
|
18 |
-
setTimeout(refresh_grid, 500);
|
19 |
-
setTimeout(refresh_grid, 1000);
|
20 |
-
}
|
21 |
-
|
22 |
-
function resized() {
|
23 |
-
let windowHeight = window.innerHeight - 260;
|
24 |
-
let elements = document.getElementsByClassName('main_view');
|
25 |
-
|
26 |
-
if (windowHeight > 745) windowHeight = 745;
|
27 |
-
|
28 |
-
for (let i = 0; i < elements.length; i++) {
|
29 |
-
elements[i].style.height = windowHeight + 'px';
|
30 |
-
}
|
31 |
-
|
32 |
-
window.main_viewer_height = windowHeight;
|
33 |
-
|
34 |
-
refresh_grid();
|
35 |
-
}
|
36 |
-
|
37 |
-
function viewer_to_top(delay = 100) {
|
38 |
-
setTimeout(() => window.scrollTo({top: 0, behavior: 'smooth'}), delay);
|
39 |
-
}
|
40 |
-
|
41 |
-
function viewer_to_bottom(delay = 100) {
|
42 |
-
let element = document.getElementById('positive_prompt');
|
43 |
-
let yPos = window.main_viewer_height;
|
44 |
-
|
45 |
-
if (element) {
|
46 |
-
yPos = element.getBoundingClientRect().top + window.scrollY;
|
47 |
-
}
|
48 |
-
|
49 |
-
setTimeout(() => window.scrollTo({top: yPos - 8, behavior: 'smooth'}), delay);
|
50 |
-
}
|
51 |
-
|
52 |
-
window.addEventListener('resize', (e) => {
|
53 |
-
resized();
|
54 |
-
});
|
55 |
-
|
56 |
-
onUiLoaded(async () => {
|
57 |
-
resized();
|
58 |
-
});
|
59 |
-
|
60 |
-
function on_style_selection_blur() {
|
61 |
-
let target = document.querySelector("#gradio_receiver_style_selections textarea");
|
62 |
-
target.value = "on_style_selection_blur " + Math.random();
|
63 |
-
let e = new Event("input", {bubbles: true})
|
64 |
-
Object.defineProperty(e, "target", {value: target})
|
65 |
-
target.dispatchEvent(e);
|
66 |
-
}
|
67 |
-
|
68 |
-
onUiLoaded(async () => {
|
69 |
-
let spans = document.querySelectorAll('.aspect_ratios span');
|
70 |
-
|
71 |
-
spans.forEach(function (span) {
|
72 |
-
span.innerHTML = span.innerHTML.replace(/</g, '<').replace(/>/g, '>');
|
73 |
-
});
|
74 |
-
|
75 |
-
document.querySelector('.style_selections').addEventListener('focusout', function (event) {
|
76 |
-
setTimeout(() => {
|
77 |
-
if (!this.contains(document.activeElement)) {
|
78 |
-
on_style_selection_blur();
|
79 |
-
}
|
80 |
-
}, 200);
|
81 |
-
});
|
82 |
-
|
83 |
-
let inputs = document.querySelectorAll('.lora_weight input[type="range"]');
|
84 |
-
|
85 |
-
inputs.forEach(function (input) {
|
86 |
-
input.style.marginTop = '12px';
|
87 |
-
});
|
88 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/zoom.js
DELETED
@@ -1,645 +0,0 @@
|
|
1 |
-
onUiLoaded(async() => {
|
2 |
-
// Helper functions
|
3 |
-
|
4 |
-
// Detect whether the element has a horizontal scroll bar
|
5 |
-
function hasHorizontalScrollbar(element) {
|
6 |
-
return element.scrollWidth > element.clientWidth;
|
7 |
-
}
|
8 |
-
|
9 |
-
// Function for defining the "Ctrl", "Shift" and "Alt" keys
|
10 |
-
function isModifierKey(event, key) {
|
11 |
-
switch (key) {
|
12 |
-
case "Ctrl":
|
13 |
-
return event.ctrlKey;
|
14 |
-
case "Shift":
|
15 |
-
return event.shiftKey;
|
16 |
-
case "Alt":
|
17 |
-
return event.altKey;
|
18 |
-
default:
|
19 |
-
return false;
|
20 |
-
}
|
21 |
-
}
|
22 |
-
|
23 |
-
// Create hotkey configuration with the provided options
|
24 |
-
function createHotkeyConfig(defaultHotkeysConfig) {
|
25 |
-
const result = {}; // Resulting hotkey configuration
|
26 |
-
for (const key in defaultHotkeysConfig) {
|
27 |
-
result[key] = defaultHotkeysConfig[key];
|
28 |
-
}
|
29 |
-
return result;
|
30 |
-
}
|
31 |
-
|
32 |
-
// Default config
|
33 |
-
const defaultHotkeysConfig = {
|
34 |
-
canvas_hotkey_zoom: "Shift",
|
35 |
-
canvas_hotkey_adjust: "Ctrl",
|
36 |
-
canvas_zoom_undo_extra_key: "Ctrl",
|
37 |
-
canvas_zoom_hotkey_undo: "KeyZ",
|
38 |
-
canvas_hotkey_reset: "KeyR",
|
39 |
-
canvas_hotkey_fullscreen: "KeyS",
|
40 |
-
canvas_hotkey_move: "KeyF",
|
41 |
-
canvas_show_tooltip: true,
|
42 |
-
canvas_auto_expand: true,
|
43 |
-
canvas_blur_prompt: true,
|
44 |
-
};
|
45 |
-
|
46 |
-
// Loading the configuration from opts
|
47 |
-
const hotkeysConfig = createHotkeyConfig(
|
48 |
-
defaultHotkeysConfig
|
49 |
-
);
|
50 |
-
|
51 |
-
let isMoving = false;
|
52 |
-
let activeElement;
|
53 |
-
|
54 |
-
const elemData = {};
|
55 |
-
|
56 |
-
function applyZoomAndPan(elemId) {
|
57 |
-
const targetElement = gradioApp().querySelector(elemId);
|
58 |
-
|
59 |
-
if (!targetElement) {
|
60 |
-
console.log("Element not found");
|
61 |
-
return;
|
62 |
-
}
|
63 |
-
|
64 |
-
targetElement.style.transformOrigin = "0 0";
|
65 |
-
|
66 |
-
elemData[elemId] = {
|
67 |
-
zoom: 1,
|
68 |
-
panX: 0,
|
69 |
-
panY: 0
|
70 |
-
};
|
71 |
-
|
72 |
-
let fullScreenMode = false;
|
73 |
-
|
74 |
-
// Create tooltip
|
75 |
-
function createTooltip() {
|
76 |
-
const toolTipElemnt =
|
77 |
-
targetElement.querySelector(".image-container");
|
78 |
-
const tooltip = document.createElement("div");
|
79 |
-
tooltip.className = "canvas-tooltip";
|
80 |
-
|
81 |
-
// Creating an item of information
|
82 |
-
const info = document.createElement("i");
|
83 |
-
info.className = "canvas-tooltip-info";
|
84 |
-
info.textContent = "";
|
85 |
-
|
86 |
-
// Create a container for the contents of the tooltip
|
87 |
-
const tooltipContent = document.createElement("div");
|
88 |
-
tooltipContent.className = "canvas-tooltip-content";
|
89 |
-
|
90 |
-
// Define an array with hotkey information and their actions
|
91 |
-
const hotkeysInfo = [
|
92 |
-
{
|
93 |
-
configKey: "canvas_hotkey_zoom",
|
94 |
-
action: "Zoom canvas",
|
95 |
-
keySuffix: " + wheel"
|
96 |
-
},
|
97 |
-
{
|
98 |
-
configKey: "canvas_hotkey_adjust",
|
99 |
-
action: "Adjust brush size",
|
100 |
-
keySuffix: " + wheel"
|
101 |
-
},
|
102 |
-
{configKey: "canvas_zoom_hotkey_undo", action: "Undo last action", keyPrefix: `${hotkeysConfig.canvas_zoom_undo_extra_key} + ` },
|
103 |
-
{configKey: "canvas_hotkey_reset", action: "Reset zoom"},
|
104 |
-
{
|
105 |
-
configKey: "canvas_hotkey_fullscreen",
|
106 |
-
action: "Fullscreen mode"
|
107 |
-
},
|
108 |
-
{configKey: "canvas_hotkey_move", action: "Move canvas"}
|
109 |
-
];
|
110 |
-
|
111 |
-
// Create hotkeys array based on the config values
|
112 |
-
const hotkeys = hotkeysInfo.map((info) => {
|
113 |
-
const configValue = hotkeysConfig[info.configKey];
|
114 |
-
|
115 |
-
let key = configValue.slice(-1);
|
116 |
-
|
117 |
-
if (info.keySuffix) {
|
118 |
-
key = `${configValue}${info.keySuffix}`;
|
119 |
-
}
|
120 |
-
|
121 |
-
if (info.keyPrefix && info.keyPrefix !== "None + ") {
|
122 |
-
key = `${info.keyPrefix}${configValue[3]}`;
|
123 |
-
}
|
124 |
-
|
125 |
-
return {
|
126 |
-
key,
|
127 |
-
action: info.action,
|
128 |
-
};
|
129 |
-
});
|
130 |
-
|
131 |
-
hotkeys
|
132 |
-
.forEach(hotkey => {
|
133 |
-
const p = document.createElement("p");
|
134 |
-
p.innerHTML = `<b>${hotkey.key}</b> - ${hotkey.action}`;
|
135 |
-
tooltipContent.appendChild(p);
|
136 |
-
});
|
137 |
-
|
138 |
-
tooltip.append(info, tooltipContent);
|
139 |
-
|
140 |
-
// Add a hint element to the target element
|
141 |
-
toolTipElemnt.appendChild(tooltip);
|
142 |
-
}
|
143 |
-
|
144 |
-
//Show tool tip if setting enable
|
145 |
-
if (hotkeysConfig.canvas_show_tooltip) {
|
146 |
-
createTooltip();
|
147 |
-
}
|
148 |
-
|
149 |
-
// Reset the zoom level and pan position of the target element to their initial values
|
150 |
-
function resetZoom() {
|
151 |
-
elemData[elemId] = {
|
152 |
-
zoomLevel: 1,
|
153 |
-
panX: 0,
|
154 |
-
panY: 0
|
155 |
-
};
|
156 |
-
|
157 |
-
targetElement.style.overflow = "hidden";
|
158 |
-
|
159 |
-
targetElement.isZoomed = false;
|
160 |
-
|
161 |
-
targetElement.style.transform = `scale(${elemData[elemId].zoomLevel}) translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px)`;
|
162 |
-
|
163 |
-
const canvas = gradioApp().querySelector(
|
164 |
-
`${elemId} canvas[key="interface"]`
|
165 |
-
);
|
166 |
-
|
167 |
-
toggleOverlap("off");
|
168 |
-
fullScreenMode = false;
|
169 |
-
|
170 |
-
const closeBtn = targetElement.querySelector("button[aria-label='Remove Image']");
|
171 |
-
if (closeBtn) {
|
172 |
-
closeBtn.addEventListener("click", resetZoom);
|
173 |
-
}
|
174 |
-
|
175 |
-
if (canvas) {
|
176 |
-
const parentElement = targetElement.closest('[id^="component-"]');
|
177 |
-
if (
|
178 |
-
canvas &&
|
179 |
-
parseFloat(canvas.style.width) > parentElement.offsetWidth &&
|
180 |
-
parseFloat(targetElement.style.width) > parentElement.offsetWidth
|
181 |
-
) {
|
182 |
-
fitToElement();
|
183 |
-
return;
|
184 |
-
}
|
185 |
-
|
186 |
-
}
|
187 |
-
|
188 |
-
targetElement.style.width = "";
|
189 |
-
}
|
190 |
-
|
191 |
-
// Toggle the zIndex of the target element between two values, allowing it to overlap or be overlapped by other elements
|
192 |
-
function toggleOverlap(forced = "") {
|
193 |
-
const zIndex1 = "0";
|
194 |
-
const zIndex2 = "998";
|
195 |
-
|
196 |
-
targetElement.style.zIndex =
|
197 |
-
targetElement.style.zIndex !== zIndex2 ? zIndex2 : zIndex1;
|
198 |
-
|
199 |
-
if (forced === "off") {
|
200 |
-
targetElement.style.zIndex = zIndex1;
|
201 |
-
} else if (forced === "on") {
|
202 |
-
targetElement.style.zIndex = zIndex2;
|
203 |
-
}
|
204 |
-
}
|
205 |
-
|
206 |
-
// Adjust the brush size based on the deltaY value from a mouse wheel event
|
207 |
-
function adjustBrushSize(
|
208 |
-
elemId,
|
209 |
-
deltaY,
|
210 |
-
withoutValue = false,
|
211 |
-
percentage = 5
|
212 |
-
) {
|
213 |
-
const input =
|
214 |
-
gradioApp().querySelector(
|
215 |
-
`${elemId} input[aria-label='Brush radius']`
|
216 |
-
) ||
|
217 |
-
gradioApp().querySelector(
|
218 |
-
`${elemId} button[aria-label="Use brush"]`
|
219 |
-
);
|
220 |
-
|
221 |
-
if (input) {
|
222 |
-
input.click();
|
223 |
-
if (!withoutValue) {
|
224 |
-
const maxValue =
|
225 |
-
parseFloat(input.getAttribute("max")) || 100;
|
226 |
-
const changeAmount = maxValue * (percentage / 100);
|
227 |
-
const newValue =
|
228 |
-
parseFloat(input.value) +
|
229 |
-
(deltaY > 0 ? -changeAmount : changeAmount);
|
230 |
-
input.value = Math.min(Math.max(newValue, 0), maxValue);
|
231 |
-
input.dispatchEvent(new Event("change"));
|
232 |
-
}
|
233 |
-
}
|
234 |
-
}
|
235 |
-
|
236 |
-
// Reset zoom when uploading a new image
|
237 |
-
const fileInput = gradioApp().querySelector(
|
238 |
-
`${elemId} input[type="file"][accept="image/*"].svelte-116rqfv`
|
239 |
-
);
|
240 |
-
fileInput.addEventListener("click", resetZoom);
|
241 |
-
|
242 |
-
// Update the zoom level and pan position of the target element based on the values of the zoomLevel, panX and panY variables
|
243 |
-
function updateZoom(newZoomLevel, mouseX, mouseY) {
|
244 |
-
newZoomLevel = Math.max(0.1, Math.min(newZoomLevel, 15));
|
245 |
-
|
246 |
-
elemData[elemId].panX +=
|
247 |
-
mouseX - (mouseX * newZoomLevel) / elemData[elemId].zoomLevel;
|
248 |
-
elemData[elemId].panY +=
|
249 |
-
mouseY - (mouseY * newZoomLevel) / elemData[elemId].zoomLevel;
|
250 |
-
|
251 |
-
targetElement.style.transformOrigin = "0 0";
|
252 |
-
targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${newZoomLevel})`;
|
253 |
-
targetElement.style.overflow = "visible";
|
254 |
-
|
255 |
-
toggleOverlap("on");
|
256 |
-
|
257 |
-
return newZoomLevel;
|
258 |
-
}
|
259 |
-
|
260 |
-
// Change the zoom level based on user interaction
|
261 |
-
function changeZoomLevel(operation, e) {
|
262 |
-
if (isModifierKey(e, hotkeysConfig.canvas_hotkey_zoom)) {
|
263 |
-
e.preventDefault();
|
264 |
-
|
265 |
-
let zoomPosX, zoomPosY;
|
266 |
-
let delta = 0.2;
|
267 |
-
|
268 |
-
if (elemData[elemId].zoomLevel > 7) {
|
269 |
-
delta = 0.9;
|
270 |
-
} else if (elemData[elemId].zoomLevel > 2) {
|
271 |
-
delta = 0.6;
|
272 |
-
}
|
273 |
-
|
274 |
-
zoomPosX = e.clientX;
|
275 |
-
zoomPosY = e.clientY;
|
276 |
-
|
277 |
-
fullScreenMode = false;
|
278 |
-
elemData[elemId].zoomLevel = updateZoom(
|
279 |
-
elemData[elemId].zoomLevel +
|
280 |
-
(operation === "+" ? delta : -delta),
|
281 |
-
zoomPosX - targetElement.getBoundingClientRect().left,
|
282 |
-
zoomPosY - targetElement.getBoundingClientRect().top
|
283 |
-
);
|
284 |
-
|
285 |
-
targetElement.isZoomed = true;
|
286 |
-
}
|
287 |
-
}
|
288 |
-
|
289 |
-
/**
|
290 |
-
* This function fits the target element to the screen by calculating
|
291 |
-
* the required scale and offsets. It also updates the global variables
|
292 |
-
* zoomLevel, panX, and panY to reflect the new state.
|
293 |
-
*/
|
294 |
-
|
295 |
-
function fitToElement() {
|
296 |
-
//Reset Zoom
|
297 |
-
targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`;
|
298 |
-
|
299 |
-
let parentElement;
|
300 |
-
|
301 |
-
parentElement = targetElement.closest('[id^="component-"]');
|
302 |
-
|
303 |
-
// Get element and screen dimensions
|
304 |
-
const elementWidth = targetElement.offsetWidth;
|
305 |
-
const elementHeight = targetElement.offsetHeight;
|
306 |
-
|
307 |
-
const screenWidth = parentElement.clientWidth - 24;
|
308 |
-
const screenHeight = parentElement.clientHeight;
|
309 |
-
|
310 |
-
// Calculate scale and offsets
|
311 |
-
const scaleX = screenWidth / elementWidth;
|
312 |
-
const scaleY = screenHeight / elementHeight;
|
313 |
-
const scale = Math.min(scaleX, scaleY);
|
314 |
-
|
315 |
-
const offsetX =0;
|
316 |
-
const offsetY =0;
|
317 |
-
|
318 |
-
// Apply scale and offsets to the element
|
319 |
-
targetElement.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
|
320 |
-
|
321 |
-
// Update global variables
|
322 |
-
elemData[elemId].zoomLevel = scale;
|
323 |
-
elemData[elemId].panX = offsetX;
|
324 |
-
elemData[elemId].panY = offsetY;
|
325 |
-
|
326 |
-
fullScreenMode = false;
|
327 |
-
toggleOverlap("off");
|
328 |
-
}
|
329 |
-
|
330 |
-
// Undo last action
|
331 |
-
function undoLastAction(e) {
|
332 |
-
let isCtrlPressed = isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)
|
333 |
-
const isAuxButton = e.button >= 3;
|
334 |
-
|
335 |
-
if (isAuxButton) {
|
336 |
-
isCtrlPressed = true
|
337 |
-
} else {
|
338 |
-
if (!isModifierKey(e, hotkeysConfig.canvas_zoom_undo_extra_key)) return;
|
339 |
-
}
|
340 |
-
|
341 |
-
// Move undoBtn query outside the if statement to avoid unnecessary queries
|
342 |
-
const undoBtn = document.querySelector(`${activeElement} button[aria-label="Undo"]`);
|
343 |
-
|
344 |
-
if ((isCtrlPressed) && undoBtn ) {
|
345 |
-
e.preventDefault();
|
346 |
-
undoBtn.click();
|
347 |
-
}
|
348 |
-
}
|
349 |
-
|
350 |
-
/**
|
351 |
-
* This function fits the target element to the screen by calculating
|
352 |
-
* the required scale and offsets. It also updates the global variables
|
353 |
-
* zoomLevel, panX, and panY to reflect the new state.
|
354 |
-
*/
|
355 |
-
|
356 |
-
// Fullscreen mode
|
357 |
-
function fitToScreen() {
|
358 |
-
const canvas = gradioApp().querySelector(
|
359 |
-
`${elemId} canvas[key="interface"]`
|
360 |
-
);
|
361 |
-
|
362 |
-
if (!canvas) return;
|
363 |
-
|
364 |
-
targetElement.style.width = (canvas.offsetWidth + 2) + "px";
|
365 |
-
targetElement.style.overflow = "visible";
|
366 |
-
|
367 |
-
if (fullScreenMode) {
|
368 |
-
resetZoom();
|
369 |
-
fullScreenMode = false;
|
370 |
-
return;
|
371 |
-
}
|
372 |
-
|
373 |
-
//Reset Zoom
|
374 |
-
targetElement.style.transform = `translate(${0}px, ${0}px) scale(${1})`;
|
375 |
-
|
376 |
-
// Get scrollbar width to right-align the image
|
377 |
-
const scrollbarWidth =
|
378 |
-
window.innerWidth - document.documentElement.clientWidth;
|
379 |
-
|
380 |
-
// Get element and screen dimensions
|
381 |
-
const elementWidth = targetElement.offsetWidth;
|
382 |
-
const elementHeight = targetElement.offsetHeight;
|
383 |
-
const screenWidth = window.innerWidth - scrollbarWidth;
|
384 |
-
const screenHeight = window.innerHeight;
|
385 |
-
|
386 |
-
// Get element's coordinates relative to the page
|
387 |
-
const elementRect = targetElement.getBoundingClientRect();
|
388 |
-
const elementY = elementRect.y;
|
389 |
-
const elementX = elementRect.x;
|
390 |
-
|
391 |
-
// Calculate scale and offsets
|
392 |
-
const scaleX = screenWidth / elementWidth;
|
393 |
-
const scaleY = screenHeight / elementHeight;
|
394 |
-
const scale = Math.min(scaleX, scaleY);
|
395 |
-
|
396 |
-
// Get the current transformOrigin
|
397 |
-
const computedStyle = window.getComputedStyle(targetElement);
|
398 |
-
const transformOrigin = computedStyle.transformOrigin;
|
399 |
-
const [originX, originY] = transformOrigin.split(" ");
|
400 |
-
const originXValue = parseFloat(originX);
|
401 |
-
const originYValue = parseFloat(originY);
|
402 |
-
|
403 |
-
// Calculate offsets with respect to the transformOrigin
|
404 |
-
const offsetX =
|
405 |
-
(screenWidth - elementWidth * scale) / 2 -
|
406 |
-
elementX -
|
407 |
-
originXValue * (1 - scale);
|
408 |
-
const offsetY =
|
409 |
-
(screenHeight - elementHeight * scale) / 2 -
|
410 |
-
elementY -
|
411 |
-
originYValue * (1 - scale);
|
412 |
-
|
413 |
-
// Apply scale and offsets to the element
|
414 |
-
targetElement.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
|
415 |
-
|
416 |
-
// Update global variables
|
417 |
-
elemData[elemId].zoomLevel = scale;
|
418 |
-
elemData[elemId].panX = offsetX;
|
419 |
-
elemData[elemId].panY = offsetY;
|
420 |
-
|
421 |
-
fullScreenMode = true;
|
422 |
-
toggleOverlap("on");
|
423 |
-
}
|
424 |
-
|
425 |
-
// Handle keydown events
|
426 |
-
function handleKeyDown(event) {
|
427 |
-
// Disable key locks to make pasting from the buffer work correctly
|
428 |
-
if ((event.ctrlKey && event.code === 'KeyV') || (event.ctrlKey && event.code === 'KeyC') || event.code === "F5") {
|
429 |
-
return;
|
430 |
-
}
|
431 |
-
|
432 |
-
// before activating shortcut, ensure user is not actively typing in an input field
|
433 |
-
if (!hotkeysConfig.canvas_blur_prompt) {
|
434 |
-
if (event.target.nodeName === 'TEXTAREA' || event.target.nodeName === 'INPUT') {
|
435 |
-
return;
|
436 |
-
}
|
437 |
-
}
|
438 |
-
|
439 |
-
const hotkeyActions = {
|
440 |
-
[hotkeysConfig.canvas_hotkey_reset]: resetZoom,
|
441 |
-
[hotkeysConfig.canvas_hotkey_overlap]: toggleOverlap,
|
442 |
-
[hotkeysConfig.canvas_hotkey_fullscreen]: fitToScreen,
|
443 |
-
[hotkeysConfig.canvas_zoom_hotkey_undo]: undoLastAction,
|
444 |
-
};
|
445 |
-
|
446 |
-
const action = hotkeyActions[event.code];
|
447 |
-
if (action) {
|
448 |
-
event.preventDefault();
|
449 |
-
action(event);
|
450 |
-
}
|
451 |
-
|
452 |
-
if (
|
453 |
-
isModifierKey(event, hotkeysConfig.canvas_hotkey_zoom) ||
|
454 |
-
isModifierKey(event, hotkeysConfig.canvas_hotkey_adjust)
|
455 |
-
) {
|
456 |
-
event.preventDefault();
|
457 |
-
}
|
458 |
-
}
|
459 |
-
|
460 |
-
// Get Mouse position
|
461 |
-
function getMousePosition(e) {
|
462 |
-
mouseX = e.offsetX;
|
463 |
-
mouseY = e.offsetY;
|
464 |
-
}
|
465 |
-
|
466 |
-
// Simulation of the function to put a long image into the screen.
|
467 |
-
// We detect if an image has a scroll bar or not, make a fullscreen to reveal the image, then reduce it to fit into the element.
|
468 |
-
// We hide the image and show it to the user when it is ready.
|
469 |
-
|
470 |
-
targetElement.isExpanded = false;
|
471 |
-
function autoExpand() {
|
472 |
-
const canvas = document.querySelector(`${elemId} canvas[key="interface"]`);
|
473 |
-
if (canvas) {
|
474 |
-
if (hasHorizontalScrollbar(targetElement) && targetElement.isExpanded === false) {
|
475 |
-
targetElement.style.visibility = "hidden";
|
476 |
-
setTimeout(() => {
|
477 |
-
fitToScreen();
|
478 |
-
resetZoom();
|
479 |
-
targetElement.style.visibility = "visible";
|
480 |
-
targetElement.isExpanded = true;
|
481 |
-
}, 10);
|
482 |
-
}
|
483 |
-
}
|
484 |
-
}
|
485 |
-
|
486 |
-
targetElement.addEventListener("mousemove", getMousePosition);
|
487 |
-
targetElement.addEventListener("auxclick", undoLastAction);
|
488 |
-
|
489 |
-
//observers
|
490 |
-
// Creating an observer with a callback function to handle DOM changes
|
491 |
-
const observer = new MutationObserver((mutationsList, observer) => {
|
492 |
-
for (let mutation of mutationsList) {
|
493 |
-
// If the style attribute of the canvas has changed, by observation it happens only when the picture changes
|
494 |
-
if (mutation.type === 'attributes' && mutation.attributeName === 'style' &&
|
495 |
-
mutation.target.tagName.toLowerCase() === 'canvas') {
|
496 |
-
targetElement.isExpanded = false;
|
497 |
-
setTimeout(resetZoom, 10);
|
498 |
-
}
|
499 |
-
}
|
500 |
-
});
|
501 |
-
|
502 |
-
// Apply auto expand if enabled
|
503 |
-
if (hotkeysConfig.canvas_auto_expand) {
|
504 |
-
targetElement.addEventListener("mousemove", autoExpand);
|
505 |
-
// Set up an observer to track attribute changes
|
506 |
-
observer.observe(targetElement, { attributes: true, childList: true, subtree: true });
|
507 |
-
}
|
508 |
-
|
509 |
-
// Handle events only inside the targetElement
|
510 |
-
let isKeyDownHandlerAttached = false;
|
511 |
-
|
512 |
-
function handleMouseMove() {
|
513 |
-
if (!isKeyDownHandlerAttached) {
|
514 |
-
document.addEventListener("keydown", handleKeyDown);
|
515 |
-
isKeyDownHandlerAttached = true;
|
516 |
-
|
517 |
-
activeElement = elemId;
|
518 |
-
}
|
519 |
-
}
|
520 |
-
|
521 |
-
function handleMouseLeave() {
|
522 |
-
if (isKeyDownHandlerAttached) {
|
523 |
-
document.removeEventListener("keydown", handleKeyDown);
|
524 |
-
isKeyDownHandlerAttached = false;
|
525 |
-
|
526 |
-
activeElement = null;
|
527 |
-
}
|
528 |
-
}
|
529 |
-
|
530 |
-
// Add mouse event handlers
|
531 |
-
targetElement.addEventListener("mousemove", handleMouseMove);
|
532 |
-
targetElement.addEventListener("mouseleave", handleMouseLeave);
|
533 |
-
|
534 |
-
targetElement.addEventListener("wheel", e => {
|
535 |
-
// change zoom level
|
536 |
-
const operation = e.deltaY > 0 ? "-" : "+";
|
537 |
-
changeZoomLevel(operation, e);
|
538 |
-
|
539 |
-
// Handle brush size adjustment with ctrl key pressed
|
540 |
-
if (isModifierKey(e, hotkeysConfig.canvas_hotkey_adjust)) {
|
541 |
-
e.preventDefault();
|
542 |
-
|
543 |
-
// Increase or decrease brush size based on scroll direction
|
544 |
-
adjustBrushSize(elemId, e.deltaY);
|
545 |
-
}
|
546 |
-
});
|
547 |
-
|
548 |
-
// Handle the move event for pan functionality. Updates the panX and panY variables and applies the new transform to the target element.
|
549 |
-
function handleMoveKeyDown(e) {
|
550 |
-
|
551 |
-
// Disable key locks to make pasting from the buffer work correctly
|
552 |
-
if ((e.ctrlKey && e.code === 'KeyV') || (e.ctrlKey && e.code === 'KeyC') || e.code === "F5") {
|
553 |
-
return;
|
554 |
-
}
|
555 |
-
|
556 |
-
// before activating shortcut, ensure user is not actively typing in an input field
|
557 |
-
if (!hotkeysConfig.canvas_blur_prompt) {
|
558 |
-
if (e.target.nodeName === 'TEXTAREA' || e.target.nodeName === 'INPUT') {
|
559 |
-
return;
|
560 |
-
}
|
561 |
-
}
|
562 |
-
|
563 |
-
|
564 |
-
if (e.code === hotkeysConfig.canvas_hotkey_move) {
|
565 |
-
if (!e.ctrlKey && !e.metaKey && isKeyDownHandlerAttached) {
|
566 |
-
e.preventDefault();
|
567 |
-
document.activeElement.blur();
|
568 |
-
isMoving = true;
|
569 |
-
}
|
570 |
-
}
|
571 |
-
}
|
572 |
-
|
573 |
-
function handleMoveKeyUp(e) {
|
574 |
-
if (e.code === hotkeysConfig.canvas_hotkey_move) {
|
575 |
-
isMoving = false;
|
576 |
-
}
|
577 |
-
}
|
578 |
-
|
579 |
-
document.addEventListener("keydown", handleMoveKeyDown);
|
580 |
-
document.addEventListener("keyup", handleMoveKeyUp);
|
581 |
-
|
582 |
-
// Detect zoom level and update the pan speed.
|
583 |
-
function updatePanPosition(movementX, movementY) {
|
584 |
-
let panSpeed = 2;
|
585 |
-
|
586 |
-
if (elemData[elemId].zoomLevel > 8) {
|
587 |
-
panSpeed = 3.5;
|
588 |
-
}
|
589 |
-
|
590 |
-
elemData[elemId].panX += movementX * panSpeed;
|
591 |
-
elemData[elemId].panY += movementY * panSpeed;
|
592 |
-
|
593 |
-
// Delayed redraw of an element
|
594 |
-
requestAnimationFrame(() => {
|
595 |
-
targetElement.style.transform = `translate(${elemData[elemId].panX}px, ${elemData[elemId].panY}px) scale(${elemData[elemId].zoomLevel})`;
|
596 |
-
toggleOverlap("on");
|
597 |
-
});
|
598 |
-
}
|
599 |
-
|
600 |
-
function handleMoveByKey(e) {
|
601 |
-
if (isMoving && elemId === activeElement) {
|
602 |
-
updatePanPosition(e.movementX, e.movementY);
|
603 |
-
targetElement.style.pointerEvents = "none";
|
604 |
-
targetElement.style.overflow = "visible";
|
605 |
-
} else {
|
606 |
-
targetElement.style.pointerEvents = "auto";
|
607 |
-
}
|
608 |
-
}
|
609 |
-
|
610 |
-
// Prevents sticking to the mouse
|
611 |
-
window.onblur = function() {
|
612 |
-
isMoving = false;
|
613 |
-
};
|
614 |
-
|
615 |
-
// Checks for extension
|
616 |
-
function checkForOutBox() {
|
617 |
-
const parentElement = targetElement.closest('[id^="component-"]');
|
618 |
-
if (parentElement.offsetWidth < targetElement.offsetWidth && !targetElement.isExpanded) {
|
619 |
-
resetZoom();
|
620 |
-
targetElement.isExpanded = true;
|
621 |
-
}
|
622 |
-
|
623 |
-
if (parentElement.offsetWidth < targetElement.offsetWidth && elemData[elemId].zoomLevel == 1) {
|
624 |
-
resetZoom();
|
625 |
-
}
|
626 |
-
|
627 |
-
if (parentElement.offsetWidth < targetElement.offsetWidth && targetElement.offsetWidth * elemData[elemId].zoomLevel > parentElement.offsetWidth && elemData[elemId].zoomLevel < 1 && !targetElement.isZoomed) {
|
628 |
-
resetZoom();
|
629 |
-
}
|
630 |
-
}
|
631 |
-
|
632 |
-
targetElement.addEventListener("mousemove", checkForOutBox);
|
633 |
-
|
634 |
-
window.addEventListener('resize', (e) => {
|
635 |
-
resetZoom();
|
636 |
-
|
637 |
-
targetElement.isExpanded = false;
|
638 |
-
targetElement.isZoomed = false;
|
639 |
-
});
|
640 |
-
|
641 |
-
gradioApp().addEventListener("mousemove", handleMoveByKey);
|
642 |
-
}
|
643 |
-
|
644 |
-
applyZoomAndPan("#inpaint_canvas");
|
645 |
-
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|