Move all nodes into core subdirectory

This makes it easier to distinguish core nodes from those added later
This commit is contained in:
Nicholas O'Leary
2013-11-14 15:52:19 +00:00
parent affcc8ae65
commit 48dabffefc
70 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,371 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="inject">
<div class="form-row node-input-payload">
<label for="node-input-payload"><i class="icon-envelope"></i> Payload</label>
<input type="text" id="node-input-payload" placeholder="Payload">
</div>
<div class="form-row">
<label for="node-input-topic"><i class="icon-tasks"></i> Topic</label>
<input type="text" id="node-input-topic" placeholder="Topic">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-once" placeholder="once" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-once" style="width: 70%;">Fire once at start ?</label>
</div>
<div class="form-row">
<label for=""><i class="icon-repeat"></i> Repeat</label>
<select id="inject-time-type-select"><option value="none">None</option><option value="interval">interval</option><option value="interval-time">interval between times</option><option value="time">at a specific time</option></select>
<input type="hidden" id="node-input-repeat" placeholder="Payload">
<input type="hidden" id="node-input-crontab" placeholder="Payload">
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-interval">
every <input id="inject-time-interval-count" class="inject-time-count" value="1"></input>
<select style="width: 100px" id="inject-time-interval-units"><option value="s">seconds</option><option value="m">minutes</option><option value="h">hours</option></select><br/>
on <select disabled id="inject-time-interval-days" class="inject-time-days"></select>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-interval-time">
every <input id="inject-time-interval-time-units" class="inject-time-count" value="1"></input> minutes<br/>
between <select id="inject-time-interval-time-start" class="inject-time-times"></select>
and <select id="inject-time-interval-time-end" class="inject-time-times"></select><br/>
on <select id="inject-time-interval-time-days" class="inject-time-days"></select>
</div>
<div class="form-row inject-time-row hidden" id="inject-time-row-time">
at <input id="inject-time-time" value="12:00"></input><br/>
on <select id="inject-time-time-days" class="inject-time-days"></select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips">Tip: Injects Date.now() if no payload set</div>
<script>
{
$("#inject-time-type-select").change(function() {
var id = $("#inject-time-type-select option:selected").val();
$(".inject-time-row").hide();
$("#inject-time-row-"+id).show();
});
var days = [
{v:"*",t:"every day"},
{v:"1-5",t:"Mondays to Fridays"},
{v:"6-7",t:"Saturdays and Sundays"},
{v:"1",t:"Mondays"},
{v:"2",t:"Tuesdays"},
{v:"3",t:"Wednesdays"},
{v:"4",t:"Thursdays"},
{v:"5",t:"Fridays"},
{v:"6",t:"Saturdays"},
{v:"7",t:"Sundays"}
];
$(".inject-time-days").each(function() {
for (var d in days) {
$(this).append($("<option></option>").val(days[d].v).text(days[d].t));
}
});
$(".inject-time-times").each(function() {
for (var i=0;i<24;i++) {
var l = (i<10?"0":"")+i+":00";
$(this).append($("<option></option>").val(i).text(l));
}
});
$(".inject-time-count").spinner({
min:1,
max:60
});
$("#inject-time-interval-units").change(function() {
var units = $("#inject-time-interval-units option:selected").val();
$("#inject-time-interval-days").prop("disabled",(units == "s")?"disabled":false);
$(".inject-time-count").spinner("option","max",(units == "h")?24:60);
});
$.widget( "ui.injecttimespinner", $.ui.spinner, {
options: {
// seconds
step: 60 * 1000,
// hours
page: 60,
min:0,
max:(23*60+59)*60*1000
},
_parse: function( value ) {
if ( typeof value === "string" ) {
// already a timestamp
if ( Number( value ) == value ) {
return Number( value );
}
var p = value.split(":");
return ((p[0]*60)+Number(p[1]))*60*1000;
}
return value;
},
_format: function( value ) {
var d = new Date(value);
var h = d.getHours();
var m = d.getMinutes();
return ((h<10)?"0":"")+h+":"+((m<10)?"0":"")+m;
}
});
$("#inject-time-time").injecttimespinner();
};
</script>
</script>
<style>
.inject-time-row {
padding-left: 110px;
}
.inject-time-row select {
margin: 3px 0;
}
.inject-time-days {
width: 225px;
}
.inject-time-times {
width: 90px;
}
.inject-time-row > .ui-spinner {
height: 28px;
margin: 3px 0;
border-color: rgb(204, 204, 204);
}
#inject-time-time {
margin-top: 3px;
width: 75px;
}
.inject-time-count {
width: 30px !important;
}
.
</style>
<script type="text/x-red" data-help-name="inject">
<p>Pressing the button on the left side of the node allows a message on a topic to be injected into the flow. This is mainly for test purposes.</p>
<p>If no payload is specified the payload is set to the current time in millisecs since 1970. This allows subsequent functions to perform time based actions.</p>
<p>The repeat function does what it says on the tin and continuously sends the payload every x seconds.</p>
<p>The Fire once at start option actually waits 50mS before firing to give other nodes a chance to instantiate properly.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('inject',{
category: 'input',
color:"#a6bbcf",
defaults: {
name: {value:""},
topic: {value:""},
payload: {value:""},
repeat: {value:""},
crontab: {value:""},
once: {value:false}
},
inputs:0,
outputs:1,
icon: "inject.png",
label: function() {
return this.name||this.topic||this.payload||"inject";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
var repeattype = "none";
if (this.repeat != "" && this.repeat != 0) {
repeattype = "interval";
$("#inject-time-interval-units option").filter(function() {return $(this).val() == "s";}).attr('selected',true);
$("#inject-time-interval-count").val(this.repeat);
$("#inject-time-interval-days").prop("disabled","disabled");
} else if (this.crontab) {
var cronparts = this.crontab.split(" ");
var days = cronparts[4];
if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {
repeattype = "time";
// Fixed time
var time = cronparts[1]+":"+cronparts[0];
$("#inject-time-time").val(time);
$("#inject-time-type-select option").filter(function() {return $(this).val() == "s";}).attr('selected',true);
$("#inject-time-time-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);
} else if (cronparts[0] == "0") {
// interval - hours
var hours = cronparts[1].slice(2);
repeattype = "interval";
$("#inject-time-interval-days").prop("disabled",false);
$("#inject-time-interval-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);
$("#inject-time-interval-count").val(hours)
$("#inject-time-interval-units option").filter(function() {return $(this).val() == "h";}).attr('selected',true);
} else if (cronparts[1] == "*") {
// interval - minutes
var minutes = cronparts[0].slice(2);
repeattype = "interval";
$("#inject-time-interval-days").prop("disabled",false);
$("#inject-time-interval-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);
$("#inject-time-interval-count").val(minutes)
$("#inject-time-interval-units option").filter(function() {return $(this).val() == "m";}).attr('selected',true);
} else {
repeattype = "interval-time";
// interval - time period
var minutes = cronparts[0].slice(2);
$("#inject-time-interval-time-units").val(minutes);
$("#inject-time-interval-time-days option").filter(function() {return $(this).val() == days;}).attr('selected',true);
var time = cronparts[1];
var timeparts = time.split(",");
var start;
var end;
if (timeparts.length == 1) {
// 0 or 0-10
var hours = timeparts[0].split("-");
if (hours.length == 1) {
start = hours[0];
end = Number(hours[0])+1;
} else {
start = hours[0];
end = (Number(hours[1])+1)%24;
}
} else {
// 23,0 or 17-23,0-10 or 23,0-2 or 17-23,0
var startparts = timeparts[0].split("-");
start = startparts[0];
var endparts = timeparts[1].split("-");
if (endparts.length == 1) {
end = Number(endparts[0])+1;
} else {
end = Number(endparts[1])+1;
}
}
$("#inject-time-interval-time-start option").filter(function() {return $(this).val() == start;}).attr('selected',true);
$("#inject-time-interval-time-end option").filter(function() {return $(this).val() == end;}).attr('selected',true);
}
} else {
$("#inject-time-type-select option").filter(function() {return $(this).val() == "none";}).attr('selected',true);
}
$(".inject-time-row").hide();
$("#inject-time-type-select option").filter(function() {return $(this).val() == repeattype;}).attr('selected',true);
$("#inject-time-row-"+repeattype).show();
},
oneditsave: function() {
var repeat = "";
var crontab = "";
var type = $("#inject-time-type-select option:selected").val();
if (type == "none") {
// nothing
} else if (type == "interval") {
var count = $("#inject-time-interval-count").val();
var units = $("#inject-time-interval-units option:selected").val();
var days = $("#inject-time-interval-days option:selected").val();
if (units == "s") {
repeat = count;
} else {
if (units == "m") {
crontab = "*/"+count+" * * * "+days;
} else if (units == "h") {
crontab = "0 */"+count+" * * "+days;
}
}
} else if (type == "interval-time") {
var count = $("#inject-time-interval-time-units").val();
var startTime = Number($("#inject-time-interval-time-start option:selected").val());
var endTime = Number($("#inject-time-interval-time-end option:selected").val());
var days = $("#inject-time-interval-time-days option:selected").val();
var timerange = "";
if (startTime == endTime) {
//TODO: invalid
repeat = "";
crontab = "";
} else if (endTime == 0) {
timerange = startTime+"-23";
} else if (startTime+1 < endTime) {
timerange = startTime+"-"+(endTime-1);
} else if (startTime+1 == endTime) {
timerange = startTime;
} else {
var startpart = "";
var endpart = "";
if (startTime == 23) {
startpart = "23";
} else {
startpart = startTime+"-23";
}
if (endTime == 1) {
endpart = "0";
} else {
endpart = "0-"+(endTime-1);
}
timerange = startpart+","+endpart;
}
repeat = "";
crontab = "*/"+count+" "+timerange+" * * "+days;
} else if (type == "time") {
var time = $("#inject-time-time").val();
var days = $("#inject-time-time-days option:selected").val();
var parts = time.split(":");
repeat = "";
crontab = parts[1]+" "+parts[0]+" * * "+days;
}
$("#node-input-repeat").val(repeat);
$("#node-input-crontab").val(crontab);
},
button: {
onclick: function() {
var label = this.name||this.payload;
d3.xhr("inject/"+this.id).post(function(err,resp) {
if (err) {
if (err.status == 404) {
RED.notify("<strong>Error</strong>: inject node not deployed","error");
} else if (err.status == 500) {
RED.notify("<strong>Error</strong>: inject failed, see log for details.","error");
} else if (err.status == 0) {
RED.notify("<strong>Error</strong>: no response from server","error");
} else {
RED.notify("<strong>Error</strong>: unexpected error: ("+err.status+")"+err.response,"error");
}
} else if (resp.status == 200) {
RED.notify("Successfully injected: "+label,"success");
} else {
RED.notify("<strong>Error</strong>: unexpected response: ("+resp.status+") "+resp.response,"error");
}
});
}
}
});
</script>

View File

@@ -0,0 +1,93 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
try {
var cron = require("cron");
} catch(err) {
require("util").log("[inject] Warning: cannot find module 'cron'");
}
function InjectNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
this.payload = n.payload;
this.repeat = n.repeat;
this.crontab = n.crontab;
this.once = n.once;
var node = this;
this.interval_id = null;
this.cronjob = null;
if (this.repeat && !isNaN(this.repeat) && this.repeat > 0) {
this.repeat = this.repeat * 1000;
this.log("repeat = "+this.repeat);
this.interval_id = setInterval( function() {
node.emit("input",{});
}, this.repeat );
} else if (this.crontab) {
if (cron) {
this.log("crontab = "+this.crontab);
this.cronjob = new cron.CronJob(this.crontab,
function() {
node.emit("input",{});
},
null,true);
} else {
this.error("'cron' module not found");
}
}
if (this.once) {
setTimeout( function(){ node.emit("input",{}); }, 50);
}
this.on("input",function(msg) {
var msg = {topic:this.topic,payload:this.payload};
if (msg.payload == "") { msg.payload = Date.now(); }
this.send(msg);
msg = null;
});
}
RED.nodes.registerType("inject",InjectNode);
InjectNode.prototype.close = function() {
if (this.interval_id != null) {
clearInterval(this.interval_id);
this.log("inject: repeat stopped");
} else if (this.cronjob != null) {
this.cronjob.stop();
this.log("inject: cronjob stopped");
delete this.cronjob;
}
}
RED.app.post("/inject/:id", function(req,res) {
var node = RED.nodes.getNode(req.params.id);
if (node != null) {
try {
node.receive();
res.send(200);
} catch(err) {
res.send(500);
node.error("Inject failed:"+err);
console.log(err.stack);
}
} else {
res.send(404);
}
});

View File

@@ -0,0 +1,250 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="debug">
<div class="form-row">
<label for="node-input-complete"><i class="icon-list"></i> Output</label>
<select type="text" id="node-input-complete" style="display: inline-block; width: auto; vertical-align: top;">
<option value=false>Payload only</option>
<option value=true>Complete msg object</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="debug">
<p>The Debug node can be connected to the output of any node. It will display the timestamp, <b>msg.topic</b> and <b>msg.payload</b> fields of any messages it receives in the debug tab of the sidebar.
<br/>The sidebar can be accessed under the options drop-down in the top right corner.</p>
<p>The button to the right of the node will toggle it's output on and off so you can de-clutter the debug window.</p>
<p>If the payload is an object it will be stringified first for display and indicate that by saying "(Object) ".</p>
<p>If the payload is a buffer it will be stringified first for display and indicate that by saying "(Buffer) ".</p>
<p>Selecting any particular message will highlight (in red) the debug node that reported it. This is useful if you wire up multiple debug nodes.</p>
<p>Optionally can show the complete msg object - but the screen can get messy.</p>
<p>In addition any calls to node.warn or node.error will appear here.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('debug',{
category: 'output',
defaults: {
name: {value:""},
active: {value:true},
complete: {value:false}
},
label: function() {
return this.name||"debug";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
color:"#87a980",
inputs:1,
outputs:0,
icon: "debug.png",
align: "right",
button: {
toggle: "active",
onclick: function() {
var label = this.name||"debug";
d3.xhr("debug/"+this.id+"/"+(this.active?"enable":"disable")).post(function(err,resp) {
if (err) {
if (err.status == 404) {
RED.notify("<strong>Error</strong>: debug node not deployed","error");
} else if (err.status == 0) {
RED.notify("<strong>Error</strong>: no response from server","error");
} else {
RED.notify("<strong>Error</strong>: unexpected error: ("+err.status+")"+err.response,"error");
}
} else if (resp.status == 200) {
RED.notify("Successfully activated: "+label,"success");
} else if (resp.status == 201) {
RED.notify("Successfully deactivated: "+label,"success");
} else {
RED.notify("<strong>Error</strong>: unexpected response: ("+resp.status+") "+resp.response,"error");
}
});
}
}
});
var a = function() {
var content = document.createElement("div");
content.id = "tab-debug";
var toolbar = document.createElement("div");
toolbar.id = "debug-toolbar";
content.appendChild(toolbar);
toolbar.innerHTML = '<div class="btn-group pull-right"><a id="debug-tab-clear" title="clear log" class="btn btn-mini" href="#"><i class="icon-trash"></i></a></div> ';
var messages = document.createElement("div");
messages.id = "debug-content";
content.appendChild(messages);
RED.sidebar.addTab("debug",content);
function getTimestamp() {
var d = new Date();
return d.toUTCString().substring(5,25)+"."+d.getMilliseconds();
}
var sbc = document.getElementById("debug-content");
var errornotification = null;
var messageCount = 0;
function debugConnect() {
//console.log("debug ws connecting");
var path = location.hostname+":"+location.port+document.location.pathname;
path = path+(path.slice(-1) == "/"?"":"/")+"debug/ws";
path = "ws"+(document.location.protocol=="https:"?"s":"")+"://"+path;
var ws = new WebSocket(path);
ws.onopen = function() {
if (errornotification) {
errornotification.close();
errornotification = null;
}
//console.log("debug ws connected");
}
ws.onmessage = function(event) {
var o = JSON.parse(event.data);
//console.log(msg);
var msg = document.createElement("div");
msg.onmouseover = function() {
msg.style.borderRightColor = "#999";
RED.nodes.eachNode(function(node) {
if( node.id == o.id) {
node.highlighted = true;
node.dirty = true;
}
});
RED.view.redraw();
};
msg.onmouseout = function() {
msg.style.borderRightColor = "";
RED.nodes.eachNode(function(node) {
if( node.id == o.id) {
node.highlighted = false;
node.dirty = true;
}
});
RED.view.redraw();
};
var name = (o.name?o.name:o.id).toString().replace(/</g,"&lt;").replace(/>/g,"&gt;");
var topic = (o.topic||"").toString().replace(/</g,"&lt;").replace(/>/g,"&gt;");
var payload = (o.msg||"").toString().replace(/</g,"&lt;").replace(/>/g,"&gt;");
msg.className = 'debug-message'+(o.level?(' debug-message-level-'+o.level):'')
msg.innerHTML = '<span class="debug-message-date">'+getTimestamp()+'</span>'+
'<span class="debug-message-name">['+name+']</span>'+
(o.topic?'<span class="debug-message-topic">'+topic+'</span>':'')+
'<span class="debug-message-payload">'+payload+'</span>';
var atBottom = (sbc.scrollHeight-messages.offsetHeight-sbc.scrollTop) < 5;
messageCount++;
$(messages).append(msg);
if (messageCount > 200) {
$("#debug-content .debug-message:first").remove();
messageCount--;
}
if (atBottom) {
$(sbc).scrollTop(sbc.scrollHeight);
}
};
ws.onclose = function() {
if (errornotification == null) {
errornotification = RED.notify("<b>Error</b>: Lost connection to server","error",true);
}
setTimeout(debugConnect,1000);
}
}
debugConnect();
$("#debug-tab-clear").click(function() {
$(".debug-message").remove();
messageCount = 0;
RED.nodes.eachNode(function(node) {
node.highlighted = false;
node.dirty = true;
});
RED.view.redraw();
});
}();
</script>
<style>
#debug-content {
position: absolute;
top: 30px;
bottom: 0px;
left:0px;
right: 0px;
overflow-y: scroll;
}
#debug-toolbar {
padding: 3px 10px;
height: 24px;
background: #f3f3f3;
}
.debug-message {
cursor: pointer;
border-bottom: 1px solid #eee;
border-left: 8px solid #eee;
border-right: 8px solid #eee;
padding: 2px;
}
.debug-message-date {
background: #fff;
font-size: 9px;
color: #aaa;
padding: 1px 5px 1px 1px;
}
.debug-message-topic {
display: block;
background: #fff;
padding: 1px 5px;
font-size: 9px;
color: #caa;
}
.debug-message-name {
background: #fff;
padding: 1px 5px;
font-size: 9px;
color: #aac;
}
.debug-message-payload {
display: block;
padding: 2px;
background: #fff;
}
.debug-message-level-log {
border-left-color: #eee;
border-right-color: #eee;
}
.debug-message-level-warn {
border-left-color: #ffdf9d;
border-right-color: #ffdf9d;
}
.debug-message-level-error {
border-left-color: #f99;
border-right-color: #f99;
}
</style>

123
nodes/core/core/58-debug.js Normal file
View File

@@ -0,0 +1,123 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var util = require("util");
var ws = require('ws');
var events = require("events");
var debuglength = RED.settings.debugMaxLength||1000;
function DebugNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
this.complete = n.complete;
this.active = (n.active == null)||n.active;
this.on("input",function(msg) {
if (this.active) {
if (msg.payload instanceof Buffer) {
msg.payload = "(Buffer) "+msg.payload.toString();
}
if (this.complete == "true") {
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg,_path:msg._path});
} else {
if (typeof msg.payload !== "undefined") {
DebugNode.send({id:this.id,name:this.name,topic:msg.topic,msg:msg.payload,_path:msg._path});
}
}
}
});
}
RED.nodes.registerType("debug",DebugNode);
DebugNode.send = function(msg) {
if (msg.msg instanceof Error) {
msg.msg = msg.msg.toString();
}
else if (typeof msg.msg === 'object') {
var seen = [];
msg.msg = "(Object) " + JSON.stringify(msg.msg, function(key, value) {
if (typeof value === 'object' && value !== null) {
if (seen.indexOf(value) !== -1) { return "[circular]"; }
seen.push(value);
}
return value;
}," ");
seen = null;
}
else if (typeof msg.msg === "boolean") msg.msg = "(boolean) "+msg.msg.toString();
else if (msg.msg === 0) msg.msg = "0";
if (msg.msg.length > debuglength) {
msg.msg = msg.msg.substr(0,debuglength) +" ....";
}
for (var i in DebugNode.activeConnections) {
var ws = DebugNode.activeConnections[i];
try {
var p = JSON.stringify(msg);
ws.send(p);
} catch(err) {
util.log("[debug] ws error : "+err);
}
}
}
DebugNode.activeConnections = [];
var path = RED.settings.httpRoot || "/";
path = path + (path.slice(-1) == "/" ? "":"/") + "debug/ws";
DebugNode.wsServer = new ws.Server({server:RED.server,path:path});
DebugNode.wsServer.on('connection',function(ws) {
DebugNode.activeConnections.push(ws);
ws.on('close',function() {
for (var i in DebugNode.activeConnections) {
if (DebugNode.activeConnections[i] === ws) {
DebugNode.activeConnections.splice(i,1);
break;
}
}
});
});
DebugNode.logHandler = new events.EventEmitter();
DebugNode.logHandler.on("log",function(msg) {
if (msg.level == "warn" || msg.level == "error") {
DebugNode.send(msg);
}
});
RED.nodes.addLogHandler(DebugNode.logHandler);
RED.app.post("/debug/:id/:state", function(req,res) {
var node = RED.nodes.getNode(req.params.id);
var state = req.params.state;
if (node != null) {
if (state === "enable") {
node.active = true;
res.send(201);
} else if (state === "disable") {
node.active = false;
res.send(200);
} else {
res.send(404);
}
} else {
res.send(404);
}
});

