CVE-2022-3783: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability, which was classified as problematic, has been found in node-red-dashboard. This issue affects some unknown processing of the file components/ui-component/ui-component-ctrl.js of the component ui_text Format Handler. The manipulation leads to cross site scripting. The attack may be initiated remotely. The name of the patch is 9305d1a82f19b235dfad24a7d1dd4ed244db7743. It is recommended to apply a patch to fix this issue. The associated identifier of this vulnerability is VDB-212555.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2022-10-31T21:15Z
Repository: https://github.com/node-red/node-red-dashboard
Language: JavaScript
Files changed: CHANGELOG.md, dist/dashboard.appcache, dist/js/app.min.js, package.json, src/components/ui-component/ui-component-ctrl.js
Commit date: 2022-08-24 17:38:03 +0100
Commit message: Fix ui_text XSS

to close #772

Diff: diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3006b9b..6f45cb5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 
+### 3.1.9: Maintenance Release
+
+ - Fix Cross site scripting for ui_text format input. Issue #772
+
 ### 3.1.8: Maintenance Release
 
  - Use Node-RED CSS vars for ui-bas to help themeing. PR #763
  - Let spacer also have custom class
 
diff --git a/dist/dashboard.appcache b/dist/dashboard.appcache
index 7fd35a2..dcb2adc 100644
--- a/dist/dashboard.appcache
+++ b/dist/dashboard.appcache
@@ -1,7 +1,7 @@
 CACHE MANIFEST
-# Time: Wed May 25 2022 11:23:30 GMT+0100 (British Summer Time)
+# Time: Wed Aug 24 2022 17:30:31 GMT+0100 (British Summer Time)
 
 CACHE:
 i18n.js
 icon120x120.png
 icon192x192.png
@@ -24,6 +24,6 @@ gs/gridstack.min.js
 loading.html
 
 NETWORK:
 *
 
