| (function () { |
| 'use strict'; |
|
|
| const FIX_TAG = '[a1111-fix]'; |
| const FIX_VERSION = 'v5.2-hardened'; |
|
|
| if (window.__a1111_fix_v52_applied) { |
| console.warn(FIX_TAG, 'already applied, skipping duplicate load'); |
| return; |
| } |
| window.__a1111_fix_v52_applied = true; |
|
|
| const wrappedCache = new WeakMap(); |
| const crashLogOnce = new WeakMap(); |
| const slowLogOnce = new WeakMap(); |
|
|
| function markWeakOnce(store, callback, kind) { |
| if (typeof callback !== 'function') return false; |
| let kinds = store.get(callback); |
| if (!kinds) { |
| kinds = new Set(); |
| store.set(callback, kinds); |
| } |
|
|
| if (kinds.has(kind)) return false; |
| kinds.add(kind); |
| return true; |
| } |
|
|
| function isWrappedForKind(callback, kind) { |
| return !!( |
| callback && |
| typeof callback === 'function' && |
| callback.__a1111_fix_wrapped === true && |
| callback.__a1111_fix_kind === kind && |
| typeof callback.__a1111_fix_original === 'function' |
| ); |
| } |
|
|
| function getWrappedCallback(callback, kind, slowThresholdMs) { |
| if (typeof callback !== 'function') return callback; |
| if (isWrappedForKind(callback, kind)) return callback; |
|
|
| let sourceCallback = callback; |
| if ( |
| callback.__a1111_fix_wrapped === true && |
| callback.__a1111_fix_kind === kind && |
| typeof callback.__a1111_fix_original === 'function' |
| ) { |
| sourceCallback = callback.__a1111_fix_original; |
| } |
|
|
| let perKind = wrappedCache.get(sourceCallback); |
| if (!perKind) { |
| perKind = Object.create(null); |
| wrappedCache.set(sourceCallback, perKind); |
| } |
|
|
| if (perKind[kind]) return perKind[kind]; |
|
|
| const wrapped = function (arg) { |
| const t0 = performance.now(); |
| try { |
| return sourceCallback(arg); |
| } catch (e) { |
| if (markWeakOnce(crashLogOnce, sourceCallback, kind)) { |
| console.error(FIX_TAG, kind + ' callback crashed:', sourceCallback.name || '(anonymous)', e); |
| } |
| } finally { |
| const elapsed = performance.now() - t0; |
| if (elapsed > slowThresholdMs && markWeakOnce(slowLogOnce, sourceCallback, kind)) { |
| console.warn( |
| FIX_TAG, |
| 'SLOW ' + kind + ': "' + (sourceCallback.name || '(anonymous)') + '" took ' + elapsed.toFixed(0) + 'ms' |
| ); |
| } |
| } |
| }; |
|
|
| wrapped.__a1111_fix_wrapped = true; |
| wrapped.__a1111_fix_original = sourceCallback; |
| wrapped.__a1111_fix_kind = kind; |
| perKind[kind] = wrapped; |
| return wrapped; |
| } |
|
|
| function wrapQueue(queue, kind, slowThresholdMs) { |
| if (!Array.isArray(queue)) return 0; |
|
|
| let wrappedCount = 0; |
| for (let i = 0; i < queue.length; i++) { |
| if (typeof queue[i] === 'function' && !isWrappedForKind(queue[i], kind)) { |
| queue[i] = getWrappedCallback(queue[i], kind, slowThresholdMs); |
| wrappedCount++; |
| } |
| } |
| return wrappedCount; |
| } |
|
|
| function patchQueuePush(queue, kind, slowThresholdMs) { |
| if (!Array.isArray(queue) || queue.__a1111_fix_push_patched) return false; |
|
|
| const originalPush = queue.push; |
| if (typeof originalPush !== 'function') return false; |
|
|
| queue.push = function (...items) { |
| const wrappedItems = items.map((item) => |
| typeof item === 'function' ? getWrappedCallback(item, kind, slowThresholdMs) : item |
| ); |
| return originalPush.apply(this, wrappedItems); |
| }; |
| queue.__a1111_fix_push_patched = true; |
| return true; |
| } |
|
|
| function safeGradioApp() { |
| try { |
| if (typeof window.gradioApp === 'function') { |
| return window.gradioApp(); |
| } |
| } catch (e) { |
| console.warn(FIX_TAG, 'gradioApp() failed while resolving accordion:', e); |
| } |
| return document; |
| } |
|
|
| function applyFix1() { |
| const originalSchedule = window.scheduleAfterUiUpdateCallbacks; |
| if (typeof originalSchedule !== 'function' || |
| typeof window.executeCallbacks !== 'function' || |
| !Array.isArray(window.uiAfterUpdateCallbacks)) { |
| console.warn(FIX_TAG, 'scheduleAfterUiUpdateCallbacks/executeCallbacks/uiAfterUpdateCallbacks not found, skipping FIX-1'); |
| return; |
| } |
|
|
| if (originalSchedule.__a1111_fix_afterupdate_patched) { |
| console.warn(FIX_TAG, 'FIX-1 already patched, skipping duplicate apply'); |
| return; |
| } |
|
|
| const MAX_WAIT_MS = 1000; |
| let maxWaitTimer = null; |
| let running = false; |
|
|
| function clearMaxWaitTimer() { |
| if (maxWaitTimer) { |
| clearTimeout(maxWaitTimer); |
| maxWaitTimer = null; |
| } |
| } |
|
|
| function runAfterUpdateNow() { |
| clearMaxWaitTimer(); |
|
|
| const timeoutId = window.uiAfterUpdateTimeout; |
| if (timeoutId) { |
| clearTimeout(timeoutId); |
| window.uiAfterUpdateTimeout = null; |
| } |
|
|
| if (running) return; |
| running = true; |
| try { |
| if (typeof window.executeCallbacks === 'function') { |
| window.executeCallbacks(window.uiAfterUpdateCallbacks); |
| } |
| } finally { |
| running = false; |
| } |
| } |
|
|
| if (!window.executeCallbacks.__a1111_fix_afterupdate_guard) { |
| const previousExecuteCallbacks = window.executeCallbacks; |
| const guardedExecuteCallbacks = function (queue, arg) { |
| if (queue === window.uiAfterUpdateCallbacks) { |
| clearMaxWaitTimer(); |
| } |
| return previousExecuteCallbacks(queue, arg); |
| }; |
| guardedExecuteCallbacks.__a1111_fix_afterupdate_guard = true; |
| guardedExecuteCallbacks.__a1111_fix_afterupdate_guard_original = previousExecuteCallbacks; |
| window.executeCallbacks = guardedExecuteCallbacks; |
| } |
|
|
| const patchedSchedule = function (...args) { |
| const result = originalSchedule.apply(this, args); |
|
|
| if (!maxWaitTimer) { |
| maxWaitTimer = setTimeout(runAfterUpdateNow, MAX_WAIT_MS); |
| } |
|
|
| return result; |
| }; |
| patchedSchedule.__a1111_fix_afterupdate_patched = true; |
| patchedSchedule.__a1111_fix_afterupdate_original = originalSchedule; |
| window.scheduleAfterUiUpdateCallbacks = patchedSchedule; |
|
|
| console.log(FIX_TAG, 'FIX-1: bounded after-update max-wait=' + MAX_WAIT_MS + 'ms applied (wrapper mode)'); |
| } |
|
|
| function applyFix2() { |
| const configs = [ |
| { queueName: 'uiLoadedCallbacks', registerName: 'onUiLoaded', slowThresholdMs: 100 }, |
| { queueName: 'uiAfterUpdateCallbacks', registerName: 'onAfterUiUpdate', slowThresholdMs: 100 }, |
| { queueName: 'uiUpdateCallbacks', registerName: 'onUiUpdate', slowThresholdMs: 50 }, |
| { queueName: 'optionsChangedCallbacks', registerName: 'onOptionsChanged', slowThresholdMs: 50 }, |
| { queueName: 'optionsAvailableCallbacks', registerName: 'onOptionsAvailable', slowThresholdMs: 50 }, |
| { queueName: 'uiTabChangeCallbacks', registerName: 'onUiTabChange', slowThresholdMs: 50 }, |
| ]; |
|
|
| const activeConfigs = []; |
| const summary = []; |
|
|
| for (const cfg of configs) { |
| const queue = window[cfg.queueName]; |
| const register = window[cfg.registerName]; |
| if (!Array.isArray(queue) || typeof register !== 'function') { |
| continue; |
| } |
|
|
| const existingCount = wrapQueue(queue, cfg.registerName, cfg.slowThresholdMs); |
| patchQueuePush(queue, cfg.registerName, cfg.slowThresholdMs); |
|
|
| if (!register.__a1111_fix_register_patched) { |
| const originalRegister = register; |
| const patchedRegister = function (callback) { |
| return originalRegister(getWrappedCallback(callback, cfg.registerName, cfg.slowThresholdMs)); |
| }; |
| patchedRegister.__a1111_fix_register_patched = true; |
| patchedRegister.__a1111_fix_register_original = originalRegister; |
| window[cfg.registerName] = patchedRegister; |
| } |
|
|
| activeConfigs.push(cfg); |
| summary.push(cfg.registerName + '=' + existingCount); |
| } |
|
|
| if (activeConfigs.length === 0) { |
| console.warn(FIX_TAG, 'no callback queues found, skipping FIX-2'); |
| return; |
| } |
|
|
| if (typeof window.executeCallbacks === 'function' && !window.executeCallbacks.__a1111_fix_patched) { |
| const originalExecuteCallbacks = window.executeCallbacks; |
| const patchedExecuteCallbacks = function (queue, arg) { |
| for (const cfg of activeConfigs) { |
| if (queue === window[cfg.queueName]) { |
| wrapQueue(queue, cfg.registerName, cfg.slowThresholdMs); |
| break; |
| } |
| } |
| return originalExecuteCallbacks(queue, arg); |
| }; |
| patchedExecuteCallbacks.__a1111_fix_patched = true; |
| patchedExecuteCallbacks.__a1111_fix_original = originalExecuteCallbacks; |
| window.executeCallbacks = patchedExecuteCallbacks; |
| } |
|
|
| console.log(FIX_TAG, 'FIX-2: callback guards applied to', summary.join(', ')); |
| } |
|
|
| function applyFix3() { |
| if (typeof window.inputAccordionChecked !== 'function') { |
| console.warn(FIX_TAG, 'inputAccordionChecked not found, skipping FIX-3'); |
| return; |
| } |
|
|
| const warnedOnce = new Set(); |
|
|
| function isRealAccordion(el) { |
| return !!( |
| el && |
| el.visibleCheckbox instanceof HTMLInputElement && |
| typeof el.onVisibleCheckboxChange === 'function' |
| ); |
| } |
|
|
| function resolveRealAccordion(id) { |
| const app = safeGradioApp(); |
| const direct = app.getElementById ? app.getElementById(id) : null; |
| if (isRealAccordion(direct)) return direct; |
|
|
| const dotted = app.getElementById ? app.getElementById('.' + id) : null; |
| if (isRealAccordion(dotted)) return dotted; |
|
|
| if (direct && typeof direct.querySelector === 'function') { |
| const nestedCheckbox = direct.querySelector('.input-accordion-checkbox'); |
| if (nestedCheckbox) { |
| const parentAccordion = nestedCheckbox.closest('.input-accordion'); |
| if (isRealAccordion(parentAccordion)) return parentAccordion; |
| } |
| } |
|
|
| return null; |
| } |
|
|
| window.inputAccordionChecked = function (id, checked) { |
| const realEl = resolveRealAccordion(id); |
| if (!realEl) { |
| if (!warnedOnce.has(id)) { |
| warnedOnce.add(id); |
| const app = safeGradioApp(); |
| const direct = app.getElementById ? app.getElementById(id) : null; |
| const dotted = app.getElementById ? app.getElementById('.' + id) : null; |
| console.error( |
| FIX_TAG, 'FIX-3: cannot resolve accordion for id:', id, |
| '\n direct el:', direct, |
| '\n direct.visibleCheckbox:', direct && direct.visibleCheckbox, |
| '\n direct.visibleCheckbox instanceof HTMLInputElement:', |
| direct && (direct.visibleCheckbox instanceof HTMLInputElement), |
| '\n dotted el:', dotted |
| ); |
| } |
| return; |
| } |
|
|
| realEl.visibleCheckbox.checked = checked; |
| realEl.onVisibleCheckboxChange(); |
| }; |
|
|
| console.log(FIX_TAG, 'FIX-3: resilient accordion resolver applied'); |
| } |
|
|
| function applyFix4() { |
| window.__a1111ScriptRegistry = window.__a1111ScriptRegistry || { |
| mode: 'unknown', |
| scripts: {}, |
| loaded: {}, |
| errors: {}, |
| injected_order: [], |
| }; |
|
|
| function registerScriptElement(el) { |
| if (!el || el.tagName !== 'SCRIPT') return; |
| if (typeof window.__a1111RegisterScript === 'function') { |
| window.__a1111RegisterScript(el); |
| return; |
| } |
|
|
| const src = el.getAttribute('src') || ''; |
| window.__a1111ScriptRegistry.scripts[src] = { |
| role: el.getAttribute('data-a1111-role') || 'unknown', |
| mode: el.getAttribute('data-a1111-mode') || 'unknown', |
| path: el.getAttribute('data-a1111-path') || src, |
| basedir: el.getAttribute('data-a1111-basedir') || '', |
| }; |
| if (!window.__a1111ScriptRegistry.injected_order.includes(src)) { |
| window.__a1111ScriptRegistry.injected_order.push(src); |
| } |
| } |
|
|
| window.addEventListener('error', function (event) { |
| const target = event && event.target; |
| if (target && target.tagName === 'SCRIPT') { |
| registerScriptElement(target); |
| const src = target.getAttribute('src') || ''; |
| window.__a1111ScriptRegistry.errors[src] = true; |
| return; |
| } |
|
|
| const filename = event && event.filename; |
| if (filename) { |
| console.error(FIX_TAG, 'window error from script:', filename, event.error || event.message || event); |
| } |
| }, true); |
|
|
| window.addEventListener('unhandledrejection', function (event) { |
| console.error(FIX_TAG, 'unhandled promise rejection:', event.reason || event); |
| }); |
|
|
| function summarizeRegistry() { |
| const registry = window.__a1111ScriptRegistry || {}; |
| const scripts = registry.scripts || {}; |
| const loaded = registry.loaded || {}; |
| const errors = registry.errors || {}; |
| const order = registry.injected_order || []; |
|
|
| const ok = []; |
| const failed = []; |
| const pending = []; |
|
|
| for (const src of order.length ? order : Object.keys(scripts)) { |
| const meta = scripts[src] || {}; |
| const item = { |
| src, |
| role: meta.role || 'unknown', |
| mode: meta.mode || 'unknown', |
| path: meta.path || src, |
| }; |
|
|
| if (errors[src]) { |
| failed.push(item); |
| } else if (loaded[src]) { |
| ok.push(item); |
| } else { |
| pending.push(item); |
| } |
| } |
|
|
| return { ok, failed, pending, mode: registry.mode || 'unknown' }; |
| } |
|
|
| function summarizeCallbacks() { |
| const groups = [ |
| ['uiLoadedCallbacks', 'onUiLoaded'], |
| ['uiAfterUpdateCallbacks', 'onAfterUiUpdate'], |
| ['uiUpdateCallbacks', 'onUiUpdate'], |
| ['optionsChangedCallbacks', 'onOptionsChanged'], |
| ['optionsAvailableCallbacks', 'onOptionsAvailable'], |
| ['uiTabChangeCallbacks', 'onUiTabChange'], |
| ]; |
| return groups.map(([queueName, registerName]) => { |
| const queue = window[queueName]; |
| return { |
| queue: queueName, |
| register: registerName, |
| present: Array.isArray(queue), |
| count: Array.isArray(queue) ? queue.length : 0, |
| }; |
| }); |
| } |
|
|
| window.__a1111FixReport = function () { |
| const report = summarizeRegistry(); |
| const callbacks = summarizeCallbacks(); |
| console.log(FIX_TAG, 'loader mode =', report.mode); |
| console.log(FIX_TAG, 'loaded scripts =', report.ok.length, 'failed =', report.failed.length, 'pending =', report.pending.length); |
| console.table(callbacks); |
|
|
| if (report.failed.length) { |
| console.warn(FIX_TAG, 'failed scripts:'); |
| console.table(report.failed); |
| } |
| if (report.pending.length) { |
| console.warn(FIX_TAG, 'pending/unconfirmed scripts:'); |
| console.table(report.pending); |
| } |
| if (!report.failed.length && !report.pending.length) { |
| console.log(FIX_TAG, 'all tracked scripts loaded cleanly'); |
| } |
| return { ...report, callbacks }; |
| }; |
|
|
| window.addEventListener('load', function () { |
| setTimeout(function () { |
| const report = window.__a1111FixReport(); |
| if (report.failed.length || report.pending.length) { |
| console.warn(FIX_TAG, 'FIX-4: loader diagnostics detected script issues; inspect __a1111FixReport() output'); |
| } |
| }, 1500); |
| }, { once: true }); |
|
|
| console.log(FIX_TAG, 'FIX-4: loader diagnostics ready'); |
| } |
|
|
| applyFix1(); |
| applyFix2(); |
| applyFix3(); |
| applyFix4(); |
|
|
| console.log(FIX_TAG, FIX_VERSION, 'ready'); |
| })(); |
|
|