View File

@@ -0,0 +1,63 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="exec">
<div class="form-row">
<label for="node-input-command"><i class="icon-file"></i> Command</label>
<input type="text" id="node-input-command" placeholder="command">
</div>
<div class="form-row">
<label for="node-input-append"><i class="icon-list"></i> Append</label>
<input type="text" id="node-input-append" placeholder="extra input">
</div>
<div class="form-row">
<label>&nbsp;</label>
<input type="checkbox" id="node-input-useSpawn" placeholder="spawn" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-useSpawn" style="width: 70%;">Use spawn() instead of exec() ?</label>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="exec">
<p>Call to a system command.<br/>This can be very dangerous...</p>
<p>Provides 3 outputs... stdout, stderr, and return code.</p>
<p>By default uses exec() which calls the command, waits for completion and then returns the complete result in one go. Along with any errors.</p>
<p>Optionally can use spawn() instead, which returns output from stdout and stderr as the command runs (ie one line at a time). On completion then returns a return code (on the 3rd output).</p>
<p>The optional append gets added to the command after the <b>msg.payload</b> (so you can do things like pipe etc.)</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('exec',{
category: 'advanced-function',
color:"darksalmon",
defaults: {
command: {value:"",required:true},
append: {value:""},
useSpawn: {value:""},
name: {value:""}
},
inputs:1,
outputs:3,
icon: "arrow-in.png",
align: "right",
label: function() {
return this.name||this.command;
}
});
</script>

