node-red-dashboard
Version:
A set of dashboard nodes for Node-RED
220 lines (208 loc) • 10.4 kB
HTML
<script type="text/javascript">
// convert to i18 text
function c_(x) {
return RED._("node-red-dashboard/ui_template:ui_template."+x);
}
RED.nodes.registerType('ui_template',{
category: c_("label.category"),
color: 'rgb( 63, 173, 181)',
defaults: {
group: {type: 'ui_group', required:false},
name: {value: ''},
order: {value: 0},
width: {value: 0, validate: function(v) {
var valid = true
if (this.templateScope !== 'global') {
var width = v||0;
var currentGroup = $('#node-input-group').val()||this.group;
var groupNode = RED.nodes.node(currentGroup);
valid = !groupNode || +width <= +groupNode.width;
$("#node-input-size").toggleClass("input-error",!valid);
}
return valid;
}},
height: {value: 0},
format: {value: '<div ng-bind-html="msg.payload"></div>'},
storeOutMessages: {value: true},
fwdInMessages: {value: true},
templateScope: {value: 'local'}
},
inputs:1,
outputs:1,
icon: "ui_template.png",
paletteLabel: 'template',
label: function() { return this.name || 'template'; },
oneditprepare: function() {
var that = this;
$("#node-input-size").elementSizer({
width: "#node-input-width",
height: "#node-input-height",
group: "#node-input-group"
});
if (typeof this.storeOutMessages === 'undefined') {
this.storeOutMessages = true;
$('#node-input-storeOutMessages').prop('checked', true);
}
if (typeof this.fwdInMessages === 'undefined') {
this.fwdInMessages = true;
$('#node-input-fwdInMessages').prop('checked', true);
}
if (typeof this.templateScope === 'undefined') {
this.templateScope = 'local';
$('#node-input-templateScope').val(this.templateScope);
}
$('#node-input-templateScope').on('change', function() {
if ($('#node-input-templateScope').val() === 'global') {
$('#template-row-group, #template-row-size, #template-pass-store').hide();
that._def.defaults.group.required = false;
}
else {
$('#template-row-group, #template-row-size, #template-pass-store').show();
that._def.defaults.group.required = true;
}
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height = height - $(rows[i]).outerHeight(true);
}
if ($('#node-input-templateScope').val() === "global") { height += 240; }
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
if (this.editor) { this.editor.resize(); }
})
this.editor = RED.editor.createEditor({
id: 'node-input-format-editor',
mode: 'ace/mode/html',
value: $("#node-input-format").val()
});
RED.library.create({
url:"uitemplates", // where to get the data from
type:"ui_template", // the type of object the library is for
editor:this.editor, // the field name the main text body goes to
mode:"ace/mode/html",
fields:['name']
});
this.editor.focus();
},
oneditsave: function() {
var annot = this.editor.getSession().getAnnotations();
this.noerr = 0;
$("#node-input-noerr").val(0);
for (var k=0; k < annot.length; k++) {
if (annot[k].type === "error") {
$("#node-input-noerr").val(annot.length);
this.noerr = annot.length;
}
}
$("#node-input-format").val(this.editor.getValue());
this.editor.destroy();
delete this.editor;
},
oneditcancel: function() {
this.editor.destroy();
delete this.editor;
},
oneditresize: function(size) {
var rows = $("#dialog-form>div:not(.node-text-editor-row)");
var height = $("#dialog-form").height();
for (var i=0; i<rows.size(); i++) {
height = height - $(rows[i]).outerHeight(true);
}
if ($('#node-input-templateScope').val() === "global") { height += 232; }
var editorRow = $("#dialog-form>div.node-text-editor-row");
height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom")));
$(".node-text-editor").css("height",height+"px");
this.editor.resize();
}
});
</script>
<script type="text/x-red" data-template-name="ui_template">
<div class="form-row">
<label for="node-input-format"><span data-i18n="ui_template.label.type"></span></label>
<select style="width:76%" id="node-input-templateScope">
<option value="local" data-i18n="ui_template.label.local"></option>
<option value="global" data-i18n="ui_template.label.global"></option>
</select>
</div>
<div class="form-row" id="template-row-group">
<label for="node-input-group"><i class="fa fa-table"></i> <span data-i18n="ui_template.label.group"></span></label>
<input type="text" id="node-input-group">
</div>
<div class="form-row" id="template-row-size">
<label><i class="fa fa-object-group"></i> <span data-i18n="ui_template.label.size"></span></label>
<input type="hidden" id="node-input-width">
<input type="hidden" id="node-input-height">
<button class="editor-button" id="node-input-size"></button>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="ui_template.label.name"></span></label>
<input type="text" id="node-input-name">
</div>
<div id="template-pass-store">
<div class="form-row" style="margin-bottom:0px;">
<label> </label>
<input type="checkbox" id="node-input-fwdInMessages" style="display:inline-block; width:auto; vertical-align:top;">
<label for="node-input-fwdInMessages" style="width:70%;"> <span data-i18n="ui_template.label.pass-through"></span></label>
</div>
<div class="form-row" style="margin-bottom:0px;">
<label> </label>
<input type="checkbox" id="node-input-storeOutMessages" style="display:inline-block; width:auto; vertical-align:top;">
<label for="node-input-storeOutMessages" style="width:70%;"> <span data-i18n="ui_template.label.store-state"></span></label>
</div>
</div>
<div class="form-row" style="margin-bottom:0px;">
<label for="node-input-format"><i class="fa fa-copy"></i> <span data-i18n="ui_template.label.template"></span></label>
<input type="hidden" id="node-input-format">
</div>
<div class="form-row node-text-editor-row">
<div style="height:250px; min-height:100px" class="node-text-editor" id="node-input-format-editor" ></div>
</div>
</script>
<script type="text/x-red" data-help-name="ui_template">
<p>The template widget can contain any valid html and Angular/Angular-Material directives.</p>
<p>This node can be used to create a dynamic user interface element that changes its appearence
based on the input message and can send back messages to Node-RED.</p>
<p><b>For example:</b><br>
<pre style="font-size:smaller;"><div layout="row" layout-align="space-between">
<p>The number is</p>
<p ng-style="{color: (msg.payload || 0) % 2 === 0 ? 'green' : 'red'}">
{{(msg.payload || 0) % 2 === 0 ? 'even' : 'odd'}}
</p>
</div></pre>
Will display if the number received as <code>msg.payload</code> is even or odd. It will also
change the color of the text to green if the number is even or red if odd.<br/>
The next example shows how to set a unique id for your template, pick up the default theme colour,
and watch for any incoming message.</p>
<pre style="font-size:smaller;">
<div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}">Some text</div>
<script>
(function(scope) {
scope.$watch('msg', function(msg) {
if (msg) {
// Do something when msg arrives
$("#my_"+scope.$id).html(msg.payload);
}
});
})(scope);
</script></pre>
<p>Templates made in this way can be copied and remain independent of each other.</p>
<p><b>Sending a message:</b><br>
<pre style="font-size:smaller;">
<script>
var value = "hello world";
// or overwrite value in your callback function ...
this.scope.action = function() { return value; }
</script>
<md-button ng-click="send({payload:action()})">
Click me to send a hello world
</md-button></pre>
Will display a button that when clicked will send a message with the payload <code>'Hello world'</code>.</p>
<p><b>Using <code>msg.template</code>:</b><br>
You can also define the template content via <code>msg.template</code>, so you can use external files for example.<br>
Template will be reloaded on input if it has changed.<br>
Code written in the Template field will be ignored when <code>msg.template</code> is present.</p>
<p>The following icon fonts are also available: <a href="https://design.google.com/icons/" target="_blank">Material Design icons</a>,
<a href="https://fontawesome.com/v4.7.0/icons/" target="_blank">Font Awesome icons</a>,
<a href="https://github.com/Paul-Reed/weather-icons-lite/blob/master/css/weather-icons-lite.css" target="_blank">Weather icons</a>.</p>
</script>