diff --git a/README.md b/README.md
index 10f384d3a..cdc862615 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
A visual tool for wiring the Internet of Things.
+![Screenshot](http://nodered.org/images/node-red-screenshot.png "Node-RED: A visual tool for wiring the Internet of Things")
+
## Quick Start
Check out [INSTALL](INSTALL.md) for full instructions on getting started.
@@ -16,6 +18,8 @@ Check out [INSTALL](INSTALL.md) for full instructions on getting started.
More documentation can be found [here](http://nodered.org/docs).
+For further help, or general discussion, there is also a [mailing list](https://groups.google.com/forum/#!forum/node-red).
+
## Browser Support
The Node-RED editor runs in the browser. We routinely develop and test using
@@ -28,9 +32,11 @@ list.
### Reporting issues
-Please raise any bug reports or feature requests on the project's issue
-tracker. Be sure to search the list to see if your issue has already
-been raised.
+Please raise any bug reports on the project's [issue tracker](https://github.com/node-red/node-red/issues?state=open).
+Be sure to search the list to see if your issue has already been raised.
+
+For feature requests, please raise them on the [mailing list](https://groups.google.com/forum/#!forum/node-red)
+first.
### Creating new nodes
diff --git a/nodes/99-sample.html.demo b/nodes/99-sample.html.demo
index 2b87ad16e..e26197aa7 100644
--- a/nodes/99-sample.html.demo
+++ b/nodes/99-sample.html.demo
@@ -17,6 +17,8 @@
+
+
diff --git a/nodes/99-sample.js.demo b/nodes/99-sample.js.demo
index a212df469..5db5b141d 100644
--- a/nodes/99-sample.js.demo
+++ b/nodes/99-sample.js.demo
@@ -14,38 +14,39 @@
* limitations under the License.
**/
+// If you use this as a template, replace IBM Corp. with your own name.
+
// Sample Node-RED node file
// Require main module
var RED = require("../../red/red");
// The main node definition - most things happen in here
-function SampleNode(n) {
+function SampleNode(n) {
// Create a RED node
RED.nodes.createNode(this,n);
-
+
// Store local copies of the node configuration (as defined in the .html)
this.topic = n.topic;
-
+
// Do whatever you need to do in here - declare callbacks etc
// Note: this sample doesn't do anything much - it will only send
// this message once at startup...
// Look at other real nodes for some better ideas of what to do....
var msg = {};
- msg.topic = node.topic;
+ msg.topic = this.topic;
msg.payload = "Hello world !"
-
+
// send out the message to the rest of the workspace.
this.send(msg);
+
+ this.on("close", function() {
+ // Called when the node is shutdown - eg on redeploy.
+ // Allows ports to be closed, connections dropped etc.
+ // eg: this.client.disconnect();
+ });
}
// Register the node by name. This must be called before overriding any of the
// Node functions.
RED.nodes.registerType("sample",SampleNode);
-
-
-SampleNode.prototype.close = function() {
- // Called when the node is shutdown - eg on redeploy.
- // Allows ports to be closed, connections dropped etc.
- // eg: this.client.disconnect();
-}
diff --git a/nodes/analysis/73-parsexml.html b/nodes/analysis/73-parsexml.html
index 77e4cb8ca..71b3a21cb 100644
--- a/nodes/analysis/73-parsexml.html
+++ b/nodes/analysis/73-parsexml.html
@@ -37,7 +37,7 @@
category: 'advanced-function',
color:"#E6E0F8",
defaults: {
- useEyes: {value:"false"},
+ useEyes: {value:false},
name: {value:""},
},
inputs:1,
diff --git a/nodes/core/20-inject.html b/nodes/core/20-inject.html
index 8ab75445b..0d0de8a02 100644
--- a/nodes/core/20-inject.html
+++ b/nodes/core/20-inject.html
@@ -202,7 +202,7 @@
},
oneditprepare: function() {
var repeattype = "none";
- if (Number(this.repeat) != 0) {
+ if (this.repeat != "") {
repeattype = "interval";
$("#inject-time-interval-units option").filter(function() {return $(this).val() == "s";}).attr('selected',true);
$("#inject-time-interval-count").val(this.repeat);
@@ -210,7 +210,7 @@
} else if (this.crontab) {
var cronparts = this.crontab.split(" ");
var days = cronparts[4];
- if (Number(cronparts[0]) && Number(cronparts[1])) {
+ if (!isNaN(cronparts[0]) && !isNaN(cronparts[1])) {
repeattype = "time";
// Fixed time
var time = cronparts[1]+":"+cronparts[0];
diff --git a/nodes/core/80-function.html b/nodes/core/80-function.html
index f4090f801..68b71cc75 100644
--- a/nodes/core/80-function.html
+++ b/nodes/core/80-function.html
@@ -21,7 +21,7 @@
-
+
@@ -85,6 +85,7 @@
editor:that.editor, // the field name the main text body goes to
fields:['name','outputs']
});
+ $("#node-input-name").focus();
});
},
diff --git a/nodes/core/80-template.html b/nodes/core/80-template.html
index f0a024173..8d7c8ddd1 100644
--- a/nodes/core/80-template.html
+++ b/nodes/core/80-template.html
@@ -22,7 +22,7 @@
-
+
@@ -79,7 +79,7 @@
editor:that.editor, // the field name the main text body goes to
fields:['name']
});
-
+ $("#node-input-name").focus();
});
},
oneditsave: function() {
diff --git a/nodes/core/90-comment.html b/nodes/core/90-comment.html
index 86b8922cb..b909b5d1f 100644
--- a/nodes/core/90-comment.html
+++ b/nodes/core/90-comment.html
@@ -21,7 +21,7 @@
-
+
Tip: this isn't meant for War and Peace - but useful notes can be kept here.
@@ -75,6 +75,7 @@
showFoldingRuler:false,
contents: $("#node-input-info").val()
});
+ $("#node-input-name").focus();
});
},
oneditsave: function() {
diff --git a/nodes/hardware/35-arduino.html b/nodes/hardware/35-arduino.html
index e4d1a9d43..6640b77a0 100644
--- a/nodes/hardware/35-arduino.html
+++ b/nodes/hardware/35-arduino.html
@@ -138,7 +138,7 @@
category: 'config',
defaults: {
//baud: {baud:"57600",required:true},
- repeat: {value:"25",required:true,validate:RED.validators.number()},
+ repeat: {value:"50",required:true,validate:RED.validators.number()},
device: {value:"",required:true}
},
label: function() {
diff --git a/nodes/hardware/35-arduino.js b/nodes/hardware/35-arduino.js
index 3e6d648da..b81ea7cfc 100644
--- a/nodes/hardware/35-arduino.js
+++ b/nodes/hardware/35-arduino.js
@@ -25,46 +25,46 @@ function ArduinoNode(n) {
RED.nodes.createNode(this,n);
this.device = n.device;
this.repeat = n.repeat||25;
- util.log("[firmata] Opening"+this.device);
+ util.log("[firmata] Opening "+this.device);
+ var node = this;
-// var tou = setInterval(function() {
-// if (!arduinoReady) {
-// clearInterval(tou);
-
- arduinoReady = false;
- if (thisboard == null) {
- this.board = new firmata.Board(this.device, function(err) {
- if (err) {
- util.log("[firmata] "+err);
- return;
+ node.toun = setInterval(function() {
+ if (!arduinoReady) {
+ if (thisboard == null) {
+ node.board = new firmata.Board(node.device, function(err) {
+ if (err) {
+ console.log("[firmata] error: ",err);
+ return;
+ }
+ arduinoReady = true;
+ thisboard = node.board;
+ clearInterval(node.toun);
+ util.log('[firmata] Arduino connected');
+ });
}
- arduinoReady = true;
- util.log('[firmata] Arduino connected');
- });
- thisboard = this.board;
- }
- else {
- util.log("[firmata] Arduino already connected");
- this.board = thisboard;
- console.log(this.board._events);
- this.board.removeAllListeners();
- arduinoReady = true;
- }
+ else {
+ node.board = thisboard;
+ node.board.removeAllListeners();
+ arduinoReady = true;
+ clearInterval(node.toun);
+ node.toun = false;
+ util.log("[firmata] Arduino already connected");
+ }
+ } else { util.log("[firmata] Waiting for Firmata"); }
+ }, 10000); // wait for firmata to connect to arduino
-// } else { util.log("[firmata] Waiting for Firmata"); }
-// }, 1000); // wait for firmata to disconnect from arduino
-
- this._close = function() {
+ this.on('close', function() {
//this.board.sp.close(function() { console.log("[firmata] Serial port closed"); arduinoReady = false; });
+ arduinoReady = false;
+ if (node.toun) {
+ clearInterval(node.toun);
+ util.log("[firmata] arduino wait loop stopped");
+ }
util.log("[firmata] Stopped");
- }
+ });
}
-
RED.nodes.registerType("arduino-board",ArduinoNode);
-ArduinoNode.prototype.close = function() {
- this._close();
-}
// The Input Node
function DuinoNodeIn(n) {
@@ -78,11 +78,13 @@ function DuinoNodeIn(n) {
this.board = this.serverConfig.board;
this.repeat = this.serverConfig.repeat;
var node = this;
-
- var tout = setInterval(function() {
- if (arduinoReady) {
- clearInterval(tout);
- console.log(node.state,node.pin,node.board.MODES[node.state]);
+
+ node.toui = setInterval(function() {
+ if (thisboard != null) {
+ node.board = thisboard;
+ clearInterval(node.toui);
+ node.toui = false;
+ //console.log(node.state,node.pin,node.board.MODES[node.state]);
node.board.pinMode(node.pin, node.board.MODES[node.state]);
node.board.setSamplingInterval(node.repeat);
var oldrdg = "";
@@ -103,23 +105,21 @@ function DuinoNodeIn(n) {
}
}
else { node.log("Waiting for Arduino"); }
- }, 2000); // loop to wait for firmata to connect to arduino
-
- this._close = function() {
- clearInterval(this._interval);
- util.log("[arduino] input eventlistener stopped");
- }
+ }, 5000); // loop to wait for firmata to connect to arduino
+
+ this.on('close', function() {
+ if (node.toui) {
+ clearInterval(node.toui);
+ util.log("[firmata] input wait loop stopped");
+ }
+ });
}
else {
- util.log("[arduino] Serial Port not Configured");
+ util.log("[firmata] Serial Port not Configured");
}
}
RED.nodes.registerType("arduino in",DuinoNodeIn);
-DuinoNodeIn.prototype.close = function() {
- this._close();
-}
-
// The Output Node
function DuinoNodeOut(n) {
@@ -132,10 +132,10 @@ function DuinoNodeOut(n) {
if (typeof this.serverConfig === "object") {
this.board = this.serverConfig.board;
var node = this;
-
+
this.on("input", function(msg) {
//console.log(msg);
- if (arduinoReady) {
+ if (thisboard != null) {
if (node.state == "OUTPUT") {
if ((msg.payload == true)||(msg.payload == 1)||(msg.payload.toString().toLowerCase() == "on")) {
node.board.digitalWrite(node.pin, node.board.HIGH);
@@ -161,17 +161,26 @@ function DuinoNodeOut(n) {
}
//else { console.log("Arduino not ready"); }
});
-
- var touo = setInterval(function() {
- if (arduinoReady) {
- clearInterval(touo);
- //console.log(node.state,node.pin,node.board.MODES[node.state]);
+
+ node.touo = setInterval(function() {
+ if (thisboard != null) {
+ clearInterval(node.touo);
+ node.touo = false;
+ node.board = thisboard;
node.board.pinMode(node.pin, node.board.MODES[node.state]);
}
+ else { util.log("[firmata] waiting for arduino to connect"); }
}, 5000); // loop to wait for firmata to connect to arduino
+
+ this.on('close', function() {
+ if (node.touo) {
+ clearInterval(node.touo);
+ util.log("[firmata] output wait loop stopped");
+ }
+ });
}
else {
- util.log("[arduino] Serial Port not Configured");
+ util.log("[firmata] Serial Port not Configured");
}
}
RED.nodes.registerType("arduino out",DuinoNodeOut);
diff --git a/nodes/io/21-httpin.js b/nodes/io/21-httpin.js
index c3e3a027b..0776d0383 100644
--- a/nodes/io/21-httpin.js
+++ b/nodes/io/21-httpin.js
@@ -57,7 +57,7 @@ RED.nodes.registerType("http in",HTTPIn);
function HTTPOut(n) {
RED.nodes.createNode(this,n);
-
+ var node = this;
this.on("input",function(msg) {
if (msg.res) {
if (msg.headers) {
@@ -65,6 +65,8 @@ function HTTPOut(n) {
}
var statusCode = msg.statusCode || 200;
msg.res.send(statusCode,msg.payload);
+ } else {
+ node.warn("No response object");
}
});
}
@@ -80,9 +82,9 @@ function HTTPRequest(n) {
this.on("input",function(msg) {
var opts = urllib.parse(msg.url||url);
- opts.method = msg.method||method;
+ opts.method = (msg.method||method).toUpperCase();
if (msg.headers) {
- opts.header = headers;
+ opts.header = msg.headers;
}
var req = httplib.request(opts,function(res) {
res.setEncoding('utf8');
@@ -103,7 +105,7 @@ function HTTPRequest(n) {
msg.statusCode = err.code;
node.send(msg);
});
- if (msg.payload) {
+ if (msg.payload && (method == "PUSH" || method == "PUT") ) {
if (typeof msg.payload === "string" || Buffer.isBuffer(msg.payload)) {
req.write(msg.payload);
} else if (typeof msg.payload == "number") {
diff --git a/nodes/io/31-tcpin.js b/nodes/io/31-tcpin.js
index 78b7ab731..8d52df7a9 100644
--- a/nodes/io/31-tcpin.js
+++ b/nodes/io/31-tcpin.js
@@ -30,7 +30,7 @@ function TcpIn(n) {
this.server = (typeof n.server == 'boolean')?n.server:(n.server == "server");
this.closing = false;
var node = this;
-
+
if (!node.server) {
var buffer = null;
var client;
@@ -41,13 +41,13 @@ function TcpIn(n) {
buffer = (node.datatype == 'buffer')? new Buffer(0):"";
node.log("connected to "+node.host+":"+node.port);
});
-
+
client.on('data', function (data) {
if (node.datatype != 'buffer') {
data = data.toString(node.datatype);
}
if (node.stream) {
- if ((typeof data) === "string" && node.newline != "") {
+ if ((node.datatype) === "utf8" && node.newline != "") {
buffer = buffer+data;
var parts = buffer.split(node.newline);
for (var i = 0;i
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/nodes/io/32-udp.js b/nodes/io/32-udp.js
new file mode 100644
index 000000000..39b7b1222
--- /dev/null
+++ b/nodes/io/32-udp.js
@@ -0,0 +1,115 @@
+/**
+ * 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("../../red/red");
+var dgram = require('dgram');
+
+// The Input Node
+function UDPin(n) {
+ RED.nodes.createNode(this,n);
+ this.group = n.group;
+ this.port = n.port;
+ this.host = n.host || null;
+ this.datatype = n.datatype;
+ this.iface = n.iface || null;
+ this.multicast = n.multicast;
+ var node = this;
+
+ var server = dgram.createSocket('udp4');
+
+ server.on("error", function (err) {
+ console.log("udp listener error:\n" + err.stack);
+ server.close();
+ });
+
+ server.on('message', function (message, remote) {
+ var msg;
+ if (node.datatype =="base64") { msg = { payload:message.toString('base64'), fromip:remote.address+':'+remote.port }; }
+ else if (node.datatype =="utf8") { msg = { payload:message.toString('utf8'), fromip:remote.address+':'+remote.port }; }
+ else { msg = { payload:message, fromip:remote.address+':'+remote.port }; }
+ node.send(msg);
+ });
+
+ server.on('listening', function () {
+ var address = server.address();
+ node.log('udp listener at ' + address.address + ":" + address.port);
+ if (node.multicast == "true") {
+ server.setBroadcast(true)
+ server.setMulticastTTL(128);
+ server.addMembership(node.group,node.iface);
+ node.log("udp multicast group "+node.group);
+ }
+ });
+
+ node.on("close", function() {
+ try {
+ server.close();
+ node.log('udp listener stopped');
+ }
+ catch (err) { console.log(err); }
+ });
+
+ server.bind(node.port,node.host);
+}
+RED.nodes.registerType("udp in",UDPin);
+
+
+// The Output Node
+function UDPout(n) {
+ RED.nodes.createNode(this,n);
+ //this.group = n.group;
+ this.port = n.port;
+ this.base64 = n.base64;
+ this.addr = n.addr;
+ this.iface = n.iface || null;
+ this.multicast = n.multicast;
+ var node = this;
+
+ var sock = dgram.createSocket('udp4'); // only use ipv4 for now
+ sock.bind(node.port); // have to bind before you can enable broadcast...
+ if (this.multicast != "false") {
+ sock.setBroadcast(true); // turn on broadcast
+ if (this.multicast == "multi") {
+ sock.setMulticastTTL(128);
+ sock.addMembership(node.addr,node.iface); // Add to the multicast group
+ node.log('udp multicast ready : '+node.addr+":"+node.port);
+ }
+ else node.log('udp broadcast ready : '+node.addr+":"+node.port);
+ }
+ else node.log('udp ready : '+node.addr+":"+node.port);
+
+ node.on("input", function(msg) {
+ if (msg.payload != null) {
+ //console.log("UDP:",msg.payload);
+ var message;
+ if (node.base64) { message = new Buffer(b64string, 'base64'); }
+ else { message = new Buffer(""+msg.payload); }
+ console.log("UDP send :",node.addr,node.port);
+ sock.send(message, 0, message.length, node.port, node.addr, function(err, bytes) {
+ if (err) node.error("udp : "+err);
+ });
+ }
+ });
+
+ node.on("close", function() {
+ try {
+ sock.close();
+ node.log('udp output stopped');
+ }
+ catch (err) { console.log(err); }
+ });
+}
+RED.nodes.registerType("udp out",UDPout);
diff --git a/nodes/social/27-twitter.html b/nodes/social/27-twitter.html
index 08e80786b..223c42c4a 100644
--- a/nodes/social/27-twitter.html
+++ b/nodes/social/27-twitter.html
@@ -29,8 +29,8 @@
pathname += "/";
}
var callback = encodeURIComponent(location.protocol+"//"+location.hostname+":"+location.port+pathname+"twitter/"+twitterConfigNodeId+"/auth/callback");
-
- $("#node-config-twitter-row").html('Click here to authenticate with Twitter.');
+
+ $("#node-config-twitter-row").html('Click here to authenticate with Twitter.');
$("#node-config-twitter-start").click(function() {
twitterConfigNodeIntervalId = window.setTimeout(pollTwitterCredentials,2000);
});
@@ -102,34 +102,33 @@
@@ -140,7 +139,7 @@
defaults: {
twitter: {type:"twitter-credentials",required:true},
tags: {value:"",required:true},
- user: {value:false},
+ user: {value:"false",required:true},
name: {value:""},
topic: {value:"tweets"}
},
diff --git a/nodes/social/27-twitter.js b/nodes/social/27-twitter.js
index 923fec859..751ef2d65 100644
--- a/nodes/social/27-twitter.js
+++ b/nodes/social/27-twitter.js
@@ -24,14 +24,13 @@ function TwitterNode(n) {
}
RED.nodes.registerType("twitter-credentials",TwitterNode);
-
function TwitterInNode(n) {
RED.nodes.createNode(this,n);
this.active = true;
this.user = n.user;
this.tags = n.tags.replace(/ /g,'');
this.twitter = n.twitter;
- this.topic = n.topic;
+ this.topic = n.topic||"tweets";
this.twitterConfig = RED.nodes.getNode(this.twitter);
var credentials = RED.nodes.getCredentials(this.twitter);
@@ -47,11 +46,12 @@ function TwitterInNode(n) {
if (this.tags !== "") {
try {
var thing = 'statuses/filter';
- if (this.user) { thing = 'user'; }
+ if (this.user == "true") { thing = 'user'; }
function setupStream() {
if (node.active) {
twit.stream(thing, { track: [node.tags] }, function(stream) {
//twit.stream('user', { track: [node.tags] }, function(stream) {
+ //twit.stream('site', { track: [node.tags] }, function(stream) {
//twit.stream('statuses/filter', { track: [node.tags] }, function(stream) {
node.stream = stream;
stream.on('data', function(tweet) {
@@ -101,8 +101,6 @@ TwitterInNode.prototype.close = function() {
}
}
-
-
function TwitterOutNode(n) {
RED.nodes.createNode(this,n);
this.topic = n.topic;
diff --git a/nodes/social/57-notify.html b/nodes/social/57-notify.html
index ed711bed0..67c04cbf3 100644
--- a/nodes/social/57-notify.html
+++ b/nodes/social/57-notify.html
@@ -16,7 +16,7 @@
@@ -103,7 +103,7 @@
-
+
diff --git a/nodes/social/91-irc.js b/nodes/social/91-irc.js
index 4041147dc..21456c32d 100644
--- a/nodes/social/91-irc.js
+++ b/nodes/social/91-irc.js
@@ -16,6 +16,7 @@
var RED = require("../../red/red");
var irc = require("irc");
+var util = require("util");
// The Server Definition - this opens (and closes) the connection
function IRCServerNode(n) {
@@ -23,40 +24,38 @@ function IRCServerNode(n) {
this.server = n.server;
this.channel = n.channel;
this.nickname = n.nickname;
- this.ircclient = new irc.Client(this.server, this.nickname, {
- channels: [this.channel]
+ this.ircclient = null;
+ this.on("close", function() {
+ if (this.ircclient != null) {
+ this.ircclient.disconnect();
+ }
});
- this._close = function() {
- this.ircclient.disconnect();
- }
}
RED.nodes.registerType("irc-server",IRCServerNode);
-IRCServerNode.prototype.close = function() {
- this._close();
-}
-
-
// The Input Node
function IrcInNode(n) {
RED.nodes.createNode(this,n);
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
+ if (this.serverConfig.ircclient == null) {
+ this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
+ channels: [this.serverConfig.channel]
+ });
+ this.serverConfig.ircclient.addListener('error', function(message) {
+ util.log('[irc] '+ JSON.stringify(message));
+ });
+ }
this.ircclient = this.serverConfig.ircclient;
var node = this;
-
this.ircclient.addListener('message', function (from, to, message) {
console.log(from + ' => ' + to + ': ' + message);
var msg = { "topic":from, "to":to, "payload":message };
node.send(msg);
});
- this.ircclient.addListener('error', function(message) {
- node.error(JSON.stringify(message));
- });
-
}
RED.nodes.registerType("irc in",IrcInNode);
@@ -66,12 +65,20 @@ function IrcOutNode(n) {
this.sendAll = n.sendObject;
this.ircserver = n.ircserver;
this.serverConfig = RED.nodes.getNode(this.ircserver);
- this.ircclient = this.serverConfig.ircclient;
this.channel = this.serverConfig.channel;
+ if (this.serverConfig.ircclient == null) {
+ this.serverConfig.ircclient = new irc.Client(this.serverConfig.server, this.serverConfig.nickname, {
+ channels: [this.serverConfig.channel]
+ });
+ this.serverConfig.ircclient.addListener('error', function(message) {
+ util.log('[irc] '+ JSON.stringify(message));
+ });
+ }
+ this.ircclient = this.serverConfig.ircclient;
var node = this;
this.on("input", function(msg) {
- console.log(msg);
+ //console.log(msg,node.channel);
if (node.sendAll) {
node.ircclient.say(node.channel, JSON.stringify(msg));
}
diff --git a/nodes/social/92-xmpp.js b/nodes/social/92-xmpp.js
index f8c8c227c..15f957958 100644
--- a/nodes/social/92-xmpp.js
+++ b/nodes/social/92-xmpp.js
@@ -14,8 +14,17 @@
* limitations under the License.
**/
+var orig=console.warn;
+console.warn=(function() { // suppress warning from stringprep when not needed)
+ var orig=console.warn;
+ return function() {
+ //orig.apply(console, arguments);
+ };
+})();
+
var RED = require("../../red/red");
var xmpp = require('simple-xmpp');
+console.warn = orig;
try {
var xmppkey = require("../../settings").xmpp || require("../../../xmppkeys.js");
@@ -97,17 +106,13 @@ function XmppNode(n) {
}
});
- this._close = function() {
+ this.on("close", function() {
xmpp.setPresence('offline');
//xmpp.conn.end();
// TODO - DCJ NOTE... this is not good. It leaves the connection up over a restart - which will end up with bad things happening...
// (but requires the underlying xmpp lib to be fixed (which does have an open bug request on fixing the close method)).
this.warn("Due to an underlying bug in the xmpp library this does not disconnect old sessions. This is bad... A restart would be better.");
- }
+ });
}
RED.nodes.registerType("xmpp",XmppNode);
-
-XmppNode.prototype.close = function() {
- this._close();
-}
diff --git a/public/icons/bluetooth.png b/public/icons/bluetooth.png
new file mode 100644
index 000000000..f94e92f19
Binary files /dev/null and b/public/icons/bluetooth.png differ
diff --git a/public/red/ui/editor.js b/public/red/ui/editor.js
index fc85f58cc..98605baf6 100644
--- a/public/red/ui/editor.js
+++ b/public/red/ui/editor.js
@@ -143,8 +143,34 @@ RED.editor = function() {
var changes = {};
var changed = false;
var wasDirty = RED.view.dirty();
+
+
if (editing_node._def.oneditsave) {
+ var oldValues = {};
+ for (var d in editing_node._def.defaults) {
+ if (typeof editing_node[d] === "string" || typeof editing_node[d] === "number") {
+ oldValues[d] = editing_node[d];
+ } else {
+ oldValues[d] = $.extend(true,{},{v:editing_node[d]}).v;
+ }
+ }
editing_node._def.oneditsave.call(editing_node);
+
+ for (var d in editing_node._def.defaults) {
+ if (oldValues[d] === null || typeof oldValues[d] === "string" || typeof oldValues[d] === "number") {
+ if (oldValues[d] !== editing_node[d]) {
+ changes[d] = oldValues[d];
+ changed = true;
+ }
+ } else {
+ if (JSON.stringify(oldValues[d]) !== JSON.stringify(editing_node[d])) {
+ changes[d] = oldValues[d];
+ changed = true;
+ }
+ }
+ }
+
+
}
if (editing_node._def.defaults) {
@@ -177,7 +203,6 @@ RED.editor = function() {
changes[d] = editing_node[d];
editing_node[d] = newValue;
changed = true;
- RED.view.dirty(true);
}
}
}
@@ -185,6 +210,7 @@ RED.editor = function() {
var removedLinks = updateNodeProperties(editing_node);
if (changed) {
+ RED.view.dirty(true);
RED.history.push({t:'edit',node:editing_node,changes:changes,links:removedLinks,dirty:wasDirty});
}
diff --git a/public/red/ui/palette.js b/public/red/ui/palette.js
index 8975c71f7..994b85ade 100644
--- a/public/red/ui/palette.js
+++ b/public/red/ui/palette.js
@@ -63,7 +63,10 @@ RED.palette = function() {
container:'body',
content: $(($("script[data-help-name|='"+nt+"']").html()||"
no information available
").trim())[0]
});
-
+ $(d).click(function() {
+ var help = '