View File

@@ -0,0 +1,75 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
function ExecNode(n) {
RED.nodes.createNode(this,n);
this.cmd = n.command;
this.append = n.append || "";
this.useSpawn = n.useSpawn;
var node = this;
this.on("input", function(msg) {
if (msg != null) {
if (this.useSpawn == true) {
// make the extra args into an array
// then prepend with the msg.payload
var arg = node.append.split(",");
if (msg.payload != " ") { arg.unshift(msg.payload); }
//console.log(arg);
var ex = spawn(node.cmd,arg);
ex.stdout.on('data', function (data) {
//console.log('[exec] stdout: ' + data);
msg.payload = data;
node.send([msg,null,null]);
});
ex.stderr.on('data', function (data) {
//console.log('[exec] stderr: ' + data);
msg.payload = data;
node.send([null,msg,null]);
});
ex.on('close', function (code) {
//console.log('[exec] result: ' + code);
msg.payload = code;
node.send([null,null,msg]);
});
}
else {
var cl = node.cmd+" "+msg.payload+" "+node.append;
var child = exec(cl, function (error, stdout, stderr) {
msg.payload = stdout;
var msg2 = {payload:stderr};
//console.log('[exec] stdout: ' + stdout);
//console.log('[exec] stderr: ' + stderr);
if (error !== null) {
var msg3 = {payload:error};
//console.log('[exec] error: ' + error);
}
node.send([msg,msg2,msg3]);
});
}
}
});
}
RED.nodes.registerType("exec",ExecNode);

