From 8fce3214b8101b62dc8ff0309eced14f312936ee Mon Sep 17 00:00:00 2001 From: Fxvoid Date: Wed, 12 Jul 2023 21:04:44 +0300 Subject: [PATCH 1/3] Implemented storing state for 3 extensions --- javascript/state.ext.adetailer.js | 173 ++++++++++++++++++++++ javascript/state.ext.dynamic-prompting.js | 118 +++++++++++++++ javascript/state.ext.multidiffusion.js | 130 ++++++++++++++++ scripts/state_settings.py | 5 +- 4 files changed, 425 insertions(+), 1 deletion(-) create mode 100644 javascript/state.ext.adetailer.js create mode 100644 javascript/state.ext.dynamic-prompting.js create mode 100644 javascript/state.ext.multidiffusion.js diff --git a/javascript/state.ext.adetailer.js b/javascript/state.ext.adetailer.js new file mode 100644 index 0000000..3769062 --- /dev/null +++ b/javascript/state.ext.adetailer.js @@ -0,0 +1,173 @@ +window.state = window.state || {}; +window.state.extensions = window.state.extensions || {}; +state = window.state; + +state.extensions['adetailer'] = (function () { + + let container = null; + let store = null; + let cnTabs = []; + + function bindTabEvents() { + const tabs = container.querySelectorAll('.tabs > div > button'); + tabs.forEach(tab => { // dirty hack here + tab.removeEventListener('click', onTabClick); + tab.addEventListener('click', onTabClick); + }); + return tabs; + } + + function handleTabs() { + let tabs = bindTabEvents(); + let value = store.get('tab'); + if (value) { + for (var i = 0; i < tabs.length; i++) { + if (tabs[i].textContent === value) { + state.utils.triggerEvent(tabs[i], 'click'); + break; + } + } + } + } + + function onTabClick() { + store.set('tab', this.textContent); + bindTabEvents(); + } + + function handleCheckbox(checkbox, id) { + let value = store.get(id); + if (value) { + state.utils.setValue(checkbox, value, 'change'); + } + checkbox.addEventListener('change', function () { + store.set(id, this.checked); + }); + } + + function handleCheckboxes(container, container_idx) { + let checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(function checkbox(checkbox, idx) { + handleCheckbox(checkbox, `ad-tab-${container_idx}-checkbox-${idx}`) + }); + } + + function handleSliders(container, container_idx) { + let sliders = container.querySelectorAll('input[type="range"]'); + sliders.forEach(function (slider, idx) { + let id = `ad-tab-${container_idx}-slider-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(slider, value, 'change'); + } + slider.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleTextboxes(container, container_idx) { + let textboxes = container.querySelectorAll('textarea'); + textboxes.forEach(function (textbox, idx) { + let id = `ad-tab-${container_idx}-textbox-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(textbox, value, 'change'); + } + textbox.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleSelects(container, container_idx) { + let selects = container.querySelectorAll('.gradio-dropdown') + selects.forEach(function (select, idx) { + state.utils.handleSelect(select, `ad-tab-${container_idx}-select-${idx}`, store); + }); + } + + function handleRadioButtons(container, container_idx) { + let fieldsets = container.querySelectorAll('fieldset'); + fieldsets.forEach(function (fieldset, idx) { + let radios = fieldset.querySelectorAll('input[type="radio"]'); + let id = `ad-tab-${container_idx}-fieldset-${idx}`; + let value = store.get(id); + if (value) { + radios.forEach(function (radio) { + state.utils.setValue(radio, value, 'change'); + }); + } + radios.forEach(function (radio) { + radio.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + }); + } + + function handleDropdown(dropdown, id) { + let value = store.get(id); + + if (value && value === 'true') { + state.utils.triggerEvent(dropdown, 'click'); + } + dropdown.addEventListener('click', function () { + let span = this.querySelector('.transition, .icon'); + store.set(id, span.style.transform !== 'rotate(90deg)'); + }); + } + + function handleDropdowns(container, container_idx) { + let dropdowns = container.querySelectorAll('.gradio-accordion .label-wrap'); + dropdowns.forEach(function (dropdown, idx) { + handleDropdown(dropdown, `ad-tab-${container_idx}-dropdown-${idx}`); + }); + } + + function load() { + setTimeout(function () { + handleDropdown(container.querySelector('#script_txt2img_adetailer_ad_main_accordion > .label-wrap'), 'ad-dropdown-main'); + handleCheckbox(container.querySelector('#script_txt2img_adetailer_ad_enable > label > input'), 'ad-checkbox-enable'); + cnTabs.forEach(({ container, container_idx }) => { + handleTabs(container, container_idx); + handleTextboxes(container, container_idx); + handleCheckboxes(container, container_idx); + handleSliders(container, container_idx); + handleRadioButtons(container, container_idx); + handleSelects(container, container_idx); + handleDropdowns(container, container_idx); + }); + }, 500); + } + + function init() { + + container = gradioApp().getElementById('script_txt2img_adetailer_ad_main_accordion'); + store = new state.Store('ext-adetailerr'); + + if (! container) { + return; + } + + let tabs = container.querySelectorAll('.tabitem'); + + if (tabs.length) { + cnTabs = []; + tabs.forEach((tabContainer, i) => { + cnTabs.push({ + container: tabContainer, + container_idx: i + }); + }); + } else { + cnTabs = [{ + container: container + }]; + } + + load(); + } + + return { init }; +}()); diff --git a/javascript/state.ext.dynamic-prompting.js b/javascript/state.ext.dynamic-prompting.js new file mode 100644 index 0000000..78928b8 --- /dev/null +++ b/javascript/state.ext.dynamic-prompting.js @@ -0,0 +1,118 @@ +window.state = window.state || {}; +window.state.extensions = window.state.extensions || {}; +state = window.state; + +state.extensions['dynamic prompting'] = (function () { + + let container = null; + let store = null; + + function handleCheckboxes() { + let checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(function (checkbox, idx) { + let id = `dp-checkbox-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(checkbox, value, 'change'); + } + checkbox.addEventListener('change', function () { + store.set(id, this.checked); + }); + }); + } + + function handleSliders() { + let sliders = container.querySelectorAll('input[type="range"]'); + sliders.forEach(function (slider, idx) { + let id = `dp-slider-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(slider, value, 'change'); + } + slider.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleTextboxes() { + let textboxes = container.querySelectorAll('textarea'); + textboxes.forEach(function (textbox, idx) { + let id = `dp-textbox-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(textbox, value, 'change'); + } + textbox.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleSelects() { + let selects = container.querySelectorAll('.gradio-dropdown') + selects.forEach(function (select, idx) { + state.utils.handleSelect(select, `dp-select-${idx}`, store); + }); + } + + function handleRadioButtons() { + let fieldsets = container.querySelectorAll('fieldset'); + fieldsets.forEach(function (fieldset, idx) { + let radios = fieldset.querySelectorAll('input[type="radio"]'); + let id = `dp-fieldset-${idx}` + let value = store.get(id); + if (value) { + radios.forEach(function (radio) { + state.utils.setValue(radio, value, 'change'); + }); + } + radios.forEach(function (radio) { + radio.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + }); + } + + function handleDropdowns() { + let dropdowns = container.querySelectorAll('.gradio-accordion .label-wrap'); + dropdowns.forEach(function (dropdown, idx) { + let id = `dp-dropdown-${idx}`; + let value = store.get(id); + + if (value && value === 'true') { + state.utils.triggerEvent(dropdown, 'click'); + } + dropdown.addEventListener('click', function () { + let span = this.querySelector('.transition, .icon'); + store.set(id, span.style.transform !== 'rotate(90deg)'); + }); + }); + } + + function load() { + setTimeout(function () { + handleCheckboxes(); + handleSliders(); + handleTextboxes(); + handleSelects(); + handleRadioButtons(); + handleDropdowns(); + }, 500); + } + + function init() { + + container = gradioApp().getElementById('sddp-dynamic-prompting'); + store = new state.Store('ext-dynamic-prompting'); + + if (! container) { + return; + } + + load(); + } + + return { init }; +}()); diff --git a/javascript/state.ext.multidiffusion.js b/javascript/state.ext.multidiffusion.js new file mode 100644 index 0000000..4fe374d --- /dev/null +++ b/javascript/state.ext.multidiffusion.js @@ -0,0 +1,130 @@ +window.state = window.state || {}; +window.state.extensions = window.state.extensions || {}; +state = window.state; + +state.extensions['multidiffusion'] = (function () { + + let containers = []; + let store = null; + + function handleCheckboxes(container, name) { + let checkboxes = container.querySelectorAll('input[type="checkbox"]'); + checkboxes.forEach(function (checkbox, idx) { + let id = `md-${name}-checkbox-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(checkbox, value, 'change'); + } + checkbox.addEventListener('change', function () { + store.set(id, this.checked); + }); + }); + } + + function handleSliders(container, name) { + let sliders = container.querySelectorAll('input[type="range"]'); + sliders.forEach(function (slider, idx) { + let id = `md-${name}-slider-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(slider, value, 'change'); + } + slider.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleTextboxes(container, name) { + let textboxes = container.querySelectorAll('textarea'); + textboxes.forEach(function (textbox, idx) { + let id = `md-${name}-textbox-${idx}`; + let value = store.get(id); + if (value) { + state.utils.setValue(textbox, value, 'change'); + } + textbox.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + } + + function handleSelects(container, name) { + let selects = container.querySelectorAll('.gradio-dropdown') + selects.forEach(function (select, idx) { + state.utils.handleSelect(select, `md-${name}-select-${idx}`, store); + }); + } + + function handleRadioButtons(container, name) { + let fieldsets = container.querySelectorAll('fieldset'); + fieldsets.forEach(function (fieldset, idx) { + let radios = fieldset.querySelectorAll('input[type="radio"]'); + let id = `md-${name}-fieldset-${idx}`; + let value = store.get(id); + if (value) { + radios.forEach(function (radio) { + state.utils.setValue(radio, value, 'change'); + }); + } + radios.forEach(function (radio) { + radio.addEventListener('change', function () { + store.set(id, this.value); + }); + }); + }); + } + + function handleDropdowns(container, name) { + let dropdowns = container.querySelectorAll('.gradio-accordion .label-wrap'); + dropdowns.forEach(function (dropdown, idx) { + let id = `md-${name}-dropdown-${idx}`; + let value = store.get(id); + + if (value && value === 'true') { + state.utils.triggerEvent(dropdown, 'click'); + } + dropdown.addEventListener('click', function () { + let span = this.querySelector('.transition, .icon'); + store.set(id, span.style.transform !== 'rotate(90deg)'); + }); + }); + } + + function load() { + setTimeout(function () { + containers.forEach(({container, name}) => { + handleCheckboxes(container, name); + handleSliders(container, name); + handleTextboxes(container, name); + handleSelects(container, name); + handleRadioButtons(container, name); + handleDropdowns(container, name); + }); + }, 500); + } + + function init() { + + let spanTags = gradioApp().getElementsByTagName("span"); + for (var i = 0; i < spanTags.length; i++) { + if (spanTags[i].textContent == 'Tiled Diffusion') { + containers.push({container: spanTags[i].parentElement.parentElement,name: 'diffusion'}); + } + if (spanTags[i].textContent == 'Tiled VAE') { + containers.push({container: spanTags[i].parentElement.parentElement,name: 'vae'}); + break; + } + }; + + store = new state.Store('ext-multidiffusion'); + + if (! containers.length) { + return; + } + + load(); + } + + return { init }; +}()); diff --git a/scripts/state_settings.py b/scripts/state_settings.py index bb20d31..6646e07 100644 --- a/scripts/state_settings.py +++ b/scripts/state_settings.py @@ -64,7 +64,10 @@ def on_ui_settings(): shared.opts.add_option("state_extensions", shared.OptionInfo([], "Saved elements from extensions", gr.CheckboxGroup, lambda: { "choices": [ - "control-net" + "control-net", + "adetailer", + "multidiffusion", + "dynamic prompting" ] }, section=section)) From 1ec0072fabcc40109803dd1e8024953ee4dcf962 Mon Sep 17 00:00:00 2001 From: Fxvoid Date: Wed, 12 Jul 2023 21:11:09 +0300 Subject: [PATCH 2/3] Added queue for handleSelect function --- javascript/state.utils.js | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/javascript/state.utils.js b/javascript/state.utils.js index f755aca..6836a2a 100644 --- a/javascript/state.utils.js +++ b/javascript/state.utils.js @@ -1,5 +1,6 @@ window.state = window.state || {}; state = window.state; +let selectingQueue = -1; state.utils = { triggerEvent: function triggerEvent(element, event) { @@ -59,20 +60,23 @@ state.utils = { let value = store.get(id); if (value) { - - let input = select.querySelector('input'); - state.utils.triggerMouseEvent(input, 'focus'); - + selectingQueue += 1; setTimeout(() => { - let items = Array.from(select.querySelectorAll('ul li')); - items.forEach(li => { - if (li.lastChild.wholeText.trim() === value) { - state.utils.triggerMouseEvent(li, 'mousedown'); - return false; - } - }); - state.utils.triggerMouseEvent(input, 'blur'); - }, 100); + let input = select.querySelector('input'); + state.utils.triggerMouseEvent(input, 'focus'); + + setTimeout(() => { + let items = Array.from(select.querySelectorAll('ul li')); + items.forEach(li => { + if (li.lastChild.wholeText.trim() === value) { + state.utils.triggerMouseEvent(li, 'mousedown'); + return false; + } + }); + state.utils.triggerMouseEvent(input, 'blur'); + selectingQueue -= 1; + }, 100); + }, selectingQueue * 200) } setTimeout(() => { From da38b5fd04aff252419df2db7a9ce06c32889823 Mon Sep 17 00:00:00 2001 From: Fxvoid Date: Wed, 12 Jul 2023 21:19:28 +0300 Subject: [PATCH 3/3] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b3afd1f..74260ff 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,9 @@ This extension is for AUTOMATIC1111's [Stable Diffusion web UI](https://github.c * Import / Export and Reset state options * Supported extensions: - Control Net + - ADetailer + - Dynamic Prompting + - Multidiffusion upscale/Tiled Diffusion & VAE ### Usage