Debug messages using uibuilder
Well maybe "debug" is slightly over selling it!
This example will dump any msg you send to the uibuilder node out to the front-end web page and will nicely format it.
You will get an entry on the page for every topic that you send.
[{"id":"13c0a870.e90988","type":"uibuilder","z":"18cb249f.38bafb","name":"vDebug","topic":"","url":"vdebug","fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"showfolder":false,"x":580,"y":800,"wires":[[],[]]},{"id":"57b49b8.69f6564","type":"comment","z":"18cb249f.38bafb","name":"index.html","info":"<!doctype html><html lang=\"en\"><head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, user-scalable=yes\">\n <title>uibuilder - Debug (jQuery version)</title>\n <meta name=\"description\" content=\"uibuilder - Debug (jQuery version)\">\n <link rel=\"icon\" href=\"./images/node-blue.ico\">\n\n <link type=\"text/css\" rel=\"stylesheet\" href=\"../uibuilder/vendor/bootstrap/dist/css/bootstrap.min.css\" />\n <link type=\"text/css\" rel=\"stylesheet\" href=\"../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.css\" />\n\n <link rel=\"stylesheet\" href=\"./index.css\" media=\"all\">\n</head><body>\n <div id=\"app\">\n <b-container id=\"app_container\">\n <h1>Node-RED Debug display</h1>\n <p>Using uibuilder VueJS and bootstrap-vue</p>\n <p v-if=\"Object.getOwnPropertyNames(this.topics).length === 1\"><i>Nothing to show</i></p>\n <ul>\n <transition-group name=\"fade\" mode=\"out-in\">\n <li v-for=\"(topic,title) in topics\" :key=\"topic.encodedTopic\">\n <a :href=\"'#t'+topic.encodedTopic\">{{title}}</a> ({{topic.count+1}})\n </li>\n </transition-group>\n </ul>\n <div v-for=\"(topic,title) in topics\">\n <a :href=\"'#t'+topic.encodedTopic\"></a>\n <h2>{{title}} ({{topic.count+1}})</h2>\n <pre :id=\"'t'+topic.encodedTopic\" v-html=\"syntaxHighlight(topic.data)\" class=\"syntax-highlight\"></pre>\n </div>\n </b-container>\n </div>\n\n <script src=\"../uibuilder/vendor/socket.io/socket.io.js\"></script>\n <script src=\"../uibuilder/vendor/vue/dist/vue.js\"></script> <!-- dev version with component compiler -->\n <!-- <script src=\"../uibuilder/vendor/vue/dist/vue.min.js\"></script> prod version with component compiler -->\n <!-- <script src=\"../uibuilder/vendor/vue/dist/vue.runtime.min.js\"></script> prod version without component compiler -->\n <!-- <script src=\"https://unpkg.com/babel-polyfill@latest/dist/polyfill.min.js\"></script> for older browsers -->\n <script src=\"../uibuilder/vendor/bootstrap-vue/dist/bootstrap-vue.js\"></script>\n <!-- <script src=\"./uibuilderfe.js\"></script> //dev version -->\n <script src=\"./uibuilderfe.min.js\"></script> <!-- //prod version -->\n <script src=\"./index.js\"></script>\n</body></html>\n","x":720,"y":820,"wires":[],"icon":"node-red/parser-html.svg"},{"id":"28da072c.7096b8","type":"comment","z":"18cb249f.38bafb","name":"index.js","info":"/* jshint browser: true, esversion: 5, asi: true */\n/* globals document,Vue,window,uibuilder */\n/*\n Copyright (c) 2019 Julian Knight (Totally Information)\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n*/\n\n/** @see https://github.com/TotallyInformation/node-red-contrib-uibuilder/wiki/Front-End-Library---available-properties-and-methods */\n\nconst app1 = new Vue({\n el: '#app',\n data: {\n topics : {},\n }, // --- End of data --- //\n computed: {\n }, // --- End of computed --- //\n\n methods: {\n // return formatted HTML version of JSON object\n syntaxHighlight: function(json) {\n json = JSON.stringify(json, undefined, 4)\n json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n return json.replace(/(\"(\\\\u[a-zA-Z0-9]{4}|\\\\[^u]|[^\\\\\"])*\"(\\s*:)?|\\b(true|false|null)\\b|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)/g, function (match) {\n var cls = 'number'\n if (/^\"/.test(match)) {\n if (/:$/.test(match)) {\n cls = 'key'\n } else {\n cls = 'string'\n }\n } else if (/true|false/.test(match)) {\n cls = 'boolean'\n } else if (/null/.test(match)) {\n cls = 'null'\n }\n return '<span class=\"' + cls + '\">' + match + '</span>'\n })\n }, // --- End of syntaxHighlight --- //\n }, // --- End of methods --- //\n\n mounted: function(){\n /** **REQUIRED** Start uibuilder comms with Node-RED @since v2.0.0-dev3\n * Pass the namespace and ioPath variables if hosting page is not in the instance root folder\n * e.g. If you get continual `uibuilderfe:ioSetup: SOCKET CONNECT ERROR` error messages.\n * e.g. uibuilder.start('/nr/uib', '/nr/uibuilder/vendor/socket.io') // change to use your paths/names\n */\n uibuilder.start()\n \n var vueApp = this\n\n uibuilder.onChange('msg', function(newVal){\n console.info('[uibuilder.onChange] property msg changed!', newVal)\n\n /** keep track of inbound topics\n * We have to use Vue.set since Vue doesn't track deep object updates\n */\n if ( (newVal.topic !=='') && (newVal.topic !== undefined) ) {\n // Existing topic?\n if ( newVal.topic in vueApp.topics ) {\n // update count & data\n Vue.set(vueApp.topics, newVal.topic, {\n 'count': vueApp.topics[newVal.topic].count + 1,\n 'encodedTopic': vueApp.topics[newVal.topic].encodedTopic,\n 'data': newVal,\n })\n } else { // new topic\n /** add to obj\n * @type {{count:integer,encodedTopic:string,data:Object}} vueApp.topics[]\n */\n Vue.set(vueApp.topics, newVal.topic, {\n 'count': 0,\n 'encodedTopic': encodeURIComponent(newVal.topic).replace(/\\%/g,''),\n 'data': newVal,\n })\n // vueApp.topics[newVal.topic] = {\n // 'count': 0,\n // 'encodedTopic': encodeURIComponent(newVal.topic).replace(/\\%/g,''),\n // 'data': newVal,\n // }\n }\n }\n }) // -- end of on-change-msg -- //\n } // --- End of mounted hook --- //\n\n}) // --- End of app1 --- //\n\n// EOF\n","x":850,"y":820,"wires":[],"icon":"font-awesome/fa-file-code-o"},{"id":"4e02591f.4b6be8","type":"comment","z":"18cb249f.38bafb","name":"Debug input (Vue version)","info":"A simple page that will display the latest msg output for each topic.\nUse to help debug msg's.\n\n## To use\n\nAfter setup, send any msg to the uibuilder node, open the resulting web page and see the output.\n\n## To install this example:\n\n1. Install `node-red-contrib-uibuilder` & import\n from the library\n\n2. Copy the code from the comment nodes \n (index.htm, index.css and index.js) and paste into the \n corresponding files.\n\nSee here for further details: https://discourse.nodered.org/t/node-red-multi-line-status/8775/28\n\nRequires uibuilder v2.","x":770,"y":780,"wires":[]},{"id":"d26aa73.6ed5b58","type":"comment","z":"18cb249f.38bafb","name":"index.css","info":"/* Cloak elements on initial load to hide the possible display of {{ ... }} \n * Add to the app tag or to specific tags\n * To display \"loading...\", change to the following:\n * [v-cloak] > * { display:none }\n * [v-cloak]::before { content: \"loading…\" }\n */\n[v-cloak] { display: none; }\n\n/* Colours for Syntax Highlighted pre's */\n.syntax-highlight {color:white;background-color:black;padding:5px 10px;}\n.syntax-highlight > .key {color:#ffbf35}\n.syntax-highlight > .string {color:#5dff39;}\n.syntax-highlight > .number {color:#70aeff;}\n.syntax-highlight > .boolean {color:#b993ff;}","x":980,"y":820,"wires":[],"icon":"node-red/hash.svg"},{"id":"c1e24247.6841f","type":"link in","z":"18cb249f.38bafb","name":"vDebug","links":["8c7b3d33.6e8aa"],"x":440,"y":800,"wires":[["13c0a870.e90988"]]}]