View File

@@ -0,0 +1,97 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="function">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-func"><i class="icon-wrench"></i> Function</label>
<input type="hidden" id="node-input-func" autofocus="autofocus">
<div style="height: 250px;" class="node-text-editor" id="node-input-func-editor" ></div>
</div>
<div class="form-row">
<label for="node-input-outputs"><i class="icon-random"></i> Outputs</label>
<input id="node-input-outputs" style="width: 60px; height: 1.7em;" value="1">
</div>
</script>
<script type="text/x-red" data-help-name="function">
<p>The generic function block where you can write code to do more interesting things.</p>
<p>You can have multiple outputs - in which case the function expects you to return an array of messages... <pre>return [msg,msg2,...];</pre></p>
<p>You may return null for any or all outputs if you want to.</p>
<p>You can save your functions to a library (button to right of name field) - and likewise pick from that library.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('function',{
color:"#fdd0a2",
category: 'function',
defaults: {
name: {value:""},
func: {value:"// The received message is stored in 'msg'\n// It will have at least a 'payload' property:\n// console.log(msg.payload);\n// The 'context' object is available to store state\n// between invocations of the function\n// context = {};\n\n\nreturn msg;"},
outputs: {value:1}
},
inputs:1,
outputs:1,
icon: "function.png",
label: function() {
return this.name;
},
oneditprepare: function() {
$( "#node-input-outputs" ).spinner({
min:1
});
function functionDialogResize(ev,ui) {
$("#node-input-func-editor").css("height",(ui.size.height-235)+"px");
};
$( "#dialog" ).on("dialogresize", functionDialogResize);
$( "#dialog" ).one("dialogopen", function(ev) {
var size = $( "#dialog" ).dialog('option','sizeCache-function');
if (size) {
functionDialogResize(null,{size:size});
}
});
$( "#dialog" ).one("dialogclose", function(ev,ui) {
var height = $( "#dialog" ).dialog('option','height');
$( "#dialog" ).off("dialogresize",functionDialogResize);
});
var that = this;
require(["orion/editor/edit"], function(edit) {
that.editor = edit({
parent:document.getElementById('node-input-func-editor'),
lang:"js",
contents: $("#node-input-func").val()
});
RED.library.create({
url:"functions", // where to get the data from
type:"function", // the type of object the library is for
editor:that.editor, // the field name the main text body goes to
fields:['name','outputs']
});
$("#node-input-name").focus();
});
},
oneditsave: function() {
$("#node-input-func").val(this.editor.getText())
delete this.editor;
}
});
</script>