-# hash: 22f744c7102e4eb0375d482c7bd34ac0d407159d34773e84e1f5087d0b6444d3
+# hash: 9ff936fabba7ec5170a4f63f8f6b72aa1343c36c57f8382848eb81dae9ca5512
diff --git a/dist/js/app.min.js b/dist/js/app.min.js
index 64c4a5e..58389ed 100644
--- a/dist/js/app.min.js
+++ b/dist/js/app.min.js
@@ -591,11 +591,11 @@ angular.module("ui").service("UiEvents",function(){var e="update-value",t=this;t
 var sizes={sx:48,sy:48,gx:6,gy:6,cx:6,cy:6,px:0,py:0};window.innerWidth<350&&(sizes.sx=42,sizes.sy=42),sizes.setSizes=function(s){sizes.sx=s.sx,sizes.sy=s.sy,sizes.gx=s.gx,sizes.gy=s.gy,sizes.cx=s.cx,sizes.cy=s.cy,sizes.px=s.px,sizes.py=s.py},sizes.columns=function(s){return parseInt(s.header.config.width)},angular.module("ui").value("uiSizes",sizes);
 angular.module("ui").directive("uiTemplate",["$compile","$rootScope","UiEvents",function($compile,$rootScope,events){function createInnerScope(n){var e=$rootScope.$new();return e.send=function(e){events.emit({id:n,msg:e})},e}return function(scope,element,attrs){var id=scope.$eval("me.item.id"),innerScope;scope.$watch(attrs.uiTemplate,function(value){var oldMsg;innerScope&&(oldMsg=innerScope.msg,innerScope.$destroy()),innerScope=createInnerScope(id),innerScope.theme=scope.$eval("me.item.theme"),window.scope=innerScope,element.html(value),delete window.scope,void 0!==oldMsg&&(innerScope.msg=oldMsg);var ic=scope.$eval("me.item.initController");if(ic){var func=eval("("+ic+")");func(innerScope,events)}innerScope.width=scope.$eval("me.item.width"),innerScope.height=scope.$eval("me.item.height"),innerScope.label=scope.$eval("me.item.label"),$compile(element.contents())(innerScope)}),scope.$watch("me.item.msg",function(e){innerScope&&void 0!==(innerScope.msg=e)&&void 0!==e.template&&scope.$parent.me.setFormat(e.template)}),scope.$on("$destroy",function(){innerScope&&innerScope.$destroy()})}}]);
 angular.module("ui").directive("uiHighlight",function(){return{restrict:"A",link:function(i,o,t){t.$observe("uiHighlight",function(i){i?o.css("border-bottom","5px solid "+i):o.css("border-bottom",void 0)})}}});
 angular.module("ui").directive("colorPickerInputWrapper",function(){return{restrict:"C",link:function(r,i,n){r.AngularColorPickerController.options.pickerOnly&&i.hide()}}});
 angular.module("ui").directive("uiComponent",["$http","$compile","$templateCache","$q",function(e,t,n,l){return{restrict:"E",bindToController:{item:"="},replace:!0,controller:"uiComponentController",controllerAs:"me",template:"<div flex ng-include='::templateUrl' include-replace></div>",scope:!0,link:function(e,t,n,l){e.templateUrl="components/ui-component/templates/"+l.item.type+".html",l.init()}}}]),angular.module("ui").directive("includeReplace",function(){return{require:"ngInclude",restrict:"A",link:function(e,t,n){t.replaceWith(t.children())}}});
-angular.module("ui").controller("uiComponentController",["$scope","UiEvents","$interpolate","$interval",function(l,u,e,r){this.$onInit=function(){var i,m=this;"string"==typeof m.item.format&&(m.item.getText=e(m.item.format).bind(null,m.item)),"string"==typeof m.item.label&&(m.item.getLabel=e(m.item.label).bind(null,m.item),m.item.safeLabel="nr-dashboard-widget-"+m.item.label.replace(/\W/g,"_")),"string"==typeof m.item.tooltip&&(m.item.getTooltip=e(m.item.tooltip).bind(null,m.item)),"string"==typeof m.item.color&&(m.item.getColor=e(m.item.color).bind(null,m.item)),"string"==typeof m.item.icon&&(m.item.getIcon=e(m.item.icon).bind(null,m.item)),"string"==typeof m.item.units&&(m.item.getUnits=e(m.item.units).bind(null,m.item)),m.init=function(){switch(m.item.type){case"button":m.buttonClick=function(e){n({id:m.item.id,value:m.item.value,event:{clientX:e.originalEvent.clientX,clientY:e.originalEvent.clientY,bbox:[e.originalEvent.clientX-e.originalEvent.layerX,e.originalEvent.clientY-e.originalEvent.layerY+e.currentTarget.clientHeight,e.originalEvent.clientX-e.originalEvent.layerX+e.currentTarget.clientWidth,e.originalEvent.clientY-e.originalEvent.layerY]}},0)};break;case"switch":m.switchClick=function(){n({id:m.item.id,value:!m.item.value},0)};break;case"dropdown":m.searchTerm="",m.selectAll=!1,m.changed=!1,m.itemChanged=function(){m.searchTerm="",m.item.multiple?m.changed=!0:m.valueChanged(0)},m.checkAll=function(){var e=m.item.options.filter(function(e){return e.label.toLowerCase().includes(m.searchTerm.toLowerCase())});m.item.value=m.selectAll?e.map(function(e){return e.value}):[],m.valueChanged(0)},m.closed=function(){m.changed&&(m.changed=!1,m.valueChanged(0))},(m.item.me=m).processInput=function(e){o(e)};break;case"numeric":var i=function(e){m.item.value=parseFloat(m.item.value),isNaN(m.item.value)&&(m.item.value=m.item.min),0<e?(m.item.value==m.item.max&&1==m.item.wrap?m.item.value=m.item.min:m.item.value<m.item.max&&(m.item.value=Math.round(1e4*Math.min(m.item.value+e,m.item.max))/1e4),m.item.value<m.item.min&&(m.item.value=m.item.min)):e<0&&(m.item.value==m.item.min&&1==m.item.wrap?m.item.value=m.item.max:m.item.value>m.item.min&&(m.item.value=Math.round(1e4*Math.max(m.item.value+e,m.item.min))/1e4),m.item.value>m.item.max&&(m.item.value=m.item.max))},e=9.5*(Math.round(1e4*(m.item.min+m.item.step))/1e4).toString().length,t=9.5*(Math.round(1e4*(m.item.max+m.item.step))/1e4).toString().length;m.item.minWidth=t<e?e:t;var a=null;m.newValue=function(){isNaN(parseFloat(m.item.value))||(m.item.value<m.item.min&&(m.item.value=m.item.min),m.item.value>m.item.max&&(m.item.value=m.item.max),u.emit({id:m.item.id,value:m.item.value}))},m.periodicChange=function(e){i(e);var t=0;a=r(function(){75<++t?i(250*e):50<t?i(50*e):35<t?i(10*e):25<t?i(2*e):15<t?i(e):5<t&&t%2&&i(e)},100)},m.stopPeriodic=function(){a&&(r.cancel(a),a=null,m.valueChanged(0))};break;case"chart":m.item.theme=l.main.selectedTab.theme;break;case"colour-picker":(m.item.width<4||!m.item.showValue&&!m.item.showPicker)&&(m.item.showPicker=!1,m.item.showValue=!1,m.item.showSwatch=!0),m.item.showPicker&&m.item.height<4&&(m.item.height=m.item.showSwatch||m.item.showValue?4:3),m.item.options={format:m.item.format,inline:m.item.showPicker,hue:m.item.showHue,alpha:m.item.showAlpha,lightness:m.item.showLightness,swatch:m.item.showSwatch,swatchOnly:m.item.width<2||!m.item.showValue,swatchPos:"right",pos:"bottom right",case:"lower",round:!m.item.square,pickerOnly:m.item.showPicker&&!(m.item.showSwatch||m.item.showValue)},m.item.key=function(e){13!==e.charCode&&13!==e.which&&9!==e.charCode&&9!==e.which||(u.emit({id:m.item.id,value:m.item.value}),m.api&&m.api.close())},m.item.eventapi={onChange:function(e,t,i){void 0!==i&&m.valueChanged(0)},onOpen:function(e,t){m.api=e}},l.$watch("me.item.value",function(){m.item.oldValue||(m.item.oldValue=m.item.value),"true"===m.item.dynOutput&&m.item.value!==m.item.oldValue&&(m.item.oldValue=m.item.value,m.valueChanged(20))});break;case"text-input":case"text-input-CR":-1!=m.item.mode.indexOf("time")&&(m.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=e.value.match(/^(\d\d):(\d\d)/);if(null==i){var a=Date.parse(e.value);isNaN(a)&&(a=Date.now()),t=new Date(a)}else t=new Date("1970-01-01 "+i[1]+":"+i[2]+":00Z")}t.setMilliseconds(0),t.setSeconds(0),e.value=t,m.item.value=e.value},m.item.me=m),"week"!==m.item.mode&&"month"!==m.item.mode||(m.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=Date.parse(e.value);isNaN(i)&&(i=Date.now()),t=new Date(i)}t.setMilliseconds(0),t.setSeconds(0),e.value=t,m.item.value=e.value},m.item.me=m);break;case"date-picker":void 0!==m.item.ddd&&("number"!=typeof m.item.ddd&&"string"!=typeof m.item.ddd||(m.item.ddd=new Date(m.item.ddd))),m.processInput=function(e){e.value=new Date(e.value),m.item.ddd=e.value},m.setDate=function(){m.item.value=m.item.ddd,m.valueChanged(0)},m.item.me=m;break;case"form":m.processInput=function(e){if("object"==typeof e.value)for(var t in e.value)if(m.item.formValue.hasOwnProperty(t))for(var i in m.item.options)"date"!==m.item.options[i].type&&"time"!==m.item.options[i].type||m.item.options[i].value!==t||(e.value[t]=new Date(e.value[t])),m.item.formValue[t]=e.value[t]},m.item.extraRows=0,m.item.options.map(function(e){"multiline"==e.type&&1<e.rows&&(m.item.extraRows+=e.rows-1)}),m.item.rowCount=1==m.item.splitLayout?Math.ceil(m.item.options.length/2):m.item.options.length,m.item.rowCount+=""==m.item.label?1:2,m.item.rowCount+=m.item.extraRows,m.item.rowHeight=((m.item.rowCount-1)*m.item.sy+(""==m.item.label?.3*m.item.sy:1.2*m.item.sy)+(m.item.rowCount-1)*m.item.cy)/m.item.rowCount,m.stop=function(e){13!==e.charCode&&13!==e.which||(e.preventDefault(),e.stopPropagation())},m.submit=function(){m.item.value=JSON.parse(JSON.stringify(m.item.formValue)),m.valueChanged(0),m.reset()},m.reset=function(){for(var e in m.item.options)"checkbox"===m.item.options[e].type||"switch"===m.item.options[e].type?m.item.formValue[m.item.options[e].value]=!1:m.item.formValue[m.item.options[e].value]="";l.$$childTail.form.$setUntouched(),l.$$childTail.form.$setPristine()},m.item.me=m;break;case"template":m.setFormat=function(e){m.item.format=e},void 0!==m.item.msg&&void 0!==m.item.msg.template&&m.setFormat(m.item.msg.template);break;case"slider":m.wheel=function(e){e.preventDefault(),0<e.originalEvent.deltaY&&(m.item.value+=m.item.step,m.item.value>m.item.max&&(m.item.value=m.item.max)),e.originalEvent.deltaY<0&&(m.item.value-=m.item.step,m.item.value<m.item.min&&(m.item.value=m.item.min)),m.valueChanged(0)},m.active=!1,m.mdown=function(){m.active=!0},m.menter=function(){m.active=!0},m.mleave=function(){m.active=!1},m.mchange=function(){m.active=!1,m.valueChanged(0)},m.mup=function(){m.active&&(m.active=!1,m.valueChanged(0))}}},m.valueChanged=function(e){n({id:m.item.id,value:m.item.value},"number"==typeof e?e:10)},m.keyPressed=function(e){13===e.charCode||13===e.which?(u.emit({id:m.item.id,value:m.item.value}),m.lastItemSent=m.item.value):"blur"===e.type&&m.item.value!==m.lastItemSent&&(u.emit({id:m.item.id,value:m.item.value}),m.lastItemSent=m.item.value)};var n=function(e,t){0!==t?(i&&clearTimeout(i),i=setTimeout(function(){i=void 0,u.emit(e)},t)):u.emit(e)},o=function(e){e&&e.isOptionsValid&&(m.item.options=e.newOptions,delete m.item.isOptionsValid,delete m.item.newOptions)}}}]);
+angular.module("ui").controller("uiComponentController",["$scope","UiEvents","$interpolate","$interval",function(l,u,e,r){this.$onInit=function(){var i,a=this;"string"==typeof a.item.format&&(-1===a.item.format.indexOf("constructor")?a.item.getText=e(a.item.format).bind(null,a.item):a.item.getText=function(){return a.item.format}),"string"==typeof a.item.label&&(-1===a.item.label.indexOf("constructor")?(a.item.getLabel=e(a.item.label).bind(null,a.item),a.item.safeLabel="nr-dashboard-widget-"+a.item.label.replace(/\W/g,"_")):a.item.getText=function(){return a.item.label}),"string"==typeof a.item.tooltip&&(-1===a.item.tooltip.indexOf("constructor")?a.item.getTooltip=e(a.item.tooltip).bind(null,a.item):a.item.getText=function(){return a.item.tooltip}),"string"==typeof a.item.color&&(-1===a.item.color.indexOf("constructor")?a.item.getColor=e(a.item.color).bind(null,a.item):a.item.getText=function(){return a.item.color}),"string"==typeof a.item.icon&&(-1===a.item.icon.indexOf("constructor")?a.item.getIcon=e(a.item.icon).bind(null,a.item):a.item.getText=function(){return a.item.icon}),"string"==typeof a.item.units&&(-1===a.item.units.indexOf("constructor")?a.item.getUnits=e(a.item.units).bind(null,a.item):a.item.getText=function(){return a.item.units}),a.init=function(){switch(a.item.type){case"button":a.buttonClick=function(e){m({id:a.item.id,value:a.item.value,event:{clientX:e.originalEvent.clientX,clientY:e.originalEvent.clientY,bbox:[e.originalEvent.clientX-e.originalEvent.layerX,e.originalEvent.clientY-e.originalEvent.layerY+e.currentTarget.clientHeight,e.originalEvent.clientX-e.originalEvent.layerX+e.currentTarget.clientWidth,e.originalEvent.clientY-e.originalEvent.layerY]}},0)};break;case"switch":a.switchClick=function(){m({id:a.item.id,value:!a.item.value},0)};break;case"dropdown":a.searchTerm="",a.selectAll=!1,a.changed=!1,a.itemChanged=function(){a.searchTerm="",a.item.multiple?a.changed=!0:a.valueChanged(0)},a.checkAll=function(){var e=a.item.options.filter(function(e){return e.label.toLowerCase().includes(a.searchTerm.toLowerCase())});a.item.value=a.selectAll?e.map(function(e){return e.value}):[],a.valueChanged(0)},a.closed=function(){a.changed&&(a.changed=!1,a.valueChanged(0))},(a.item.me=a).processInput=function(e){o(e)};break;case"numeric":var i=function(e){a.item.value=parseFloat(a.item.value),isNaN(a.item.value)&&(a.item.value=a.item.min),0<e?(a.item.value==a.item.max&&1==a.item.wrap?a.item.value=a.item.min:a.item.value<a.item.max&&(a.item.value=Math.round(1e4*Math.min(a.item.value+e,a.item.max))/1e4),a.item.value<a.item.min&&(a.item.value=a.item.min)):e<0&&(a.item.value==a.item.min&&1==a.item.wrap?a.item.value=a.item.max:a.item.value>a.item.min&&(a.item.value=Math.round(1e4*Math.max(a.item.value+e,a.item.min))/1e4),a.item.value>a.item.max&&(a.item.value=a.item.max))},e=9.5*(Math.round(1e4*(a.item.min+a.item.step))/1e4).toString().length,t=9.5*(Math.round(1e4*(a.item.max+a.item.step))/1e4).toString().length;a.item.minWidth=t<e?e:t;var n=null;a.newValue=function(){isNaN(parseFloat(a.item.value))||(a.item.value<a.item.min&&(a.item.value=a.item.min),a.item.value>a.item.max&&(a.item.value=a.item.max),u.emit({id:a.item.id,value:a.item.value}))},a.periodicChange=function(e){i(e);var t=0;n=r(function(){75<++t?i(250*e):50<t?i(50*e):35<t?i(10*e):25<t?i(2*e):15<t?i(e):5<t&&t%2&&i(e)},100)},a.stopPeriodic=function(){n&&(r.cancel(n),n=null,a.valueChanged(0))};break;case"chart":a.item.theme=l.main.selectedTab.theme;break;case"colour-picker":(a.item.width<4||!a.item.showValue&&!a.item.showPicker)&&(a.item.showPicker=!1,a.item.showValue=!1,a.item.showSwatch=!0),a.item.showPicker&&a.item.height<4&&(a.item.height=a.item.showSwatch||a.item.showValue?4:3),a.item.options={format:a.item.format,inline:a.item.showPicker,hue:a.item.showHue,alpha:a.item.showAlpha,lightness:a.item.showLightness,swatch:a.item.showSwatch,swatchOnly:a.item.width<2||!a.item.showValue,swatchPos:"right",pos:"bottom right",case:"lower",round:!a.item.square,pickerOnly:a.item.showPicker&&!(a.item.showSwatch||a.item.showValue)},a.item.key=function(e){13!==e.charCode&&13!==e.which&&9!==e.charCode&&9!==e.which||(u.emit({id:a.item.id,value:a.item.value}),a.api&&a.api.close())},a.item.eventapi={onChange:function(e,t,i){void 0!==i&&a.valueChanged(0)},onOpen:function(e,t){a.api=e}},l.$watch("me.item.value",function(){a.item.oldValue||(a.item.oldValue=a.item.value),"true"===a.item.dynOutput&&a.item.value!==a.item.oldValue&&(a.item.oldValue=a.item.value,a.valueChanged(20))});break;case"text-input":case"text-input-CR":-1!=a.item.mode.indexOf("time")&&(a.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=e.value.match(/^(\d\d):(\d\d)/);if(null==i){var n=Date.parse(e.value);isNaN(n)&&(n=Date.now()),t=new Date(n)}else t=new Date("1970-01-01 "+i[1]+":"+i[2]+":00Z")}t.setMilliseconds(0),t.setSeconds(0),e.value=t,a.item.value=e.value},a.item.me=a),"week"!==a.item.mode&&"month"!==a.item.mode||(a.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=Date.parse(e.value);isNaN(i)&&(i=Date.now()),t=new Date(i)}t.setMilliseconds(0),t.setSeconds(0),e.value=t,a.item.value=e.value},a.item.me=a);break;case"date-picker":void 0!==a.item.ddd&&("number"!=typeof a.item.ddd&&"string"!=typeof a.item.ddd||(a.item.ddd=new Date(a.item.ddd))),a.processInput=function(e){e.value=new Date(e.value),a.item.ddd=e.value},a.setDate=function(){a.item.value=a.item.ddd,a.valueChanged(0)},a.item.me=a;break;case"form":a.processInput=function(e){if("object"==typeof e.value)for(var t in e.value)if(a.item.formValue.hasOwnProperty(t))for(var i in a.item.options)"date"!==a.item.options[i].type&&"time"!==a.item.options[i].type||a.item.options[i].value!==t||(e.value[t]=new Date(e.value[t])),a.item.formValue[t]=e.value[t]},a.item.extraRows=0,a.item.options.map(function(e){"multiline"==e.type&&1<e.rows&&(a.item.extraRows+=e.rows-1)}),a.item.rowCount=1==a.item.splitLayout?Math.ceil(a.item.options.length/2):a.item.options.length,a.item.rowCount+=""==a.item.label?1:2,a.item.rowCount+=a.item.extraRows,a.item.rowHeight=((a.item.rowCount-1)*a.item.sy+(""==a.item.label?.3*a.item.sy:1.2*a.item.sy)+(a.item.rowCount-1)*a.item.cy)/a.item.rowCount,a.stop=function(e){13!==e.charCode&&13!==e.which||(e.preventDefault(),e.stopPropagation())},a.submit=function(){a.item.value=JSON.parse(JSON.stringify(a.item.formValue)),a.valueChanged(0),a.reset()},a.reset=function(){for(var e in a.item.options)"checkbox"===a.item.options[e].type||"switch"===a.item.options[e].type?a.item.formValue[a.item.options[e].value]=!1:a.item.formValue[a.item.options[e].value]="";l.$$childTail.form.$setUntouched(),l.$$childTail.form.$setPristine()},a.item.me=a;break;case"template":a.setFormat=function(e){a.item.format=e},void 0!==a.item.msg&&void 0!==a.item.msg.template&&a.setFormat(a.item.msg.template);break;case"slider":a.wheel=function(e){e.preventDefault(),0<e.originalEvent.deltaY&&(a.item.value+=a.item.step,a.item.value>a.item.max&&(a.item.value=a.item.max)),e.originalEvent.deltaY<0&&(a.item.value-=a.item.step,a.item.value<a.item.min&&(a.item.value=a.item.min)),a.valueChanged(0)},a.active=!1,a.mdown=function(){a.active=!0},a.menter=function(){a.active=!0},a.mleave=function(){a.active=!1},a.mchange=function(){a.active=!1,a.valueChanged(0)},a.mup=function(){a.active&&(a.active=!1,a.valueChanged(0))}}},a.valueChanged=function(e){m({id:a.item.id,value:a.item.value},"number"==typeof e?e:10)},a.keyPressed=function(e){13===e.charCode||13===e.which?(u.emit({id:a.item.id,value:a.item.value}),a.lastItemSent=a.item.value):"blur"===e.type&&a.item.value!==a.lastItemSent&&(u.emit({id:a.item.id,value:a.item.value}),a.lastItemSent=a.item.value)};var m=function(e,t){0!==t?(i&&clearTimeout(i),i=setTimeout(function(){i=void 0,u.emit(e)},t)):u.emit(e)},o=function(e){e&&e.isOptionsValid&&(a.item.options=e.newOptions,delete a.item.isOptionsValid,delete a.item.newOptions)}}}]);
 angular.module("ui").directive("uiGauge",["$timeout","$interpolate",function(e){return{restrict:"E",replace:!0,templateUrl:"components/ui-gauge/ui-gauge.html",link:function(c){e(function(){var r,t,s,u,m,e,g=c.$eval("main.selectedTab.theme.name")||"theme-light",o=c.$eval("main.selectedTab.theme.themeState");o&&(t=o["widget-borderColor"].value,s=o["widget-backgroundColor"].value,u=o["widget-textColor"].value),t&&s||(u=s="theme-dark"===g?(t="#097479","#eeeeee"):(t="#0094CE","#111111")),c.$watch("me.item.gtype",function(){e&&e();var l=c.$eval("me.item"),n=c.$eval("$id");e="wave"===l.gtype?(document.getElementById("gauge_"+n).innerHTML='<svg id="gauge'+n+'" style="width:100%; height:100%;"></svg>',c.$watchGroup(["me.item.min","me.item.max","me.item.units","me.item.waveoptions","me.item.options"],function(){m&&m();var o=liquidFillGaugeDefaultSettings();o.minValue=l.min,o.maxValue=l.max,o.units=l.units,o.textVertPosition=.33,o.waveHeight=.09,o.waveRise=!1,o.waveCount=2,o.displayPercent=!1;var e=l.waveoptions;o.circleColor=e.circleColor[g],o.waveColor=e.waveColor[g],o.textColor=e.textColor[g],o.waveTextColor=e.waveTextColor[g],void 0===o.circleColor&&(o.circleColor=t),void 0===o.waveColor&&(o.waveColor=t),void 0===o.textColor&&(o.textColor=s),void 0===o.waveTextColor&&(o.waveTextColor=s),null!==l.options&&Object.keys(l.options).forEach(function(e){o[e]=l.options[e]}),r=loadLiquidFillGauge("gauge"+n,l.value,o),m=c.$watch("me.item.value",function(e){e=l.getText(),(isNaN(e)||""===e)&&(e=o.minValue),r.update(e)})})):c.$watchGroup(["me.item.min","me.item.max","me.item.seg1","me.item.seg2","me.item.colors","me.item.reverse","me.item.options"],function(){m&&m(),document.getElementById("gauge_"+n).innerHTML="";var o={id:"gauge_"+n,value:l.value,min:l.min,max:l.max,reverse:l.reverse,hideMinMax:l.hideMinMax,levelColors:l.reverse?l.colors.reverse():l.colors,valueMinFontSize:12,minLabelMinFontSize:8,labelMinFontSize:8,titleFontFamily:"inherit",valueFontFamily:"inherit",label:l.units,pointer:!0,relativeGaugeSize:!1,textRenderer:function(){return l.getText()||""}};if("donut"===l.gtype&&(o.donut=!0,o.pointer=!1),void 0===o.gaugeWidthScale&&delete o.gaugeWidthScale,void 0===o.gaugeColor&&(o.gaugeColor="rgba(127,127,127,0.5)"),void 0===o.pointerOptions&&(o.pointerOptions={color:u}),"compass"===l.gtype)o.donut=!0,o.gaugeWidthScale=.3,o.pointer=!0,o.refreshAnimationTime=5,o.pointerOptions={toplength:12,bottomlength:16,bottomwidth:8,color:void 0},o.gaugeColor=l.gageoptions.compassColor[g],o.levelColors=[l.gageoptions.compassColor[g]],void 0===o.gaugeColor&&(o.gaugeColor=s),void 0===o.pointerOptions.color&&(o.pointerOptions.color=s);else{var e=l.seg1,t=l.seg2;if(!isNaN(parseFloat(e))&&!isNaN(parseFloat(t))){var i=l.colors;o.customSectors={percents:!1,ranges:[{color:i[0],lo:o.min,hi:e},{color:i[1],lo:e,hi:t},{color:i[2],lo:t,hi:o.max}]},o.noGradient=!0}}o.valueFontColor=l.gageoptions.valueFontColor[g],o.labelFontColor=l.gageoptions.valueFontColor[g],null!==l.options&&Object.keys(l.options).forEach(function(e){o[e]=l.options[e]}),(r=new JustGage(o)).refreshLabel=function(e){e&&"string"==typeof e&&this.txtLabel.attr({text:e})};var a="";m=c.$watch("me.item.value",function(e){"object"==typeof e&&(e=l.getText()),isNaN(e=parseFloat(e))&&(e=o.min),l.getUnits()!==a&&(a=l.getUnits(),o.label=a,r.refreshLabel(a)),r.refresh(e)})})})},0)}}}]);
 function loadConfiguration(n,a){var l=a.config||{data:[],series:[],labels:[],nodata:!0},e=a.$eval("me.item"),o=parseFloat(e.ymin),t=parseFloat(e.ymax),i=e.xformat,s=a.$eval("main.selectedTab.theme.themeState"),r=e.useUTC||!1;l.options={animation:e.animation,spanGaps:e.spanGaps,scales:{},legend:!1,responsive:!0,maintainAspectRatio:!1,useDifferentColor:e.useDifferentColor},"pie"===n&&(l.options.cutoutPercentage=e.cutout||0,l.options.elements={arc:{borderWidth:0}});var c=(e.colors||["#1F77B4","#AEC7E8","#FF7F0E","#2CA02C","#98DF8A","#D62728","#FF9896","#9467BD","#C5B0D5"]).concat(["#7EB3C6","#BB9A61","#3F8FB9","#57A13F","#BC5879","#6DC2DF","#D7D185","#91CA96","#DEB64D","#31615A","#B46E3F","#9B2FAA","#61A240","#AA3167","#9D6D5E","#3498DB","#EC7063","#DAF7A6","#FFC300","#D98880","#48C9B0","#7FB3D5","#F9E79F","#922B21"]);if(l.colours=l.colours||c,a.barColours=[],a.lineColours=[],c.forEach(function(e,o){a.lineColours.push({backgroundColor:e,borderColor:e}),a.barColours.push({backgroundColor:c,borderColor:"#888",borderWidth:1})}),"line"===n)switch(l.options.scales.xAxes=[{type:"time",scaleLabel:{fontColor:"#fff",display:!0}}],"auto"!==i&&(l.options.scales.xAxes[0].time={displayFormats:{millisecond:i,second:i,minute:i,hour:i,day:i,week:i,month:i,quarter:i,year:i}}),!0===r&&(l.options.scales.xAxes[0].time.parser=function(e){return moment.utc(e)}),l.options.tooltips={mode:"x-axis",position:"cursor",bodyFontSize:10,bodySpacing:0,callbacks:{title:function(e,o){var a=e[0].xLabel;if(a=new Date(a).getTime(),isNaN(a)||a<1e6)return a;for(var t=1;t<e.length;t++)e[t].xLabel>a&&(a=e[t].xLabel);var s=moment(a);return!0===r&&(s=moment.utc(a)),"auto"!==i?s.format(i):s.calendar(null,{sameDay:"HH:mm:ss",nextDay:"HH:mm",lastDay:"HH:mm",lastWeek:"MMM D, hA",sameElse:"lll"})}}},l.options.hover={mode:"x-axis"},l.options.elements={line:{fill:!1},point:{radius:e.dot?2:0,hitRadius:4,hoverRadius:4}},e.interpolate){case"cubic":l.options.elements.line.cubicInterpolationMode="default";break;case"monotone":l.options.elements.line.cubicInterpolationMode="monotone";break;case"linear":l.options.elements.line.tension=0;break;case"bezier":l.options.elements.line.tension=.4;break;case"step":l.options.elements.line.stepped=!0}else if("bar"===n||"horizontalBar"===n)l.options.scales.xAxes=[{}];else if("radar"===n&&(l.options={scale:{ticks:{beginAtZero:!0,showLabelBackdrop:!1}}},isNaN(o)||(l.options.scale.ticks.min=o),isNaN(t)||(l.options.scale.ticks.max=t),s)){var u=s["widget-textColor"].value,p=tinycolor(u).toRgb(),d="rgba("+p.r+","+p.g+","+p.b+",0.1)",g="rgba("+p.r+","+p.g+","+p.b+",0.3)",f="rgba("+p.r+","+p.g+","+p.b+",0.6)";l.options.scale.ticks.fontColor=f,l.options.scale.ticks.fontSize=8,l.options.scale.pointLabels={fontColor:u,fontSize:14},l.options.scale.gridLines={color:d},l.options.scale.angleLines={color:g}}if("pie"!==n&&"polar-area"!==n&&"radar"!==n){if(l.options.scales.yAxes=[{}],l.options.scales.xAxes[0].ticks={},l.options.scales.yAxes[0].ticks={},"line"!==n&&"bar"!==n||(l.options.scales.yAxes[0].ticks.autoSkip=!0,l.options.scales.yAxes[0].ticks.callback=function(e,o,a){var t=navigator.languages&&navigator.languages.length?navigator.languages[0]:navigator.language;return e.toLocaleString(t)},isNaN(o)||(l.options.scales.yAxes[0].ticks.min=o),isNaN(t)||(l.options.scales.yAxes[0].ticks.max=t),isNaN(o)||isNaN(t)||(l.options.scales.yAxes[0].ticks.stepSize=(t-o)/4),"bar"===n&&(l.options.scales.yAxes[0].ticks.beginAtZero=!0)),"horizontalBar"===n&&(l.options.scales.xAxes[0].ticks.beginAtZero=!0,isNaN(o)||(l.options.scales.xAxes[0].ticks.min=o),isNaN(t)||(l.options.scales.xAxes[0].ticks.max=t),l.options.scales.xAxes[0].ticks.callback=function(e,o,a){var t=navigator.languages&&navigator.languages.length?navigator.languages[0]:navigator.language;return e.toLocaleString(t)}),s){l.options.scales.xAxes[0].ticks.fontColor=l.options.scales.yAxes[0].ticks.fontColor=s["widget-textColor"].value;var m=tinycolor(s["widget-textColor"].value).toRgb(),x="rgba("+m.r+","+m.g+","+m.b+",0.1)";l.options.scales.xAxes[0].gridLines=l.options.scales.yAxes[0].gridLines={color:x,zeroLineColor:x}}l.options.scales.xAxes[0].ticks.maxRotation=0,l.options.scales.xAxes[0].ticks.autoSkipPadding=4,l.options.scales.xAxes[0].ticks.autoSkip=!0}return!0!==e.legend&&"true"!==e.legend||(l.overrides=[],l.options.legend={display:!0,position:"top",labels:{boxWidth:10,fontSize:12,padding:8},onClick:function(e,o){var a,t=o.datasetIndex||0,s=this.chart;if("pie"===n||"polar-area"===n)for(var i=0;i<s.config.data.datasets.length;i++)(a=s.getDatasetMeta(i)).data[o.index].hidden=!1===a.data[o.index].hidden;else(a=s.getDatasetMeta(t)).hidden=null===a.hidden?!s.data.datasets[t].hidden:null;l.overrides[t]={hidden:a.hidden},s.update()}},"pie"!==n&&"polar-area"!==n&&"radar"!==n||(l.options.legend.position="left"),s&&(l.options.legend.labels.fontColor=s["widget-textColor"].value)),"pie"!==n&&"polar-area"!==n||(l.options.tooltips={callbacks:{title:function(e,o){return o.labels[e[0].index]},label:function(e,o){var a=o.datasets[e.datasetIndex],t=a.label||"";return t&&(t+=": "),t+=a.data[e.index]}}}),l.options=Object.assign({},l.options,e.options),l}angular.module("ui").directive("uiChartJs",["$timeout","$interpolate",function(a,e){return{restrict:"E",replace:!0,templateUrl:"components/ui-chart-js/ui-chart-js.html",link:function(r,e,o){a(function(){var s=r.$eval("me.item.look"),l=r.$eval("me.item.useOneColor");Chart.scaleService.updateScaleDefaults("time",{afterBuildTicks:function(e){var o=e.ticks.length-1;1<o&&(e.parseTime(e.ticks[o]).diff(e.parseTime(e.ticks[o-1]))<e.parseTime(e.ticks[o-1]).diff(e.parseTime(e.ticks[o-2]))&&e.ticks.splice(o-1,1))}}),Chart.defaults.global.elements.line.borderJoinStyle="round",Chart.plugins.register({beforeDatasetsDraw:function(e){var o=e.chart.ctx,a=e.chartArea;o.save(),o.beginPath(),o.rect(a.left,a.top,a.right-a.left,a.bottom-a.top),o.clip()},afterDatasetsDraw:function(e){e.chart.ctx.restore()}}),r.$watchGroup(["me.item.legend","me.item.interpolate","me.item.ymin","me.item.ymax","me.item.xformat","me.item.dot","me.item.cutout","me.item.nodata","me.item.animation","me.item.spanGaps","me.item.options","me.item.look"],function(e,o){s=e[11],JSON.stringify(e)!==JSON.stringify(o)&&(r.config=loadConfiguration(s,r))}),r.$watch("me.item.value",function(i){if(void 0!==i&&0<i.length)if(i=i[0],r.hasOwnProperty("config")||(r.config=loadConfiguration(s,r)),r.config.nodata=!1,"line"===s&&i.update){var e=i.values.series,o=r.config.series.indexOf(e);-1===o&&(r.config.series.push(e),o=r.config.series.indexOf(e),r.config.data.push([])),o>r.config.data.length&&r.config.data.push([]),i.remove&&r.config.data[o].splice(0,i.remove),r.config.data[o].push(i.values.data)}else{if("line"===s){if(void 0===i.values.data[0][0]){for(var a=!1,t=1;t<i.values.data.length;t++)i.values.data[t][0]&&i.values.data[t][0].hasOwnProperty("x")&&(a=!0);i.values.data[0]=a?[{x:null,y:null}]:[null]}isNaN(i.values.data[0][0])||(delete r.config.options.scales.xAxes[0].type,delete r.config.options.scales.xAxes[0].time)}if("bar"!==s&&"horizontalBar"!==s||(1<i.values.series.length||l?r.config.colours=r.lineColours:r.config.colours=r.barColours),"pie"===s)r.config.colours=r.barColours;else if("polar-area"===s&&r.config.options&&r.config.options.useDifferentColor){r.config.colours=r.barColours;var n=[];r.barColours.map(function(e){var o=Object.assign({},e),s=[];o.backgroundColor.map(function(e){var o=.7/i.values.series.length+.1,a=tinycolor(e).toRgb(),t="rgba("+a.r+","+a.g+","+a.b+","+o+")";s.push(t)}),o.backgroundColor=s,n.push(o)}),r.config.colours=n}r.config.data=i.values.data,r.config.series=i.values.series,r.config.labels=i.values.labels}else delete r.config,r.config=loadConfiguration(s,r)})},0),a(function(){r.$broadcast("$resize")},50)}}}]);
 angular.module("ui").directive("uiCardPanel",["$timeout","$rootScope",function(n,c){return{restrict:"E",transclude:!0,templateUrl:"components/ui-card-panel/ui-card-panel.html",controller:"uiCardPanelController",controllerAs:"ctrl",link:function(e,l,o,a){e.collapsed="true"==("undefined"!=typeof localStorage&&localStorage.getItem(o.id)||!1);var r=l.find(".nr-dashboard-cardcontainer"),t=0;a.init(r),e.collapseCard=function(){e.collapsed=!e.collapsed,"undefined"!=typeof localStorage&&localStorage.setItem(o.id,e.collapsed),r.slideToggle(t),n(function(){$(window).trigger("resize")},t),t=parseInt(o.slideToggleDuration,10)||150,c.$emit("collapse",o.id,!e.collapsed)},!0===e.collapsed&&(e.collapsed=!1,n(function(){l.find(".nr-dashboard-cardcarat").trigger("click")},20))}}}]);
 angular.module("ui").controller("uiCardPanelController",["uiSizes","$timeout","$scope",function(f,t,c){var i=this;i.width=f.columns(c.group)*f.sx+2*f.px+(f.columns(c.group)-1)*f.cx;var e,s,p=f.columns(c.group),l=0,n=!(i.init=function(r){e=r});function d(r,t,i,e){for(var n=0;n<e;n++){var a=s[t+n];a||(s[t+n]=a=new Array(f.columns(c.group)));for(var o=0;o<i;o++)a[r+o]=!0}}function h(r,t,i,e){for(var n=0;n<e;n++){var a=s[t+n];if(!a)break;for(var o=0;o<i;o++)if(a[r+o])return!1}return!0}i.refreshLayout=function(r){n||(n=!0,t(function(){s=[],e.children().each(function(){var r=$(this),t=r.find("[ui-card-size]:first").attr("ui-card-size")||r.attr("ui-card-size"),i=t.split("x"),e=Math.max(1,Math.min(f.columns(c.group),i&&parseInt(i[0])||p)),n=Math.max(1,i&&parseInt(i[1])||l);if(0==parseInt(i[1])&&void 0!==r.attr("ui-template")){var a=r.height()*parseInt(c.group.header.config.width)/e;if(!a||a<=0){var o=r[a=0].innerHTML.toLowerCase();-1!==o.indexOf("<div")&&(a=1),-1!==o.indexOf("<p")&&(a=1),-1!==o.indexOf("<span")&&(a=1),-1!==o.indexOf("<b")&&(a=1),-1!==o.indexOf("<h")&&(a=1),-1!==o.indexOf("<f")&&(a=1),-1!==o.indexOf("<iframe")&&(a=parseInt(3*c.group.header.config.width/4*(f.cx+f.sx)))}n=Math.ceil(a/(f.cy+f.sy))}parseInt(i[1])<0&&void 0!==r.attr("ui-template")&&(n=0);var s,u=(s=function(r,t){for(var i=f.columns(c.group)-r,e=0;e<1e3;e++)for(var n=0;n<=i;n++)if(h(n,e,r,t))return d(n,e,r,t),{x:n,y:e}}(e,n),{top:f.py+s.y*f.sy+s.y*f.cy,left:f.px+s.x*f.sx+s.x*f.cx});r.css({left:u.left,top:u.top,width:f.sx*e+f.cx*(e-1),height:f.sy*n+f.cy*(n-1)}),0!==n&&r.addClass("visible")}),i.height=s.length?2*f.py+s.length*f.sy+(s.length-1)*f.cy:0,n=!1,r&&r()},25))}}]);
 angular.module("ui").directive("uiCardSize",["uiSizes",function(){return{restrict:"A",require:["^uiCardPanel","^?uiMasonry"],link:function(i,e,r,u){r.$observe("uiCardSize",function(){u[0].refreshLayout(function(){u[1]&&u[1].refreshLayout()})})}}}]);
