From 32630083790d22594dca8ebb8796b3b1308311d0 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Tue, 23 Apr 2019 14:23:17 +0100 Subject: [PATCH] Move library import/export to single dialog --- .../editor-client/locales/en-US/editor.json | 7 +- .../@node-red/editor-client/src/js/red.js | 2 +- .../editor-client/src/js/ui/clipboard.js | 251 ++++-- .../src/js/ui/common/treeList.js | 69 +- .../editor-client/src/js/ui/library.js | 782 ++++++++++-------- .../editor-client/src/sass/colors.scss | 4 + .../editor-client/src/sass/library.scss | 109 +++ .../editor-client/src/sass/mixins.scss | 26 +- .../editor-client/src/sass/tabs.scss | 2 +- .../src/sass/ui/common/treeList.scss | 21 +- 10 files changed, 842 insertions(+), 431 deletions(-) diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json index 5b4985765..d178a8f1e 100755 --- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json @@ -182,7 +182,11 @@ "all":"all flows", "compact":"compact", "formatted":"formatted", - "copy": "Export to clipboard" + "copy": "Copy to clipboard", + "export": "Export to library", + "exportAs": "Export as", + "overwrite": "Replace", + "exists": "

\"__file__\" already exists.

Do you want to replace it?

" }, "import": { "import": "Import to", @@ -354,6 +358,7 @@ "typeLibrary": "__type__ library", "unnamedType": "Unnamed __type__", "exportToLibrary": "Export nodes to library", + "exportedToLibrary": "Nodes exported to library", "dialogSaveOverwrite": "A __libraryType__ called __libraryName__ already exists. Overwrite?", "invalidFilename": "Invalid filename", "savedNodes": "Saved nodes", diff --git a/packages/node_modules/@node-red/editor-client/src/js/red.js b/packages/node_modules/@node-red/editor-client/src/js/red.js index 011b5b8d7..8fdb0de08 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/red.js +++ b/packages/node_modules/@node-red/editor-client/src/js/red.js @@ -468,7 +468,7 @@ var RED = (function() { ]}); menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),options:[ {id:"menu-item-export-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-export-dialog"}, - {id:"menu-item-export-library",label:RED._("menu.label.library"),disabled:true,onselect:"core:library-export"} + {id:"menu-item-export-library",label:RED._("menu.label.library"),onselect:"core:library-export"} ]}); menuOptions.push(null); menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"}); diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js index 97addf5c5..09af09251 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js @@ -24,6 +24,8 @@ RED.clipboard = (function() { var disabled = false; var popover; var currentPopoverError; + var activeExportTab; + var libraryBrowser; function setupDialogs() { dialog = $('
') @@ -31,7 +33,7 @@ RED.clipboard = (function() { .dialog({ modal: true, autoOpen: false, - width: 500, + width: 800, resizable: false, buttons: [ { @@ -41,14 +43,6 @@ RED.clipboard = (function() { $( this ).dialog( "close" ); } }, - { - id: "clipboard-dialog-close", - class: "primary", - text: RED._("common.label.close"), - click: function() { - $( this ).dialog( "close" ); - } - }, { id: "clipboard-dialog-download", class: "primary", @@ -65,15 +59,71 @@ RED.clipboard = (function() { } }, { - id: "clipboard-dialog-copy", + id: "clipboard-dialog-export", class: "primary", text: RED._("clipboard.export.copy"), click: function() { - $("#clipboard-export").select(); - document.execCommand("copy"); - document.getSelection().removeAllRanges(); - RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"}); - $( this ).dialog( "close" ); + if (activeExportTab === "clipboard-dialog-export-tab-clipboard") { + $("#clipboard-export").select(); + document.execCommand("copy"); + document.getSelection().removeAllRanges(); + RED.notify(RED._("clipboard.nodesExported"),{id:"clipboard"}); + $( this ).dialog( "close" ); + } else { + var flowToExport = $("#clipboard-export").val(); + var selectedPath = libraryBrowser.getPath(); + var filename = $("#clipboard-dialog-tab-library-name").val().trim(); + var saveFlow = function() { + $.ajax({ + url:'library/flows/'+selectedPath.path + filename, + type: "POST", + data: flowToExport, + contentType: "application/json; charset=utf-8" + }).done(function() { + // RED.library.loadFlowLibrary(); + $(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.files) { + var exists = false; + selectedPath.files.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(); + } + } } }, { @@ -101,22 +151,39 @@ RED.clipboard = (function() { exportNodesDialog = '
'+ - ''+ + ''+ ''+ ''+ ''+ ''+ ''+ '
'+ - '
'+ - ''+ - '
'+ - '
'+ - ''+ - ''+ - ''+ - ''+ - '
'; + '
'+ + '
'+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    '+ + '
    '+ + ''+ + ''+ + ''+ + ''+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    '+ + '
    '+ + '
    '+ + '
    ' + ; + importNodesDialog = '
    '+ @@ -135,6 +202,26 @@ RED.clipboard = (function() { '
    '; } + var validateExportFilenameTimeout + function validateExportFilename() { + if (validateExportFilenameTimeout) { + clearTimeout(validateExportFilenameTimeout); + } + validateExportFilenameTimeout = setTimeout(function() { + var filenameInput = $("#clipboard-dialog-tab-library-name"); + var filename = filenameInput.val().trim(); + var valid = filename.length > 0 && !/[\/\\]/.test(filename); + if (valid) { + filenameInput.removeClass("input-error"); + $("#clipboard-dialog-export").button("enable"); + } else { + filenameInput.addClass("input-error"); + $("#clipboard-dialog-export").button("disable"); + } + },100); + } + + var validateImportTimeout; function validateImport() { @@ -239,8 +326,7 @@ RED.clipboard = (function() { $("#clipboard-dialog-ok").show(); $("#clipboard-dialog-cancel").show(); - $("#clipboard-dialog-close").hide(); - $("#clipboard-dialog-copy").hide(); + $("#clipboard-dialog-export").hide(); $("#clipboard-dialog-download").hide(); $("#clipboard-dialog-ok").button("disable"); $("#clipboard-import").keyup(validateImport); @@ -277,13 +363,95 @@ RED.clipboard = (function() { }); } - function exportNodes() { + function exportNodes(mode) { if (disabled) { return; } + mode = mode || "clipboard"; + dialogContainer.empty(); dialogContainer.append($(exportNodesDialog)); + + var tabs = RED.tabs.create({ + id: "clipboard-dialog-export-tabs", + vertical: true, + onchange: function(tab) { + $("#clipboard-dialog-export-tabs-content").children().hide(); + $("#" + tab.id).show(); + activeExportTab = tab.id; + if (tab.id === "clipboard-dialog-export-tab-clipboard") { + $("#clipboard-dialog-export").button("option","label", RED._("clipboard.export.copy")) + $("#clipboard-dialog-download").show(); + } else { + $("#clipboard-dialog-export").button("option","label", RED._("clipboard.export.export")) + $("#clipboard-dialog-download").hide(); + } + + } + }); + tabs.addTab({ + id: "clipboard-dialog-export-tab-clipboard", + label: "Clipboard" + }); + tabs.addTab({ + id: "clipboard-dialog-export-tab-library", + label: "Library" + }); + + tabs.activateTab("clipboard-dialog-export-tab-"+mode); + + $("#clipboard-dialog-tab-library-name").keyup(validateExportFilename); + $("#clipboard-dialog-tab-library-name").on('paste',function() { setTimeout(validateExportFilename,10)}); + $("#clipboard-dialog-export").button("enable"); + + libraryBrowser = RED.library.createBrowser({ + container: $("#clipboard-dialog-export-tab-library-browser"), + addFolderButton: true, + onselect: function(file) { + if (file && file.label) { + $("#clipboard-dialog-tab-library-name").val(file.label); + } + } + }) + + function xformList(list,label,root) { + var result = { + icon: root===""?"fa fa-archive":'fa fa-folder', + label: label, + path: root + }; + + if (list.f) { + result.files = list.f.map(function(f) { + return { + icon: 'fa fa-file-o', + label: f, + path: root+f + } + }); + } + result.children = []; + if (list.d) { + for (var l in list.d) { + if (list.d.hasOwnProperty(l)) { + if (root+l !== "_examples_") { + result.children.push(xformList(list.d[l], l,root+l+"/")) + } + } + } + } + return result; + } + + $.getJSON("library/flows", function(data) { + var listing = [xformList(data,"Local","")]; + listing[0].expanded = true; + libraryBrowser.data(listing); + }); + $("#clipboard-dialog-tab-library-name").val("flows.json").select(); + + dialogContainer.i18n(); var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini"; @@ -307,6 +475,8 @@ RED.clipboard = (function() { flow = JSON.stringify(nodes); } $("#clipboard-export").val(flow); + setTimeout(function() { $("#clipboard-export").scrollTop(0); },50); + $("#clipboard-export").focus(); } }); @@ -314,7 +484,6 @@ RED.clipboard = (function() { $("#export-range-group > a").click(function(evt) { evt.preventDefault(); if ($(this).hasClass('disabled') || $(this).hasClass('selected')) { - $("#clipboard-export").focus(); return; } $(this).parent().children().removeClass('selected'); @@ -357,13 +526,13 @@ RED.clipboard = (function() { $("#export-copy").addClass('disabled'); } $("#clipboard-export").val(flow); + setTimeout(function() { $("#clipboard-export").scrollTop(0); },50); $("#clipboard-export").focus(); }) $("#clipboard-dialog-ok").hide(); $("#clipboard-dialog-cancel").hide(); - $("#clipboard-dialog-copy").hide(); - $("#clipboard-dialog-close").hide(); + $("#clipboard-dialog-export").hide(); var selection = RED.workspaces.selection(); if (selection.length > 0) { $("#export-range-selected").click(); @@ -381,25 +550,11 @@ RED.clipboard = (function() { } else { $("#export-format-mini").click(); } - $("#clipboard-export") - .focus(function() { - var textarea = $(this); - textarea.select(); - textarea.mouseup(function() { - textarea.unbind("mouseup"); - return false; - }) - }); dialog.dialog("option","title",RED._("clipboard.exportNodes")).dialog( "open" ); $("#clipboard-export").focus(); - if (!document.queryCommandSupported("copy")) { - $("#clipboard-dialog-cancel").hide(); - $("#clipboard-dialog-close").show(); - } else { - $("#clipboard-dialog-cancel").show(); - $("#clipboard-dialog-copy").show(); - } + $("#clipboard-dialog-cancel").show(); + $("#clipboard-dialog-export").show(); $("#clipboard-dialog-download").show(); } @@ -460,6 +615,7 @@ RED.clipboard = (function() { 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; }); @@ -468,7 +624,6 @@ RED.clipboard = (function() { RED.events.on("type-search:open",function() { disabled = true; }); RED.events.on("type-search:close",function() { disabled = false; }); - $('#chart').on("dragenter",function(event) { if ($.inArray("text/plain",event.originalEvent.dataTransfer.types) != -1 || $.inArray("Files",event.originalEvent.dataTransfer.types) != -1) { diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js index 8e0249183..79371fee6 100644 --- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js +++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/treeList.js @@ -32,7 +32,7 @@ * label: 'Local', // label for the item * icon: 'fa fa-rocket', // (optional) icon for the item * selected: true/false, // (optional) if present, display checkbox accordingly - * children: [] | function(done) // (optional) an array of child items, or a function + * children: [] | function(item,done) // (optional) an array of child items, or a function * // that will call the `done` callback with an array * // of child items * } @@ -66,7 +66,7 @@ scrollOnAdd: false, height: '100%', addItem: function(container,i,item) { - that._addSubtree(container,item,0); + that._addSubtree(that._topList,container,item,0); } }); if (this.options.data) { @@ -80,20 +80,27 @@ scrollOnAdd: false, height: 'auto', addItem: function(container,i,item) { - that._addSubtree(container,item,depth+1); + that._addSubtree(subtree,container,item,depth+1); } }); for (var i=0;i').appendTo(label); - // $('').appendTo(label); - label.click(function(e) { + item.treeList.addChild = function(newItem) { + item.treeList.childList.editableList('addItem',newItem) + item.children.push(newItem); + } + item.treeList.expand = function() { if (!container.hasClass("built") && typeof item.children === 'function') { container.addClass('built'); var childrenAdded = false; var spinner; - item.children(function(children) { + item.children(item,function(children) { childrenAdded = true; - that._addChildren(container,children,depth); + item.treeList.childList = that._addChildren(container,children,depth); if (spinner) { spinner.remove(); } + that._trigger("childrenloaded",null,item) }); if (!childrenAdded) { spinner = $('
    ').css({ @@ -125,7 +135,20 @@ } } - container.toggleClass("expanded"); + container.addClass("expanded"); + } + item.treeList.collapse = function() { + container.removeClass("expanded"); + } + + $('').appendTo(label); + // $('').appendTo(label); + label.click(function(e) { + if (container.hasClass("expanded")) { + item.treeList.collapse(); + } else { + item.treeList.expand(); + } }) } else { $('').appendTo(label); @@ -140,21 +163,27 @@ item.selected = this.checked; that._trigger("select",e,item); }) - } else if (!item.children) { + } else { label.click(function(e) { + that._topList.find(".selected").removeClass("selected"); + label.addClass("selected"); that._trigger("select",e,item) }) } if (item.icon) { $('').appendTo(label); } - $('').text(item.label).appendTo(label); + if (item.label) { + $('').text(item.label).appendTo(label); + } else if (item.element) { + $(item.element).appendTo(label); + } if (item.children) { if (Array.isArray(item.children)) { - that._addChildren(container,item.children,depth); + item.treeList.childList = that._addChildren(container,item.children,depth); } if (item.expanded) { - label.click(); + item.treeList.expand(); } } }, @@ -168,6 +197,8 @@ for (var i=0; i'+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + '
    '+ + ''+ + '
    ' - var _librarySaveConfirm = '
    '; - var _librarySave = '
    '; - var _libraryLookup = '
      '; + var _librarySave = '
      '+ + '
      '+ + '
      '+ + '
      '+ + '
      '+ + ''+ + '
      '+ + '
      '+ + '
      '+ + '
      ' + function saveToLibrary() { + var elementPrefix = activeLibrary.elementPrefix || "node-input-"; + var name = $("#"+elementPrefix+"name").val().trim(); + if (name === "") { + name = RED._("library.unnamedType",{type:activeLibrary.type}); + } + var filename = $("#node-dialog-library-save-filename").val().trim() + var selectedPath = saveLibraryBrowser.getPath(); + var queryArgs = []; + var data = {}; + for (var i=0; i 0 && !/[\/\\]/.test(filename); + if (valid) { + filenameInput.removeClass("input-error"); + $("#node-dialog-library-save-button").button("enable"); + } else { + filenameInput.addClass("input-error"); + $("#node-dialog-library-save-button").button("disable"); + } + },100); + } + function createUI(options) { var libraryData = {}; var selectedLibraryItem = null; - var libraryEditor = null; - elementPrefix = options.elementPrefix || "node-input-"; + var elementPrefix = options.elementPrefix || "node-input-"; // Orion editor has set/getText // ACE editor has set/getValue @@ -107,64 +247,7 @@ RED.library = (function() { options.editor.getValue = options.editor.getText; } - function buildFileListItem(item) { - var li = document.createElement("li"); - li.onmouseover = function(e) { $(this).addClass("list-hover"); }; - li.onmouseout = function(e) { $(this).removeClass("list-hover"); }; - return li; - } - - function buildFileList(root,data) { - var ul = document.createElement("ul"); - var li; - for (var i=0; i/ '); - $('').text(dirName).appendTo(bcli).click(function(e) { - $(this).parent().nextAll().remove(); - $.getJSON("library/"+options.url+root+dirName,function(data) { - $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data)); - }); - e.stopPropagation(); - }); - var bc = $("#node-dialog-library-breadcrumbs"); - $(".active",bc).removeClass("active"); - bc.append(bcli); - $.getJSON("library/"+options.url+root+dirName,function(data) { - $("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data)); - }); - } - })(); - $('').appendTo(li); - $('').text(" "+v).appendTo(li); - ul.appendChild(li); - } else { - // file - li = buildFileListItem(v); - li.innerText = v.name; - li.onclick = (function() { - var item = v; - return function(e) { - $(".list-selected",ul).removeClass("list-selected"); - $(this).addClass("list-selected"); - $.get("library/"+options.url+root+item.fn, function(data) { - selectedLibraryItem = item; - libraryEditor.setValue(data,-1); - }); - } - })(); - ul.appendChild(li); - } - } - return ul; - } - + // Add the library button to the name in the edit dialog $('#'+elementPrefix+"name").css("width","calc(100% - 52px)").after( '
      '+ ' '+ @@ -175,331 +258,332 @@ RED.library = (function() { ); $('#node-input-'+options.type+'-menu-open-library').click(function(e) { - $("#node-select-library").children().remove(); - var bc = $("#node-dialog-library-breadcrumbs"); - bc.children().first().nextAll().remove(); - libraryEditor.setValue('',-1); - - $.getJSON("library/"+options.url,function(data) { - $("#node-select-library").append(buildFileList("/",data)); - $("#node-dialog-library-breadcrumbs a").click(function(e) { - $(this).parent().nextAll().remove(); - $("#node-select-library").children().first().replaceWith(buildFileList("/",data)); - e.stopPropagation(); - }); - $( "#node-dialog-library-lookup" ).dialog( "open" ); + activeLibrary = options; + loadLibraryFolder(options.url, "", function(files,items) { + var listing = [{ + icon: 'fa fa-archive', + label: "Local", + path: "", + expanded: true, + writable: false, + children: [{ + icon: 'fa fa-cube', + label: options.type, + path: options.type+"/", + expanded: true, + children: items, + files: files + }] + }] + loadLibraryBrowser.data(listing); }); + libraryEditor = ace.edit('node-dialog-library-load-preview-text'); + libraryEditor.setTheme("ace/theme/tomorrow"); + if (options.mode) { + libraryEditor.getSession().setMode(options.mode); + } + libraryEditor.setOptions({ + readOnly: true, + highlightActiveLine: false, + highlightGutterLine: false + }); + libraryEditor.renderer.$cursorLayer.element.style.opacity=0; + libraryEditor.$blockScrolling = Infinity; + + $( "#node-dialog-library-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" ); e.preventDefault(); }); $('#node-input-'+options.type+'-menu-save-library').click(function(e) { + activeLibrary = options; //var found = false; var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,""); - - //var buildPathList = function(data,root) { - // var paths = []; - // if (data.d) { - // for (var i in data.d) { - // var dn = root+(root==""?"":"/")+i; - // var d = { - // label:dn, - // files:[] - // }; - // for (var f in data.d[i].f) { - // d.files.push(data.d[i].f[f].fn.split("/").slice(-1)[0]); - // } - // paths.push(d); - // paths = paths.concat(buildPathList(data.d[i],root+(root==""?"":"/")+i)); - // } - // } - // return paths; - //}; - $("#node-dialog-library-save-folder").attr("value",""); - var filename = name.replace(/[^\w-]/g,"-"); if (filename === "") { filename = "unnamed-"+options.type; } $("#node-dialog-library-save-filename").attr("value",filename+".js"); - //var paths = buildPathList(libraryData,""); - //$("#node-dialog-library-save-folder").autocomplete({ - // minLength: 0, - // source: paths, - // select: function( event, ui ) { - // $("#node-dialog-library-save-filename").autocomplete({ - // minLength: 0, - // source: ui.item.files - // }); - // } - //}); + loadLibraryFolder(options.url, "", function(files,items) { + var listing = [{ + icon: 'fa fa-archive', + label: "Local", + path: "", + expanded: true, + writable: false, + children: [{ + icon: 'fa fa-cube', + label: options.type, + path: options.type+"/", + expanded: true, + children: items, + files: files + }] + }] + saveLibraryBrowser.data(listing); + }); $( "#node-dialog-library-save" ).dialog( "open" ); e.preventDefault(); }); - libraryEditor = ace.edit('node-select-library-text'); - libraryEditor.setTheme("ace/theme/tomorrow"); - if (options.mode) { - libraryEditor.getSession().setMode(options.mode); - } - libraryEditor.setOptions({ - readOnly: true, - highlightActiveLine: false, - highlightGutterLine: false - }); - libraryEditor.renderer.$cursorLayer.element.style.opacity=0; - libraryEditor.$blockScrolling = Infinity; - - $( "#node-dialog-library-lookup" ).dialog({ - title: RED._("library.typeLibrary", {type:options.type}), - modal: true, - autoOpen: false, - width: 800, - height: 450, - buttons: [ - { - text: RED._("common.label.cancel"), - click: function() { - $( this ).dialog( "close" ); - } - }, - { - text: RED._("common.label.load"), - class: "primary", - click: function() { - if (selectedLibraryItem) { - for (var i=0; i
      ').appendTo(options.container); + var dirsPane = $('
      ').appendTo(panes); + var filesPane = $('
      ').appendTo(panes); + // + // '
      '+ + // '
      '+ + // '
      '+ + // '
      '+ + RED.panels.create({ + container:panes, + dir: "horizontal" + }); + var dirList = $("
      ").css({width: "100%", height: "100%"}).appendTo(dirsPane) + .treeList({}).on('treelistselect', function(event, item) { + fileList.treeList('data',item.files||[]); + if (addButton) { + if (item.writable === false) { + addButton.prop('disabled', true); + } else { + addButton.prop('disabled', false); + } + } + if (options.onpathselect) { + options.onpathselect(item); + } + }).on('treelistchildrenloaded', function(event) { + var selected = dirList.treeList('selected'); + fileList.treeList('data',selected.files||[]); + }); + var addButton; + if (options.addFolderButton) { + var tools = $("
      ").css({position: "absolute",bottom:"3px",left:"3px"}).appendTo(dirsPane) + addButton= $('').appendTo(tools).click(function(e) { + var selected = dirList.treeList('selected'); + + var defaultFolderName = "new-folder"; + var defaultFolderNameMatches = {}; + selected.children.forEach(function(c) { + if (/^new-folder/.test(c.label)) { + defaultFolderNameMatches[c.label] = true + } + }); + var folderIndex = 2; + while(defaultFolderNameMatches[defaultFolderName]) { + defaultFolderName = "new-folder-"+(folderIndex++) + } + + selected.treeList.expand(); + var input = $('').val(defaultFolderName); + var newItem = { + icon: "fa fa-folder-o", + children:[], + path: selected.path, + element: input + } + var confirmAdd = function() { + var val = input.val().trim(); + if (val === "") { + cancelAdd(); + return; + } else { + for (var i=0;i").css({width: "100%", height: "100%"}).appendTo(filesPane) + .treeList({}).on('treelistselect', function(event, item) { + if (options.onselect) { + options.onselect(item); + } + }) + return { + getFile: function() { + return fileList.treeList('selected'); + }, + getPath: function() { + return dirList.treeList('selected'); + }, + data: function(content) { + dirList.treeList('data',content); + setTimeout(function() { + dirList.treeList('select',content[0]); + },100); + } + } } return { init: function() { - $(_librarySave).appendTo(document.body); - $(_librarySaveConfirm).appendTo(document.body); $(_libraryLookup).appendTo(document.body); - RED.actions.add("core:library-export",exportFlow); - - RED.events.on("view:selection-changed",function(selection) { - if (!selection.nodes) { - RED.menu.setDisabled("menu-item-export-library",true); - } else { - RED.menu.setDisabled("menu-item-export-library",false); + $( "#node-dialog-library-save" ).dialog({ + title: RED._("library.saveToLibrary"), + modal: true, + autoOpen: false, + width: 800, + resizable: false, + buttons: [ + { + text: RED._("common.label.cancel"), + click: function() { + $( this ).dialog( "close" ); + } + }, + { + id: "node-dialog-library-save-button", + text: RED._("common.label.save"), + class: "primary", + click: function() { + saveToLibrary(false); + $( this ).dialog( "close" ); + } + } + ], + open: function(e) { + $(this).parent().find(".ui-dialog-titlebar-close").hide(); } }); + saveLibraryBrowser = RED.library.createBrowser({ + container: $("#node-dialog-library-save-browser"), + addFolderButton: true, + onpathselect: function(item) { + try { + if (item.writable === false) { + $("#node-dialog-library-save-button").button("disable"); + } else { + $("#node-dialog-library-save-button").button("enable"); + } + } catch(err) {} + }, + onselect: function(file) { + $("#node-dialog-library-save-filename").val(file.label); + } + }); + $("#node-dialog-library-save-filename").keyup(function() { validateExportFilename($(this))}); + $("#node-dialog-library-save-filename").on('paste',function() { var input = $(this); setTimeout(function() { validateExportFilename(input)},10)}); + + $( "#node-dialog-library-load" ).dialog({ + modal: true, + autoOpen: false, + width: 800, + resizable: false, + buttons: [ + { + text: RED._("common.label.cancel"), + click: function() { + $( this ).dialog( "close" ); + } + }, + { + text: RED._("common.label.load"), + class: "primary", + click: function() { + if (selectedLibraryItem) { + for (var i=0; iType').appendTo(table); + $(propRow.children()[1]).text(activeLibrary.type); + if (file.props.hasOwnProperty('name')) { + propRow = $('Name'+file.props.name+'').appendTo(table); + $(propRow.children()[1]).text(file.props.name); + } + for (var p in file.props) { + if (file.props.hasOwnProperty(p) && p !== 'name' && p !== 'fn') { + propRow = $('').appendTo(table); + $(propRow.children()[0]).text(p); + RED.utils.createObjectElement(file.props[p]).appendTo(propRow.children()[1]); + } + } + libraryEditor.setValue(data,-1); + }); + } else { + libraryEditor.setValue("",-1); + } + } + }); + + if (RED.settings.theme("menu.menu-item-import-library") !== false) { loadFlowLibrary(); } - - exportToLibraryDialog = $('
      ') - .appendTo("body") - .dialog({ - modal: true, - autoOpen: false, - width: 500, - resizable: false, - title: RED._("library.exportToLibrary"), - buttons: [ - { - id: "library-dialog-cancel", - text: RED._("common.label.cancel"), - click: function() { - $( this ).dialog( "close" ); - } - }, - { - id: "library-dialog-ok", - class: "primary", - text: RED._("common.label.export"), - click: function() { - //TODO: move this to RED.library - var flowName = $("#node-input-library-filename").val(); - flowName = flowName.trim(); - if(flowName === "" || flowName.endsWith("/")) { - RED.notify(RED._("library.invalidFilename"),"warning"); - } else { - $.ajax({ - url:'library/flows/'+flowName, - type: "POST", - data: $("#node-input-library-filename").attr('nodes'), - contentType: "application/json; charset=utf-8" - }).done(function() { - RED.library.loadFlowLibrary(); - RED.notify(RED._("library.savedNodes"),"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"); - } - }); - } - $( this ).dialog( "close" ); - } - } - ], - open: function(e) { - $(this).parent().find(".ui-dialog-titlebar-close").hide(); - }, - close: function(e) { - } - }); - exportToLibraryDialog.children(".dialog-form").append($( - '
      '+ - ''+ - ''+ - ''+ // Second hidden input to prevent submit on Enter - '
      ' - )); }, create: createUI, loadFlowLibrary: loadFlowLibrary, - + createBrowser:createBrowser, export: exportFlow } })(); diff --git a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss index 3066e247c..367a05a7c 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/colors.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/colors.scss @@ -22,6 +22,10 @@ $form-input-focus-color: rgba(85,150,230,0.8); $form-input-border-color: #ccc; $form-input-border-selected-color: #aaa; +$list-item-color: #666; +$list-item-background-hover: #f3f3f3; +$list-item-background-active: #efefef; +$list-item-background-selected: #eee; $node-selected-color: #ff7f0e; $port-selected-color: #ff7f0e; diff --git a/packages/node_modules/@node-red/editor-client/src/sass/library.scss b/packages/node_modules/@node-red/editor-client/src/sass/library.scss index cb0032cd0..26ef9fe09 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/library.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/library.scss @@ -48,3 +48,112 @@ } } } +#clipboard-dialog-export-tab-clipboard { + padding: 10px; + textarea { + resize: none; + width: 100%; + border-radius: 4px; + font-family: monospace !important; + font-size: 13px !important; + height: 430px; + line-height: 1.3em; + padding: 6px 10px; + background: #F3E7E7; + color: #533; + } +} + +#clipboard-dialog-export-tabs-content { + position: absolute; + top: 0; + left: 120px; + right: 0; + bottom: 0; + padding: 0; + background: white; + + &>div { + height: calc(100% - 20px) + } +} + +#clipboard-dialog-export-tab-library { + .form-row { + margin-left: 10px; + } +} + + +#clipboard-dialog-tab-library-name { + width: calc(100% - 120px); +} +#clipboard-dialog-export-tab-library-browser { + height: calc(100% - 40px); + margin-bottom: 10px; + border-bottom: 1px solid $primary-border-color; + box-sizing: border-box; +} + + + +.red-ui-library-browser { + height: 100%; + + .red-ui-treeList-container { + background: white; + border: none; + border-radius: 0; + li { + background: none; + } + label { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + .red-ui-editableList-border { + border-radius: 0; + } + + .red-ui-treeList-label input.red-ui-treeList-input { + border-radius: 2px; + margin-top: -6px; + margin-bottom: -6px; + } +} + +#node-dialog-library-save-browser { + height: calc(100% - 60px); + border: 1px solid $primary-border-color; + margin-bottom: 10px; +} +#node-dialog-library-load-browser { + height: 200px; + border: 1px solid $primary-border-color; + margin-bottom: 10px; +} +#node-dialog-library-load-preview { + height: 300px; +} + +#node-dialog-library-load-preview-text { + box-sizing: border-box; + display: inline-block; + height: 100%; + width: calc(50% - 5px); + border: 1px solid $primary-border-color; +} +#node-dialog-library-load-preview-details { + box-sizing: border-box; + display: inline-block; + height: 100%; + width: calc(50% - 5px); + margin-right: 10px; + border: 1px solid $primary-border-color; + + .node-info-node-row:first-child { + border-top: none; + } +} diff --git a/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss b/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss index 8dd0fc3ae..aacda031c 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/mixins.scss @@ -36,17 +36,10 @@ } -@mixin workspace-button { - @include disable-selection; - box-sizing: border-box; - display: inline-block; +@mixin reset-a-style { color: $workspace-button-color !important; background: $workspace-button-background; - border: 1px solid $form-input-border-color; - text-align: center; - margin:0; text-decoration: none; - cursor:pointer; &.disabled, &:disabled { cursor: default; @@ -67,6 +60,19 @@ background: $workspace-button-background-active; text-decoration: none; } +} + +@mixin workspace-button { + @include disable-selection; + @include reset-a-style; + + box-sizing: border-box; + display: inline-block; + border: 1px solid $form-input-border-color; + text-align: center; + margin:0; + cursor:pointer; + // &.selected:not(.disabled):not(:disabled) { // color: $workspace-button-color-selected !important; // background: $workspace-button-background-active; @@ -150,12 +156,12 @@ } &:not(.single) { color: $workspace-button-toggle-color !important; - background:$workspace-button-background-active; + background:$workspace-button-background; margin-bottom: 1px; &.selected:not(.disabled):not(:disabled) { color: $workspace-button-toggle-color-selected !important; - background: $workspace-button-background; + background: $workspace-button-background-active; border-bottom-width: 2px; border-bottom-color: $form-input-border-selected-color; margin-bottom: 0; diff --git a/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss b/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss index 489cce5f8..6770baf24 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/tabs.scss @@ -247,7 +247,7 @@ z-index: 2; &.red-ui-tab-link-button { &:not(.active) { - background: #eee; + // background: #eee; } } &.red-ui-tab-link-button-menu { diff --git a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/treeList.scss b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/treeList.scss index 2d090ae72..a6f0388e5 100644 --- a/packages/node_modules/@node-red/editor-client/src/sass/ui/common/treeList.scss +++ b/packages/node_modules/@node-red/editor-client/src/sass/ui/common/treeList.scss @@ -72,22 +72,29 @@ label.red-ui-treeList-label { @include disable-selection; padding: 6px 0; display: block; - color: $form-text-color; + color: $list-item-color; text-decoration: none; cursor: pointer; vertical-align: middle; margin: 0; - &:hover { - background: #f9f9f9; - color: $form-text-color; - text-decoration: none; - } + // &:hover { + // background: $list-item-background-hover; + // color: $list-item-color; + // text-decoration: none; + // } &:focus { + background: $list-item-background-hover; outline: none; - color: $form-text-color; + color: $list-item-color; text-decoration: none; } + &.selected { + background: $list-item-background-selected; + outline: none; + color: $list-item-color; + } + input { margin: 0; }