File size: 4,637 Bytes
1e3b872
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { app } from "../../../scripts/app.js";
import { addMenuHandler } from "./common/utils.js";
import { findWidgetByName } from "./common/utils.js";

function replaceNode(oldNode, newNodeName) {
    const newNode = LiteGraph.createNode(newNodeName);
    if (!newNode) {
        return;
    }
    app.graph.add(newNode);

    newNode.pos = oldNode.pos.slice();
    newNode.size = oldNode.size.slice();

    // Transfer widget values
    const widgetMapping = {
        "ckpt_name": "base_ckpt_name",
        "vae_name": "vae_name",
        "clip_skip": "base_clip_skip",
        "positive": "positive",
        "negative": "negative",
        "prompt_style": "prompt_style",
        "empty_latent_width": "empty_latent_width",
        "empty_latent_height": "empty_latent_height",
        "batch_size": "batch_size"
    };

    let effectiveWidgetMapping = widgetMapping;

    // Invert the mapping when going from "Eff. Loader SDXL" to "Efficient Loader"
    if (oldNode.type === "Eff. Loader SDXL" && newNodeName === "Efficient Loader") {
        effectiveWidgetMapping = {};
        for (const [key, value] of Object.entries(widgetMapping)) {
            effectiveWidgetMapping[value] = key;
        }
    }

    oldNode.widgets.forEach(widget => {
        const newName = effectiveWidgetMapping[widget.name];
        if (newName) {
            const newWidget = findWidgetByName(newNode, newName);
            if (newWidget) {
                newWidget.value = widget.value;
            }
        }
    });

    // Hardcoded transfer for specific outputs based on the output names from the nodes in the image
    const outputMapping = {
        "MODEL": null,           // Not present in "Eff. Loader SDXL"
        "CONDITIONING+": null,   // Not present in "Eff. Loader SDXL"
        "CONDITIONING-": null,   // Not present in "Eff. Loader SDXL"
        "LATENT": "LATENT",
        "VAE": "VAE",
        "CLIP": null,            // Not present in "Eff. Loader SDXL"
        "DEPENDENCIES": "DEPENDENCIES"
    };

    // Transfer connections from old node outputs to new node outputs based on the outputMapping
    oldNode.outputs.forEach((output, index) => {
        if (output && output.links && outputMapping[output.name]) {
            const newOutputName = outputMapping[output.name];
            
            // If the new node does not have this output, skip
            if (newOutputName === null) {
                return;
            }
            
            const newOutputIndex = newNode.findOutputSlot(newOutputName);
            if (newOutputIndex !== -1) {
                output.links.forEach(link => {
                    const targetLinkInfo = oldNode.graph.links[link];
                    if (targetLinkInfo) {
                        const targetNode = oldNode.graph.getNodeById(targetLinkInfo.target_id);
                        if (targetNode) {
                            newNode.connect(newOutputIndex, targetNode, targetLinkInfo.target_slot);
                        }
                    }
                });
            }
        }
    });

    // Remove old node
    app.graph.remove(oldNode);
}

function replaceNodeMenuCallback(currentNode, targetNodeName) {
    return function() {
        replaceNode(currentNode, targetNodeName);
    };
}

function showSwapMenu(value, options, e, menu, node) {
    const swapOptions = [];

    if (node.type !== "Efficient Loader") {
        swapOptions.push({
            content: "Efficient Loader",
            callback: replaceNodeMenuCallback(node, "Efficient Loader")
        });
    }

    if (node.type !== "Eff. Loader SDXL") {
        swapOptions.push({
            content: "Eff. Loader SDXL",
            callback: replaceNodeMenuCallback(node, "Eff. Loader SDXL")
        });
    }

    new LiteGraph.ContextMenu(swapOptions, {
        event: e,
        callback: null,
        parentMenu: menu,
        node: node
    });

    return false;  // This ensures the original context menu doesn't proceed
}

// Extension Definition
app.registerExtension({
    name: "efficiency.SwapLoaders",
    async beforeRegisterNodeDef(nodeType, nodeData, app) {
        if (["Efficient Loader", "Eff. Loader SDXL"].includes(nodeData.name)) {
            addMenuHandler(nodeType, function (insertOption) {
                insertOption({
                    content: "🔄 Swap with...",
                    has_submenu: true,
                    callback: showSwapMenu
                });
            });
        }
    },
});