File size: 4,296 Bytes
9855482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 * Give a badge on ControlNet Accordion indicating total number of active 
 * units.
 * Make active unit's tab name green.
 */
const cnetAllUnits = new Map/* <Element, GradioTab> */();
const cnetAllAccordions = new Set();
onUiUpdate(() => {
    function childIndex(element) {
        // Get all child nodes of the parent
        let children = Array.from(element.parentNode.childNodes);

        // Filter out non-element nodes (like text nodes and comments)
        children = children.filter(child => child.nodeType === Node.ELEMENT_NODE);

        return children.indexOf(element);
    }

    class GradioTab {
        constructor(tab) {
            this.enabledCheckbox = tab.querySelector('.cnet-unit-enabled input');
            this.inputImage = tab.querySelector('.cnet-input-image-group .cnet-image input[type="file"]');
            const tabs = tab.parentNode;
            this.tabNav = tabs.querySelector('.tab-nav');
            this.tabIndex = childIndex(tab) - 1; // -1 because tab-nav is also at the same level.            

            this.attachEnabledButtonListener();
            this.attachTabNavChangeObserver();
            this.attachImageUploadListener();
        }

        getTabNavButton() {
            return this.tabNav.querySelector(`:nth-child(${this.tabIndex + 1})`);
        }

        applyActiveState() {
            const tabNavButton = this.getTabNavButton();
            if (!tabNavButton) return;

            if (this.enabledCheckbox.checked) {
                tabNavButton.classList.add('cnet-unit-active');
            } else {
                tabNavButton.classList.remove('cnet-unit-active');
            }
        }

        attachEnabledButtonListener() {
            this.enabledCheckbox.addEventListener('change', () => {
                this.applyActiveState();
            });
        }

        /**
         * Each time the active tab change, all tab nav buttons are cleared and
         * regenerated by gradio. So we need to reapply the active states on 
         * them.
         */
        attachTabNavChangeObserver() {
            const observer = new MutationObserver((mutationsList, observer) => {
                for (const mutation of mutationsList) {
                    if (mutation.type === 'childList') {
                        this.applyActiveState();
                    }
                }
            });
            observer.observe(this.tabNav, { childList: true });
        }

        attachImageUploadListener() {
            this.inputImage.addEventListener('change', (event) => {
                if (!event.target.files) return;
                if (!this.enabledCheckbox.checked)
                    this.enabledCheckbox.click();
            });
        }
    }

    gradioApp().querySelectorAll('.cnet-unit-tab').forEach(tab => {
        if (cnetAllUnits.has(tab)) return;
        cnetAllUnits.set(tab, new GradioTab(tab));
    });

    function getActiveUnitCount(checkboxes) {
        let activeUnitCount = 0;
        for (const checkbox of checkboxes) {
            if (checkbox.checked)
                activeUnitCount++;
        }
        return activeUnitCount;
    }

    gradioApp().querySelectorAll('#controlnet').forEach(accordion => {
        if (cnetAllAccordions.has(accordion)) return;
        const checkboxes = accordion.querySelectorAll('.cnet-unit-enabled input');
        if (!checkboxes) return;

        const span = accordion.querySelector('.label-wrap span');
        checkboxes.forEach(checkbox => {
            checkbox.addEventListener('change', () => {
                // Remove existing badge.
                if (span.childNodes.length !== 1) {
                    span.removeChild(span.lastChild);
                }
                // Add new badge if necessary.
                const activeUnitCount = getActiveUnitCount(checkboxes);
                if (activeUnitCount > 0) {
                    const div = document.createElement('div');
                    div.classList.add('cnet-badge');
                    div.classList.add('primary');
                    div.innerHTML = `${activeUnitCount} unit${activeUnitCount > 1 ? 's' : ''}`;
                    span.appendChild(div);
                }
            });
        });
        cnetAllAccordions.add(accordion);
    });
});