Can anyone else please offer a hand or suggestions on these final points ?
My worst fears, nothing works now:
[{"id":"449863c1.3b7fec","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"1","order":2,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"1\"\n data-payload=\"1\">1\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":130,"y":140,"wires":[[]]},{"id":"700f1600.04891c","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"2","order":3,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"2\"\n data-payload=\"2\">2\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":250,"y":140,"wires":[[]]},{"id":"4c6394f2.9d8d9c","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"3","order":4,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"3\"\n data-payload=\"3\">3\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":370,"y":140,"wires":[[]]},{"id":"98688ec.eae177","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"4","order":5,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"btn<br>on\">on</span>\n <span class=\"btn<br>off\">off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <span style=\"background-color:#006600\" class=\"onoff\">Node red line that may overflow the 1234 width of the button<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":130,"y":180,"wires":[[]]},{"id":"b6b4ee71.45c86","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"5","order":6,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"on\">btn<br>on</span>\n <span class=\"off\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"5\"\n data-payload=\"5\">\n <label class=\"ck-switch\">\n <span class=\"onoff\">btn height problem<br>off</span>\n </label>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":250,"y":180,"wires":[[]]},{"id":"6fa8e5a1.c6102c","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"6","order":7,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"on\">btn<br>on</span>\n <span class=\"off\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"6\"\n data-payload=\"6\">\n <label class=\"ck-switch\">\n <span class=\"onoff\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":370,"y":180,"wires":[[]]},{"id":"b045c8d3.031958","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"script for all buttons with class remote-button","order":14,"width":"1","height":"1","format":"<div>\n<!--diliberately emtpy - only need the script below -->\n</div>\n\n<script>\n\n(function($scope) {\n//debugger\n\n //cause a small delay while things load \n //ideally this would be an init event or on all parts of document loaded\n //(may not be necessary!)\n setTimeout(function() {\n //debugger\n $scope.init();\n },100);\n \n \n //SETTINGS...\n var BUTTON_CLASS = \".remote-button\";\n var SEND_0_FOR_CLEARED_RADIO_BUTTONS = true;\n var SEND_ONLY_STATE_CHANGES_RADIO_BUTTONS = true;\n \n \n /** \n * Initialise all buttons with class BUTTON_CLASS\n */\n $scope.init = function () {\n //debugger\n console.log(\"$scope.init called. Adding event handlers to all buttons with class '\" + BUTTON_CLASS + \"'.\");\n var clickButtons = $(BUTTON_CLASS) \n clickButtons.click(function(e){\n \n var btn = $(this)\n var type = btn.data(\"buttontype\");//get the button type from attribute data-buttontype=\"xxxxx\"\n var topic = btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n var payload = btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\nvar group = btn.data(\"radiogroup\") || null;\nvar state = btn.data(\"state\") || 0;//get the last state payload from attribute data-state=\"n\"\nvar ck = {\"class\": BUTTON_CLASS, \"new type\": type, \"topic\":topic,\"payload\":payload, \"group\": group, \"state\": state, \"event\": \"click\"};\nconsole.log(\"click():\",ck);\n //debugger\n if(type == \"radio\"){\n setRadioButton(btn, true);\n } else if(type == \"toggle\"){\n var state = btn.data(\"state\") || 0;//get the last state payload from attribute data-state=\"n\"\n var newPayload = state == 1 ? 0 : 1;\n setButtonState(btn,newPayload)\n var tm = {\"type\": type, \"topic\":topic,\"payload\":newPayload, \"event\": \"click\"}\n console.log(\"Sending msg for clicked toggle button\", tm)\n $scope.send(tm)\n } else {\n var sm = {\"type\": type, \"topic\":topic,\"payload\":payload, \"event\": \"click\"}\n console.log(\"Sending msg for clicked button\", tm)\n $scope.send(sm)\n }\n });\n \n };\n\n //watch for node-red msgs\n $scope.$watch('msg', function(msg) {\n //debugger\n if(!msg){ //if no msg \n console.log(\"$scope.$watch('msg', ...) - msg is empty\");\n return;\n }\n if(!msg.topic){ //if no topic set found\n console.log(\"msg.topic is empty - cannot match this to any button\")\n return; //stop processing!\n }\n\n var buttonSelector = BUTTON_CLASS + \"[data-topic='\" + msg.topic + \"']\" \n var $btn = $(buttonSelector);//get the button\n \n if(!$btn.length){ //if no button found\n console.log(buttonSelector + \" not found - cannot set state\")\n return; //stop processing!\n }\n \n if($btn.length > 1){ //if MORE than one button found\n console.log(buttonSelector + \" found more than 1 button - is this intended? Do you have the same data-topic set on multiple buttons?\")\n }\n \n //see if this is a command - if so, process the command\n if(typeof msg.payload === \"object\" && msg.payload.command){\n processCommand($btn, msg.payload)\n return;\n } \n \n if($btn.data(\"buttontype\") === \"radio\"){\n setRadioButton($btn, false);\n }\n \n if($btn.data(\"buttontype\") === \"toggle\"){\n if(msg.payload == \"1\"){\n setButtonState($btn, 1);\n } else if(msg.payload == \"0\"){\n setButtonState($btn, 0);\n } else {\n console.log(\"Invalid toggle value in msg.payload, cannot set \" + buttonSelector + \". Ensure msg.payload is either 0 or 1\") \n }\n }\n\n }); \n \n /** \n * helper function to set the correct icon & update the \"data-payload\" memory \n */\n function setButtonState($btn, state){\n console.log(\"setButtonState\", $btn[0], state);\n var oldState = $btn.data(\"state\");\n var btntxt = \"\";\n var btnbgc = \"#333333\";\n $btn.data(\"state\", state);//set data-payload to new state value (used as a memory)\n \n //determine the opposite state\n var oppositeState;\n var oldIcon = $btn.data(\"icon\" + oldstate); //get icon1 or icon2 depending on oppositeState\n var newIcon = $btn.data(\"icon\" + state); //get icon1 or icon2 depending on newPayload\n var $span = $btn.find(\".onoff\"); //get the <span> element\n// var $chck=$btn.find(\"input[type=checkbox]\");//get the checkbox\n// var $state=$chck.is(\":checked\");\n// console.log(\"$chck=\" + $state);\n\n if(state == \"1\" || state === 1){\n state = 1; //normalise to a number\n oppositeState = 0;\n btntxt = $btn.data(\"ontext\");\n btnbgc = $btn.data(\"onbgcolour\");\n // $chck.prop('checked',true);\n } else {\n state = 0; //normalise to a number\n oppositeState = 1;\n btntxt = $btn.data(\"offtext\");\n btnbgc = $btn.data(\"offbgcolour\");\n // $chck.prop('checked',false);\n }\n/* if(!$icon.length){\n $icon = $btn.find(\"span\"); //get the <span> element instead!\n }\n if(!$icon.length){\n console.log(\"<i> or <span> not found inside button - cant toggle the icon!\")\n return oldState;//exit this function - nothing to toggle!\n }\n \n //get the old icon and new icon names\n var oldIcon = $btn.data(\"icon\" + oppositeState); //get icon1 or icon2 depending on oppositeState\n var newIcon = $btn.data(\"icon\" + state); //get icon1 or icon2 depending on newPayload\n*/ \n //if we have newIcon and an actual DOM element ($icon) - update it...\n if(newIcon && oldIcon){ //$icon.length){\n// if(newIcon.includes(\"fa-\")){ \n $icon.removeClass(oldIcon).addClass(newIcon); // fontawesome\n// } else { \n// $icon.text(newIcon); // MDI\n }\n/* $icon.css({\"background-color\": btnbgc});*/\n// $btn.css({\"background-color\": btnbgc});\n $span.css({\"background-color\": btnbgc});\n $span.text(btntxt);\n }\n return oldState;\n }\n/*\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"on\">btn<br>on more text</span>\n <span class=\"off\">btn<br>off</span>\n </label>\n </md-button>\n*/ \n\n /** \n * helper function \n */\n function setRadioButton($btn, sendMsgs){\n// var $chck=$btn.find(\"input[type=checkbox]\");//get the checkbox\n var topic = $btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n var group = $btn.data(\"radiogroup\");\n var groupBtns = $(\"[data-radiogroup='\"+group+\"']\");\n var m = null;\n for(var i = 0; i < groupBtns.length; i++) {\n var oldState;\n var rb = $(groupBtns[i]);\n if(!rb || !rb.length) continue;\n var t = rb.data(\"topic\");\n if(t == topic) continue;//skip clicked button\n oldState = setButtonState(rb,0);\n// $chck.prop('checked',false);\n if(sendMsgs && SEND_0_FOR_CLEARED_RADIO_BUTTONS) {\n if(SEND_ONLY_STATE_CHANGES_RADIO_BUTTONS && oldState == 0) continue;\n m = {\"type\": \"radio\", \"topic\":t,\"payload\":0, \"event\": \"click\"};\n console.log(\"Sending 0 payload for other radio button in group\", m)\n $scope.send(m);\n }\n }\n if(sendMsgs) {\n// var p = $btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n// var m = {\"type\": \"radio\", \"topic\":topic, \"payload\": p, \"event\": \"click\"};\n var m = {\"type\": \"radio\", \"topic\":topic, \"payload\": 1, \"event\": \"click\"};\n console.log(\"Sending msg for radio button\", m)\n $scope.send(m);\n }\n setButtonState($btn,1);//set state of this button\n// $chck.prop('checked',true);\n setTimeout(function(){\n setButtonState($btn,1);//set state of this button \n },200) \n\n }\n \n function processCommand($btn, payload){\n //first check payload is correct format...\n if(!payload || !payload.command || !payload.value){\n console.log(\"Cannot process command. Expected a payload object with .command and .value. \")\n }\n var cmd = payload.command.trim();\n switch(cmd){\n case \"addClass\":\n $btn.addClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n case \"toggleClass\":\n $btn.toggleClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n case \"removeClass\":\n $btn.removeClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n default:\n console.log(\"command '\" + payload.command + \"' is not supported\")\n }\n } \n \n /** \n * helper function to determine a value is REALLY a number \n */\n function isNumeric(n){\n if(n === \"\") return false;\n if(n === true || n === false) return false;\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n \n\n})(scope);\n</script>","storeOutMessages":false,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":250,"y":340,"wires":[["ac92a2e7.532df"]]},{"id":"ac92a2e7.532df","type":"debug","z":"cb2d7de9.28bbe","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":530,"y":340,"wires":[]},{"id":"7f2122c8.6d6c3c","type":"inject","z":"cb2d7de9.28bbe","name":"choose radio btn 4","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"4","payload":"4","payloadType":"num","x":150,"y":500,"wires":[["b045c8d3.031958"]]},{"id":"97dbd289.389b","type":"inject","z":"cb2d7de9.28bbe","name":"toggleClass disabled, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"disabled\"}","payloadType":"json","x":170,"y":440,"wires":[["b045c8d3.031958"]]},{"id":"75fbec6e.793664","type":"inject","z":"cb2d7de9.28bbe","name":"choose radio btn 5","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"5","payloadType":"num","x":150,"y":540,"wires":[["b045c8d3.031958"]]},{"id":"5295fbe8.20ecf4","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"7","order":8,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"On\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"7\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"7\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":130,"y":220,"wires":[[]]},{"id":"8118294d.6b4298","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"8","order":9,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"nOn\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"8\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"8\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":250,"y":220,"wires":[[]]},{"id":"4f76813a.a6fe6","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"9","order":10,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"On\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"9\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"9\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":370,"y":220,"wires":[[]]},{"id":"c9b79c0f.e8ef1","type":"comment","z":"cb2d7de9.28bbe","name":"radiogroup1","info":"","x":490,"y":180,"wires":[]},{"id":"71c9ddee.9f3d34","type":"comment","z":"cb2d7de9.28bbe","name":"radiogroup2","info":"","x":490,"y":220,"wires":[]},{"id":"fb6d5cde.77948","type":"inject","z":"cb2d7de9.28bbe","name":"toggleClass blinking, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"blinking\"}","payloadType":"json","x":470,"y":440,"wires":[["b045c8d3.031958"]]},{"id":"772502cd.dad3ac","type":"ui_template","z":"cb2d7de9.28bbe","group":"49c9cca6.e7da04","name":"CSS only ","order":1,"width":0,"height":0,"format":"<style>\n :root {\n --remote-button-background: black;\n --remote-button-foreground: #cccccc;\n }\n .nr-dashboard-template {\n padding: 0px;\n }\n .md-button {\n border-radius: 10px;\n }\n .md-button:hover {\n border:1px solid red;\n }\n .bigger{\n font-size:1.5em;\n }\n .bold {\n font-weight:bold;\n }\n /* This is for buttons with a lot of text. `font-size:0.7em` */\n /* makes the font 70% normal size */\n .small{\n font-size:0.5em;\n }\n .remote-button.disabled{\n pointer-events: none;\n opacity: 0.5;\n }\n.remote-button, .onoff {\n height: 100%;\n opacity: 1;\n color: white;\n}\n\n\n.remote-button {\n margin: -6px;\n padding: 6px;\n width: 100%;\n height: 100%;\n overflow: hidden;\n\n}\n\n.remote-button:hover {\n border: 1px solid red;\n}\n\n.remote-button span {\n text-align: center;\n}\n.remote-button span {\n white-space: normal;\n word-break: break-word;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n /* This is for buttons with just icons, to upsize the size */\n /* of the icon with the line: */\n /* <i class=\"fa fa-fw fa-plus remote-icon\"> in the other node */\n .remote-icon{\n font-size:2.0em;\n }\n /* This is the same as the other one, but it makes the icon smaller */\n .remote-iconS{\n font-size:0.5em;\n }\n .remote-button.red{\n background-color: #cc0000 !important;\n }\n .remote-button.green{\n background-color: #00bb00 !important;\n }\n .remote-button.blue{\n background-color: #0000dd !important;\n }\n\n .remote-button.blinking {\n animation: blink-animation 1s steps(5, start) infinite;\n animation-timing-function: ease;\n -webkit-animation: blink-animation 1s steps(5, start) infinite;\n }\n @keyframes blink-animation {\n to { visibility: hidden; }\n }\n @-webkit-keyframes blink-animation {\n to { visibility: hidden; }\n }\n.remote-button.warning {\n color: red;\n}\n\n.remote-button.animated .remote-button.warning {\n -webkit-animation: pulse 1s infinite;\n animation: pulse 1s infinite;\n}\n\n@-webkit-keyframes pulse {\n 0% {\n opacity: 0.2\n }\n\n 35% {\n opacity: 1.0\n }\n\n 100% {\n opacity: 0.2\n }\n}\n\n@keyframes pulse {\n 0% {\n opacity: 0.2\n }\n\n 35% {\n opacity: 1.0\n }\n\n 100% {\n opacity: 0.2\n }\n}\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"global","x":140,"y":300,"wires":[[]]},{"id":"a01fe5a2.5ff8f8","type":"inject","z":"cb2d7de9.28bbe","name":"toggleClass red, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"red\"}","payloadType":"json","x":460,"y":480,"wires":[["b045c8d3.031958"]]},{"id":"19c84e72.c23fe2","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"mute","order":12,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button\" \n data-payload=\"1\" \n data-buttontype=\"toggle\"\n data-topic=\"mute\"\n data-icon0=\"volume_off\"\n data-icon1=\"volume_mute\"\n aria-label=\"volume mute\"\n >\n <i class=\"material-icons md-48\">volume_mute</i>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":250,"y":260,"wires":[[]],"info":" class=\"material-icons\"> volume_off"},{"id":"c1c9b13b.49d93","type":"ui_template","z":"cb2d7de9.28bbe","group":"50a1d6b5.ce2c88","name":"0","order":2,"width":"3","height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#aa00aa'\n data-offbgcolour='#660066'\n data-topic=\"0\"\n data-payload=\"0\">0\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":130,"y":100,"wires":[[]]},{"id":"50a1d6b5.ce2c88","type":"ui_group","z":"","name":"HOME","tab":"6ff5405c.a8e6","order":1,"disp":true,"width":3,"collapse":false},{"id":"49c9cca6.e7da04","type":"ui_group","z":"","name":"Full_Remote2","tab":"58443ae1.3adab4","order":3,"disp":false,"width":"3","collapse":false},{"id":"6ff5405c.a8e6","type":"ui_tab","z":"","name":"TEST","icon":"dashboard","order":3,"disabled":false,"hidden":false},{"id":"58443ae1.3adab4","type":"ui_tab","z":"","name":"HDMI_TV_control","icon":"dashboard","order":7,"disabled":false,"hidden":false}]
Made syntax corrected and buttons to have text to be changed
[{"id":"9d7fa5bb.c4fc58","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"1","order":2,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"1\"\n data-payload=\"1\">1\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":230,"y":120,"wires":[[]]},{"id":"e51bcde3.5a5bc","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"2","order":3,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"2\"\n data-payload=\"2\">2\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":350,"y":120,"wires":[[]]},{"id":"e6ebced.0762b3","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"3","order":4,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#ff0000'\n data-offbgcolour='#660000'\n data-buttontype=\"toggle\"\n data-topic=\"3\"\n data-payload=\"3\">3\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":470,"y":120,"wires":[[]]},{"id":"1862dd6.e4cc923","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"4","order":5,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"btn<br>on\">on</span>\n <span class=\"btn<br>off\">off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <span style=\"background-color:#006600\" class=\"onoff\">Node red line that may overflow the 1234 width of the button<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off<br>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":230,"y":160,"wires":[[]]},{"id":"e10f21dd.ee5f","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"5","order":6,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"on\">btn<br>on</span>\n <span class=\"off\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"5\"\n data-payload=\"5\">\n <label class=\"ck-switch\">\n <span class=\"onoff\">btn height problem<br>off</span>\n </label>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":350,"y":160,"wires":[[]]},{"id":"64479b0a.398754","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"6","order":7,"width":1,"height":"2","format":"<!--\n V1\n ==\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n <i class=\"fa fa-circle-o\"></i>\n V2\n ==\n<div>\n<md-button class=\"md-button ck-button on off small\"\n <div class=\"ck-button\" \n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n </div>\n</md-button>\n<div>\n<md-button class=\"md-button ck-button on off small\"\n data-payload=\"1\"\n data-state=\"1\"\n data-buttontype='checkbox'\n data-radiogroup='group1'\n data-topic=\"11\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <div style=\"background-color:#097479);\" class=\"on\">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</div>\n <div style=\"background-color:#003333;\" class=\"off\">radio<br>group1<br><br>btn 11<br>off</div>\n </label>\n</md-button>\n</div>\n</div> \n v3\n ==\n<div>\n <md-button class=\"md-button remote-button on off small\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"4\"\n data-payload=\"4\">\n <label class=\"ck-switch\">\n <input type=\"checkbox\" unchecked>\n <span class=\"on\">btn<br>on</span>\n <span class=\"off\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n//-->\n<div>\n <md-button class=\"md-button remote-button small\"\n data-state=\"1\"\n data-ontext=\"btn<br>On\"\n data-offtext=\"Off\"\n data-onbgcolour='#0000ff'\n data-offbgcolour='#000066'\n data-buttontype='radio'\n data-radiogroup='group1'\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-topic=\"6\"\n data-payload=\"6\">\n <label class=\"ck-switch\">\n <span class=\"onoff\">btn<br>off</span>\n </label>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":470,"y":160,"wires":[[]]},{"id":"100f412b.7f633f","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"script for all buttons with class remote-button","order":14,"width":"1","height":"1","format":"<div>\n<!--diliberately emtpy - only need the script below -->\n</div>\n\n<script>\n\n(function($scope) {\n//debugger\n\n //cause a small delay while things load \n //ideally this would be an init event or on all parts of document loaded\n //(may not be necessary!)\n setTimeout(function() {\n //debugger\n $scope.init();\n },100);\n \n \n //SETTINGS...\n var BUTTON_CLASS = \".remote-button\";\n var SEND_0_FOR_CLEARED_RADIO_BUTTONS = true;\n var SEND_ONLY_STATE_CHANGES_RADIO_BUTTONS = true;\n \n \n /** \n * Initialise all buttons with class BUTTON_CLASS\n */\n $scope.init = function () {\n //debugger\n console.log(\"$scope.init called. Adding event handlers to all buttons with class '\" + BUTTON_CLASS + \"'.\");\n var clickButtons = $(BUTTON_CLASS) \n clickButtons.click(function(e){\n \n var btn = $(this)\n var type = btn.data(\"buttontype\");//get the button type from attribute data-buttontype=\"xxxxx\"\n var topic = btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n var payload = btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n var group = btn.data(\"radiogroup\") || null;\n var state = btn.data(\"state\") || 0;//get the last state payload from attribute data-state=\"n\"\n var ck = {\"class\": BUTTON_CLASS, \"new type\": type, \"topic\":topic,\"payload\":payload, \"group\": group, \"state\": state, \"event\": \"click\"};\n console.log(\"click():\",ck);\n //debugger\n if(type == \"radio\"){\n setRadioButton(btn, true);\n } else if(type == \"toggle\"){\n var state = btn.data(\"state\") || 0;//get the last state payload from attribute data-state=\"n\"\n var newPayload = state == 1 ? 0 : 1;\n setButtonState(btn,newPayload)\n var tm = {\"type\": type, \"topic\":topic,\"payload\":newPayload, \"event\": \"click\"}\n console.log(\"Sending msg for clicked toggle button\", tm)\n $scope.send(tm)\n } else {\n var sm = {\"type\": type, \"topic\":topic,\"payload\":payload, \"event\": \"click\"}\n console.log(\"Sending msg for clicked button\", tm)\n $scope.send(sm)\n }\n });\n \n };\n\n //watch for node-red msgs\n $scope.$watch('msg', function(msg) {\n //debugger\n if(!msg){ //if no msg \n console.log(\"$scope.$watch('msg', ...) - msg is empty\");\n return;\n }\n if(!msg.topic){ //if no topic set found\n console.log(\"msg.topic is empty - cannot match this to any button\")\n return; //stop processing!\n }\n\n var buttonSelector = BUTTON_CLASS + \"[data-topic='\" + msg.topic + \"']\" \n var $btn = $(buttonSelector);//get the button\n \n if(!$btn.length){ //if no button found\n console.log(buttonSelector + \" not found - cannot set state\")\n return; //stop processing!\n }\n \n if($btn.length > 1){ //if MORE than one button found\n console.log(buttonSelector + \" found more than 1 button - is this intended? Do you have the same data-topic set on multiple buttons?\")\n }\n \n //see if this is a command - if so, process the command\n if(typeof msg.payload === \"object\" && msg.payload.command){\n processCommand($btn, msg.payload)\n return;\n } \n \n if($btn.data(\"buttontype\") === \"radio\"){\n setRadioButton($btn, false);\n }\n \n if($btn.data(\"buttontype\") === \"toggle\"){\n if(msg.payload == \"1\"){\n setButtonState($btn, 1);\n } else if(msg.payload == \"0\"){\n setButtonState($btn, 0);\n } else {\n console.log(\"Invalid toggle value in msg.payload, cannot set \" + buttonSelector + \". Ensure msg.payload is either 0 or 1\") \n }\n }\n\n }); \n \n /** \n * helper function to set the correct icon & update the \"data-payload\" memory \n */\n function setButtonState($btn, state){\n console.log(\"setButtonState\", $btn[0], state);\n var oldState = $btn.data(\"state\");\n var btntxt = \"\";\n var btnbgc = \"#333333\";\n $btn.data(\"state\", state);//set data-payload to new state value (used as a memory)\n \n //determine the opposite state\n var oppositeState;\n if(state == \"1\" || state === 1){\n state = 1; //normalise to a number\n oppositeState = 0;\n btntxt = $btn.data(\"ontext\");\n btnbgc = $btn.data(\"onbgcolour\");\n } else {\n state = 0; //normalise to a number\n oppositeState = 1;\n btntxt = $btn.data(\"offtext\");\n btnbgc = $btn.data(\"offbgcolour\");\n }\n\n var $icon = $btn.find(\"i\"); //get the <i> element\n if(!$icon.length){\n $icon = $btn.find(\"span\"); //get the <span> element instead!\n }\n if(!$icon.length){\n console.log(\"<i> or <span> not found inside button - cant toggle the icon!\")\n return oldState;//exit this function - nothing to toggle!\n }\n \n //get the old icon and new icon names\n var oldIcon = $btn.data(\"icon\" + oppositeState); //get icon1 or icon2 depending on oppositeState\n var newIcon = $btn.data(\"icon\" + state); //get icon1 or icon2 depending on newPayload\n \n //if we have newIcon and an actual DOM element ($icon) - update it...\n if(newIcon && $icon.length){\n if(newIcon.includes(\"fa-\")){ \n $icon.removeClass(oldIcon).addClass(newIcon); // fontawesome\n } else { \n $icon.text(newIcon); // MDI\n }\n $btn.css({\"background-color\": btnbgc});\n var txt = $btn.find(\"span\") // find any span element in button. no class, no id. works until there is only one of such\n txt.text(btntxt)\n }\n return oldState;\n }\n \n\n /** \n * helper function \n */\n function setRadioButton($btn, sendMsgs){\n// var $chck=$btn.find(\"input[type=checkbox]\");//get the checkbox\n var topic = $btn.data(\"topic\");//get the topic from attribute data-topic=\"xxxxx\"\n var group = $btn.data(\"radiogroup\");\n var groupBtns = $(\"[data-radiogroup='\"+group+\"']\");\n var m = null;\n for(var i = 0; i < groupBtns.length; i++) {\n var oldState;\n var rb = $(groupBtns[i]);\n if(!rb || !rb.length) continue;\n var t = rb.data(\"topic\");\n if(t == topic) continue;//skip clicked button\n oldState = setButtonState(rb,0);\n\n if(sendMsgs && SEND_0_FOR_CLEARED_RADIO_BUTTONS) {\n if(SEND_ONLY_STATE_CHANGES_RADIO_BUTTONS && oldState == 0) continue;\n m = {\"type\": \"radio\", \"topic\":t,\"payload\":0, \"event\": \"click\"};\n console.log(\"Sending 0 payload for other radio button in group\", m)\n $scope.send(m);\n }\n }\n if(sendMsgs) {\n// var p = $btn.data(\"payload\");//get the payload from attribute data-payload=\"xxxxx\"\n// var m = {\"type\": \"radio\", \"topic\":topic, \"payload\": p, \"event\": \"click\"};\n var m = {\"type\": \"radio\", \"topic\":topic, \"payload\": 1, \"event\": \"click\"};\n console.log(\"Sending msg for radio button\", m)\n $scope.send(m);\n }\n setButtonState($btn,1);//set state of this button\n// $chck.prop('checked',true);\n setTimeout(function(){\n setButtonState($btn,1);//set state of this button \n },200) \n\n }\n \n function processCommand($btn, payload){\n //first check payload is correct format...\n if(!payload || !payload.command || !payload.value){\n console.log(\"Cannot process command. Expected a payload object with .command and .value. \")\n }\n var cmd = payload.command.trim();\n switch(cmd){\n case \"addClass\":\n $btn.addClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n case \"toggleClass\":\n $btn.toggleClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n case \"removeClass\":\n $btn.removeClass(payload.value); //this calls the jquery function by name (specified in .command) on the $btn and passes in .value\n break;\n default:\n console.log(\"command '\" + payload.command + \"' is not supported\")\n }\n } \n \n /** \n * helper function to determine a value is REALLY a number \n */\n function isNumeric(n){\n if(n === \"\") return false;\n if(n === true || n === false) return false;\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n \n\n})(scope);\n</script>","storeOutMessages":false,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":350,"y":320,"wires":[["140196c1.7eebe9"]]},{"id":"140196c1.7eebe9","type":"debug","z":"3b43cc76.155114","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":630,"y":320,"wires":[]},{"id":"52fc52ae.92122c","type":"inject","z":"3b43cc76.155114","name":"choose radio btn 4","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"4","payload":"4","payloadType":"num","x":250,"y":480,"wires":[["100f412b.7f633f"]]},{"id":"cbe05d1a.6f93d","type":"inject","z":"3b43cc76.155114","name":"toggleClass disabled, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"disabled\"}","payloadType":"json","x":270,"y":420,"wires":[["100f412b.7f633f"]]},{"id":"1883732.276038d","type":"inject","z":"3b43cc76.155114","name":"choose radio btn 5","repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"5","payloadType":"num","x":250,"y":520,"wires":[["100f412b.7f633f"]]},{"id":"b5ed30a0.aac3e","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"7","order":8,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"On\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"7\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"7\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":230,"y":200,"wires":[[]]},{"id":"3f5da4e0.3b13bc","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"8","order":9,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"On\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"8\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"8\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":350,"y":200,"wires":[[]]},{"id":"5b854fa3.0fb7c","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"9","order":10,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button small\"\n data-ontext=\"On\"\n data-offtext=\"Off\"\n data-onbgcolour='#00ff00'\n data-offbgcolour='#006600'\n data-buttontype='radio'\n data-radiogroup='group2'\n data-topic=\"9\"\n data-icon0=\"fa fa-circle-o\"\n data-icon1=\"fa fa-check-circle-o\"\n data-payload=\"9\">\n <i class=\"fa fa-circle-o\"></i>\n <span>off</span>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":470,"y":200,"wires":[[]]},{"id":"f21ad72d.920178","type":"comment","z":"3b43cc76.155114","name":"radiogroup1","info":"","x":650,"y":160,"wires":[]},{"id":"249e591a.de8c66","type":"comment","z":"3b43cc76.155114","name":"radiogroup2","info":"","x":650,"y":200,"wires":[]},{"id":"c5442a27.bc5a88","type":"inject","z":"3b43cc76.155114","name":"toggleClass blinking, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"blinking\"}","payloadType":"json","x":570,"y":420,"wires":[["100f412b.7f633f"]]},{"id":"97ed64ec.d6e0a8","type":"ui_template","z":"3b43cc76.155114","group":"49c9cca6.e7da04","name":"CSS only ","order":1,"width":0,"height":0,"format":"<style>\n :root {\n --remote-button-background: black;\n --remote-button-foreground: #cccccc;\n }\n .nr-dashboard-template {\n padding: 0px;\n }\n .md-button {\n border-radius: 10px;\n }\n .md-button:hover {\n border:1px solid red;\n }\n .bigger{\n font-size:1.5em;\n }\n .bold {\n font-weight:bold;\n }\n /* This is for buttons with a lot of text. `font-size:0.7em` */\n /* makes the font 70% normal size */\n .small{\n font-size:0.5em;\n }\n .remote-button.disabled{\n pointer-events: none;\n opacity: 0.5;\n }\n.remote-button, .onoff {\n height: 100%;\n opacity: 1;\n color: white;\n}\n\n\n.remote-button {\n margin: -6px;\n padding: 6px;\n width: 100%;\n height: 100%;\n overflow: hidden;\n\n}\n\n.remote-button:hover {\n border: 1px solid red;\n}\n\n.remote-button span {\n text-align: center;\n}\n.remote-button span {\n white-space: normal;\n word-break: break-word;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n /* This is for buttons with just icons, to upsize the size */\n /* of the icon with the line: */\n /* <i class=\"fa fa-fw fa-plus remote-icon\"> in the other node */\n .remote-icon{\n font-size:2.0em;\n }\n /* This is the same as the other one, but it makes the icon smaller */\n .remote-iconS{\n font-size:0.5em;\n }\n .remote-button.red{\n background-color: #cc0000 !important;\n }\n .remote-button.green{\n background-color: #00bb00 !important;\n }\n .remote-button.blue{\n background-color: #0000dd !important;\n }\n\n .remote-button.blinking {\n animation: blink-animation 1s steps(5, start) infinite;\n animation-timing-function: ease;\n -webkit-animation: blink-animation 1s steps(5, start) infinite;\n }\n @keyframes blink-animation {\n to { visibility: hidden; }\n }\n @-webkit-keyframes blink-animation {\n to { visibility: hidden; }\n }\n.remote-button.warning {\n color: red;\n}\n\n.remote-button.animated .remote-button.warning {\n -webkit-animation: pulse 1s infinite;\n animation: pulse 1s infinite;\n}\n\n@-webkit-keyframes pulse {\n 0% {\n opacity: 0.2\n }\n\n 35% {\n opacity: 1.0\n }\n\n 100% {\n opacity: 0.2\n }\n}\n\n@keyframes pulse {\n 0% {\n opacity: 0.2\n }\n\n 35% {\n opacity: 1.0\n }\n\n 100% {\n opacity: 0.2\n }\n}\n\n</style>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"global","x":240,"y":280,"wires":[[]]},{"id":"beb14dd8.71a37","type":"inject","z":"3b43cc76.155114","name":"toggleClass red, on 5","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"5","payload":"{\"command\":\"toggleClass\",\"value\":\"red\"}","payloadType":"json","x":560,"y":460,"wires":[["100f412b.7f633f"]]},{"id":"243ef41b.a1545c","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"mute","order":12,"width":1,"height":1,"format":"<div>\n <md-button class=\"md-button remote-button\" \n data-payload=\"1\" \n data-buttontype=\"toggle\"\n data-topic=\"mute\"\n data-icon0=\"volume_off\"\n data-icon1=\"volume_mute\"\n aria-label=\"volume mute\"\n >\n <i class=\"material-icons md-48\">volume_mute</i>\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":350,"y":240,"wires":[[]],"info":" class=\"material-icons\"> volume_off"},{"id":"fbfb2ac2.edc168","type":"ui_template","z":"3b43cc76.155114","group":"50a1d6b5.ce2c88","name":"0","order":2,"width":"3","height":1,"format":"<div>\n <md-button class=\"md-button remote-button bigger\"\n data-ontext=\"Btn4\\nOn\"\n data-offtext=\"Btn4\\nOff\"\n data-onbgcolour='#aa00aa'\n data-offbgcolour='#660066'\n data-topic=\"0\"\n data-payload=\"0\">0\n </md-button>\n</div>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":230,"y":80,"wires":[[]]},{"id":"50a1d6b5.ce2c88","type":"ui_group","z":"","name":"HOME","tab":"6ff5405c.a8e6","order":1,"disp":true,"width":3,"collapse":false},{"id":"49c9cca6.e7da04","type":"ui_group","z":"","name":"Full_Remote2","tab":"58443ae1.3adab4","order":3,"disp":false,"width":"3","collapse":false},{"id":"6ff5405c.a8e6","type":"ui_tab","z":"","name":"TEST","icon":"dashboard","order":3,"disabled":false,"hidden":false},{"id":"58443ae1.3adab4","type":"ui_tab","z":"","name":"HDMI_TV_control","icon":"dashboard","order":7,"disabled":false,"hidden":false}]
Hi, Thank you. What should it look like ?
Heh, I just made corrections to have the functionality working again. I will not do the styles for you. No way. It is question of art and you are the artist here. I'm pretty bad on art.
And yes it looks same for me.
Before you go what is happening on this line;
<md-button class="md-button remote-button small"
in comparison to:
<md-button class="md-button remote-button on off small"
that makes a mess of the controller etc.
I don't see such classes and I don't see the controller using them. We may be on different sources again thus hard to tell.
I think you should take it more like step by step. Take one issue at the time and work it out and then take next challenge.
I will try to ask in another way.
What is the connection between the structure of ui_template and the shape of messages in and out of the controller ?
I don't think I understand the question.
HTML elements and the button structure can't be something arbitrary. Otherwise the controller can not reach the elements it needs to manipulate. Controller can't guess. Controller can be made to recognize certain structure, there can be many of structures with more complexity.
Controller gives behaviors to elements (buttons) It makes buttons clickable and creates structure of that outgoing message.
And controller takes in messages with certain shape (let's say protocol). It can do different things based on what is asked to do.
That's the connection between them with my very poor explanation.
I think your English is very good. In this development context I find it very hard to phrase and ask the right question in the first place.
For example if the template was more elaborate with say multiple spans. When there is a click event, what is the format of the incoming message to the click listener ?
And what format should the outgoing message be in ?
should it always match that of the incoming msg ?
It all depends what for there will be multiple spans. (or what ever HTMLElement) Do you need control the appearance or content of those spans individually ....
As the button itself is nothing more than a button, it does not matter what kind of message will be sent out if you click on it. But what ever going to take any action when such message is feed in, must understand what it is and behave accordingly.
But !!!!!, there is 2 types of buttons which listen the messages they send out by itself. And those are special cases. If you try to do it with "regular" button, you will create infinite loop.
And that is why the message structure means a lot.
if($btn.data("buttontype") === "radio"){
....
}
if($btn.data("buttontype") === "toggle"){
.....
}
When I had a more elaborate ui_template I seemed to get a message cascade.
I spent a whole week getting:
<md-button class="md-button ck-button on off small"
data-payload="1"
data-state="1"
data-buttontype='checkbox'
data-radiogroup='group1'
data-topic="11">
<label class="ck-switch">
<input type="checkbox" unchecked>
<span style="background-color:#097479);" class="on">radio<br>group1<br><br>btn 11<br>with a lot more text fun<br>on</span>
<span style="background-color:#003333;" class="off">radio<br>group1<br><br>btn 11<br>off</span>
</label>
</md-button>
To render as:
One last try at asking the right question.
Can the incompatibilities between your fixed controller and the above template be restricted to the function seButtonState() ?
There is 2 spans. setButtonState
finds both and changes both in same way. If you need to do something more fancy, the setButtonState
must be made smarter.
Thank you that is a great relief. By the way my original controller was so rubbish because I was trying to keep your controller code unchanged except for additions relating to the new template. And what a mess it was.
I am very happy if any changes would be restricted to that one function.
I am having a bit of trouble changing your code to accept a pair of icons + text, or just icons or just text.
Any suggestions ?
The confusion I have is that your code uses the variable $icon for both an icon or a fallback to a span ?
The exact portion of code is:
var $icon = $btn.find("i"); //get the <i> element
if(!$icon.length){
$icon = $btn.find("span"); //get the <span> element instead!
}
if(!$icon.length){
console.log("<i> or <span> not found inside button - cant toggle the icon!")
return oldState;//exit this function - nothing to toggle!
}
//get the old icon and new icon names
var oldIcon = $btn.data("icon" + oppositeState); //get icon1 or icon2 depending on oppositeState
var newIcon = $btn.data("icon" + state); //get icon1 or icon2 depending on newPayload
//if we have newIcon and an actual DOM element ($icon) - update it...
if(newIcon && $icon.length){
if(newIcon.includes("fa-")){
$icon.removeClass(oldIcon).addClass(newIcon); // fontawesome
} else {
$icon.text(newIcon); // MDI
}
$btn.css({"background-color": btnbgc});
var txt = $btn.find("span") // find any span element in button. no class, no id. works until there is only one of such
txt.text(btntxt)
I am not so good at this part, as you know already !
Now, it all depends again if you will have differently made buttons or will they share similar setup.
But already there is one catch. the icon can be placed directly or inside span. And there is no indication that this span contains icon.
var $icon = $btn.find("i"); //get the <i> element
if(!$icon.length){
$icon = $btn.find("span"); //get the <span> element instead!
}
You can choose to remove ability to have icon inside span but that also means that you can probably only use fa-icons. Or you can add class or id for that element so you can deal with it individually.
Then ,you need to figure out all possible setups for buttons. And if you going to use multiple spans for text contents you'll need to add even class or id-s so again, the controller must be able to find them individually.
But what is the purpose of having two spans here.
As there is no classes on and off, I cant see the use case. Do you want to switch between them according the state or will be visible together?
The css moves one span on top of the other.
The css also makes one of them invisiible according to the state of the hidden input checkbox. (This is a standard way of emulating a toggle button using pure css).
It also means that a call to:
var $chck=$btn.find("input[type=checkbox]");//get the checkbox
$chck.prop('checked',false); //To uncheck it.
$chck.prop('checked',true); //To check it.
var $state=$chck.is(":checked"); //To read it.
For the css to work the structure must be the same just with missing attributes for icon etc.
You have data-state
defined in button. Any reason to have another element (checkbox) to hold state? I really doubt on that. According to current state of button you can choose if you'll need to add or remove classes from spans and change icon if exists and/or change text inside span if needed.
The resultant button text styling with embedded \n format capability is only possible with the css structure that includes the checkbox. So I could get rid of data-state. I probably left it there as a sanity check to see if the checkbox is in sync with the data-state/