@sammachin/node-red-dragonpbx
Version:
A Node-RED node to append JSON objects to an array in msg.callScript
121 lines (110 loc) • 11.3 kB
HTML
<script>
var objectToString=Object.prototype.toString,isArray=Array.isArray||function(e){return"[object Array]"===objectToString.call(e)};function isFunction(e){return"function"==typeof e}function typeStr(e){return isArray(e)?"array":typeof e}function escapeRegExp(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(e,t){return null!=e&&"object"==typeof e&&t in e}function primitiveHasOwnProperty(e,t){return null!=e&&"object"!=typeof e&&e.hasOwnProperty&&e.hasOwnProperty(t)}var regExpTest=RegExp.prototype.test;function testRegExp(e,t){return regExpTest.call(e,t)}var nonSpaceRe=/\S/;function isWhitespace(e){return!testRegExp(nonSpaceRe,e)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(e){return String(e).replace(/[&<>"'`=\/]/g,function(e){return entityMap[e]})}var whiteRe=/\s*/,spaceRe=/\s+/,equalsRe=/\s*=/,curlyRe=/\s*\}/,tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(e,t){if(!e)return[];var r,n,i,a=!1,s=[],o=[],c=[],p=!1,u=!1,h="",l=0;function f(){if(p&&!u)for(;c.length;)delete o[c.pop()];else c=[];p=!1,u=!1}function g(e){if("string"==typeof e&&(e=e.split(spaceRe,2)),!isArray(e)||2!==e.length)throw new Error("Invalid tags: "+e);r=new RegExp(escapeRegExp(e[0])+"\\s*"),n=new RegExp("\\s*"+escapeRegExp(e[1])),i=new RegExp("\\s*"+escapeRegExp("}"+e[1]))}g(t||mustache.tags);for(var d,v,y,m,w,x,C=new Scanner(e);!C.eos();){if(d=C.pos,y=C.scanUntil(r))for(var W=0,R=y.length;W<R;++W)isWhitespace(m=y.charAt(W))?(c.push(o.length),h+=m):(u=!0,a=!0,h+=" "),o.push(["text",m,d,d+1]),d+=1,"\n"===m&&(f(),h="",l=0,a=!1);if(!C.scan(r))break;if(p=!0,v=C.scan(tagRe)||"name",C.scan(whiteRe),"="===v?(y=C.scanUntil(equalsRe),C.scan(equalsRe),C.scanUntil(n)):"{"===v?(y=C.scanUntil(i),C.scan(curlyRe),C.scanUntil(n),v="&"):y=C.scanUntil(n),!C.scan(n))throw new Error("Unclosed tag at "+C.pos);if(w=">"==v?[v,y,d,C.pos,h,l,a]:[v,y,d,C.pos],l++,o.push(w),"#"===v||"^"===v)s.push(w);else if("/"===v){if(!(x=s.pop()))throw new Error('Unopened section "'+y+'" at '+d);if(x[1]!==y)throw new Error('Unclosed section "'+x[1]+'" at '+d)}else"name"===v||"{"===v||"&"===v?u=!0:"="===v&&g(y)}if(f(),x=s.pop())throw new Error('Unclosed section "'+x[1]+'" at '+C.pos);return nestTokens(squashTokens(o))}function squashTokens(e){for(var t,r,n=[],i=0,a=e.length;i<a;++i)(t=e[i])&&("text"===t[0]&&r&&"text"===r[0]?(r[1]+=t[1],r[3]=t[3]):(n.push(t),r=t));return n}function nestTokens(e){for(var t,r=[],n=r,i=[],a=0,s=e.length;a<s;++a)switch((t=e[a])[0]){case"#":case"^":n.push(t),i.push(t),n=t[4]=[];break;case"/":i.pop()[5]=t[2],n=i.length>0?i[i.length-1][4]:r;break;default:n.push(t)}return r}function Scanner(e){this.string=e,this.tail=e,this.pos=0}function Context(e,t){this.view=e,this.cache={".":this.view},this.parent=t}function Writer(){this.templateCache={_cache:{},set:function(e,t){this._cache[e]=t},get:function(e){return this._cache[e]},clear:function(){this._cache={}}}}Scanner.prototype.eos=function(){return""===this.tail},Scanner.prototype.scan=function(e){var t=this.tail.match(e);if(!t||0!==t.index)return"";var r=t[0];return this.tail=this.tail.substring(r.length),this.pos+=r.length,r},Scanner.prototype.scanUntil=function(e){var t,r=this.tail.search(e);switch(r){case-1:t=this.tail,this.tail="";break;case 0:t="";break;default:t=this.tail.substring(0,r),this.tail=this.tail.substring(r)}return this.pos+=t.length,t},Context.prototype.push=function(e){return new Context(e,this)},Context.prototype.lookup=function(e){var t,r=this.cache;if(r.hasOwnProperty(e))t=r[e];else{for(var n,i,a,s=this,o=!1;s;){if(e.indexOf(".")>0)for(n=s.view,i=e.split("."),a=0;null!=n&&a<i.length;)a===i.length-1&&(o=hasProperty(n,i[a])||primitiveHasOwnProperty(n,i[a])),n=n[i[a++]];else n=s.view[e],o=hasProperty(s.view,e);if(o){t=n;break}s=s.parent}r[e]=t}return isFunction(t)&&(t=t.call(this.view)),t},Writer.prototype.clearCache=function(){void 0!==this.templateCache&&this.templateCache.clear()},Writer.prototype.parse=function(e,t){var r=this.templateCache,n=e+":"+(t||mustache.tags).join(":"),i=void 0!==r,a=i?r.get(n):void 0;return null==a&&(a=parseTemplate(e,t),i&&r.set(n,a)),a},Writer.prototype.render=function(e,t,r,n){var i=this.getConfigTags(n),a=this.parse(e,i),s=t instanceof Context?t:new Context(t,void 0);return this.renderTokens(a,s,r,e,n)},Writer.prototype.renderTokens=function(e,t,r,n,i){for(var a,s,o,c="",p=0,u=e.length;p<u;++p)o=void 0,"#"===(s=(a=e[p])[0])?o=this.renderSection(a,t,r,n,i):"^"===s?o=this.renderInverted(a,t,r,n,i):">"===s?o=this.renderPartial(a,t,r,i):"&"===s?o=this.unescapedValue(a,t):"name"===s?o=this.escapedValue(a,t,i):"text"===s&&(o=this.rawValue(a)),void 0!==o&&(c+=o);return c},Writer.prototype.renderSection=function(e,t,r,n,i){var a=this,s="",o=t.lookup(e[1]);if(o){if(isArray(o))for(var c=0,p=o.length;c<p;++c)s+=this.renderTokens(e[4],t.push(o[c]),r,n,i);else if("object"==typeof o||"string"==typeof o||"number"==typeof o)s+=this.renderTokens(e[4],t.push(o),r,n,i);else if(isFunction(o)){if("string"!=typeof n)throw new Error("Cannot use higher-order sections without the original template");null!=(o=o.call(t.view,n.slice(e[3],e[5]),function(e){return a.render(e,t,r,i)}))&&(s+=o)}else s+=this.renderTokens(e[4],t,r,n,i);return s}},Writer.prototype.renderInverted=function(e,t,r,n,i){var a=t.lookup(e[1]);if(!a||isArray(a)&&0===a.length)return this.renderTokens(e[4],t,r,n,i)},Writer.prototype.indentPartial=function(e,t,r){for(var n=t.replace(/[^ \t]/g,""),i=e.split("\n"),a=0;a<i.length;a++)i[a].length&&(a>0||!r)&&(i[a]=n+i[a]);return i.join("\n")},Writer.prototype.renderPartial=function(e,t,r,n){if(r){var i=this.getConfigTags(n),a=isFunction(r)?r(e[1]):r[e[1]];if(null!=a){var s=e[6],o=e[5],c=e[4],p=a;0==o&&c&&(p=this.indentPartial(a,c,s));var u=this.parse(p,i);return this.renderTokens(u,t,r,p,n)}}},Writer.prototype.unescapedValue=function(e,t){var r=t.lookup(e[1]);if(null!=r)return r},Writer.prototype.escapedValue=function(e,t,r){var n=this.getConfigEscape(r)||mustache.escape,i=t.lookup(e[1]);if(null!=i)return"number"==typeof i&&n===mustache.escape?String(i):n(i)},Writer.prototype.rawValue=function(e){return e[1]},Writer.prototype.getConfigTags=function(e){return isArray(e)?e:e&&"object"==typeof e?e.tags:void 0},Writer.prototype.getConfigEscape=function(e){return e&&"object"==typeof e&&!isArray(e)?e.escape:void 0};var mustache={name:"mustache.js",version:"4.2.0",tags:["{{","}}"],clearCache:void 0,escape:void 0,parse:void 0,render:void 0,Scanner:void 0,Context:void 0,Writer:void 0,set templateCache(e){defaultWriter.templateCache=e},get templateCache(){return defaultWriter.templateCache}},defaultWriter=new Writer;mustache.clearCache=function(){return defaultWriter.clearCache()},mustache.parse=function(e,t){return defaultWriter.parse(e,t)},mustache.render=function(e,t,r,n){if("string"!=typeof e)throw new TypeError('Invalid template! Template should be a "string" but "'+typeStr(e)+'" was given as the first argument for mustache#render(template, view, partials)');return defaultWriter.render(e,t,r,n)},mustache.escape=escapeHtml,mustache.Scanner=Scanner,mustache.Context=Context,mustache.Writer=Writer;
</script>
<script type="text/javascript">
function set(t, path, value) {
if (path == "") return value
const [k, next] = path.split({
[Symbol.split](s) {
const i = s.indexOf(".")
return i == -1 ? [s, ""] : [s.slice(0, i), s.slice(i + 1)]
}
})
if (t !== undefined && typeof t !== "object")
throw Error(`cannot set property ${k} of ${typeof t}`)
return Object.assign(
t ?? (/^\d+$/.test(k) ? [] : {}),
{ [k]: set(t?.[k], next, value) },
)
}
function dummyData(template) {
const tokens = mustache.parse(template)
const tags = [];
tokens.forEach(token => {
if (token[0] === 'name') {
tags.push(token[1]);
}
});
r = {msg: {}, flow: {}, global: {}}
tags.forEach((t) => {
set(r, t, 0)
})
return r
}
RED.nodes.registerType('basenode', {
category: 'function',
color: '#E0E0EE',
icon: 'font-awesome/fa-list',
defaults: {
name: { value: "" },
jsonObject: { value: "{}", validate: function(v) {
try {
const dd = dummyData(v)
const j = mustache.render(v, dd)
JSON.parse(j);
return true;
}
catch(e) {
console.error(e)
return false;
}
}}
},
inputs: 1,
outputs: 1,
label: function() {
return this.name || "callScript";
},
paletteLabel: "callScript",
oneditprepare: function() {
this.editor = RED.editor.createEditor({
id: 'node-input-jsonObject-editor',
mode: 'ace/mode/json',
value: this.jsonObject
});
},
oneditsave: function() {
this.jsonObject = this.editor.getValue();
this.editor.destroy();
delete this.editor;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
}
});
</script>
<script type="text/html" data-template-name="basenode">
<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>
<div class="form-row" style="position: relative; height: 250px;">
<label for="node-input-jsonObject"><i class="fa fa-code"></i> JSON Object</label>
<div style="position: absolute; right: 0; bottom: 0; top: 0; left: 100px;">
<div id="node-input-jsonObject-editor" style="width: 100%; height: 100%;"></div>
</div>
</div>
</script>
<script type="text/html" data-help-name="basenode">
<p>Appends a JSON object to an array in msg.callScript.</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>msg.callScript <span class="property-type">array</span></dt>
<dd>The array to which the JSON object will be appended. If it doesn't exist or is not an array, and "Create if missing" is checked, it will be created.</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>msg.callScript <span class="property-type">array</span></dt>
<dd>The original array with the new JSON object appended.</dd>
</dl>
<h3>Details</h3>
<p>This node appends the configured JSON object to an array in msg.callScript. If msg.callScript doesn't exist or is not an array, and "Create if missing" is checked, it will be created automatically.</p>
<h3>Configuration</h3>
<dl class="message-properties">
<dt>JSON Object</dt>
<dd>The JSON object that will be appended to the array.</dd>
<dt>Create if missing</dt>
<dd>If checked, the node will create msg.callScript as an array if it doesn't exist or convert it to an array if it's not already one.</dd>
</dl>
</script>