diff --git a/nodes/core/core/80-template.html b/nodes/core/core/80-template.html index 446284dbf..0bbf4da42 100644 --- a/nodes/core/core/80-template.html +++ b/nodes/core/core/80-template.html @@ -67,6 +67,7 @@ }
The resulting property will be:
Hello Fred. Today is Monday+
It is possible to use property from flow context or global context. Just use {{flow.name}}
or {{global.name}}
.
By default, mustache will escape any HTML entities in the values it substitutes.
To prevent this, use {{{triple}}}
braces.
diff --git a/nodes/core/core/80-template.js b/nodes/core/core/80-template.js
index 8e93b1530..ba571d458 100644
--- a/nodes/core/core/80-template.js
+++ b/nodes/core/core/80-template.js
@@ -18,6 +18,39 @@ module.exports = function(RED) {
"use strict";
var mustache = require("mustache");
+ /**
+ * Custom Mustache Context capable to resolve message property and node
+ * flow and global context
+ */
+ function NodeContext(msg, nodeContext) {
+ this.msgContext = new mustache.Context(msg);
+ this.nodeContext = nodeContext;
+ }
+
+ NodeContext.prototype = new mustache.Context();
+
+ NodeContext.prototype.lookup = function (name) {
+ // try message first:
+ var value = this.msgContext.lookup(name);
+ if (value !== undefined) {
+ return value;
+ }
+
+ // try node context:
+ var dot = name.indexOf(".");
+ if (dot > 0) {
+ var contextName = name.substr(0, dot);
+ var variableName = name.substr(dot + 1);
+
+ if (contextName === "flow" && this.nodeContext.flow) {
+ return this.nodeContext.flow.get(variableName);
+ }
+ else if (contextName === "global" && this.nodeContext.global) {
+ return this.nodeContext.global.get(variableName);
+ }
+ }
+ }
+
function TemplateNode(n) {
RED.nodes.createNode(this,n);
this.name = n.name;
@@ -31,7 +64,7 @@ module.exports = function(RED) {
try {
var value;
if (node.syntax === "mustache") {
- value = mustache.render(node.template,msg);
+ value = mustache.render(node.template, new NodeContext(msg, node.context()));
} else {
value = node.template;
}
diff --git a/test/nodes/core/core/80-template_spec.js b/test/nodes/core/core/80-template_spec.js
index b93601989..686f77ede 100644
--- a/test/nodes/core/core/80-template_spec.js
+++ b/test/nodes/core/core/80-template_spec.js
@@ -43,6 +43,52 @@ describe('template node', function() {
});
});
+ it('should modify payload from flow context', function(done) {
+ var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
+ helper.load(templateNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n1.context().flow.set("value","foo");
+ n2.on("input", function(msg) {
+ msg.should.have.property('topic', 'bar');
+ msg.should.have.property('payload', 'payload=foo');
+ done();
+ });
+ n1.receive({payload:"foo",topic: "bar"});
+ });
+ });
+
+ it('should modify payload from global context', function(done) {
+ var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
+ helper.load(templateNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n1.context().global.set("value","foo");
+ n2.on("input", function(msg) {
+ msg.should.have.property('topic', 'bar');
+ msg.should.have.property('payload', 'payload=foo');
+ done();
+ });
+ n1.receive({payload:"foo",topic: "bar"});
+ });
+ });
+
+ it('should handle missing node context', function(done) {
+ // this is artificial test because in flow there is missing z property (probably never happen in real usage)
+ var flow = [{id:"n1",type:"template", field:"payload", template:"payload={{flow.value}},{{global.value}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
+ helper.load(templateNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ msg.should.have.property('topic', 'bar');
+ msg.should.have.property('payload', 'payload=,');
+ done();
+ });
+ n1.receive({payload:"foo",topic: "bar"});
+ });
+ });
+
+
it('should modify payload in plain text mode', function(done) {
var flow = [{id:"n1", type:"template", field:"payload", syntax:"plain", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
helper.load(templateNode, flow, function() {
@@ -57,32 +103,36 @@ describe('template node', function() {
});
});
- xit('should modify flow context', function(done) {
- var flow = [{id:"n1", type:"template", field:"payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
+ it('should modify flow context', function(done) {
+ var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
- setTimeout( function() {
- console.log(n2);
- console.log(n2.context().global.get("payload"));
- //c.should.equal(1); // should only have had one output.
+ n2.on("input", function(msg) {
+ // mesage is intact
+ msg.should.have.property('topic', 'bar');
+ msg.should.have.property('payload', 'foo');
+ // result is in flow context
+ n2.context().flow.get("payload").should.equal("payload=foo");
done();
- },50);
+ });
n1.receive({payload:"foo",topic: "bar"});
});
});
- xit('should modify global context', function(done) {
- var flow = [{id:"n1", type:"template", field:"payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
+ it('should modify global context', function(done) {
+ var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
- setTimeout( function() {
- console.log(n2);
- console.log(n2.context().global.get("payload"));
- //c.should.equal(1); // should only have had one output.
+ n2.on("input", function(msg) {
+ // mesage is intact
+ msg.should.have.property('topic', 'bar');
+ msg.should.have.property('payload', 'foo');
+ // result is in global context
+ n2.context().global.get("payload").should.equal("payload=foo");
done();
- },50);
+ });
n1.receive({payload:"foo",topic: "bar"});
});
});