UNPKG

node-red-dashboard

Version:
220 lines (208 loc) 10.4 kB
<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>&nbsp;</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>&nbsp;</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;">&lt;div layout=&quot;row&quot; layout-align=&quot;space-between&quot;&gt; &lt;p&gt;The number is&lt;/p&gt; &lt;p ng-style=&quot;{color: (msg.payload || 0) % 2 === 0 ? 'green' : 'red'}&quot;&gt; {{(msg.payload || 0) % 2 === 0 ? 'even' : 'odd'}} &lt;/p&gt; &lt;/div&gt;</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;"> &lt;div id="{{'my_'+$id}}" style="{{'color:'+theme.base_color}}"&gt;Some text&lt;/div&gt; &lt;script&gt; (function(scope) { scope.$watch('msg', function(msg) { if (msg) { // Do something when msg arrives $("#my_"+scope.$id).html(msg.payload); } }); })(scope); &lt;/script&gt;</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;"> &lt;script&gt; var value = "hello world"; // or overwrite value in your callback function ... this.scope.action = function() { return value; } &lt;/script&gt; &lt;md-button ng-click=&quot;send({payload:action()})&quot;&gt; Click me to send a hello world &lt;/md-button&gt;</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>