diff --git a/javascript/_textAreas.js b/javascript/_textAreas.js new file mode 100644 index 0000000..af1b5c1 --- /dev/null +++ b/javascript/_textAreas.js @@ -0,0 +1,80 @@ +// Utility functions to select text areas the script should work on, +// including third party options. +// Supported third party options so far: +// - Dataset Tag Editor + +// Core text area selectors +const core = [ + "#txt2img_prompt > label > textarea", + "#img2img_prompt > label > textarea", + "#txt2img_neg_prompt > label > textarea", + "#img2img_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" + ] + } +} + +function getTextAreas() { + // 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); + let allTextAreas = [...base.querySelectorAll("textarea")]; + + // 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; +} + +const thirdPartyIdSet = new Set(); +// Get the identifier for the text area to differentiate between positive and negative +function getTextAreaIdentifier(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; +} \ No newline at end of file diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 8376424..0b8ca6e 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -205,7 +205,8 @@ async function syncOptions() { global: opts["tac_active"], txt2img: opts["tac_activeIn.txt2img"], img2img: opts["tac_activeIn.img2img"], - negativePrompts: opts["tac_activeIn.negativePrompts"] + negativePrompts: opts["tac_activeIn.negativePrompts"], + thirdParty: opts["tac_activeIn.thirdParty"] }, // Results related settings maxResults: opts["tac_maxResults"], @@ -293,33 +294,6 @@ function difference(a, b) { )].reduce((acc, [v, count]) => acc.concat(Array(Math.abs(count)).fill(v)), []); } -// Get the identifier for the text area to differentiate between positive and negative -function getTextAreaIdentifier(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: - break; - } - return modifier; -} - // Create the result list div and necessary styling function createResultsDiv(textArea) { let resultsDiv = document.createElement("div"); @@ -860,11 +834,7 @@ async function setup() { } // Find all textareas - let txt2imgTextArea = gradioApp().querySelector('#txt2img_prompt > label > textarea'); - let img2imgTextArea = gradioApp().querySelector('#img2img_prompt > label > textarea'); - let txt2imgTextArea_n = gradioApp().querySelector('#txt2img_neg_prompt > label > textarea'); - let img2imgTextArea_n = gradioApp().querySelector('#img2img_neg_prompt > label > textarea'); - let textAreas = [txt2imgTextArea, img2imgTextArea, txt2imgTextArea_n, img2imgTextArea_n]; + let textAreas = getTextAreas(); // Add event listener to apply settings button so we can mirror the changes to our internal config let applySettingsButton = gradioApp().querySelector("#tab_settings > div > .gr-button-primary"); @@ -901,7 +871,8 @@ async function setup() { let textAreaId = getTextAreaIdentifier(area); if ((!CFG.activeIn.img2img && textAreaId.includes("img2img")) || (!CFG.activeIn.txt2img && textAreaId.includes("txt2img")) - || (!CFG.activeIn.negativePrompts && textAreaId.includes("n"))) { + || (!CFG.activeIn.negativePrompts && textAreaId.includes("n")) + || (!CFG.activeIn.thirdParty && textAreaId.includes("thirdParty"))) { return; } diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 39acbad..5682ecb 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -127,6 +127,7 @@ def on_ui_settings(): shared.opts.add_option("tac_activeIn.txt2img", shared.OptionInfo(True, "Active in txt2img (Requires restart)", section=TAC_SECTION)) shared.opts.add_option("tac_activeIn.img2img", shared.OptionInfo(True, "Active in img2img (Requires restart)", section=TAC_SECTION)) shared.opts.add_option("tac_activeIn.negativePrompts", shared.OptionInfo(True, "Active in negative prompts (Requires restart)", section=TAC_SECTION)) + shared.opts.add_option("tac_activeIn.thirdParty", shared.OptionInfo(True, "Active in third party textboxes [Dataset Tag Editor] (Requires restart)", section=TAC_SECTION)) # Results related settings shared.opts.add_option("tac_maxResults", shared.OptionInfo(5, "Maximum results", section=TAC_SECTION)) shared.opts.add_option("tac_showAllResults", shared.OptionInfo(False, "Show all results", section=TAC_SECTION))