View File

@@ -0,0 +1,71 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var util = require("util");
var vm = require("vm");
var fs = require('fs');
var fspath = require('path');
function FunctionNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
this.func = n.func;
var functionText = "var results = (function(msg){"+this.func+"})(msg);";
this.topic = n.topic;
this.context = {global:RED.settings.functionGlobalContext || {}};
try {
this.script = vm.createScript(functionText);
this.on("input", function(msg) {
if (msg != null) {
var sandbox = {msg:msg,console:console,util:util,Buffer:Buffer,context:this.context};
try {
this.script.runInNewContext(sandbox);
var results = sandbox.results;
if (results == null) {
results = [];
} else if (results.length == null) {
results = [results];
}
if (msg._topic) {
for (var m in results) {
if (results[m]) {
if (util.isArray(results[m])) {
for (var n in results[m]) {
results[m][n]._topic = msg._topic;
}
} else {
results[m]._topic = msg._topic;
}
}
}
}
this.send(results);
} catch(err) {
this.error(err.message);
}
}
});
} catch(err) {
this.error(err.message);
}
}
RED.nodes.registerType("function",FunctionNode);
RED.library.register("functions");

View File

@@ -0,0 +1,91 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="template">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-row">
<label for="node-input-template"><i class="icon-wrench"></i> Template</label>
<input type="hidden" id="node-input-template" autofocus="autofocus">
<div style="height: 250px;" class="node-text-editor" id="node-input-template-editor" ></div>
</div>
</script>
<script type="text/x-red" data-help-name="template">
<p>Creates new messages based on a template.</p>
<p>Very useful for creating boilerplate web pages, emails, tweets and so on.</p>
<p>Uses the <i><a href="http://mustache.github.io/mustache.5.html" target="_new">Mustache</a></i> format.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('template',{
color:"rgb(243, 181, 103)",
category: 'function',
defaults: {
name: {value:""},
template: {value:"This is the payload: {{payload}}!"},
},
inputs:1,
outputs:1,
icon: "template.png",
label: function() {
return this.name;
},
oneditprepare: function() {
function templateDialogResize(ev,ui) {
$("#node-input-template-editor").css("height",(ui.size.height-200)+"px");
};
$( "#dialog" ).on("dialogresize", templateDialogResize);
$( "#dialog" ).one("dialogopen", function(ev) {
var size = $( "#dialog" ).dialog('option','sizeCache-template');
if (size) {
templateDialogResize(null,{size:size});
}
});
$( "#dialog" ).one("dialogclose", function(ev,ui) {
var height = $( "#dialog" ).dialog('option','height');
$( "#dialog" ).off("dialogresize",templateDialogResize);
});
var that = this;
require(["orion/editor/edit"], function(edit) {
that.editor = edit({
parent:document.getElementById('node-input-template-editor'),
lang:"html",
contents: $("#node-input-template").val()
});
RED.library.create({
url:"templates", // where to get the data from
type:"template", // the type of object the library is for
editor:that.editor, // the field name the main text body goes to
fields:['name']
});
$("#node-input-name").focus();
});
},
oneditsave: function() {
$("#node-input-template").val(this.editor.getText())
delete this.editor;
}
});
</script>

