242 lines
5.6 KiB
JavaScript
242 lines
5.6 KiB
JavaScript
// Dynamic form generator for editing model (LoRA/embedding) metadata in the Image Drawer.
|
|
// Renders form fields from FormObject definitions and submits changes via the /jnodes_edit_model_info API.
|
|
|
|
import { $el } from "/scripts/ui.js";
|
|
|
|
import { utilitiesInstance } from "../common/Utilities.js";
|
|
|
|
export class FormObject {
|
|
|
|
constructor(
|
|
name,
|
|
type,
|
|
defaultValue,
|
|
displayName = "",
|
|
tooltipText = "",
|
|
options = {},
|
|
onClickResetToDefault = undefined,
|
|
customWidget = undefined
|
|
) {
|
|
|
|
this._name = name;
|
|
this._displayName = displayName;
|
|
this._type = type;
|
|
this._defaultValue = defaultValue;
|
|
this._tooltipText = tooltipText;
|
|
this._options = options;
|
|
this._onClickResetToDefault = onClickResetToDefault;
|
|
this._customWidget = customWidget;
|
|
}
|
|
}
|
|
|
|
export class FormInfo {
|
|
|
|
constructor() {
|
|
|
|
this.itemToEdit;
|
|
this.buttonText;
|
|
this.onButtonClickFunction;
|
|
}
|
|
}
|
|
|
|
export class ModelEditForm {
|
|
|
|
constructor(imageDrawerInstance) {
|
|
|
|
this.imageDrawerInstance = imageDrawerInstance;
|
|
|
|
this._form;
|
|
this._formContainer;
|
|
}
|
|
|
|
_getFormResponse(){
|
|
|
|
let json = {};
|
|
|
|
if (this._form) {
|
|
|
|
for(const row of this._form.childNodes) {
|
|
|
|
const label = row.childNodes[0].childNodes[0];
|
|
let widget = row.childNodes[1].childNodes[0];
|
|
|
|
if (widget && widget.id == "inputContainer") {
|
|
widget = widget.childNodes[0];
|
|
}
|
|
|
|
if (label && widget) {
|
|
|
|
let widgetValue = undefined;
|
|
|
|
if (widget.getValue != undefined) {
|
|
|
|
widgetValue = widget.getValue();
|
|
|
|
} else if (widget.type == "checkbox") {
|
|
|
|
widgetValue = widget.checked;
|
|
|
|
} else if (widget.value != undefined) {
|
|
|
|
widgetValue = widget.value;
|
|
}
|
|
|
|
if (widgetValue != undefined) {
|
|
json[label.htmlFor] = widgetValue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return JSON.stringify(json);
|
|
}
|
|
|
|
focusFirstTextElement() {
|
|
|
|
const textInput = this._formContainer.querySelector('input[type="text"]');
|
|
if (textInput) {
|
|
textInput.focus();
|
|
}
|
|
}
|
|
|
|
createForm(formObjects, formInfo) {
|
|
|
|
// Create the form element
|
|
this._formContainer = $el('div',
|
|
{
|
|
style: {
|
|
|
|
backgroundColor: "rgba(0,0,0,1)",
|
|
padding: "0% 25px",
|
|
borderStyle: "double",
|
|
border: "deepskyblue",
|
|
borderCollapse: "separate",
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center"
|
|
}
|
|
}
|
|
);
|
|
|
|
const headerText = $el("h2", {
|
|
|
|
textContent: `Editing${formInfo?.itemToEdit ? ' ' + formInfo.itemToEdit : ''}`,
|
|
});
|
|
this._formContainer.appendChild(headerText);
|
|
|
|
this._form = $el("div");
|
|
this._formContainer.appendChild(this._form);
|
|
|
|
// Loop through each FormObject and create inputs
|
|
formObjects.forEach((formObject) => {
|
|
// Create a label for the input
|
|
const label = $el('label', { style: { padding: "0px 25px 0px 0px" } });
|
|
label.setAttribute('for', formObject._name);
|
|
label.textContent =
|
|
formObject._displayName ? formObject._displayName :
|
|
utilitiesInstance.convertToTitleCase(formObject._name);
|
|
|
|
// Create the input element
|
|
let input;
|
|
if (formObject._customWidget) {
|
|
// If a custom widget is provided, use it
|
|
input = formObject._customWidget;
|
|
} else {
|
|
// Create a standard input element based on the type
|
|
input = $el('input');
|
|
input.setAttribute('type', formObject._type);
|
|
|
|
if (formObject._type == "checkbox") {
|
|
input.checked = formObject._defaultValue;
|
|
} else {
|
|
input.setAttribute('value', formObject._defaultValue);
|
|
}
|
|
|
|
if (formObject._type == "text") {
|
|
input.style.width = "25vw";
|
|
}
|
|
}
|
|
|
|
// Set the name and ID for the input
|
|
input.setAttribute('name', formObject._name);
|
|
input.setAttribute('id', formObject._name);
|
|
|
|
if (formObject._options) {
|
|
|
|
for (const key in formObject._options) {
|
|
|
|
input.setAttribute(key, formObject._options[key]);
|
|
}
|
|
}
|
|
|
|
let finalInputWidget = input;
|
|
if (formObject._onClickResetToDefault) {
|
|
|
|
const inputContainer = $el("div", {
|
|
id: "inputContainer",
|
|
style: {
|
|
display: "flex"
|
|
}
|
|
});
|
|
inputContainer.style.width = input.style.width;
|
|
input.style.width = "inherit";
|
|
const button = $el("button", {
|
|
onclick: () => { formObject._onClickResetToDefault(input); },
|
|
textContent: "↩️",
|
|
title: "Reset to default",
|
|
style: {
|
|
border: "none",
|
|
background: "transparent",
|
|
cursor: "pointer",
|
|
fontSize: "1rem",
|
|
padding: "2px",
|
|
}
|
|
});
|
|
inputContainer.appendChild(input);
|
|
inputContainer.appendChild(button);
|
|
|
|
finalInputWidget = inputContainer;
|
|
}
|
|
|
|
// Append the label and input to the form
|
|
let row = $el("tr",
|
|
{
|
|
style: {
|
|
verticalAlign: "middle",
|
|
}
|
|
},
|
|
[
|
|
$el("td", { style:{ textAlign: "left" } }, [label]),
|
|
$el("td", { style:{ textAlign: "right" } }, [finalInputWidget])
|
|
]
|
|
);
|
|
if (formObject._tooltipText) { row.title = formObject._tooltipText; }
|
|
this._form.appendChild(row);
|
|
|
|
if (this._form.childNodes.length % 2 == 0) {
|
|
row.style.background = "rgba(255,255,255,0.1)"
|
|
}
|
|
});
|
|
|
|
// Add a submit button to the form
|
|
if (formInfo.buttonText && formInfo.onButtonClickFunction) {
|
|
const button = $el('button', { style: { margin: "5%" } });
|
|
button.classList.add("JNodes-interactive-container");
|
|
button.textContent = formInfo.buttonText;
|
|
button.addEventListener('click',
|
|
async () => { formInfo.onButtonClickFunction(this._getFormResponse()); });
|
|
this._formContainer.appendChild(button);
|
|
|
|
this._formContainer.addEventListener("keydown", (event) => {
|
|
|
|
if (event.key == "Enter") {
|
|
|
|
event.preventDefault();
|
|
button.click();
|
|
}
|
|
});
|
|
}
|
|
|
|
return this._formContainer;
|
|
}
|
|
} |