update according to comments

This commit is contained in:
Hiroyasu Nishiyama 2020-05-11 14:37:14 +09:00
parent c649e1b4a2
commit 5b197adf33
7 changed files with 69 additions and 29 deletions

View File

@ -9,7 +9,7 @@
<ul style="min-width: 600px; margin-bottom: 20px;" id="func-tabs"></ul>
</div>
<div id="func-tabs-content" style="min-height: calc(100% - 80px);">
<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;">
@ -17,8 +17,8 @@
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-init-editor" ></div>
<div style="position: absolute; right:0; margin-top:5px;"><button id="node-init-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<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>
@ -29,8 +29,8 @@
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-func-editor" ></div>
<div style="position: absolute; right:0; margin-top:5px;"><button id="node-function-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<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">
@ -45,8 +45,8 @@
<input type="hidden" id="node-input-finalize" autofocus="autofocus">
</div>
<div class="form-row node-text-editor-row" style="position:relative">
<div style="height: 250px; min-height:150px;" class="node-text-editor" id="node-input-finalize-editor" ></div>
<div style="position: absolute; right:0; margin-top:5px;"><button id="node-finalize-expand-js" class="red-ui-button red-ui-button-small"><i class="fa fa-expand"></i></button></div>
<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>
@ -129,19 +129,34 @@
value: $("#node-input-func").val(),
globals: globals
});
var initCode = $("#node-input-initialize").val();
var initText = RED._("node-red:function.text.initialize");
var isEmptyInitCode = (initCode === "");
this.initEditor = RED.editor.createEditor({
id: 'node-input-init-editor',
mode: 'ace/mode/nrjavascript',
value: $("#node-input-initialize").val(),
value: (isEmptyInitCode ? initText : initCode),
globals: globals
});
if (isEmptyInitCode) {
var count = initText.split("\n").length;
this.initEditor.moveCursorTo(count -1, 0);
}
var finalCode = $("#node-input-finalize").val();
var finalText = RED._("node-red:function.text.finalize");
var isEmptyFinalCode = (finalCode === "");
this.finalizeEditor = RED.editor.createEditor({
id: 'node-input-finalize-editor',
mode: 'ace/mode/nrjavascript',
value: $("#node-input-finalize").val(),
value: (isEmptyFinalCode ? finalText : finalCode),
globals: globals
});
if (isEmptyFinalCode) {
var count = finalText.split("\n").length;
this.finalizeEditor.moveCursorTo(count -1, 0);
}
RED.library.create({
url:"functions", // where to get the data from
@ -266,11 +281,19 @@
node.editor.destroy();
delete node.editor;
$("#node-input-initialize").val(node.initEditor.getValue());
var initCode = node.initEditor.getValue();
if (initCode === RED._("node-red:function.text.initialize")) {
initCode = "";
}
$("#node-input-initialize").val(initCode);
node.initEditor.destroy();
delete node.initEditor;
$("#node-input-finalize").val(node.finalizeEditor.getValue());
var finalCode = node.finalizeEditor.getValue();
if (finalCode === RED._("node-red:function.text.finalize")) {
finalCode = "";
}
$("#node-input-finalize").val(finalCode);
node.finalizeEditor.destroy();
delete node.finalizeEditor;
},
@ -298,9 +321,9 @@
this.editor.resize();
var height = size.height;
$("#node-input-init-editor").css("height", (height -100)+"px");
$("#node-input-func-editor").css("height", (height -120)+"px");
$("#node-input-finalize-editor").css("height", (height -100)+"px");
$("#node-input-init-editor").css("height", (height -105)+"px");
$("#node-input-func-editor").css("height", (height -140)+"px");
$("#node-input-finalize-editor").css("height", (height -105)+"px");
}
});
</script>

View File

