/** * 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; 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: [ { id: "red-ui-clipboard-dialog-cancel", text: RED._("common.label.cancel"), click: function() { $( this ).dialog( "close" ); } }, { id: "red-ui-clipboard-dialog-download", class: "primary", text: RED._("clipboard.download"), click: function() { var element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent($("#red-ui-clipboard-dialog-export-text").val())); element.setAttribute('download', "flows.json"); element.style.display = 'none'; document.body.appendChild(element); element.trigger("click"); document.body.removeChild(element); $( this ).dialog( "close" ); } }, { id: "red-ui-clipboard-dialog-export", class: "primary", text: RED._("clipboard.export.copy"), click: function() { if (activeTab === "red-ui-clipboard-dialog-export-tab-clipboard") { $("#red-ui-clipboard-dialog-export-text").select(); document.execCommand("copy"); document.getSelection().removeAllRanges(); 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(); } } } }, { 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-red-ui-clipboard-dialog-import-opt-clipboard") { RED.view.importNodes($("#red-ui-clipboard-dialog-import-text").val(),addNewFlow); } else { var selectedPath = libraryBrowser.getSelected(); if (selectedPath.path) { $.get('library/'+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path, function(data) { RED.view.importNodes(data,addNewFlow); }); } } $( this ).dialog( "close" ); } } ], close: function(e) { if (popover) { popover.close(true); currentPopoverError = null; } } }); dialogContainer = dialog.children(".dialog-form"); exportNodesDialog = '
'+ ''+ ''+ ''+ ''+ ''+ ''+ '
'+ '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
'+ ''+ '
'+ '
'+ ''+ ''+ ''+ ''+ '
'+ '
'+ '
'+ '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
' ; importNodesDialog = '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
'+ ' '+ ''+ '
'+ '
'+ ''+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ '
'+ ''+ ''+ ''+ ''+ ''+ '
'; } 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 importNodes(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.activateTab("red-ui-clipboard-dialog-import-tab-"+mode);
        if (mode === 'clipboard') {
            setTimeout(function() {
                $("#red-ui-clipboard-dialog-import-text").trigger("focus");
            },100)
        }


        $("#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-browser"),
            onselect: function(file) {
                if (file && file.label && !file.children) {
                    $("#red-ui-clipboard-dialog-ok").button("enable");
                } else {
                    $("#red-ui-clipboard-dialog-ok").button("disable");
                }
            }
        })
        loadFlowLibrary(libraryBrowser,true);

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

        dialog.dialog("option","title",RED._("clipboard.importNodes")).dialog("open");
        popover = RED.popover.create({
            target: $("#red-ui-clipboard-dialog-import-text"),
            trigger: "manual",
            direction: "bottom",
            content: ""
        });
    }

    function exportNodes(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")
        });

        tabs.activateTab("red-ui-clipboard-dialog-export-tab-"+mode);

        $("#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,false);

        $("#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');
            var flow = "";
            var nodes = null;
            if (type === 'red-ui-clipboard-dialog-export-rng-selected') {
                var selection = RED.workspaces.selection();
                if (selection.length > 0) {
                    nodes = [];
                    selection.forEach(function(n) {
                        nodes.push(n);
                        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 === 'red-ui-clipboard-dialog-export-rng-flow') {
                var activeWorkspace = RED.workspaces.active();
                nodes = 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 === 'red-ui-clipboard-dialog-export-rng-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); },50);
            $("#red-ui-clipboard-dialog-export-text").trigger("focus");
        })

        $("#red-ui-clipboard-dialog-ok").hide();
        $("#red-ui-clipboard-dialog-cancel").hide();
        $("#red-ui-clipboard-dialog-export").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");
        }
        dialog.dialog("option","title",RED._("clipboard.exportNodes")).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();

    }

    function loadFlowLibrary(browser,includeExamples) {
        var listing = [];
        if (includeExamples) {
            listing.push({
                library: "_examples_",
                type: "flows",
                icon: 'fa fa-hdd-o',
                label: RED._("library.types.examples"),
                path: "",
                children: function(item,done) {
                    RED.library.loadLibraryFolder("_examples_","flows","",function(children) {
                        item.children = children;
                        done(children);
                    })
                }
            })
        }
        listing.push({
            library: "local",
            type: "flows",
            icon: 'fa fa-hdd-o',
            label: RED._("library.types.local"),
            path: "",
            expanded: true,
            children: function(item,done) {
                RED.library.loadLibraryFolder("local","flows","",function(children) {
                    item.children = children;
                    done(children);
                })
            }
        })
        browser.data(listing);
    }

    function hideDropTarget() {
        $("#red-ui-drop-target").hide();
        RED.keyboard.remove("escape");
    }
    function copyText(value,element,msg) {
        var truncated = false;
        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;
                        }
                    }
                }
                return value;
            });
        }
        if (truncated) {
            msg += "_truncated";
        }
        $("#red-ui-clipboard-hidden").val(value).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();
        }
        return result;
    }
    return {
        init: function() {
            setupDialogs();

            $('').appendTo("#red-ui-editor");

            RED.actions.add("core:show-export-dialog",exportNodes);
            RED.actions.add("core:show-import-dialog",importNodes);

            RED.actions.add("core:library-export",function() { exportNodes('library') });

            RED.events.on("editor:open",function() { disabled = true; });
            RED.events.on("editor:close",function() { disabled = false; });
            RED.events.on("search:open",function() { disabled = true; });
            RED.events.on("search:close",function() { disabled = false; });
            RED.events.on("type-search:open",function() { disabled = true; });
            RED.events.on("type-search:close",function() { disabled = false; });

            $('

').appendTo('#red-ui-editor'); $('#red-ui-workspace-chart').on("dragenter",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { $("#red-ui-drop-target").css({display:'table'}); RED.keyboard.add("*", "escape" ,hideDropTarget); } }); $('#red-ui-drop-target').on("dragover",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { event.preventDefault(); } }) .on("dragleave",function(event) { hideDropTarget(); }) .on("drop",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1) { var data = event.originalEvent.dataTransfer.getData("text/plain"); data = data.substring(data.indexOf('['),data.lastIndexOf(']')+1); RED.view.importNodes(data); } else if ($.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { var files = event.originalEvent.dataTransfer.files; if (files.length === 1) { var file = files[0]; var reader = new FileReader(); reader.onload = (function(theFile) { return function(e) { RED.view.importNodes(e.target.result); }; })(file); reader.readAsText(file); } } hideDropTarget(); event.preventDefault(); }); }, import: importNodes, export: exportNodes, copyText: copyText } })();