1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Split node UI rework - WIP

This commit is contained in:
Nick O'Leary 2016-06-04 00:40:40 +01:00
parent 762eb07dd4
commit 9f8c32ce8f
5 changed files with 772 additions and 9 deletions

View File

@ -150,7 +150,11 @@
this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect); this.typeField = $("<input>",{type:'hidden'}).appendTo(this.uiSelect);
} }
this.selectTrigger = $('<a href="#"><i class="fa fa-sort-desc"></i></a>').prependTo(this.uiSelect); this.selectTrigger = $('<a href="#"></a>').prependTo(this.uiSelect);
$('<i class="fa fa-sort-desc"></i>').appendTo(this.selectTrigger);
if (this.types.length === 1) {
this.selectTrigger.addClass("disabled");
}
this.selectLabel = $('<span></span>').appendTo(this.selectTrigger); this.selectLabel = $('<span></span>').appendTo(this.selectTrigger);
this.element.on('focus', function() { this.element.on('focus', function() {
@ -162,11 +166,17 @@
this.element.on('change', function() { this.element.on('change', function() {
that.validate(); that.validate();
}) })
if (this.types.length > 1) {
this.selectTrigger.click(function(event) { this.selectTrigger.click(function(event) {
event.preventDefault(); event.preventDefault();
that._showMenu(that.menu,that.selectTrigger); that._showMenu(that.menu,that.selectTrigger);
}); });
} else {
this.selectTrigger.click(function(event) {
event.preventDefault();
that.element.focus();
})
}
if (hasSubOptions) { if (hasSubOptions) {

View File

@ -57,21 +57,26 @@
margin-top: 1px; margin-top: 1px;
vertical-align: middle; vertical-align: middle;
} }
&.disabled {
cursor: default;
i {
color: #bbb;
}
}
span { span {
display: inline-block; display: inline-block;
height: 100%; height: 100%;
padding: 0 1px 0 5px; padding: 0 1px 0 5px;
} }
&:hover { &:not(.disabled):hover {
text-decoration: none; text-decoration: none;
background: $typedInput-button-background-hover; background: $typedInput-button-background-hover;
} }
&:focus { &:focus {
text-decoration: none; text-decoration: none;
} }
&:active { &:not(.disabled):active {
background: $typedInput-button-background-active; background: $typedInput-button-background-active;
text-decoration: none; text-decoration: none;
} }

View File

@ -0,0 +1,164 @@
<!DOCTYPE html>
<!--
Copyright 2016 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<script type="text/x-red" data-template-name="split">
<div class="form-row">
<label for="node-input-splt"><i class="fa fa-scissors"></i> Split</label>
<input type="text" id="node-input-splt" placeholder="character to split strings on : e.g. \n">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
</script>
<script type="text/x-red" data-help-name="split">
<p>A function that splits the <code>msg.payload</code> in various ways to create multiple messages out.</p>
<p><ul>
<li>splits an <b>array</b> into individual messages, one element per message.</li>
<li>splits a <b>string</b> on a character - default is <code>""</code>, split on every character. A typical
use would be <code>\n</code> to split on line breaks. Split is actually a regex value so use <code>\.</code> to
split on a full stop .</li>
<li>splits an <b>object</b> into individual messages, promoting each property value to the <code>msg.payload</code>,
and saving each property key name as <code>msg.parts.key</code>.
</ul></p>
</script>
<script type="text/javascript">
RED.nodes.registerType('split',{
category: 'function',
color:"#E2D96E",
defaults: {
name: {value:""},
splt: {value:""}
},
inputs:1,
outputs:1,
icon: "switch.png",
align: "right",
label: function() {
return this.name||"split";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
}
});
</script>
<script type="text/x-red" data-template-name="join">
<div class="form-row">
<label for="node-input-out"><i class="fa fa-long-arrow-right"></i> Output</label>
<select id="node-input-out" style="width:70%; margin-right:5px;">
<option value="auto">automatic</option>
<option value="str">a String of joined properties</option>
<option value="arr">an Array of properties</option>
<option value="obj">an Object of key/property pairs</option>
</select>
</div>
<div class="form-row node-row-key">
<label for="node-input-key" style="padding-right: 10px; box-sizing: border-box; text-align: right;">Key</label>
<input type="text" id="node-input-key">
</div>
<div class="form-row node-row-property">
<label for="node-input-property" style="padding-right: 10px; box-sizing: border-box; text-align: right;">Property</label>
<input type="text" id="node-input-property">
<input type="hidden" id="node-input-propertyType">
</div>
<div class="form-row node-row-join">
<label for="node-input-join" style="padding-right: 10px; box-sizing: border-box; text-align: right;">joined using</label>
<input type="text" id="node-input-join" style="width: 40px">
</div>
<div class="form-row node-row-trigger">
<label style="width: auto;">Send the message:</label>
<div style="height: 40px;">
<label style="margin-left: 40px; width: auto;"><input type="checkbox" style="width: auto;margin-bottom: 5px;"> after a fixed number of messages: <input type="text" style="width: 75px;"></label>
</div>
<div style="height: 40px;">
<label style="margin-left: 40px; width: auto;"><input type="checkbox" style="width: auto;margin-bottom: 5px;"> after a timeout following the first message: <input placeholder="seconds" type="text" style="width: 75px;"></label>
</div>
<div style="height: 40px; padding-top: 6px;" class="node-row-accumulate">
<label style="margin-left: 40px; width: auto;"><input type="checkbox" style="width: auto;margin-bottom: 5px;"> whenever a property is updated</label>
</div>
</div>
<div class="form-tips form-tips-auto hide">This mode assumes this node is either
paired with a <i>split</i> node or the received messages will have a properly
configured <code>msg.parts</code> property.</div>
</script>
<script type="text/x-red" data-help-name="join">
<p>A function that joins <code>msg.payload</code> from multiple msgs to create a single msg out.</p>
<p>Other properties of the msg are not guaranteed as they could come from any of the incoming msgs.</p>
<p>An optional <i>count</i> can be set that waits for that many <code>payload</code> to arrive before passing on the new message.</p>
<p>An optional <i>timeout</i> can be set that can then send the incomplete message, drop the message or raise a catchable error.</p>
<p>An optional <i>join character</i> can be set that can be used for joining multiple payloads together and returns a
string rather than an array.</p>
<p>When used with a <b>split</b> node the <i>count</i> and <i>join character</i> are automatically set - but can be
overridden by values in the configuration.</p>
<p>Messages can be joined into an <i>array</i> or <i>object</i>. To be joined into an object the incoming message must
have either a <code>msg.key</code> or <code>msg.topic</code> property - or <code>msg.payload</code> should
be an object with properties.</p>
</script>
<script type="text/javascript">
RED.nodes.registerType('join',{
category: 'function',
color:"#E2D96E",
defaults: {
name: {value:""},
out: { value:"auto"},
property: { value: "payload"},
timeout: {value:""},
timerr: {value:"send"},
count: {value:""},
joiner: {value:""},
build: {value:"array"}
},
inputs:1,
outputs:1,
icon: "join.png",
label: function() {
return this.name||"join";
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
$("#node-input-out").change(function(e) {
var val = $(this).val();
$(".node-row-key").toggle(val==='obj');
$(".node-row-property").toggle(val!=='auto');
$(".node-row-join").toggle(val==='str');
$(".node-row-trigger").toggle(val!=='auto');
$(".node-row-accumulate").toggle(val==='obj');
$(".form-tips-auto").toggle(val==='auto');
})
$("#node-input-property").typedInput({
typeField: $("#node-input-propertyType"),
types:['msg', {value:"full",label:"complete message",hasValue:false}]
})
$("#node-input-key").typedInput({
types:['msg']
})
$("#node-input-out").change();
}
});
</script>

View File

@ -0,0 +1,205 @@
/**
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
module.exports = function(RED) {
"use strict";
function SplitNode(n) {
RED.nodes.createNode(this,n);
this.splt = n.splt || "";
this.split = new RegExp(this.splt);
var node = this;
this.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) {
var a = msg.payload;
if (msg.hasOwnProperty("parts")) { msg.parts = { parts:msg.parts }; } // push existing parts to a stack
else { msg.parts = {}; }
msg.parts.id = msg._msgid; // use the existing _msgid by default.
if (typeof msg.payload === "string") { // Split String into array
a = msg.payload.split(node.split);
msg.parts.ch = node.splt; // pass the split char to other end for rejoin
msg.parts.type = "string";
}
if (Array.isArray(a)) { // then split array into messages
msg.parts.type = msg.parts.type || "array"; // if it wasn't a string in the first place
for (var i = 0; i < a.length; i++) {
msg.payload = a[i];
msg.parts.index = i;
msg.parts.count = a.length;
node.send(msg);
}
}
else if ((typeof msg.payload === "object") && !Buffer.isBuffer(msg.payload)) {
var j = 0;
var l = Object.keys(msg.payload).length;
var pay = msg.payload;
msg.parts.type = "object";
for (var p in pay) {
if (pay.hasOwnProperty(p)) {
msg.payload = pay[p];
msg.parts.key = p;
msg.parts.index = j;
msg.parts.count = l;
node.send(msg);
j += 1;
}
}
}
// TODO not handling Buffers at present...
//else { } // otherwise drop the message.
}
});
}
RED.nodes.registerType("split",SplitNode);
function JoinNode(n) {
RED.nodes.createNode(this,n);
this.timer = Number(n.timeout || 0);
this.timerr = n.timerr || "send";
this.count = Number(n.count || 0);
this.joiner = n.joiner;
this.build = n.build || "array";
var node = this;
var inflight = {};
var misc = (this.build === "array") ? [] : {};
var tout;
function isObject (item) {
return (typeof item === "object" && !Array.isArray(item)&& ! Buffer.isBuffer(item) && item !== null);
}
// if array came from a string then reassemble it and send it
var sendIt = function(m) {
if (inflight[m.parts.id].ch !== undefined) { // if it was a string - rejoin it using the split char
var jc = (node.joiner || inflight[m.parts.id].ch).replace(/\\n/,"\n").replace(/\\r/,"\r").replace(/\\t/,"\t").replace(/\\e/,"\e").replace(/\\f/,"\c").replace(/\\0/,"\0");
m.payload = inflight[m.parts.id].a.join(jc);
} else { // leave it as an array
m.payload = inflight[m.parts.id].a;
}
m._msgid = m.parts.id;
clearTimeout(inflight[m.parts.id].timeout); // unset any timer
delete inflight[m.parts.id]; // remove from the keep track object
if (m.parts.hasOwnProperty("parts")) {
m.parts = m.parts.parts; // pop existing parts
}
else { delete m.parts; } // remove the parts flags
node.send(m);
}
// check all elements of the array are strings (or claim to be).
var onlyString = function(a) { // check if the array is all strings
for (var i = 0; i < a.length; i++) {
if (typeof a[i] !== "string") { return false; }
}
return true;
}
// send array of misc message that arrived. (convert to string if all were strings and need joining)
var sendMisc = function(m) {
if (tout) { clearTimeout(tout); tout = null; }
m.payload = misc;
if (node.joiner && onlyString(misc)) { // if the array is all strings and there is a join char set
m.payload = misc.join(node.joiner.replace(/\\n/,"\n").replace(/\\r/,"\r").replace(/\\t/,"\t").replace(/\\e/,"\e").replace(/\\f/,"\c").replace(/\\0/,"\0"));
}
if (node.build === "array") { misc = []; }
if (node.build === "object") { misc = {}; }
node.send(m);
}
this.on("input", function(msg) {
if (msg.hasOwnProperty("payload")) {
if (msg.hasOwnProperty("parts")) { // only act if it has parts
var count = node.count || msg.parts.count || 1;
if (msg.parts.hasOwnProperty("index")) { // it's a numbered part (from a split node)
if (!inflight[msg.parts.id]) { // New message - create new empty array of correct size
if (msg.parts.type === "object") {
inflight[msg.parts.id] = {i:0, a:{}, c:msg.parts.count, ch:msg.parts.ch, t:msg.parts.type};
} else { // it's an array or string
inflight[msg.parts.id] = {i:0, a:new Array(msg.parts.count), ch:msg.parts.ch, t:msg.parts.type};
}
if (node.timer !== 0) { // If there is a timer to set start it now
inflight[msg.parts.id].timeout = setTimeout(function() {
if (node.timerr === "send") { sendIt(msg); }
if (node.timerr === "error") { node.error("Incomplete",msg); }
delete inflight[msg.parts.id];
}, node.timer);
}
}
if (msg.parts.type === "object") {
inflight[msg.parts.id].a[msg.parts.key] = msg.payload; // Add to the tracking array
inflight[msg.parts.id].i = Object.keys(inflight[msg.parts.id].a).length;
} else { // it's an array or string
inflight[msg.parts.id].a[msg.parts.index] = msg.payload; // Add to the tracking array
inflight[msg.parts.id].i += 1; // Increment the count
}
if (inflight[msg.parts.id].i >= count) { sendIt(msg); } // All arrived - send
} // otherwise ignore it
if (msg.hasOwnProperty("complete")) { // if set then send right away anyway...
delete(msg.complete);
sendIt(msg);
}
}
// The case for any messages arriving without parts - ie random messages you want to join.
else {
var l;
if (node.build === "array") { // simple case of build the array
misc.push(msg.payload); // Add the payload to an array
l = misc.length;
} else { // OK so let's build an object
if ((msg.key === undefined) && ((msg.topic === undefined) || (msg.topic === ''))) {
if (isObject(msg.payload)) { // if it's already an object (and no topic or key) just append it
misc = Object.assign(misc,msg.payload);
l = Object.keys(misc).length;
}
else { // if no topic or key and not an object then warn and drop it.
node.warn("key or topic not defined");
return;
}
}
else { // if it's got a msg.key or msg.topic then use key||topic as the property name
misc[ msg.key || msg.topic ] = msg.payload;
//if (msg.topic) { msg.topic = (msg.topic.split('/')).slice(0,-1).join('/'); }
l = Object.keys(misc).length;
}
}
if (l >= node.count) { sendMisc(msg); } // if it's long enough send it
else if (msg.hasOwnProperty("complete")) { // if set then send right away anyway...
delete(msg.complete);
sendMisc(msg);
}
else if ((node.timer !== 0) && !tout) { // if not start the timer if there is one.
tout = setTimeout(function() {
if (node.timerr === "send") { sendMisc(msg); }
if (node.timerr === "error") { node.error("Timeout",msg); }
if (node.build === "array") { misc = []; }
if (node.build === "object") { misc = {}; }
}, node.timer);
}
}
}
});
this.on("close", function() {
if (tout) { clearTimeout(tout); }
for (var i in inflight) {
if (inflight[i].timeout) { clearTimeout(inflight[i].timeout); }
}
});
}
RED.nodes.registerType("join",JoinNode);
}

View File

@ -0,0 +1,379 @@
/**
* Copyright 2016 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var splitNode = require("../../../../nodes/core/logic/17-split.js");
var joinNode = require("../../../../nodes/core/logic/17-split.js");
var helper = require("../../helper.js");
describe('SPLIT node', function() {
before(function(done) {
helper.startServer(done);
});
afterEach(function() {
helper.unload();
});
it('should be loaded', function(done) {
var flow = [{id:"splitNode1", type:"split", name:"splitNode" }];
helper.load(splitNode, flow, function() {
var splitNode1 = helper.getNode("splitNode1");
splitNode1.should.have.property('name', 'splitNode');
done();
});
});
it('should split an array into multiple messages', function(done) {
var flow = [{id:"sn1", type:"split", wires:[["sn2"]]},
{id:"sn2", type:"helper"}];
helper.load(splitNode, flow, function() {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function(msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count",4);
msg.parts.should.have.property("type","array");
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.should.equal(1); }
if (msg.parts.index === 1) { msg.payload.should.equal(2); }
if (msg.parts.index === 2) { msg.payload.should.equal(3); }
if (msg.parts.index === 3) { msg.payload.should.equal(4); done(); }
});
sn1.receive({payload:[1,2,3,4]});
});
});
it('should split a string into characters', function(done) {
var flow = [{id:"sn1", type:"split", wires:[["sn2"]]},
{id:"sn2", type:"helper"}];
helper.load(splitNode, flow, function() {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function(msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count",4);
msg.parts.should.have.property("type","string");
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.should.equal("D"); }
if (msg.parts.index === 1) { msg.payload.should.equal("a"); }
if (msg.parts.index === 2) { msg.payload.should.equal("v"); }
if (msg.parts.index === 3) { msg.payload.should.equal("e"); done(); }
});
sn1.receive({payload:"Dave"});
});
});
it('should split a string on a specified char', function(done) {
var flow = [{id:"sn1", type:"split", wires:[["sn2"]], splt:"\n"},
{id:"sn2", type:"helper"}];
helper.load(splitNode, flow, function() {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function(msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count",3);
msg.parts.should.have.property("ch","\n");
msg.parts.should.have.property("index");
msg.parts.should.have.property("type","string");
if (msg.parts.index === 0) { msg.payload.should.equal("1"); }
if (msg.parts.index === 1) { msg.payload.should.equal("2"); }
if (msg.parts.index === 2) { msg.payload.should.equal("3"); done(); }
});
sn1.receive({payload:"1\n2\n3"});
});
});
it('should split an object into pieces', function(done) {
var flow = [{id:"sn1", type:"split", wires:[["sn2"]]},
{id:"sn2", type:"helper"}];
helper.load(splitNode, flow, function() {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
var count = 0;
sn2.on("input", function(msg) {
msg.should.have.property("payload");
msg.should.have.property("parts");
msg.parts.should.have.property("type","object");
msg.parts.should.have.property("key");
msg.parts.should.have.property("count");
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.should.equal(1); }
if (msg.parts.index === 1) { msg.payload.should.equal("2"); }
if (msg.parts.index === 2) { msg.payload.should.equal(true); done(); }
});
sn1.receive({payload:{a:1,b:"2",c:true}});
});
});
});
describe('JOIN node', function() {
before(function(done) {
helper.startServer(done);
});
afterEach(function() {
helper.unload();
});
it('should be loaded', function(done) {
var flow = [{id:"joinNode1", type:"join", name:"joinNode" }];
helper.load(joinNode, flow, function() {
var joinNode1 = helper.getNode("joinNode1");
joinNode1.should.have.property('name', 'joinNode');
joinNode1.should.have.property('count', 0);
joinNode1.should.have.property('timer', 0);
joinNode1.should.have.property('timerr', 'send');
joinNode1.should.have.property('build', 'array');
done();
});
});
it('should join things into an array after a count', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:3, joiner:","},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
msg.payload[0].should.equal(1);
msg.payload[1].should.equal(true);
//msg.payload[2].a.should.equal(1);
done();
}
catch(e) { }//console.log(e); }
});
n1.receive({payload:1});
n1.receive({payload:true});
n1.receive({payload:{a:1}});
});
});
it('should join things into an object after a count', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], count:5, build:"object"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.have.property("a",1);
msg.payload.should.have.property("b","2");
msg.payload.should.have.property("c",true);
msg.payload.should.have.property("d");
msg.payload.d.should.have.property("e",5);
msg.payload.should.have.property("f",6);
done();
}
catch(e) { }//console.log(e); }
});
n1.receive({payload:1, topic:"a"});
n1.receive({payload:"2", topic:"b"});
n1.receive({payload:true, topic:"c"});
n1.receive({payload:{e:5}, topic:"d"});
n1.receive({payload:{f:6}});
});
});
it('should join strings with a specifed character after a timeout', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:50, count:10, joiner:","},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal("a,b,c");
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:"a"});
n1.receive({payload:"b"});
n1.receive({payload:"c"});
});
});
it('should join strings with a specifed character and complete when told to', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:5000, count:100, joiner:"\n"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal("Hello\nNodeRED\nWorld\n");
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:"Hello"});
n1.receive({payload:"NodeRED"});
n1.receive({payload:"World"});
n1.receive({payload:'', complete:true});
});
});
it('should join split things back into an array', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]]},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
msg.payload[0].should.equal(1);
msg.payload[1].should.equal(2);
msg.payload[2].should.equal(3);
msg.payload[3].should.equal(4);
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:111}});
n1.receive({payload:2, parts:{index:1, count:4, id:111}});
n1.receive({payload:4, parts:{index:3, count:4, id:111}});
n1.receive({payload:1, parts:{index:0, count:4, id:111}});
});
});
it('should join split things back into an object', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]]},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.have.property("a",1);
msg.payload.should.have.property("b",2);
msg.payload.should.have.property("c",3);
msg.payload.should.have.property("d",4);
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:222, key:"c", type:"object"}});
n1.receive({payload:2, parts:{index:1, count:4, id:222, key:"b", type:"object"}});
n1.receive({payload:4, parts:{index:3, count:4, id:222, key:"d", type:"object"}});
n1.receive({payload:1, parts:{index:0, count:4, id:222, key:"a", type:"object"}});
});
});
it.skip('should join split things, missing some after a timeout', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:50},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
(msg.payload[0] === undefined).should.be.true;
msg.payload[1].should.equal(2);
msg.payload[2].should.equal(3);
(msg.payload[3] === undefined).should.be.true;
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:333}});
n1.receive({payload:2, parts:{index:1, count:4, id:333}});
});
});
it('should join split things, send when told complete', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:250},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
(msg.payload[0] === undefined).should.be.true;
msg.payload[1].should.equal(2);
msg.payload[2].should.equal(3);
msg.payload[3].should.equal(4);
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:444} });
n1.receive({payload:2, parts:{index:1, count:4, id:444} });
n1.receive({payload:4, parts:{index:3, count:4, id:444}, complete:true});
});
});
it('should join split strings back into a word', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]]},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
msg.payload.should.equal("abcd");
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:"a", parts:{index:0, count:4, ch:"", id:555}});
n1.receive({payload:"d", parts:{index:3, count:4, ch:"", id:555}});
n1.receive({payload:"c", parts:{index:2, count:4, ch:"", id:555}});
n1.receive({payload:"b", parts:{index:1, count:4, ch:"", id:555}});
});
});
it('should join split strings back overriding the join char', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], joiner:":"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array;
msg.payload.should.equal("a:b:c:d");
done();
}
catch(e) { console.log(e); }
});
n1.receive({payload:"a", parts:{index:0, count:4, ch:"", id:666}});
n1.receive({payload:"d", parts:{index:3, count:4, ch:"", id:666}});
n1.receive({payload:"c", parts:{index:2, count:4, ch:"", id:666}});
n1.receive({payload:"b", parts:{index:1, count:4, ch:"", id:666}});
});
});
});