Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
automatic1111
GitHub Repository: automatic1111/stable-diffusion-webui
Path: blob/master/javascript/ui.js
3055 views
1
// various functions for interaction with ui.py not large enough to warrant putting them in separate files
2
3
function set_theme(theme) {
4
var gradioURL = window.location.href;
5
if (!gradioURL.includes('?__theme=')) {
6
window.location.replace(gradioURL + '?__theme=' + theme);
7
}
8
}
9
10
function all_gallery_buttons() {
11
var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small');
12
var visibleGalleryButtons = [];
13
allGalleryButtons.forEach(function(elem) {
14
if (elem.parentElement.offsetParent) {
15
visibleGalleryButtons.push(elem);
16
}
17
});
18
return visibleGalleryButtons;
19
}
20
21
function selected_gallery_button() {
22
return all_gallery_buttons().find(elem => elem.classList.contains('selected')) ?? null;
23
}
24
25
function selected_gallery_index() {
26
return all_gallery_buttons().findIndex(elem => elem.classList.contains('selected'));
27
}
28
29
function gallery_container_buttons(gallery_container) {
30
return gradioApp().querySelectorAll(`#${gallery_container} .thumbnail-item.thumbnail-small`);
31
}
32
33
function selected_gallery_index_id(gallery_container) {
34
return Array.from(gallery_container_buttons(gallery_container)).findIndex(elem => elem.classList.contains('selected'));
35
}
36
37
function extract_image_from_gallery(gallery) {
38
if (gallery.length == 0) {
39
return [null];
40
}
41
if (gallery.length == 1) {
42
return [gallery[0]];
43
}
44
45
var index = selected_gallery_index();
46
47
if (index < 0 || index >= gallery.length) {
48
// Use the first image in the gallery as the default
49
index = 0;
50
}
51
52
return [gallery[index]];
53
}
54
55
window.args_to_array = Array.from; // Compatibility with e.g. extensions that may expect this to be around
56
57
function switch_to_txt2img() {
58
gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click();
59
60
return Array.from(arguments);
61
}
62
63
function switch_to_img2img_tab(no) {
64
gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click();
65
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[no].click();
66
}
67
function switch_to_img2img() {
68
switch_to_img2img_tab(0);
69
return Array.from(arguments);
70
}
71
72
function switch_to_sketch() {
73
switch_to_img2img_tab(1);
74
return Array.from(arguments);
75
}
76
77
function switch_to_inpaint() {
78
switch_to_img2img_tab(2);
79
return Array.from(arguments);
80
}
81
82
function switch_to_inpaint_sketch() {
83
switch_to_img2img_tab(3);
84
return Array.from(arguments);
85
}
86
87
function switch_to_extras() {
88
gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click();
89
90
return Array.from(arguments);
91
}
92
93
function get_tab_index(tabId) {
94
let buttons = gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button');
95
for (let i = 0; i < buttons.length; i++) {
96
if (buttons[i].classList.contains('selected')) {
97
return i;
98
}
99
}
100
return 0;
101
}
102
103
function create_tab_index_args(tabId, args) {
104
var res = Array.from(args);
105
res[0] = get_tab_index(tabId);
106
return res;
107
}
108
109
function get_img2img_tab_index() {
110
let res = Array.from(arguments);
111
res.splice(-2);
112
res[0] = get_tab_index('mode_img2img');
113
return res;
114
}
115
116
function create_submit_args(args) {
117
var res = Array.from(args);
118
119
// As it is currently, txt2img and img2img send back the previous output args (txt2img_gallery, generation_info, html_info) whenever you generate a new image.
120
// This can lead to uploading a huge gallery of previously generated images, which leads to an unnecessary delay between submitting and beginning to generate.
121
// I don't know why gradio is sending outputs along with inputs, but we can prevent sending the image gallery here, which seems to be an issue for some.
122
// If gradio at some point stops sending outputs, this may break something
123
if (Array.isArray(res[res.length - 3])) {
124
res[res.length - 3] = null;
125
}
126
127
return res;
128
}
129
130
function setSubmitButtonsVisibility(tabname, showInterrupt, showSkip, showInterrupting) {
131
gradioApp().getElementById(tabname + '_interrupt').style.display = showInterrupt ? "block" : "none";
132
gradioApp().getElementById(tabname + '_skip').style.display = showSkip ? "block" : "none";
133
gradioApp().getElementById(tabname + '_interrupting').style.display = showInterrupting ? "block" : "none";
134
}
135
136
function showSubmitButtons(tabname, show) {
137
setSubmitButtonsVisibility(tabname, !show, !show, false);
138
}
139
140
function showSubmitInterruptingPlaceholder(tabname) {
141
setSubmitButtonsVisibility(tabname, false, true, true);
142
}
143
144
function showRestoreProgressButton(tabname, show) {
145
var button = gradioApp().getElementById(tabname + "_restore_progress");
146
if (!button) return;
147
button.style.setProperty('display', show ? 'flex' : 'none', 'important');
148
}
149
150
function submit() {
151
showSubmitButtons('txt2img', false);
152
153
var id = randomId();
154
localSet("txt2img_task_id", id);
155
156
requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() {
157
showSubmitButtons('txt2img', true);
158
localRemove("txt2img_task_id");
159
showRestoreProgressButton('txt2img', false);
160
});
161
162
var res = create_submit_args(arguments);
163
164
res[0] = id;
165
166
return res;
167
}
168
169
function submit_txt2img_upscale() {
170
var res = submit(...arguments);
171
172
res[2] = selected_gallery_index();
173
174
return res;
175
}
176
177
function submit_img2img() {
178
showSubmitButtons('img2img', false);
179
180
var id = randomId();
181
localSet("img2img_task_id", id);
182
183
requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() {
184
showSubmitButtons('img2img', true);
185
localRemove("img2img_task_id");
186
showRestoreProgressButton('img2img', false);
187
});
188
189
var res = create_submit_args(arguments);
190
191
res[0] = id;
192
res[1] = get_tab_index('mode_img2img');
193
194
return res;
195
}
196
197
function submit_extras() {
198
showSubmitButtons('extras', false);
199
200
var id = randomId();
201
202
requestProgress(id, gradioApp().getElementById('extras_gallery_container'), gradioApp().getElementById('extras_gallery'), function() {
203
showSubmitButtons('extras', true);
204
});
205
206
var res = create_submit_args(arguments);
207
208
res[0] = id;
209
210
console.log(res);
211
return res;
212
}
213
214
function restoreProgressTxt2img() {
215
showRestoreProgressButton("txt2img", false);
216
var id = localGet("txt2img_task_id");
217
218
if (id) {
219
showSubmitInterruptingPlaceholder('txt2img');
220
requestProgress(id, gradioApp().getElementById('txt2img_gallery_container'), gradioApp().getElementById('txt2img_gallery'), function() {
221
showSubmitButtons('txt2img', true);
222
}, null, 0);
223
}
224
225
return id;
226
}
227
228
function restoreProgressImg2img() {
229
showRestoreProgressButton("img2img", false);
230
231
var id = localGet("img2img_task_id");
232
233
if (id) {
234
showSubmitInterruptingPlaceholder('img2img');
235
requestProgress(id, gradioApp().getElementById('img2img_gallery_container'), gradioApp().getElementById('img2img_gallery'), function() {
236
showSubmitButtons('img2img', true);
237
}, null, 0);
238
}
239
240
return id;
241
}
242
243
244
/**
245
* Configure the width and height elements on `tabname` to accept
246
* pasting of resolutions in the form of "width x height".
247
*/
248
function setupResolutionPasting(tabname) {
249
var width = gradioApp().querySelector(`#${tabname}_width input[type=number]`);
250
var height = gradioApp().querySelector(`#${tabname}_height input[type=number]`);
251
for (const el of [width, height]) {
252
el.addEventListener('paste', function(event) {
253
var pasteData = event.clipboardData.getData('text/plain');
254
var parsed = pasteData.match(/^\s*(\d+)\D+(\d+)\s*$/);
255
if (parsed) {
256
width.value = parsed[1];
257
height.value = parsed[2];
258
updateInput(width);
259
updateInput(height);
260
event.preventDefault();
261
}
262
});
263
}
264
}
265
266
onUiLoaded(function() {
267
showRestoreProgressButton('txt2img', localGet("txt2img_task_id"));
268
showRestoreProgressButton('img2img', localGet("img2img_task_id"));
269
setupResolutionPasting('txt2img');
270
setupResolutionPasting('img2img');
271
});
272
273
274
function modelmerger() {
275
var id = randomId();
276
requestProgress(id, gradioApp().getElementById('modelmerger_results_panel'), null, function() {});
277
278
var res = create_submit_args(arguments);
279
res[0] = id;
280
return res;
281
}
282
283
284
function ask_for_style_name(_, prompt_text, negative_prompt_text) {
285
var name_ = prompt('Style name:');
286
return [name_, prompt_text, negative_prompt_text];
287
}
288
289
function confirm_clear_prompt(prompt, negative_prompt) {
290
if (confirm("Delete prompt?")) {
291
prompt = "";
292
negative_prompt = "";
293
}
294
295
return [prompt, negative_prompt];
296
}
297
298
299
var opts = {};
300
onAfterUiUpdate(function() {
301
if (Object.keys(opts).length != 0) return;
302
303
var json_elem = gradioApp().getElementById('settings_json');
304
if (json_elem == null) return;
305
306
var textarea = json_elem.querySelector('textarea');
307
var jsdata = textarea.value;
308
opts = JSON.parse(jsdata);
309
310
executeCallbacks(optionsAvailableCallbacks); /*global optionsAvailableCallbacks*/
311
executeCallbacks(optionsChangedCallbacks); /*global optionsChangedCallbacks*/
312
313
Object.defineProperty(textarea, 'value', {
314
set: function(newValue) {
315
var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
316
var oldValue = valueProp.get.call(textarea);
317
valueProp.set.call(textarea, newValue);
318
319
if (oldValue != newValue) {
320
opts = JSON.parse(textarea.value);
321
}
322
323
executeCallbacks(optionsChangedCallbacks);
324
},
325
get: function() {
326
var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
327
return valueProp.get.call(textarea);
328
}
329
});
330
331
json_elem.parentElement.style.display = "none";
332
});
333
334
onOptionsChanged(function() {
335
var elem = gradioApp().getElementById('sd_checkpoint_hash');
336
var sd_checkpoint_hash = opts.sd_checkpoint_hash || "";
337
var shorthash = sd_checkpoint_hash.substring(0, 10);
338
339
if (elem && elem.textContent != shorthash) {
340
elem.textContent = shorthash;
341
elem.title = sd_checkpoint_hash;
342
elem.href = "https://google.com/search?q=" + sd_checkpoint_hash;
343
}
344
});
345
346
let txt2img_textarea, img2img_textarea = undefined;
347
348
function restart_reload() {
349
document.body.style.backgroundColor = "var(--background-fill-primary)";
350
document.body.innerHTML = '<h1 style="font-family:monospace;margin-top:20%;color:lightgray;text-align:center;">Reloading...</h1>';
351
var requestPing = function() {
352
requestGet("./internal/ping", {}, function(data) {
353
location.reload();
354
}, function() {
355
setTimeout(requestPing, 500);
356
});
357
};
358
359
setTimeout(requestPing, 2000);
360
361
return [];
362
}
363
364
// Simulate an `input` DOM event for Gradio Textbox component. Needed after you edit its contents in javascript, otherwise your edits
365
// will only visible on web page and not sent to python.
366
function updateInput(target) {
367
let e = new Event("input", {bubbles: true});
368
Object.defineProperty(e, "target", {value: target});
369
target.dispatchEvent(e);
370
}
371
372
373
var desiredCheckpointName = null;
374
function selectCheckpoint(name) {
375
desiredCheckpointName = name;
376
gradioApp().getElementById('change_checkpoint').click();
377
}
378
379
function currentImg2imgSourceResolution(w, h, scaleBy) {
380
var img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img');
381
return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy];
382
}
383
384
function updateImg2imgResizeToTextAfterChangingImage() {
385
// At the time this is called from gradio, the image has no yet been replaced.
386
// There may be a better solution, but this is simple and straightforward so I'm going with it.
387
388
setTimeout(function() {
389
gradioApp().getElementById('img2img_update_resize_to').click();
390
}, 500);
391
392
return [];
393
394
}
395
396
397
398
function setRandomSeed(elem_id) {
399
var input = gradioApp().querySelector("#" + elem_id + " input");
400
if (!input) return [];
401
402
input.value = "-1";
403
updateInput(input);
404
return [];
405
}
406
407
function switchWidthHeight(tabname) {
408
var width = gradioApp().querySelector("#" + tabname + "_width input[type=number]");
409
var height = gradioApp().querySelector("#" + tabname + "_height input[type=number]");
410
if (!width || !height) return [];
411
412
var tmp = width.value;
413
width.value = height.value;
414
height.value = tmp;
415
416
updateInput(width);
417
updateInput(height);
418
return [];
419
}
420
421
422
var onEditTimers = {};
423
424
// calls func after afterMs milliseconds has passed since the input elem has been edited by user
425
function onEdit(editId, elem, afterMs, func) {
426
var edited = function() {
427
var existingTimer = onEditTimers[editId];
428
if (existingTimer) clearTimeout(existingTimer);
429
430
onEditTimers[editId] = setTimeout(func, afterMs);
431
};
432
433
elem.addEventListener("input", edited);
434
435
return edited;
436
}
437
438