File size: 6,196 Bytes
b5ba7a5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 * Display the currently active img2img tab's input image as an uninteractable
 * background image behind ControlNet's image input. This change will hint user
 * that if no ControlNet input image is uploaded, by default ControlNet will
 * fallback onto img2img input image.
 */
(function () {
    function getActiveImg2ImgTabImgSrc(img2imgTabs) {
        const tabs = img2imgTabs.querySelectorAll('.tabitem');
        const activeTabs = [...tabs].filter(tab => tab.style.display !== 'none');
        if (!activeTabs) return;
        const image = activeTabs[0].querySelector('.image-container img')
        return image ? image.src : undefined;
    }

    function updateControlNetInputFallbackPreview(cnetInputContainers, imgDataURL) {
        for (const container of cnetInputContainers) {
            const badge = container.querySelector('.cnet-badge');
            if (badge) badge.remove();

            if (imgDataURL) {
                // Do not add fallback image if controlnet input already exists.
                if (container.querySelector('img'))
                    continue;

                // Set the background image
                container.style.backgroundImage = `url('${imgDataURL}')`;

                // Set other background properties
                container.style.backgroundPosition = 'center';
                container.style.backgroundRepeat = 'no-repeat';
                container.style.backgroundSize = 'contain';
                container.title = "Img2Img input will be used if no ControlNet input is specified.";

                const div = document.createElement('div');
                div.classList.add('cnet-badge', 'primary', 'cnet-a1111-badge');
                div.innerHTML = 'A1111';
                container.appendChild(div);
            } else {
                container.style.backgroundImage = 'none';
            }
        }
    }

    const ImgChangeType = {
        NO_CHANGE: 0,
        REMOVE: 1,
        ADD: 2,
        SRC_CHANGE: 3,
    };

    function imgChangeObserved(mutationsList) {
        // Iterate over all mutations that just occured
        for (let mutation of mutationsList) {
            // Check if the mutation is an addition or removal of a node
            if (mutation.type === 'childList') {
                // Check if nodes were added
                if (mutation.addedNodes.length > 0) {
                    for (const node of mutation.addedNodes) {
                        if (node.tagName === 'IMG') {
                            return ImgChangeType.ADD;
                        }
                    }
                }

                // Check if nodes were removed
                if (mutation.removedNodes.length > 0) {
                    for (const node of mutation.removedNodes) {
                        if (node.tagName === 'IMG') {
                            return ImgChangeType.REMOVE;
                        }
                    }
                }
            }
            // Check if the mutation is a change of an attribute
            else if (mutation.type === 'attributes') {
                if (mutation.target.tagName === 'IMG' && mutation.attributeName === 'src') {
                    return ImgChangeType.SRC_CHANGE;
                }
            }
        }
        return ImgChangeType.NO_CHANGE;
    }

    let callback_registered = false;
    onUiUpdate(() => {
        if (callback_registered) return;

        const cnetInputContainers = gradioApp().querySelectorAll(
            "#img2img_controlnet_tabs .cnet-input-image-group .cnet-image");
        if (!cnetInputContainers) return;

        const img2imgTabs = gradioApp().querySelector("#mode_img2img");
        if (!img2imgTabs) return;

        // Every time img2img input updates, update fallback preview.
        const img2imgContainers = img2imgTabs.querySelectorAll('.tabitem .image-container');
        for (const container of img2imgContainers) {
            new MutationObserver((mutationsList) => {
                if (imgChangeObserved(mutationsList) !== ImgChangeType.NO_CHANGE) {
                    updateControlNetInputFallbackPreview(
                        cnetInputContainers,
                        getActiveImg2ImgTabImgSrc(img2imgTabs)
                    );
                    return;
                }
            }).observe(container, {
                childList: true,
                attributes: true,
                attributeFilter: ['src'],
                subtree: true,
            });
        }

        // Every time controlnet input updates, update fallback preview.
        for (const container of cnetInputContainers) {
            new MutationObserver((mutationsList) => {
                const changeObserved = imgChangeObserved(mutationsList);
                if (changeObserved === ImgChangeType.REMOVE) {
                    updateControlNetInputFallbackPreview(
                        [container],
                        getActiveImg2ImgTabImgSrc(img2imgTabs)
                    );
                    return;
                }
                if (changeObserved === ImgChangeType.ADD ||
                    changeObserved === ImgChangeType.SRC_CHANGE) {
                    updateControlNetInputFallbackPreview(
                        [container],
                        undefined
                    );
                    return;
                }
            }).observe(container, {
                childList: true,
                attributes: true,
                attributeFilter: ['src'],
                subtree: true,
            });
        }

        // Every time the img2img tab is switched, update fallback preview.
        new MutationObserver((mutationsList) => {
            for (const mutation of mutationsList) {
                if (mutation.type === 'childList') {
                    updateControlNetInputFallbackPreview(
                        cnetInputContainers,
                        getActiveImg2ImgTabImgSrc(img2imgTabs)
                    );
                    return;
                }
            }
        }).observe(img2imgTabs.querySelector('.tab-nav'), { childList: true });

        callback_registered = true;
    });
})();