// Utility functions to select text areas the script should work on, // including third party options. TAC.TextAreas = new (function () { // Core text area selectors const core = [ "#txt2img_prompt > label > textarea", "#img2img_prompt > label > textarea", "#txt2img_neg_prompt > label > textarea", "#img2img_neg_prompt > label > textarea", ".prompt > label > textarea", "#txt2img_edit_style_prompt > label > textarea", "#txt2img_edit_style_neg_prompt > label > textarea", "#img2img_edit_style_prompt > label > textarea", "#img2img_edit_style_neg_prompt > label > textarea", ]; // Third party text area selectors const thirdParty = { "dataset-tag-editor": { base: "#tab_dataset_tag_editor_interface", hasIds: false, selectors: [ "Caption of Selected Image", "Interrogate Result", "Edit Caption", "Edit Tags", ], }, "image browser": { base: "#tab_image_browser", hasIds: false, selectors: ["Filename keyword search", "EXIF keyword search"], }, tab_tagger: { base: "#tab_tagger", hasIds: false, selectors: ["Additional tags (split by comma)", "Exclude tags (split by comma)"], }, "tiled-diffusion-t2i": { base: "#txt2img_script_container", hasIds: true, onDemand: true, selectors: [ "[id^=MD-t2i][id$=prompt] textarea", "[id^=MD-t2i][id$=prompt] input[type='text']", ], }, "tiled-diffusion-i2i": { base: "#img2img_script_container", hasIds: true, onDemand: true, selectors: [ "[id^=MD-i2i][id$=prompt] textarea", "[id^=MD-i2i][id$=prompt] input[type='text']", ], }, "adetailer-t2i": { base: "#txt2img_script_container", hasIds: true, onDemand: true, selectors: [ "[id^=script_txt2img_adetailer_ad_prompt] textarea", "[id^=script_txt2img_adetailer_ad_negative_prompt] textarea", ], }, "adetailer-i2i": { base: "#img2img_script_container", hasIds: true, onDemand: true, selectors: [ "[id^=script_img2img_adetailer_ad_prompt] textarea", "[id^=script_img2img_adetailer_ad_negative_prompt] textarea", ], }, "deepdanbooru-object-recognition": { base: "#tab_deepdanboru_object_recg_tab", hasIds: false, selectors: ["Found tags"], }, TIPO: { base: "#tab_txt2img", hasIds: false, selectors: ["Tag Prompt"], }, }; this.getTextAreas = function () { // First get all core text areas let textAreas = [...gradioApp().querySelectorAll(core.join(", "))]; for (const [key, entry] of Object.entries(thirdParty)) { if (entry.hasIds) { // If the entry has proper ids, we can just select them textAreas = textAreas.concat([ ...gradioApp().querySelectorAll(entry.selectors.join(", ")), ]); } else { // Otherwise, we have to find the text areas by their adjacent labels let base = gradioApp().querySelector(entry.base); // Safety check if (!base) continue; let allTextAreas = [...base.querySelectorAll("textarea, input[type='text']")]; // Filter the text areas where the adjacent label matches one of the selectors let matchingTextAreas = allTextAreas.filter((ta) => [...ta.parentElement.childNodes].some((x) => entry.selectors.includes(x.innerText) ) ); textAreas = textAreas.concat(matchingTextAreas); } } return textAreas; } this.addOnDemandObservers = function (setupFunction) { for (const [key, entry] of Object.entries(thirdParty)) { if (!entry.onDemand) continue; let base = gradioApp().querySelector(entry.base); if (!base) continue; let accordions = [...base?.querySelectorAll(".gradio-accordion")]; if (!accordions) continue; accordions.forEach((acc) => { let accObserver = new MutationObserver((mutationList, observer) => { for (const mutation of mutationList) { if (mutation.type === "childList") { let newChildren = mutation.addedNodes; if (!newChildren) { accObserver.disconnect(); continue; } newChildren.forEach((child) => { if ( child.classList.contains("gradio-accordion") || child.querySelector(".gradio-accordion") ) { let newAccordions = [ ...child.querySelectorAll(".gradio-accordion"), ]; newAccordions.forEach((nAcc) => accObserver.observe(nAcc, { childList: true }) ); } }); if (entry.hasIds) { // If the entry has proper ids, we can just select them [ ...gradioApp().querySelectorAll(entry.selectors.join(", ")), ].forEach((x) => setupFunction(x)); } else { // Otherwise, we have to find the text areas by their adjacent labels let base = gradioApp().querySelector(entry.base); // Safety check if (!base) continue; let allTextAreas = [ ...base.querySelectorAll("textarea, input[type='text']"), ]; // Filter the text areas where the adjacent label matches one of the selectors let matchingTextAreas = allTextAreas.filter((ta) => [...ta.parentElement.childNodes].some((x) => entry.selectors.includes(x.innerText) ) ); matchingTextAreas.forEach((x) => setupFunction(x)); } } } }); accObserver.observe(acc, { childList: true }); }); } } const thirdPartyIdSet = new Set(); // Get the identifier for the text area to differentiate between positive and negative this.getTextAreaIdentifier = function (textArea) { let txt2img_p = gradioApp().querySelector("#txt2img_prompt > label > textarea"); let txt2img_n = gradioApp().querySelector("#txt2img_neg_prompt > label > textarea"); let img2img_p = gradioApp().querySelector("#img2img_prompt > label > textarea"); let img2img_n = gradioApp().querySelector("#img2img_neg_prompt > label > textarea"); let modifier = ""; switch (textArea) { case txt2img_p: modifier = ".txt2img.p"; break; case txt2img_n: modifier = ".txt2img.n"; break; case img2img_p: modifier = ".img2img.p"; break; case img2img_n: modifier = ".img2img.n"; break; default: // If the text area is not a core text area, it must be a third party text area // Add it to the set of third party text areas and get its index as a unique identifier if (!thirdPartyIdSet.has(textArea)) thirdPartyIdSet.add(textArea); modifier = `.thirdParty.ta${[...thirdPartyIdSet].indexOf(textArea)}`; break; } return modifier; } })();