/** * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. **/ RED.clipboard = (function() { var dialog; var dialogContainer; var exportNodesDialog; var importNodesDialog; var disabled = false; var popover; var currentPopoverError; var activeTab; var libraryBrowser; var examplesBrowser; var pendingImportConfig; function downloadData(file, data) { if (window.navigator.msSaveBlob) { // IE11 workaround // IE does not support data uri scheme for downloading data var blob = new Blob([data], { type: "data:text/plain;charset=utf-8" }); navigator.msSaveBlob(blob, file); } else { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(data)); element.setAttribute('download', file); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } } function setupDialogs() { dialog = $('
') .appendTo("#red-ui-editor") .dialog({ modal: true, autoOpen: false, width: 700, resizable: false, classes: { "ui-dialog": "red-ui-editor-dialog", "ui-dialog-titlebar-close": "hide", "ui-widget-overlay": "red-ui-editor-dialog" }, buttons: [ { // red-ui-clipboard-dialog-cancel id: "red-ui-clipboard-dialog-cancel", text: RED._("common.label.cancel"), click: function() { $( this ).dialog( "close" ); } }, { // red-ui-clipboard-dialog-download id: "red-ui-clipboard-dialog-download", class: "primary", text: RED._("clipboard.download"), click: function() { var data = $("#red-ui-clipboard-dialog-export-text").val(); downloadData("flows.json", data); $( this ).dialog( "close" ); } }, { // red-ui-clipboard-dialog-export id: "red-ui-clipboard-dialog-export", class: "primary", text: RED._("clipboard.export.copy"), click: function() { if (activeTab === "red-ui-clipboard-dialog-export-tab-clipboard") { copyText($("#red-ui-clipboard-dialog-export-text").val()); RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"}); $( this ).dialog( "close" ); } else { var flowToExport = $("#red-ui-clipboard-dialog-export-text").val(); var selectedPath = libraryBrowser.getSelected(); if (!selectedPath.children) { selectedPath = selectedPath.parent; } var filename = $("#red-ui-clipboard-dialog-tab-library-name").val().trim(); var saveFlow = function() { $.ajax({ url:'library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path + filename, type: "POST", data: flowToExport, contentType: "application/json; charset=utf-8" }).done(function() { $(dialog).dialog( "close" ); RED.notify(RED._("library.exportedToLibrary"),"success"); }).fail(function(xhr,textStatus,err) { if (xhr.status === 401) { RED.notify(RED._("library.saveFailed",{message:RED._("user.notAuthorized")}),"error"); } else { RED.notify(RED._("library.saveFailed",{message:xhr.responseText}),"error"); } }); } if (selectedPath.children) { var exists = false; selectedPath.children.forEach(function(f) { if (f.label === filename) { exists = true; } }); if (exists) { dialog.dialog("close"); var notification = RED.notify(RED._("clipboard.export.exists",{file:RED.utils.sanitize(filename)}),{ type: "warning", fixed: true, buttons: [{ text: RED._("common.label.cancel"), click: function() { notification.hideNotification() dialog.dialog( "open" ); } },{ text: RED._("clipboard.export.overwrite"), click: function() { notification.hideNotification() saveFlow(); } }] }); } else { saveFlow(); } } else { saveFlow(); } } } }, { // red-ui-clipboard-dialog-ok id: "red-ui-clipboard-dialog-ok", class: "primary", text: RED._("common.label.import"), click: function() { var addNewFlow = ($("#red-ui-clipboard-dialog-import-opt > a.selected").attr('id') === 'red-ui-clipboard-dialog-import-opt-new'); if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") { importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow); } else { var selectedPath; if (activeTab === "red-ui-clipboard-dialog-import-tab-library") { selectedPath = libraryBrowser.getSelected(); } else { selectedPath = examplesBrowser.getSelected(); } if (selectedPath.path) { $.get('library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path, function(data) { importNodes(data,addNewFlow); }); } } $( this ).dialog( "close" ); } }, { // red-ui-clipboard-dialog-import-conflict id: "red-ui-clipboard-dialog-import-conflict", class: "primary", text: RED._("clipboard.import.importSelected"), click: function() { var importMap = {}; $('#red-ui-clipboard-dialog-import-conflicts-list input[type="checkbox"]').each(function() { importMap[$(this).attr("data-node-id")] = this.checked?"import":"skip"; }) $('.red-ui-clipboard-dialog-import-conflicts-controls input[type="checkbox"]').each(function() { if (!$(this).attr("disabled")) { importMap[$(this).attr("data-node-id")] = this.checked?"replace":"copy" } }) // skip - don't import // import - import as-is // copy - import with new id // replace - import over the top of existing pendingImportConfig.importOptions.importMap = importMap; var newNodes = pendingImportConfig.importNodes.filter(function(n) { if (!importMap[n.id] || importMap[n.z]) { importMap[n.id] = importMap[n.z]; } return importMap[n.id] !== "skip" }) // console.table(pendingImportConfig.importNodes.map(function(n) { return {id:n.id,type:n.type,result:importMap[n.id]}})) RED.view.importNodes(newNodes, pendingImportConfig.importOptions); $( this ).dialog( "close" ); } } ], open: function( event, ui ) { RED.keyboard.disable(); }, close: function(e) { RED.keyboard.enable(); if (popover) { popover.close(true); currentPopoverError = null; } } }); dialogContainer = dialog.children(".dialog-form"); exportNodesDialog = '
'+ ''+ ''+ ''+ ''+ ''+ ''+ '
'+ '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
'+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ ''+ '
    '+ '
    '+ ''+ ''+ ''+ ''+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ ''+ '
    '+ '
    '+ '
    '+ '
    ' ; importNodesDialog = '
    '+ '
    '+ ''+ '
    '+ '
    '+ '
    '+ '
    '+ ' '+ ''+ '
    '+ '
    '+ ''+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ '
    '+ ''+ ''+ ''+ ''+ ''+ '
    '; importConflictsDialog = '
    '+ '

    '+ '
    '+ '
    '+ '
    '+ '
    '; } var validateExportFilenameTimeout function validateExportFilename() { if (validateExportFilenameTimeout) { clearTimeout(validateExportFilenameTimeout); } validateExportFilenameTimeout = setTimeout(function() { var filenameInput = $("#red-ui-clipboard-dialog-tab-library-name"); var filename = filenameInput.val().trim(); var valid = filename.length > 0 && !/[\/\\]/.test(filename); if (valid) { filenameInput.removeClass("input-error"); $("#red-ui-clipboard-dialog-export").button("enable"); } else { filenameInput.addClass("input-error"); $("#red-ui-clipboard-dialog-export").button("disable"); } },100); } var validateImportTimeout; function validateImport() { if (activeTab === "red-ui-clipboard-dialog-import-tab-clipboard") { if (validateImportTimeout) { clearTimeout(validateImportTimeout); } validateImportTimeout = setTimeout(function() { var importInput = $("#red-ui-clipboard-dialog-import-text"); var v = importInput.val().trim(); if (v === "") { popover.close(true); currentPopoverError = null; importInput.removeClass("input-error"); $("#red-ui-clipboard-dialog-ok").button("disable"); return; } try { if (!/^\[[\s\S]*\]$/m.test(v)) { throw new Error(RED._("clipboard.import.errors.notArray")); } var res = JSON.parse(v); for (var i=0;i').text(errString); var errorPos; // Chrome error messages var m = /at position (\d+)/i.exec(errString); if (m) { errorPos = parseInt(m[1]); } else { // Firefox error messages m = /at line (\d+) column (\d+)/i.exec(errString); if (m) { var line = parseInt(m[1])-1; var col = parseInt(m[2])-1; var lines = v.split("\n"); errorPos = 0; for (var i=0;i').appendTo(message); var code = $('
    ').appendTo(parseError);
                                    $('').text(v.substring(errorPos-12,errorPos)).appendTo(code)
                                    $('').text(v.charAt(errorPos)).appendTo(code);
                                    $('').text(v.substring(errorPos+1,errorPos+12)).appendTo(code);
                                }
                                popover.close(true).setContent(message).open();
                                currentPopoverError = errString;
                            }
                        } else {
                            currentPopoverError = null;
                        }
                        $("#red-ui-clipboard-dialog-ok").button("disable");
                    }
                },100);
            } else {
                var file = libraryBrowser.getSelected();
                if (file && file.label && !file.children) {
                    $("#red-ui-clipboard-dialog-ok").button("enable");
                } else {
                    $("#red-ui-clipboard-dialog-ok").button("disable");
                }
            }
        }
    
        function showImportNodes(mode) {
            if (disabled) {
                return;
            }
            mode = mode || "clipboard";
    
            dialogContainer.empty();
            dialogContainer.append($(importNodesDialog));
    
            var tabs = RED.tabs.create({
                id: "red-ui-clipboard-dialog-import-tabs",
                vertical: true,
                onchange: function(tab) {
                    $("#red-ui-clipboard-dialog-import-tabs-content").children().hide();
                    $("#" + tab.id).show();
                    activeTab = tab.id;
                    if (popover) {
                        popover.close(true);
                        currentPopoverError = null;
                    }
                    if (tab.id === "red-ui-clipboard-dialog-import-tab-clipboard") {
                        $("#red-ui-clipboard-dialog-import-text").trigger("focus");
                    } else {
                        libraryBrowser.focus();
                    }
                    validateImport();
                }
            });
            tabs.addTab({
                id: "red-ui-clipboard-dialog-import-tab-clipboard",
                label: RED._("clipboard.clipboard")
            });
            tabs.addTab({
                id: "red-ui-clipboard-dialog-import-tab-library",
                label: RED._("library.library")
            });
            tabs.addTab({
                id: "red-ui-clipboard-dialog-import-tab-examples",
                label: RED._("library.types.examples")
            });
    
            $("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
            $("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
            $("#red-ui-clipboard-dialog-export").button("enable");
    
            libraryBrowser = RED.library.createBrowser({
                container: $("#red-ui-clipboard-dialog-import-tab-library"),
                onselect: function(file) {
                    if (file && file.label && !file.children) {
                        $("#red-ui-clipboard-dialog-ok").button("enable");
                    } else {
                        $("#red-ui-clipboard-dialog-ok").button("disable");
                    }
                },
                onconfirm: function(item) {
                    if (item && item.label && !item.children) {
                        $("#red-ui-clipboard-dialog-ok").trigger("click");
                    }
                }
            })
            loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local"));
    
            examplesBrowser = RED.library.createBrowser({
                container: $("#red-ui-clipboard-dialog-import-tab-examples"),
                onselect: function(file) {
                    if (file && file.label && !file.children) {
                        $("#red-ui-clipboard-dialog-ok").button("enable");
                    } else {
                        $("#red-ui-clipboard-dialog-ok").button("disable");
                    }
                },
                onconfirm: function(item) {
                    if (item && item.label && !item.children) {
                        $("#red-ui-clipboard-dialog-ok").trigger("click");
                    }
                }
            })
            loadFlowLibrary(examplesBrowser,"_examples_",RED._("library.types.examples"));
    
    
            dialogContainer.i18n();
    
            $("#red-ui-clipboard-dialog-ok").show();
            $("#red-ui-clipboard-dialog-cancel").show();
            $("#red-ui-clipboard-dialog-export").hide();
            $("#red-ui-clipboard-dialog-download").hide();
            $("#red-ui-clipboard-dialog-import-conflict").hide();
    
            $("#red-ui-clipboard-dialog-ok").button("disable");
            $("#red-ui-clipboard-dialog-import-text").on("keyup", validateImport);
            $("#red-ui-clipboard-dialog-import-text").on('paste',function() { setTimeout(validateImport,10)});
    
            $("#red-ui-clipboard-dialog-import-opt > a").on("click", function(evt) {
                evt.preventDefault();
                if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
                    return;
                }
                $(this).parent().children().removeClass('selected');
                $(this).addClass('selected');
            });
    
            $("#red-ui-clipboard-dialog-import-file-upload").on("change", function() {
                var fileReader = new FileReader();
                fileReader.onload = function () {
                    $("#red-ui-clipboard-dialog-import-text").val(fileReader.result);
                    validateImport();
                };
                fileReader.readAsText($(this).prop('files')[0]);
            })
            $("#red-ui-clipboard-dialog-import-file-upload-btn").on("click", function(evt) {
                evt.preventDefault();
                $("#red-ui-clipboard-dialog-import-file-upload").trigger("click");
            })
    
            tabs.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
            if (mode === 'clipboard') {
                setTimeout(function() {
                    $("#red-ui-clipboard-dialog-import-text").trigger("focus");
                },100)
            }
    
            var dialogHeight = 400;
            var winHeight = $(window).height();
            if (winHeight < 600) {
                dialogHeight = 400 - (600 - winHeight);
            }
            $(".red-ui-clipboard-dialog-box").height(dialogHeight);
    
            dialog.dialog("option","title",RED._("clipboard.importNodes"))
                  .dialog("option","width",700)
                  .dialog("open");
            popover = RED.popover.create({
                target: $("#red-ui-clipboard-dialog-import-text"),
                trigger: "manual",
                direction: "bottom",
                content: ""
            });
        }
    
        function showExportNodes(mode) {
            if (disabled) {
                return;
            }
    
            mode = mode || "clipboard";
    
            dialogContainer.empty();
            dialogContainer.append($(exportNodesDialog));
    
            var tabs = RED.tabs.create({
                id: "red-ui-clipboard-dialog-export-tabs",
                vertical: true,
                onchange: function(tab) {
                    $("#red-ui-clipboard-dialog-export-tabs-content").children().hide();
                    $("#" + tab.id).show();
                    activeTab = tab.id;
                    if (tab.id === "red-ui-clipboard-dialog-export-tab-clipboard") {
                        $("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.copy"))
                        $("#red-ui-clipboard-dialog-download").show();
                    } else {
                        $("#red-ui-clipboard-dialog-export").button("option","label", RED._("clipboard.export.export"))
                        $("#red-ui-clipboard-dialog-download").hide();
                        libraryBrowser.focus();
                    }
    
                }
            });
            tabs.addTab({
                id: "red-ui-clipboard-dialog-export-tab-clipboard",
                label: RED._("clipboard.clipboard")
            });
            tabs.addTab({
                id: "red-ui-clipboard-dialog-export-tab-library",
                label: RED._("library.library")
            });
    
            $("#red-ui-clipboard-dialog-tab-library-name").on("keyup", validateExportFilename);
            $("#red-ui-clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)});
            $("#red-ui-clipboard-dialog-export").button("enable");
    
            libraryBrowser = RED.library.createBrowser({
                container: $("#red-ui-clipboard-dialog-export-tab-library-browser"),
                folderTools: true,
                onselect: function(file) {
                    if (file && file.label && !file.children) {
                        $("#red-ui-clipboard-dialog-tab-library-name").val(file.label);
                    }
                }
            })
            loadFlowLibrary(libraryBrowser,"local",RED._("library.types.local"));
    
            var clipboardTabs = RED.tabs.create({
                id: "red-ui-clipboard-dialog-export-tab-clipboard-tabs",
                onchange: function(tab) {
                    $(".red-ui-clipboard-dialog-export-tab-clipboard-tab").hide();
                    $("#" + tab.id).show();
                }
            });
    
            clipboardTabs.addTab({
                id: "red-ui-clipboard-dialog-export-tab-clipboard-preview",
                label: RED._("clipboard.exportNodes")
            });
    
            clipboardTabs.addTab({
                id: "red-ui-clipboard-dialog-export-tab-clipboard-json",
                label: RED._("editor.types.json")
            });
    
    
            var previewList = $("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({
                data: []
            })
            refreshExportPreview();
    
            $("#red-ui-clipboard-dialog-tab-library-name").val("flows.json").select();
    
            dialogContainer.i18n();
            var format = RED.settings.flowFilePretty ? "red-ui-clipboard-dialog-export-fmt-full" : "red-ui-clipboard-dialog-export-fmt-mini";
    
            $("#red-ui-clipboard-dialog-export-fmt-group > a").on("click", function(evt) {
                evt.preventDefault();
                if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
                    $("#red-ui-clipboard-dialog-export-text").trigger("focus");
                    return;
                }
                $(this).parent().children().removeClass('selected');
                $(this).addClass('selected');
    
                var flow = $("#red-ui-clipboard-dialog-export-text").val();
                if (flow.length > 0) {
                    var nodes = JSON.parse(flow);
    
                    format = $(this).attr('id');
                    if (format === 'red-ui-clipboard-dialog-export-fmt-full') {
                        flow = JSON.stringify(nodes,null,4);
                    } else {
                        flow = JSON.stringify(nodes);
                    }
                    $("#red-ui-clipboard-dialog-export-text").val(flow);
                    setTimeout(function() { $("#red-ui-clipboard-dialog-export-text").scrollTop(0); },50);
    
                    $("#red-ui-clipboard-dialog-export-text").trigger("focus");
                }
            });
    
            $("#red-ui-clipboard-dialog-export-rng-group > a").on("click", function(evt) {
                evt.preventDefault();
                if ($(this).hasClass('disabled') || $(this).hasClass('selected')) {
                    return;
                }
                $(this).parent().children().removeClass('selected');
                $(this).addClass('selected');
                var type = $(this).attr('id').substring("red-ui-clipboard-dialog-export-rng-".length);
                var flow = "";
                var nodes = null;
                if (type === 'selected') {
                    var selection = RED.workspaces.selection();
                    if (selection.length > 0) {
                        nodes = [];
                        selection.forEach(function(n) {
                            nodes.push(n);
                            nodes = nodes.concat(RED.nodes.groups(n.id));
                            nodes = nodes.concat(RED.nodes.filterNodes({z:n.id}));
                        });
                    } else {
                        nodes = RED.view.selection().nodes||[];
                    }
                    // Don't include the subflow meta-port nodes in the exported selection
                    nodes = RED.nodes.createExportableNodeSet(nodes.filter(function(n) { return n.type !== 'subflow'}));
                } else if (type === 'flow') {
                    var activeWorkspace = RED.workspaces.active();
                    nodes = RED.nodes.groups(activeWorkspace);
                    nodes = nodes.concat(RED.nodes.filterNodes({z:activeWorkspace}));
                    var parentNode = RED.nodes.workspace(activeWorkspace)||RED.nodes.subflow(activeWorkspace);
                    nodes.unshift(parentNode);
                    nodes = RED.nodes.createExportableNodeSet(nodes);
                } else if (type === 'full') {
                    nodes = RED.nodes.createCompleteNodeSet(false);
                }
                if (nodes !== null) {
                    if (format === "red-ui-clipboard-dialog-export-fmt-full") {
                        flow = JSON.stringify(nodes,null,4);
                    } else {
                        flow = JSON.stringify(nodes);
                    }
                }
                if (flow.length > 0) {
                    $("#red-ui-clipboard-dialog-export").removeClass('disabled');
                } else {
                    $("#red-ui-clipboard-dialog-export").addClass('disabled');
                }
                $("#red-ui-clipboard-dialog-export-text").val(flow);
                setTimeout(function() {
                    $("#red-ui-clipboard-dialog-export-text").scrollTop(0);
                    refreshExportPreview(type);
                },50);
            })
    
            $("#red-ui-clipboard-dialog-ok").hide();
            $("#red-ui-clipboard-dialog-cancel").hide();
            $("#red-ui-clipboard-dialog-export").hide();
            $("#red-ui-clipboard-dialog-import-conflict").hide();
    
            var selection = RED.workspaces.selection();
            if (selection.length > 0) {
                $("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
            } else {
                selection = RED.view.selection();
                if (selection.nodes) {
                    $("#red-ui-clipboard-dialog-export-rng-selected").trigger("click");
                } else {
                    $("#red-ui-clipboard-dialog-export-rng-selected").addClass('disabled').removeClass('selected');
                    $("#red-ui-clipboard-dialog-export-rng-flow").trigger("click");
                }
            }
            if (format === "red-ui-clipboard-dialog-export-fmt-full") {
                $("#red-ui-clipboard-dialog-export-fmt-full").trigger("click");
            } else {
                $("#red-ui-clipboard-dialog-export-fmt-mini").trigger("click");
            }
            tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);
    
            var dialogHeight = 400;
            var winHeight = $(window).height();
            if (winHeight < 600) {
                dialogHeight = 400 - (600 - winHeight);
            }
            $(".red-ui-clipboard-dialog-box").height(dialogHeight);
    
            dialog.dialog("option","title",RED._("clipboard.exportNodes"))
                  .dialog("option","width",700)
                  .dialog("open");
    
            $("#red-ui-clipboard-dialog-export-text").trigger("focus");
            $("#red-ui-clipboard-dialog-cancel").show();
            $("#red-ui-clipboard-dialog-export").show();
            $("#red-ui-clipboard-dialog-download").show();
            $("#red-ui-clipboard-dialog-import-conflict").hide();
    
        }
    
        function refreshExportPreview(type) {
    
            var flowData = $("#red-ui-clipboard-dialog-export-text").val() || "[]";
            var flow = JSON.parse(flowData);
            var flows = {};
            var subflows = {};
            var nodes = [];
            var nodesByZ = {};
    
            var treeFlows = [];
            var treeSubflows = [];
    
            flow.forEach(function(node) {
                if (node.type === "tab") {
                    flows[node.id] = {
                        element: getFlowLabel(node,false),
                        deferBuild: type !== "flow",
                        expanded: type === "flow",
                        children: []
                    };
                    treeFlows.push(flows[node.id])
                } else if (node.type === "subflow") {
                    subflows[node.id] = {
                        element: getNodeLabel(node,false),
                        deferBuild: true,
                        children: []
                    };
                    treeSubflows.push(subflows[node.id])
                } else {
                    nodes.push(node);
                }
            });
    
            var globalNodes = [];
            var parentlessNodes = [];
    
            nodes.forEach(function(node) {
                var treeNode = {
                    element: getNodeLabel(node, false, false)
                };
                if (node.z) {
                    if (!flows[node.z] && !subflows[node.z]) {
                        parentlessNodes.push(treeNode)
                    } else if (flows[node.z]) {
                        flows[node.z].children.push(treeNode)
                    } else if (subflows[node.z]) {
                        subflows[node.z].children.push(treeNode)
                    }
                } else {
                    globalNodes.push(treeNode);
                }
            });
            var treeData = [];
    
            if (parentlessNodes.length > 0) {
                treeData = treeData.concat(parentlessNodes);
            }
            if (type === "flow") {
                treeData = treeData.concat(treeFlows);
            } else if (treeFlows.length > 0) {
                treeData.push({
                    label: RED._("menu.label.flows"),
                    deferBuild: treeFlows.length > 20,
                    expanded: treeFlows.length <= 20,
                    children: treeFlows
                })
            }
            if (treeSubflows.length > 0) {
                treeData.push({
                    label: RED._("menu.label.subflows"),
                    deferBuild: treeSubflows.length > 10,
                    expanded: treeSubflows.length <= 10,
                    children: treeSubflows
                })
            }
            if (globalNodes.length > 0) {
                treeData.push({
                    label: RED._("sidebar.info.globalConfig"),
                    deferBuild: globalNodes.length > 10,
                    expanded: globalNodes.length <= 10,
                    children: globalNodes
                })
            }
    
            $("#red-ui-clipboard-dialog-export-tab-clipboard-preview-list").treeList('data',treeData);
        }
    
        function loadFlowLibrary(browser,library,label) {
            // if (includeExamples) {
            //     listing.push({
            //         library: "_examples_",
            //         type: "flows",
            //         icon: 'fa fa-hdd-o',
            //         label: RED._("library.types.examples"),
            //         path: "",
            //         children: function(done,item) {
            //             RED.library.loadLibraryFolder("_examples_","flows","",function(children) {
            //                 item.children = children;
            //                 done(children);
            //             })
            //         }
            //     })
            // }
            browser.data([{
                library: library,
                type: "flows",
                icon: 'fa fa-hdd-o',
                label: label,
                path: "",
                expanded: true,
                children: function(done, item) {
                    RED.library.loadLibraryFolder(library,"flows","",function(children) {
                        item.children = children;
                        done(children);
                    })
                }
            }], true);
    
        }
    
        function hideDropTarget() {
            $("#red-ui-drop-target").hide();
            RED.keyboard.remove("escape");
        }
        function copyText(value,element,msg) {
            var truncated = false;
            var currentFocus = document.activeElement;
            if (typeof value !== "string" ) {
                value = JSON.stringify(value, function(key,value) {
                    if (value !== null && typeof value === 'object') {
                        if (value.__enc__) {
                            if (value.hasOwnProperty('data') && value.hasOwnProperty('length')) {
                                truncated = value.data.length !== value.length;
                                return value.data;
                            }
                            if (value.type === 'function' || value.type === 'internal') {
                                return undefined
                            }
                            if (value.type === 'number') {
                                // Handle NaN and Infinity - they are not permitted
                                // in JSON. We can either substitute with a String
                                // representation or null
                                return null;
                            }
                            if (value.type === 'bigint') {
                                return value.data.toString();
                            }
                            if (value.type === 'undefined') {
                                return undefined;
                            }
                        }
                    }
                    return value;
                });
            }
            if (truncated) {
                msg += "_truncated";
            }
            $("#red-ui-clipboard-hidden").val(value).focus().select();
            var result =  document.execCommand("copy");
            if (result && element) {
                var popover = RED.popover.create({
                    target: element,
                    direction: 'left',
                    size: 'small',
                    content: RED._(msg)
                });
                setTimeout(function() {
                    popover.close();
                },1000);
                popover.open();
            }
            $("#red-ui-clipboard-hidden").val("");
            if (currentFocus) {
                $(currentFocus).focus();
            }
            return result;
        }
    
    
        function importNodes(nodesStr,addFlow) {
            var newNodes = nodesStr;
            if (typeof nodesStr === 'string') {
                try {
                    nodesStr = nodesStr.trim();
                    if (nodesStr.length === 0) {
                        return;
                    }
                    newNodes = JSON.parse(nodesStr);
                } catch(err) {
                    var e = new Error(RED._("clipboard.invalidFlow",{message:err.message}));
                    e.code = "NODE_RED";
                    throw e;
                }
            }
            var importOptions = {generateIds: false, addFlow: addFlow};
            try {
                RED.view.importNodes(newNodes, importOptions);
            } catch(error) {
                // Thrown for import_conflict
                confirmImport(error.importConfig, newNodes, importOptions);
            }
        }
    
        function confirmImport(importConfig,importNodes,importOptions) {
            var notification = RED.notify("

    "+RED._("clipboard.import.conflictNotification1")+"

    ",{ type: "info", fixed: true, buttons: [ {text: RED._("common.label.cancel"), click: function() { notification.close(); }}, {text: RED._("clipboard.import.viewNodes"), click: function() { notification.close(); showImportConflicts(importConfig,importNodes,importOptions); }}, {text: RED._("clipboard.import.importCopy"), click: function() { notification.close(); // generateIds=true to avoid conflicts // and default to the 'old' behaviour around matching // config nodes and subflows importOptions.generateIds = true; RED.view.importNodes(importNodes, importOptions); }} ] }) } function showImportConflicts(importConfig,importNodes,importOptions) { pendingImportConfig = { importConfig: importConfig, importNodes: importNodes, importOptions: importOptions } var id,node; var treeData = []; var container; var addedHeader = false; for (id in importConfig.subflows) { if (importConfig.subflows.hasOwnProperty(id)) { if (!addedHeader) { treeData.push({gutter:$(''), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"}) addedHeader = true; } node = importConfig.subflows[id]; var isConflicted = importConfig.conflicted[node.id]; var isSelected = !isConflicted; var elements = getNodeElement(node, isConflicted, isSelected ); container = { id: node.id, gutter: elements.gutter.element, element: elements.element, class: isSelected?"":"disabled", deferBuild: true, children: [] } treeData.push(container); if (importConfig.zMap[id]) { importConfig.zMap[id].forEach(function(node) { var childElements = getNodeElement(node, importConfig.conflicted[node.id], isSelected, elements.gutter.cb); container.children.push({ id: node.id, gutter: childElements.gutter.element, element: childElements.element, class: isSelected?"":"disabled" }) }); } } } addedHeader = false; for (id in importConfig.tabs) { if (importConfig.tabs.hasOwnProperty(id)) { if (!addedHeader) { treeData.push({gutter:$(''), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"}) addedHeader = true; } node = importConfig.tabs[id]; var isConflicted = importConfig.conflicted[node.id]; var isSelected = true; var elements = getNodeElement(node, isConflicted, isSelected); container = { id: node.id, gutter: elements.gutter.element, element: elements.element, icon: "red-ui-icons red-ui-icons-flow", deferBuild: true, class: isSelected?"":"disabled", children: [] } treeData.push(container); if (importConfig.zMap[id]) { importConfig.zMap[id].forEach(function(node) { var childElements = getNodeElement(node, importConfig.conflicted[node.id], isSelected, elements.gutter.cb); container.children.push({ id: node.id, gutter: childElements.gutter.element, element: childElements.element, class: isSelected?"":"disabled" }) // console.log(" ["+(importConfig.conflicted[node.id]?"*":" ")+"] "+node.type+" "+node.id); }); } } } addedHeader = false; var extraNodes = []; importConfig.all.forEach(function(node) { if (node.type !== "tab" && node.type !== "subflow" && !importConfig.tabs[node.z] && !importConfig.subflows[node.z]) { var isConflicted = importConfig.conflicted[node.id]; var isSelected = !isConflicted || !importConfig.configs[node.id]; var elements = getNodeElement(node, isConflicted, isSelected); var item = { id: node.id, gutter: elements.gutter.element, element: elements.element, class: isSelected?"":"disabled" } if (importConfig.configs[node.id]) { extraNodes.push(item); } else { if (!addedHeader) { treeData.push({gutter:$(''), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"}) addedHeader = true; } treeData.push(item); } // console.log("["+(importConfig.conflicted[node.id]?"*":" ")+"] "+node.type+" "+node.id); } }) if (extraNodes.length > 0) { treeData.push({gutter:$(''), label: '', class:"red-ui-clipboard-dialog-import-conflicts-item-header"}) addedHeader = true; treeData = treeData.concat(extraNodes); } dialogContainer.empty(); dialogContainer.append($(importConflictsDialog)); var nodeList = $("#red-ui-clipboard-dialog-import-conflicts-list").css({position:"absolute",top:0,right:0,bottom:0,left:0}).treeList({ data: treeData }) dialogContainer.i18n(); var dialogHeight = 400; var winHeight = $(window).height(); if (winHeight < 600) { dialogHeight = 400 - (600 - winHeight); } $(".red-ui-clipboard-dialog-box").height(dialogHeight); $("#red-ui-clipboard-dialog-ok").hide(); $("#red-ui-clipboard-dialog-cancel").show(); $("#red-ui-clipboard-dialog-export").hide(); $("#red-ui-clipboard-dialog-download").hide(); $("#red-ui-clipboard-dialog-import-conflict").show(); dialog.dialog("option","title",RED._("clipboard.importNodes")) .dialog("option","width",500) .dialog( "open" ); } function getNodeElement(n, isConflicted, isSelected, parent) { var element; if (n.type === "tab") { element = getFlowLabel(n, isSelected); } else { element = getNodeLabel(n, isConflicted, isSelected); } var controls = $('
    ',{class:"red-ui-clipboard-dialog-import-conflicts-controls"}).appendTo(element); controls.on("click", function(evt) { evt.stopPropagation(); }); if (isConflicted && !parent) { var cb = $('').appendTo(controls); if (n.type === "tab" || (n.type !== "subflow" && n.hasOwnProperty("x") && n.hasOwnProperty("y"))) { cb.hide(); } } return { element: element, gutter: getGutter(n, isSelected, parent) } } function getGutter(n, isSelected, parent) { var span = $("