View File

@@ -0,0 +1,41 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var mustache = require("mustache");
var util = require("util");
var fs = require('fs');
function TemplateNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
this.template = n.template;
this.on("input", function(msg) {
if (msg != null) {
try {
msg.payload = mustache.render(this.template,msg)
this.send(msg);
} catch(err) {
this.error(err.message);
}
}
});
}
RED.nodes.registerType("template",TemplateNode);
RED.library.register("templates");

View File

@@ -0,0 +1,163 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<!-- First, the content of the edit dialog is defined. -->
<script type="text/x-red" data-template-name="delay">
<div class="form-row">
<label for="node-input-pauseType"><i class="icon-tasks"></i> Action</label>
<select id="node-input-pauseType" style="width:270px !important">
<option value="delay">Delay message</option>
<option value="rate">Limit rate to</option>
<option value="random">Random delay</option>
</select>
</div>
<div id="delay-details" class="form-row">
<label for="node-input-timeout"><i class="icon-time"></i> For</label>
<input type="text" id="node-input-timeout" placeholder="Time" style="direction:rtl; width:50px !important">
<select id="node-input-timeoutUnits" style="width:200px !important">
<option value="milliseconds">Milliseconds</option>
<option value="seconds">Seconds</option>
<option value="minutes">Minutes</option>
<option value="hours">Hours</option>
<option value="days">Days</option>
</select>
</div>
<div id="rate-details" class="form-row">
<label for="node-input-rate"><i class="icon-time"></i> To</label>
<input type="text" id="node-input-rate" placeholder="1" style="direction:rtl; width:50px !important">
<label for="node-input-reateUnits">message(s) per</label>
<select id="node-input-rateUnits" style="width:140px !important">
<option value="second">Second</option>
<option value="minute">Minute</option>
<option value="hour">Hour</option>
<option value="day">Day</option>
</select>
</div>
<div id="random-details" class="form-row">
<label for="node-input-randomFirst"><i class="icon-time"></i> Between</label>
<input type="text" id="node-input-randomFirst" placeholder="" style="directon:rtl; width:30px !important">
<label for="node-input-randomLast" style="width:20px"> & </label>
<input type="text" id="node-input-randomLast" placeholder="" style="directon:rtl; width:30px !important">
<select id="node-input-randomUnits" style="width:140px !important">
<option value="milliseconds">Milliseconds</option>
<option value="seconds">Seconds</option>
<option value="minutes">Minutes</option>
<option value="hours">Hours</option>
<option value="days">Days</option>
</select>
</div>
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<!-- Next, some simple help text is provided for the node. -->
<script type="text/x-red" data-help-name="delay">
<p>Introduces a delay into a flow or rate limts messges</p>
<p>Default delay is 5 seconds and rate limit of 1 msg/second, but both can be configured</p>
</script>
<!-- Finally, the node type is registered along with all of its properties -->
<script type="text/javascript">
RED.nodes.registerType('delay',{
category: 'function', // the palette category
color:"#E6E0F8",
defaults: { // defines the editable properties of the node
name: {value:""}, // along with default values.
pauseType: {value:"delay", required:true},
timeout: {value:"5", required:true, validate:RED.validators.number()},
timeoutUnits: {value:"seconds"},
rate: {value:"1", required:true, validate:RED.validators.number()},
rateUnits: {value: "second"},
randomFirst: {value:"1", required:true, validate:RED.validators.number()},
randomLast: {value:"5", required:true, validate:RED.validators.number()},
randomUnits: {value: "seconds"}
},
inputs:1, // set the number of inputs - only 0 or 1
outputs:1, // set the number of outputs - 0 to n
icon: "timer.png", // set the icon (held in public/icons)
label: function() { // sets the default label contents
if (this.pauseType == "delay") {
var units = this.timeoutUnits ? this.timeoutUnits.charAt(0) : "s";
return this.name||"delay "+this.timeout+" " + units;
} else if (this.pauseType == "rate") {
var units = this.rateUnits ? this.rateUnits.charAt(0) : "s";
return this.name||"limit "+this.rate+" msg/"+ units;
} else if (this.pauseType == "random") {
return "random";
}
return "foo";
},
labelStyle: function() { // sets the class to apply to the label
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$( "#node-input-timeout" ).spinner({min:1,max:60});
$( "#node-input-rate" ).spinner({min:1});
$( "#node-input-randomFirst" ).spinner({min:0});
$( "#node-input-randomLast" ).spinner({min:1});
if (this.pauseType == "delay") {
$("#delay-details").show();
$("#rate-details").hide();
$("#random-details").hide();
} else if (this.pauseType == "rate") {
$("#delay-details").hide();
$("#rate-details").show();
$("#random-details").hide();
} else if (this.pauseType == "random") {
$("#delay-details").hide();
$("#rate-details").hide();
$("#random-details").show();
}
if (!this.timeoutUnits) {
$("#node-input-timeoutUnits option").filter(function() {
return $(this).val() == 'seconds';
}).attr('selected', true);
}
if (!this.randomUnits) {
$("#node-input-randomUnits option").filter(function() {
return $(this).val() == 'seconds';
}).attr('selected', true);
}
$("#node-input-pauseType").on("change",function() {
if (this.value == "delay") {
$("#delay-details").show();
$("#rate-details").hide();
$("#random-details").hide();
} else if (this.value == "rate") {
$("#delay-details").hide();
$("#rate-details").show();
$("#random-details").hide();
} else if (this.value == "random") {
$("#delay-details").hide();
$("#rate-details").hide();
$("#random-details").show();
}
});
}
});
</script>

