UNPKG

@gregoriusrippenstein/node-red-contrib-nodedev

Version:

Support the development of Node-RED nodes within Node-RED.

443 lines (378 loc) 17.8 kB
<script type="text/html" data-template-name="NodeFactory"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-name" placeholder="Name"></div> </div> <div class="form-row"> <label for="node-input-nodename"><i class="fa fa-tag"></i> Node Type</label> <div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-nodename" placeholder="Node Type"> </div> </div> <div class="form-row"> <label for="node-input-nodelabel"><i class="fa fa-tag"></i> Node Label</label> <div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-nodelabel" placeholder="Node Label"> </div> </div> <div class="form-row"> <label for="node-input-category"><i class="fa fa-tag"></i> Node Category</label> <div style="display: inline-block; width: calc(100% - 105px)"><input type="text" id="node-input-category" placeholder="Node Category"> </div> </div> <div id="node-input-row-style-colour" class="form-row"> <label>Color</label> </div> <div id="node-input-row-icon-picker" class="form-row"> </div> <div class="form-row"> <label for="node-input-hasbutton"> <span>Has button?</span> </label> <input type="checkbox" id="node-input-hasbutton" style="display:inline-block; width:15px; vertical-align:baseline;"> <label for="node-input-minify"> <span>Minify by default?</span> </label> <input type="checkbox" id="node-input-minify" style="margin-left: 10px; display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-hasinput"> <span>Has input port?</span> </label> <input type="checkbox" id="node-input-hasinput" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-outputcount"> <i class="fa fa-tag"></i> Output ports </label> <select id="node-input-outputcount"></select> </div> <div class="form-row"> <label for="node-input-summary"> <i class="fa fa-tag"></i> <span>Summary (REQUIRED)</span> </label> <div style="height: 150px; min-height:150px; max-height: 150px;" class="node-text-editor" id="node-input-summary"> </div> </div> <div class="form-row"> <label for="node-input-description"> <i class="fa fa-tag"></i> <span>Description (REQUIRED)</span> </label> <div style="height: 350px; min-height:350px; max-height: 350px;" class="node-text-editor" id="node-input-description"> </div> </div> <div class="form-row"> <label for="node-input-isrealplugin" style="min-width: 250px;"> <span>Plugin?</span> </label> <input type="checkbox" id="node-input-isrealplugin" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-isplugin" style="min-width: 250px;"> <span>Sidebar + Config?</span> </label> <input type="checkbox" id="node-input-isplugin" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-frt2bakcomm" style="min-width: 250px;"> <span>Frontend to Backend communication?</span> </label> <input type="checkbox" id="node-input-frt2bakcomm" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-bak2frtcomm" style="min-width: 250px;"> <span>Backend to Frontend communication?</span> </label> <input type="checkbox" id="node-input-bak2frtcomm" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <label for="node-input-createmanifest" style="min-width: 250px;"> <span>Create manifest?</span> </label> <input type="checkbox" id="node-input-createmanifest" style="display:inline-block; width:15px; vertical-align:baseline;"> </div> <div class="form-row"> <button id="node-input-generate-tmplnodes-but" class="red-ui-button">Generate Template Nodes</button> </div> </script> <script type="text/html" data-help-name="NodeFactory"> <p>Generate node templates providing starting points for node development</p> The Node-Factory can be used to create example code for various types of Node-RED nodes. </script> <script type="text/javascript"> (function () { RED.comms.subscribe("nodedev:perform-autoimport-nodes", (event,data) => { if ( data.msg == "notify") { RED.notify(data.text, { type: data.type, id: data.id || "NodeFactory", timeout: data.timeout || 2000 }); } if ( data.msg == "autoimport" ) { setTimeout(() => { RED.clipboard.import(); setTimeout(() => { $('#red-ui-clipboard-dialog-import-text').val( data.payload ).trigger("paste"); }, 300); },400) } }); function postDataOff(node,data) { $.ajax({ url: "NodeFactory/" + node.id, type: "POST", contentType: "application/json; charset=utf-8", data: JSON.stringify({ node: data, }), success: function (resp) { $('#node-dialog-ok').trigger('click'); RED.notify("Preparing Node...", { type: "warning", timeout: 2000 }); }, error: function (jqXHR, textStatus, errorThrown) { if (jqXHR.status == 404) { RED.notify("Node has not yet been deployed, please deploy.", "error"); } else if (jqXHR.status == 405) { RED.notify("Not Allowed.", "error"); } else if (jqXHR.status == 500) { RED.notify(node._("common.notification.error", { message: node._("inject.errors.failed") }), "error"); } else if (jqXHR.status == 0) { RED.notify(node._("common.notification.error", { message: node._("common.notification.errors.no-response") }), "error"); } else { RED.notify(node._("common.notification.error", { message: node._("common.notification.errors.unexpected", { status: jqXHR.status, message: textStatus }) }), "error"); } } }); } function doSubmission(node) { let data = {}; /* the data has not been stored on the node when this is called, need to retrieve everything from the various fields... */ data["summary"] = node.editorSummary.getValue(); data["description"] = node.editorDesc.getValue(); data["color"] = $('#node-input-colour').val(); data["icon"] = $('#red-ui-editor-node-icon').val(); data["iconclass"] = "fa " + data["icon"].split("/")[1]; /* Assume font-awesomeness */ data["name"] = $('#node-input-nodename').val(); data["nodelabel"] = $('#node-input-nodelabel').val(); data["namelwr"] = data["name"].toLowerCase(); data["outputcount"] = $('#node-input-outputcount').val(); data["category"] = $('#node-input-category').val(); data["hasbutton"] = $('#node-input-hasbutton').is(":checked"); data["minify"] = $('#node-input-minify').is(":checked"); data["hasinput"] = $('#node-input-hasinput').is(":checked"); data["bak2frtcomm"] = $('#node-input-bak2frtcomm').is(":checked"); data["frt2bakcomm"] = $('#node-input-frt2bakcomm').is(":checked"); data["createmanifest"] = $('#node-input-createmanifest').is(":checked"); /* Argh! This is a mess but I can't change it because isplugin is used in the wild. isplugin is actually a sidebar + config node, while isrealplugin is a plugin in the true sense of Node-RED. This was done due to lack-of-knowledge on the part of the author. */ data["isplugin"] = $('#node-input-isplugin').is(":checked"); data["isrealplugin"] = $('#node-input-isrealplugin').is(":checked"); data["__task"] = "generate_from_templates"; postDataOff(node,data) } function doButtonSubmission(node) { let data = {} Object.keys(node._def.defaults).forEach( attrname => { data[attrname] = node[attrname] }) data["name"] = node.nodename; // name clashes with the default 'name' attribute data["namelwr"] = data["name"].toLowerCase(); data["iconclass"] = "fa " + data["icon"].split("/")[1]; /* Assume font-awesomeness */ data["__task"] = "generate_from_templates"; data["name_escaped"] = data["name"].replaceAll("-",'_').replace(new RegExp(/[ \t\s]/g),'') postDataOff(node,data) } RED.nodes.registerType('NodeFactory', { color: "#e5e4ef", category: 'nodedev', defaults: { name: { value: "" }, nodename: { value: "", required: true }, nodelabel: { value: "", required: true }, color: { value: "#e5e4ef" }, hasbutton: { value: false }, minify: { value: false }, hasinput: { value: true }, outputcount: { value: 1 }, category: { value: "" }, summary: { value: "", required: true }, description: { value: "", required: true }, icon: { value: "font-awesome/fa-industry" }, frt2bakcomm: { value: false }, bak2frtcomm: { value: false }, createmanifest: { value: false }, isplugin: { value: false }, isrealplugin: { value: false }, }, inputs: 1, outputs: 1, icon: "font-awesome/fa-industry", label: function () { return this.name || this._def.paletteLabel; }, labelStyle: function () { return this.name ? "node_label_italic" : ""; }, oneditprepare: function () { const that = this; const stateId = RED.editor.generateViewStateId("node", this, ""); var sltObj = $('#node-input-outputcount'); sltObj.html(""); [0,1,2,3,4,5,6,7,8,9,10].forEach( function(v) { sltObj.append($('<option></option>').val(v).html(v)); }); sltObj.val(this.outputcount || "1"); $('#node-input-generate-tmplnodes-but').on('click', (e) => { e.preventDefault() doSubmission(that) }); var colorPalette = [ "#DDAA99", "#3FADB5", "#87A980", "#A6BBCF", "#AAAA66", "#C0C0C0", "#C0DEED", "#C7E9C0", "#D7D7A0", "#D8BFD8", "#DAC4B4", "#DEB887", "#DEBD5C", "#E2D96E", "#E6E0F8", "#E7E7AE", "#E9967A", "#F3B567", "#FDD0A2", "#FDF0C2", "#FFAAAA", "#FFCC66", "#FFF0F0", "#FFFFFF" ]; RED.editor.colorPicker.create({ id: "node-input-colour", value: this.color || "#a4a4a4", defaultValue: "#a4a4a4", palette: colorPalette, cellWidth: 16, cellHeight: 16, cellMargin: 3, none: false, opacity: 1.0, sortPalette: function (a, b) { return a.l - b.l; } }).appendTo("#node-input-row-style-colour"); $("#node-input-isrealplugin").on('change', function(ev) { if ( $('#node-input-isrealplugin').is(":checked") ) { $('#node-input-isplugin').prop('checked',false).trigger('change') $('#node-input-frt2bakcomm').prop('checked',false).trigger('change') $('#node-input-bak2frtcomm').prop('checked',false).trigger('change') } }) $("#node-input-isplugin").on('change', function(ev) { if ( $('#node-input-isplugin').is(":checked") ) { $('#node-input-isrealplugin').prop('checked',false).trigger('change') } }) $("#node-input-colour").on('change', function(ev) { var colour = $(this).val(); var nodeDiv = $('.red-ui-search-result-node') nodeDiv.css('backgroundColor',colour); var borderColor = RED.utils.getDarkerColor(colour); if (borderColor !== colour) { nodeDiv.css('border-color',borderColor); } }); this.editorSummary = RED.editor.createEditor({ id: 'node-input-summary', mode: 'ace/mode/markdown', value: $("#node-input-summary").val() }); this.editorDesc = RED.editor.createEditor({ id: 'node-input-description', mode: 'ace/mode/markdown', value: $("#node-input-description").val() }); var node = this; var iconRow = $('#node-input-row-icon-picker'); $('<label data-i18n="editor.settingIcon">').appendTo(iconRow); var iconButton = $('<button type="button" class="red-ui-button red-ui-editor-node-appearance-button">').appendTo(iconRow); $('<i class="fa fa-caret-down"></i>').appendTo(iconButton); var nodeDiv = $('<div>',{class:"red-ui-search-result-node"}).appendTo(iconButton); var colour = this.color || RED.utils.getNodeColor(node.type, node._def); var icon_url = RED.utils.getNodeIcon(node._def,node); nodeDiv.css('backgroundColor',colour); var borderColor = RED.utils.getDarkerColor(colour); if (borderColor !== colour) { nodeDiv.css('border-color',borderColor); } var iconContainer = $('<div/>',{class:"red-ui-palette-icon-container"}).appendTo(nodeDiv); RED.utils.createIconElement(icon_url, iconContainer, true); iconButton.on("click", function(e) { e.preventDefault(); var iconPath; var icon = $("#red-ui-editor-node-icon").val()||""; if (icon) { iconPath = RED.utils.separateIconPath(icon); } else { iconPath = RED.utils.getDefaultNodeIcon(node._def, node); } var backgroundColor = RED.utils.getNodeColor(node.type, node._def); if (node.type === "subflow") { backgroundColor = $("#red-ui-editor-node-color").val(); } RED.editor.iconPicker.show(iconButton,backgroundColor,iconPath,false,function(newIcon) { $("#red-ui-editor-node-icon").val(newIcon||""); var icon_url = RED.utils.getNodeIcon(node._def,{type:node.type,icon:newIcon}); RED.utils.createIconElement(icon_url, iconContainer, true); }); }); RED.popover.tooltip(iconButton, function() { return $("#red-ui-editor-node-icon").val() || RED._("editor.default"); }); $('<input type="hidden" id="red-ui-editor-node-icon">').val(node.icon).appendTo(iconRow); }, oneditsave: function () { this.color = $('#node-input-colour').val(); $("#node-input-summary").val(this.editorSummary.getValue()); $("#node-input-description").val(this.editorDesc.getValue()); this.icon = $('#red-ui-editor-node-icon').val(); this.editorSummary.destroy(); this.editorDesc.destroy(); delete this.editorSummary; delete this.editorDesc; }, oneditcancel: function () { this.editorSummary.destroy(); this.editorDesc.destroy(); delete this.editorSummary; delete this.editorDesc; }, onpaletteremove: function() { }, oneditresize: function (size) { }, button: { enabled: function() { return !this.changed }, onclick: function () { if (this.changed) { return RED.notify(RED._("notification.warning", { message: RED._("notification.warnings.undeployedChanges") }), "warning"); } doButtonSubmission(this) } }, }); })(); </script>