@ -92,8 +92,8 @@ module.exports = function(RED) {
var node = this;
node.name = n.name;
node.func = n.func;
node.ini = n.initialize;
node.fin = n.finalize;
node.ini = n.initialize ? n.initialize : "";
node.fin = n.finalize ? n.finalize : "";
var handleNodeDoneCall = true;
@ -122,14 +122,11 @@ module.exports = function(RED) {
"};\n"+
node.func+"\n"+
"})(msg,send,done);";
var iniText = "(async function () {\n"+node.ini +"\n})();";
var finText = "(function () {\n"+node.fin +"\n})();";
var finScript = null;
var finOpt = null;
node.topic = n.topic;
node.outstandingTimers = [];
node.outstandingIntervals = [];
var initValue = undefined;
var sandbox = {
console:console,
util:util,
@ -256,9 +253,6 @@ module.exports = function(RED) {
if (index > -1) {
node.outstandingIntervals.splice(index,1);
}
},
getInitValue: function() {
return initValue;
}
};
if (util.hasOwnProperty('promisify')) {
@ -273,13 +267,15 @@ module.exports = function(RED) {
try {
var iniScript = null;
var iniOpt = null;
if (iniText || (iniText === "")) {
if (node.ini && (node.ini !== "")) {
var iniText = "(async function () {\n"+node.ini +"\n})();";
iniOpt = createVMOpt(node, " setup");
iniScript = new vm.Script(iniText, iniOpt);
}
node.script = vm.createScript(functionText, createVMOpt(node, ""));
if (finText || (finText === "")) {
finOpt = createVMOpt(node, "cleanup");
if (node.fin && (node.fin !== "")) {
var finText = "(function () {\n"+node.fin +"\n})();";
finOpt = createVMOpt(node, " cleanup");
finScript = new vm.Script(finText, finOpt);
}
var promise = Promise.resolve();
@ -380,7 +376,6 @@ module.exports = function(RED) {
});
promise.then(function (v) {
initValue = v;
var msgs = messages;
messages = [];
while (msgs.length > 0) {

View File

@ -21,7 +21,7 @@
the body of the message.</p>
<p>The function is expected to return a message object (or multiple message objects), but can choose
to return nothing in order to halt a flow.</p>
<p>Setup code executed before deploy can be specified in <b>Setup</b> tab. Also, cleanup code executed before flow shutdown can be specified in <b>Cleanup</b> tab.</p>
<p>Setup code executed once whenever Node-RED is started or a new flow configuration is deployed can be specified in <b>Setup</b> tab. Also, cleanup code executed when the node is being stopped or re-deployed can be specified in <b>Close</b> tab.</p>
<h3>Details</h3>
<p>See the <a target="_blank" href="http://nodered.org/docs/writing-functions.html">online documentation</a>
for more information on writing functions.</p>

View File

@ -208,9 +208,13 @@
"label": {
"function": "Function",
"initialize": "Setup",
"finalize": "Cleanup",
"finalize": "Close",
"outputs": "Outputs"
},
"text": {
"initialize": "// Code added here will be run once whenever Node-RED is started\n// or a new flow configuration is deployed.\n",
"finalize": "// Code added here will be run when the node is being stopped\n// or re-deployed.\n"
},
"error": {
"inputListener":"Cannot add listener to 'input' event within Function",
"non-message-returned":"Function tried to send a message of type __type__"

View File

@ -19,7 +19,7 @@
<p>入力メッセージは<code>msg</code>という名称のJavaScriptオブジェクトで受け渡されます。</p>
<p><code>msg</code>オブジェクトは<code>msg.payload</code>プロパティにメッセージ本体を保持するのが慣例です。</p>
<p>通常、コードはメッセージオブジェクト(もしくは複数のメッセージオブジェクト)を返却します。後続フローの実行を停止したい場合は、オブジェクトを返却しなくてもかまいません。</p>
<p>デプロイ前に実行すべき初期化コードを<b>初期化処理</b>タブに、フローの停止時に実行すべき終了処理コードを<b>終了処理</b>タブに指定できます。</p>
<p>Node-REDの開始時もしくはフローの設定をデプロイした際実行される初期化コードを<b>初期化処理</b>タブに、ノードの停止もしくは再デプロイ時に実行される終了処理コードを<b>終了処理</b>タブに指定できます。</p>
<h3>詳細</h3>
<p>コードの書き方の詳細については、<a target="_blank" href="http://nodered.org/docs/writing-functions.html">オンラインドキュメント</a>を参照してください。</p>
<h4>メッセージの送信</h4>

View File

@ -211,6 +211,10 @@
"finalize": "終了処理",
"outputs": "出力数"
},
"text": {
"initialize": "// ここに記述したコードはNode-REDの実行開始時\n// もしくは新しいフローのデプロイ時に一度だけ実行されます。\n",
"finalize": "// ここに記述したコードはノードの停止時\n// もしくは再デプロイ時に実行されます。\n"
},
"error": {
"inputListener": "コード内で'input'イベントのリスナを設定できません",
"non-message-returned": "Functionードが __type__ 型のメッセージ送信を試みました"

View File

@ -1349,6 +1349,20 @@ describe('function node', function() {
});
});
it('should wait completion of initialization', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload = global.get('X'); return msg;",initialize:"global.set('X', '-'); return new Promise((resolve, reject) => setTimeout(() => { global.set('X','bar'); resolve(); }, 500));"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property("payload", "bar");
done();
});
n1.receive({payload: "foo"});
});
});
it('should execute finalization', function(done) {
var flow = [{id:"n1",type:"function",wires:[],func:"return msg;",finalize:"global.set('X','bar');"}];
helper.load(functionNode, flow, function() {