157
nodes/core/core/89-delay.js Normal file
View File

@@ -0,0 +1,157 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
//Simple node to introduce a pause into a flow
//Require main module
var RED = require(process.env.NODE_RED_HOME+"/red/red");
var node;
function random() {
var wait = node.randomFirst + (node.diff * Math.random());
if (node.buffer.length > 0) {
node.send(node.buffer.pop());
node.randomID = setTimeout(random,wait);
} else {
node.randomID = -1;
}
}
//main node definition
function DelayNode(n) {
RED.nodes.createNode(this,n);
this.pauseType = n.pauseType;
this.timeoutUnits = n.timeoutUnits;
this.randomUnits = n.randomUnits;
this.rateUnits = n.rateUnits;
if (n.timeoutUnits === "milliseconds") {
this.timeout = n.timout;
} else if (n.timeoutUnits === "seconds") {
this.timeout = n.timeout * 1000;
} else if (n.timeoutUnits === "minutes") {
this.timeout = n.timeout * (60 * 1000);
} else if (n.timeoutUnits === "hours") {
this.timeout = n.timeout * (60 * 60 * 1000);
} else if (n.timeoutUnits === "days") {
this.timeout = n.timeout * (24 * 60 * 60 * 1000);
}
if (n.rateUnits === "second") {
this.rate = 1000/n.rate;
} else if (n.rateUnits === "minute") {
this.rate = (60 * 1000)/n.rate;
} else if (n.rateUnits === "hour") {
this.rate = (60 * 60 * 1000)/n.rate;
} else if (n.rateUnits === "day") {
this.rate = (24 * 60 * 60 * 1000)/n.rate;
}
if (n.randomUnits === "milliseconds") {
this.randomFirst = n.randomFirst;
this.randomLast = n.randomLast;
} else if (n.randomUnits === "seconds") {
this.randomFirst = n.randomFirst * 1000;
this.randomLast = n.randomLast * 1000;
} else if (n.randomUnits === "minutes") {
this.randomFirst = n.randomFirst * (60 * 1000);
this.randomLast = n.randomLast * (60 * 1000);
} else if (n.randomUnits === "hours") {
this.randomFirst = n.randomFirst * (60 * 60 * 1000);
this.randomLast = n.randomLast * (60 * 60 * 1000);
} else if (n.randomUnits === "days") {
this.randomFirst = n.randomFirst * (24 * 60 * 60 * 1000);
this.randomLast = n.randomLast * (24 * 60 * 60 * 1000);
}
this.diff = this.randomLast - this.randomFirst;
this.name = n.name;
this.idList = [];
this.buffer = [];
this.intervalID = -1;
this.randomID = -1;
node= this;
if (this.pauseType === "delay") {
this.on("input", function(msg) {
var node= this;
var id;
id = setTimeout(function(){
node.idList.splice(node.idList.indexOf(id),1);
node.send(msg);
}, node.timeout);
this.idList.push(id);
});
this.on("close", function() {
for (var i=0; i<this.idList.length; i++ ) {
clearTimeout(this.idList[i]);
}
this.idList = [];
});
} else if (this.pauseType === "rate") {
this.on("input", function(msg) {
if ( node.intervalID !== -1) {
node.buffer.push(msg);
if (node.buffer.length > 1000) {
node.warn(this.name + " buffer exceeded 1000 messages");
}
} else {
node.send(msg);
node.intervalID = setInterval(function() {
if (node.buffer.length === 0) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
if (node.buffer.length > 0) {
node.send(node.buffer.shift());
}
},node.rate);
}
});
this.on("close", function() {
clearInterval(this.intervalID);
this.buffer = [];
});
} else if (this.pauseType === "random") {
this.on("input",function(msg){
node.buffer.push(msg);
if (node.randomID === -1) {
var wait = node.randomFirst + (node.diff * Math.random());
node.randomID = setTimeout(random,wait);
}
});
this.on("close", function (){
if (this.randomID !== -1) {
clearTimeout(node.randomID);
}
});
}
}
//register node
RED.nodes.registerType("delay",DelayNode);

