mirror of
https://github.com/AUTOMATIC1111/stable-diffusion-webui.git
synced 2024-06-07 21:20:49 +00:00
374fe636b8
commit b030b67ad005bfe29bcda692238a00042dcae816 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Wed Feb 8 16:38:56 2023 -0800 styling adjustements commit 80a2acb0230dd77489b0eb466f2efe827a053f6d Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Wed Feb 8 10:49:47 2023 -0800 badge indicator toggles visibility by selection commit 898922e025a6422ac947fb45c1fa4f1109882f0a Merge: 745382a0 31bbfa72 Author: Gerschel <9631031+Gerschel@users.noreply.github.com> Date: Wed Feb 8 08:35:26 2023 -0800 Merge pull request #1 from w-e-w/Rounding-Method Rounding Method commit 31bbfa729a15ef35fa1f905345d3ba2b17b26ab9 Author: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Wed Feb 8 19:41:45 2023 +0900 use switch commit 85dbe511c33521d3ac62224bf0e0f3a48194ce63 Author: w-e-w <40751091+w-e-w@users.noreply.github.com> Date: Wed Feb 8 16:47:52 2023 +0900 Rounding Method commit 745382a0f4b8d16241545a3460d5206915959255 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 21:19:20 2023 -0800 default set to round commit 728579c618af30ec98a5af0991bd3f28bdaca399 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 21:17:03 2023 -0800 cleaned some commented code out; added indicator commit 5b288c24a1edd8a5c2f35214b9634316d05b8dae Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 18:19:00 2023 -0800 needs cleaning; attempt at rounding commit d9f18ae92b929576b0b8c5f1ef8b3b38e441e381 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 15:46:25 2023 -0800 add rounding option in setting for aspect ratio commit af22106802c9e42205649e4c71c23fcf5b8c62f6 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 13:18:45 2023 -0800 added some ratios, sorted ratios by commonality commit 11e2fba73cffe8cdbf4cd0860641b94428ca0e74 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Tue Feb 7 10:46:53 2023 -0800 snaps to mulitples of 8 and along ratio commit fa00387e07460b10ee82671a1bfa8687e00ee60b Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:54:59 2023 -0800 updated slidercomponentcontroller commit 8059bc111c3e2d1edb3314e05ab21b65120fa1dd Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:29:11 2023 -0800 added step size adjustment on number field commit 641157b9f27a874a24ee7b0a854a092e9eac3eec Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:12:03 2023 -0800 added return step size to default when ratio is disabled commit 5fb75ad28f2476f36100ec93922a8199adbd2a68 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 14:09:34 2023 -0800 added step size adjustment commit e33532883bc4709cd41c3775cbb646d1d5ab0584 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 11:56:15 2023 -0800 adjusted dropdown size, padding, text-align commit 81937329cee77f466c5a5b23c268d0c810128f84 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 11:39:57 2023 -0800 added positioning and styling commit 86eb4583782d92880a9a113a54ffbac9d92f3753 Author: Gerschel <Gerschel_Payne@hotmail.com> Date: Mon Feb 6 08:54:45 2023 -0800 fix typo in defaults; added preventDefault in event
260 lines
9.1 KiB
JavaScript
260 lines
9.1 KiB
JavaScript
/* This is a basic library that allows controlling elements that take some form of user input.
|
|
|
|
This was previously written in typescript, where all controllers implemented an interface. Not
|
|
all methods were needed in all the controllers, but it was done to keep a common interface, so
|
|
your main app can serve as a controller of controllers.
|
|
|
|
These controllers were built to work on the shapes of html elements that gradio components use.
|
|
|
|
There may be some notes in it that only applied to my use case, but I left them to help others
|
|
along.
|
|
|
|
You will need the parent element for these to work.
|
|
The parent element can be defined as the element (div) that gets the element id when assigning
|
|
an element id to a gradio component.
|
|
|
|
Example:
|
|
gr.TextBox(value="...", elem_id="THISID")
|
|
|
|
Basic usage, grab an element that is the parent container for the component.
|
|
|
|
Send it in to the class, like a function, don't forget the "new" keyword so it calls the constructor
|
|
and sends back a new object.
|
|
|
|
Example:
|
|
|
|
let txt2imgPrompt = new TextComponentController(gradioApp().querySelector("#txt2img_prompt"))
|
|
|
|
Then use the getVal() method to get the value, or use the setVal(myValue) method to set the value.
|
|
|
|
Input types that are groups, like Checkbox groups (not individual checkboxes), take in an array of values.
|
|
|
|
Checkbox group has to reset all values to False (unchecked), then set the values in your array to true (checked).
|
|
If you don't hold a reference to the values (the labels in string format), you can acquire them using the getVal() method.
|
|
*/
|
|
class DropdownComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.childSelector = this.element.querySelector('select');
|
|
this.children = new Map();
|
|
Array.from(this.childSelector.querySelectorAll('option')).forEach(opt => this.children.set(opt.value, opt));
|
|
}
|
|
getVal() {
|
|
return this.childSelector.value;
|
|
}
|
|
updateVal(optionElement) {
|
|
optionElement.selected = true;
|
|
}
|
|
setVal(name) {
|
|
this.updateVal(this.children.get(name));
|
|
this.eventHandler();
|
|
}
|
|
eventHandler() {
|
|
this.childSelector.dispatchEvent(new Event("change"));
|
|
}
|
|
}
|
|
class CheckboxComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.child = this.element.querySelector('input');
|
|
}
|
|
getVal() {
|
|
return this.child.checked;
|
|
}
|
|
updateVal(checked) {
|
|
this.child.checked = checked;
|
|
}
|
|
setVal(checked) {
|
|
this.updateVal(checked);
|
|
this.eventHandler();
|
|
}
|
|
eventHandler() {
|
|
this.child.dispatchEvent(new Event("change"));
|
|
}
|
|
}
|
|
class CheckboxGroupComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
//this.checkBoxes = new Object;
|
|
this.children = new Map();
|
|
Array.from(this.element.querySelectorAll('input')).forEach(input => this.children.set(input.nextElementSibling.innerText, input));
|
|
/* element id gets use fieldset, grab all inputs (the bool val) get the userfriendly label, use as key, put bool value in mapping */
|
|
//Array.from(this.component.querySelectorAll("input")).forEach( _input => this.checkBoxes[_input.nextElementSibling.innerText] = _input)
|
|
/*Checkboxgroup structure
|
|
<fieldset>
|
|
<div> css makes translucent
|
|
<span>
|
|
serves as label for component
|
|
</span>
|
|
<div data-testid='checkbox-group'> container for checkboxes
|
|
<label>
|
|
<input type=checkbox>
|
|
<span>checkbox words</span>
|
|
</label>
|
|
...
|
|
</div>
|
|
</fieldset>
|
|
*/
|
|
}
|
|
updateVal(label) {
|
|
/*********
|
|
calls updates using a throttle or else the backend does not get updated properly
|
|
* ********/
|
|
setTimeout(() => this.conditionalToggle(true, this.children.get(label)), 2);
|
|
}
|
|
setVal(labels) {
|
|
/* Handles reset and updates all in array to true */
|
|
this.reupdateVals();
|
|
labels.forEach(l => this.updateVal(l));
|
|
}
|
|
getVal() {
|
|
//return the list of values that are true
|
|
return [...this.children].filter(([k, v]) => v.checked).map(arr => arr[0]);
|
|
}
|
|
reupdateVals() {
|
|
/**************
|
|
* for reupdating all vals, first set to false
|
|
**************/
|
|
this.children.forEach(inputChild => this.conditionalToggle(false, inputChild));
|
|
}
|
|
conditionalToggle(desiredVal, inputChild) {
|
|
//This method behaves like 'set this value to this'
|
|
//Using element.checked = true/false, does not register the change, even if you called change afterwards,
|
|
// it only sets what it looks like in our case, because there is no form submit, a person then has to click on it twice.
|
|
//Options are to use .click() or dispatch an event
|
|
if (desiredVal != inputChild.checked) {
|
|
inputChild.dispatchEvent(new Event("change")); //using change event instead of click, in case browser ad-blockers blocks the click method
|
|
}
|
|
}
|
|
eventHandler(checkbox) {
|
|
checkbox.dispatchEvent(new Event("change"));
|
|
}
|
|
}
|
|
class RadioComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.children = new Map();
|
|
Array.from(this.element.querySelectorAll("input")).forEach(input => this.children.set(input.value, input));
|
|
}
|
|
getVal() {
|
|
//radio groups have a single element that's checked is true
|
|
// as array arr k,v pair element.checked ) -> array of len(1) with [k,v] so either [0] [1].value
|
|
return [...this.children].filter(([l, e]) => e.checked)[0][0];
|
|
//return Array.from(this.children).filter( ([label, input]) => input.checked)[0][1].value
|
|
}
|
|
updateVal(child) {
|
|
this.eventHandler(child);
|
|
}
|
|
setVal(name) {
|
|
//radio will trigger all false except the one that get the event change
|
|
//to keep the api similar, other methods are still called
|
|
this.updateVal(this.children.get(name));
|
|
}
|
|
eventHandler(child) {
|
|
child.dispatchEvent(new Event("change"));
|
|
}
|
|
}
|
|
class NumberComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.childNumField = element.querySelector('input[type=number]');
|
|
}
|
|
getVal() {
|
|
return this.childNumField.value;
|
|
}
|
|
updateVal(text) {
|
|
this.childNumField.value = text;
|
|
}
|
|
eventHandler() {
|
|
this.element.dispatchEvent(new Event("input"));
|
|
}
|
|
setVal(text) {
|
|
this.updateVal(text);
|
|
this.eventHandler();
|
|
}
|
|
}
|
|
class SliderComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.childNumField = this.element.querySelector('input[type=number]');
|
|
this.childRangeField = this.element.querySelector('input[type=range]');
|
|
}
|
|
getVal() {
|
|
return this.childNumField.value;
|
|
}
|
|
updateVal(text) {
|
|
//both are not needed, either works, both are left in so one is a fallback in case of gradio changes
|
|
this.childNumField.value = text;
|
|
this.childRangeField.value = text;
|
|
}
|
|
eventHandler() {
|
|
this.element.dispatchEvent(new Event("input"));
|
|
this.childNumField.dispatchEvent(new Event("input"));
|
|
this.childRangeField.dispatchEvent(new Event("input"));
|
|
}
|
|
setVal(text) {
|
|
this.updateVal(text);
|
|
this.eventHandler();
|
|
}
|
|
}
|
|
class TextComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.child = element.querySelector('textarea');
|
|
}
|
|
getVal() {
|
|
return this.child.value;
|
|
}
|
|
eventHandler() {
|
|
this.element.dispatchEvent(new Event("input"));
|
|
this.child.dispatchEvent(new Event("change"));
|
|
//Workaround to solve no target with v(o) on eventhandler, define my own target
|
|
let ne = new Event("input");
|
|
Object.defineProperty(ne, "target", { value: this.child });
|
|
this.child.dispatchEvent(ne);
|
|
}
|
|
updateVal(text) {
|
|
this.child.value = text;
|
|
}
|
|
appendValue(text) {
|
|
//might add delimiter option
|
|
this.child.value += ` ${text}`;
|
|
}
|
|
setVal(text, append = false) {
|
|
if (append) {
|
|
this.appendValue(text);
|
|
}
|
|
else {
|
|
this.updateVal(text);
|
|
}
|
|
this.eventHandler();
|
|
}
|
|
}
|
|
class JsonComponentController extends TextComponentController {
|
|
constructor(element) {
|
|
super(element);
|
|
}
|
|
getVal() {
|
|
return JSON.parse(this.child.value);
|
|
}
|
|
}
|
|
class ColorComponentController {
|
|
constructor(element) {
|
|
this.element = element;
|
|
this.child = this.element.querySelector('input[type=color]');
|
|
}
|
|
updateVal(text) {
|
|
this.child.value = text;
|
|
}
|
|
getVal() {
|
|
return this.child.value;
|
|
}
|
|
setVal(text) {
|
|
this.updateVal(text);
|
|
this.eventHandler();
|
|
}
|
|
eventHandler() {
|
|
this.child.dispatchEvent(new Event("input"));
|
|
}
|
|
}
|