File size: 6,442 Bytes
34097e9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 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"
        ]
    },
    "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']"
        ]
    }
}

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);

            // 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;
}

function addOnDemandObservers(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
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;
}