node-red/packages/node_modules/@node-red/nodes/core/function/10-function.html

618 lines
24 KiB
HTML
Raw Normal View History

<script type="text/html" data-template-name="library-config">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)">
<input type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
</div>
</div>
<div class="form-row" style="margin-bottom: 2px; margin-top: 15px;">
<label style="width: 65%;"><i class="fa fa-cog"></i> <span>Import Libraries</span></label>
<input type="checkbox" id="node-config-input-showAll" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-showAll" style="width: auto;">Show All Libraries</label>
</div>
<div class="form-row "">
<ol id="node-input-libs-container"></ol>
</div>
</script>
<script type="text/javascript">
// object that maps from library name to its descriptor
var allLibs = {};
/**
* Add library descriptor
* @param {string} name - library name
*/
function addLib(name) {
var item = allLibs[name]
if (item) {
item.count++;
}
else {
allLibs[name] = {
name: name,
count: 1
};
}
}
/**
* Remove library descriptor if reference count=0
* @param {string} name - library name
*/
function removeLib(name) {
var item = allLibs[name];
if (item) {
item.count--;
if (item.count === 0) {
delete allLibs[name];
}
}
}
function currentLibs() {
var result = [];
var libs = $("#node-input-libs-container").editableList("items");
libs.each(function(i) {
var item = $(this);
var n = item.find(".node-input-libs-val").val();
if (n && (n !== "")) {
result.push(n);
}
});
return result;
}
/**
* Validate library spec including conflicts with other specs
* @param {string} name - library name
*/
function checkLib(name) {
var m0 = name.match(/^([^@]+)(@.*)?$/);
if (m0) {
var lname0 = m0[1];
var ver0 = m0[2];
var ok = true;
var current = currentLibs(libs);
var libs = Object.keys(allLibs).concat(current);
libs.forEach(function(lib) {
if (name !== lib) {
var m1 = lib.match(/^([^@]+)(@.*)?$/);
if (m1) {
var lname1 = m1[1];
var ver1 = m1[2];
if ((lname1 === lname0) && (ver0 !== ver1)) {
ok = false;
return;
}
}
}
});
return ok;
}
return false;
}
/**
* Update library list
*/
function updateLib(done) {
allLibs = {};
RED.nodes.eachConfig(function(n) {
if (n.type === "library-config") {
var libs = n.libs || [];
libs.forEach(function(lib) { addLib(lib.name); });
}
});
var root = RED.settings.apiRootUrl || "";
$.ajax({
headers: {
"Accept":"application/json"
},
cache: false,
url: root + "/function/modules",
success: function(data) {
data.forEach(function(lib) {
var name = lib.name;
if (lib.version && (lib.version !== "")) {
name += "@" +lib.version;
}
addLib(name);
});
done();
}
});
}
/**
* Register NPM library configuration node
*/
RED.nodes.registerType("library-config", {
category: "config",
defaults: {
name: {value: ""},
libs: {value: []},
showAll: {value: false}
},
label: function() {
if (this.name && (this.name !== "")) {
return this.name;
}
return "Library Set:"+this.id;
},
oneditprepare: function() {
var node = this;
var popovers = {};
$("#node-input-libs-container").css('min-height','250px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var disabled = (opt && !!opt.unused);
var row = $("<div/>").appendTo(container);
var fvar = $("<input/>", {
class: "node-input-libs-var",
placeholder: RED._("node-red:function.require.var"),
type: "text",
disabled: disabled
}).css({
width: "90px",
"margin-left": "5px"
}).appendTo(row);
var fmodule = $("<input/>", {
class: "node-input-libs-val",
placeholder: RED._("node-red:function.require.module"),
type: "text",
disabled: disabled
}).css({
width: "280px",
"margin-left": "5px"
}).appendTo(row);
fvar.on("change", function (e) {
opt.vname = $(this).val();
});
fmodule.on("change", function (e) {
var val = $(this).val();
if (!checkLib(val)) {
$(this).addClass("input-error");
var popover = RED.popover.tooltip($(this), "conflict in module spec");
popovers[i] = popover;
}
else {
$(this).removeClass("input-error");
var popover = popovers[i];
if (popover) {
popover.setContent(function () {
return null;
});
}
}
opt.name = val;
});
if (opt) {
if (opt.vname) {
fvar.val(opt.vname);
}
if (opt.name) {
fmodule.val(opt.name);
addLib(opt.name);
}
}
},
removeItem: function(item) {
removeLib(item.name);
},
removable: true,
sortable: true
});
var libs = node.libs ? node.libs : [];
libs.forEach(function(lib) {
var conf = {
vname: lib.vname,
name: lib.name
};
$("#node-input-libs-container").editableList("addItem", conf);
});
$("#node-config-input-showAll").on("change", function () {
var checked = $(this).prop("checked");
var fun = null;
if (checked) {
fun = null;
}
else {
fun = function(item) {
return (!item.unused) ||
((item.vname && (item.vname !== "")) &&
(item.name && (item.name !== "")));
};
}
$("#node-input-libs-container").editableList("filter", fun);
});
updateLib(function () {
Object.values(allLibs).forEach(function(lib) {
function pred(x) {
return (x.name === lib.name);
}
if (libs.find(pred)) {
return;
}
var conf = {
vname: "",
name: lib.name,
unused: true
};
$("#node-input-libs-container").editableList("addItem", conf);
});
$("#node-config-input-showAll").change();
});
},
oneditsave: function() {
var node = this;
var libs = $("#node-input-libs-container").editableList("items");
var oldLibs = node.libs || [];
var newLibs = [];
node.libs = newLibs;
libs.each(function(i) {
var item = $(this);
var v = item.find(".node-input-libs-var").val();
var n = item.find(".node-input-libs-val").val();
if (!v || (v === "") ||
!n || (n === "")) {
return;
}
newLibs.push({
vname: v,
name: n
});
});
},
oneditresize: function(size) {
var height = size.height;
$("#node-input-libs-container").editableList("height", height -60);
}
});
</script>
2013-09-05 16:02:48 +02:00
<script type="text/html" data-template-name="function">
2013-09-05 16:02:48 +02:00
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></div>
2013-09-05 16:02:48 +02:00
</div>
<div class="form-row">
<ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"></ul>
2013-09-05 16:02:48 +02:00
</div>
2020-05-11 07:37:14 +02:00
<div id="func-tabs-content" style="min-height: calc(100% - 95px);">
<div id="func-tab-init" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-initialize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
2020-05-11 07:37:14 +02:00
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-init-editor" ></div>
</div>
</div>
<div id="func-tab-body" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-func" autofocus="autofocus">
<input type="hidden" id="node-input-noerr">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
2020-05-11 07:37:14 +02:00
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 220px; min-height:120px; margin-top: 30px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div>
<div class="form-row" style="margin-bottom: 0px">
<label for="node-input-outputs"><i class="fa fa-random"></i> <span data-i18n="function.label.outputs"></span></label>
<input id="node-input-outputs" style="width: 60px;" value="1">
</div>
</div>
<div id="func-tab-finalize" style="display:none">
<div class="form-row" style="margin-bottom: 0px;">
<input type="hidden" id="node-input-finalize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
2020-05-11 07:37:14 +02:00
<div style="position: absolute; right:0; bottom: calc(100% + 3px);"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<div style="height: 250px; min-height:150px; margin-top: 30px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
</div>
</div>
<div id="func-tab-config" style="display:none">
<div class="form-row">
<label><i class="fa fa-wrench"></i> <span>Use Library</span></label>
<input type="text" id="node-input-libs">
</div>
<div class="form-row" style="height: 250px; min-height: 150px">
<ol id="node-input-require-container"></ol>
</div>
</div>
2013-09-05 16:02:48 +02:00
</div>
2013-09-05 16:02:48 +02:00
</script>
<script type="text/javascript">
RED.nodes.registerType('function',{
color:"#fdd0a2",
category: 'function',
defaults: {
name: {value:""},
func: {value:"\nreturn msg;"},
outputs: {value:1},
noerr: {value:0,required:true,validate:function(v) { return !v; }},
initialize: {value:""},
finalize: {value:""},
libs: {value:"", type:"library-config", required:false}
2013-09-05 16:02:48 +02:00
},
inputs:1,
outputs:1,
icon: "function.svg",
2013-09-05 16:02:48 +02:00
label: function() {
return this.name||this._("function.function");
2013-09-05 16:02:48 +02:00
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
2013-09-05 16:02:48 +02:00
oneditprepare: function() {
2015-02-13 01:15:07 +01:00
var that = this;
var tabs = RED.tabs.create({
id: "func-tabs",
onchange: function(tab) {
$("#func-tabs-content").children().hide();
$("#" + tab.id).show();
}
});
tabs.addTab({
id: "func-tab-init",
label: that._("function.label.initialize")
});
tabs.addTab({
id: "func-tab-body",
label: that._("function.label.function")
});
tabs.addTab({
id: "func-tab-finalize",
label: that._("function.label.finalize")
});
tabs.addTab({
id: "func-tab-config",
label: "Config"
});
tabs.activateTab("func-tab-body");
2013-09-05 16:02:48 +02:00
$( "#node-input-outputs" ).spinner({
2019-09-30 10:54:05 +02:00
min:0,
change: function(event, ui) {
var value = this.value;
if (!value.match(/^\d+$/)) { value = 1; }
else if (value < this.min) { value = this.min; }
if (value !== this.value) { $(this).spinner("value", value); }
}
2013-09-05 16:02:48 +02:00
});
var buildEditor = function(id, value, defaultValue) {
var editor = RED.editor.createEditor({
id: id,
mode: 'ace/mode/nrjavascript',
value: value || defaultValue || "",
globals: {
msg:true,
context:true,
RED: true,
util: true,
flow: true,
global: true,
console: true,
Buffer: true,
setTimeout: true,
clearTimeout: true,
setInterval: true,
clearInterval: true
}
});
if (defaultValue && value === "") {
editor.moveCursorTo(defaultValue.split("\n").length - 1, 0);
}
return editor;
2020-05-11 07:37:14 +02:00
}
this.initEditor = buildEditor('node-input-init-editor',$("#node-input-initialize").val(),RED._("node-red:function.text.initialize"))
this.editor = buildEditor('node-input-func-editor',$("#node-input-func").val())
this.finalizeEditor = buildEditor('node-input-finalize-editor',$("#node-input-finalize").val(),RED._("node-red:function.text.finalize"))
2015-02-13 01:15:07 +01:00
RED.library.create({
url:"functions", // where to get the data from
type:"function", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/nrjavascript",
fields:[
'name', 'outputs',
{
name: 'initialize',
get: function() {
return that.initEditor.getValue();
},
set: function(v) {
that.initEditor.setValue(v||RED._("node-red:function.text.initialize"), -1);
}
},
{
name: 'finalize',
get: function() {
return that.finalizeEditor.getValue();
},
set: function(v) {
that.finalizeEditor.setValue(v||RED._("node-red:function.text.finalize"), -1);
}
2020-05-22 16:43:17 +02:00
},
{
name: 'info',
get: function() {
return that.infoEditor.getValue();
},
set: function(v) {
that.infoEditor.setValue(v||"", -1);
}
}
],
ext:"js"
2013-09-05 16:02:48 +02:00
});
this.editor.focus();
var expandButtonClickHandler = function(editor) {
return function(e) {
e.preventDefault();
var value = editor.getValue();
RED.editor.editJavaScript({
value: value,
width: "Infinity",
cursor: editor.getCursorPosition(),
mode: "ace/mode/nrjavascript",
complete: function(v,cursor) {
editor.setValue(v, -1);
editor.gotoLine(cursor.row+1,cursor.column,false);
setTimeout(function() {
editor.focus();
},300);
}
})
}
}
$("#node-init-expand-js").on("click", expandButtonClickHandler(this.initEditor));
$("#node-function-expand-js").on("click", expandButtonClickHandler(this.editor));
$("#node-finalize-expand-js").on("click", expandButtonClickHandler(this.finalizeEditor));
RED.popover.tooltip($("#node-init-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-function-expand-js"), RED._("node-red:common.label.expand"));
RED.popover.tooltip($("#node-finalize-expand-js"), RED._("node-red:common.label.expand"));
$("#node-input-require-container").css('min-height','250px').css('min-width','450px').editableList({
addItem: function(container,i,opt) {
var row = $("<div/>").appendTo(container);
var fvar = $("<input/>", {
class: "node-input-require-var",
placeholder: RED._("node-red:function.require.var"),
type: "text",
disabled: true
}).css({
width: "130px",
"margin-left": "5px"
}).appendTo(row);
var fmodule = $("<input/>", {
class: "node-input-require-val",
placeholder: RED._("node-red:function.require.module"),
type: "text",
disabled: true
}).css({
width: "390px",
"margin-left": "5px"
}).appendTo(row);
if (opt) {
if (opt.vname) {
fvar.val(opt.vname);
}
if (opt.name) {
fmodule.val(opt.name);
}
}
},
addButton: false,
removable: false
});
function updateLibs() {
var id = $("#node-input-libs").val();
var node = RED.nodes.node(id);
if (node && node.libs) {
var libs = node.libs;
$("#node-input-require-container").editableList("empty");
libs.forEach(function (r) {
$("#node-input-require-container").editableList("addItem", r);
});
}
}
updateLibs();
$("#node-input-libs").on("change", function () {
updateLibs();
});
2013-09-05 16:02:48 +02:00
},
oneditsave: function() {
var node = this;
var noerr = 0;
$("#node-input-noerr").val(0);
var disposeEditor = function(editorName,targetName,defaultValue) {
var editor = node[editorName];
var annot = editor.getSession().getAnnotations();
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
noerr += annot.length;
break;
}
}
var val = editor.getValue();
if (defaultValue) {
if (val.trim() == defaultValue.trim()) {
val = "";
}
}
editor.destroy();
delete node[editorName];
$("#"+targetName).val(val);
}
disposeEditor("editor","node-input-func");
disposeEditor("initEditor","node-input-initialize", RED._("node-red:function.text.initialize"));
disposeEditor("finalizeEditor","node-input-finalize", RED._("node-red:function.text.finalize"));
$("#node-input-noerr").val(noerr);
this.noerr = noerr;
2016-01-04 17:53:32 +01:00
},
oneditcancel: function() {
var node = this;
node.editor.destroy();
delete node.editor;
node.initEditor.destroy();
delete node.initEditor;
node.finalizeEditor.destroy();
delete node.finalizeEditor;
},
2016-01-04 17:53:32 +01:00
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.length; i++) {
2016-01-04 17:53:32 +01:00
height -= $(rows[i]).outerHeight(true);
}
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop"))+parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
var height = size.height;
2020-05-11 07:37:14 +02:00
$("#node-input-init-editor").css("height", (height -105)+"px");
$("#node-input-func-editor").css("height", (height -145)+"px");
2020-05-11 07:37:14 +02:00
$("#node-input-finalize-editor").css("height", (height -105)+"px");
this.initEditor.resize();
this.editor.resize();
this.finalizeEditor.resize();
$("#node-input-require-container").css("height", (height -155)+"px");
2013-09-05 16:02:48 +02:00
}
});
</script>