@@ -603,6 +603,6 @@ function blockSort(n,t){return n.y<t.y?-1:n.y>t.y?1:n.x-t.x}function intersectBl
 var iconFontOddEven=!1;angular.module("ui").directive("uiIcon",function(){var o=/^https?:\/\//i,t=/^fa-/i,c=/^wi-/i,e=/^mi-/i,a=/^icofont-/i,r=/^iconify-/i;return{restrict:"E",templateUrl:"components/ui-icon/ui-icon.html",scope:{icon:"@"},link:function(n){n.$watch("icon",function(i){""!==i&&(t.test(i)?n.iconType="fa":c.test(i)?n.iconType="wi":e.test(i)?n.iconType="mi":a.test(i)?n.iconType="icofont":r.test(i)?(n.iconType=iconFontOddEven?"iconify":"iconify1",iconFontOddEven=!iconFontOddEven):o.test(i)?(n.iconType="image",n.url=i):n.iconType="angular-material")})}}});
 angular.module("ui").filter("chartGetRange",function(){return function(n,t){t=[parseFloat(t[0]),parseFloat(t[1])];var a=0<=Math.abs(t[0])?t[0]:d3.min(n,function(n){return d3.min(n.values,function(n){return n[1]})}),r=0<=Math.abs(t[1])?t[1]:d3.max(n,function(n){return d3.max(n.values,function(n){return n[1]})});return[Math.floor(a),Math.ceil(r)]}});
 angular.module("ui").filter("trusted",["$sce",function(u){return function(t){return u.trustAsHtml(t)}}]);
 angular.module("ui").filter("spaceToUnderscore",function(){return function(e){return e.replace(/ /g,"_")}}),angular.module("ui").filter("underscoreToSpace",function(){return function(e){return e.replace(/_/g," ")}});
 
-angular.module("ui").run(["$templateCache",function(e){e.put("logout.html",'<head></head> <body> <script src="js/app.min.js"><\/script> <script> for (var key in localStorage) {\n    if (localStorage.hasOwnProperty(key)) {\n        if (key.indexOf("nr-") === 0) {\n            localStorage.removeItem(key);\n        }\n    }\n}\n$.ajax({\n    type: "GET",\n    url: window.location.href,\n    async: true,\n    username: "some_non_user_name",\n    password: "a_not_valid_password"\n})\n.done(function() { alert(\'Error!\') })\n.fail(function() {\n    var url = window.location.href.split("logout")[0];\n    setTimeout(function() { window.location.href = url; }, 1000);\n}); <\/script> <style> div {\n    width: 400px;\n    height: 300px;\n    position: absolute;\n    top:0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    margin: auto;\n    font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n} </style> <div class="node-red-ui--notabs"> <table><tr><td><center><a href="./"><img src="icon120x120.png"></a></center></td></tr> <tr><td><center><h2>Welcome to the Node-RED Dashboard</h2></center></td></tr> <tr><td><center>Please <a href="./">sign in</a> to see your flow.</center></td></tr></table> </div> </body> '),e.put("partials/main.html",'<md-toolbar ng-show="main.hideToolbar !== true" id="toolbar"> <div class="md-toolbar-tools" id="nr-dashboard-toolbar"> <md-button ng-show="!(main.lockMenu != \'false\') && main.len > 1" ng-click="main.toggleSidenav()" class="md-icon-button" aria-label="menu button"> <ng-md-icon icon="menu"></ng-md-icon> </md-button> <h1 ng-show="main.len <= 1" style="width:30px"> </h1> <h1 ng-show="main.lockMenu != \'false\'" node-id="{{main.id}}">{{main.name}}</h1> <h1 ng-show="!(main.lockMenu != \'false\') && main.loaded" node-id="{{main.selectedTab.id}}">{{main.selectedTab.header || main.selectedTab.name}}</h1> </div> </md-toolbar> <section layout="row" flex> <md-sidenav ng-hide="main.len <= 1" class="md-sidenav-left" md-component-id="left" md-is-locked-open="(main.lockMenu != \'false\')"> <md-list> <md-list-item ng-repeat="obj in main.menu" ng-class="{\'nr-menu-item-active\':location.$$path==\'/\'+$index}" ng-disabled="obj.disabled" ng-if="!obj.hidden" ng-click="main.open(obj, $index)"> <ui-icon icon="{{obj.icon}}" style="margin:5px"></ui-icon> <p style="margin-right:12px; min-width:120px;" ng-show="(main.lockMenu != \'icon\')">{{main.getMenuName(obj)}}</p> </md-list-item> </md-list> </md-sidenav> <md-content flex> <div ui-masonry ng-show="main.selectedTab.header" id="{{\'Tab_\'+main.selectedTab.header | spaceToUnderscore}}"> <ui-card-panel node-id="{{group.header.id}}" ng-repeat="group in main.selectedTab.items" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}" ng-if="group.header && group.header.config && !group.header.config.hidden"> <ui-component ng-repeat="control in group.items" item="control"></ui-component> </ui-card-panel> </div> <div class="node-red-ui--inline-link" ng-show="!main.selectedTab.header"> <iframe class="iframe" ng-src="{{ main.selectedTab.link }}" allowfullscreen></iframe> \x3c!-- <div>The url {{ }} cannot be loaded into an iframe.</div> --\x3e </div> </md-content> </section> <div id="nr-dashboard-footer" layout="row"></div> '),e.put("partials/toast.html",'<md-toast layout="column" style="border:4px solid {{::toast.highlight}}; padding:0px; transition:border-color 0.1s;"> <div> <h3 ng-if="toast.title">{{::toast.title}}</h3> <h4 flex ng-bind-html="::toast.message | trusted"></h4> </div> </md-toast> '),e.put("components/ui-card-panel/ui-card-panel.html",'<div layout="column" class="nr-dashboard-cardpanel" ng-class="[group.header.config && group.header.config.className]" node-classname="{{group.header.config.className}}"> <p class="nr-dashboard-cardtitle" ng-style="{width:ctrl.width-12}" ng-if="group.header && group.header.config.disp && group.header[group.header.length-1]!=\'!\'">{{group.header.name}} <span ng-if="group.header.config.collapse" ng-model="collapsed" ng-click="collapseCard()" class="nr-dashboard-cardcarat"> <i ng-class="{ \'fa fa-caret-down\':collapsed, \'fa fa-caret-up\':!collapsed }"></i> </span> </p> <div class="nr-dashboard-cardcontainer" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}_cards" ng-transclude ng-style="{width:ctrl.width, height:ctrl.height}"></div> </div> '),e.put("components/ui-chart-js/ui-chart-js.html",'<div> <canvas ng-if="me.item.look===\'line\'" class="chart chart-line" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'bar\'" class="chart chart-bar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'horizontalBar\'" class="chart chart-horizontalBar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'pie\'" class="chart chart-pie" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'polar-area\'" class="chart chart-polar-area" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'radar\'" class="chart chart-radar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> </div> '),e.put("components/ui-gauge/ui-gauge.html","<div id=\"gauge_{{$id}}\" style=\"width:{{0.95 * me.item.width * me.item.sizes.sx - (20 * (me.item.gtype === 'compass')) }}px;\n    height:{{0.95 * (me.item.height * me.item.sizes.sy)+((me.item.title.length == 0) * me.item.sizes.sy) - (20 * (me.item.gtype === 'compass')) }}px;\n    margin-top:-20px;\n    padding-bottom:{{(me.item.gtype === 'wave') * 6}}px;\"> </div> "),e.put("components/ui-icon/ui-icon.html",'<ng-md-icon ng-if="iconType===\'angular-material\'" icon="{{icon}}"></ng-md-icon> <div ng-if="iconType===\'fa\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="fa fa-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'wi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="wi wi-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'mi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="material-icons" ng-class="icon">{{icon.substr(3)}}</i></div> <div ng-if="iconType===\'icofont\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="icofont icofont-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify1\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <img ng-if="iconType===\'image\'" ng-src="{{url}}" style="width:24px; display:block; margin:auto; line-height:initial;"> '),e.put("components/ui-component/templates/button.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-button" node-class="{{ me.item.className }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-button class="md-raised" ng-click="me.buttonClick($event)" ng-disabled="me.item.disabled" aria-label="{{\'button\' + me.item.label}}" ng-style="{\'background-color\':me.item.getText(), \'color\':me.item.getColor(), \'z-index\':1, \'padding\':\'0px\'}"> <ui-icon ng-show="me.item.icon.length" icon="{{me.item.getIcon()}}" ng-style="{color:me.item.getColor()}"> </ui-icon> <span ng-bind-html="me.item.getLabel()"></span> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> </md-button> </md-card> '),e.put("components/ui-component/templates/chart.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <div class="nr-dashboard-chart-container" style="width:100%; height:100%;"> <p class="label nr-dashboard-chart-title" ng-class="{\'nr-dashboard-chart-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()"> </p> <ui-chart-js class="nr-dashboard-chart" ng-class="{\'nr-dashboard-chart-nolabel\':me.item.getLabel() == \'\'}" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </ui-chart-js> <p class="blank-label" ng-if="config && config.nodata">{{ me.item.nodata }} </p> </div> </md-card> '),e.put("components/ui-component/templates/colour-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-colour-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p> <span ng-hide="(me.item.width < 2) || (me.item.width < 5 && (me.item.inline || me.item.textValue))" class="label" ng-bind-html="me.item.getLabel()"> </span> </p> <color-picker ng-model="me.item.value" aria-label="{{me.item.label}}" ng-attr-options="me.item.options" ng-attr-event-api="me.item.eventapi" ng-keypress="me.item.key($event)" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </color-picker> </md-card> '),e.put("components/ui-component/templates/date-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-date-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p class="nr-dashboard-date-picker-label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-datepicker class="nr-dashboard-date-picker" md-placeholder="{{me.item.getLabel()}}" md-open-on-focus ng-model="me.item.ddd" ng-blur="me.setDate()"> </md-datepicker> </md-input-container> </md-card> '),e.put("components/ui-component/templates/dropdown.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-dropdown" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p ng-if="me.item.width>1 && me.item.getLabel().length>0" class="label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-select ng-if="!me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation();" ng-click="$event.stopPropagation();" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> <md-select ng-if="me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" md-on-close="me.closed()" multiple="multiple" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-checkbox md-no-ink aria-label="Select all" ng-model="me.selectAll" ng-change="me.checkAll()" style="width:unset;"></md-checkbox> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation()" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> </md-input-container> </md-card> '),e.put("components/ui-component/templates/form.html",'<md-card ui-card-size="{{me.item.width}}x{{(me.item.height > me.item.rowCount ? me.item.height : me.item.rowCount )}}" layout="row" layout-align="space-between center" class="nr-dashboard-form" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <form name="form" ng-submit="me.submit(form)" style="margin-top:{{(me.item.label ? 0 : me.item.rowCount < 3 ? me.item.rowHeight/6 : me.item.rowHeight/2.5)}}px"> <p class="formlabel" style="margin-bottom:{{(me.item.rowHeight/9)}}px" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"></p> <div class="formElement" ng-class="{\'formElementSplit\':(me.item.splitLayout)}" layout-gt-sm="row" ng-repeat="opt in me.item.options track by $index"> <md-input-container class="md-block" style="height:{{(me.item.rowHeight * (opt.type==\'multiline\' ? opt.rows : 1)) }}px" flex> <label ng-if="(opt.type==\'text\' || opt.type==\'number\' || opt.type==\'email\' || opt.type==\'multiline\' || opt.type==\'password\' || opt.type==\'date\' || opt.type==\'time\') && opt.label">{{opt.label}}</label> <input ng-if="opt.type==\'text\' || opt.type==\'email\' || opt.type==\'password\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)"> <input ng-if="opt.type==\'date\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="yyyy-mm-dd"> <input ng-if="opt.type==\'time\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="HH:MM"> <input ng-if="opt.type==\'number\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" step="any"> <textarea ng-if="opt.type==\'multiline\'" md-no-autogrow ng-required="opt.required" ng-model="me.item.formValue[opt.value]" style="height:{{(opt.rows * me.item.sy) - 10}}px; padding:10px 2px 1px 0;"></textarea> <md-switch ng-if="opt.type==\'switch\'" md-no-ink ng-model="me.item.formValue[opt.value]">{{opt.label}}</md-switch> <md-checkbox ng-if="opt.type==\'checkbox\'" md-no-ink aria-label="Checkbox No Ink" ng-model="me.item.formValue[opt.value]"> {{opt.label}}</md-checkbox> </md-input-container> \x3c!-- <md-datepicker ng-if="opt.type==\'date\'" ng-model="me.item.formValue[opt.value]"></md-datepicker> --\x3e </div> <div class="form-control" ng-class="{\'form-control-single\':me.item.cancel == \'\',\'form-control-no-label\':me.item.label == \'\'}" style="margin-top:{{( me.item.label ==\'\' ? me.item.rowCount < 3 ? me.item.rowHeight * 0.4 : me.item.rowHeight * 0.2 : me.item.rowHeight * -0.1)}}px;"> <md-button class="md-raised nr-dashboard-form-button" type="submit" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px">{{me.item.submit}}</md-button> <md-button ng-if="me.item.cancel != \'\'" class="md-raised nr-dashboard-form-button" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px" ng-click="me.reset()">{{me.item.cancel}}</md-button> </div> </form> </md-card> cancel'),e.put("components/ui-component/templates/gauge.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label nr-dashboard-gauge-title" ng-class="{\'nr-dashboard-gauge-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()" ng-hide="(me.item.height <= 2)"> </p> <p ng-show="(me.item.height == 2)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titlem\':(me.item.height == 2)}"> </p> <p ng-show="(me.item.height == 1)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titles\':(me.item.height == 1)}"> </p> <ui-gauge style="text-align:center;" class="nr-dashboard-gauge"> </ui-gauge> </md-card> '),e.put("components/ui-component/templates/numeric.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-numeric" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <div layout="row" layout-align="center center"> <md-button class="md-icon-button down-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(-me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_more"></ui-icon> </md-button> <center> <p ng-if="(me.item.ed === false)" class="value" style="min-width:{{me.item.minWidth}}px;" ng-bind-html="me.item.getText()"> </p> <span ng-if="(me.item.ed === true)"> <span class="value" ng-bind-html="me.item.pre"></span> <input ng-model="me.item.value" ng-change="me.newValue()" class="value" ng-disabled="me.item.disabled" style="max-width:{{me.item.minWidth}}px;"> <span class="value" ng-bind-html="me.item.post"></span> </span> </center> <md-button class="md-icon-button up-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_less"></ui-icon> </md-button> </div> </md-card> '),e.put("components/ui-component/templates/slider.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-slider" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, {\'nr-dashboard-slider-v\':(me.item.width < me.item.height)}, me.item.className]" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" node-id="{{me.item.id}}"> <p ng-show="{{me.item.width >= me.item.height}}" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-slider ng-if="me.item.outs===\'all\'" flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.valueChanged(10)" ng-on-wheel="me.wheel($event)" style="z-index:1; touch-action:none; min-width:32px;" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <md-slider ng-if="me.item.outs===\'end\'" md-discrete flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.mchange()" ng-mouseup="me.mup()" ng-mouseleave="me.mleave()" ng-mouseenter="me.menter()" style="z-index:1; touch-action:none; min-width:32px;" ng-style="(me.item.width >= me.item.height) && {\'margin-top\':\'20px\'};" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <p ng-hide="{{me.item.width >= me.item.height}}" class="label-v" ng-bind-html="me.item.getLabel()"> </p> </md-card> '),e.put("components/ui-component/templates/spacer.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-spacer" ng-class="{\'nr-dashboard-disabled\':me.item.disabled}"> </md-card> '),e.put("components/ui-component/templates/switch.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-switch" ng-click="me.switchClick()" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p ng-if="me.item.label && (me.item.width !== 1)" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-switch ng-model="me.item.value" ng-change="me.item.value = !me.item.value" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" aria-label="{{me.item.label}}" ng-class="{\'center\' : !me.item.label}" ng-if="!me.item.oncolor || !me.item.onicon || !me.item.offcolor || !me.item.officon" style="z-index:1"> </md-switch> <ui-icon icon="{{me.item.onicon}}" ng-style="{color: me.item.oncolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': !me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> <ui-icon icon="{{me.item.officon}}" ng-style="{color:me.item.offcolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> </md-card> '),e.put("components/ui-component/templates/template.html",'<md-card ui-template="me.item.format" ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-template {{ me.item.class }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" ng-show="{{me.item.height >= 0}}" node-id="{{me.item.id}}"> </md-card> '),e.put("components/ui-component/templates/text-input-CR.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-keydown="me.keyPressed($event)" ng-blur="me.item.sendOnBlur ? me.keyPressed($event) : false" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text-input.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-change="me.valueChanged({{me.item.delay}})" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" ng-style="(me.item.mode===\'color\') && {\'padding-left\':\'25%\'}" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-text" ng-class="[ me.item.safeLabel, {\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"></p> <p class="value" ng-bind-html="me.item.getText()"></p> </md-card> ')}]);
+angular.module("ui").run(["$templateCache",function(e){e.put("logout.html",'<head></head> <body> <script src="js/app.min.js"><\/script> <script> for (var key in localStorage) {\n    if (localStorage.hasOwnProperty(key)) {\n        if (key.indexOf("nr-") === 0) {\n            localStorage.removeItem(key);\n        }\n    }\n}\n$.ajax({\n    type: "GET",\n    url: window.location.href,\n    async: true,\n    username: "some_non_user_name",\n    password: "a_not_valid_password"\n})\n.done(function() { alert(\'Error!\') })\n.fail(function() {\n    var url = window.location.href.split("logout")[0];\n    setTimeout(function() { window.location.href = url; }, 1000);\n}); <\/script> <style> div {\n    width: 400px;\n    height: 300px;\n    position: absolute;\n    top:0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    margin: auto;\n    font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n} </style> <div class="node-red-ui--notabs"> <table><tr><td><center><a href="./"><img src="icon120x120.png"></a></center></td></tr> <tr><td><center><h2>Welcome to the Node-RED Dashboard</h2></center></td></tr> <tr><td><center>Please <a href="./">sign in</a> to see your flow.</center></td></tr></table> </div> </body> '),e.put("partials/main.html",'<md-toolbar ng-show="main.hideToolbar !== true" id="toolbar"> <div class="md-toolbar-tools" id="nr-dashboard-toolbar"> <md-button ng-show="!(main.lockMenu != \'false\') && main.len > 1" ng-click="main.toggleSidenav()" class="md-icon-button" aria-label="menu button"> <ng-md-icon icon="menu"></ng-md-icon> </md-button> <h1 ng-show="main.len <= 1" style="width:30px"> </h1> <h1 ng-show="main.lockMenu != \'false\'" node-id="{{main.id}}">{{main.name}}</h1> <h1 ng-show="!(main.lockMenu != \'false\') && main.loaded" node-id="{{main.selectedTab.id}}">{{main.selectedTab.header || main.selectedTab.name}}</h1> </div> </md-toolbar> <section layout="row" flex> <md-sidenav ng-hide="main.len <= 1" class="md-sidenav-left" md-component-id="left" md-is-locked-open="(main.lockMenu != \'false\')"> <md-list> <md-list-item ng-repeat="obj in main.menu" ng-class="{\'nr-menu-item-active\':location.$$path==\'/\'+$index}" ng-disabled="obj.disabled" ng-if="!obj.hidden" ng-click="main.open(obj, $index)"> <ui-icon icon="{{obj.icon}}" style="margin:5px"></ui-icon> <p style="margin-right:12px; min-width:120px;" ng-show="(main.lockMenu != \'icon\')">{{main.getMenuName(obj)}}</p> </md-list-item> </md-list> </md-sidenav> <md-content flex> <div ui-masonry ng-show="main.selectedTab.header" id="{{\'Tab_\'+main.selectedTab.header | spaceToUnderscore}}"> <ui-card-panel node-id="{{group.header.id}}" ng-repeat="group in main.selectedTab.items" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}" ng-if="group.header && group.header.config && !group.header.config.hidden"> <ui-component ng-repeat="control in group.items" item="control"></ui-component> </ui-card-panel> </div> <div class="node-red-ui--inline-link" ng-show="!main.selectedTab.header"> <iframe class="iframe" ng-src="{{ main.selectedTab.link }}" allowfullscreen></iframe> \x3c!-- <div>The url {{ }} cannot be loaded into an iframe.</div> --\x3e </div> </md-content> </section> <div id="nr-dashboard-footer" layout="row"></div> '),e.put("partials/toast.html",'<md-toast layout="column" style="border:4px solid {{::toast.highlight}}; padding:0px; transition:border-color 0.1s;"> <div> <h3 ng-if="toast.title">{{::toast.title}}</h3> <h4 flex ng-bind-html="::toast.message | trusted"></h4> </div> </md-toast> '),e.put("components/ui-card-panel/ui-card-panel.html",'<div layout="column" class="nr-dashboard-cardpanel" ng-class="[group.header.config && group.header.config.className]" node-classname="{{group.header.config.className}}"> <p class="nr-dashboard-cardtitle" ng-style="{width:ctrl.width-12}" ng-if="group.header && group.header.config.disp && group.header[group.header.length-1]!=\'!\'">{{group.header.name}} <span ng-if="group.header.config.collapse" ng-model="collapsed" ng-click="collapseCard()" class="nr-dashboard-cardcarat"> <i ng-class="{ \'fa fa-caret-down\':collapsed, \'fa fa-caret-up\':!collapsed }"></i> </span> </p> <div class="nr-dashboard-cardcontainer" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}_cards" ng-transclude ng-style="{width:ctrl.width, height:ctrl.height}"></div> </div> '),e.put("components/ui-chart-js/ui-chart-js.html",'<div> <canvas ng-if="me.item.look===\'line\'" class="chart chart-line" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'bar\'" class="chart chart-bar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'horizontalBar\'" class="chart chart-horizontalBar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'pie\'" class="chart chart-pie" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'polar-area\'" class="chart chart-polar-area" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'radar\'" class="chart chart-radar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> </div> '),e.put("components/ui-gauge/ui-gauge.html","<div id=\"gauge_{{$id}}\" style=\"width:{{0.95 * me.item.width * me.item.sizes.sx - (20 * (me.item.gtype === 'compass')) }}px;\n    height:{{0.95 * (me.item.height * me.item.sizes.sy)+((me.item.title.length == 0) * me.item.sizes.sy) - (20 * (me.item.gtype === 'compass')) }}px;\n    margin-top:-20px;\n    padding-bottom:{{(me.item.gtype === 'wave') * 6}}px;\"> </div> "),e.put("components/ui-icon/ui-icon.html",'<ng-md-icon ng-if="iconType===\'angular-material\'" icon="{{icon}}"></ng-md-icon> <div ng-if="iconType===\'fa\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="fa fa-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'wi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="wi wi-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'mi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="material-icons" ng-class="icon">{{icon.substr(3)}}</i></div> <div ng-if="iconType===\'icofont\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="icofont icofont-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify1\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <img ng-if="iconType===\'image\'" ng-src="{{url}}" style="width:24px; display:block; margin:auto; line-height:initial;"> '),e.put("components/ui-component/templates/button.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-button" node-class="{{ me.item.className }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-button class="md-raised" ng-click="me.buttonClick($event)" ng-disabled="me.item.disabled" aria-label="{{\'button\' + me.item.label}}" ng-style="{\'background-color\':me.item.getText(), \'color\':me.item.getColor(), \'z-index\':1, \'padding\':\'0px\'}"> <ui-icon ng-show="me.item.icon.length" icon="{{me.item.getIcon()}}" ng-style="{color:me.item.getColor()}"> </ui-icon> <span ng-bind-html="me.item.getLabel()"></span> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> </md-button> </md-card> '),e.put("components/ui-component/templates/chart.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <div class="nr-dashboard-chart-container" style="width:100%; height:100%;"> <p class="label nr-dashboard-chart-title" ng-class="{\'nr-dashboard-chart-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()"> </p> <ui-chart-js class="nr-dashboard-chart" ng-class="{\'nr-dashboard-chart-nolabel\':me.item.getLabel() == \'\'}" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </ui-chart-js> <p class="blank-label" ng-if="config && config.nodata">{{ me.item.nodata }} </p> </div> </md-card> '),e.put("components/ui-component/templates/colour-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-colour-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p> <span ng-hide="(me.item.width < 2) || (me.item.width < 5 && (me.item.inline || me.item.textValue))" class="label" ng-bind-html="me.item.getLabel()"> </span> </p> <color-picker ng-model="me.item.value" aria-label="{{me.item.label}}" ng-attr-options="me.item.options" ng-attr-event-api="me.item.eventapi" ng-keypress="me.item.key($event)" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </color-picker> </md-card> '),e.put("components/ui-component/templates/date-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-date-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p class="nr-dashboard-date-picker-label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-datepicker class="nr-dashboard-date-picker" md-placeholder="{{me.item.getLabel()}}" md-open-on-focus ng-model="me.item.ddd" ng-blur="me.setDate()"> </md-datepicker> </md-input-container> </md-card> '),e.put("components/ui-component/templates/dropdown.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-dropdown" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p ng-if="me.item.width>1 && me.item.getLabel().length>0" class="label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-select ng-if="!me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation();" ng-click="$event.stopPropagation();" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> <md-select ng-if="me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" md-on-close="me.closed()" multiple="multiple" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-checkbox md-no-ink aria-label="Select all" ng-model="me.selectAll" ng-change="me.checkAll()" style="width:unset;"></md-checkbox> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation()" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> </md-input-container> </md-card> '),e.put("components/ui-component/templates/form.html",'<md-card ui-card-size="{{me.item.width}}x{{(me.item.height > me.item.rowCount ? me.item.height : me.item.rowCount )}}" layout="row" layout-align="space-between center" class="nr-dashboard-form" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <form name="form" ng-submit="me.submit(form)" style="margin-top:{{(me.item.label ? 0 : me.item.rowCount < 3 ? me.item.rowHeight/6 : me.item.rowHeight/2.5)}}px"> <p class="formlabel" style="margin-bottom:{{(me.item.rowHeight/9)}}px" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"></p> <div class="formElement" ng-class="{\'formElementSplit\':(me.item.splitLayout)}" layout-gt-sm="row" ng-repeat="opt in me.item.options track by $index"> <md-input-container class="md-block" style="height:{{(me.item.rowHeight * (opt.type==\'multiline\' ? opt.rows : 1)) }}px" flex> <label ng-if="(opt.type==\'text\' || opt.type==\'number\' || opt.type==\'email\' || opt.type==\'multiline\' || opt.type==\'password\' || opt.type==\'date\' || opt.type==\'time\') && opt.label">{{opt.label}}</label> <input ng-if="opt.type==\'text\' || opt.type==\'email\' || opt.type==\'password\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)"> <input ng-if="opt.type==\'date\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="yyyy-mm-dd"> <input ng-if="opt.type==\'time\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="HH:MM"> <input ng-if="opt.type==\'number\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" step="any"> <textarea ng-if="opt.type==\'multiline\'" md-no-autogrow ng-required="opt.required" ng-model="me.item.formValue[opt.value]" style="height:{{(opt.rows * me.item.sy) - 10}}px; padding:10px 2px 1px 0;"></textarea> <md-switch ng-if="opt.type==\'switch\'" md-no-ink ng-model="me.item.formValue[opt.value]">{{opt.label}}</md-switch> <md-checkbox ng-if="opt.type==\'checkbox\'" md-no-ink aria-label="Checkbox No Ink" ng-model="me.item.formValue[opt.value]"> {{opt.label}}</md-checkbox> </md-input-container> \x3c!-- <md-datepicker ng-if="opt.type==\'date\'" ng-model="me.item.formValue[opt.value]"></md-datepicker> --\x3e </div> <div class="form-control" ng-class="{\'form-control-single\':me.item.cancel == \'\',\'form-control-no-label\':me.item.label == \'\'}" style="margin-top:{{( me.item.label ==\'\' ? me.item.rowCount < 3 ? me.item.rowHeight * 0.4 : me.item.rowHeight * 0.2 : me.item.rowHeight * -0.1)}}px;"> <md-button class="md-raised nr-dashboard-form-button" type="submit" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px">{{me.item.submit}}</md-button> <md-button ng-if="me.item.cancel != \'\'" class="md-raised nr-dashboard-form-button" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px" ng-click="me.reset()">{{me.item.cancel}}</md-button> </div> </form> </md-card> cancel'),e.put("components/ui-component/templates/gauge.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label nr-dashboard-gauge-title" ng-class="{\'nr-dashboard-gauge-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()" ng-hide="(me.item.height <= 2)"> </p> <p ng-show="(me.item.height == 2)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titlem\':(me.item.height == 2)}"> </p> <p ng-show="(me.item.height == 1)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titles\':(me.item.height == 1)}"> </p> <ui-gauge style="text-align:center;" class="nr-dashboard-gauge"> </ui-gauge> </md-card> '),e.put("components/ui-component/templates/numeric.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-numeric" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <div layout="row" layout-align="center center"> <md-button class="md-icon-button down-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(-me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_more"></ui-icon> </md-button> <center> <p ng-if="(me.item.ed === false)" class="value" style="min-width:{{me.item.minWidth}}px;" ng-bind-html="me.item.getText()"> </p> <span ng-if="(me.item.ed === true)"> <span class="value" ng-bind-html="me.item.pre"></span> <input ng-model="me.item.value" ng-change="me.newValue()" class="value" ng-disabled="me.item.disabled" style="max-width:{{me.item.minWidth}}px;"> <span class="value" ng-bind-html="me.item.post"></span> </span> </center> <md-button class="md-icon-button up-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_less"></ui-icon> </md-button> </div> </md-card> '),e.put("components/ui-component/templates/slider.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-slider" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, {\'nr-dashboard-slider-v\':(me.item.width < me.item.height)}, me.item.className]" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" node-id="{{me.item.id}}"> <p ng-show="{{me.item.width >= me.item.height}}" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-slider ng-if="me.item.outs===\'all\'" flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.valueChanged(10)" ng-on-wheel="me.wheel($event)" style="z-index:1; touch-action:none; min-width:32px;" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <md-slider ng-if="me.item.outs===\'end\'" md-discrete flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.mchange()" ng-mouseup="me.mup()" ng-mouseleave="me.mleave()" ng-mouseenter="me.menter()" style="z-index:1; touch-action:none; min-width:32px;" ng-style="(me.item.width >= me.item.height) && {\'margin-top\':\'20px\'};" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <p ng-hide="{{me.item.width >= me.item.height}}" class="label-v" ng-bind-html="me.item.getLabel()"> </p> </md-card> '),e.put("components/ui-component/templates/spacer.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-spacer" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]"> </md-card> '),e.put("components/ui-component/templates/switch.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-switch" ng-click="me.switchClick()" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p ng-if="me.item.label && (me.item.width !== 1)" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-switch ng-model="me.item.value" ng-change="me.item.value = !me.item.value" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" aria-label="{{me.item.label}}" ng-class="{\'center\' : !me.item.label}" ng-if="!me.item.oncolor || !me.item.onicon || !me.item.offcolor || !me.item.officon" style="z-index:1"> </md-switch> <ui-icon icon="{{me.item.onicon}}" ng-style="{color: me.item.oncolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': !me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> <ui-icon icon="{{me.item.officon}}" ng-style="{color:me.item.offcolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> </md-card> '),e.put("components/ui-component/templates/template.html",'<md-card ui-template="me.item.format" ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-template {{ me.item.class }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" ng-show="{{me.item.height >= 0}}" node-id="{{me.item.id}}"> </md-card> '),e.put("components/ui-component/templates/text-input-CR.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-keydown="me.keyPressed($event)" ng-blur="me.item.sendOnBlur ? me.keyPressed($event) : false" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text-input.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-change="me.valueChanged({{me.item.delay}})" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" ng-style="(me.item.mode===\'color\') && {\'padding-left\':\'25%\'}" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-text" ng-class="[ me.item.safeLabel, {\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"></p> <p class="value" ng-bind-html="me.item.getText()"></p> </md-card> ')}]);
diff --git a/package.json b/package.json
index ef1ea1d..ca5bd46 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
     "name": "node-red-dashboard",
-    "version": "3.1.8",
+    "version": "3.1.9",
     "description": "A set of dashboard nodes for Node-RED",
     "keywords": [
         "node-red"
     ],
     "scripts": {
diff --git a/src/components/ui-component/ui-component-ctrl.js b/src/components/ui-component/ui-component-ctrl.js
index d7c2f8f..4fbcd09 100644
--- a/src/components/ui-component/ui-component-ctrl.js
+++ b/src/components/ui-component/ui-component-ctrl.js
@@ -10,32 +10,62 @@ angular.module('ui').controller('uiComponentController', ['$scope', 'UiEvents',
     function ($scope, events, $interpolate, $interval) {
         this.$onInit = function() {
             var me = this;
 
             if (typeof me.item.format === "string") {
-                me.item.getText = $interpolate(me.item.format).bind(null, me.item);
+                if (me.item.format.indexOf("constructor") === -1) {
+                    me.item.getText = $interpolate(me.item.format).bind(null, me.item);
+                }
+                else {
+                    me.item.getText = function() { return me.item.format };
+                }
             }
 
             if (typeof me.item.label === "string") {
-                me.item.getLabel = $interpolate(me.item.label).bind(null, me.item);
-                me.item.safeLabel = "nr-dashboard-widget-" + (me.item.label).replace(/\W/g,'_');
+                if (me.item.label.indexOf("constructor") === -1) {
+                    me.item.getLabel = $interpolate(me.item.label).bind(null, me.item);
+                    me.item.safeLabel = "nr-dashboard-widget-" + (me.item.label).replace(/\W/g,'_');
+                }
+                else {
+                    me.item.getText = function() { return me.item.label };
+                }
             }
 
             if (typeof me.item.tooltip === "string") {
-                me.item.getTooltip = $interpolate(me.item.tooltip).bind(null, me.item);
+                if (me.item.tooltip.indexOf("constructor") === -1) {
+                    me.item.getTooltip = $interpolate(me.item.tooltip).bind(null, me.item);
+                }
+                else {
+                    me.item.getText = function() { return me.item.tooltip };
+                }
             }
 
             if (typeof me.item.color === "string") {
-                me.item.getColor = $interpolate(me.item.color).bind(null, me.item);
+                if (me.item.color.indexOf("constructor") === -1) {
+                    me.item.getColor = $interpolate(me.item.color).bind(null, me.item);
+                }
+                else {
+                    me.item.getText = function() { return me.item.color };
+                }
             }
 
             if (typeof me.item.icon === "string") {
-                me.item.getIcon = $interpolate(me.item.icon).bind(null, me.item);
+                if (me.item.icon.indexOf("constructor") === -1) {
+                    me.item.getIcon = $interpolate(me.item.icon).bind(null, me.item);
+                }
+                else {
+                    me.item.getText = function() { return me.item.icon };
+                }
             }
 
             if (typeof me.item.units === "string") {
-                me.item.getUnits = $interpolate(me.item.units).bind(null, me.item);
+                if (me.item.units.indexOf("constructor") === -1) {
+                    me.item.getUnits = $interpolate(me.item.units).bind(null, me.item);
+                }
+                else {
+                    me.item.getText = function() { return me.item.units };
+                }
             }
 
             me.init = function () {
                 switch (me.item.type) {
                     case 'button': {

Vulnerable code: # Time: Wed May 25 2022 11:23:30 GMT+0100 (British Summer Time)
# hash: 22f744c7102e4eb0375d482c7bd34ac0d407159d34773e84e1f5087d0b6444d3
angular.module("ui").controller("uiComponentController",["$scope","UiEvents","$interpolate","$interval",function(l,u,e,r){this.$onInit=function(){var i,m=this;"string"==typeof m.item.format&&(m.item.getText=e(m.item.format).bind(null,m.item)),"string"==typeof m.item.label&&(m.item.getLabel=e(m.item.label).bind(null,m.item),m.item.safeLabel="nr-dashboard-widget-"+m.item.label.replace(/\W/g,"_")),"string"==typeof m.item.tooltip&&(m.item.getTooltip=e(m.item.tooltip).bind(null,m.item)),"string"==typeof m.item.color&&(m.item.getColor=e(m.item.color).bind(null,m.item)),"string"==typeof m.item.icon&&(m.item.getIcon=e(m.item.icon).bind(null,m.item)),"string"==typeof m.item.units&&(m.item.getUnits=e(m.item.units).bind(null,m.item)),m.init=function(){switch(m.item.type){case"button":m.buttonClick=function(e){n({id:m.item.id,value:m.item.value,event:{clientX:e.originalEvent.clientX,clientY:e.originalEvent.clientY,bbox:[e.originalEvent.clientX-e.originalEvent.layerX,e.originalEvent.clientY-e.originalEvent.layerY+e.currentTarget.clientHeight,e.originalEvent.clientX-e.originalEvent.layerX+e.currentTarget.clientWidth,e.originalEvent.clientY-e.originalEvent.layerY]}},0)};break;case"switch":m.switchClick=function(){n({id:m.item.id,value:!m.item.value},0)};break;case"dropdown":m.searchTerm="",m.selectAll=!1,m.changed=!1,m.itemChanged=function(){m.searchTerm="",m.item.multiple?m.changed=!0:m.valueChanged(0)},m.checkAll=function(){var e=m.item.options.filter(function(e){return e.label.toLowerCase().includes(m.searchTerm.toLowerCase())});m.item.value=m.selectAll?e.map(function(e){return e.value}):[],m.valueChanged(0)},m.closed=function(){m.changed&&(m.changed=!1,m.valueChanged(0))},(m.item.me=m).processInput=function(e){o(e)};break;case"numeric":var i=function(e){m.item.value=parseFloat(m.item.value),isNaN(m.item.value)&&(m.item.value=m.item.min),0<e?(m.item.value==m.item.max&&1==m.item.wrap?m.item.value=m.item.min:m.item.value<m.item.max&&(m.item.value=Math.round(1e4*Math.min(m.item.value+e,m.item.max))/1e4),m.item.value<m.item.min&&(m.item.value=m.item.min)):e<0&&(m.item.value==m.item.min&&1==m.item.wrap?m.item.value=m.item.max:m.item.value>m.item.min&&(m.item.value=Math.round(1e4*Math.max(m.item.value+e,m.item.min))/1e4),m.item.value>m.item.max&&(m.item.value=m.item.max))},e=9.5*(Math.round(1e4*(m.item.min+m.item.step))/1e4).toString().length,t=9.5*(Math.round(1e4*(m.item.max+m.item.step))/1e4).toString().length;m.item.minWidth=t<e?e:t;var a=null;m.newValue=function(){isNaN(parseFloat(m.item.value))||(m.item.value<m.item.min&&(m.item.value=m.item.min),m.item.value>m.item.max&&(m.item.value=m.item.max),u.emit({id:m.item.id,value:m.item.value}))},m.periodicChange=function(e){i(e);var t=0;a=r(function(){75<++t?i(250*e):50<t?i(50*e):35<t?i(10*e):25<t?i(2*e):15<t?i(e):5<t&&t%2&&i(e)},100)},m.stopPeriodic=function(){a&&(r.cancel(a),a=null,m.valueChanged(0))};break;case"chart":m.item.theme=l.main.selectedTab.theme;break;case"colour-picker":(m.item.width<4||!m.item.showValue&&!m.item.showPicker)&&(m.item.showPicker=!1,m.item.showValue=!1,m.item.showSwatch=!0),m.item.showPicker&&m.item.height<4&&(m.item.height=m.item.showSwatch||m.item.showValue?4:3),m.item.options={format:m.item.format,inline:m.item.showPicker,hue:m.item.showHue,alpha:m.item.showAlpha,lightness:m.item.showLightness,swatch:m.item.showSwatch,swatchOnly:m.item.width<2||!m.item.showValue,swatchPos:"right",pos:"bottom right",case:"lower",round:!m.item.square,pickerOnly:m.item.showPicker&&!(m.item.showSwatch||m.item.showValue)},m.item.key=function(e){13!==e.charCode&&13!==e.which&&9!==e.charCode&&9!==e.which||(u.emit({id:m.item.id,value:m.item.value}),m.api&&m.api.close())},m.item.eventapi={onChange:function(e,t,i){void 0!==i&&m.valueChanged(0)},onOpen:function(e,t){m.api=e}},l.$watch("me.item.value",function(){m.item.oldValue||(m.item.oldValue=m.item.value),"true"===m.item.dynOutput&&m.item.value!==m.item.oldValue&&(m.item.oldValue=m.item.value,m.valueChanged(20))});break;case"text-input":case"text-input-CR":-1!=m.item.mode.indexOf("time")&&(m.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=e.value.match(/^(\d\d):(\d\d)/);if(null==i){var a=Date.parse(e.value);isNaN(a)&&(a=Date.now()),t=new Date(a)}else t=new Date("1970-01-01 "+i[1]+":"+i[2]+":00Z")}t.setMilliseconds(0),t.setSeconds(0),e.value=t,m.item.value=e.value},m.item.me=m),"week"!==m.item.mode&&"month"!==m.item.mode||(m.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=Date.parse(e.value);isNaN(i)&&(i=Date.now()),t=new Date(i)}t.setMilliseconds(0),t.setSeconds(0),e.value=t,m.item.value=e.value},m.item.me=m);break;case"date-picker":void 0!==m.item.ddd&&("number"!=typeof m.item.ddd&&"string"!=typeof m.item.ddd||(m.item.ddd=new Date(m.item.ddd))),m.processInput=function(e){e.value=new Date(e.value),m.item.ddd=e.value},m.setDate=function(){m.item.value=m.item.ddd,m.valueChanged(0)},m.item.me=m;break;case"form":m.processInput=function(e){if("object"==typeof e.value)for(var t in e.value)if(m.item.formValue.hasOwnProperty(t))for(var i in m.item.options)"date"!==m.item.options[i].type&&"time"!==m.item.options[i].type||m.item.options[i].value!==t||(e.value[t]=new Date(e.value[t])),m.item.formValue[t]=e.value[t]},m.item.extraRows=0,m.item.options.map(function(e){"multiline"==e.type&&1<e.rows&&(m.item.extraRows+=e.rows-1)}),m.item.rowCount=1==m.item.splitLayout?Math.ceil(m.item.options.length/2):m.item.options.length,m.item.rowCount+=""==m.item.label?1:2,m.item.rowCount+=m.item.extraRows,m.item.rowHeight=((m.item.rowCount-1)*m.item.sy+(""==m.item.label?.3*m.item.sy:1.2*m.item.sy)+(m.item.rowCount-1)*m.item.cy)/m.item.rowCount,m.stop=function(e){13!==e.charCode&&13!==e.which||(e.preventDefault(),e.stopPropagation())},m.submit=function(){m.item.value=JSON.parse(JSON.stringify(m.item.formValue)),m.valueChanged(0),m.reset()},m.reset=function(){for(var e in m.item.options)"checkbox"===m.item.options[e].type||"switch"===m.item.options[e].type?m.item.formValue[m.item.options[e].value]=!1:m.item.formValue[m.item.options[e].value]="";l.$$childTail.form.$setUntouched(),l.$$childTail.form.$setPristine()},m.item.me=m;break;case"template":m.setFormat=function(e){m.item.format=e},void 0!==m.item.msg&&void 0!==m.item.msg.template&&m.setFormat(m.item.msg.template);break;case"slider":m.wheel=function(e){e.preventDefault(),0<e.originalEvent.deltaY&&(m.item.value+=m.item.step,m.item.value>m.item.max&&(m.item.value=m.item.max)),e.originalEvent.deltaY<0&&(m.item.value-=m.item.step,m.item.value<m.item.min&&(m.item.value=m.item.min)),m.valueChanged(0)},m.active=!1,m.mdown=function(){m.active=!0},m.menter=function(){m.active=!0},m.mleave=function(){m.active=!1},m.mchange=function(){m.active=!1,m.valueChanged(0)},m.mup=function(){m.active&&(m.active=!1,m.valueChanged(0))}}},m.valueChanged=function(e){n({id:m.item.id,value:m.item.value},"number"==typeof e?e:10)},m.keyPressed=function(e){13===e.charCode||13===e.which?(u.emit({id:m.item.id,value:m.item.value}),m.lastItemSent=m.item.value):"blur"===e.type&&m.item.value!==m.lastItemSent&&(u.emit({id:m.item.id,value:m.item.value}),m.lastItemSent=m.item.value)};var n=function(e,t){0!==t?(i&&clearTimeout(i),i=setTimeout(function(){i=void 0,u.emit(e)},t)):u.emit(e)},o=function(e){e&&e.isOptionsValid&&(m.item.options=e.newOptions,delete m.item.isOptionsValid,delete m.item.newOptions)}}}]);
angular.module("ui").run(["$templateCache",function(e){e.put("logout.html",'<head></head> <body> <script src="js/app.min.js"><\/script> <script> for (var key in localStorage) {\n    if (localStorage.hasOwnProperty(key)) {\n        if (key.indexOf("nr-") === 0) {\n            localStorage.removeItem(key);\n        }\n    }\n}\n$.ajax({\n    type: "GET",\n    url: window.location.href,\n    async: true,\n    username: "some_non_user_name",\n    password: "a_not_valid_password"\n})\n.done(function() { alert(\'Error!\') })\n.fail(function() {\n    var url = window.location.href.split("logout")[0];\n    setTimeout(function() { window.location.href = url; }, 1000);\n}); <\/script> <style> div {\n    width: 400px;\n    height: 300px;\n    position: absolute;\n    top:0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    margin: auto;\n    font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n} </style> <div class="node-red-ui--notabs"> <table><tr><td><center><a href="./"><img src="icon120x120.png"></a></center></td></tr> <tr><td><center><h2>Welcome to the Node-RED Dashboard</h2></center></td></tr> <tr><td><center>Please <a href="./">sign in</a> to see your flow.</center></td></tr></table> </div> </body> '),e.put("partials/main.html",'<md-toolbar ng-show="main.hideToolbar !== true" id="toolbar"> <div class="md-toolbar-tools" id="nr-dashboard-toolbar"> <md-button ng-show="!(main.lockMenu != \'false\') && main.len > 1" ng-click="main.toggleSidenav()" class="md-icon-button" aria-label="menu button"> <ng-md-icon icon="menu"></ng-md-icon> </md-button> <h1 ng-show="main.len <= 1" style="width:30px"> </h1> <h1 ng-show="main.lockMenu != \'false\'" node-id="{{main.id}}">{{main.name}}</h1> <h1 ng-show="!(main.lockMenu != \'false\') && main.loaded" node-id="{{main.selectedTab.id}}">{{main.selectedTab.header || main.selectedTab.name}}</h1> </div> </md-toolbar> <section layout="row" flex> <md-sidenav ng-hide="main.len <= 1" class="md-sidenav-left" md-component-id="left" md-is-locked-open="(main.lockMenu != \'false\')"> <md-list> <md-list-item ng-repeat="obj in main.menu" ng-class="{\'nr-menu-item-active\':location.$$path==\'/\'+$index}" ng-disabled="obj.disabled" ng-if="!obj.hidden" ng-click="main.open(obj, $index)"> <ui-icon icon="{{obj.icon}}" style="margin:5px"></ui-icon> <p style="margin-right:12px; min-width:120px;" ng-show="(main.lockMenu != \'icon\')">{{main.getMenuName(obj)}}</p> </md-list-item> </md-list> </md-sidenav> <md-content flex> <div ui-masonry ng-show="main.selectedTab.header" id="{{\'Tab_\'+main.selectedTab.header | spaceToUnderscore}}"> <ui-card-panel node-id="{{group.header.id}}" ng-repeat="group in main.selectedTab.items" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}" ng-if="group.header && group.header.config && !group.header.config.hidden"> <ui-component ng-repeat="control in group.items" item="control"></ui-component> </ui-card-panel> </div> <div class="node-red-ui--inline-link" ng-show="!main.selectedTab.header"> <iframe class="iframe" ng-src="{{ main.selectedTab.link }}" allowfullscreen></iframe> \x3c!-- <div>The url {{ }} cannot be loaded into an iframe.</div> --\x3e </div> </md-content> </section> <div id="nr-dashboard-footer" layout="row"></div> '),e.put("partials/toast.html",'<md-toast layout="column" style="border:4px solid {{::toast.highlight}}; padding:0px; transition:border-color 0.1s;"> <div> <h3 ng-if="toast.title">{{::toast.title}}</h3> <h4 flex ng-bind-html="::toast.message | trusted"></h4> </div> </md-toast> '),e.put("components/ui-card-panel/ui-card-panel.html",'<div layout="column" class="nr-dashboard-cardpanel" ng-class="[group.header.config && group.header.config.className]" node-classname="{{group.header.config.className}}"> <p class="nr-dashboard-cardtitle" ng-style="{width:ctrl.width-12}" ng-if="group.header && group.header.config.disp && group.header[group.header.length-1]!=\'!\'">{{group.header.name}} <span ng-if="group.header.config.collapse" ng-model="collapsed" ng-click="collapseCard()" class="nr-dashboard-cardcarat"> <i ng-class="{ \'fa fa-caret-down\':collapsed, \'fa fa-caret-up\':!collapsed }"></i> </span> </p> <div class="nr-dashboard-cardcontainer" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}_cards" ng-transclude ng-style="{width:ctrl.width, height:ctrl.height}"></div> </div> '),e.put("components/ui-chart-js/ui-chart-js.html",'<div> <canvas ng-if="me.item.look===\'line\'" class="chart chart-line" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'bar\'" class="chart chart-bar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'horizontalBar\'" class="chart chart-horizontalBar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'pie\'" class="chart chart-pie" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'polar-area\'" class="chart chart-polar-area" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'radar\'" class="chart chart-radar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> </div> '),e.put("components/ui-gauge/ui-gauge.html","<div id=\"gauge_{{$id}}\" style=\"width:{{0.95 * me.item.width * me.item.sizes.sx - (20 * (me.item.gtype === 'compass')) }}px;\n    height:{{0.95 * (me.item.height * me.item.sizes.sy)+((me.item.title.length == 0) * me.item.sizes.sy) - (20 * (me.item.gtype === 'compass')) }}px;\n    margin-top:-20px;\n    padding-bottom:{{(me.item.gtype === 'wave') * 6}}px;\"> </div> "),e.put("components/ui-icon/ui-icon.html",'<ng-md-icon ng-if="iconType===\'angular-material\'" icon="{{icon}}"></ng-md-icon> <div ng-if="iconType===\'fa\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="fa fa-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'wi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="wi wi-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'mi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="material-icons" ng-class="icon">{{icon.substr(3)}}</i></div> <div ng-if="iconType===\'icofont\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="icofont icofont-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify1\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <img ng-if="iconType===\'image\'" ng-src="{{url}}" style="width:24px; display:block; margin:auto; line-height:initial;"> '),e.put("components/ui-component/templates/button.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-button" node-class="{{ me.item.className }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-button class="md-raised" ng-click="me.buttonClick($event)" ng-disabled="me.item.disabled" aria-label="{{\'button\' + me.item.label}}" ng-style="{\'background-color\':me.item.getText(), \'color\':me.item.getColor(), \'z-index\':1, \'padding\':\'0px\'}"> <ui-icon ng-show="me.item.icon.length" icon="{{me.item.getIcon()}}" ng-style="{color:me.item.getColor()}"> </ui-icon> <span ng-bind-html="me.item.getLabel()"></span> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> </md-button> </md-card> '),e.put("components/ui-component/templates/chart.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <div class="nr-dashboard-chart-container" style="width:100%; height:100%;"> <p class="label nr-dashboard-chart-title" ng-class="{\'nr-dashboard-chart-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()"> </p> <ui-chart-js class="nr-dashboard-chart" ng-class="{\'nr-dashboard-chart-nolabel\':me.item.getLabel() == \'\'}" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </ui-chart-js> <p class="blank-label" ng-if="config && config.nodata">{{ me.item.nodata }} </p> </div> </md-card> '),e.put("components/ui-component/templates/colour-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-colour-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p> <span ng-hide="(me.item.width < 2) || (me.item.width < 5 && (me.item.inline || me.item.textValue))" class="label" ng-bind-html="me.item.getLabel()"> </span> </p> <color-picker ng-model="me.item.value" aria-label="{{me.item.label}}" ng-attr-options="me.item.options" ng-attr-event-api="me.item.eventapi" ng-keypress="me.item.key($event)" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </color-picker> </md-card> '),e.put("components/ui-component/templates/date-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-date-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p class="nr-dashboard-date-picker-label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-datepicker class="nr-dashboard-date-picker" md-placeholder="{{me.item.getLabel()}}" md-open-on-focus ng-model="me.item.ddd" ng-blur="me.setDate()"> </md-datepicker> </md-input-container> </md-card> '),e.put("components/ui-component/templates/dropdown.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-dropdown" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p ng-if="me.item.width>1 && me.item.getLabel().length>0" class="label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-select ng-if="!me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation();" ng-click="$event.stopPropagation();" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> <md-select ng-if="me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" md-on-close="me.closed()" multiple="multiple" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-checkbox md-no-ink aria-label="Select all" ng-model="me.selectAll" ng-change="me.checkAll()" style="width:unset;"></md-checkbox> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation()" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> </md-input-container> </md-card> '),e.put("components/ui-component/templates/form.html",'<md-card ui-card-size="{{me.item.width}}x{{(me.item.height > me.item.rowCount ? me.item.height : me.item.rowCount )}}" layout="row" layout-align="space-between center" class="nr-dashboard-form" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <form name="form" ng-submit="me.submit(form)" style="margin-top:{{(me.item.label ? 0 : me.item.rowCount < 3 ? me.item.rowHeight/6 : me.item.rowHeight/2.5)}}px"> <p class="formlabel" style="margin-bottom:{{(me.item.rowHeight/9)}}px" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"></p> <div class="formElement" ng-class="{\'formElementSplit\':(me.item.splitLayout)}" layout-gt-sm="row" ng-repeat="opt in me.item.options track by $index"> <md-input-container class="md-block" style="height:{{(me.item.rowHeight * (opt.type==\'multiline\' ? opt.rows : 1)) }}px" flex> <label ng-if="(opt.type==\'text\' || opt.type==\'number\' || opt.type==\'email\' || opt.type==\'multiline\' || opt.type==\'password\' || opt.type==\'date\' || opt.type==\'time\') && opt.label">{{opt.label}}</label> <input ng-if="opt.type==\'text\' || opt.type==\'email\' || opt.type==\'password\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)"> <input ng-if="opt.type==\'date\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="yyyy-mm-dd"> <input ng-if="opt.type==\'time\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="HH:MM"> <input ng-if="opt.type==\'number\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" step="any"> <textarea ng-if="opt.type==\'multiline\'" md-no-autogrow ng-required="opt.required" ng-model="me.item.formValue[opt.value]" style="height:{{(opt.rows * me.item.sy) - 10}}px; padding:10px 2px 1px 0;"></textarea> <md-switch ng-if="opt.type==\'switch\'" md-no-ink ng-model="me.item.formValue[opt.value]">{{opt.label}}</md-switch> <md-checkbox ng-if="opt.type==\'checkbox\'" md-no-ink aria-label="Checkbox No Ink" ng-model="me.item.formValue[opt.value]"> {{opt.label}}</md-checkbox> </md-input-container> \x3c!-- <md-datepicker ng-if="opt.type==\'date\'" ng-model="me.item.formValue[opt.value]"></md-datepicker> --\x3e </div> <div class="form-control" ng-class="{\'form-control-single\':me.item.cancel == \'\',\'form-control-no-label\':me.item.label == \'\'}" style="margin-top:{{( me.item.label ==\'\' ? me.item.rowCount < 3 ? me.item.rowHeight * 0.4 : me.item.rowHeight * 0.2 : me.item.rowHeight * -0.1)}}px;"> <md-button class="md-raised nr-dashboard-form-button" type="submit" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px">{{me.item.submit}}</md-button> <md-button ng-if="me.item.cancel != \'\'" class="md-raised nr-dashboard-form-button" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px" ng-click="me.reset()">{{me.item.cancel}}</md-button> </div> </form> </md-card> cancel'),e.put("components/ui-component/templates/gauge.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label nr-dashboard-gauge-title" ng-class="{\'nr-dashboard-gauge-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()" ng-hide="(me.item.height <= 2)"> </p> <p ng-show="(me.item.height == 2)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titlem\':(me.item.height == 2)}"> </p> <p ng-show="(me.item.height == 1)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titles\':(me.item.height == 1)}"> </p> <ui-gauge style="text-align:center;" class="nr-dashboard-gauge"> </ui-gauge> </md-card> '),e.put("components/ui-component/templates/numeric.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-numeric" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <div layout="row" layout-align="center center"> <md-button class="md-icon-button down-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(-me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_more"></ui-icon> </md-button> <center> <p ng-if="(me.item.ed === false)" class="value" style="min-width:{{me.item.minWidth}}px;" ng-bind-html="me.item.getText()"> </p> <span ng-if="(me.item.ed === true)"> <span class="value" ng-bind-html="me.item.pre"></span> <input ng-model="me.item.value" ng-change="me.newValue()" class="value" ng-disabled="me.item.disabled" style="max-width:{{me.item.minWidth}}px;"> <span class="value" ng-bind-html="me.item.post"></span> </span> </center> <md-button class="md-icon-button up-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_less"></ui-icon> </md-button> </div> </md-card> '),e.put("components/ui-component/templates/slider.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-slider" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, {\'nr-dashboard-slider-v\':(me.item.width < me.item.height)}, me.item.className]" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" node-id="{{me.item.id}}"> <p ng-show="{{me.item.width >= me.item.height}}" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-slider ng-if="me.item.outs===\'all\'" flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.valueChanged(10)" ng-on-wheel="me.wheel($event)" style="z-index:1; touch-action:none; min-width:32px;" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <md-slider ng-if="me.item.outs===\'end\'" md-discrete flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.mchange()" ng-mouseup="me.mup()" ng-mouseleave="me.mleave()" ng-mouseenter="me.menter()" style="z-index:1; touch-action:none; min-width:32px;" ng-style="(me.item.width >= me.item.height) && {\'margin-top\':\'20px\'};" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <p ng-hide="{{me.item.width >= me.item.height}}" class="label-v" ng-bind-html="me.item.getLabel()"> </p> </md-card> '),e.put("components/ui-component/templates/spacer.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-spacer" ng-class="{\'nr-dashboard-disabled\':me.item.disabled}"> </md-card> '),e.put("components/ui-component/templates/switch.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-switch" ng-click="me.switchClick()" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p ng-if="me.item.label && (me.item.width !== 1)" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-switch ng-model="me.item.value" ng-change="me.item.value = !me.item.value" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" aria-label="{{me.item.label}}" ng-class="{\'center\' : !me.item.label}" ng-if="!me.item.oncolor || !me.item.onicon || !me.item.offcolor || !me.item.officon" style="z-index:1"> </md-switch> <ui-icon icon="{{me.item.onicon}}" ng-style="{color: me.item.oncolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': !me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> <ui-icon icon="{{me.item.officon}}" ng-style="{color:me.item.offcolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> </md-card> '),e.put("components/ui-component/templates/template.html",'<md-card ui-template="me.item.format" ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-template {{ me.item.class }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" ng-show="{{me.item.height >= 0}}" node-id="{{me.item.id}}"> </md-card> '),e.put("components/ui-component/templates/text-input-CR.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-keydown="me.keyPressed($event)" ng-blur="me.item.sendOnBlur ? me.keyPressed($event) : false" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text-input.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-change="me.valueChanged({{me.item.delay}})" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" ng-style="(me.item.mode===\'color\') && {\'padding-left\':\'25%\'}" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-text" ng-class="[ me.item.safeLabel, {\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"></p> <p class="value" ng-bind-html="me.item.getText()"></p> </md-card> ')}]);
    "version": "3.1.8",
                me.item.getText = $interpolate(me.item.format).bind(null, me.item);
                me.item.getLabel = $interpolate(me.item.label).bind(null, me.item);
                me.item.safeLabel = "nr-dashboard-widget-" + (me.item.label).replace(/\W/g,'_');
                me.item.getTooltip = $interpolate(me.item.tooltip).bind(null, me.item);
                me.item.getColor = $interpolate(me.item.color).bind(null, me.item);
                me.item.getIcon = $interpolate(me.item.icon).bind(null, me.item);
                me.item.getUnits = $interpolate(me.item.units).bind(null, me.item);
Fixed code: ### 3.1.9: Maintenance Release

 - Fix Cross site scripting for ui_text format input. Issue #772

# Time: Wed Aug 24 2022 17:30:31 GMT+0100 (British Summer Time)
# hash: 9ff936fabba7ec5170a4f63f8f6b72aa1343c36c57f8382848eb81dae9ca5512
angular.module("ui").controller("uiComponentController",["$scope","UiEvents","$interpolate","$interval",function(l,u,e,r){this.$onInit=function(){var i,a=this;"string"==typeof a.item.format&&(-1===a.item.format.indexOf("constructor")?a.item.getText=e(a.item.format).bind(null,a.item):a.item.getText=function(){return a.item.format}),"string"==typeof a.item.label&&(-1===a.item.label.indexOf("constructor")?(a.item.getLabel=e(a.item.label).bind(null,a.item),a.item.safeLabel="nr-dashboard-widget-"+a.item.label.replace(/\W/g,"_")):a.item.getText=function(){return a.item.label}),"string"==typeof a.item.tooltip&&(-1===a.item.tooltip.indexOf("constructor")?a.item.getTooltip=e(a.item.tooltip).bind(null,a.item):a.item.getText=function(){return a.item.tooltip}),"string"==typeof a.item.color&&(-1===a.item.color.indexOf("constructor")?a.item.getColor=e(a.item.color).bind(null,a.item):a.item.getText=function(){return a.item.color}),"string"==typeof a.item.icon&&(-1===a.item.icon.indexOf("constructor")?a.item.getIcon=e(a.item.icon).bind(null,a.item):a.item.getText=function(){return a.item.icon}),"string"==typeof a.item.units&&(-1===a.item.units.indexOf("constructor")?a.item.getUnits=e(a.item.units).bind(null,a.item):a.item.getText=function(){return a.item.units}),a.init=function(){switch(a.item.type){case"button":a.buttonClick=function(e){m({id:a.item.id,value:a.item.value,event:{clientX:e.originalEvent.clientX,clientY:e.originalEvent.clientY,bbox:[e.originalEvent.clientX-e.originalEvent.layerX,e.originalEvent.clientY-e.originalEvent.layerY+e.currentTarget.clientHeight,e.originalEvent.clientX-e.originalEvent.layerX+e.currentTarget.clientWidth,e.originalEvent.clientY-e.originalEvent.layerY]}},0)};break;case"switch":a.switchClick=function(){m({id:a.item.id,value:!a.item.value},0)};break;case"dropdown":a.searchTerm="",a.selectAll=!1,a.changed=!1,a.itemChanged=function(){a.searchTerm="",a.item.multiple?a.changed=!0:a.valueChanged(0)},a.checkAll=function(){var e=a.item.options.filter(function(e){return e.label.toLowerCase().includes(a.searchTerm.toLowerCase())});a.item.value=a.selectAll?e.map(function(e){return e.value}):[],a.valueChanged(0)},a.closed=function(){a.changed&&(a.changed=!1,a.valueChanged(0))},(a.item.me=a).processInput=function(e){o(e)};break;case"numeric":var i=function(e){a.item.value=parseFloat(a.item.value),isNaN(a.item.value)&&(a.item.value=a.item.min),0<e?(a.item.value==a.item.max&&1==a.item.wrap?a.item.value=a.item.min:a.item.value<a.item.max&&(a.item.value=Math.round(1e4*Math.min(a.item.value+e,a.item.max))/1e4),a.item.value<a.item.min&&(a.item.value=a.item.min)):e<0&&(a.item.value==a.item.min&&1==a.item.wrap?a.item.value=a.item.max:a.item.value>a.item.min&&(a.item.value=Math.round(1e4*Math.max(a.item.value+e,a.item.min))/1e4),a.item.value>a.item.max&&(a.item.value=a.item.max))},e=9.5*(Math.round(1e4*(a.item.min+a.item.step))/1e4).toString().length,t=9.5*(Math.round(1e4*(a.item.max+a.item.step))/1e4).toString().length;a.item.minWidth=t<e?e:t;var n=null;a.newValue=function(){isNaN(parseFloat(a.item.value))||(a.item.value<a.item.min&&(a.item.value=a.item.min),a.item.value>a.item.max&&(a.item.value=a.item.max),u.emit({id:a.item.id,value:a.item.value}))},a.periodicChange=function(e){i(e);var t=0;n=r(function(){75<++t?i(250*e):50<t?i(50*e):35<t?i(10*e):25<t?i(2*e):15<t?i(e):5<t&&t%2&&i(e)},100)},a.stopPeriodic=function(){n&&(r.cancel(n),n=null,a.valueChanged(0))};break;case"chart":a.item.theme=l.main.selectedTab.theme;break;case"colour-picker":(a.item.width<4||!a.item.showValue&&!a.item.showPicker)&&(a.item.showPicker=!1,a.item.showValue=!1,a.item.showSwatch=!0),a.item.showPicker&&a.item.height<4&&(a.item.height=a.item.showSwatch||a.item.showValue?4:3),a.item.options={format:a.item.format,inline:a.item.showPicker,hue:a.item.showHue,alpha:a.item.showAlpha,lightness:a.item.showLightness,swatch:a.item.showSwatch,swatchOnly:a.item.width<2||!a.item.showValue,swatchPos:"right",pos:"bottom right",case:"lower",round:!a.item.square,pickerOnly:a.item.showPicker&&!(a.item.showSwatch||a.item.showValue)},a.item.key=function(e){13!==e.charCode&&13!==e.which&&9!==e.charCode&&9!==e.which||(u.emit({id:a.item.id,value:a.item.value}),a.api&&a.api.close())},a.item.eventapi={onChange:function(e,t,i){void 0!==i&&a.valueChanged(0)},onOpen:function(e,t){a.api=e}},l.$watch("me.item.value",function(){a.item.oldValue||(a.item.oldValue=a.item.value),"true"===a.item.dynOutput&&a.item.value!==a.item.oldValue&&(a.item.oldValue=a.item.value,a.valueChanged(20))});break;case"text-input":case"text-input-CR":-1!=a.item.mode.indexOf("time")&&(a.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=e.value.match(/^(\d\d):(\d\d)/);if(null==i){var n=Date.parse(e.value);isNaN(n)&&(n=Date.now()),t=new Date(n)}else t=new Date("1970-01-01 "+i[1]+":"+i[2]+":00Z")}t.setMilliseconds(0),t.setSeconds(0),e.value=t,a.item.value=e.value},a.item.me=a),"week"!==a.item.mode&&"month"!==a.item.mode||(a.processInput=function(e){var t=new Date(e.value);if(isNaN(e.value)){var i=Date.parse(e.value);isNaN(i)&&(i=Date.now()),t=new Date(i)}t.setMilliseconds(0),t.setSeconds(0),e.value=t,a.item.value=e.value},a.item.me=a);break;case"date-picker":void 0!==a.item.ddd&&("number"!=typeof a.item.ddd&&"string"!=typeof a.item.ddd||(a.item.ddd=new Date(a.item.ddd))),a.processInput=function(e){e.value=new Date(e.value),a.item.ddd=e.value},a.setDate=function(){a.item.value=a.item.ddd,a.valueChanged(0)},a.item.me=a;break;case"form":a.processInput=function(e){if("object"==typeof e.value)for(var t in e.value)if(a.item.formValue.hasOwnProperty(t))for(var i in a.item.options)"date"!==a.item.options[i].type&&"time"!==a.item.options[i].type||a.item.options[i].value!==t||(e.value[t]=new Date(e.value[t])),a.item.formValue[t]=e.value[t]},a.item.extraRows=0,a.item.options.map(function(e){"multiline"==e.type&&1<e.rows&&(a.item.extraRows+=e.rows-1)}),a.item.rowCount=1==a.item.splitLayout?Math.ceil(a.item.options.length/2):a.item.options.length,a.item.rowCount+=""==a.item.label?1:2,a.item.rowCount+=a.item.extraRows,a.item.rowHeight=((a.item.rowCount-1)*a.item.sy+(""==a.item.label?.3*a.item.sy:1.2*a.item.sy)+(a.item.rowCount-1)*a.item.cy)/a.item.rowCount,a.stop=function(e){13!==e.charCode&&13!==e.which||(e.preventDefault(),e.stopPropagation())},a.submit=function(){a.item.value=JSON.parse(JSON.stringify(a.item.formValue)),a.valueChanged(0),a.reset()},a.reset=function(){for(var e in a.item.options)"checkbox"===a.item.options[e].type||"switch"===a.item.options[e].type?a.item.formValue[a.item.options[e].value]=!1:a.item.formValue[a.item.options[e].value]="";l.$$childTail.form.$setUntouched(),l.$$childTail.form.$setPristine()},a.item.me=a;break;case"template":a.setFormat=function(e){a.item.format=e},void 0!==a.item.msg&&void 0!==a.item.msg.template&&a.setFormat(a.item.msg.template);break;case"slider":a.wheel=function(e){e.preventDefault(),0<e.originalEvent.deltaY&&(a.item.value+=a.item.step,a.item.value>a.item.max&&(a.item.value=a.item.max)),e.originalEvent.deltaY<0&&(a.item.value-=a.item.step,a.item.value<a.item.min&&(a.item.value=a.item.min)),a.valueChanged(0)},a.active=!1,a.mdown=function(){a.active=!0},a.menter=function(){a.active=!0},a.mleave=function(){a.active=!1},a.mchange=function(){a.active=!1,a.valueChanged(0)},a.mup=function(){a.active&&(a.active=!1,a.valueChanged(0))}}},a.valueChanged=function(e){m({id:a.item.id,value:a.item.value},"number"==typeof e?e:10)},a.keyPressed=function(e){13===e.charCode||13===e.which?(u.emit({id:a.item.id,value:a.item.value}),a.lastItemSent=a.item.value):"blur"===e.type&&a.item.value!==a.lastItemSent&&(u.emit({id:a.item.id,value:a.item.value}),a.lastItemSent=a.item.value)};var m=function(e,t){0!==t?(i&&clearTimeout(i),i=setTimeout(function(){i=void 0,u.emit(e)},t)):u.emit(e)},o=function(e){e&&e.isOptionsValid&&(a.item.options=e.newOptions,delete a.item.isOptionsValid,delete a.item.newOptions)}}}]);
angular.module("ui").run(["$templateCache",function(e){e.put("logout.html",'<head></head> <body> <script src="js/app.min.js"><\/script> <script> for (var key in localStorage) {\n    if (localStorage.hasOwnProperty(key)) {\n        if (key.indexOf("nr-") === 0) {\n            localStorage.removeItem(key);\n        }\n    }\n}\n$.ajax({\n    type: "GET",\n    url: window.location.href,\n    async: true,\n    username: "some_non_user_name",\n    password: "a_not_valid_password"\n})\n.done(function() { alert(\'Error!\') })\n.fail(function() {\n    var url = window.location.href.split("logout")[0];\n    setTimeout(function() { window.location.href = url; }, 1000);\n}); <\/script> <style> div {\n    width: 400px;\n    height: 300px;\n    position: absolute;\n    top:0;\n    bottom: 0;\n    left: 0;\n    right: 0;\n    margin: auto;\n    font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif;\n} </style> <div class="node-red-ui--notabs"> <table><tr><td><center><a href="./"><img src="icon120x120.png"></a></center></td></tr> <tr><td><center><h2>Welcome to the Node-RED Dashboard</h2></center></td></tr> <tr><td><center>Please <a href="./">sign in</a> to see your flow.</center></td></tr></table> </div> </body> '),e.put("partials/main.html",'<md-toolbar ng-show="main.hideToolbar !== true" id="toolbar"> <div class="md-toolbar-tools" id="nr-dashboard-toolbar"> <md-button ng-show="!(main.lockMenu != \'false\') && main.len > 1" ng-click="main.toggleSidenav()" class="md-icon-button" aria-label="menu button"> <ng-md-icon icon="menu"></ng-md-icon> </md-button> <h1 ng-show="main.len <= 1" style="width:30px"> </h1> <h1 ng-show="main.lockMenu != \'false\'" node-id="{{main.id}}">{{main.name}}</h1> <h1 ng-show="!(main.lockMenu != \'false\') && main.loaded" node-id="{{main.selectedTab.id}}">{{main.selectedTab.header || main.selectedTab.name}}</h1> </div> </md-toolbar> <section layout="row" flex> <md-sidenav ng-hide="main.len <= 1" class="md-sidenav-left" md-component-id="left" md-is-locked-open="(main.lockMenu != \'false\')"> <md-list> <md-list-item ng-repeat="obj in main.menu" ng-class="{\'nr-menu-item-active\':location.$$path==\'/\'+$index}" ng-disabled="obj.disabled" ng-if="!obj.hidden" ng-click="main.open(obj, $index)"> <ui-icon icon="{{obj.icon}}" style="margin:5px"></ui-icon> <p style="margin-right:12px; min-width:120px;" ng-show="(main.lockMenu != \'icon\')">{{main.getMenuName(obj)}}</p> </md-list-item> </md-list> </md-sidenav> <md-content flex> <div ui-masonry ng-show="main.selectedTab.header" id="{{\'Tab_\'+main.selectedTab.header | spaceToUnderscore}}"> <ui-card-panel node-id="{{group.header.id}}" ng-repeat="group in main.selectedTab.items" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}" ng-if="group.header && group.header.config && !group.header.config.hidden"> <ui-component ng-repeat="control in group.items" item="control"></ui-component> </ui-card-panel> </div> <div class="node-red-ui--inline-link" ng-show="!main.selectedTab.header"> <iframe class="iframe" ng-src="{{ main.selectedTab.link }}" allowfullscreen></iframe> \x3c!-- <div>The url {{ }} cannot be loaded into an iframe.</div> --\x3e </div> </md-content> </section> <div id="nr-dashboard-footer" layout="row"></div> '),e.put("partials/toast.html",'<md-toast layout="column" style="border:4px solid {{::toast.highlight}}; padding:0px; transition:border-color 0.1s;"> <div> <h3 ng-if="toast.title">{{::toast.title}}</h3> <h4 flex ng-bind-html="::toast.message | trusted"></h4> </div> </md-toast> '),e.put("components/ui-card-panel/ui-card-panel.html",'<div layout="column" class="nr-dashboard-cardpanel" ng-class="[group.header.config && group.header.config.className]" node-classname="{{group.header.config.className}}"> <p class="nr-dashboard-cardtitle" ng-style="{width:ctrl.width-12}" ng-if="group.header && group.header.config.disp && group.header[group.header.length-1]!=\'!\'">{{group.header.name}} <span ng-if="group.header.config.collapse" ng-model="collapsed" ng-click="collapseCard()" class="nr-dashboard-cardcarat"> <i ng-class="{ \'fa fa-caret-down\':collapsed, \'fa fa-caret-up\':!collapsed }"></i> </span> </p> <div class="nr-dashboard-cardcontainer" id="{{main.selectedTab.header+\'_\'+group.header.name | spaceToUnderscore}}_cards" ng-transclude ng-style="{width:ctrl.width, height:ctrl.height}"></div> </div> '),e.put("components/ui-chart-js/ui-chart-js.html",'<div> <canvas ng-if="me.item.look===\'line\'" class="chart chart-line" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'bar\'" class="chart chart-bar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'horizontalBar\'" class="chart chart-horizontalBar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'pie\'" class="chart chart-pie" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'polar-area\'" class="chart chart-polar-area" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> <canvas ng-if="me.item.look===\'radar\'" class="chart chart-radar" chart-data="config.data" chart-series="config.series" chart-labels="config.labels" chart-options="config.options" chart-dataset-override="config.overrides" chart-colors="config.colours"> </canvas> </div> '),e.put("components/ui-gauge/ui-gauge.html","<div id=\"gauge_{{$id}}\" style=\"width:{{0.95 * me.item.width * me.item.sizes.sx - (20 * (me.item.gtype === 'compass')) }}px;\n    height:{{0.95 * (me.item.height * me.item.sizes.sy)+((me.item.title.length == 0) * me.item.sizes.sy) - (20 * (me.item.gtype === 'compass')) }}px;\n    margin-top:-20px;\n    padding-bottom:{{(me.item.gtype === 'wave') * 6}}px;\"> </div> "),e.put("components/ui-icon/ui-icon.html",'<ng-md-icon ng-if="iconType===\'angular-material\'" icon="{{icon}}"></ng-md-icon> <div ng-if="iconType===\'fa\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="fa fa-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'wi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="wi wi-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'mi\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="material-icons" ng-class="icon">{{icon.substr(3)}}</i></div> <div ng-if="iconType===\'icofont\'" style="display:inline-block; margin:auto; line-height:initial;"><i class="icofont icofont-fw" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <div ng-if="iconType===\'iconify1\'" style="display:inline-block; margin:auto; line-height:18px; vertical-align:middle;" class="{{icon.split(\' \')[0].substr(8)}}"><i class="iconify" data-icon="{{icon.split(\' \')[0].substr(8)}}" data-width="{{icon.split(\' \')[1] || \'1.3em\'}}" data-height="{{icon.split(\' \')[1] || \'1.3em\'}}" data-inline="true" ng-class="icon"></i></div> <img ng-if="iconType===\'image\'" ng-src="{{url}}" style="width:24px; display:block; margin:auto; line-height:initial;"> '),e.put("components/ui-component/templates/button.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-button" node-class="{{ me.item.className }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-button class="md-raised" ng-click="me.buttonClick($event)" ng-disabled="me.item.disabled" aria-label="{{\'button\' + me.item.label}}" ng-style="{\'background-color\':me.item.getText(), \'color\':me.item.getColor(), \'z-index\':1, \'padding\':\'0px\'}"> <ui-icon ng-show="me.item.icon.length" icon="{{me.item.getIcon()}}" ng-style="{color:me.item.getColor()}"> </ui-icon> <span ng-bind-html="me.item.getLabel()"></span> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> </md-button> </md-card> '),e.put("components/ui-component/templates/chart.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <div class="nr-dashboard-chart-container" style="width:100%; height:100%;"> <p class="label nr-dashboard-chart-title" ng-class="{\'nr-dashboard-chart-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()"> </p> <ui-chart-js class="nr-dashboard-chart" ng-class="{\'nr-dashboard-chart-nolabel\':me.item.getLabel() == \'\'}" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </ui-chart-js> <p class="blank-label" ng-if="config && config.nodata">{{ me.item.nodata }} </p> </div> </md-card> '),e.put("components/ui-component/templates/colour-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-colour-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p> <span ng-hide="(me.item.width < 2) || (me.item.width < 5 && (me.item.inline || me.item.textValue))" class="label" ng-bind-html="me.item.getLabel()"> </span> </p> <color-picker ng-model="me.item.value" aria-label="{{me.item.label}}" ng-attr-options="me.item.options" ng-attr-event-api="me.item.eventapi" ng-keypress="me.item.key($event)" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();"> </color-picker> </md-card> '),e.put("components/ui-component/templates/date-picker.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-date-picker" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p class="nr-dashboard-date-picker-label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-datepicker class="nr-dashboard-date-picker" md-placeholder="{{me.item.getLabel()}}" md-open-on-focus ng-model="me.item.ddd" ng-blur="me.setDate()"> </md-datepicker> </md-input-container> </md-card> '),e.put("components/ui-component/templates/dropdown.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-dropdown" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container flex layout="row"> <p ng-if="me.item.width>1 && me.item.getLabel().length>0" class="label" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-select ng-if="!me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation();" ng-click="$event.stopPropagation();" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> <md-select ng-if="me.item.multiple" ng-change="me.itemChanged()" ng-disabled="me.item.disabled" md-on-close="me.closed()" multiple="multiple" ng-model="me.item.value" placeholder="{{ me.item.place }}" flex="100"> <md-select-header ng-if="me.item.options.length > 7" class="nr-dashboard-dropdown-header"> <md-checkbox md-no-ink aria-label="Select all" ng-model="me.selectAll" ng-change="me.checkAll()" style="width:unset;"></md-checkbox> <md-input-container class="md-block" style="height:32px;" flex> <input ng-model="me.searchTerm" ng-keydown="$event.stopPropagation()" type="search" aria-label="Filter"> <ng-md-icon icon="search"></ng-md-icon> </md-input-container> </md-select-header> <md-option ng-value="opt.value" ng-repeat="opt in me.item.options | filter: { label: me.searchTerm }">{{ opt.label }} </md-option> </md-select> </md-input-container> </md-card> '),e.put("components/ui-component/templates/form.html",'<md-card ui-card-size="{{me.item.width}}x{{(me.item.height > me.item.rowCount ? me.item.height : me.item.rowCount )}}" layout="row" layout-align="space-between center" class="nr-dashboard-form" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <form name="form" ng-submit="me.submit(form)" style="margin-top:{{(me.item.label ? 0 : me.item.rowCount < 3 ? me.item.rowHeight/6 : me.item.rowHeight/2.5)}}px"> <p class="formlabel" style="margin-bottom:{{(me.item.rowHeight/9)}}px" ng-if="me.item.label" ng-bind-html="me.item.getLabel()"></p> <div class="formElement" ng-class="{\'formElementSplit\':(me.item.splitLayout)}" layout-gt-sm="row" ng-repeat="opt in me.item.options track by $index"> <md-input-container class="md-block" style="height:{{(me.item.rowHeight * (opt.type==\'multiline\' ? opt.rows : 1)) }}px" flex> <label ng-if="(opt.type==\'text\' || opt.type==\'number\' || opt.type==\'email\' || opt.type==\'multiline\' || opt.type==\'password\' || opt.type==\'date\' || opt.type==\'time\') && opt.label">{{opt.label}}</label> <input ng-if="opt.type==\'text\' || opt.type==\'email\' || opt.type==\'password\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)"> <input ng-if="opt.type==\'date\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="yyyy-mm-dd"> <input ng-if="opt.type==\'time\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" placeholder="HH:MM"> <input ng-if="opt.type==\'number\'" type="{{opt.type}}" ng-model="me.item.formValue[opt.value]" ng-required="opt.required" ng-keydown="me.stop($event)" step="any"> <textarea ng-if="opt.type==\'multiline\'" md-no-autogrow ng-required="opt.required" ng-model="me.item.formValue[opt.value]" style="height:{{(opt.rows * me.item.sy) - 10}}px; padding:10px 2px 1px 0;"></textarea> <md-switch ng-if="opt.type==\'switch\'" md-no-ink ng-model="me.item.formValue[opt.value]">{{opt.label}}</md-switch> <md-checkbox ng-if="opt.type==\'checkbox\'" md-no-ink aria-label="Checkbox No Ink" ng-model="me.item.formValue[opt.value]"> {{opt.label}}</md-checkbox> </md-input-container> \x3c!-- <md-datepicker ng-if="opt.type==\'date\'" ng-model="me.item.formValue[opt.value]"></md-datepicker> --\x3e </div> <div class="form-control" ng-class="{\'form-control-single\':me.item.cancel == \'\',\'form-control-no-label\':me.item.label == \'\'}" style="margin-top:{{( me.item.label ==\'\' ? me.item.rowCount < 3 ? me.item.rowHeight * 0.4 : me.item.rowHeight * 0.2 : me.item.rowHeight * -0.1)}}px;"> <md-button class="md-raised nr-dashboard-form-button" type="submit" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px">{{me.item.submit}}</md-button> <md-button ng-if="me.item.cancel != \'\'" class="md-raised nr-dashboard-form-button" style="height:{{(me.item.sy -4)}}px;line-height:{{(me.item.sy -4)}}px" ng-click="me.reset()">{{me.item.cancel}}</md-button> </div> </form> </md-card> cancel'),e.put("components/ui-component/templates/gauge.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout-align="center center" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label nr-dashboard-gauge-title" ng-class="{\'nr-dashboard-gauge-titlel\':(me.item.width > 3)}" ng-bind-html="me.item.getLabel()" ng-hide="(me.item.height <= 2)"> </p> <p ng-show="(me.item.height == 2)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titlem\':(me.item.height == 2)}"> </p> <p ng-show="(me.item.height == 1)" ng-bind-html="me.item.getLabel()" ng-class="{\'nr-dashboard-gauge-titles\':(me.item.height == 1)}"> </p> <ui-gauge style="text-align:center;" class="nr-dashboard-gauge"> </ui-gauge> </md-card> '),e.put("components/ui-component/templates/numeric.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-numeric" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <div layout="row" layout-align="center center"> <md-button class="md-icon-button down-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(-me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_more"></ui-icon> </md-button> <center> <p ng-if="(me.item.ed === false)" class="value" style="min-width:{{me.item.minWidth}}px;" ng-bind-html="me.item.getText()"> </p> <span ng-if="(me.item.ed === true)"> <span class="value" ng-bind-html="me.item.pre"></span> <input ng-model="me.item.value" ng-change="me.newValue()" class="value" ng-disabled="me.item.disabled" style="max-width:{{me.item.minWidth}}px;"> <span class="value" ng-bind-html="me.item.post"></span> </span> </center> <md-button class="md-icon-button up-button" aria-label="{{me.item.label}}" ng-mousedown="me.periodicChange(me.item.step)" ng-mouseup="me.stopPeriodic()" ng-mouseleave="me.stopPeriodic()" style="z-index:1"> <ui-icon icon="expand_less"></ui-icon> </md-button> </div> </md-card> '),e.put("components/ui-component/templates/slider.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" flex layout="row" layout-align="space-between center" class="nr-dashboard-slider" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, {\'nr-dashboard-slider-v\':(me.item.width < me.item.height)}, me.item.className]" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" node-id="{{me.item.id}}"> <p ng-show="{{me.item.width >= me.item.height}}" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-slider ng-if="me.item.outs===\'all\'" flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.valueChanged(10)" ng-on-wheel="me.wheel($event)" style="z-index:1; touch-action:none; min-width:32px;" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <md-slider ng-if="me.item.outs===\'end\'" md-discrete flex="100" min="{{me.item.min}}" max="{{me.item.max}}" step="{{me.item.step}}" ng-model="me.item.value" aria-label="{{me.item.label}}" ng-change="me.mchange()" ng-mouseup="me.mup()" ng-mouseleave="me.mleave()" ng-mouseenter="me.menter()" style="z-index:1; touch-action:none; min-width:32px;" ng-style="(me.item.width >= me.item.height) && {\'margin-top\':\'20px\'};" ng-attr-md-vertical="{{ (me.item.width < me.item.height) || undefined}}" ng-attr-md-invert="{{ me.item.invert || undefined}}"> </md-slider> <p ng-hide="{{me.item.width >= me.item.height}}" class="label-v" ng-bind-html="me.item.getLabel()"> </p> </md-card> '),e.put("components/ui-component/templates/spacer.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-spacer" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]"> </md-card> '),e.put("components/ui-component/templates/switch.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-switch" ng-click="me.switchClick()" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p ng-if="me.item.label && (me.item.width !== 1)" class="label" ng-bind-html="me.item.getLabel()"> </p> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <md-switch ng-model="me.item.value" ng-change="me.item.value = !me.item.value" ng-swipe-right="$event.stopPropagation();" ng-swipe-left="$event.stopPropagation();" aria-label="{{me.item.label}}" ng-class="{\'center\' : !me.item.label}" ng-if="!me.item.oncolor || !me.item.onicon || !me.item.offcolor || !me.item.officon" style="z-index:1"> </md-switch> <ui-icon icon="{{me.item.onicon}}" ng-style="{color: me.item.oncolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': !me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> <ui-icon icon="{{me.item.officon}}" ng-style="{color:me.item.offcolor}" ng-class="{\'center\' : !me.item.label, \'ng-hide\': me.item.value}" class="{{me.item.animate}}" ng-if="me.item.oncolor && me.item.onicon && me.item.offcolor && me.item.officon" style="z-index:1"> </ui-icon> </md-card> '),e.put("components/ui-component/templates/template.html",'<md-card ui-template="me.item.format" ui-card-size="{{ me.item.width }}x{{ me.item.height }}" class="nr-dashboard-template {{ me.item.class }}" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" ng-show="{{me.item.height >= 0}}" node-id="{{me.item.id}}"> </md-card> '),e.put("components/ui-component/templates/text-input-CR.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-keydown="me.keyPressed($event)" ng-blur="me.item.sendOnBlur ? me.keyPressed($event) : false" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text-input.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="row" layout-align="space-between center" class="nr-dashboard-textinput" ng-class="[{\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <md-input-container class="md-block" flex md-is-error="false" ng-class="{\'has-label\':me.item.label}"> <label ng-bind-html="me.item.getLabel()"></label> <md-tooltip ng-if="me.item.getTooltip().length" md-delay="700" md-direction="bottom" ng-bind-html="me.item.getTooltip()"> </md-tooltip> <input ng-model="me.item.value" ng-model-options="{\'timezone\':\'UTC\'}" ng-change="me.valueChanged({{me.item.delay}})" ng-trim="false" ng-disabled="me.item.disabled" aria-label="{{me.item.label}}" type="{{me.item.mode}}" style="z-index:1" ng-style="(me.item.mode===\'color\') && {\'padding-left\':\'25%\'}" step="any"> </md-input-container> </md-card> '),e.put("components/ui-component/templates/text.html",'<md-card ui-card-size="{{ me.item.width }}x{{ me.item.height }}" layout="{{ me.item.layout }}" layout-align="{{ me.item.layoutAlign }}" class="nr-dashboard-text" ng-class="[ me.item.safeLabel, {\'nr-dashboard-disabled\':me.item.disabled}, me.item.className]" node-id="{{me.item.id}}"> <p class="label" ng-bind-html="me.item.getLabel()"></p> <p class="value" ng-bind-html="me.item.getText()"></p> </md-card> ')}]);
    "version": "3.1.9",
                if (me.item.format.indexOf("constructor") === -1) {
                    me.item.getText = $interpolate(me.item.format).bind(null, me.item);
                }
                else {
                    me.item.getText = function() { return me.item.format };
                }
                if (me.item.label.indexOf("constructor") === -1) {
                    me.item.getLabel = $interpolate(me.item.label).bind(null, me.item);
                    me.item.safeLabel = "nr-dashboard-widget-" + (me.item.label).replace(/\W/g,'_');
                }
                else {
                    me.item.getText = function() { return me.item.label };
                }
                if (me.item.tooltip.indexOf("constructor") === -1) {
                    me.item.getTooltip = $interpolate(me.item.tooltip).bind(null, me.item);
                }
                else {
                    me.item.getText = function() { return me.item.tooltip };
                }
                if (me.item.color.indexOf("constructor") === -1) {
                    me.item.getColor = $interpolate(me.item.color).bind(null, me.item);
                }
                else {
                    me.item.getText = function() { return me.item.color };
                }
                if (me.item.icon.indexOf("constructor") === -1) {
                    me.item.getIcon = $interpolate(me.item.icon).bind(null, me.item);
                }
                else {
                    me.item.getText = function() { return me.item.icon };
                }
                if (me.item.units.indexOf("constructor") === -1) {
                    me.item.getUnits = $interpolate(me.item.units).bind(null, me.item);
                }
                else {
                    me.item.getText = function() { return me.item.units };
                }