1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00
node-red/editor/js/ui/library.js

506 lines
23 KiB
JavaScript
Raw Normal View History

2013-09-05 16:02:48 +02:00
/**
* Copyright JS Foundation and other contributors, http://js.foundation
2013-09-05 16:02:48 +02:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
2014-08-08 01:01:35 +02:00
RED.library = (function() {
2015-06-29 17:12:18 +02:00
var exportToLibraryDialog;
var elementPrefix = "node-input-";
2018-04-26 18:53:45 +02:00
var _librarySaveConfirm = '<div id="node-dialog-library-save-confirm" class="hide"><form class="form-horizontal"><div style="text-align: center; padding-top: 30px;" id="node-dialog-library-save-content"></div></form></div>';
var _librarySave = '<div id="node-dialog-library-save" class="hide"><form class="form-horizontal"><div class="form-row"><label for="node-dialog-library-save-folder" data-i18n="[append]library.folder"><i class="fa fa-folder-open"></i> </label><input type="text" id="node-dialog-library-save-folder" data-i18n="[placeholder]library.folderPlaceholder"></div><div class="form-row"><label for="node-dialog-library-save-filename" data-i18n="[append]library.filename"><i class="fa fa-file"></i> </label><input type="text" id="node-dialog-library-save-filename" data-i18n="[placeholder]library.filenamePlaceholder"></div></form></div>';
var _libraryLookup = '<div id="node-dialog-library-lookup" class="hide"><form class="form-horizontal"><div class="form-row"><ul id="node-dialog-library-breadcrumbs" class="breadcrumb"><li class="active"><a href="#" data-i18n="[append]library.breadcrumb"></a></li></ul></div><div class="form-row"><div style="vertical-align: top; display: inline-block; height: 100%; width: 30%; padding-right: 20px;"><div id="node-select-library" style="border: 1px solid #999; width: 100%; height: 100%; overflow:scroll;"><ul></ul></div></div><div style="vertical-align: top; display: inline-block;width: 65%; height: 100%;"><div style="height: 100%; width: 95%;" class="node-text-editor" id="node-select-library-text" ></div></div></div></form></div>';
2013-09-05 16:02:48 +02:00
function loadFlowLibrary() {
2014-04-21 00:07:54 +02:00
$.getJSON("library/flows",function(data) {
2014-08-08 01:01:35 +02:00
//console.log(data);
2013-09-05 16:02:48 +02:00
2014-08-08 01:01:35 +02:00
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";
}
2014-08-08 01:01:35 +02:00
ul.className = "dropdown-menu";
if (data.d) {
for (i in data.d) {
if (data.d.hasOwnProperty(i)) {
li = document.createElement("li");
2013-09-05 16:02:48 +02:00
li.className = "dropdown-submenu pull-left";
2014-08-08 01:01:35 +02:00
a = document.createElement("a");
2013-09-05 16:02:48 +02:00
a.href="#";
var label = i.replace(/^@.*\//,"").replace(/^node-red-contrib-/,"").replace(/^node-red-node-/,"").replace(/-/," ").replace(/_/," ");
a.innerHTML = label;
2013-09-05 16:02:48 +02:00
li.appendChild(a);
2014-08-08 01:01:35 +02:00
li.appendChild(buildMenu(data.d[i],root+(root!==""?"/":"")+i));
2013-09-05 16:02:48 +02:00
ul.appendChild(li);
}
}
2014-08-08 01:01:35 +02:00
}
if (data.f) {
for (i in data.f) {
if (data.f.hasOwnProperty(i)) {
li = document.createElement("li");
a = document.createElement("a");
2013-09-05 16:02:48 +02:00
a.href="#";
a.innerHTML = data.f[i];
2014-08-08 01:01:35 +02:00
a.flowName = root+(root!==""?"/":"")+data.f[i];
2013-09-05 16:02:48 +02:00
a.onclick = function() {
$.get('library/flows/'+this.flowName, function(data) {
RED.view.importNodes(data);
2013-09-05 16:02:48 +02:00
});
};
li.appendChild(a);
ul.appendChild(li);
}
}
2014-08-08 01:01:35 +02:00
}
return ul;
};
var examples;
if (data.d && data.d._examples_) {
examples = data.d._examples_;
delete data.d._examples_;
}
2014-08-08 01:01:35 +02:00
var menu = buildMenu(data,"");
$("#menu-item-import-examples").remove();
if (examples) {
RED.menu.addItem("menu-item-import",{id:"menu-item-import-examples",label:RED._("menu.label.examples"),options:[]})
$("#menu-item-import-examples-submenu").replaceWith(buildMenu(examples,"_examples_"));
}
2014-08-20 22:58:54 +02:00
//TODO: need an api in RED.menu for this
$("#menu-item-import-library-submenu").replaceWith(menu);
2013-09-05 16:02:48 +02:00
});
}
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
function createUI(options) {
var libraryData = {};
var selectedLibraryItem = null;
var libraryEditor = null;
elementPrefix = options.elementPrefix || "node-input-";
2015-06-29 17:12:18 +02:00
// Orion editor has set/getText
// ACE editor has set/getValue
// normalise to set/getValue
if (options.editor.setText) {
// Orion doesn't like having pos passed in, so proxy the call to drop it
options.editor.setValue = function(text,pos) {
options.editor.setText.call(options.editor,text);
}
}
if (options.editor.getText) {
options.editor.getValue = options.editor.getText;
}
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
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;
}
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
function buildFileList(root,data) {
var ul = document.createElement("ul");
2014-08-08 01:01:35 +02:00
var li;
2017-06-05 18:04:31 +02:00
for (var i=0; i<data.length; i++) {
2013-09-05 16:02:48 +02:00
var v = data[i];
if (typeof v === "string") {
// directory
2014-08-08 01:01:35 +02:00
li = buildFileListItem(v);
li.onclick = (function () {
2013-09-05 16:02:48 +02:00
var dirName = v;
return function(e) {
2014-04-21 00:07:54 +02:00
var bcli = $('<li class="active"><span class="divider">/</span> <a href="#">'+dirName+'</a></li>');
2015-06-29 17:12:18 +02:00
$("a",bcli).click(function(e) {
2014-08-08 01:01:35 +02:00
$(this).parent().nextAll().remove();
$.getJSON("library/"+options.url+root+dirName,function(data) {
$("#node-select-library").children().first().replaceWith(buildFileList(root+dirName+"/",data));
});
e.stopPropagation();
2013-09-05 16:02:48 +02:00
});
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));
2013-09-05 16:02:48 +02:00
});
}
2014-08-08 01:01:35 +02:00
})();
2014-08-19 23:58:52 +02:00
li.innerHTML = '<i class="fa fa-folder"></i> '+v+"</i>";
2013-09-05 16:02:48 +02:00
ul.appendChild(li);
} else {
// file
li = buildFileListItem(v);
li.innerHTML = 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);
2013-09-05 16:02:48 +02:00
}
}
return ul;
}
2015-06-29 17:12:18 +02:00
$('#'+elementPrefix+"name").css("width","calc(100% - 52px)").after(
'<div class="btn-group" style="margin-left:5px;">'+
2015-07-14 00:21:03 +02:00
'<a id="node-input-'+options.type+'-lookup" class="editor-button" data-toggle="dropdown"><i class="fa fa-book"></i> <i class="fa fa-caret-down"></i></a>'+
2013-09-05 16:02:48 +02:00
'<ul class="dropdown-menu pull-right" role="menu">'+
2015-05-22 01:40:27 +02:00
'<li><a id="node-input-'+options.type+'-menu-open-library" tabindex="-1" href="#">'+RED._("library.openLibrary")+'</a></li>'+
'<li><a id="node-input-'+options.type+'-menu-save-library" tabindex="-1" href="#">'+RED._("library.saveToLibrary")+'</a></li>'+
2013-09-05 16:02:48 +02:00
'</ul></div>'
);
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
$('#node-input-'+options.type+'-menu-open-library').click(function(e) {
2014-08-08 01:01:35 +02:00
$("#node-select-library").children().remove();
var bc = $("#node-dialog-library-breadcrumbs");
bc.children().first().nextAll().remove();
libraryEditor.setValue('',-1);
2015-06-29 17:12:18 +02:00
2014-08-08 01:01:35 +02:00
$.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();
2013-09-05 16:02:48 +02:00
});
2014-08-08 01:01:35 +02:00
$( "#node-dialog-library-lookup" ).dialog( "open" );
});
2015-06-29 17:12:18 +02:00
2014-08-08 01:01:35 +02:00
e.preventDefault();
2013-09-05 16:02:48 +02:00
});
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
$('#node-input-'+options.type+'-menu-save-library').click(function(e) {
2014-08-08 01:01:35 +02:00
//var found = false;
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
2014-08-08 01:01:35 +02:00
//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
// });
// }
//});
$( "#node-dialog-library-save" ).dialog( "open" );
e.preventDefault();
2013-09-05 16:02:48 +02:00
});
2015-06-29 17:12:18 +02:00
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
2013-09-05 16:02:48 +02:00
});
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
$( "#node-dialog-library-lookup" ).dialog({
2015-05-22 01:40:27 +02:00
title: RED._("library.typeLibrary", {type:options.type}),
2014-08-08 01:01:35 +02:00
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",
2014-08-08 01:01:35 +02:00
click: function() {
if (selectedLibraryItem) {
2017-06-05 18:04:31 +02:00
for (var i=0; i<options.fields.length; i++) {
2014-08-08 01:01:35 +02:00
var field = options.fields[i];
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
2013-09-05 16:02:48 +02:00
}
options.editor.setValue(libraryEditor.getValue(),-1);
2013-09-05 16:02:48 +02:00
}
2014-08-08 01:01:35 +02:00
$( this ).dialog( "close" );
2013-09-05 16:02:48 +02:00
}
}
2014-08-08 01:01:35 +02:00
],
open: function(e) {
var form = $("form",this);
form.height(form.parent().height()-30);
$("#node-select-library-text").height("100%");
$(".form-row:last-child",form).children().height(form.height()-60);
},
resize: function(e) {
var form = $("form",this);
form.height(form.parent().height()-30);
$(".form-row:last-child",form).children().height(form.height()-60);
}
2013-09-05 16:02:48 +02:00
});
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
function saveToLibrary(overwrite) {
var name = $("#"+elementPrefix+"name").val().replace(/(^\s*)|(\s*$)/g,"");
2014-08-08 01:01:35 +02:00
if (name === "") {
2015-05-22 01:40:27 +02:00
name = RED._("library.unnamedType",{type:options.type});
2013-09-05 16:02:48 +02:00
}
var filename = $("#node-dialog-library-save-filename").val().replace(/(^\s*)|(\s*$)/g,"");
var pathname = $("#node-dialog-library-save-folder").val().replace(/(^\s*)|(\s*$)/g,"");
2014-08-08 01:01:35 +02:00
if (filename === "" || !/.+\.js$/.test(filename)) {
2015-07-01 00:42:03 +02:00
RED.notify(RED._("library.invalidFilename"),"warning");
2013-09-05 16:02:48 +02:00
return;
}
2014-08-08 01:01:35 +02:00
var fullpath = pathname+(pathname===""?"":"/")+filename;
2013-09-05 16:02:48 +02:00
if (!overwrite) {
//var pathnameParts = pathname.split("/");
//var exists = false;
//var ds = libraryData;
//for (var pnp in pathnameParts) {
// if (ds.d && pathnameParts[pnp] in ds.d) {
// ds = ds.d[pathnameParts[pnp]];
// } else {
// ds = null;
// break;
// }
//}
//if (ds && ds.f) {
// for (var f in ds.f) {
// if (ds.f[f].fn == fullpath) {
// exists = true;
// break;
// }
// }
//}
//if (exists) {
// $("#node-dialog-library-save-content").html(RED._("library.dialogSaveOverwrite",{libraryType:options.type,libraryName:fullpath}));
2013-09-05 16:02:48 +02:00
// $("#node-dialog-library-save-confirm").dialog( "open" );
// return;
//}
}
var queryArgs = [];
2015-02-26 18:08:20 +01:00
var data = {};
2017-06-05 18:04:31 +02:00
for (var i=0; i<options.fields.length; i++) {
2013-09-05 16:02:48 +02:00
var field = options.fields[i];
if (field == "name") {
2015-02-26 18:08:20 +01:00
data.name = name;
2013-09-05 16:02:48 +02:00
} else {
data[field] = $("#"+elementPrefix+field).val();
2013-09-05 16:02:48 +02:00
}
}
2015-06-29 17:12:18 +02:00
data.text = options.editor.getValue();
2015-02-26 18:08:20 +01:00
$.ajax({
url:"library/"+options.url+'/'+fullpath,
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
2015-07-01 00:42:03 +02:00
RED.notify(RED._("library.savedType", {type:options.type}),"success");
2015-02-26 18:08:20 +01:00
}).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");
}
2013-09-05 16:02:48 +02:00
});
}
$( "#node-dialog-library-save-confirm" ).dialog({
2015-05-22 01:40:27 +02:00
title: RED._("library.saveToLibrary"),
2014-08-08 01:01:35 +02:00
modal: true,
autoOpen: false,
width: 530,
height: 230,
buttons: [
{
text: RED._("common.label.cancel"),
2014-08-08 01:01:35 +02:00
click: function() {
$( this ).dialog( "close" );
2013-09-05 16:02:48 +02:00
}
2014-08-08 01:01:35 +02:00
},
{
text: RED._("common.label.save"),
class: "primary",
2014-08-08 01:01:35 +02:00
click: function() {
saveToLibrary(true);
2014-08-08 01:01:35 +02:00
$( this ).dialog( "close" );
}
}
]
2013-09-05 16:02:48 +02:00
});
$( "#node-dialog-library-save" ).dialog({
2015-05-22 01:40:27 +02:00
title: RED._("library.saveToLibrary"),
2014-08-08 01:01:35 +02:00
modal: true,
autoOpen: false,
width: 530,
height: 230,
buttons: [
{
text: RED._("common.label.cancel"),
2014-08-08 01:01:35 +02:00
click: function() {
$( this ).dialog( "close" );
2013-09-05 16:02:48 +02:00
}
2014-08-08 01:01:35 +02:00
},
{
text: RED._("common.label.save"),
class: "primary",
2014-08-08 01:01:35 +02:00
click: function() {
saveToLibrary(false);
2014-08-08 01:01:35 +02:00
$( this ).dialog( "close" );
}
}
]
2013-09-05 16:02:48 +02:00
});
}
2015-06-29 17:12:18 +02:00
function exportFlow() {
//TODO: don't rely on the main dialog
var nns = RED.nodes.createExportableNodeSet(RED.view.selection().nodes);
$("#node-input-library-filename").attr('nodes',JSON.stringify(nns));
exportToLibraryDialog.dialog( "open" );
}
2015-06-29 17:12:18 +02:00
2013-09-05 16:02:48 +02:00
return {
2014-11-11 11:15:02 +01:00
init: function() {
2018-04-26 18:53:45 +02:00
$(_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) {
2015-03-12 12:21:05 +01:00
if (!selection.nodes) {
RED.menu.setDisabled("menu-item-export",true);
RED.menu.setDisabled("menu-item-export-clipboard",true);
RED.menu.setDisabled("menu-item-export-library",true);
2015-03-12 12:21:05 +01:00
} else {
RED.menu.setDisabled("menu-item-export",false);
RED.menu.setDisabled("menu-item-export-clipboard",false);
RED.menu.setDisabled("menu-item-export-library",false);
2015-03-12 12:21:05 +01:00
}
});
2015-06-29 17:12:18 +02:00
if (RED.settings.theme("menu.menu-item-import-library") !== false) {
2015-04-13 14:55:17 +02:00
loadFlowLibrary();
}
exportToLibraryDialog = $('<div id="library-dialog" class="hide"><form class="dialog-form form-horizontal"></form></div>')
.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();
if (!/^\s*$/.test(flowName)) {
$.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($(
'<div class="form-row">'+
'<label for="node-input-library-filename" data-i18n="[append]editor:library.filename"><i class="fa fa-file"></i> </label>'+
'<input type="text" id="node-input-library-filename" data-i18n="[placeholder]editor:library.fullFilenamePlaceholder">'+
'<input type="text" style="display: none;" />'+ // Second hidden input to prevent submit on Enter
'</div>'
));
2014-11-11 11:15:02 +01:00
},
2013-09-05 16:02:48 +02:00
create: createUI,
loadFlowLibrary: loadFlowLibrary,
2015-06-29 17:12:18 +02:00
export: exportFlow
2013-09-05 16:02:48 +02:00
}
2014-08-08 01:01:35 +02:00
})();