node-red/packages/node_modules/@node-red/editor-client/src/js/ui/library.js

526 lines
22 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 loadLibraryBrowser;
var saveLibraryBrowser;
var libraryEditor;
var activeLibrary;
var _libraryLookup = '<div id="node-dialog-library-load" class="hide">'+
'<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+
'<div id="node-dialog-library-load-panes">'+
'<div class="red-ui-panel" id="node-dialog-library-load-browser"></div>'+
'<div class="red-ui-panel">'+
'<div id="node-dialog-library-load-preview">'+
'<div class="red-ui-panel" id="node-dialog-library-load-preview-text"></div>'+
'<div class="red-ui-panel" id="node-dialog-library-load-preview-details">'+
'<table id="node-dialog-library-load-preview-details-table" class="node-info"></table>'+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</div>'+
'</form>'+
'</div>'
var _librarySave = '<div id="node-dialog-library-save" class="hide">'+
'<form class="form-horizontal">'+
'<div style="height: 400px; position:relative; ">'+
'<div id="node-dialog-library-save-browser"></div>'+
'<div class="form-row">'+
'<label data-i18n="clipboard.export.exportAs"></label><input id="node-dialog-library-save-filename" type="text">'+
'</div>'+
'</div>'+
'</form>'+
'</div>'
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;
}
var queryArgs = [];
var data = {};
for (var i=0; i<activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
if (field == "name") {
data.name = name;
} else {
data[field] = $("#"+elementPrefix+field).val();
}
}
data.text = activeLibrary.editor.getValue();
var saveFlow = function() {
$.ajax({
url:"library/"+selectedPath.library+'/'+selectedPath.type+'/'+selectedPath.path + filename,
type: "POST",
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8"
}).done(function(data,textStatus,xhr) {
RED.notify(RED._("library.savedType", {type:activeLibrary.type}),"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) {
$( "#node-dialog-library-save" ).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()
$( "#node-dialog-library-save" ).dialog( "open" );
}
},{
text: RED._("clipboard.export.overwrite"),
click: function() {
notification.hideNotification()
saveFlow();
}
}]
});
} else {
saveFlow();
}
} else {
saveFlow();
}
}
2018-04-26 18:53:45 +02:00
function loadLibraryFolder(library,type,root,done) {
$.getJSON("library/"+library+"/"+type+"/"+root,function(data) {
var items = data.map(function(d) {
if (typeof d === "string") {
return {
library: library,
type: type,
icon: 'fa fa-folder',
label: d,
path: root+d+"/",
children: function(item,done) {
loadLibraryFolder(library,type,root+d+"/", function(children) {
item.children = children; // TODO: should this be done by treeList for us
done(children);
})
}
};
} else {
return {
library: library,
type: type,
icon: 'fa fa-file-o',
label: d.fn,
path: root+d.fn,
props: d
};
}
});
items.sort(function(A,B){
if (A.children && !B.children) {
return -1;
} else if (!A.children && B.children) {
return 1;
} else {
return A.label.localeCompare(B.label);
}
});
done(items);
});
}
var validateExportFilenameTimeout;
function validateExportFilename(filenameInput) {
if (validateExportFilenameTimeout) {
clearTimeout(validateExportFilenameTimeout);
}
validateExportFilenameTimeout = setTimeout(function() {
var filename = filenameInput.val().trim();
var valid = filename.length > 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);
}
2013-09-05 16:02:48 +02:00
function createUI(options) {
var libraryData = {};
var 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
// Add the library button to the name <input> in the edit dialog
$('#'+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) {
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
2014-08-08 01:01:35 +02:00
});
libraryEditor.renderer.$cursorLayer.element.style.opacity=0;
libraryEditor.$blockScrolling = Infinity;
2015-06-29 17:12:18 +02:00
$( "#node-dialog-library-load" ).dialog("option","title",RED._("library.typeLibrary", {type:options.type})).dialog( "open" );
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) {
activeLibrary = options;
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 filename = name.replace(/[^\w-]/g,"-");
if (filename === "") {
filename = "unnamed-"+options.type;
}
$("#node-dialog-library-save-filename").attr("value",filename+".js");
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);
});
2014-08-08 01:01:35 +02:00
$( "#node-dialog-library-save" ).dialog( "open" );
e.preventDefault();
2013-09-05 16:02:48 +02:00
});
2015-06-29 17:12:18 +02:00
}
function exportFlow() {
console.warn("Deprecated call to RED.library.export");
}
function createBrowser(options) {
var panes = $('<div class="red-ui-library-browser"></div>').appendTo(options.container);
var dirList = $("<div>").css({width: "100%", height: "100%"}).appendTo(panes)
.treeList({}).on('treelistselect', function(event, item) {
if (addButton) {
if (item.writable === false) {
addButton.prop('disabled', true);
} else {
addButton.prop('disabled', false);
2013-09-05 16:02:48 +02:00
}
}
if (options.onselect) {
options.onselect(item);
}
2013-09-05 16:02:48 +02:00
});
var addButton;
if (options.addFolderButton) {
var tools = $("<div>").css({position: "absolute",bottom:"3px",right:"25px"}).appendTo(panes)
addButton= $('<button type="button" class="editor-button editor-button-small"><i class="fa fa-plus"> <i class="fa fa-folder-o"></button>').appendTo(tools).click(function(e) {
var defaultFolderName = "new-folder";
var defaultFolderNameMatches = {};
var selected = dirList.treeList('selected');
if (!selected.children) {
selected = selected.parent;
}
selected.children.forEach(function(c) {
if (/^new-folder/.test(c.label)) {
defaultFolderNameMatches[c.label] = true
2014-08-08 01:01:35 +02:00
}
});
var folderIndex = 2;
while(defaultFolderNameMatches[defaultFolderName]) {
defaultFolderName = "new-folder-"+(folderIndex++)
2014-08-08 01:01:35 +02:00
}
selected.treeList.expand();
var input = $('<input type="text" class="red-ui-treeList-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<selected.children.length;i++) {
if (selected.children[i].label === val) {
cancelAdd();
return;
}
}
2014-08-08 01:01:35 +02:00
}
newItem.treeList.remove();
selected.treeList.addChild({
icon: "fa fa-folder",
children:[],
label: val,
path: newItem.path+val+"/"
});
2014-08-08 01:01:35 +02:00
}
var cancelAdd = function() {
newItem.treeList.remove();
}
input.on('keydown', function(evt) {
if (evt.keyCode === 13) {
evt.stopPropagation();
confirmAdd();
} else if (evt.keyCode === 27) {
evt.stopPropagation();
cancelAdd();
}
})
input.blur(function() {
confirmAdd();
})
selected.treeList.addChild(newItem);
setTimeout(function() {
input.focus();
input.select();
},200);
});
}
2015-06-29 17:12:18 +02:00
return {
getSelected: function() {
return dirList.treeList('selected');
},
data: function(content) {
dirList.treeList('data',content);
setTimeout(function() {
dirList.treeList('select',content[0]);
},100);
}
}
}
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);
$(_libraryLookup).appendTo(document.body);
$( "#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();
2015-03-12 12:21:05 +01:00
}
});
2015-06-29 17:12:18 +02:00
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");
}
}
}
});
$("#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; i<activeLibrary.fields.length; i++) {
var field = activeLibrary.fields[i];
$("#"+elementPrefix+field).val(selectedLibraryItem[field]);
}
activeLibrary.editor.setValue(libraryEditor.getValue(),-1);
}
$( this ).dialog( "close" );
}
}
],
open: function(e) {
$(this).parent().find(".ui-dialog-titlebar-close").hide();
},
close: function(e) {
if (libraryEditor) {
libraryEditor.destroy();
libraryEditor = null;
}
}
});
loadLibraryBrowser = RED.library.createBrowser({
container: $("#node-dialog-library-load-browser"),
onselect: function(file) {
var table = $("#node-dialog-library-load-preview-details-table").empty();
selectedLibraryItem = file.props;
if (file && file.label && !file.children) {
$.get("library/"+file.library+"/"+file.type+"/"+file.path, function(data) {
//TODO: nls + sanitize
var propRow = $('<tr class="node-info-node-row"><td>Type</td><td></td></tr>').appendTo(table);
$(propRow.children()[1]).text(activeLibrary.type);
if (file.props.hasOwnProperty('name')) {
propRow = $('<tr class="node-info-node-row"><td>Name</td><td>'+file.props.name+'</td></tr>').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 = $('<tr class="node-info-node-row"><td></td><td></td></tr>').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"
});
2014-11-11 11:15:02 +01:00
},
2013-09-05 16:02:48 +02:00
create: createUI,
createBrowser:createBrowser,
export: exportFlow,
loadLibraryFolder: loadLibraryFolder
2013-09-05 16:02:48 +02:00
}
2014-08-08 01:01:35 +02:00
})();