mirror of https://github.com/vladmandic/automatic
199 lines
6.7 KiB
JavaScript
199 lines
6.7 KiB
JavaScript
window.gradioObserver = null;
|
|
|
|
async function sleep(ms) {
|
|
return new Promise((resolve) => { setTimeout(resolve, ms); });
|
|
}
|
|
|
|
function gradioApp() {
|
|
const elems = document.getElementsByTagName('gradio-app');
|
|
const elem = elems.length === 0 ? document : elems[0];
|
|
if (elem !== document) elem.getElementById = (id) => document.getElementById(id);
|
|
return elem.shadowRoot ? elem.shadowRoot : elem;
|
|
}
|
|
|
|
function logFn(func) { // not recommended: use log, debug or error explicitly
|
|
return async function () { // eslint-disable-line func-names
|
|
const t0 = performance.now();
|
|
const returnValue = func(...arguments);
|
|
const t1 = performance.now();
|
|
log(func.name, `time=${Math.round(t1 - t0)}`);
|
|
timer(func.name, t1 - t0);
|
|
return returnValue;
|
|
};
|
|
}
|
|
|
|
function getUICurrentTab() {
|
|
return gradioApp().querySelector('#tabs button.selected');
|
|
}
|
|
|
|
function getUICurrentTabContent() {
|
|
return gradioApp().querySelector('.tabitem[id^=tab_]:not([style*="display: none"])');
|
|
}
|
|
|
|
const get_uiCurrentTabContent = getUICurrentTabContent;
|
|
const get_uiCurrentTab = getUICurrentTab;
|
|
const uiAfterUpdateCallbacks = [];
|
|
const uiUpdateCallbacks = [];
|
|
const uiLoadedCallbacks = [];
|
|
const uiReadyCallbacks = [];
|
|
const uiTabChangeCallbacks = [];
|
|
const optionsChangedCallbacks = [];
|
|
let uiCurrentTab = null;
|
|
let uiAfterUpdateTimeout = null;
|
|
|
|
function onAfterUiUpdate(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onAfterUiUpdate was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
uiAfterUpdateCallbacks.push(callback);
|
|
}
|
|
|
|
function onUiUpdate(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onUiUpdate was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
uiUpdateCallbacks.push(callback);
|
|
}
|
|
|
|
function onUiLoaded(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onUiLoaded was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
uiLoadedCallbacks.push(callback);
|
|
}
|
|
|
|
function onUiReady(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onUiReady was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
uiReadyCallbacks.push(callback);
|
|
}
|
|
|
|
function onUiTabChange(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onUiTabChange was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
uiTabChangeCallbacks.push(callback);
|
|
}
|
|
|
|
function onOptionsChanged(callback) {
|
|
if (typeof callback !== 'function') {
|
|
error(`onOptionsChanged was called without a valid value. Expected a function but got: ${callback}`);
|
|
return;
|
|
}
|
|
optionsChangedCallbacks.push(callback);
|
|
}
|
|
|
|
function executeCallbacks(queue, arg) {
|
|
// if (!uiLoaded) return
|
|
for (const callback of queue) {
|
|
if (!callback) continue;
|
|
try {
|
|
const t0 = performance.now();
|
|
callback(arg);
|
|
const t1 = performance.now();
|
|
if (t1 - t0 > 250) log('callbackSlow', callback.name || callback, `time=${Math.round(t1 - t0)}`);
|
|
timer(callback.name || 'anonymousCallback', t1 - t0);
|
|
} catch (e) {
|
|
error(`executeCallbacks: ${callback} ${e}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
const anyPromptExists = () => gradioApp().querySelectorAll('.main-prompts').length > 0;
|
|
|
|
function scheduleAfterUiUpdateCallbacks() {
|
|
clearTimeout(uiAfterUpdateTimeout);
|
|
uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks), 250);
|
|
}
|
|
|
|
let executedOnLoaded = false;
|
|
const ignoreElements = ['logMonitorData', 'logWarnings', 'logErrors', 'tooltip-container', 'logger'];
|
|
const ignoreElementsSet = new Set(ignoreElements);
|
|
const ignoreClasses = ['wrap'];
|
|
|
|
let mutationTimer = null;
|
|
let validMutations = [];
|
|
|
|
async function mutationCallback(mutations) {
|
|
if (mutations.length <= 0) return;
|
|
for (const mutation of mutations) {
|
|
const target = mutation.target;
|
|
if (target.nodeName === 'LABEL') continue;
|
|
if (ignoreElementsSet.has(target.id)) continue;
|
|
if (target.classList?.contains(ignoreClasses[0])) continue;
|
|
validMutations.push(mutation);
|
|
}
|
|
if (validMutations.length < 1) return;
|
|
|
|
if (mutationTimer) clearTimeout(mutationTimer);
|
|
mutationTimer = setTimeout(async () => {
|
|
if (!executedOnLoaded && anyPromptExists()) { // execute once
|
|
executedOnLoaded = true;
|
|
executeCallbacks(uiLoadedCallbacks);
|
|
}
|
|
if (executedOnLoaded) { // execute on each mutation
|
|
executeCallbacks(uiUpdateCallbacks, mutations);
|
|
scheduleAfterUiUpdateCallbacks();
|
|
}
|
|
const newTab = getUICurrentTab();
|
|
if (newTab && (newTab !== uiCurrentTab)) {
|
|
uiCurrentTab = newTab;
|
|
executeCallbacks(uiTabChangeCallbacks);
|
|
}
|
|
validMutations = [];
|
|
mutationTimer = null;
|
|
}, 100);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
log('DOMContentLoaded');
|
|
window.gradioObserver = new MutationObserver(mutationCallback);
|
|
window.gradioObserver.observe(gradioApp(), { childList: true, subtree: true, attributes: false });
|
|
});
|
|
|
|
/**
|
|
* Add a listener to the document for keydown events
|
|
*/
|
|
document.addEventListener('keydown', (e) => {
|
|
let elem;
|
|
if (e.key === 'Escape') elem = getUICurrentTabContent().querySelector('button[id$=_interrupt]');
|
|
if (e.key === 'Enter' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_generate]');
|
|
if (e.key === 'i' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_reprocess]');
|
|
if (e.key === ' ' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_extra_networks_btn]');
|
|
if (e.key === 'n' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id$=_extra_networks_btn]');
|
|
if (e.key === 's' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=save_]');
|
|
if (e.key === 'Insert' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=save_]');
|
|
if (e.key === 'd' && e.ctrlKey) elem = getUICurrentTabContent().querySelector('button[id^=delete_]');
|
|
// if (e.key === 'm' && e.ctrlKey) elem = gradioApp().getElementById('setting_sd_model_checkpoint');
|
|
if (elem) {
|
|
e.preventDefault();
|
|
log('hotkey', { key: e.key, meta: e.metaKey, ctrl: e.ctrlKey, alt: e.altKey }, elem?.id, elem.nodeName);
|
|
if (elem.nodeName === 'BUTTON') elem.click();
|
|
else elem.focus();
|
|
}
|
|
});
|
|
|
|
/**
|
|
* checks that a UI element is not in another hidden element or tab content
|
|
*/
|
|
function uiElementIsVisible(el) {
|
|
if (el === document) return true;
|
|
const computedStyle = getComputedStyle(el);
|
|
const isVisible = computedStyle.display !== 'none';
|
|
if (!isVisible) return false;
|
|
return uiElementIsVisible(el.parentNode);
|
|
}
|
|
|
|
function uiElementInSight(el) {
|
|
const clRect = el.getBoundingClientRect();
|
|
const windowHeight = window.innerHeight;
|
|
const isOnScreen = clRect.bottom > 0 && clRect.top < windowHeight;
|
|
return isOnScreen;
|
|
}
|