View File

@@ -0,0 +1,86 @@
<!--
Copyright 2013 IBM Corp.
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.
-->
<script type="text/x-red" data-template-name="comment">
<div class="form-row">
<label for="node-input-name"><i class="icon-tag"></i> Comment</label>
<input type="text" id="node-input-name" placeholder="Comment">
</div>
<div class="form-row">
<label for="node-input-info" style="width: 100% !important;"><i class="icon-file"></i> More</label>
<input type="hidden" id="node-input-info" autofocus="autofocus">
<div style="height: 250px;" class="node-text-editor" id="node-input-info-editor" ></div>
</div>
<div class="form-tips">Tip: this isn't meant for War and Peace - but useful notes can be kept here.</div>
</script>
<script type="text/x-red" data-help-name="comment">
<p>Simple comment block.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('comment',{
category: 'function',
color:"#ffffff",
defaults: {
name: {value:""},
info: {value:""}
},
inputs:0,
outputs:0,
icon: "file.png",
label: function() {
return this.name||"";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$( "#node-input-outputs" ).spinner({
min:1
});
function functionDialogResize(ev,ui) {
$("#node-input-info-editor").css("height",(ui.size.height-235)+"px");
};
$( "#dialog" ).on("dialogresize", functionDialogResize);
$( "#dialog" ).one("dialogopen", function(ev) {
var size = $( "#dialog" ).dialog('option','sizeCache-function');
if (size) {
functionDialogResize(null,{size:size});
}
});
$( "#dialog" ).one("dialogclose", function(ev,ui) {
var height = $( "#dialog" ).dialog('option','height');
$( "#dialog" ).off("dialogresize",functionDialogResize);
});
var that = this;
require(["orion/editor/edit"], function(edit) {
that.editor = edit({
parent:document.getElementById('node-input-info-editor'),
lang:"text",
showLinesRuler:false,
showFoldingRuler:false,
contents: $("#node-input-info").val()
});
$("#node-input-name").focus();
});
},
oneditsave: function() {
$("#node-input-info").val(this.editor.getText());
delete this.editor;
}
});
</script>

View File

@@ -0,0 +1,23 @@
/**
* Copyright 2013 IBM Corp.
*
* 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.
**/
var RED = require(process.env.NODE_RED_HOME+"/red/red");
function CommentNode(n) {
RED.nodes.createNode(this,n);
}
RED.nodes.registerType("comment",CommentNode);