diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/index.js b/packages/node_modules/@node-red/editor-api/lib/editor/index.js index 44b4ffa89..3628fa702 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/index.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/index.js @@ -93,9 +93,8 @@ module.exports = { // Library var library = require("./library"); library.init(runtimeAPI); - editorApp.get("/library/flows",needsPermission("library.read"),library.getAll,apiUtil.errorHandler); - editorApp.get(/library\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry); - editorApp.post(/library\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry); + editorApp.get(/library\/([^\/]+)\/([^\/]+)(?:$|\/(.*))/,needsPermission("library.read"),library.getEntry); + editorApp.post(/library\/([^\/]+)\/([^\/]+)\/(.*)/,needsPermission("library.write"),library.saveEntry); // Credentials diff --git a/packages/node_modules/@node-red/editor-api/lib/editor/library.js b/packages/node_modules/@node-red/editor-api/lib/editor/library.js index e8b09424a..47a41bb7b 100644 --- a/packages/node_modules/@node-red/editor-api/lib/editor/library.js +++ b/packages/node_modules/@node-red/editor-api/lib/editor/library.js @@ -25,23 +25,12 @@ module.exports = { init: function(_runtimeAPI) { runtimeAPI = _runtimeAPI; }, - - getAll: function(req,res) { - var opts = { - user: req.user, - type: 'flows' - } - runtimeAPI.library.getEntries(opts).then(function(result) { - res.json(result); - }).catch(function(err) { - apiUtils.rejectHandler(req,res,err); - }); - }, getEntry: function(req,res) { var opts = { user: req.user, - type: req.params[0], - path: req.params[1]||"" + library: req.params[0], + type: req.params[1], + path: req.params[2]||"" } runtimeAPI.library.getEntry(opts).then(function(result) { if (typeof result === "string") { @@ -62,8 +51,9 @@ module.exports = { saveEntry: function(req,res) { var opts = { user: req.user, - type: req.params[0], - path: req.params[1]||"" + library: req.params[0], + type: req.params[1], + path: req.params[2]||"" } // TODO: horrible inconsistencies between flows and all other types if (opts.type === "flows") { diff --git a/packages/node_modules/@node-red/editor-client/locales/de/editor.json b/packages/node_modules/@node-red/editor-client/locales/de/editor.json index d477d3f0e..d052b5ef8 100755 --- a/packages/node_modules/@node-red/editor-client/locales/de/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/de/editor.json @@ -55,9 +55,6 @@ "export" : "Exportieren", "search" : "Flows durchsuchen", "searchInput" : "durchsuchen Sie Ihre Flows", - "clipboard" : "Zwischenablage", - "library" : "Bibliothek", - "examples" : "Beispiele", "subflows" : "Subflow", "createSubflow" : "Subflow erstellen", "selectionToSubflow" : "Auswahl für Subflow", @@ -136,8 +133,8 @@ } }, "clipboard" : { + "clipboard" : "Zwischenablage", "nodes" : "Knoten", - "selectNodes" : "Wählen Sie den Text oben aus, und kopieren Sie die Datei in die Zwischenablage.", "pasteNodes" : "Knoten hier einfügen", "importNodes" : "Knoten importieren", "exportNodes" : "Knoten in Zwischenablage exportieren", @@ -297,22 +294,19 @@ "managePalette" : "Palette verwalten" }, "library" : { + "library" : "Bibliothek", "openLibrary" : "Bibliothek öffnen ...", "saveToLibrary" : "In Bibliothek speichern ...", "typeLibrary" : "__type__, Bibliothek", "unnamedType" : "Unbenannt __type__", - "exportToLibrary" : "Knoten in Bibliothek exportieren", "dialogSaveOverwrite" : "Ein __libraryType__ mit dem Namen __libraryName__ ist bereits vorhanden. Überschreiben?", "invalidFilename" : "Ungültiger Dateiname", "savedNodes" : "Gespeicherte Knoten", "savedType" : "Gespeichert __type__", "saveFailed" : "Speichern fehlgeschlagen: __message__", - "filename" : "Name der Datei", - "folder" : "Ordner", - "filenamePlaceholder" : "Datei", - "fullFilenamePlaceholder" : "a/b/Datei", - "folderPlaceholder" : "a/b", - "breadcrumb" : "Bibliothek" + "types": { + "examples" : "Beispiele" + } }, "palette" : { "noInfo" : "Keine Informationen verfügbar", @@ -826,4 +820,4 @@ "code" : "code" } } -} \ No newline at end of file +} 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 22cb436b1..a48af013d 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 @@ -61,9 +61,6 @@ "export": "Export", "search": "Search flows", "searchInput": "search your flows", - "clipboard": "Clipboard", - "library": "Library", - "examples": "Examples", "subflows": "Subflows", "createSubflow": "Create Subflow", "selectionToSubflow": "Selection to Subflow", @@ -156,6 +153,7 @@ } }, "clipboard": { + "clipboard": "Clipboard", "nodes": "Nodes", "node": "__count__ node", "node_plural": "__count__ nodes", @@ -165,7 +163,6 @@ "flow_plural": "__count__ flows", "subflow": "__count__ subflow", "subflow_plural": "__count__ subflows", - "selectNodes": "Select the text above and copy to the clipboard.", "pasteNodes": "Paste flow json or", "selectFile": "select a file to import", "importNodes": "Import nodes", @@ -184,7 +181,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", @@ -351,22 +352,21 @@ "managePalette": "Manage palette" }, "library": { + "library": "Library", "openLibrary": "Open Library...", "saveToLibrary": "Save to Library...", "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", "savedType": "Saved __type__", "saveFailed": "Save failed: __message__", - "filename": "Filename", - "folder": "Folder", - "filenamePlaceholder": "file", - "fullFilenamePlaceholder": "a/b/file", - "folderPlaceholder": "a/b", - "breadcrumb": "Library" + "types": { + "local": "Local", + "examples": "Examples" + } }, "palette": { "noInfo": "no information available", diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json index 3672dde38..83a00a06e 100755 --- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -59,9 +59,6 @@ "export": "書き出し", "search": "ノードを検索", "searchInput": "ノードを検索", - "clipboard": "クリップボード", - "library": "ライブラリ", - "examples": "サンプル", "subflows": "サブフロー", "createSubflow": "サブフローを作成", "selectionToSubflow": "選択部分をサブフロー化", @@ -154,6 +151,7 @@ } }, "clipboard": { + "clipboard": "クリップボード", "nodes": "ノード", "node": "__count__ 個のノード", "node_plural": "__count__ 個のノード", @@ -163,7 +161,6 @@ "flow_plural": "__count__ 個のフロー", "subflow": "__count__ 個のサブフロー", "subflow_plural": "__count__ 個のサブフロー", - "selectNodes": "上のテキストを選択し、クリップボードへコピーしてください", "pasteNodes": "JSON形式のフローデータを貼り付けてください", "selectFile": "読み込むファイルを選択してください", "importNodes": "フローをクリップボートから読み込み", @@ -349,22 +346,19 @@ "managePalette": "パレットの管理" }, "library": { + "library": "ライブラリ", "openLibrary": "ライブラリを開く", "saveToLibrary": "ライブラリへ保存", "typeLibrary": "__type__ ライブラリ", "unnamedType": "名前なし __type__", - "exportToLibrary": "ライブラリへフローを書き出す", "dialogSaveOverwrite": "__libraryName__ という __libraryType__ は既に存在しています 上書きしますか?", "invalidFilename": "不正なファイル名", "savedNodes": "フローを保存しました", "savedType": "__type__ を保存しました", "saveFailed": "保存に失敗しました: __message__", - "filename": "ファイル名", - "folder": "フォルダ", - "filenamePlaceholder": "ファイル", - "fullFilenamePlaceholder": "a/b/file", - "folderPlaceholder": "a/b", - "breadcrumb": "ライブラリ" + "types": { + "examples": "サンプル" + } }, "palette": { "noInfo": "情報がありません", diff --git a/packages/node_modules/@node-red/editor-client/locales/ko/editor.json b/packages/node_modules/@node-red/editor-client/locales/ko/editor.json index da7c69e64..3e7811f53 100755 --- a/packages/node_modules/@node-red/editor-client/locales/ko/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ko/editor.json @@ -58,9 +58,6 @@ "export": "내보내기", "search": "플로우 겅색", "searchInput": "플로우 검색", - "clipboard": "클립보드", - "library": "라이브러리", - "examples": "예시", "subflows": "보조 플로우", "createSubflow": "보조 플로우 생성", "selectionToSubflow": "보조 플로우 선택", @@ -148,6 +145,7 @@ } }, "clipboard": { + "clipboard": "클립보드", "nodes": "노드", "node": "__count__ 개의 노드", "node_plural": "__count__ 개의 노드", @@ -157,7 +155,6 @@ "flow_plural": "__count__ 개의 플로우", "subflow": "__count__ 개의 서브 플로우", "subflow_plural": "__count__ 개의 서브 플로우", - "selectNodes": "텍스트를 선택하고 클립보드에 복사하세요", "pasteNodes": "여기에 노드를 붙여넣기 하세요", "selectFile": "불러올 파일을 선택하세요", "importNodes": "노드 불러오기", @@ -338,22 +335,19 @@ "managePalette": "팔렛트 관리" }, "library": { + "library": "라이브러리", "openLibrary": "라이브러리 열기...", "saveToLibrary": "라이브러리로 저장...", "typeLibrary": "__type__ 라이브러리", "unnamedType": "이름없는 __type__", - "exportToLibrary": "라이브러리로 노드 내보내기", "dialogSaveOverwrite": "__libraryType__이 __libraryName__으로 이미 등록되어있습니다. 덮어쓸까요?", "invalidFilename": "파일명이 올바르지 않습니다", "savedNodes": "저장된 노드", "savedType": "저장된 __type__", "saveFailed": "저장 실패 : __message__", - "filename": "파일명", - "folder": "폴더명", - "filenamePlaceholder": "파일", - "fullFilenamePlaceholder": "a/b/file", - "folderPlaceholder": "a/b", - "breadcrumb": "라이브러리" + "types": { + "examples": "예시" + } }, "palette": { "noInfo": "정보 없음", @@ -904,4 +898,4 @@ "description": "상세 내역", "appearance": "모양" } -} \ No newline at end of file +} diff --git a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json index 975a20448..f65f428f6 100644 --- a/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json @@ -50,9 +50,6 @@ "export": "导出", "search": "查找流程", "searchInput": "查找流程", - "clipboard": "剪贴板", - "library": "库", - "examples": "例子", "subflows": "子流程", "createSubflow": "新建子流程", "selectionToSubflow": "将选择部分更改为子流程", @@ -100,8 +97,8 @@ } }, "clipboard": { + "clipboard": "剪贴板", "nodes": "节点", - "selectNodes": "选择上面的文本并复制到剪贴板", "pasteNodes": "在这里粘贴节点", "importNodes": "导入节点", "exportNodes": "导出节点至剪贴板", @@ -237,6 +234,7 @@ "managePalette": "管理面板" }, "library": { + "library": "库", "openLibrary": "打开库...", "saveToLibrary": "保存到库...", "typeLibrary": "__type__类型库", @@ -247,12 +245,9 @@ "savedNodes": "保存的节点", "savedType": "已保存__type__", "saveFailed": "保存失败: __message__", - "filename": "文件名", - "folder": "文件夹", - "filenamePlaceholder": "文件", - "fullFilenamePlaceholder": "a/b/文件", - "folderPlaceholder": "a/b", - "breadcrumb": "库" + "types": { + "examples": "例子" + } }, "palette": { "noInfo": "无可用信息", 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..787166c00 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 @@ -462,14 +462,8 @@ var RED = (function() { null ]}); menuOptions.push(null); - menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),options:[ - {id:"menu-item-import-clipboard",label:RED._("menu.label.clipboard"),onselect:"core:show-import-dialog"}, - {id:"menu-item-import-library",label:RED._("menu.label.library"),options:[]} - ]}); - 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"} - ]}); + menuOptions.push({id:"menu-item-import",label:RED._("menu.label.import"),onselect:"core:show-import-dialog"}); + menuOptions.push({id:"menu-item-export",label:RED._("menu.label.export"),onselect:"core:show-export-dialog"}); menuOptions.push(null); menuOptions.push({id:"menu-item-search",label:RED._("menu.label.search"),onselect:"core:search"}); menuOptions.push(null); 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..ac14e2689 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 activeTab; + var libraryBrowser; function setupDialogs() { dialog = $('') @@ -31,7 +33,7 @@ RED.clipboard = (function() { .dialog({ modal: true, autoOpen: false, - width: 500, + width: 700, 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,73 @@ 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 (activeTab === "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.getSelected(); + if (!selectedPath.children) { + selectedPath = selectedPath.parent; + } + var filename = $("#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(); + } + } } }, { @@ -81,7 +133,17 @@ RED.clipboard = (function() { class: "primary", text: RED._("common.label.import"), click: function() { - RED.view.importNodes($("#clipboard-import").val(),$("#import-tab > a.selected").attr('id') === 'import-tab-new'); + var addNewFlow = ($("#import-tab > a.selected").attr('id') === 'import-tab-new'); + if (activeTab === "clipboard-dialog-import-tab-clipboard") { + RED.view.importNodes($("#clipboard-import").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" ); } } @@ -101,146 +163,257 @@ RED.clipboard = (function() { exportNodesDialog = ''+ - '').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;
- }
- $("#clipboard-dialog-ok").button("disable");
+ 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);
}
- function importNodes() {
+ var validateImportTimeout;
+ function validateImport() {
+ if (activeTab === "clipboard-dialog-import-tab-clipboard") {
+ if (validateImportTimeout) {
+ clearTimeout(validateImportTimeout);
+ }
+ validateImportTimeout = setTimeout(function() {
+ var importInput = $("#clipboard-import");
+ var v = importInput.val().trim();
+ if (v === "") {
+ popover.close(true);
+ currentPopoverError = null;
+ importInput.removeClass("input-error");
+ $("#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
').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;
+ }
+ $("#clipboard-dialog-ok").button("disable");
+ }
+ },100);
+ } else {
+ var file = libraryBrowser.getSelected();
+ if (file && file.label && !file.children) {
+ $("#clipboard-dialog-ok").button("enable");
+ } else {
+ $("#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: "clipboard-dialog-import-tabs",
+ vertical: true,
+ onchange: function(tab) {
+ $("#clipboard-dialog-import-tabs-content").children().hide();
+ $("#" + tab.id).show();
+ activeTab = tab.id;
+ if (popover) {
+ popover.close(true);
+ currentPopoverError = null;
+ }
+ if (tab.id === "clipboard-dialog-import-tab-clipboard") {
+ $("#clipboard-import").focus();
+ } else {
+ libraryBrowser.focus();
+ }
+ validateImport();
+ }
+ });
+ tabs.addTab({
+ id: "clipboard-dialog-import-tab-clipboard",
+ label: RED._("clipboard.clipboard")
+ });
+ tabs.addTab({
+ id: "clipboard-dialog-import-tab-library",
+ label: RED._("library.library")
+ });
+
+ tabs.activateTab("clipboard-dialog-import-tab-"+mode);
+ if (mode === 'clipboard') {
+ setTimeout(function() {
+ $("#clipboard-import").focus();
+ },100)
+ }
+
+
+ $("#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-import-tab-library-browser"),
+ onselect: function(file) {
+ if (file && file.label && !file.children) {
+ $("#clipboard-dialog-ok").button("enable");
+ } else {
+ $("#clipboard-dialog-ok").button("disable");
+ }
+ }
+ })
+ loadFlowLibrary(libraryBrowser,true);
+
dialogContainer.i18n();
$("#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 +450,62 @@ 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();
+ activeTab = 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();
+ libraryBrowser.focus();
+ }
+
+ }
+ });
+ tabs.addTab({
+ id: "clipboard-dialog-export-tab-clipboard",
+ label: RED._("clipboard.clipboard")
+ });
+ tabs.addTab({
+ id: "clipboard-dialog-export-tab-library",
+ label: RED._("library.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"),
+ folderTools: true,
+ onselect: function(file) {
+ if (file && file.label && !file.children) {
+ $("#clipboard-dialog-tab-library-name").val(file.label);
+ }
+ }
+ })
+ loadFlowLibrary(libraryBrowser,false);
+
+ $("#clipboard-dialog-tab-library-name").val("flows.json").select();
+
dialogContainer.i18n();
var format = RED.settings.flowFilePretty ? "export-format-full" : "export-format-mini";
@@ -307,6 +529,8 @@ RED.clipboard = (function() {
flow = JSON.stringify(nodes);
}
$("#clipboard-export").val(flow);
+ setTimeout(function() { $("#clipboard-export").scrollTop(0); },50);
+
$("#clipboard-export").focus();
}
});
@@ -314,7 +538,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 +580,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,29 +604,49 @@ 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();
}
+ 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() {
$("#dropTarget").hide();
RED.keyboard.remove("escape");
@@ -460,6 +703,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 +712,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/menu.js b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js
index 612bf4516..adac42463 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js
@@ -263,6 +263,5 @@ RED.menu = (function() {
addItem: addItem,
removeItem: removeItem,
setAction: setAction
- //TODO: add an api for replacing a submenu - see library.js:loadFlowLibrary
}
})();
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..0b21ca146 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
* }
@@ -51,8 +51,55 @@
var that = this;
this.element.addClass('red-ui-treeList');
+ this.element.attr("tabIndex",0);
var wrapper = $('',{class:'red-ui-treeList-container'}).appendTo(this.element);
-
+ this.element.on('keydown', function(evt) {
+ var selected = that._topList.find(".selected").parent().data('data');
+ if (!selected && (evt.keyCode === 40 || evt.keyCode === 38)) {
+ that.select(that._data[0]);
+ return;
+ }
+ var target;
+ switch(evt.keyCode) {
+ case 37: // LEFT
+ if (selected.children&& selected.treeList.container.hasClass("expanded")) {
+ selected.treeList.collapse()
+ } else if (selected.parent) {
+ target = selected.parent;
+ }
+ break;
+ case 38: // UP
+ target = that._getPreviousSibling(selected);
+ if (target) {
+ target = that._getLastDescendant(target);
+ }
+ if (!target && selected.parent) {
+ target = selected.parent;
+ }
+ break;
+ case 39: // RIGHT
+ if (selected.children) {
+ if (!selected.treeList.container.hasClass("expanded")) {
+ selected.treeList.expand()
+ }
+ }
+ break
+ case 40: //DOWN
+ if (selected.children && Array.isArray(selected.children) && selected.children.length > 0 && selected.treeList.container.hasClass("expanded")) {
+ target = selected.children[0];
+ } else {
+ target = that._getNextSibling(selected);
+ while (!target && selected.parent) {
+ selected = selected.parent;
+ target = that._getNextSibling(selected);
+ }
+ }
+ break
+ }
+ if (target) {
+ that.select(target);
+ }
+ });
this._data = [];
this._topList = $('').css({
@@ -66,34 +113,83 @@
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) {
this.data(this.options.data);
}
},
- _addChildren: function(container,children,depth) {
+ _getLastDescendant: function(item) {
+ // Gets the last visible descendant of the item
+ if (!item.children || !item.treeList.container.hasClass("expanded") || item.children.length === 0) {
+ return item;
+ }
+ return this._getLastDescendant(item.children[item.children.length-1]);
+ },
+ _getPreviousSibling: function(item) {
+ var candidates;
+ if (!item.parent) {
+ candidates = this._data;
+ } else {
+ candidates = item.parent.children;
+ }
+ var index = candidates.indexOf(item);
+ if (index === 0) {
+ return null;
+ } else {
+ return candidates[index-1];
+ }
+ },
+ _getNextSibling: function(item) {
+ var candidates;
+ if (!item.parent) {
+ candidates = this._data;
+ } else {
+ candidates = item.parent.children;
+ }
+ var index = candidates.indexOf(item);
+ if (index === candidates.length - 1) {
+ return null;
+ } else {
+ return candidates[index+1];
+ }
+ },
+ _addChildren: function(container,parent,children,depth) {
var that = this;
var subtree = $('').appendTo(container).editableList({
addButton: false,
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);
- // $('').css({
"background-position": (35+depth*15)+'px 50%'
}).appendTo(container);
}
+ } else {
+ item.treeList.childList.slideDown('fast');
+ done && done();
+ }
+ container.addClass("expanded");
+ }
+ item.treeList.collapse = function() {
+ item.treeList.childList.slideUp('fast');
+ container.removeClass("expanded");
+ }
+
+ $(''+
+ ''+
+ ''+
+ ''+
+ ''+
+ ''+
+ ''+
+ ''+
+ '
'+
+ ''+
+ ''+
+ ''+
+ ''+
+ ''+
+ ''+
+ ' '
- var _librarySaveConfirm = '';
- var _librarySave = '';
- var _libraryLookup = '';
+ var _librarySave = ' ').appendTo(label);
+ // $(' ').appendTo(label);
+ label.click(function(e) {
+ if (container.hasClass("expanded")) {
+ if (item.hasOwnProperty('selected') || label.hasClass("selected")) {
+ item.treeList.collapse();
+ }
+ } else {
+ item.treeList.expand();
}
- container.toggleClass("expanded");
})
} else {
$('').appendTo(label);
@@ -140,21 +284,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,item.children,depth).hide();
}
if (item.expanded) {
- label.click();
+ item.treeList.expand();
}
}
},
@@ -168,6 +318,8 @@
for (var i=0; i'+
+ ''+
+ ''
+ 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.getSelected();
+ if (!selectedPath.children) {
+ selectedPath = selectedPath.parent;
+ }
- function loadFlowLibrary() {
- $.getJSON("library/flows",function(data) {
- //console.log(data);
-
- var buildMenu = function(data,root) {
- var i;
- var li;
- var a;
- var ul = document.createElement("ul");
- if (root === "") {
- ul.id = "menu-item-import-library-submenu";
- }
- ul.className = "dropdown-menu";
- if (data.d) {
- for (i in data.d) {
- if (data.d.hasOwnProperty(i)) {
- li = document.createElement("li");
- li.className = "dropdown-submenu pull-left";
- a = document.createElement("a");
- a.href="#";
- var label = i.replace(/^@.*\//,"").replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/g," ").replace(/_/g," ");
- a.innerText = label;
- li.appendChild(a);
- li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i));
- ul.appendChild(li);
- }
- }
- }
- if (data.f) {
- for (i in data.f) {
- if (data.f.hasOwnProperty(i)) {
- li = document.createElement("li");
- a = document.createElement("a");
- a.href="#";
- a.innerText = data.f[i];
- a.flowName = root+(root!==""?"/":"")+data.f[i];
- a.onclick = function() {
- $.get('library/flows/'+this.flowName, function(data) {
- RED.view.importNodes(data);
- });
- };
- li.appendChild(a);
- ul.appendChild(li);
- }
- }
- }
- return ul;
- };
- var examples;
- if (data.d && data.d._examples_) {
- examples = data.d._examples_;
- delete data.d._examples_;
+ 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 +199,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 +210,346 @@ 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("local",options.url, "", function(items) {
+ var listing = [{
+ library: "local",
+ type: options.url,
+ icon: 'fa fa-hdd-o',
+ label: RED._("library.types.local"),
+ path: "",
+ expanded: true,
+ writable: false,
+ children: [{
+ icon: 'fa fa-cube',
+ label: options.type,
+ path: options.type+"/",
+ expanded: true,
+ children: items
+ }]
+ }]
+ loadLibraryBrowser.data(listing);
});
+ libraryEditor = ace.edit('node-dialog-library-load-preview-text',{
+ useWorker: false
+ });
+ 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("local",options.url, "", function(items) {
+ var listing = [{
+ icon: 'fa fa-archive',
+ label: RED._("library.types.local"),
+ path: "",
+ expanded: true,
+ writable: false,
+ children: [{
+ icon: 'fa fa-cube',
+ label: options.type,
+ path: options.type+"/",
+ expanded: true,
+ children: items
+ }]
+ }]
+ 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 dirList = $("").css({width: "100%", height: "100%"}).appendTo(panes)
+ .treeList({}).on('treelistselect', function(event, item) {
+ if (options.onselect) {
+ options.onselect(item);
+ }
+ });
+ var itemTools = $("").css({position: "absolute",bottom:"6px",right:"8px"});
+ var menuButton = $('')
+ .click(function(evt) {
+ evt.preventDefault();
+ evt.stopPropagation();
+ var elementPos = menuButton.offset();
+
+ var menuOptionMenu = RED.menu.init({id:"red-ui-library-browser-menu",
+ options: [
+ {id:"red-ui-library-browser-menu-addFolder",label:"New folder", onselect: function() {
+ var defaultFolderName = "new-folder";
+ var defaultFolderNameMatches = {};
+
+ var selected = dirList.treeList('selected');
+ if (!selected.children) {
+ selected = selected.parent;
+ }
+ var complete = function() {
+ 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 ')
- .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" );
- }
+ saveLibraryBrowser = RED.library.createBrowser({
+ container: $("#node-dialog-library-save-browser"),
+ addFolderButton: true,
+ onselect: function(item) {
+ if (item.label) {
+ if (!item.children) {
+ $("#node-dialog-library-save-filename").val(item.label);
+ item = item.parent;
+ }
+ if (item.writable === false) {
+ $("#node-dialog-library-save-button").button("disable");
+ } else {
+ $("#node-dialog-library-save-button").button("enable");
}
- ],
- 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
- ''
- ));
+ }
+ });
+ $("#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) {
+ var elementPrefix = activeLibrary.elementPrefix || "node-input-";
+ 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);
+ }
+ }
+ });
+ RED.panels.create({
+ container:$("#node-dialog-library-load-panes"),
+ dir: "horizontal"
+ });
+ RED.panels.create({
+ container:$("#node-dialog-library-load-preview"),
+ dir: "vertical"
+ });
},
create: createUI,
- loadFlowLibrary: loadFlowLibrary,
-
- export: exportFlow
+ createBrowser:createBrowser,
+ export: exportFlow,
+ loadLibraryFolder: loadLibraryFolder
}
})();
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..6b832f461 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,117 @@
}
}
}
+.clipboard-dialog-tab-clipboard {
+ padding: 10px;
+ textarea {
+ resize: none;
+ width: 100%;
+ border-radius: 4px;
+ font-family: monospace !important;
+ font-size: 13px !important;
+ height: 300px;
+ line-height: 1.3em;
+ padding: 6px 10px;
+ background: #F3E7E7;
+ color: #533;
+ }
+}
+
+.clipboard-dialog-tabs-content {
+ position: absolute;
+ top: 0;
+ left: 120px;
+ right: 0;
+ bottom: 0;
+ padding: 0;
+ background: white;
+ &>div {
+ height: calc(100% - 20px)
+ }
+}
+
+.clipboard-dialog-tab-library {
+ .form-row {
+ margin-left: 10px;
+ }
+}
+
+#clipboard-dialog {
+ form {
+ margin-bottom: 0;
+ }
+ .form-row:last-child {
+ margin-bottom: 0;
+ }
+}
+#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;
+}
+#clipboard-dialog-import-tab-library {
+ height: 100%;
+}
+#clipboard-dialog-import-tab-library-browser {
+ height: 100%;
+ box-sizing: border-box;
+}
+
+
+.red-ui-library-browser {
+ position: relative;
+ 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 {
+ // border: 1px solid $primary-border-color;
+}
+#node-dialog-library-load-panes {
+ border: 1px solid $primary-border-color;
+}
+
+
+#node-dialog-library-load-preview {
+ height: 100%;
+}
+
+#node-dialog-library-load-preview-text {
+ box-sizing: border-box;
+}
+#node-dialog-library-load-preview-details {
+ box-sizing: border-box;
+ .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/panels.scss b/packages/node_modules/@node-red/editor-client/src/sass/panels.scss
index 00fc771eb..b6b98e6ac 100644
--- a/packages/node_modules/@node-red/editor-client/src/sass/panels.scss
+++ b/packages/node_modules/@node-red/editor-client/src/sass/panels.scss
@@ -41,13 +41,13 @@
.red-ui-panels.red-ui-panels-horizontal {
height: 100%;
- .red-ui-panel {
+ &>.red-ui-panel {
vertical-align: top;
display: inline-block;
height: 100%;
width: calc(50% - 4px);
}
- .red-ui-panels-separator {
+ &>.red-ui-panels-separator {
vertical-align: top;
border-top: none;
border-bottom: none;
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..ea217cffe 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
@@ -15,7 +15,9 @@
**/
.red-ui-treeList {
-
+ &:focus {
+ outline: none !important;
+ }
}
.red-ui-treeList-container {
@@ -49,45 +51,49 @@
transition: transform 0.1s ease-in-out;
}
.red-ui-editableList {
- display: none;
+ // display: none;
}
&.expanded {
& > .red-ui-treeList-label .fa-angle-right {
transform: rotate(90deg)
}
- & > .red-ui-editableList {
- display: block
- }
- & > .red-ui-treeList-spinner {
- display: block;
- }
+ // & > .red-ui-editableList {
+ // display: block
+ // }
+ // & > .red-ui-treeList-spinner {
+ // display: block;
+ // }
}
}
}
-label.red-ui-treeList-label {
- display: block;
- width: auto;
-}
.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;
+ position: relative;
- &: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;
}
@@ -101,7 +107,6 @@ label.red-ui-treeList-label {
text-align: center;
}
.red-ui-treeList-spinner {
- display: none;
height: 32px;
background: url(images/spin.svg) 50% 50% no-repeat;
background-size: auto 20px;
diff --git a/packages/node_modules/@node-red/registry/lib/library.js b/packages/node_modules/@node-red/registry/lib/library.js
index 9f7c6e8b2..1eea6ed56 100644
--- a/packages/node_modules/@node-red/registry/lib/library.js
+++ b/packages/node_modules/@node-red/registry/lib/library.js
@@ -16,7 +16,6 @@
var fs = require('fs');
var fspath = require('path');
-var when = require('when');
var runtime;
@@ -24,7 +23,7 @@ var exampleRoots = {};
var exampleFlows = null;
function getFlowsFromPath(path) {
- return when.promise(function(resolve,reject) {
+ return new Promise(function(resolve,reject) {
var result = {};
fs.readdir(path,function(err,files) {
var promises = [];
@@ -37,11 +36,11 @@ function getFlowsFromPath(path) {
promises.push(getFlowsFromPath(fullPath));
} else if (/\.json$/.test(file)){
validFiles.push(file);
- promises.push(when.resolve(file.split(".")[0]))
+ promises.push(Promise.resolve(file.split(".")[0]))
}
})
var i=0;
- when.all(promises).then(function(results) {
+ Promise.all(promises).then(function(results) {
results.forEach(function(r) {
if (typeof r === 'string') {
result.f = result.f||[];
@@ -62,21 +61,20 @@ function getFlowsFromPath(path) {
function addNodeExamplesDir(module,path) {
exampleRoots[module] = path;
return getFlowsFromPath(path).then(function(result) {
- exampleFlows = exampleFlows||{d:{}};
- exampleFlows.d[module] = result;
+ exampleFlows = exampleFlows||{};
+ exampleFlows[module] = result;
});
}
function removeNodeExamplesDir(module) {
delete exampleRoots[module];
- if (exampleFlows && exampleFlows.d) {
- delete exampleFlows.d[module];
+ if (exampleFlows) {
+ delete exampleFlows[module];
}
- if (exampleFlows && Object.keys(exampleFlows.d).length === 0) {
+ if (exampleFlows && Object.keys(exampleFlows).length === 0) {
exampleFlows = null;
}
}
-
function init() {
exampleRoots = {};
exampleFlows = null;
diff --git a/packages/node_modules/@node-red/runtime/lib/api/library.js b/packages/node_modules/@node-red/runtime/lib/api/library.js
index 6f6571463..31037858b 100644
--- a/packages/node_modules/@node-red/runtime/lib/api/library.js
+++ b/packages/node_modules/@node-red/runtime/lib/api/library.js
@@ -29,6 +29,7 @@ var api = module.exports = {
* Gets an entry from the library.
* @param {Object} opts
* @param {User} opts.user - the user calling the api
+ * @param {String} opts.library - the library
* @param {String} opts.type - the type of entry
* @param {String} opts.path - the path of the entry
* @return {Promise} - resolves when complete
@@ -36,12 +37,12 @@ var api = module.exports = {
*/
getEntry: function(opts) {
return new Promise(function(resolve,reject) {
- runtime.library.getEntry(opts.type,opts.path).then(function(result) {
- runtime.log.audit({event: "library.get",type:opts.type,path:opts.path});
+ runtime.library.getEntry(opts.library,opts.type,opts.path).then(function(result) {
+ runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path});
return resolve(result);
}).catch(function(err) {
if (err) {
- runtime.log.warn(runtime.log._("api.library.error-load-entry",{path:opts.path,message:err.toString()}));
+ runtime.log.warn(runtime.log._("api.library.error-load-entry",{library:opts.library,type:opts.type,path:opts.path,message:err.toString()}));
if (err.code === 'forbidden') {
err.status = 403;
return reject(err);
@@ -50,10 +51,10 @@ var api = module.exports = {
} else {
err.status = 400;
}
- runtime.log.audit({event: "library.get",type:opts.type,path:opts.path,error:err.code});
+ runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,path:opts.path,error:err.code});
return reject(err);
}
- runtime.log.audit({event: "library.get",type:opts.type,error:"not_found"});
+ runtime.log.audit({event: "library.get",library:opts.library,type:opts.type,error:"not_found"});
var error = new Error();
error.code = "not_found";
error.status = 404;
@@ -66,6 +67,7 @@ var api = module.exports = {
* Saves an entry to the library
* @param {Object} opts
* @param {User} opts.user - the user calling the api
+ * @param {String} opts.library - the library
* @param {String} opts.type - the type of entry
* @param {String} opts.path - the path of the entry
* @param {Object} opts.meta - any meta data associated with the entry
@@ -75,7 +77,7 @@ var api = module.exports = {
*/
saveEntry: function(opts) {
return new Promise(function(resolve,reject) {
- runtime.library.saveEntry(opts.type,opts.path,opts.meta,opts.body).then(function() {
+ runtime.library.saveEntry(opts.library,opts.type,opts.path,opts.meta,opts.body).then(function() {
runtime.log.audit({event: "library.set",type:opts.type,path:opts.path});
return resolve();
}).catch(function(err) {
@@ -91,30 +93,5 @@ var api = module.exports = {
return reject(error);
});
})
- },
- /**
- * Returns a complete listing of all entries of a given type in the library.
- * @param {Object} opts
- * @param {User} opts.user - the user calling the api
- * @param {String} opts.type - the type of entry
- * @return {Promise ').appendTo(label);
- label.click(function(e) {
+ item.treeList.addChild = function(newItem,select) {
+ item.treeList.childList.editableList('addItem',newItem)
+ newItem.parent = item;
+ item.children.push(newItem);
+ if (select) {
+ setTimeout(function() {
+ that.select(newItem)
+ },100);
+ }
+ }
+ item.treeList.expand = function(done) {
+ if (container.hasClass("expanded")) {
+ done && done();
+ return;
+ }
if (!container.hasClass("built") && typeof item.children === 'function') {
container.addClass('built');
var childrenAdded = false;
var spinner;
- item.children(function(children) {
+ var startTime = 0;
+ item.children(item,function(children) {
childrenAdded = true;
- that._addChildren(container,children,depth);
- if (spinner) {
- spinner.remove();
+ item.treeList.childList = that._addChildren(container,item,children,depth).hide();
+ var delta = Date.now() - startTime;
+ if (delta < 400) {
+ setTimeout(function() {
+ item.treeList.childList.slideDown('fast');
+ if (spinner) {
+ spinner.remove();
+ }
+ },400-delta);
+ } else {
+ item.treeList.childList.slideDown('fast');
+ if (spinner) {
+ spinner.remove();
+ }
}
+ done && done();
+ that._trigger("childrenloaded",null,item)
});
if (!childrenAdded) {
+ startTime = Date.now();
spinner = $('