Compare commits

..

33 Commits

Author SHA1 Message Date
Dave Conway-Jones
539ca8b84d keep changes in this branch in sync with other trigger changes 2017-12-29 16:57:37 +00:00
Dave Conway-Jones
813a5d2879 add some istanbul ignore to trigger 2017-11-03 19:20:03 +00:00
Dave Conway-Jones
d2b53ebba0 boost trigger node test coverage 2017-09-20 17:35:24 +01:00
Dave Conway-Jones
32d98a7fa3 trigger test - add missing try/catch to all test with callback 2017-09-20 09:31:11 +01:00
Dave Conway-Jones
69946f0be0 test trigger repeat for pass by ref error 2017-09-20 08:42:23 +01:00
Dave Conway-Jones
6e610c0435 Add some tests for trigger by topic 2017-09-19 23:21:50 +01:00
Dave Conway-Jones
cdf9e2c214 ensure trigger node clones repeating message 2017-09-19 22:40:36 +01:00
Dave Conway-Jones
6b672bd9af Let trigger node support per topic mode 2017-09-18 15:44:37 +01:00
btsimonh
b81940351f Allow port zero for Express (#1363)
* Allow uiPort to be 0 (i.e. distinguish from undefined).  When Express runs up, catch the real port number to settings.serverPort, and use that in getListenPath if set, else use uiPort.
2017-09-17 09:30:39 +01:00
Kazuki Nakanishi
a42e99c4aa Fix the appearance of 'is between' rule on switch node property (#1383) 2017-09-17 08:46:47 +01:00
HirokiUchikawa
ff40b521b7 Fix problem with multi-byte character (#1391) 2017-09-17 08:46:14 +01:00
Nick O'Leary
85392496e7 Allow setTimeout in Function node to be promisified in node 8 2017-09-12 15:13:13 +01:00
Jeston Tigchon
29cae9975e Upgrade JSONata to v1.3.0 (#1386) 2017-09-07 21:58:29 +01:00
Kosuke Akizuki
170d6b28f8 Change font family (#1357)
thanks  @k4zzk
2017-08-24 12:14:55 +01:00
Dave Conway-Jones
a844ca161f Spinner fixes (#1371)
* Fix for function node invalid spinner values

to close #1370

* better validation of spinners for inject and delay

(don’t allow negative numbers)

* remove need for declaring local min variable
2017-08-21 22:00:23 +01:00
btsimonh
e09efba313 mqtt: Add 'name' to mqtt-broker node, and label it by this if it is set. (#1364)
This allows you to easily distinguish between broker nodes which are talking to the same server but with different credentials.
2017-08-09 22:22:40 +01:00
Nick O'Leary
96a0dbea2d Don't include subflow meta-port nodes in exported selection
Fixes #1362
2017-08-08 15:48:54 +01:00
Nick O'Leary
5b3b5271ad Remove test diff code 2017-08-07 16:38:15 +01:00
Kazuhito Yokoi
d7d13c12fe Modify messages to refer to language files (#1361) 2017-08-07 10:00:28 +01:00
Nick O'Leary
54220d0e71 Ensure shade elements have a higher z-index than ui elements 2017-08-04 22:20:58 +01:00
Nick O'Leary
4a2e3586f1 Allow delay node in rate-limit mode to be reset
Fixes #1360
2017-08-04 21:09:00 +01:00
Nick O'Leary
f808e85da9 Diff view: subflows can have port labels as well 2017-08-04 14:26:05 +01:00
Nick O'Leary
1671d1f580 Allow expanding diff elements to stay in-sync deeper 2017-08-04 14:23:28 +01:00
Nick O'Leary
7de1bf9d95 Better node properties layout in diff table 2017-08-03 23:04:39 +01:00
Nick O'Leary
7368b0cefb Make diff tool a maximised tray rather than dialog 2017-08-03 09:58:25 +01:00
Nick O'Leary
4af43d676a Include input/output labels in diff view 2017-08-02 21:57:23 +01:00
Nick O'Leary
67dc848b2d getNodeIcon should handle subflow types properly 2017-08-02 21:55:25 +01:00
Nick O'Leary
7ec8f0d26b Do not include tab types in typeSearch dialog 2017-08-02 21:54:58 +01:00
Nick O'Leary
eaf08a9971 Keep local/remote diff objects in sync as they expand 2017-07-31 23:29:36 +01:00
Nick O'Leary
5bdb9e972e Add httpStatic log statement on start up 2017-07-26 11:45:49 -07:00
Nick O'Leary
d4d87054c4 Ensure tab property changes are listed in diff view 2017-07-26 07:55:53 -07:00
Nick O'Leary
0f93929544 Fix diff view node properties table rendering 2017-07-26 07:47:19 -07:00
Nick O'Leary
1c0e794f87 Ensure tabs get their definition object properly attached 2017-07-26 07:46:22 -07:00
43 changed files with 1032 additions and 448 deletions

View File

@@ -219,12 +219,12 @@
menuOptions.push(null); menuOptions.push(null);
} }
menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.userSettings"),onselect:"core:show-user-settings"}); menuOptions.push({id:"menu-item-user-settings",label:RED._("menu.label.settings"),onselect:"core:show-user-settings"});
menuOptions.push(null); menuOptions.push(null);
menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"}); menuOptions.push({id:"menu-item-keyboard-shortcuts",label:RED._("menu.label.keyboardShortcuts"),onselect:"core:show-help"});
menuOptions.push({id:"menu-item-help", menuOptions.push({id:"menu-item-help",
label: RED.settings.theme("menu.menu-item-help.label","Node-RED website"), label: RED.settings.theme("menu.menu-item-help.label",RED._("menu.label.help")),
href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs") href: RED.settings.theme("menu.menu-item-help.url","http://nodered.org/docs")
}); });
menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" }); menuOptions.push({id:"menu-item-node-red-version", label:"v"+RED.settings.version, onselect: "core:show-about" });

View File

@@ -41,6 +41,15 @@ RED.nodes = (function() {
var typeToId = {}; var typeToId = {};
var nodeDefinitions = {}; var nodeDefinitions = {};
nodeDefinitions['tab'] = {
defaults: {
label: {value:""},
disabled: {value: false},
info: {value: ""}
}
};
var exports = { var exports = {
setModulePendingUpdated: function(module,version) { setModulePendingUpdated: function(module,version) {
moduleList[module].pending_version = version; moduleList[module].pending_version = version;
@@ -274,14 +283,7 @@ RED.nodes = (function() {
function addWorkspace(ws) { function addWorkspace(ws) {
workspaces[ws.id] = ws; workspaces[ws.id] = ws;
ws._def = { ws._def = RED.nodes.getType('tab');
defaults: {
label: {value:""},
disabled: {value: false},
info: {value: ""}
}
};
workspacesOrder.push(ws.id); workspacesOrder.push(ws.id);
} }
function getWorkspace(id) { function getWorkspace(id) {
@@ -817,7 +819,7 @@ RED.nodes = (function() {
// Add a tab if there isn't one there already // Add a tab if there isn't one there already
if (defaultWorkspace == null) { if (defaultWorkspace == null) {
defaultWorkspace = { type:"tab", id:getID(), label:RED._('workspace.defaultName',{number:1})}; defaultWorkspace = { type:"tab", id:getID(), disabled: false, info:"", label:RED._('workspace.defaultName',{number:1})};
addWorkspace(defaultWorkspace); addWorkspace(defaultWorkspace);
RED.workspaces.add(defaultWorkspace); RED.workspaces.add(defaultWorkspace);
new_workspaces.push(defaultWorkspace); new_workspaces.push(defaultWorkspace);

View File

@@ -203,7 +203,8 @@ RED.clipboard = (function() {
var nodes = null; var nodes = null;
if (type === 'export-range-selected') { if (type === 'export-range-selected') {
var selection = RED.view.selection(); var selection = RED.view.selection();
nodes = RED.nodes.createExportableNodeSet(selection.nodes); // Don't include the subflow meta-port nodes in the exported selection
nodes = RED.nodes.createExportableNodeSet(selection.nodes.filter(function(n) { return n.type !== 'subflow'}));
} else if (type === 'export-range-flow') { } else if (type === 'export-range-flow') {
var activeWorkspace = RED.workspaces.active(); var activeWorkspace = RED.workspaces.active();
nodes = RED.nodes.filterNodes({z:activeWorkspace}); nodes = RED.nodes.filterNodes({z:activeWorkspace});

View File

@@ -85,7 +85,7 @@
if (this.element.css("position") === "absolute") { if (this.element.css("position") === "absolute") {
["top","left","bottom","right"].forEach(function(s) { ["top","left","bottom","right"].forEach(function(s) {
var v = that.element.css(s); var v = that.element.css(s);
if (s!=="auto" && s!=="") { if (v!=="auto" && v!=="") {
that.topContainer.css(s,v); that.topContainer.css(s,v);
that.uiContainer.css(s,"0"); that.uiContainer.css(s,"0");
that.element.css(s,'auto'); that.element.css(s,'auto');

View File

@@ -157,8 +157,8 @@ RED.deploy = (function() {
create: function() { create: function() {
$("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane") $("#node-dialog-confirm-deploy").parent().find("div.ui-dialog-buttonpane")
.prepend('<div style="height:0; vertical-align: middle; display:inline-block; margin-top: 13px; float:left;">'+ .prepend('<div style="height:0; vertical-align: middle; display:inline-block; margin-top: 13px; float:left;">'+
'<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide">'+ '<input style="vertical-align:top;" type="checkbox" id="node-dialog-confirm-deploy-hide"> '+
'<label style="display:inline;" for="node-dialog-confirm-deploy-hide"> do not warn about this again</label>'+ '<label style="display:inline;" for="node-dialog-confirm-deploy-hide" data-i18n="deploy.confirm.doNotWarn"></label>'+
'<input type="hidden" id="node-dialog-confirm-deploy-type">'+ '<input type="hidden" id="node-dialog-confirm-deploy-type">'+
'</div>'); '</div>');
}, },

View File

@@ -1,52 +1,26 @@
RED.diff = (function() { RED.diff = (function() {
var currentDiff = {}; var currentDiff = {};
var diffVisible = false;
var diffList;
function init() { function init() {
// RED.actions.add("core:show-current-diff",showLocalDiff); // RED.actions.add("core:show-current-diff",showLocalDiff);
RED.actions.add("core:show-remote-diff",showRemoteDiff); RED.actions.add("core:show-remote-diff",showRemoteDiff);
// RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff"); // RED.keyboard.add("*","ctrl-shift-l","core:show-current-diff");
RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff"); RED.keyboard.add("*","ctrl-shift-r","core:show-remote-diff");
}
var dialog = $('<div id="node-dialog-view-diff" class="hide"><div id="node-dialog-view-diff-headers"></div><ol id="node-dialog-view-diff-diff"></ol></div>').appendTo(document.body); function buildDiffPanel(container) {
var diffPanel = $('<div id="node-dialog-view-diff"><div id="node-dialog-view-diff-headers"></div><ol id="node-dialog-view-diff-diff"></ol></div>').appendTo(container);
var toolbar = $('<div class="node-diff-toolbar">'+ var toolbar = $('<div class="node-diff-toolbar">'+
'<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+ '<span><span id="node-diff-toolbar-resolved-conflicts"></span></span> '+
'</div>').prependTo(dialog); '</div>').prependTo(diffPanel);
$("#node-dialog-view-diff").dialog({ diffList = diffPanel.find("#node-dialog-view-diff-diff").editableList({
title: RED._('deploy.confirm.button.review'),
modal: true,
autoOpen: false,
buttons: [
{
text: RED._("common.label.cancel"),
click: function() {
$( this ).dialog( "close" );
}
},
{
id: "node-diff-view-diff-merge",
text: RED._("deploy.confirm.button.merge"),
class: "primary disabled",
click: function() {
if (!$("#node-diff-view-diff-merge").hasClass('disabled')) {
refreshConflictHeader();
mergeDiff(currentDiff);
$( this ).dialog( "close" );
}
}
}
],
open: function() {
$(this).dialog({width:Math.min($(window).width(),900),height:Math.min($(window).height(),600)});
}
});
var diffList = $("#node-dialog-view-diff-diff").editableList({
addButton: false, addButton: false,
scrollOnAdd: false, scrollOnAdd: false,
addItem: function(container,i,object) { addItem: function(container,i,object) {
@@ -77,7 +51,7 @@ RED.diff = (function() {
} else if (tab.type === 'subflow') { } else if (tab.type === 'subflow') {
titleSpan.html((tabForLabel.name||tabForLabel.id)); titleSpan.html((tabForLabel.name||tabForLabel.id));
} else { } else {
titleSpan.html("Global nodes"); titleSpan.html(RED._("diff.globalNodes"));
} }
var flowStats = { var flowStats = {
local: { local: {
@@ -153,7 +127,7 @@ RED.diff = (function() {
} }
} }
$('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv); $('<span class="node-diff-chevron"><i class="fa fa-angle-down"></i></span>').appendTo(originalNodeDiv);
$('<span>').html("Flow Properties").appendTo(originalNodeDiv); $('<span>').html(RED._("diff.flowProperties")).appendTo(originalNodeDiv);
row.click(function(evt) { row.click(function(evt) {
evt.preventDefault(); evt.preventDefault();
@@ -307,6 +281,7 @@ RED.diff = (function() {
container.i18n(); container.i18n();
} }
}); });
return diffPanel;
} }
function formatWireProperty(wires,allNodes) { function formatWireProperty(wires,allNodes) {
var result = $("<div>",{class:"node-diff-property-wires"}) var result = $("<div>",{class:"node-diff-property-wires"})
@@ -563,6 +538,7 @@ RED.diff = (function() {
return div; return div;
} }
function createNodePropertiesTable(def,node,localNodeObj,remoteNodeObj) { function createNodePropertiesTable(def,node,localNodeObj,remoteNodeObj) {
var propertyElements = {};
var localNode = localNodeObj.node; var localNode = localNodeObj.node;
var remoteNode; var remoteNode;
if (remoteNodeObj) { if (remoteNodeObj) {
@@ -571,8 +547,15 @@ RED.diff = (function() {
var nodePropertiesDiv = $("<div>",{class:"node-diff-node-entry-properties"}); var nodePropertiesDiv = $("<div>",{class:"node-diff-node-entry-properties"});
var nodePropertiesTable = $("<table>").appendTo(nodePropertiesDiv); var nodePropertiesTable = $("<table>").appendTo(nodePropertiesDiv);
var nodePropertiesTableCols = $('<colgroup><col/><col/></colgroup>').appendTo(nodePropertiesTable);
if (remoteNode !== undefined) {
$("<col/>").appendTo(nodePropertiesTableCols);
}
var nodePropertiesTableBody = $("<tbody>").appendTo(nodePropertiesTable);
var row; var row;
var localCell, remoteCell; var localCell, remoteCell;
var element;
var currentValue, localValue, remoteValue; var currentValue, localValue, remoteValue;
var localChanged = false; var localChanged = false;
var remoteChanged = false; var remoteChanged = false;
@@ -581,13 +564,14 @@ RED.diff = (function() {
var conflict = false; var conflict = false;
var status; var status;
row = $("<tr>").appendTo(nodePropertiesTable); row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row); $("<td>",{class:"node-diff-property-cell-label"}).html("id").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row); localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) { if (localNode) {
localCell.addClass("node-diff-node-unchanged"); localCell.addClass("node-diff-node-unchanged");
$('<span class="node-diff-status"></span>').appendTo(localCell); $('<span class="node-diff-status"></span>').appendTo(localCell);
RED.utils.createObjectElement(localNode.id).appendTo(localCell); element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.id'] = RED.utils.createObjectElement(localNode.id).appendTo(element);
} else { } else {
localCell.addClass("node-diff-empty"); localCell.addClass("node-diff-empty");
} }
@@ -596,7 +580,8 @@ RED.diff = (function() {
remoteCell.addClass("node-diff-node-unchanged"); remoteCell.addClass("node-diff-node-unchanged");
if (remoteNode) { if (remoteNode) {
$('<span class="node-diff-status"></span>').appendTo(remoteCell); $('<span class="node-diff-status"></span>').appendTo(remoteCell);
RED.utils.createObjectElement(remoteNode.id).appendTo(remoteCell); element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.id'] = RED.utils.createObjectElement(remoteNode.id).appendTo(element);
} else { } else {
remoteCell.addClass("node-diff-empty"); remoteCell.addClass("node-diff-empty");
} }
@@ -622,13 +607,24 @@ RED.diff = (function() {
) { ) {
conflict = true; conflict = true;
} }
row = $("<tr>").appendTo(nodePropertiesTable); row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row); $("<td>",{class:"node-diff-property-cell-label"}).html("position").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row); localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) { if (localNode) {
localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged")); localCell.addClass("node-diff-node-"+(localChanged?"changed":"unchanged"));
$('<span class="node-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell); $('<span class="node-diff-status">'+(localChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(localCell);
RED.utils.createObjectElement({x:localNode.x,y:localNode.y}).appendTo(localCell); element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.position'] = RED.utils.createObjectElement({x:localNode.x,y:localNode.y},
{
path: "position",
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['remote.'+path]) {
propertyElements['remote.'+path].prop('expand')(path,state)
}
}
}
).appendTo(element);
} else { } else {
localCell.addClass("node-diff-empty"); localCell.addClass("node-diff-empty");
} }
@@ -638,7 +634,18 @@ RED.diff = (function() {
remoteCell.addClass("node-diff-node-"+(remoteChanged?"changed":"unchanged")); remoteCell.addClass("node-diff-node-"+(remoteChanged?"changed":"unchanged"));
if (remoteNode) { if (remoteNode) {
$('<span class="node-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell); $('<span class="node-diff-status">'+(remoteChanged?'<i class="fa fa-square"></i>':'')+'</span>').appendTo(remoteCell);
RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y}).appendTo(remoteCell); element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.position'] = RED.utils.createObjectElement({x:remoteNode.x,y:remoteNode.y},
{
path: "position",
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['local.'+path]) {
propertyElements['local.'+path].prop('expand')(path,state);
}
}
}
).appendTo(element);
} else { } else {
remoteCell.addClass("node-diff-empty"); remoteCell.addClass("node-diff-empty");
} }
@@ -668,7 +675,7 @@ RED.diff = (function() {
){ ){
conflict = true; conflict = true;
} }
row = $("<tr>").appendTo(nodePropertiesTable); row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row); $("<td>",{class:"node-diff-property-cell-label"}).html("wires").appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row); localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) { if (localNode) {
@@ -700,10 +707,14 @@ RED.diff = (function() {
} }
} }
} }
var properties = Object.keys(node).filter(function(p) { return p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
var properties = Object.keys(node).filter(function(p) { return p!='inputLabels'&&p!='outputLabels'&&p!='z'&&p!='wires'&&p!=='x'&&p!=='y'&&p!=='id'&&p!=='type'&&(!def.defaults||!def.defaults.hasOwnProperty(p))});
if (def.defaults) { if (def.defaults) {
properties = properties.concat(Object.keys(def.defaults)); properties = properties.concat(Object.keys(def.defaults));
} }
if (node.type !== 'tab') {
properties = properties.concat(['inputLabels','outputLabels']);
}
properties.forEach(function(d) { properties.forEach(function(d) {
localChanged = false; localChanged = false;
remoteChanged = false; remoteChanged = false;
@@ -731,8 +742,8 @@ RED.diff = (function() {
conflict = true; conflict = true;
} }
row = $("<tr>").appendTo(nodePropertiesTable); row = $("<tr>").appendTo(nodePropertiesTableBody);
$("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row); var propertyNameCell = $("<td>",{class:"node-diff-property-cell-label"}).html(d).appendTo(row);
localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row); localCell = $("<td>",{class:"node-diff-property-cell node-diff-node-local"}).appendTo(row);
if (localNode) { if (localNode) {
if (!conflict) { if (!conflict) {
@@ -742,7 +753,18 @@ RED.diff = (function() {
localCell.addClass("node-diff-node-conflict"); localCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(localCell); $('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(localCell);
} }
RED.utils.createObjectElement(localNode[d]).appendTo(localCell); element = $('<span class="node-diff-element"></span>').appendTo(localCell);
propertyElements['local.'+d] = RED.utils.createObjectElement(localNode[d],
{
path: d,
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['remote.'+d]) {
propertyElements['remote.'+d].prop('expand')(path,state)
}
}
}
).appendTo(element);
} else { } else {
localCell.addClass("node-diff-empty"); localCell.addClass("node-diff-empty");
} }
@@ -756,7 +778,18 @@ RED.diff = (function() {
remoteCell.addClass("node-diff-node-conflict"); remoteCell.addClass("node-diff-node-conflict");
$('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(remoteCell); $('<span class="node-diff-status"><i class="fa fa-exclamation"></i></span>').appendTo(remoteCell);
} }
RED.utils.createObjectElement(remoteNode[d]).appendTo(remoteCell); element = $('<span class="node-diff-element"></span>').appendTo(remoteCell);
propertyElements['remote.'+d] = RED.utils.createObjectElement(remoteNode[d],
{
path: d,
exposeApi: true,
ontoggle: function(path,state) {
if (propertyElements['local.'+d]) {
propertyElements['local.'+d].prop('expand')(path,state)
}
}
}
).appendTo(element);
} else { } else {
remoteCell.addClass("node-diff-empty"); remoteCell.addClass("node-diff-empty");
} }
@@ -1002,186 +1035,225 @@ RED.diff = (function() {
// console.log(conflicted); // console.log(conflicted);
return diff; return diff;
} }
function showDiff(diff) { function showDiff(diff) {
if (diffVisible) {
return;
}
var localDiff = diff.localDiff; var localDiff = diff.localDiff;
var remoteDiff = diff.remoteDiff; var remoteDiff = diff.remoteDiff;
var conflicts = diff.conflicts; var conflicts = diff.conflicts;
currentDiff = diff; currentDiff = diff;
var list = $("#node-dialog-view-diff-diff");
list.editableList('empty');
if (remoteDiff) { var trayOptions = {
$("#node-diff-view-diff-merge").show(); title: "Review Changes", //TODO: nls
if (Object.keys(conflicts).length === 0) { width: Infinity,
$("#node-diff-view-diff-merge").removeClass('disabled'); buttons: [
} else { {
$("#node-diff-view-diff-merge").addClass('disabled'); text: RED._("common.label.cancel"),
} click: function() {
} else { RED.tray.close();
$("#node-diff-view-diff-merge").hide(); }
} },
refreshConflictHeader(); {
id: "node-diff-view-diff-merge",
$("#node-dialog-view-diff-headers").empty(); text: RED._("deploy.confirm.button.merge"),
// console.log("--------------"); class: "primary disabled",
// console.log(localDiff); click: function() {
// console.log(remoteDiff); if (!$("#node-diff-view-diff-merge").hasClass('disabled')) {
var currentConfig = localDiff.currentConfig; refreshConflictHeader();
var newConfig = localDiff.newConfig; mergeDiff(currentDiff);
conflicts = conflicts || {}; RED.tray.close();
}
var el = { }
diff: localDiff, }
def: { ],
category: 'config', resize: function(dimensions) {
color: '#f0f0f0' // trayWidth = dimensions.width;
}, },
tab: { open: function(tray) {
n: {}, var trayBody = tray.find('.editor-tray-body');
nodes: currentConfig.globals var diffPanel = buildDiffPanel(trayBody);
}, if (remoteDiff) {
newTab: { $("#node-diff-view-diff-merge").show();
n: {}, if (Object.keys(conflicts).length === 0) {
nodes: newConfig.globals $("#node-diff-view-diff-merge").removeClass('disabled');
} } else {
}; $("#node-diff-view-diff-merge").addClass('disabled');
}
} else {
$("#node-diff-view-diff-merge").hide();
}
refreshConflictHeader();
if (remoteDiff !== undefined) { $("#node-dialog-view-diff-headers").empty();
$('#node-dialog-view-diff').addClass('node-diff-three-way'); // console.log("--------------");
// console.log(localDiff);
// console.log(remoteDiff);
var currentConfig = localDiff.currentConfig;
var newConfig = localDiff.newConfig;
conflicts = conflicts || {};
$('<div class="node-diff-node-entry-cell"></div><div class="node-diff-node-entry-cell" data-i18n="diff.local"></div><div class="node-diff-node-entry-cell" data-i18n="diff.remote"></div>').i18n().appendTo("#node-dialog-view-diff-headers");
el.remoteTab = {
n:{},
nodes:remoteDiff.newConfig.globals
};
el.remoteDiff = remoteDiff;
} else {
$('#node-dialog-view-diff').removeClass('node-diff-three-way');
}
list.editableList('addItem',el);
var seenTabs = {};
currentConfig.tabOrder.forEach(function(tabId) {
var tab = currentConfig.tabs[tabId];
var el = {
diff: localDiff,
def: {},
tab:tab
};
if (newConfig.tabs.hasOwnProperty(tabId)) {
el.newTab = newConfig.tabs[tabId];
}
if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.tabs[tabId];
el.remoteDiff = remoteDiff;
}
seenTabs[tabId] = true;
list.editableList('addItem',el)
});
newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) {
seenTabs[tabId] = true;
var tab = newConfig.tabs[tabId];
var el = { var el = {
diff: localDiff, diff: localDiff,
def: {}, def: {
tab:tab, category: 'config',
newTab: tab color: '#f0f0f0'
},
tab: {
n: {},
nodes: currentConfig.globals
},
newTab: {
n: {},
nodes: newConfig.globals
}
}; };
if (remoteDiff !== undefined) { if (remoteDiff !== undefined) {
diffPanel.addClass('node-diff-three-way');
$('<div data-i18n="diff.local"></div><div data-i18n="diff.remote"></div>').i18n().appendTo("#node-dialog-view-diff-headers");
el.remoteTab = {
n:{},
nodes:remoteDiff.newConfig.globals
};
el.remoteDiff = remoteDiff; el.remoteDiff = remoteDiff;
} else {
diffPanel.removeClass('node-diff-three-way');
} }
list.editableList('addItem',el)
} diffList.editableList('addItem',el);
});
if (remoteDiff !== undefined) { var seenTabs = {};
remoteDiff.newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) { currentConfig.tabOrder.forEach(function(tabId) {
var tab = remoteDiff.newConfig.tabs[tabId]; var tab = currentConfig.tabs[tabId];
// TODO how to recognise this is a remotely added flow
var el = { var el = {
diff: localDiff, diff: localDiff,
remoteDiff: remoteDiff, def: RED.nodes.getType('tab'),
def: {}, tab:tab
tab:tab,
remoteTab:tab
}; };
list.editableList('addItem',el) if (newConfig.tabs.hasOwnProperty(tabId)) {
} el.newTab = newConfig.tabs[tabId];
});
}
var subflowId;
for (subflowId in currentConfig.subflows) {
if (currentConfig.subflows.hasOwnProperty(subflowId)) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:currentConfig.subflows[subflowId]
}
if (newConfig.subflows.hasOwnProperty(subflowId)) {
el.newTab = newConfig.subflows[subflowId];
}
if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.subflows[subflowId];
el.remoteDiff = remoteDiff;
}
list.editableList('addItem',el)
}
}
for (subflowId in newConfig.subflows) {
if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:newConfig.subflows[subflowId],
newTab:newConfig.subflows[subflowId]
}
if (remoteDiff !== undefined) {
el.remoteDiff = remoteDiff;
}
list.editableList('addItem',el)
}
}
if (remoteDiff !== undefined) {
for (subflowId in remoteDiff.newConfig.subflows) {
if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
el = {
diff: localDiff,
remoteDiff: remoteDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:remoteDiff.newConfig.subflows[subflowId],
remoteTab: remoteDiff.newConfig.subflows[subflowId]
} }
list.editableList('addItem',el) if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.tabs[tabId];
el.remoteDiff = remoteDiff;
}
seenTabs[tabId] = true;
diffList.editableList('addItem',el)
});
newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) {
seenTabs[tabId] = true;
var tab = newConfig.tabs[tabId];
var el = {
diff: localDiff,
def: RED.nodes.getType('tab'),
tab:tab,
newTab: tab
};
if (remoteDiff !== undefined) {
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
});
if (remoteDiff !== undefined) {
remoteDiff.newConfig.tabOrder.forEach(function(tabId) {
if (!seenTabs[tabId]) {
var tab = remoteDiff.newConfig.tabs[tabId];
// TODO how to recognise this is a remotely added flow
var el = {
diff: localDiff,
remoteDiff: remoteDiff,
def: RED.nodes.getType('tab'),
tab:tab,
remoteTab:tab
};
diffList.editableList('addItem',el)
}
});
} }
var subflowId;
for (subflowId in currentConfig.subflows) {
if (currentConfig.subflows.hasOwnProperty(subflowId)) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:currentConfig.subflows[subflowId]
}
if (newConfig.subflows.hasOwnProperty(subflowId)) {
el.newTab = newConfig.subflows[subflowId];
}
if (remoteDiff !== undefined) {
el.remoteTab = remoteDiff.newConfig.subflows[subflowId];
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
}
for (subflowId in newConfig.subflows) {
if (newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
seenTabs[subflowId] = true;
el = {
diff: localDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:newConfig.subflows[subflowId],
newTab:newConfig.subflows[subflowId]
}
if (remoteDiff !== undefined) {
el.remoteDiff = remoteDiff;
}
diffList.editableList('addItem',el)
}
}
if (remoteDiff !== undefined) {
for (subflowId in remoteDiff.newConfig.subflows) {
if (remoteDiff.newConfig.subflows.hasOwnProperty(subflowId) && !seenTabs[subflowId]) {
el = {
diff: localDiff,
remoteDiff: remoteDiff,
def: {
defaults:{},
icon:"subflow.png",
category: "subflows",
color: "#da9"
},
tab:remoteDiff.newConfig.subflows[subflowId],
remoteTab: remoteDiff.newConfig.subflows[subflowId]
}
diffList.editableList('addItem',el)
}
}
}
$("#sidebar-shade").show();
},
close: function() {
diffVisible = false;
$("#sidebar-shade").hide();
},
show: function() {
} }
} }
RED.tray.show(trayOptions);
$("#node-diff-filter-changed").addClass("selected");
$("#node-diff-filter-all").removeClass("selected");
$("#node-dialog-view-diff").dialog("open");
} }
function mergeDiff(diff) { function mergeDiff(diff) {
var currentConfig = diff.localDiff.currentConfig; var currentConfig = diff.localDiff.currentConfig;
var localDiff = diff.localDiff; var localDiff = diff.localDiff;
@@ -1260,7 +1332,6 @@ RED.diff = (function() {
RED.palette.refresh(); RED.palette.refresh();
RED.workspaces.refresh(); RED.workspaces.refresh();
RED.sidebar.config.refresh(); RED.sidebar.config.refresh();
} }
return { return {
init: init, init: init,

View File

@@ -660,7 +660,7 @@ RED.editor = (function() {
function buildLabelRow(type, index, value, placeHolder) { function buildLabelRow(type, index, value, placeHolder) {
var result = $('<div>',{class:"node-label-form-row"}); var result = $('<div>',{class:"node-label-form-row"});
if (type === undefined) { if (type === undefined) {
$('<span>').html("none").appendTo(result); $('<span>').html(RED._("editor.noDefaultLabel")).appendTo(result);
result.addClass("node-label-form-none"); result.addClass("node-label-form-none");
} else { } else {
result.addClass(""); result.addClass("");

View File

@@ -89,7 +89,7 @@ RED.keyboard = (function() {
RED.userSettings.add({ RED.userSettings.add({
id:'keyboard', id:'keyboard',
title: 'Keyboard', title: RED._("keyboard.keyboard"),
get: getSettingsPane, get: getSettingsPane,
focus: function() { focus: function() {
setTimeout(function() { setTimeout(function() {
@@ -350,7 +350,8 @@ RED.keyboard = (function() {
$(this).toggleClass("input-error",!valid); $(this).toggleClass("input-error",!valid);
}) })
var scopeSelect = $('<select><option value="*">global</option><option value="workspace">workspace</option></select>').appendTo(scope); var scopeSelect = $('<select><option value="*" data-i18n="keyboard.global"></option><option value="workspace" data-i18n="keyboard.workspace"></option></select>').appendTo(scope);
scopeSelect.i18n();
scopeSelect.val(object.scope||'*'); scopeSelect.val(object.scope||'*');
var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope); var div = $('<div class="keyboard-shortcut-edit button-group-vertical"></div>').appendTo(scope);
@@ -468,9 +469,9 @@ RED.keyboard = (function() {
var pane = $('<div id="user-settings-tab-keyboard"></div>'); var pane = $('<div id="user-settings-tab-keyboard"></div>');
$('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+ $('<div class="keyboard-shortcut-entry keyboard-shortcut-list-header">'+
'<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="user-settings-tab-keyboard-filter" type="text" placeholder="filter actions"></div>'+ '<div class="keyboard-shortcut-entry-key keyboard-shortcut-entry-text"><input id="user-settings-tab-keyboard-filter" type="text" data-i18n="[placeholder]keyboard.filterActions"></div>'+
'<div class="keyboard-shortcut-entry-key">shortcut</div>'+ '<div class="keyboard-shortcut-entry-key" data-i18n="keyboard.shortcut"></div>'+
'<div class="keyboard-shortcut-entry-scope">scope</div>'+ '<div class="keyboard-shortcut-entry-scope" data-i18n="keyboard.scope"></div>'+
'</div>').appendTo(pane); '</div>').appendTo(pane);
pane.find("input").searchBox({ pane.find("input").searchBox({

View File

@@ -423,7 +423,7 @@ RED.palette.editor = (function() {
RED.userSettings.add({ RED.userSettings.add({
id:'palette', id:'palette',
title: 'Palette', title: RED._("palette.editor.palette"),
get: getSettingsPane, get: getSettingsPane,
close: function() { close: function() {
settingsPane.detach(); settingsPane.detach();

View File

@@ -125,7 +125,7 @@ RED.search = (function() {
function createDialog() { function createDialog() {
dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#main-container"); dialog = $("<div>",{id:"red-ui-search",class:"red-ui-search"}).appendTo("#main-container");
var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog); var searchDiv = $("<div>",{class:"red-ui-search-container"}).appendTo(dialog);
searchInput = $('<input type="text" placeholder="search your flows">').appendTo(searchDiv).searchBox({ searchInput = $('<input type="text" data-i18n="[placeholder]menu.label.searchInput">').appendTo(searchDiv).searchBox({
delay: 200, delay: 200,
change: function() { change: function() {
search($(this).val()); search($(this).val());
@@ -166,6 +166,7 @@ RED.search = (function() {
} }
} }
}); });
searchInput.i18n();
var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog); var searchResultsDiv = $("<div>",{class:"red-ui-search-results-container"}).appendTo(dialog);
searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({ searchResults = $('<ol>',{id:"search-result-list", style:"position: absolute;top: 5px;bottom: 5px;left: 5px;right: 5px;"}).appendTo(searchResultsDiv).editableList({

View File

@@ -50,11 +50,11 @@ RED.sidebar.info = (function() {
}).hide(); }).hide();
nodeSection = sections.add({ nodeSection = sections.add({
title: "Node", title: RED._("sidebar.info.node"),
collapsible: false collapsible: false
}); });
infoSection = sections.add({ infoSection = sections.add({
title: "Information", title: RED._("sidebar.info.information"),
collapsible: false collapsible: false
}); });
infoSection.content.css("padding","6px"); infoSection.content.css("padding","6px");
@@ -132,15 +132,15 @@ RED.sidebar.info = (function() {
var propRow; var propRow;
var subflowNode; var subflowNode;
if (node.type === "tab") { if (node.type === "tab") {
nodeSection.title.html("Flow"); nodeSection.title.html(RED._("sidebar.info.flow"));
propRow = $('<tr class="node-info-node-row"><td>Name</td><td></td></tr>').appendTo(tableBody); propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.tabName")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).html('&nbsp;'+(node.label||"")) $(propRow.children()[1]).html('&nbsp;'+(node.label||""))
propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody); propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.id")+"</td><td></td></tr>").appendTo(tableBody);
RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]); RED.utils.createObjectElement(node.id).appendTo(propRow.children()[1]);
propRow = $('<tr class="node-info-node-row"><td>Status</td><td></td></tr>').appendTo(tableBody); propRow = $('<tr class="node-info-node-row"><td>'+RED._("sidebar.info.status")+'</td><td></td></tr>').appendTo(tableBody);
$(propRow.children()[1]).html((!!!node.disabled)?"Enabled":"Disabled") $(propRow.children()[1]).html((!!!node.disabled)?RED._("sidebar.info.enabled"):RED._("sidebar.info.disabled"))
} else { } else {
nodeSection.title.html("Node"); nodeSection.title.html(RED._("sidebar.info.node"));
if (node.type !== "subflow" && node.name) { if (node.type !== "subflow" && node.name) {
$('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td>&nbsp;<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody); $('<tr class="node-info-node-row"><td>'+RED._("common.label.name")+'</td><td>&nbsp;<span class="bidiAware" dir="'+RED.text.bidi.resolveBaseTextDir(node.name)+'">'+node.name+'</span></td></tr>').appendTo(tableBody);
} }
@@ -188,7 +188,7 @@ RED.sidebar.info = (function() {
} }
} }
if (count > 0) { if (count > 0) {
$('<tr class="node-info-property-expand blank"><td colspan="2"><a href="#" class=" node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="node-info-property-show-more">show more</span><span class="node-info-property-show-less">show less</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody); $('<tr class="node-info-property-expand blank"><td colspan="2"><a href="#" class=" node-info-property-header'+(expandedSections.property?" expanded":"")+'"><span class="node-info-property-show-more">'+RED._("sidebar.info.showMore")+'</span><span class="node-info-property-show-less">'+RED._("sidebar.info.showLess")+'</span> <i class="fa fa-caret-down"></i></a></td></tr>').appendTo(tableBody);
} }
} }
} }

View File

@@ -34,6 +34,10 @@ RED.tray = (function() {
if (options.title) { if (options.title) {
$('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header); $('<div class="editor-tray-titlebar">'+options.title+'</div>').appendTo(header);
} }
if (options.width === Infinity) {
options.maximized = true;
resizer.addClass('editor-tray-resize-maximised');
}
var buttonBar = $('<div class="editor-tray-toolbar"></div>').appendTo(header); var buttonBar = $('<div class="editor-tray-toolbar"></div>').appendTo(header);
var primaryButton; var primaryButton;
if (options.buttons) { if (options.buttons) {
@@ -74,7 +78,8 @@ RED.tray = (function() {
}; };
stack.push(tray); stack.push(tray);
el.draggable({ if (!options.maximized) {
el.draggable({
handle: resizer, handle: resizer,
axis: "x", axis: "x",
start:function(event,ui) { start:function(event,ui) {
@@ -103,6 +108,7 @@ RED.tray = (function() {
tray.width = -ui.position.left; tray.width = -ui.position.left;
} }
}); });
}
function finishBuild() { function finishBuild() {
$("#header-shade").show(); $("#header-shade").show();
@@ -175,7 +181,7 @@ RED.tray = (function() {
var tray = stack[stack.length-1]; var tray = stack[stack.length-1];
var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight(); var trayHeight = tray.tray.height()-tray.header.outerHeight()-tray.footer.outerHeight();
tray.body.height(trayHeight); tray.body.height(trayHeight);
if (tray.width > $("#editor-stack").position().left-8) { if (tray.options.maximized || tray.width > $("#editor-stack").position().left-8) {
tray.width = $("#editor-stack").position().left-8; tray.width = $("#editor-stack").position().left-8;
tray.tray.width(tray.width); tray.tray.width(tray.width);
// tray.body.parent().width(tray.width); // tray.body.parent().width(tray.width);

View File

@@ -236,7 +236,7 @@ RED.typeSearch = (function() {
var items = []; var items = [];
RED.nodes.registry.getNodeTypes().forEach(function(t) { RED.nodes.registry.getNodeTypes().forEach(function(t) {
var def = RED.nodes.getType(t); var def = RED.nodes.getType(t);
if (def.category !== 'config' && t !== 'unknown') { if (def.category !== 'config' && t !== 'unknown' && t !== 'tab') {
items.push({type:t,def: def, label:getTypeLabel(t,def)}); items.push({type:t,def: def, label:getTypeLabel(t,def)});
} }
}); });

View File

@@ -33,7 +33,7 @@ RED.userSettings = (function() {
var tabContainer; var tabContainer;
var trayOptions = { var trayOptions = {
title: "User Settings", title: RED._("menu.label.userSettings"),
buttons: [ buttons: [
{ {
id: "node-dialog-ok", id: "node-dialog-ok",
@@ -100,7 +100,7 @@ RED.userSettings = (function() {
var viewSettings = [ var viewSettings = [
{ {
title: "Grid", title: "menu.label.view.grid",
options: [ options: [
{setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"}, {setting:"view-show-grid",oldSetting:"menu-menu-item-view-show-grid",label:"menu.label.view.showGrid",toggle:true,onchange:"core:toggle-show-grid"},
{setting:"view-snap-grid",oldSetting:"menu-menu-item-view-snap-grid",label:"menu.label.view.snapGrid",toggle:true,onchange:"core:toggle-snap-grid"}, {setting:"view-snap-grid",oldSetting:"menu-menu-item-view-snap-grid",label:"menu.label.view.snapGrid",toggle:true,onchange:"core:toggle-snap-grid"},
@@ -108,13 +108,13 @@ RED.userSettings = (function() {
] ]
}, },
{ {
title: "Nodes", title: "menu.label.nodes",
options: [ options: [
{setting:"view-node-status",oldSetting:"menu-menu-item-status",label:"menu.label.displayStatus",default: true, toggle:true,onchange:"core:toggle-status"} {setting:"view-node-status",oldSetting:"menu-menu-item-status",label:"menu.label.displayStatus",default: true, toggle:true,onchange:"core:toggle-status"}
] ]
}, },
{ {
title: "Other", title: "menu.label.other",
options: [ options: [
{setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"} {setting:"view-show-tips",oldSettings:"menu-menu-item-show-tips",label:"menu.label.showTips",toggle:true,default:true,onchange:"core:toggle-show-tips"}
] ]
@@ -128,7 +128,7 @@ RED.userSettings = (function() {
var pane = $('<div id="user-settings-tab-view" class="node-help"></div>'); var pane = $('<div id="user-settings-tab-view" class="node-help"></div>');
viewSettings.forEach(function(section) { viewSettings.forEach(function(section) {
$('<h3></h3>').text(section.title).appendTo(pane); $('<h3></h3>').text(RED._(section.title)).appendTo(pane);
section.options.forEach(function(opt) { section.options.forEach(function(opt) {
var initialState = RED.settings.get(opt.setting); var initialState = RED.settings.get(opt.setting);
var row = $('<div class="user-settings-row"></div>').appendTo(pane); var row = $('<div class="user-settings-row"></div>').appendTo(pane);
@@ -169,7 +169,7 @@ RED.userSettings = (function() {
addPane({ addPane({
id:'view', id:'view',
title: 'View', title: RED._("menu.label.view.view"),
get: createViewPane, get: createViewPane,
close: function() { close: function() {
viewSettings.forEach(function(section) { viewSettings.forEach(function(section) {

View File

@@ -50,24 +50,58 @@ RED.utils = (function() {
} }
return result; return result;
} }
function makeExpandable(el,onexpand,expand) { function makeExpandable(el,onbuild,ontoggle,expand) {
el.addClass("debug-message-expandable"); el.addClass("debug-message-expandable");
el.prop('toggle',function() {
return function(state) {
var parent = el.parent();
if (parent.hasClass('collapsed')) {
if (state) {
if (onbuild && !parent.hasClass('built')) {
onbuild();
parent.addClass('built');
}
parent.removeClass('collapsed');
return true;
}
} else {
if (!state) {
parent.addClass('collapsed');
return true;
}
}
return false;
}
});
el.click(function(e) { el.click(function(e) {
var parent = $(this).parent(); var parent = $(this).parent();
if (parent.hasClass('collapsed')) { var currentState = !parent.hasClass('collapsed');
if (onexpand && !parent.hasClass('built')) { if ($(this).prop('toggle')(!currentState)) {
onexpand(); if (ontoggle) {
parent.addClass('built'); ontoggle(!currentState);
} }
parent.removeClass('collapsed');
} else {
parent.addClass('collapsed');
} }
// if (parent.hasClass('collapsed')) {
// if (onbuild && !parent.hasClass('built')) {
// onbuild();
// parent.addClass('built');
// }
// if (ontoggle) {
// ontoggle(true);
// }
// parent.removeClass('collapsed');
// } else {
// parent.addClass('collapsed');
// if (ontoggle) {
// ontoggle(false);
// }
// }
e.preventDefault(); e.preventDefault();
}); });
if (expand) { if (expand) {
el.click(); el.click();
} }
} }
var pinnedPaths = {}; var pinnedPaths = {};
@@ -189,10 +223,23 @@ RED.utils = (function() {
} }
} }
function buildMessageElement(obj,key,typeHint,hideKey,path,sourceId,rootPath,expandPaths) { function buildMessageElement(obj,options) {
options = options || {};
var key = options.key;
var typeHint = options.typeHint;
var hideKey = options.hideKey;
var path = options.path;
var sourceId = options.sourceId;
var rootPath = options.rootPath;
var expandPaths = options.expandPaths;
var ontoggle = options.ontoggle;
var exposeApi = options.exposeApi;
var subElements = {};
var i; var i;
var e; var e;
var entryObj; var entryObj;
var expandableHeader;
var header; var header;
var headerHead; var headerHead;
var value; var value;
@@ -257,7 +304,7 @@ RED.utils = (function() {
$('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header); $('<span class="debug-message-type-meta debug-message-object-type-header"></span>').html(typeHint||'string').appendTo(header);
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element); var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
$('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row); $('<pre class="debug-message-type-string"></pre>').text(obj).appendTo(row);
},checkExpanded(strippedKey,expandPaths)); },function(state) {if (ontoggle) { ontoggle(path,state);}}, checkExpanded(strippedKey,expandPaths));
} }
e = $('<span class="debug-message-type-string debug-message-object-header"></span>').html('"'+formatString(sanitize(obj))+'"').appendTo(entryObj); e = $('<span class="debug-message-type-string debug-message-object-header"></span>').html('"'+formatString(sanitize(obj))+'"').appendTo(entryObj);
if (/^#[0-9a-f]{6}$/i.test(obj)) { if (/^#[0-9a-f]{6}$/i.test(obj)) {
@@ -356,7 +403,20 @@ RED.utils = (function() {
if (fullLength <= 10) { if (fullLength <= 10) {
for (i=0;i<fullLength;i++) { for (i=0;i<fullLength;i++) {
row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows); row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(arrayRows);
buildMessageElement(data[i],""+i,type==='buffer'?'hex':false,false,path+"["+i+"]",sourceId,rootPath,expandPaths).appendTo(row); subElements[path+"["+i+"]"] = buildMessageElement(
data[i],
{
key: ""+i,
typeHint: type==='buffer'?'hex':false,
hideKey: false,
path: path+"["+i+"]",
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
} }
} else { } else {
for (i=0;i<fullLength;i+=10) { for (i=0;i<fullLength;i+=10) {
@@ -371,17 +431,35 @@ RED.utils = (function() {
return function() { return function() {
for (var i=min;i<=max;i++) { for (var i=min;i<=max;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent); var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(parent);
buildMessageElement(data[i],""+i,type==='buffer'?'hex':false,false,path+"["+i+"]",sourceId,rootPath,expandPaths).appendTo(row); subElements[path+"["+i+"]"] = buildMessageElement(
data[i],
{
key: ""+i,
typeHint: type==='buffer'?'hex':false,
hideKey: false,
path: path+"["+i+"]",
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
} }
} }
})(),checkExpanded(strippedKey,expandPaths,minRange,Math.min(fullLength-1,(minRange+9)))); })(),
(function() { var path = path+"["+i+"]"; return function(state) {if (ontoggle) { ontoggle(path,state);}}})(),
checkExpanded(strippedKey,expandPaths,minRange,Math.min(fullLength-1,(minRange+9))));
$('<span class="debug-message-object-key"></span>').html("["+minRange+" &hellip; "+Math.min(fullLength-1,(minRange+9))+"]").appendTo(header); $('<span class="debug-message-object-key"></span>').html("["+minRange+" &hellip; "+Math.min(fullLength-1,(minRange+9))+"]").appendTo(header);
} }
if (fullLength < originalLength) { if (fullLength < originalLength) {
$('<div class="debug-message-object-entry collapsed"><span class="debug-message-object-key">['+fullLength+' &hellip; '+originalLength+']</span></div>').appendTo(arrayRows); $('<div class="debug-message-object-entry collapsed"><span class="debug-message-object-key">['+fullLength+' &hellip; '+originalLength+']</span></div>').appendTo(arrayRows);
} }
} }
},checkExpanded(strippedKey,expandPaths)); },
function(state) {if (ontoggle) { ontoggle(path,state);}},
checkExpanded(strippedKey,expandPaths));
} }
} else if (typeof obj === 'object') { } else if (typeof obj === 'object') {
element.addClass('collapsed'); element.addClass('collapsed');
@@ -395,17 +473,35 @@ RED.utils = (function() {
for (i=0;i<keys.length;i++) { for (i=0;i<keys.length;i++) {
var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element); var row = $('<div class="debug-message-object-entry collapsed"></div>').appendTo(element);
var newPath = path; var newPath = path;
if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) { if (newPath) {
newPath += (newPath.length > 0?".":"")+keys[i]; if (/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(keys[i])) {
} else { newPath += (newPath.length > 0?".":"")+keys[i];
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]" } else {
newPath += "[\""+keys[i].replace(/"/,"\\\"")+"\"]"
}
} }
buildMessageElement(obj[keys[i]],keys[i],false,false,newPath,sourceId,rootPath,expandPaths).appendTo(row); subElements[newPath] = buildMessageElement(
obj[keys[i]],
{
key: keys[i],
typeHint: false,
hideKey: false,
path: newPath,
sourceId: sourceId,
rootPath: rootPath,
expandPaths: expandPaths,
ontoggle: ontoggle,
exposeApi: exposeApi
}
).appendTo(row);
} }
if (keys.length === 0) { if (keys.length === 0) {
$('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element); $('<div class="debug-message-object-entry debug-message-type-meta collapsed"></div>').text("empty").appendTo(element);
} }
},checkExpanded(strippedKey,expandPaths)); },
function(state) {if (ontoggle) { ontoggle(path,state);}},
checkExpanded(strippedKey,expandPaths));
} }
if (key) { if (key) {
$('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj); $('<span class="debug-message-type-meta"></span>').html('object').appendTo(entryObj);
@@ -432,6 +528,28 @@ RED.utils = (function() {
} else { } else {
$('<span class="debug-message-type-other"></span>').text(""+obj).appendTo(entryObj); $('<span class="debug-message-type-other"></span>').text(""+obj).appendTo(entryObj);
} }
if (exposeApi) {
element.prop('expand', function() { return function(targetPath, state) {
if (path === targetPath) {
if (header.prop('toggle')) {
header.prop('toggle')(state);
}
} else if (subElements[targetPath] && subElements[targetPath].prop('expand') ) {
subElements[targetPath].prop('expand')(targetPath,state);
} else {
for (var p in subElements) {
if (subElements.hasOwnProperty(p)) {
if (targetPath.indexOf(p) === 0) {
if (subElements[p].prop('expand') ) {
subElements[p].prop('expand')(targetPath,state);
}
break;
}
}
}
}
}});
}
return element; return element;
} }
@@ -578,6 +696,8 @@ RED.utils = (function() {
return "icons/node-red/subflow.png" return "icons/node-red/subflow.png"
} else if (node && node.type === 'unknown') { } else if (node && node.type === 'unknown') {
return "icons/node-red/alert.png" return "icons/node-red/alert.png"
} else if (node && node.type === 'subflow') {
return "icons/node-red/subflow.png"
} }
var icon_url; var icon_url;
if (typeof def.icon === "function") { if (typeof def.icon === "function") {

View File

@@ -30,7 +30,7 @@ RED.workspaces = (function() {
workspaceIndex += 1; workspaceIndex += 1;
} while ($("#workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0); } while ($("#workspace-tabs a[title='"+RED._('workspace.defaultName',{number:workspaceIndex})+"']").size() !== 0);
ws = {type:"tab",id:tabId,label:RED._('workspace.defaultName',{number:workspaceIndex})}; ws = {type:"tab",id:tabId,disabled: false,info:"",label:RED._('workspace.defaultName',{number:workspaceIndex})};
RED.nodes.addWorkspace(ws); RED.nodes.addWorkspace(ws);
workspace_tabs.addTab(ws); workspace_tabs.addTab(ws);
workspace_tabs.activateTab(tabId); workspace_tabs.activateTab(tabId);

View File

@@ -50,7 +50,7 @@ RED.user = (function() {
for (;i<data.prompts.length;i++) { for (;i<data.prompts.length;i++) {
var field = data.prompts[i]; var field = data.prompts[i];
var row = $("<div/>",{class:"form-row"}); var row = $("<div/>",{class:"form-row"});
$('<label for="node-dialog-login-'+field.id+'">'+field.label+':</label><br/>').appendTo(row); $('<label for="node-dialog-login-'+field.id+'">'+RED._(field.label)+':</label><br/>').appendTo(row);
var input = $('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row); var input = $('<input style="width: 100%" id="node-dialog-login-'+field.id+'" type="'+field.type+'" tabIndex="'+(i+1)+'"/>').appendTo(row);
if (i<data.prompts.length-1) { if (i<data.prompts.length-1) {

View File

@@ -16,8 +16,6 @@
#node-dialog-view-diff { #node-dialog-view-diff {
height: 600px;
.red-ui-editableList-container { .red-ui-editableList-container {
border-radius:1px; border-radius:1px;
padding:0; padding:0;
@@ -35,7 +33,6 @@
border: none; border: none;
min-height: 0; min-height: 0;
} }
} }
.red-ui-editableList-item-content { .red-ui-editableList-item-content {
padding: 5px; padding: 5px;
@@ -44,19 +41,23 @@
} }
#node-dialog-view-diff-headers { #node-dialog-view-diff-headers {
position: absolute; position: absolute;
left:17px; left:237px;
right:32px; right:18px;
top: 55px; top: 55px;
height: 25px; height: 25px;
.node-diff-node-entry-cell:not(:first-child) { div {
height: 25px;
display: inline-block;
box-sizing: border-box;
width: 50%;
background: #f9f9f9; background: #f9f9f9;
text-align: center; text-align: center;
border-top: 1px solid $secondary-border-color; border-top: 1px solid $secondary-border-color;
border-color:$secondary-border-color; border-color:$secondary-border-color;
border-left: 1px solid $secondary-border-color;
} }
.node-diff-node-entry-cell:last-child { div:last-child {
border-right: 1px solid $secondary-border-color; border-right: 1px solid $secondary-border-color;
} }
} }
@@ -106,10 +107,10 @@
font-size: 0.9em; font-size: 0.9em;
&:first-child { &:first-child {
border-top: 1px solid #eee; border-top: 1px solid $secondary-border-color;
} }
&:not(:last-child) { &:not(:last-child) {
border-bottom: 1px solid #eee; border-bottom: 1px solid $secondary-border-color;
} }
&.collapsed { &.collapsed {
@@ -132,14 +133,21 @@
table { table {
border-collapse: collapse; border-collapse: collapse;
table-layout:fixed; table-layout:fixed;
width: calc(100% - 20px);
// Fix for table-layout: fixed on safari: margin-left: 20px;
max-width: none; }
width: auto; col:first-child {
min-width: 100%; width: 180px;
}
col:not(:first-child) {
width: 100%;
} }
td, th { td, th {
border: 1px solid $secondary-border-color; border-top: 1px solid #f3f3f3;
border-left: 1px solid $secondary-border-color;
&:first-child {
border-left: none;
}
padding: 0 0 0 3px; padding: 0 0 0 3px;
text-align: left; text-align: left;
overflow-x: auto; overflow-x: auto;
@@ -150,13 +158,12 @@
white-space:nowrap; white-space:nowrap;
overflow:hidden; overflow:hidden;
} }
&:hover {
background: #f9f9f9;
}
} }
td:first-child {
width: 140px;
}
td:not(:first-child) {
width: calc( 100% - 140px);
}
td { td {
.node-diff-status { .node-diff-status {
margin-left: 0; margin-left: 0;
@@ -179,8 +186,8 @@
width: 220px; width: 220px;
} }
} }
td:not(:first-child) { col:not(:first-child) {
width: calc( (100% - 140px) / 2); width:50%;
} }
.node-diff-node-entry { .node-diff-node-entry {
@@ -210,6 +217,9 @@
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
// background: #f6f6f6; // background: #f6f6f6;
&:hover {
background: #f9f9f9;
}
} }
.node-diff-tab-title-meta { .node-diff-tab-title-meta {
vertical-align: middle; vertical-align: middle;
@@ -218,6 +228,9 @@
} }
.node-diff-node-entry-header { .node-diff-node-entry-header {
cursor: pointer; cursor: pointer;
&:hover {
background: #f9f9f9;
}
} }
.node-diff-node-entry-node { .node-diff-node-entry-node {
vertical-align: middle; vertical-align: middle;
@@ -247,6 +260,9 @@
} }
.node-diff-tab-title { .node-diff-tab-title {
cursor: default; cursor: default;
&:hover {
background: none;
}
} }
} }
.node-diff-node-deleted { .node-diff-node-deleted {
@@ -301,7 +317,7 @@
} }
} }
.node-diff-node-entry-properties { .node-diff-node-entry-properties {
margin: 5px ; margin: 0;
color: #666; color: #666;
} }
.node-diff-status { .node-diff-status {
@@ -313,6 +329,10 @@
margin-bottom: 6px; margin-bottom: 6px;
text-align: center; text-align: center;
} }
.node-diff-element {
display: inline-block;
width: calc(100% - 20px);
}
.node-diff-node-description { .node-diff-node-description {
color: $form-text-color; color: $form-text-color;
@@ -346,7 +366,7 @@
box-sizing: border-box; box-sizing: border-box;
width: calc( (100% - 20px) / 2); width: calc( (100% - 20px) / 2);
height: 32px; height: 32px;
border-left: 1px solid #eee; border-left: 1px solid $secondary-border-color;
padding-top: 2px; padding-top: 2px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;

View File

@@ -132,6 +132,11 @@
cursor: col-resize; cursor: col-resize;
border-left: 1px solid $primary-border-color; border-left: 1px solid $primary-border-color;
box-shadow: -1px 0 6px rgba(0,0,0,0.1); box-shadow: -1px 0 6px rgba(0,0,0,0.1);
&.editor-tray-resize-maximised {
background: $background-color;
cursor: default;
}
} }
.editor-tray-resize-button { .editor-tray-resize-button {
@include workspace-button; @include workspace-button;
@@ -196,7 +201,7 @@
border-radius:5px; border-radius:5px;
overflow: hidden; overflow: hidden;
font-size: 14px !important; font-size: 14px !important;
font-family: monospace !important; font-family: Menlo, Consolas, 'DejaVu Sans Mono', Courier, monospace !important;
} }
.editor-button { .editor-button {

View File

@@ -224,4 +224,5 @@
bottom: 0; bottom: 0;
right: 0; right: 0;
background: $shade-color; background: $shade-color;
z-index: 5;
} }

View File

@@ -128,6 +128,8 @@
'$map':{ args:[ 'array', 'function' ]}, '$map':{ args:[ 'array', 'function' ]},
'$match':{ args:[ 'str', 'pattern', 'limit' ]}, '$match':{ args:[ 'str', 'pattern', 'limit' ]},
'$max':{ args:[ 'array' ]}, '$max':{ args:[ 'array' ]},
'$merge':{ args:[ 'array' ]},
'$millis':{ args:[ ]},
'$min':{ args:[ 'array' ]}, '$min':{ args:[ 'array' ]},
'$not':{ args:[ 'arg' ]}, '$not':{ args:[ 'arg' ]},
'$now':{ args:[ ]}, '$now':{ args:[ ]},

View File

@@ -181,7 +181,7 @@ If you want every 20 minutes from now - use the <i>"interval"</i> option.</p>
topic: {value:""}, topic: {value:""},
payload: {value:"", validate: RED.validators.typedInput("payloadType")}, payload: {value:"", validate: RED.validators.typedInput("payloadType")},
payloadType: {value:"date"}, payloadType: {value:"date"},
repeat: {value:""}, repeat: {value:"", validate:function(v) { return ((v === "") || (RED.validators.number(v) && (v >= 0))) }},
crontab: {value:""}, crontab: {value:""},
once: {value:false} once: {value:false}
}, },

View File

@@ -73,7 +73,13 @@
oneditprepare: function() { oneditprepare: function() {
var that = this; var that = this;
$( "#node-input-outputs" ).spinner({ $( "#node-input-outputs" ).spinner({
min:1 min:1,
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); }
}
}); });
this.editor = RED.editor.createEditor({ this.editor = RED.editor.createEditor({

View File

@@ -187,6 +187,13 @@ module.exports = function(RED) {
} }
} }
}; };
if (util.hasOwnProperty('promisify')) {
sandbox.setTimeout[util.promisify.custom] = function(after, value) {
return new Promise(function(resolve, reject) {
sandbox.setTimeout(function(){ resolve(value) }, after);
});
}
}
var context = vm.createContext(sandbox); var context = vm.createContext(sandbox);
try { try {
this.script = vm.createScript(functionText); this.script = vm.createScript(functionText);

View File

@@ -129,13 +129,13 @@
defaults: { defaults: {
name: {value:""}, name: {value:""},
pauseType: {value:"delay", required:true}, pauseType: {value:"delay", required:true},
timeout: {value:"5", required:true, validate:RED.validators.number()}, timeout: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
timeoutUnits: {value:"seconds"}, timeoutUnits: {value:"seconds"},
rate: {value:"1", required:true, validate:RED.validators.number()}, rate: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
nbRateUnits: {value:"1", required:false, validate:RED.validators.regex(/\d+|/)}, nbRateUnits: {value:"1", required:false, validate:RED.validators.regex(/\d+|/)},
rateUnits: {value: "second"}, rateUnits: {value: "second"},
randomFirst: {value:"1", required:true, validate:RED.validators.number()}, randomFirst: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
randomLast: {value:"5", required:true, validate:RED.validators.number()}, randomLast: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
randomUnits: {value: "seconds"}, randomUnits: {value: "seconds"},
drop: {value:false} drop: {value:false}
}, },

View File

@@ -171,6 +171,7 @@ module.exports = function(RED) {
} }
if (msg.hasOwnProperty("reset")) { if (msg.hasOwnProperty("reset")) {
clearInterval(node.intervalID); clearInterval(node.intervalID);
node.intervalID = -1;
node.buffer = []; node.buffer = [];
node.status({text:"reset"}); node.status({text:"reset"});
} }

View File

@@ -56,6 +56,13 @@
</ul> </ul>
</div> </div>
<br/> <br/>
<div class="form-row">
<label data-i18n="trigger.for" for="node-input-bytopic"></label>
<select id="node-input-bytopic">
<option value="all" data-i18n="trigger.alltopics"></option>
<option value="topic" data-i18n="trigger.bytopics"></option>
</select>
</div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></input> <input type="text" id="node-input-name" data-i18n="[placeholder]common.label.name"></input>
@@ -85,7 +92,7 @@
<p>If set to a <i>string</i> type, the node supports the mustache template syntax.</p> <p>If set to a <i>string</i> type, the node supports the mustache template syntax.</p>
<p>If the node receives a message with a <code>reset</code> property, or a <code>payload</code> <p>If the node receives a message with a <code>reset</code> property, or a <code>payload</code>
that matches that configured in the node, any timeout or repeat currently in that matches that configured in the node, any timeout or repeat currently in
progress will be cleared and no message triggered.</o> progress will be cleared and no message triggered.</p>
<p>The node can be configured to resend a message at a regular interval until it <p>The node can be configured to resend a message at a regular interval until it
is reset by a received message.</p> is reset by a received message.</p>
</script> </script>
@@ -103,6 +110,7 @@
extend: {value:"false"}, extend: {value:"false"},
units: {value:"ms"}, units: {value:"ms"},
reset: {value:""}, reset: {value:""},
bytopic: {value: "all"},
name: {value:""} name: {value:""}
}, },
inputs:1, inputs:1,

View File

@@ -19,6 +19,7 @@ module.exports = function(RED) {
var mustache = require("mustache"); var mustache = require("mustache");
function TriggerNode(n) { function TriggerNode(n) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.bytopic = n.bytopic || "all";
this.op1 = n.op1 || "1"; this.op1 = n.op1 || "1";
this.op2 = n.op2 || "0"; this.op2 = n.op2 || "0";
this.op1type = n.op1type || "str"; this.op1type = n.op1type || "str";
@@ -47,7 +48,7 @@ module.exports = function(RED) {
this.extend = n.extend || "false"; this.extend = n.extend || "false";
this.units = n.units || "ms"; this.units = n.units || "ms";
this.reset = n.reset || ''; this.reset = n.reset || '';
this.duration = parseInt(n.duration); this.duration = parseFloat(n.duration);
if (isNaN(this.duration)) { if (isNaN(this.duration)) {
this.duration = 250; this.duration = 250;
} }
@@ -65,29 +66,32 @@ module.exports = function(RED) {
this.op2Templated = (this.op2type === 'str' && this.op2.indexOf("{{") != -1); this.op2Templated = (this.op2type === 'str' && this.op2.indexOf("{{") != -1);
if ((this.op1type === "num") && (!isNaN(this.op1))) { this.op1 = Number(this.op1); } if ((this.op1type === "num") && (!isNaN(this.op1))) { this.op1 = Number(this.op1); }
if ((this.op2type === "num") && (!isNaN(this.op2))) { this.op2 = Number(this.op2); } if ((this.op2type === "num") && (!isNaN(this.op2))) { this.op2 = Number(this.op2); }
if (this.op1 == "null") { this.op1 = null; } //if (this.op1 == "null") { this.op1 = null; }
if (this.op2 == "null") { this.op2 = null; } //if (this.op2 == "null") { this.op2 = null; }
//try { this.op1 = JSON.parse(this.op1); } //try { this.op1 = JSON.parse(this.op1); }
//catch(e) { this.op1 = this.op1; } //catch(e) { this.op1 = this.op1; }
//try { this.op2 = JSON.parse(this.op2); } //try { this.op2 = JSON.parse(this.op2); }
//catch(e) { this.op2 = this.op2; } //catch(e) { this.op2 = this.op2; }
var node = this; var node = this;
var tout = null; node.topics = {};
var m2;
this.on("input", function(msg) { this.on("input", function(msg) {
var topic = msg.topic || "_none";
if (node.bytopic === "all") { topic = "_none"; }
node.topics[topic] = node.topics[topic] || {};
if (msg.hasOwnProperty("reset") || ((node.reset !== '') && (msg.payload == node.reset)) ) { if (msg.hasOwnProperty("reset") || ((node.reset !== '') && (msg.payload == node.reset)) ) {
if (node.loop === true) { clearInterval(tout); } if (node.loop === true) { clearInterval(node.topics[topic].tout); }
else { clearTimeout(tout); } else { clearTimeout(node.topics[topic].tout); }
tout = null; delete node.topics[topic];
node.status({}); node.status({});
} }
else { else {
if (((!tout) && (tout !== 0)) || (node.loop === true)) { if (((!node.topics[topic].tout) && (node.topics[topic].tout !== 0)) || (node.loop === true)) {
if (node.op2type === "pay" || node.op2type === "payl") { m2 = msg.payload; } if (node.op2type === "pay" || node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
else if (node.op2Templated) { m2 = mustache.render(node.op2,msg); } else if (node.op2Templated) { node.topics[topic].m2 = mustache.render(node.op2,msg); }
else if (node.op2type !== "nul") { else if (node.op2type !== "nul") {
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg); node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
} }
if (node.op1type === "pay") { } if (node.op1type === "pay") { }
@@ -96,58 +100,67 @@ module.exports = function(RED) {
msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg); msg.payload = RED.util.evaluateNodeProperty(node.op1,node.op1type,node,msg);
} }
if (node.op1type !== "nul") { node.send(msg); } if (node.op1type !== "nul") { node.send(RED.util.cloneMessage(msg)); }
if (node.duration === 0) { tout = 0; } if (node.duration === 0) { node.topics[topic].tout = 0; }
else if (node.loop === true) { else if (node.loop === true) {
if (tout) { clearInterval(tout); } /* istanbul ignore else */
if (node.topics[topic].tout) { clearInterval(node.topics[topic].tout); }
/* istanbul ignore else */
if (node.op1type !== "nul") { if (node.op1type !== "nul") {
var msg2 = RED.util.cloneMessage(msg); var msg2 = RED.util.cloneMessage(msg);
tout = setInterval(function() { node.send(msg2); },node.duration); node.topics[topic].tout = setInterval(function() { node.send(RED.util.cloneMessage(msg2)); }, node.duration);
} }
} }
else { else {
tout = setTimeout(function() { node.topics[topic].tout = setTimeout(function() {
if (node.op2type !== "nul") { if (node.op2type !== "nul") {
var msg2 = RED.util.cloneMessage(msg); var msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") { if (node.op2type === "flow" || node.op2type === "global") {
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg); node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
} }
msg2.payload = m2; msg2.payload = node.topics[topic].m2;
node.send(msg2); node.send(msg2);
} }
tout = null; delete node.topics[topic];
node.status({}); node.status({});
},node.duration); }, node.duration);
} }
node.status({fill:"blue",shape:"dot",text:" "}); node.status({fill:"blue",shape:"dot",text:" "});
} }
else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) { else if ((node.extend === "true" || node.extend === true) && (node.duration > 0)) {
if (tout) { clearTimeout(tout); } /* istanbul ignore else */
if (node.op2type === "payl") { m2 = msg.payload; } if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
tout = setTimeout(function() { /* istanbul ignore else */
if (node.topics[topic].tout) { clearTimeout(node.topics[topic].tout); }
node.topics[topic].tout = setTimeout(function() {
if (node.op2type !== "nul") { if (node.op2type !== "nul") {
var msg2 = RED.util.cloneMessage(msg); var msg2 = RED.util.cloneMessage(msg);
if (node.op2type === "flow" || node.op2type === "global") { if (node.op2type === "flow" || node.op2type === "global") {
m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg); node.topics[topic].m2 = RED.util.evaluateNodeProperty(node.op2,node.op2type,node,msg);
}
if (node.topics[topic] !== undefined) {
msg2.payload = node.topics[topic].m2;
node.send(msg2);
} }
msg2.payload = m2;
node.send(msg2);
} }
tout = null; delete node.topics[topic];
node.status({}); node.status({});
},node.duration); }, node.duration);
} }
else { else {
if (node.op2type === "payl") { m2 = msg.payload; } if (node.op2type === "payl") { node.topics[topic].m2 = RED.util.cloneMessage(msg.payload); }
} }
} }
}); });
this.on("close", function() { this.on("close", function() {
if (tout) { for (var t in node.topics) {
if (node.loop === true) { clearInterval(tout); } /* istanbul ignore else */
else { clearTimeout(tout); } if (node.topics[t]) {
tout = null; if (node.loop === true) { clearInterval(node.topics[t].tout); }
else { clearTimeout(node.topics[t].tout); }
delete node.topics[t];
}
} }
node.status({}); node.status({});
}); });

View File

@@ -441,7 +441,14 @@ RED.debug = (function() {
} }
var el = $('<span class="debug-message-payload"></span>').appendTo(msg); var el = $('<span class="debug-message-payload"></span>').appendTo(msg);
var path = o.property||''; var path = o.property||'';
var debugMessage = RED.utils.createObjectElement(payload,/*true*/null,format,false,path,sourceNode&&sourceNode.id,path); var debugMessage = RED.utils.createObjectElement(payload, {
key: /*true*/null,
typeHint: format,
hideKey: false,
path: path,
sourceId: sourceNode&&sourceNode.id,
rootPath: path
});
// Do this in a separate step so the element functions aren't stripped // Do this in a separate step so the element functions aren't stripped
debugMessage.appendTo(el); debugMessage.appendTo(el);
// NOTE: relying on function error to have a "type" that all other msgs don't // NOTE: relying on function error to have a "type" that all other msgs don't

View File

@@ -165,6 +165,10 @@
</script> </script>
<script type="text/x-red" data-template-name="mqtt-broker"> <script type="text/x-red" data-template-name="mqtt-broker">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
<input type="text" id="node-config-input-name" data-i18n="[placeholder]common.label.name">
</div>
<div class="form-row"> <div class="form-row">
<ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul> <ul style="background: #fff; min-width: 600px; margin-bottom: 20px;" id="node-config-mqtt-broker-tabs"></ul>
</div> </div>
@@ -266,6 +270,7 @@
RED.nodes.registerType('mqtt-broker',{ RED.nodes.registerType('mqtt-broker',{
category: 'config', category: 'config',
defaults: { defaults: {
name: {value:""},
broker: {value:"",required:true}, broker: {value:"",required:true},
port: {value:1883,required:true,validate:RED.validators.number()}, port: {value:1883,required:true,validate:RED.validators.number()},
tls: {type:"tls-config",required: false}, tls: {type:"tls-config",required: false},
@@ -296,9 +301,15 @@
password: {type: "password"} password: {type: "password"}
}, },
label: function() { label: function() {
var b = this.broker; var lab = this.name;
if (b === "") { b = "undefined"; } if ((lab === undefined) || (lab ==="")) {
return (this.clientid?this.clientid+"@":"")+b+":"+this.port; var b = this.broker;
if (b === "") { b = "undefined"; }
lab = (this.clientid?this.clientid+"@":"")+b+":"+this.port;
}
return lab;
}, },
oneditprepare: function () { oneditprepare: function () {
var tabs = RED.tabs.create({ var tabs = RED.tabs.create({

View File

@@ -270,6 +270,9 @@
"wait-reset": "wait to be reset", "wait-reset": "wait to be reset",
"wait-for": "wait for", "wait-for": "wait for",
"wait-loop": "resend it every", "wait-loop": "resend it every",
"for": "Handling",
"bytopics": "each msg.topic independently",
"alltopics": "all messages",
"duration": { "duration": {
"ms": "Milliseconds", "ms": "Milliseconds",
"s": "Seconds", "s": "Seconds",

View File

@@ -392,7 +392,7 @@
"tip": { "tip": {
"path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。", "path1": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。",
"path2": "This path will be relative to ", "path2": "This path will be relative to ",
"url1": "URLには ws:&#47;&#47; or wss:&#47;&#47; スキーマを使用して、存在するwebsocketリスナを設定してください。", "url1": "URLには ws:&#47;&#47; または wss:&#47;&#47; スキーマを使用して、存在するwebsocketリスナを設定してください。",
"url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。" "url2": "標準では <code>payload</code> がwebsocketから送信、受信されるデータを持ちます。クライアントはJSON形式の文字列としてメッセージ全体を送信、受信するよう設定できます。"
}, },
"errors": { "errors": {

View File

@@ -199,6 +199,7 @@
} else if (type === "btwn") { } else if (type === "btwn") {
row2.hide(); row2.hide();
row3.show(); row3.show();
btwnValue2Field.typedInput('show');
} else { } else {
row2.hide(); row2.hide();
row3.hide(); row3.hide();

View File

@@ -45,7 +45,7 @@
"is-utf8":"0.2.1", "is-utf8":"0.2.1",
"js-yaml": "3.8.4", "js-yaml": "3.8.4",
"json-stringify-safe":"5.0.1", "json-stringify-safe":"5.0.1",
"jsonata":"1.2.6", "jsonata":"1.3.0",
"media-typer": "0.3.0", "media-typer": "0.3.0",
"mqtt": "2.9.0", "mqtt": "2.9.0",
"multer": "1.3.0", "multer": "1.3.0",

19
red.js
View File

@@ -167,7 +167,16 @@ if (settings.httpNodeRoot !== false) {
settings.httpNodeAuth = settings.httpNodeAuth || settings.httpAuth; settings.httpNodeAuth = settings.httpNodeAuth || settings.httpAuth;
} }
settings.uiPort = parsedArgs.port||settings.uiPort||1880; // if we got a port from command line, use it (even if 0)
// replicate (settings.uiPort = parsedArgs.port||settings.uiPort||1880;) but allow zero
if (parsedArgs.port !== undefined){
settings.uiPort = parsedArgs.port;
} else {
if (settings.uiPort === undefined){
settings.uiPort = 1880;
}
}
settings.uiHost = settings.uiHost||"0.0.0.0"; settings.uiHost = settings.uiHost||"0.0.0.0";
if (flowFile) { if (flowFile) {
@@ -261,9 +270,14 @@ if (settings.httpStatic) {
} }
function getListenPath() { function getListenPath() {
var port = settings.serverPort;
if (port === undefined){
port = settings.uiPort;
}
var listenPath = 'http'+(settings.https?'s':'')+'://'+ var listenPath = 'http'+(settings.https?'s':'')+'://'+
(settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+ (settings.uiHost == '0.0.0.0'?'127.0.0.1':settings.uiHost)+
':'+settings.uiPort; ':'+port;
if (settings.httpAdminRoot !== false) { if (settings.httpAdminRoot !== false) {
listenPath += settings.httpAdminRoot; listenPath += settings.httpAdminRoot;
} else if (settings.httpStatic) { } else if (settings.httpStatic) {
@@ -292,6 +306,7 @@ RED.start().then(function() {
if (settings.httpAdminRoot === false) { if (settings.httpAdminRoot === false) {
RED.log.info(RED.log._("server.admin-ui-disabled")); RED.log.info(RED.log._("server.admin-ui-disabled"));
} }
settings.serverPort = server.address().port;
process.title = parsedArgs.title || 'node-red'; process.title = parsedArgs.title || 'node-red';
RED.log.info(RED.log._("server.now-running", {listenpath:getListenPath()})); RED.log.info(RED.log._("server.now-running", {listenpath:getListenPath()}));
}); });

View File

@@ -84,7 +84,7 @@ function login(req,res) {
if (settings.adminAuth.type === "credentials") { if (settings.adminAuth.type === "credentials") {
response = { response = {
"type":"credentials", "type":"credentials",
"prompts":[{id:"username",type:"text",label:"Username"},{id:"password",type:"password",label:"Password"}] "prompts":[{id:"username",type:"text",label:"user.username"},{id:"password",type:"password",label:"user.password"}]
} }
} else if (settings.adminAuth.type === "strategy") { } else if (settings.adminAuth.type === "strategy") {
response = { response = {

View File

@@ -29,6 +29,7 @@
"label": { "label": {
"view": { "view": {
"view": "View", "view": "View",
"grid": "Grid",
"showGrid": "Show grid", "showGrid": "Show grid",
"snapGrid": "Snap to grid", "snapGrid": "Snap to grid",
"gridSize": "Grid size", "gridSize": "Grid size",
@@ -41,12 +42,15 @@
"sidebar": { "sidebar": {
"show": "Show sidebar" "show": "Show sidebar"
}, },
"userSettings": "Settings", "settings": "Settings",
"userSettings": "User Settings",
"nodes": "Nodes",
"displayStatus": "Show node status", "displayStatus": "Show node status",
"displayConfig": "Configuration nodes", "displayConfig": "Configuration nodes",
"import": "Import", "import": "Import",
"export": "Export", "export": "Export",
"search": "Search flows", "search": "Search flows",
"searchInput": "search your flows",
"clipboard": "Clipboard", "clipboard": "Clipboard",
"library": "Library", "library": "Library",
"examples": "Examples", "examples": "Examples",
@@ -61,11 +65,15 @@
"login": "Login", "login": "Login",
"logout": "Logout", "logout": "Logout",
"editPalette":"Manage palette", "editPalette":"Manage palette",
"showTips": "Show tips" "other": "Other",
"showTips": "Show tips",
"help": "Node-RED website"
} }
}, },
"user": { "user": {
"loggedInAs": "Logged in as __name__", "loggedInAs": "Logged in as __name__",
"username": "Username",
"password": "Password",
"login": "Login", "login": "Login",
"loginFailed": "Login failed", "loginFailed": "Login failed",
"notAuthorized": "Not authorized" "notAuthorized": "Not authorized"
@@ -145,6 +153,7 @@
"improperlyConfigured": "The workspace contains some nodes that are not properly configured:", "improperlyConfigured": "The workspace contains some nodes that are not properly configured:",
"unknown": "The workspace contains some unknown node types:", "unknown": "The workspace contains some unknown node types:",
"confirm": "Are you sure you want to deploy?", "confirm": "Are you sure you want to deploy?",
"doNotWarn": "do not warn about this again",
"conflict": "The server is running a more recent set of flows.", "conflict": "The server is running a more recent set of flows.",
"backgroundUpdate": "The flows on the server have been updated.", "backgroundUpdate": "The flows on the server have been updated.",
"conflictChecking": "Checking to see if the changes can be merged automatically", "conflictChecking": "Checking to see if the changes can be merged automatically",
@@ -155,6 +164,8 @@
"diff": { "diff": {
"unresolvedCount": "__count__ unresolved conflict", "unresolvedCount": "__count__ unresolved conflict",
"unresolvedCount_plural": "__count__ unresolved conflicts", "unresolvedCount_plural": "__count__ unresolved conflicts",
"globalNodes": "Global nodes",
"flowProperties": "Flow Properties",
"type": { "type": {
"added": "added", "added": "added",
"changed": "changed", "changed": "changed",
@@ -167,8 +178,8 @@
}, },
"nodeCount": "__count__ node", "nodeCount": "__count__ node",
"nodeCount_plural": "__count__ nodes", "nodeCount_plural": "__count__ nodes",
"local":"Local", "local":"Local changes",
"remote":"Remote" "remote":"Remote changes"
}, },
"subflow": { "subflow": {
@@ -210,7 +221,13 @@
}, },
"keyboard": { "keyboard": {
"title": "Keyboard Shortcuts", "title": "Keyboard Shortcuts",
"keyboard": "Keyboard",
"filterActions": "filter actions",
"shortcut": "shortcut",
"scope": "scope",
"unassigned": "Unassigned", "unassigned": "Unassigned",
"global": "global",
"workspace": "workspace",
"selectAll": "Select all nodes", "selectAll": "Select all nodes",
"selectAllConnected": "Select all connected nodes", "selectAllConnected": "Select all connected nodes",
"addRemoveNode": "Add/remove node from selection", "addRemoveNode": "Add/remove node from selection",
@@ -275,6 +292,7 @@
}, },
"editor": { "editor": {
"title": "Manage palette", "title": "Manage palette",
"palette": "Palette",
"times": { "times": {
"seconds": "seconds ago", "seconds": "seconds ago",
"minutes": "minutes ago", "minutes": "minutes ago",
@@ -353,16 +371,24 @@
"sidebar": { "sidebar": {
"info": { "info": {
"name": "Node information", "name": "Node information",
"tabName": "Name",
"label": "info", "label": "info",
"node": "Node", "node": "Node",
"type": "Type", "type": "Type",
"id": "ID", "id": "ID",
"status": "Status",
"enabled": "Enabled",
"disabled": "Disabled",
"subflow": "Subflow", "subflow": "Subflow",
"instances": "Instances", "instances": "Instances",
"properties": "Properties", "properties": "Properties",
"info": "Information", "info": "Information",
"blank": "blank", "blank": "blank",
"null": "null", "null": "null",
"showMore": "show more",
"showLess": "show less",
"flow": "Flow",
"information": "Information",
"arrayItems": "__count__ items", "arrayItems": "__count__ items",
"showTips":"You can open the tips from the settings panel" "showTips":"You can open the tips from the settings panel"
}, },
@@ -389,6 +415,7 @@
"re": "regular expression", "re": "regular expression",
"bool": "boolean", "bool": "boolean",
"json": "JSON", "json": "JSON",
"bin": "buffer",
"date": "timestamp" "date": "timestamp"
} }
}, },

View File

@@ -95,6 +95,10 @@
"args":"", "args":"",
"desc":"Returns a pseudo random number greater than or equal to zero and less than one." "desc":"Returns a pseudo random number greater than or equal to zero and less than one."
}, },
"$millis": {
"args":"",
"desc":"Returns the number of milliseconds since the Unix Epoch (1 January, 1970 UTC) as a number. All invocations of `$millis()` within an evaluation of an expression will all return the same value."
},
"$sum": { "$sum": {
"args": "array", "args": "array",
"desc": "Returns the arithmetic sum of an `array` of numbers. It is an error if the input `array` contains an item which isn't a number." "desc": "Returns the arithmetic sum of an `array` of numbers. It is an error if the input `array` contains an item which isn't a number."
@@ -160,6 +164,10 @@
"args": "object", "args": "object",
"desc": "Splits an object containing key/value pairs into an array of objects, each of which has a single key/value pair from the input object. If the parameter is an array of objects, then the resultant array contains an object for every key/value pair in every object in the supplied array." "desc": "Splits an object containing key/value pairs into an array of objects, each of which has a single key/value pair from the input object. If the parameter is an array of objects, then the resultant array contains an object for every key/value pair in every object in the supplied array."
}, },
"$merge": {
"args": "array&lt;object&gt;",
"desc": "Merges an array of `objects` into a single `object` containing all the key/value pairs from each of the objects in the input array. If any of the input objects contain the same key, then the returned `object` will contain the value of the last one in the array. It is an error if the input array contains an item that is not an object."
},
"$sift": { "$sift": {
"args":"object, function", "args":"object, function",
"desc":"Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`" "desc":"Returns an object that contains only the key/value pairs from the `object` parameter that satisfy the predicate `function` passed in as the second parameter.\n\nThe `function` that is supplied as the second parameter must have the following signature:\n\n`function(value [, key [, object]])`"

View File

@@ -29,6 +29,7 @@
"label": { "label": {
"view": { "view": {
"view": "表示", "view": "表示",
"grid": "グリッド",
"showGrid": "グリッドを表示", "showGrid": "グリッドを表示",
"snapGrid": "ノードの配置を補助", "snapGrid": "ノードの配置を補助",
"gridSize": "グリッドの大きさ", "gridSize": "グリッドの大きさ",
@@ -41,12 +42,15 @@
"sidebar": { "sidebar": {
"show": "サイドバーを表示" "show": "サイドバーを表示"
}, },
"userSettings": "設定", "settings": "設定",
"userSettings": "ユーザ設定",
"nodes": "ノード",
"displayStatus": "ノードの状態を表示", "displayStatus": "ノードの状態を表示",
"displayConfig": "ノードの設定", "displayConfig": "ノードの設定",
"import": "読み込み", "import": "読み込み",
"export": "書き出し", "export": "書き出し",
"search": "ノードを検索", "search": "ノードを検索",
"searchInput": "ノードを検索",
"clipboard": "クリップボード", "clipboard": "クリップボード",
"library": "ライブラリ", "library": "ライブラリ",
"examples": "サンプル", "examples": "サンプル",
@@ -61,11 +65,15 @@
"login": "ログイン", "login": "ログイン",
"logout": "ログアウト", "logout": "ログアウト",
"editPalette": "パレットの管理", "editPalette": "パレットの管理",
"showTips": "ヒントを表示" "other": "その他",
"showTips": "ヒントを表示",
"help": "Node-REDウェブサイト"
} }
}, },
"user": { "user": {
"loggedInAs": "__name__ としてログインしました", "loggedInAs": "__name__ としてログインしました",
"username": "ユーザ名",
"password": "パスワード",
"login": "ログイン", "login": "ログイン",
"loginFailed": "ログインに失敗しました", "loginFailed": "ログインに失敗しました",
"notAuthorized": "権限がありません" "notAuthorized": "権限がありません"
@@ -75,7 +83,7 @@
"warnings": { "warnings": {
"undeployedChanges": "ノードの変更をデプロイしていません", "undeployedChanges": "ノードの変更をデプロイしていません",
"nodeActionDisabled": "ノードのアクションは、サブフロー内で無効になっています", "nodeActionDisabled": "ノードのアクションは、サブフロー内で無効になっています",
"missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください", "missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください",
"restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります" "restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります"
}, },
"error": "<strong>エラー</strong>: __message__", "error": "<strong>エラー</strong>: __message__",
@@ -85,7 +93,7 @@
"lostConnectionTry": "すぐに接続", "lostConnectionTry": "すぐに接続",
"cannotAddSubflowToItself": "サブフロー自身を追加できません", "cannotAddSubflowToItself": "サブフロー自身を追加できません",
"cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません", "cannotAddCircularReference": "循環参照を検出したため、サブフローを追加できません",
"unsupportedVersion": "サポートされていないバージョンのNode.jsを使用しています。<br/>最新のNode.js LTSに更新してください" "unsupportedVersion": "サポートされていないバージョンのNode.jsを使用しています。<br/>最新のNode.js LTSに更新してください"
} }
}, },
"clipboard": { "clipboard": {
@@ -144,6 +152,7 @@
"improperlyConfigured": "以下のノードは、正しくプロパティが設定されていません:", "improperlyConfigured": "以下のノードは、正しくプロパティが設定されていません:",
"unknown": "ワークスペースに未知の型のノードがあります。", "unknown": "ワークスペースに未知の型のノードがあります。",
"confirm": "このままデプロイしても良いですか?", "confirm": "このままデプロイしても良いですか?",
"doNotWarn": "この警告を再度表示しない",
"conflict": "フローを編集している間に、他のブラウザがフローをデプロイしました。デプロイを継続すると、他のブラウザがデプロイしたフローが削除されます。", "conflict": "フローを編集している間に、他のブラウザがフローをデプロイしました。デプロイを継続すると、他のブラウザがデプロイしたフローが削除されます。",
"backgroundUpdate": "サーバ上のフローが更新されました", "backgroundUpdate": "サーバ上のフローが更新されました",
"conflictChecking": "変更を自動的にマージしてよいか確認してください。", "conflictChecking": "変更を自動的にマージしてよいか確認してください。",
@@ -154,6 +163,8 @@
"diff": { "diff": {
"unresolvedCount": "未解決の衝突 __count__", "unresolvedCount": "未解決の衝突 __count__",
"unresolvedCount_plural": "未解決の衝突 __count__", "unresolvedCount_plural": "未解決の衝突 __count__",
"globalNodes": "グローバルノード",
"flowProperties": "フロープロパティ",
"type": { "type": {
"added": "追加", "added": "追加",
"changed": "変更", "changed": "変更",
@@ -166,8 +177,8 @@
}, },
"nodeCount": "ノード数 __count__", "nodeCount": "ノード数 __count__",
"nodeCount_plural": "ノード数 __count__", "nodeCount_plural": "ノード数 __count__",
"local": "ローカル", "local": "ローカルの変更",
"remote": "リモート" "remote": "リモートの変更"
}, },
"subflow": { "subflow": {
"editSubflow": "フローのテンプレートを編集: __name__", "editSubflow": "フローのテンプレートを編集: __name__",
@@ -208,7 +219,13 @@
}, },
"keyboard": { "keyboard": {
"title": "キーボードショートカット", "title": "キーボードショートカット",
"keyboard": "キーボード",
"filterActions": "動作を検索",
"shortcut": "ショートカット",
"scope": "範囲",
"unassigned": "未割当", "unassigned": "未割当",
"global": "グローバル",
"workspace": "ワークスペース",
"selectAll": "全てのノードを選択", "selectAll": "全てのノードを選択",
"selectAllConnected": "接続された全てのノードを選択", "selectAllConnected": "接続された全てのノードを選択",
"addRemoveNode": "ノードの選択、選択解除", "addRemoveNode": "ノードの選択、選択解除",
@@ -234,8 +251,8 @@
"exportToLibrary": "ライブラリへフローを書き出す", "exportToLibrary": "ライブラリへフローを書き出す",
"dialogSaveOverwrite": "__libraryName__ という __libraryType__ は既に存在しています 上書きしますか?", "dialogSaveOverwrite": "__libraryName__ という __libraryType__ は既に存在しています 上書きしますか?",
"invalidFilename": "不正なファイル名", "invalidFilename": "不正なファイル名",
"savedNodes": "保存されたノード", "savedNodes": "フローを保存しました",
"savedType": "保存された __type__", "savedType": "__type__ を保存しました",
"saveFailed": "保存に失敗しました: __message__", "saveFailed": "保存に失敗しました: __message__",
"filename": "ファイル名", "filename": "ファイル名",
"folder": "フォルダ", "folder": "フォルダ",
@@ -271,6 +288,7 @@
}, },
"editor": { "editor": {
"title": "パレットの管理", "title": "パレットの管理",
"palette": "パレット",
"times": { "times": {
"seconds": "秒前", "seconds": "秒前",
"minutes": "分前", "minutes": "分前",
@@ -312,12 +330,12 @@
"sortRecent": "日付順", "sortRecent": "日付順",
"more": "+ さらに __count__ 個", "more": "+ さらに __count__ 個",
"errors": { "errors": {
"catalogLoadFailed": "ノードのカタログの読み込みに失敗しました<br>詳細はブラウザのコンソールを確認してください", "catalogLoadFailed": "ノードのカタログの読み込みに失敗しました<br>詳細はブラウザのコンソールを確認してください",
"installFailed": "追加処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください", "installFailed": "追加処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください",
"removeFailed": "削除処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください", "removeFailed": "削除処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください",
"updateFailed": "更新処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください", "updateFailed": "更新処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください",
"enableFailed": "有効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください", "enableFailed": "有効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください",
"disableFailed": "無効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください" "disableFailed": "無効化処理が失敗しました: __module__<br>__message__<br>詳細はログを確認してください"
}, },
"confirm": { "confirm": {
"install": { "install": {
@@ -347,16 +365,24 @@
"sidebar": { "sidebar": {
"info": { "info": {
"name": "ノードの情報を表示", "name": "ノードの情報を表示",
"tabName": "名前",
"label": "情報", "label": "情報",
"node": "ノード", "node": "ノード",
"type": "型", "type": "型",
"id": "ID", "id": "ID",
"status": "状態",
"enabled": "有効",
"disabled": "無効",
"subflow": "サブフロー", "subflow": "サブフロー",
"instances": "インスタンス", "instances": "インスタンス",
"properties": "プロパティ", "properties": "プロパティ",
"info": "情報", "info": "情報",
"blank": "ブランク", "blank": "ブランク",
"null": "ヌル", "null": "ヌル",
"showMore": "さらに表示",
"showLess": "表示を省略",
"flow": "フロー",
"information": "情報",
"arrayItems": "__count__ 要素", "arrayItems": "__count__ 要素",
"showTips": "設定からヒントを表示できます" "showTips": "設定からヒントを表示できます"
}, },
@@ -383,6 +409,7 @@
"re": "正規表現", "re": "正規表現",
"bool": "真偽", "bool": "真偽",
"json": "JSON", "json": "JSON",
"bin": "バッファ",
"date": "日時" "date": "日時"
} }
}, },

View File

@@ -155,6 +155,9 @@ function start() {
if (settings.settingsFile) { if (settings.settingsFile) {
log.info(log._("runtime.paths.settings",{path:settings.settingsFile})); log.info(log._("runtime.paths.settings",{path:settings.settingsFile}));
} }
if (settings.httpStatic) {
log.info(log._("runtime.paths.httpStatic",{path:path.resolve(settings.httpStatic)}));
}
redNodes.loadFlows().then(redNodes.startFlows); redNodes.loadFlows().then(redNodes.startFlows);
started = true; started = true;
}).otherwise(function(err) { }).otherwise(function(err) {

View File

@@ -4,7 +4,8 @@
"version": "__component__ version: __version__", "version": "__component__ version: __version__",
"unsupported_version": "Unsupported version of __component__. Requires: __requires__ Found: __version__", "unsupported_version": "Unsupported version of __component__. Requires: __requires__ Found: __version__",
"paths": { "paths": {
"settings": "Settings file : __path__" "settings": "Settings file : __path__",
"httpStatic": "HTTP Static : __path__"
} }
}, },

View File

@@ -45,62 +45,64 @@ function getFileMeta(root,path) {
var meta = {}; var meta = {};
var read = 0; var read = 0;
var length = 10; var length = 10;
var remaining = ""; var remaining = Buffer(0);
var buffer = Buffer(length); var buffer = Buffer(length);
var idx = -1;
while(read < size) { while(read < size) {
read+=fs.readSync(fd,buffer,0,length); read+=fs.readSync(fd,buffer,0,length);
var data = remaining+buffer.toString(); var data = Buffer.concat([remaining,buffer]);
var parts = data.split("\n"); while((idx = data.indexOf("\n")) != -1){
remaining = parts.splice(-1); var part = data.slice(0,idx+1);
for (var i=0;i<parts.length;i+=1) { var match = /^\/\/ (\w+): (.*)/.exec(part.toString());
var match = /^\/\/ (\w+): (.*)/.exec(parts[i]);
if (match) { if (match) {
meta[match[1]] = match[2]; meta[match[1]] = match[2];
} else { } else {
read = size; read = size;
break; break;
} }
data = data.slice(idx+1);
} }
remaining = data;
} }
fs.closeSync(fd); fs.closeSync(fd);
return meta; return meta;
} }
function getFileBody(root,path) { function getFileBody(root,path) {
var body = ""; var body = Buffer(0);
var fn = fspath.join(root,path); var fn = fspath.join(root,path);
var fd = fs.openSync(fn,"r"); var fd = fs.openSync(fn,"r");
var size = fs.fstatSync(fd).size; var size = fs.fstatSync(fd).size;
var scanning = true; var scanning = true;
var read = 0; var read = 0;
var length = 50; var length = 50;
var remaining = ""; var remaining = Buffer(0);
var buffer = Buffer(length); var buffer = Buffer(length);
var idx = -1;
while(read < size) { while(read < size) {
var thisRead = fs.readSync(fd,buffer,0,length); var thisRead = fs.readSync(fd,buffer,0,length);
read += thisRead; read += thisRead;
if (scanning) { if (scanning) {
var data = remaining+buffer.slice(0,thisRead).toString(); var data = Buffer.concat([remaining,buffer.slice(0,thisRead)]);
var parts = data.split("\n"); while((idx = data.indexOf("\n")) != -1){
remaining = parts.splice(-1)[0]; var part = data.slice(0,idx+1);
for (var i=0;i<parts.length;i+=1) { if (! /^\/\/ \w+: /.test(part.toString())) {
if (! /^\/\/ \w+: /.test(parts[i])) {
scanning = false; scanning = false;
body += parts[i]+"\n"; body = Buffer.concat([body,data]);
break;
} }
data = data.slice(idx+1);
} }
if (! /^\/\/ \w+: /.test(remaining)) { remaining = data;
scanning = false; if (scanning && read >= size) {
} body = Buffer.concat([body,remaining]);
if (!scanning) {
body += remaining;
} }
} else { } else {
body += buffer.slice(0,thisRead).toString(); body = Buffer.concat([body,buffer.slice(0,thisRead)]);
} }
} }
fs.closeSync(fd); fs.closeSync(fd);
return body; return body.toString();
} }
/** /**

View File

@@ -15,8 +15,10 @@
**/ **/
var should = require("should"); var should = require("should");
var sinon = require("sinon");
var helper = require("../../helper.js"); var helper = require("../../helper.js");
var triggerNode = require("../../../../nodes/core/core/89-trigger.js"); var triggerNode = require("../../../../nodes/core/core/89-trigger.js");
var RED = require("../../../../red/red.js");
describe('trigger node', function() { describe('trigger node', function() {
@@ -81,14 +83,17 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", '1'); if (c === 0) {
c+=1; msg.should.have.a.property("payload", '1');
} c+=1;
else { }
msg.should.have.a.property("payload", '0'); else {
done(); msg.should.have.a.property("payload", '0');
done();
}
} }
catch(err) { done(err); }
}); });
n1.emit("input", {payload:null}); n1.emit("input", {payload:null});
}); });
@@ -161,6 +166,155 @@ describe('trigger node', function() {
}); });
}); });
it('should handle multiple topics as one if not asked to handle', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"all", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
c += 1;
if (c === 1) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "A");
}
else if (c === 2) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "A");
done();
}
} catch(err) {
done(err);
}
});
n1.emit("input", {payload:1,topic:"A"});
n1.emit("input", {payload:2,topic:"B"});
n1.emit("input", {payload:3,topic:"C"});
});
});
it('should handle multiple topics individually if asked to do so', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
c += 1;
if (c === 1) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "A");
}
else if (c === 2) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "B");
}
else if (c === 3) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "C");
}
else if (c === 4) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "A");
}
else if (c === 5) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "B");
}
else if (c === 6) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "C");
done();
}
} catch(err) {
done(err);
}
});
n1.emit("input", {payload:1,topic:"A"});
n1.emit("input", {payload:2,topic:"B"});
n1.emit("input", {payload:3,topic:"C"});
});
});
it('should handle multiple topics individually, and extend one, if asked to do so', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", extend:"true", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
c += 1;
if (c === 1) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "A");
}
else if (c === 2) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "B");
}
else if (c === 3) {
msg.should.have.a.property("payload", 1);
msg.should.have.a.property("topic", "C");
}
else if (c === 4) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "A");
}
else if (c === 5) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "C");
}
else if (c === 6) {
msg.should.have.a.property("payload", 0);
msg.should.have.a.property("topic", "B");
done();
}
} catch(err) {
done(err);
}
});
n1.emit("input", {payload:1,topic:"A"});
n1.emit("input", {payload:2,topic:"B"});
n1.emit("input", {payload:3,topic:"C"});
setTimeout( function() { n1.emit("input", {payload:2,topic:"B"})}, 20 );
});
});
it('should be able to return things from flow and global context variables', function(done) {
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
function(arg1, arg2, arg3, arg4) { return arg1; }
);
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"flow", op2:"bar", op2type:"global", duration:"20", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
if (c === 0) {
msg.should.have.a.property("payload", "foo");
c+=1;
}
else {
msg.should.have.a.property("payload", "bar");
spy.restore();
done();
}
}
catch(err) { spy.restore(); done(err); }
});
n1.emit("input", {payload:null});
});
});
it('should be able to not output anything on first trigger', function(done) { it('should be able to not output anything on first trigger', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"nul", op1:"true",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] }, var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"nul", op1:"true",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] },
{id:"n2", type:"helper"} ]; {id:"n2", type:"helper"} ];
@@ -187,8 +341,11 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
msg.should.have.a.property("payload", true); try {
c += 1; msg.should.have.a.property("payload", true);
c += 1;
}
catch(err) { done(err); }
}); });
setTimeout( function() { setTimeout( function() {
c.should.equal(1); // should only have had one output. c.should.equal(1); // should only have had one output.
@@ -199,23 +356,30 @@ describe('trigger node', function() {
}); });
it('should be able to extend the delay', function(done) { it('should be able to extend the delay', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op1:"false", op2:"true", duration:"100", wires:[["n2"]] }, var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
function(arg1, arg2, arg3, arg4) { return arg1; }
);
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"flow", op1:"foo", op2:"bar", op2type:"global", duration:"100", wires:[["n2"]] },
{id:"n2", type:"helper"} ]; {id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() { helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", "Hello"); if (c === 0) {
c += 1; msg.should.have.a.property("payload", "foo");
} c += 1;
else { }
msg.should.have.a.property("payload", "true"); else {
//console.log(Date.now() - ss); msg.should.have.a.property("payload", "bar");
(Date.now() - ss).should.be.greaterThan(149); //console.log(Date.now() - ss);
done(); (Date.now() - ss).should.be.greaterThan(149);
spy.restore();
done();
}
} }
catch(err) { spy.restore(); done(err); }
}); });
var ss = Date.now(); var ss = Date.now();
n1.emit("input", {payload:"Hello"}); n1.emit("input", {payload:"Hello"});
@@ -233,16 +397,19 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", "Hello"); if (c === 0) {
c += 1; msg.should.have.a.property("payload", "Hello");
} c += 1;
else { }
msg.should.have.a.property("payload", "World"); else {
//console.log(Date.now() - ss); msg.should.have.a.property("payload", "World");
(Date.now() - ss).should.be.greaterThan(70); //console.log(Date.now() - ss);
done(); (Date.now() - ss).should.be.greaterThan(70);
done();
}
} }
catch(err) { done(err); }
}); });
var ss = Date.now(); var ss = Date.now();
n1.emit("input", {payload:"Hello"}); n1.emit("input", {payload:"Hello"});
@@ -263,15 +430,18 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", "Goodbye"); if (c === 0) {
c += 1; msg.should.have.a.property("payload", "Goodbye");
} c += 1;
else { }
msg.should.have.a.property("payload", "World"); else {
(Date.now() - ss).should.be.greaterThan(70); msg.should.have.a.property("payload", "World");
done(); (Date.now() - ss).should.be.greaterThan(70);
done();
}
} }
catch(err) { done(err); }
}); });
var ss = Date.now(); var ss = Date.now();
n1.emit("input", {payload:"Hello"}); n1.emit("input", {payload:"Hello"});
@@ -292,15 +462,18 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", "Goodbye"); if (c === 0) {
c += 1; msg.should.have.a.property("payload", "Goodbye");
} c += 1;
else { }
msg.should.have.a.property("payload", "World"); else {
(Date.now() - ss).should.be.greaterThan(70); msg.should.have.a.property("payload", "World");
done(); (Date.now() - ss).should.be.greaterThan(70);
done();
}
} }
catch(err) { done(err); }
}); });
var ss = Date.now(); var ss = Date.now();
n1.emit("input", {payload:"Hello"}); n1.emit("input", {payload:"Hello"});
@@ -321,14 +494,17 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", "Hello"); if (c === 0) {
c+=1; msg.should.have.a.property("payload", "Hello");
} c+=1;
else { }
msg.should.have.a.property("payload", "World"); else {
done(); msg.should.have.a.property("payload", "World");
done();
}
} }
catch(err) { done(err); }
}); });
n1.emit("input", {payload:"Hello",topic:"World"}); n1.emit("input", {payload:"Hello",topic:"World"});
}); });
@@ -342,19 +518,46 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
if (c === 0) { try {
msg.should.have.a.property("payload", null); if (c === 0) {
c+=1; msg.should.have.a.property("payload", null);
} c+=1;
else { }
msg.should.have.a.property("payload", "World"); else {
done(); msg.should.have.a.property("payload", "World");
done();
}
} }
catch(err) { done(err); }
}); });
n1.emit("input", {payload:"World"}); n1.emit("input", {payload:"World"});
}); });
}); });
it('should handle string null as null on op2', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"null", op2:"null", duration:"40", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
if (c === 0) {
msg.should.have.a.property("payload", null);
c+=1;
}
else {
msg.should.have.a.property("payload", null);
done();
}
}
catch(err) { done(err); }
});
n1.emit("input", {payload:"null"});
});
});
it('should be able to set infinite timeout, and clear timeout', function(done) { it('should be able to set infinite timeout, and clear timeout', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"0", extend: false, wires:[["n2"]] }, var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"0", extend: false, wires:[["n2"]] },
{id:"n2", type:"helper"} ]; {id:"n2", type:"helper"} ];
@@ -363,8 +566,11 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
c += 1; try {
msg.should.have.a.property("payload", 1); c += 1;
msg.should.have.a.property("payload", "1");
}
catch(err) { done(err); }
}); });
setTimeout( function() { setTimeout( function() {
if (c === 2) { done(); } if (c === 2) { done(); }
@@ -388,8 +594,11 @@ describe('trigger node', function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
c += 1; try {
msg.should.have.a.property("payload", 1); c += 1;
msg.should.have.a.property("payload", "1");
}
catch(err) { done(err); }
}); });
setTimeout( function() { setTimeout( function() {
if (c === 2) { done(); } if (c === 2) { done(); }
@@ -406,7 +615,7 @@ describe('trigger node', function() {
}); });
it('should be able to set a repeat, and clear loop by reset', function(done) { it('should be able to set a repeat, and clear loop by reset', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", duration:-25, wires:[["n2"]] }, var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", op1:"", op1type:"pay", duration:-25, wires:[["n2"]] },
{id:"n2", type:"helper"} ]; {id:"n2", type:"helper"} ];
helper.load(triggerNode, flow, function() { helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
@@ -414,9 +623,14 @@ describe('trigger node', function() {
var c = 0; var c = 0;
n2.on("input", function(msg) { n2.on("input", function(msg) {
c += 1; c += 1;
msg.should.have.a.property("payload", "foo"); try {
msg.should.have.property('payload','foo');
msg.payload = "bar"; // try to provoke pass by reference error
}
catch(err) { done(err); }
}); });
n1.emit("input", {payload:"foo"}); // trigger n1.emit("input", {payload:"foo"}); // trigger
n1.emit("input", {payload:"foo"}); // trigger
setTimeout( function() { setTimeout( function() {
n1.emit("input", {reset:true}); // reset n1.emit("input", {reset:true}); // reset
},90); },90);