- ${this._config.dismissable?M`
+ ${this._config.dismissable?I`
@@ -307,17 +307,17 @@ function e(e,t,i,s){var o,n=arguments.length,r=n<3?t:null===s?s=Object.getOwnPro
${this._config.style}
}
- ${void 0!==this._config.right_button||void 0!==this._config.left_button?M`
+ ${void 0!==this._config.right_button||void 0!==this._config.left_button?I`
- ${void 0!==this._config.left_button?M`
+ ${void 0!==this._config.left_button?I`
`:""}
- ${void 0!==this._config.right_button?M`
+ ${void 0!==this._config.right_button?I`
@@ -325,7 +325,7 @@ function e(e,t,i,s){var o,n=arguments.length,r=n<3?t:null===s?s=Object.getOwnPro
`:""}
- `:M``}static get styles(){return n`
+ `:I``}static get styles(){return n`
:host {
display: none !important;
}
@@ -372,4 +372,4 @@ function e(e,t,i,s){var o,n=arguments.length,r=n<3?t:null===s?s=Object.getOwnPro
padding: 8px;
border-top: 1px solid transparent;
}
- `}}e([ee()],Pe.prototype,"hass",void 0),e([te()],Pe.prototype,"_config",void 0),e([ee({attribute:"edit-mode",reflect:!0})],Pe.prototype,"editMode",void 0),e([te()],Pe.prototype,"_element",void 0),(async()=>{for(;!window.browser_mod;)await new Promise((e=>setTimeout(e,1e3)));await window.browser_mod.connectionPromise,customElements.get("popup-card")||customElements.define("popup-card",Pe)})();const Ie=e=>class extends e{constructor(){super(),this.__currentTitle=void 0,this._auto_settings_setup(),this.addEventListener("browser-mod-config-update",(()=>this._auto_settings_setup())),window.addEventListener("location-changed",(()=>{this._updateTitle(),setTimeout((()=>this._updateTitle()),500),setTimeout((()=>this._updateTitle()),1e3),setTimeout((()=>this._updateTitle()),5e3)}))}async _auto_settings_setup(){await this.connectionPromise;const e=this.settings;e.sidebarPanelOrder&&localStorage.setItem("sidebarPanelOrder",e.sidebarPanelOrder),e.sidebarHiddenPanels&&localStorage.setItem("sidebarHiddenPanels",e.sidebarHiddenPanels),e.defaultPanel&&localStorage.setItem("defaultPanel",e.defaultPanel),!0===e.hideSidebar&&(de(document.body,"home-assistant$home-assistant-main$app-drawer-layout").then((e=>{var t;return null===(t=null==e?void 0:e.style)||void 0===t?void 0:t.setProperty("--app-drawer-width","0px")})),de(document.body,"home-assistant$home-assistant-main$app-drawer-layout app-drawer").then((e=>{var t;return null===(t=null==e?void 0:e.remove)||void 0===t?void 0:t.call(e)}))),!0===e.hideHeader&&customElements.whenDefined("app-header-layout").then((()=>{const e=customElements.get("app-header").prototype,t=e.attached;e.attached=function(){t.bind(this)(),this.style.setProperty("display","none")}})),void 0!==e.faviconTemplate&&(async()=>{this._faviconTemplateSubscription&&this._faviconTemplateSubscription(),this._faviconTemplateSubscription=void 0,this._faviconTemplateSubscription=await this.connection.subscribeMessage(this._updateFavicon,{type:"render_template",template:e.faviconTemplate,variables:{}})})(),void 0!==e.titleTemplate&&(async()=>{this._titleTemplateSubscription&&this._titleTemplateSubscription(),this._titleTemplateSubscription=void 0,this._titleTemplateSubscription=await this.connection.subscribeMessage(this._updateTitle.bind(this),{type:"render_template",template:e.titleTemplate,variables:{}})})()}get _currentFavicon(){const e=document.head.querySelector("link[rel~='icon']");return null==e?void 0:e.href}_updateFavicon({result:e}){document.head.querySelector("link[rel~='icon']").href=e,window.browser_mod.fireEvent("browser-mod-favicon-update")}get _currentTitle(){return this.__currentTitle}_updateTitle(e){e&&(this.__currentTitle=e.result),this.__currentTitle&&(document.title=this.__currentTitle),window.browser_mod.fireEvent("browser-mod-favicon-update")}},Me="browser_mod-browser-id",Oe=e=>class extends e{constructor(){if(super(),Storage&&!Storage.prototype.browser_mod_patched){const e=Storage.prototype.clear;Storage.prototype.clear=function(){const t=this.getItem(Me),i=this.getItem("suspendWhenHidden");e.apply(this),this.setItem(Me,t),this.setItem("suspendWhenHidden",i)},Storage.prototype.browser_mod_patched=!0}}async recall_id(){if(!this.connection)return;const e=await this.connection.sendMessagePromise({type:"browser_mod/recall_id"});e&&(localStorage[Me]=e)}get browserID(){return document.querySelector("hc-main")?"CAST":localStorage[Me]?localStorage[Me]:(this.browserID="",this.recall_id(),this.browserID)}set browserID(e){""===e&&(e=function(){var e,t;const i=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);return null!==(t=null===(e=window.fully)||void 0===e?void 0:e.getDeviceId())&&void 0!==t?t:`${i()}${i()}-${i()}${i()}`}());const t=localStorage[Me];localStorage[Me]=e,this.browserIDChanged(t,e)}browserIDChanged(e,t){}};class Le extends(ye(Se(fe(be(_e(me(ve(Ie(we(ge(pe(Oe(EventTarget))))))))))))){constructor(){super(),this.connect(),console.info(`%cBROWSER_MOD ${Ce} IS INSTALLED\n %cBrowserID: ${this.browserID}`,"color: green; font-weight: bold","")}}window.browser_mod||(window.browser_mod=new Le);export{Le as BrowserMod};
+ `}}e([ee()],Oe.prototype,"hass",void 0),e([te()],Oe.prototype,"_config",void 0),e([ee({attribute:"edit-mode",reflect:!0})],Oe.prototype,"editMode",void 0),e([te()],Oe.prototype,"_element",void 0),(async()=>{for(;!window.browser_mod;)await new Promise((e=>setTimeout(e,1e3)));await window.browser_mod.connectionPromise,customElements.get("popup-card")||customElements.define("popup-card",Oe)})();const Ie=t=>{class i extends t{constructor(){super(),this.__currentTitle=void 0;const e=async()=>{this.runUpdateTitle(),this.runHideHeader()};this._auto_settings_setup(),this.addEventListener("browser-mod-config-update",(()=>{this._auto_settings_setup(),e()})),window.addEventListener("location-changed",e)}async runHideHeader(){for(;!await this._hideHeader();)await new Promise((e=>setTimeout(e,500)))}async runUpdateTitle(){await async function(e,t,i){for(;t--;)e(),await new Promise((e=>setTimeout(e,i)))}((()=>this._updateTitle()),3,500)}async _auto_settings_setup(){await this.connectionPromise;const e=this.settings;e.sidebarPanelOrder&&localStorage.setItem("sidebarPanelOrder",e.sidebarPanelOrder),e.sidebarHiddenPanels&&localStorage.setItem("sidebarHiddenPanels",e.sidebarHiddenPanels),e.defaultPanel&&localStorage.setItem("defaultPanel",`"${e.defaultPanel}"`),!0===e.hideSidebar&&(de(document.body,"home-assistant$home-assistant-main$app-drawer-layout").then((e=>{var t;return null===(t=null==e?void 0:e.style)||void 0===t?void 0:t.setProperty("--app-drawer-width","0px")})),de(document.body,"home-assistant$home-assistant-main$app-drawer-layout app-drawer").then((e=>{var t;return null===(t=null==e?void 0:e.remove)||void 0===t?void 0:t.call(e)}))),e.sidebarTitle&&de(document,"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar $ .title").then((t=>{t&&(t.innerHTML=e.sidebarTitle)})),void 0!==e.faviconTemplate&&(async()=>{this._faviconTemplateSubscription&&this._faviconTemplateSubscription(),this._faviconTemplateSubscription=void 0,this._faviconTemplateSubscription=await this.connection.subscribeMessage(this._updateFavicon,{type:"render_template",template:e.faviconTemplate,variables:{}})})(),void 0!==e.titleTemplate&&(async()=>{this._titleTemplateSubscription&&this._titleTemplateSubscription(),this._titleTemplateSubscription=void 0,this._titleTemplateSubscription=await this.connection.subscribeMessage(this._updateTitle.bind(this),{type:"render_template",template:e.titleTemplate,variables:{}})})()}get _currentFavicon(){const e=document.head.querySelector("link[rel~='icon']");return null==e?void 0:e.href}_updateFavicon({result:e}){document.head.querySelector("link[rel~='icon']").href=e}get _currentTitle(){return this.__currentTitle}_updateTitle(e){e&&(this.__currentTitle=e.result),this.__currentTitle&&(document.title=this.__currentTitle)}async _hideHeader(){var e,t;if(!0!==this.settings.hideHeader)return!0;let i=await de(document,"home-assistant $ home-assistant-main $ app-drawer-layout partial-panel-resolver");if(!i)return!1;let s=0;for(;i&&"ha-app-layout"!==i.localName&&s++<5;){await re(i,!0);const s=null!==(t=null!==(e=i.querySelector("ha-app-layout"))&&void 0!==e?e:i.firstElementChild)&&void 0!==t?t:i.shadowRoot;i=s}return"ha-app-layout"===(null==i?void 0:i.localName)&&(!!i.header&&(i.header.style.setProperty("display","none"),setTimeout((()=>i._updateLayoutStates()),0),!0))}getSetting(e){var t,i,s,o;const n={global:void 0,browser:{},user:{}};n.global=null===(t=this._data.settings)||void 0===t?void 0:t[e];for(const[t,o]of Object.entries(null!==(i=this._data.browsers)&&void 0!==i?i:{}))null!=(null===(s=o.settings)||void 0===s?void 0:s[e])&&(n.browser[t]=o.settings[e]);for(const[t,i]of Object.entries(null!==(o=this._data.user_settings)&&void 0!==o?o:{}))null!=i[e]&&(n.user[t]=i[e]);return n}setSetting(e,t,i){if("global"===e)for(const[e,t]of Object.entries(i))this.connection.sendMessage({type:"browser_mod/settings",key:e,value:t});else if("browser"===e){const e=this._data.browsers[t],s=Object.assign(Object.assign({},e.settings),i);console.log(s),this.connection.sendMessage({type:"browser_mod/register",browserID:t,data:Object.assign(Object.assign({},e),{settings:s})})}else if("user"===e){const e=t;for(const[t,s]of Object.entries(i))this.connection.sendMessage({type:"browser_mod/settings",user:e,key:t,value:s})}}}return e([pe()],i.prototype,"runHideHeader",null),e([pe(!0)],i.prototype,"runUpdateTitle",null),i},Me="browser_mod-browser-id",Le=e=>class extends e{constructor(){if(super(),Storage&&!Storage.prototype.browser_mod_patched){const e=Storage.prototype.clear;Storage.prototype.clear=function(){const t=this.getItem(Me),i=this.getItem("suspendWhenHidden");e.apply(this),this.setItem(Me,t),this.setItem("suspendWhenHidden",i)},Storage.prototype.browser_mod_patched=!0}}async recall_id(){if(!this.connection)return;const e=await this.connection.sendMessagePromise({type:"browser_mod/recall_id"});e&&(localStorage[Me]=e)}get browserID(){return document.querySelector("hc-main")?"CAST":localStorage[Me]?localStorage[Me]:(this.browserID="",this.recall_id(),this.browserID)}set browserID(e){""===e&&(e=function(){var e,t;const i=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);return null!==(t=null===(e=window.fully)||void 0===e?void 0:e.getDeviceId())&&void 0!==t?t:`${i()}${i()}-${i()}${i()}`}());const t=localStorage[Me];localStorage[Me]=e,this.browserIDChanged(t,e)}browserIDChanged(e,t){}};class Ue extends(fe(Ce($e(ye(ge(_e(me(Ie(be(we(ve(Le(EventTarget))))))))))))){constructor(){super(),this.connect(),console.info(`%cBROWSER_MOD ${Te} IS INSTALLED\n %cBrowserID: ${this.browserID}`,"color: green; font-weight: bold","")}}window.browser_mod||(window.browser_mod=new Ue);export{Ue as BrowserMod};
diff --git a/custom_components/browser_mod/browser_mod_panel.js b/custom_components/browser_mod/browser_mod_panel.js
index 89135aa..526cd4c 100644
--- a/custom_components/browser_mod/browser_mod_panel.js
+++ b/custom_components/browser_mod/browser_mod_panel.js
@@ -1,14 +1,14 @@
-function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(n=(r<3?o(n):r>3?o(t,i,n):o(t,i))||n);return r>3&&n&&Object.defineProperty(t,i,n),n}const t=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,i=Symbol(),s=new WeakMap;class o{constructor(e,t,s){if(this._$cssResult$=!0,s!==i)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const i=this.t;if(t&&void 0===e){const t=void 0!==i&&1===i.length;t&&(e=s.get(i)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&s.set(i,e))}return e}toString(){return this.cssText}}const r=(e,...t)=>{const s=1===e.length?e[0]:t.reduce(((t,i,s)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(i)+e[s+1]),e[0]);return new o(s,e,i)},n=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const i of e.cssRules)t+=i.cssText;return(e=>new o("string"==typeof e?e:e+"",void 0,i))(t)})(e):e;var a;const l=window.trustedTypes,d=l?l.emptyScript:"",h=window.reactiveElementPolyfillSupport,c={toAttribute(e,t){switch(t){case Boolean:e=e?d:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let i=e;switch(t){case Boolean:i=null!==e;break;case Number:i=null===e?null:Number(e);break;case Object:case Array:try{i=JSON.parse(e)}catch(e){i=null}}return i}},u=(e,t)=>t!==e&&(t==t||e==e),p={attribute:!0,type:String,converter:c,reflect:!1,hasChanged:u};class w extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(e){var t;null!==(t=this.h)&&void 0!==t||(this.h=[]),this.h.push(e)}static get observedAttributes(){this.finalize();const e=[];return this.elementProperties.forEach(((t,i)=>{const s=this._$Ep(i,t);void 0!==s&&(this._$Ev.set(s,i),e.push(s))})),e}static createProperty(e,t=p){if(t.state&&(t.attribute=!1),this.finalize(),this.elementProperties.set(e,t),!t.noAccessor&&!this.prototype.hasOwnProperty(e)){const i="symbol"==typeof e?Symbol():"__"+e,s=this.getPropertyDescriptor(e,i,t);void 0!==s&&Object.defineProperty(this.prototype,e,s)}}static getPropertyDescriptor(e,t,i){return{get(){return this[t]},set(s){const o=this[e];this[t]=s,this.requestUpdate(e,o,i)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)||p}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const e=Object.getPrototypeOf(this);if(e.finalize(),this.elementProperties=new Map(e.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const e=this.properties,t=[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const i of t)this.createProperty(i,e[i])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const i=new Set(e.flat(1/0).reverse());for(const e of i)t.unshift(n(e))}else void 0!==e&&t.push(n(e));return t}static _$Ep(e,t){const i=t.attribute;return!1===i?void 0:"string"==typeof i?i:"string"==typeof e?e.toLowerCase():void 0}u(){var e;this._$E_=new Promise((e=>this.enableUpdating=e)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(e=this.constructor.h)||void 0===e||e.forEach((e=>e(this)))}addController(e){var t,i;(null!==(t=this._$ES)&&void 0!==t?t:this._$ES=[]).push(e),void 0!==this.renderRoot&&this.isConnected&&(null===(i=e.hostConnected)||void 0===i||i.call(e))}removeController(e){var t;null===(t=this._$ES)||void 0===t||t.splice(this._$ES.indexOf(e)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((e,t)=>{this.hasOwnProperty(t)&&(this._$Ei.set(t,this[t]),delete this[t])}))}createRenderRoot(){var e;const i=null!==(e=this.shadowRoot)&&void 0!==e?e:this.attachShadow(this.constructor.shadowRootOptions);return((e,i)=>{t?e.adoptedStyleSheets=i.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):i.forEach((t=>{const i=document.createElement("style"),s=window.litNonce;void 0!==s&&i.setAttribute("nonce",s),i.textContent=t.cssText,e.appendChild(i)}))})(i,this.constructor.elementStyles),i}connectedCallback(){var e;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostConnected)||void 0===t?void 0:t.call(e)}))}enableUpdating(e){}disconnectedCallback(){var e;null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostDisconnected)||void 0===t?void 0:t.call(e)}))}attributeChangedCallback(e,t,i){this._$AK(e,i)}_$EO(e,t,i=p){var s,o;const r=this.constructor._$Ep(e,i);if(void 0!==r&&!0===i.reflect){const n=(null!==(o=null===(s=i.converter)||void 0===s?void 0:s.toAttribute)&&void 0!==o?o:c.toAttribute)(t,i.type);this._$El=e,null==n?this.removeAttribute(r):this.setAttribute(r,n),this._$El=null}}_$AK(e,t){var i,s;const o=this.constructor,r=o._$Ev.get(e);if(void 0!==r&&this._$El!==r){const e=o.getPropertyOptions(r),n=e.converter,a=null!==(s=null!==(i=null==n?void 0:n.fromAttribute)&&void 0!==i?i:"function"==typeof n?n:null)&&void 0!==s?s:c.fromAttribute;this._$El=r,this[r]=a(t,e.type),this._$El=null}}requestUpdate(e,t,i){let s=!0;void 0!==e&&(((i=i||this.constructor.getPropertyOptions(e)).hasChanged||u)(this[e],t)?(this._$AL.has(e)||this._$AL.set(e,t),!0===i.reflect&&this._$El!==e&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(e,i))):s=!1),!this.isUpdatePending&&s&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var e;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((e,t)=>this[t]=e)),this._$Ei=void 0);let t=!1;const i=this._$AL;try{t=this.shouldUpdate(i),t?(this.willUpdate(i),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostUpdate)||void 0===t?void 0:t.call(e)})),this.update(i)):this._$Ek()}catch(e){throw t=!1,this._$Ek(),e}t&&this._$AE(i)}willUpdate(e){}_$AE(e){var t;null===(t=this._$ES)||void 0===t||t.forEach((e=>{var t;return null===(t=e.hostUpdated)||void 0===t?void 0:t.call(e)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(e){return!0}update(e){void 0!==this._$EC&&(this._$EC.forEach(((e,t)=>this._$EO(t,this[t],e))),this._$EC=void 0),this._$Ek()}updated(e){}firstUpdated(e){}}var v;w.finalized=!0,w.elementProperties=new Map,w.elementStyles=[],w.shadowRootOptions={mode:"open"},null==h||h({ReactiveElement:w}),(null!==(a=globalThis.reactiveElementVersions)&&void 0!==a?a:globalThis.reactiveElementVersions=[]).push("1.3.4");const g=globalThis.trustedTypes,b=g?g.createPolicy("lit-html",{createHTML:e=>e}):void 0,m=`lit$${(Math.random()+"").slice(9)}$`,_="?"+m,f=`<${_}>`,$=document,y=(e="")=>$.createComment(e),A=e=>null===e||"object"!=typeof e&&"function"!=typeof e,S=Array.isArray,E=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,C=/-->/g,x=/>/g,P=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),T=/'/g,k=/"/g,U=/^(?:script|style|textarea|title)$/i,H=(e=>(t,...i)=>({_$litType$:e,strings:t,values:i}))(1),O=Symbol.for("lit-noChange"),B=Symbol.for("lit-nothing"),R=new WeakMap,D=$.createTreeWalker($,129,null,!1),M=(e,t)=>{const i=e.length-1,s=[];let o,r=2===t?"
":"",n=E;for(let t=0;t"===l[0]?(n=null!=o?o:E,d=-1):void 0===l[1]?d=-2:(d=n.lastIndex-l[2].length,a=l[1],n=void 0===l[3]?P:'"'===l[3]?k:T):n===k||n===T?n=P:n===C||n===x?n=E:(n=P,o=void 0);const c=n===P&&e[t+1].startsWith("/>")?" ":"";r+=n===E?i+f:d>=0?(s.push(a),i.slice(0,d)+"$lit$"+i.slice(d)+m+c):i+m+(-2===d?(s.push(void 0),t):c)}const a=r+(e[i]||">")+(2===t?" ":"");if(!Array.isArray(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==b?b.createHTML(a):a,s]};class I{constructor({strings:e,_$litType$:t},i){let s;this.parts=[];let o=0,r=0;const n=e.length-1,a=this.parts,[l,d]=M(e,t);if(this.el=I.createElement(l,i),D.currentNode=this.el.content,2===t){const e=this.el.content,t=e.firstChild;t.remove(),e.append(...t.childNodes)}for(;null!==(s=D.nextNode())&&a.length
0){s.textContent=g?g.emptyScript:"";for(let i=0;iS(e)||"function"==typeof(null==e?void 0:e[Symbol.iterator]))(e)?this.S(e):this.T(e)}j(e,t=this._$AB){return this._$AA.parentNode.insertBefore(e,t)}k(e){this._$AH!==e&&(this._$AR(),this._$AH=this.j(e))}T(e){this._$AH!==B&&A(this._$AH)?this._$AA.nextSibling.data=e:this.k($.createTextNode(e)),this._$AH=e}$(e){var t;const{values:i,_$litType$:s}=e,o="number"==typeof s?this._$AC(e):(void 0===s.el&&(s.el=I.createElement(s.h,this.options)),s);if((null===(t=this._$AH)||void 0===t?void 0:t._$AD)===o)this._$AH.m(i);else{const e=new L(o,this),t=e.p(this.options);e.m(i),this.k(t),this._$AH=e}}_$AC(e){let t=R.get(e.strings);return void 0===t&&R.set(e.strings,t=new I(e)),t}S(e){S(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let i,s=0;for(const o of e)s===t.length?t.push(i=new j(this.j(y()),this.j(y()),this,this.options)):i=t[s],i._$AI(o),s++;s2||""!==i[0]||""!==i[1]?(this._$AH=Array(i.length-1).fill(new String),this.strings=i):this._$AH=B}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,t=this,i,s){const o=this.strings;let r=!1;if(void 0===o)e=N(this,e,t,0),r=!A(e)||e!==this._$AH&&e!==O,r&&(this._$AH=e);else{const s=e;let n,a;for(e=o[0],n=0;n{var s,o;const r=null!==(s=null==i?void 0:i.renderBefore)&&void 0!==s?s:t;let n=r._$litPart$;if(void 0===n){const e=null!==(o=null==i?void 0:i.renderBefore)&&void 0!==o?o:null;r._$litPart$=n=new j(t.insertBefore(y(),e),e,void 0,null!=i?i:{})}return n._$AI(e),n})(t,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallback(),null===(e=this._$Do)||void 0===e||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this._$Do)||void 0===e||e.setConnected(!1)}render(){return O}}Z.finalized=!0,Z._$litElement$=!0,null===(J=globalThis.litElementHydrateSupport)||void 0===J||J.call(globalThis,{LitElement:Z});const Q=globalThis.litElementPolyfillSupport;null==Q||Q({LitElement:Z}),(null!==(Y=globalThis.litElementVersions)&&void 0!==Y?Y:globalThis.litElementVersions=[]).push("3.2.2");const X=(e,t)=>"method"===t.kind&&t.descriptor&&!("value"in t.descriptor)?{...t,finisher(i){i.createProperty(t.key,e)}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:t.key,initializer(){"function"==typeof t.initializer&&(this[t.key]=t.initializer.call(this))},finisher(i){i.createProperty(t.key,e)}};function ee(e){return(t,i)=>void 0!==i?((e,t,i)=>{t.constructor.createProperty(i,e)})(e,t,i):X(e,t)}var te;null===(te=window.HTMLSlotElement)||void 0===te||te.prototype.assignedElements;class ie extends Z{constructor(){super(...arguments),this.dirty=!1}toggleRegister(){var e;(null===(e=window.browser_mod)||void 0===e?void 0:e.connected)&&(window.browser_mod.registered=!window.browser_mod.registered,this.dirty=!0)}changeBrowserID(e){window.browser_mod.browserID=e.target.value,this.dirty=!0}toggleCameraEnabled(){window.browser_mod.cameraEnabled=!window.browser_mod.cameraEnabled,this.dirty=!0}firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}render(){var e,t,i,s,o,r;return H`
+function e(e,t,s,i){var o,n=arguments.length,r=n<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,s):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,s,i);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(r=(n<3?o(r):n>3?o(t,s,r):o(t,s))||r);return n>3&&r&&Object.defineProperty(t,s,r),r}const t=window.ShadowRoot&&(void 0===window.ShadyCSS||window.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,s=Symbol(),i=new WeakMap;class o{constructor(e,t,i){if(this._$cssResult$=!0,i!==s)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=e,this.t=t}get styleSheet(){let e=this.o;const s=this.t;if(t&&void 0===e){const t=void 0!==s&&1===s.length;t&&(e=i.get(s)),void 0===e&&((this.o=e=new CSSStyleSheet).replaceSync(this.cssText),t&&i.set(s,e))}return e}toString(){return this.cssText}}const n=(e,...t)=>{const i=1===e.length?e[0]:t.reduce(((t,s,i)=>t+(e=>{if(!0===e._$cssResult$)return e.cssText;if("number"==typeof e)return e;throw Error("Value passed to 'css' function must be a 'css' function result: "+e+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(s)+e[i+1]),e[0]);return new o(i,e,s)},r=t?e=>e:e=>e instanceof CSSStyleSheet?(e=>{let t="";for(const s of e.cssRules)t+=s.cssText;return(e=>new o("string"==typeof e?e:e+"",void 0,s))(t)})(e):e;var a;const l=window.trustedTypes,d=l?l.emptyScript:"",h=window.reactiveElementPolyfillSupport,c={toAttribute(e,t){switch(t){case Boolean:e=e?d:null;break;case Object:case Array:e=null==e?e:JSON.stringify(e)}return e},fromAttribute(e,t){let s=e;switch(t){case Boolean:s=null!==e;break;case Number:s=null===e?null:Number(e);break;case Object:case Array:try{s=JSON.parse(e)}catch(e){s=null}}return s}},u=(e,t)=>t!==e&&(t==t||e==e),p={attribute:!0,type:String,converter:c,reflect:!1,hasChanged:u};class w extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.u()}static addInitializer(e){var t;null!==(t=this.h)&&void 0!==t||(this.h=[]),this.h.push(e)}static get observedAttributes(){this.finalize();const e=[];return this.elementProperties.forEach(((t,s)=>{const i=this._$Ep(s,t);void 0!==i&&(this._$Ev.set(i,s),e.push(i))})),e}static createProperty(e,t=p){if(t.state&&(t.attribute=!1),this.finalize(),this.elementProperties.set(e,t),!t.noAccessor&&!this.prototype.hasOwnProperty(e)){const s="symbol"==typeof e?Symbol():"__"+e,i=this.getPropertyDescriptor(e,s,t);void 0!==i&&Object.defineProperty(this.prototype,e,i)}}static getPropertyDescriptor(e,t,s){return{get(){return this[t]},set(i){const o=this[e];this[t]=i,this.requestUpdate(e,o,s)},configurable:!0,enumerable:!0}}static getPropertyOptions(e){return this.elementProperties.get(e)||p}static finalize(){if(this.hasOwnProperty("finalized"))return!1;this.finalized=!0;const e=Object.getPrototypeOf(this);if(e.finalize(),this.elementProperties=new Map(e.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const e=this.properties,t=[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)];for(const s of t)this.createProperty(s,e[s])}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(e){const t=[];if(Array.isArray(e)){const s=new Set(e.flat(1/0).reverse());for(const e of s)t.unshift(r(e))}else void 0!==e&&t.push(r(e));return t}static _$Ep(e,t){const s=t.attribute;return!1===s?void 0:"string"==typeof s?s:"string"==typeof e?e.toLowerCase():void 0}u(){var e;this._$E_=new Promise((e=>this.enableUpdating=e)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(e=this.constructor.h)||void 0===e||e.forEach((e=>e(this)))}addController(e){var t,s;(null!==(t=this._$ES)&&void 0!==t?t:this._$ES=[]).push(e),void 0!==this.renderRoot&&this.isConnected&&(null===(s=e.hostConnected)||void 0===s||s.call(e))}removeController(e){var t;null===(t=this._$ES)||void 0===t||t.splice(this._$ES.indexOf(e)>>>0,1)}_$Eg(){this.constructor.elementProperties.forEach(((e,t)=>{this.hasOwnProperty(t)&&(this._$Ei.set(t,this[t]),delete this[t])}))}createRenderRoot(){var e;const s=null!==(e=this.shadowRoot)&&void 0!==e?e:this.attachShadow(this.constructor.shadowRootOptions);return((e,s)=>{t?e.adoptedStyleSheets=s.map((e=>e instanceof CSSStyleSheet?e:e.styleSheet)):s.forEach((t=>{const s=document.createElement("style"),i=window.litNonce;void 0!==i&&s.setAttribute("nonce",i),s.textContent=t.cssText,e.appendChild(s)}))})(s,this.constructor.elementStyles),s}connectedCallback(){var e;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostConnected)||void 0===t?void 0:t.call(e)}))}enableUpdating(e){}disconnectedCallback(){var e;null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostDisconnected)||void 0===t?void 0:t.call(e)}))}attributeChangedCallback(e,t,s){this._$AK(e,s)}_$EO(e,t,s=p){var i,o;const n=this.constructor._$Ep(e,s);if(void 0!==n&&!0===s.reflect){const r=(null!==(o=null===(i=s.converter)||void 0===i?void 0:i.toAttribute)&&void 0!==o?o:c.toAttribute)(t,s.type);this._$El=e,null==r?this.removeAttribute(n):this.setAttribute(n,r),this._$El=null}}_$AK(e,t){var s,i;const o=this.constructor,n=o._$Ev.get(e);if(void 0!==n&&this._$El!==n){const e=o.getPropertyOptions(n),r=e.converter,a=null!==(i=null!==(s=null==r?void 0:r.fromAttribute)&&void 0!==s?s:"function"==typeof r?r:null)&&void 0!==i?i:c.fromAttribute;this._$El=n,this[n]=a(t,e.type),this._$El=null}}requestUpdate(e,t,s){let i=!0;void 0!==e&&(((s=s||this.constructor.getPropertyOptions(e)).hasChanged||u)(this[e],t)?(this._$AL.has(e)||this._$AL.set(e,t),!0===s.reflect&&this._$El!==e&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(e,s))):i=!1),!this.isUpdatePending&&i&&(this._$E_=this._$Ej())}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_}catch(e){Promise.reject(e)}const e=this.scheduleUpdate();return null!=e&&await e,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var e;if(!this.isUpdatePending)return;this.hasUpdated,this._$Ei&&(this._$Ei.forEach(((e,t)=>this[t]=e)),this._$Ei=void 0);let t=!1;const s=this._$AL;try{t=this.shouldUpdate(s),t?(this.willUpdate(s),null===(e=this._$ES)||void 0===e||e.forEach((e=>{var t;return null===(t=e.hostUpdate)||void 0===t?void 0:t.call(e)})),this.update(s)):this._$Ek()}catch(e){throw t=!1,this._$Ek(),e}t&&this._$AE(s)}willUpdate(e){}_$AE(e){var t;null===(t=this._$ES)||void 0===t||t.forEach((e=>{var t;return null===(t=e.hostUpdated)||void 0===t?void 0:t.call(e)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(e)),this.updated(e)}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(e){return!0}update(e){void 0!==this._$EC&&(this._$EC.forEach(((e,t)=>this._$EO(t,this[t],e))),this._$EC=void 0),this._$Ek()}updated(e){}firstUpdated(e){}}var g;w.finalized=!0,w.elementProperties=new Map,w.elementStyles=[],w.shadowRootOptions={mode:"open"},null==h||h({ReactiveElement:w}),(null!==(a=globalThis.reactiveElementVersions)&&void 0!==a?a:globalThis.reactiveElementVersions=[]).push("1.3.4");const v=globalThis.trustedTypes,b=v?v.createPolicy("lit-html",{createHTML:e=>e}):void 0,m=`lit$${(Math.random()+"").slice(9)}$`,f="?"+m,y=`<${f}>`,_=document,$=(e="")=>_.createComment(e),S=e=>null===e||"object"!=typeof e&&"function"!=typeof e,A=Array.isArray,E=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,x=/-->/g,P=/>/g,C=RegExp(">|[ \t\n\f\r](?:([^\\s\"'>=/]+)([ \t\n\f\r]*=[ \t\n\f\r]*(?:[^ \t\n\f\r\"'`<>=]|(\"|')|))|$)","g"),O=/'/g,T=/"/g,U=/^(?:script|style|textarea|title)$/i,k=(e=>(t,...s)=>({_$litType$:e,strings:t,values:s}))(1),H=Symbol.for("lit-noChange"),R=Symbol.for("lit-nothing"),D=new WeakMap,B=_.createTreeWalker(_,129,null,!1),M=(e,t)=>{const s=e.length-1,i=[];let o,n=2===t?"":"",r=E;for(let t=0;t"===l[0]?(r=null!=o?o:E,d=-1):void 0===l[1]?d=-2:(d=r.lastIndex-l[2].length,a=l[1],r=void 0===l[3]?C:'"'===l[3]?T:O):r===T||r===O?r=C:r===x||r===P?r=E:(r=C,o=void 0);const c=r===C&&e[t+1].startsWith("/>")?" ":"";n+=r===E?s+y:d>=0?(i.push(a),s.slice(0,d)+"$lit$"+s.slice(d)+m+c):s+m+(-2===d?(i.push(void 0),t):c)}const a=n+(e[s]||">")+(2===t?" ":"");if(!Array.isArray(e)||!e.hasOwnProperty("raw"))throw Error("invalid template strings array");return[void 0!==b?b.createHTML(a):a,i]};class N{constructor({strings:e,_$litType$:t},s){let i;this.parts=[];let o=0,n=0;const r=e.length-1,a=this.parts,[l,d]=M(e,t);if(this.el=N.createElement(l,s),B.currentNode=this.el.content,2===t){const e=this.el.content,t=e.firstChild;t.remove(),e.append(...t.childNodes)}for(;null!==(i=B.nextNode())&&a.length0){i.textContent=v?v.emptyScript:"";for(let s=0;sA(e)||"function"==typeof(null==e?void 0:e[Symbol.iterator]))(e)?this.S(e):this.T(e)}j(e,t=this._$AB){return this._$AA.parentNode.insertBefore(e,t)}k(e){this._$AH!==e&&(this._$AR(),this._$AH=this.j(e))}T(e){this._$AH!==R&&S(this._$AH)?this._$AA.nextSibling.data=e:this.k(_.createTextNode(e)),this._$AH=e}$(e){var t;const{values:s,_$litType$:i}=e,o="number"==typeof i?this._$AC(e):(void 0===i.el&&(i.el=N.createElement(i.h,this.options)),i);if((null===(t=this._$AH)||void 0===t?void 0:t._$AD)===o)this._$AH.m(s);else{const e=new L(o,this),t=e.p(this.options);e.m(s),this.k(t),this._$AH=e}}_$AC(e){let t=D.get(e.strings);return void 0===t&&D.set(e.strings,t=new N(e)),t}S(e){A(this._$AH)||(this._$AH=[],this._$AR());const t=this._$AH;let s,i=0;for(const o of e)i===t.length?t.push(s=new K(this.j($()),this.j($()),this,this.options)):s=t[i],s._$AI(o),i++;i2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=R}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(e,t=this,s,i){const o=this.strings;let n=!1;if(void 0===o)e=I(this,e,t,0),n=!S(e)||e!==this._$AH&&e!==H,n&&(this._$AH=e);else{const i=e;let r,a;for(e=o[0],r=0;r{var i,o;const n=null!==(i=null==s?void 0:s.renderBefore)&&void 0!==i?i:t;let r=n._$litPart$;if(void 0===r){const e=null!==(o=null==s?void 0:s.renderBefore)&&void 0!==o?o:null;n._$litPart$=r=new K(t.insertBefore($(),e),e,void 0,null!=s?s:{})}return r._$AI(e),r})(t,this.renderRoot,this.renderOptions)}connectedCallback(){var e;super.connectedCallback(),null===(e=this._$Do)||void 0===e||e.setConnected(!0)}disconnectedCallback(){var e;super.disconnectedCallback(),null===(e=this._$Do)||void 0===e||e.setConnected(!1)}render(){return H}}Z.finalized=!0,Z._$litElement$=!0,null===(Y=globalThis.litElementHydrateSupport)||void 0===Y||Y.call(globalThis,{LitElement:Z});const Q=globalThis.litElementPolyfillSupport;null==Q||Q({LitElement:Z}),(null!==(G=globalThis.litElementVersions)&&void 0!==G?G:globalThis.litElementVersions=[]).push("3.2.2");const X=(e,t)=>"method"===t.kind&&t.descriptor&&!("value"in t.descriptor)?{...t,finisher(s){s.createProperty(t.key,e)}}:{kind:"field",key:Symbol(),placement:"own",descriptor:{},originalKey:t.key,initializer(){"function"==typeof t.initializer&&(this[t.key]=t.initializer.call(this))},finisher(s){s.createProperty(t.key,e)}};function ee(e){return(t,s)=>void 0!==s?((e,t,s)=>{t.constructor.createProperty(s,e)})(e,t,s):X(e,t)}function te(e){return ee({...e,state:!0})}var se;null===(se=window.HTMLSlotElement)||void 0===se||se.prototype.assignedElements;async function ie(e,t=!1){var s;if((null===(s=e.localName)||void 0===s?void 0:s.includes("-"))&&await customElements.whenDefined(e.localName),e.updateComplete&&await e.updateComplete,t&&(e.pageRendered&&await e.pageRendered,e._panelState)){let t=0;for(;"loaded"!==e._panelState&&t++<5;)await new Promise((e=>setTimeout(e,100)))}}async function oe(e,t,s=!1){let i=[e];for("string"==typeof t&&(t=t.split(/(\$| )/));""===t[t.length-1];)t.pop();for(const[e,s]of t.entries()){const e=i[0];if(!e)return null;s.trim().length&&(ie(e),i="$"===s?[e.shadowRoot]:e.querySelectorAll(s))}return s?i:i[0]}async function ne(e,t,s=!1,i=1e4){return Promise.race([oe(e,t,s),new Promise(((e,t)=>setTimeout((()=>t(new Error("SELECTTREE-TIMEOUT"))),i)))]).catch((e=>{if(!e.message||"SELECTTREE-TIMEOUT"!==e.message)throw e;return null}))}class re extends Z{constructor(){super(...arguments),this.dirty=!1}toggleRegister(){var e;(null===(e=window.browser_mod)||void 0===e?void 0:e.connected)&&(window.browser_mod.registered=!window.browser_mod.registered,this.dirty=!0)}changeBrowserID(e){window.browser_mod.browserID=e.target.value,this.dirty=!0}toggleCameraEnabled(){window.browser_mod.cameraEnabled=!window.browser_mod.cameraEnabled,this.dirty=!0}firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}render(){var e,t,s,i,o,n;return k`
- `}_renderSuspensionAlert(){return this.hass.suspendWhenHidden?H`
+ `}_renderSuspensionAlert(){return this.hass.suspendWhenHidden?k`
Home Assistant will close the websocket connection to the server
automatically after 5 minutes of inactivity.
@@ -88,9 +88,9 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
and disabling the option
"${this.hass.localize("ui.panel.profile.suspend.header")||"Automatically close connection"}".
- `:H``}_renderInteractionAlert(){return H`
+ `:k``}_renderInteractionAlert(){return k`
- For security reasons many browsers require the user to interact with a
+ For privacy reasons many browsers require the user to interact with a
webpage before allowing audio playback or video capture. This may affect
the
media_player and camera components of Browser
@@ -101,33 +101,33 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
corner of the screen, please tap or click anywhere on the page. This
should allow Browser Mod to work again.
- `}_renderFKBSettingsInfo(){var e,t;return(null===(e=window.browser_mod)||void 0===e?void 0:e.fully)&&this.getFullySettings()?H`
- ${(null===(t=window.browser_mod)||void 0===t?void 0:t.fully)&&this.getFullySettings()?H`
+ `}_renderFKBSettingsInfo(){var e,t;return(null===(e=window.browser_mod)||void 0===e?void 0:e.fully)&&this.getFullySettings()?k`
+ ${(null===(t=window.browser_mod)||void 0===t?void 0:t.fully)&&this.getFullySettings()?k`
You are using FullyKiosk Browser. It is recommended to enable the
following settings:
${this.getFullySettings()}
`:""}
- `:H``}getFullySettings(){if(!window.browser_mod.fully)return null;const e=[],t=[];"true"!==window.fully.getBooleanSetting("autoplayVideos")&&t.push(H`Autoplay Videos `),"true"!==window.fully.getBooleanSetting("autoplayAudio")&&t.push(H`Autoplay Audio `),"true"!==window.fully.getBooleanSetting("webcamAccess")&&t.push(H`Enable Webcam Access (PLUS) `),0!==t.length&&e.push(H`Web Content Settings
+ `:k``}getFullySettings(){if(!window.browser_mod.fully)return null;const e=[],t=[];"true"!==window.fully.getBooleanSetting("autoplayVideos")&&t.push(k`Autoplay Videos `),"true"!==window.fully.getBooleanSetting("autoplayAudio")&&t.push(k`Autoplay Audio `),"true"!==window.fully.getBooleanSetting("webcamAccess")&&t.push(k`Enable Webcam Access (PLUS) `),0!==t.length&&e.push(k`Web Content Settings
`),"true"!==window.fully.getBooleanSetting("websiteIntegration")&&e.push(H`Advanced Web Settings
+ `),"true"!==window.fully.getBooleanSetting("websiteIntegration")&&e.push(k`Advanced Web Settings
Enable JavaScript Interface (PLUS)
- `),"true"!==window.fully.getBooleanSetting("keepScreenOn")&&e.push(H`Device Management
+ `),"true"!==window.fully.getBooleanSetting("keepScreenOn")&&e.push(k`Device Management
`),"true"!==window.fully.getBooleanSetting("preventSleepWhileScreenOff")&&e.push(H`Power Settings
+ `),"true"!==window.fully.getBooleanSetting("preventSleepWhileScreenOff")&&e.push(k`Power Settings
Prevent from Sleep while Screen Off
- `);const i=[];return"true"!==window.fully.getBooleanSetting("motionDetection")&&i.push(H`Enable Visual Motion Detection `),"true"!==window.fully.getBooleanSetting("screenOnOnMotion")&&i.push(H`Turn Screen On on Motion `),"true"!==window.fully.getBooleanSetting("stopScreensaverOnMotion")&&i.push(H`Exit Screensaver on Motion `),0!==i.length&&e.push(H`Motion Detection (PLUS)
+ `);const s=[];return"true"!==window.fully.getBooleanSetting("motionDetection")&&s.push(k`Enable Visual Motion Detection `),"true"!==window.fully.getBooleanSetting("screenOnOnMotion")&&s.push(k`Turn Screen On on Motion `),"true"!==window.fully.getBooleanSetting("stopScreensaverOnMotion")&&s.push(k`Exit Screensaver on Motion `),0!==s.length&&e.push(k`Motion Detection (PLUS)
`),"true"!==window.fully.getBooleanSetting("remoteAdmin")&&e.push(H`Remote Administration (PLUS)
+ ${s}
+ `),"true"!==window.fully.getBooleanSetting("remoteAdmin")&&e.push(k`Remote Administration (PLUS)
Enable Remote Administration
- `),e.length?e:null}static get styles(){return r`
+ `),e.length?e:null}static get styles(){return n`
.card-header {
display: flex;
justify-content: space-between;
@@ -137,10 +137,10 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
display: block;
margin-top: 8px;
}
- `}}e([ee()],ie.prototype,"hass",void 0),e([ee()],ie.prototype,"dirty",void 0),customElements.define("browser-mod-browser-settings-card",ie);class se extends Z{firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}unregister_browser(e){const t=e.currentTarget.browserID;window.browser_mod.showPopup("Unregister browser",`Are you sure you want to unregister Browser ${t}?`,{right_button:"Yes",right_button_action:()=>{t===window.browser_mod.browserID?window.browser_mod.registered=!1:window.browser_mod.connection.sendMessage({type:"browser_mod/unregister",browserID:t})},left_button:"No"})}register_cast(){window.browser_mod.connection.sendMessage({type:"browser_mod/register",browserID:"CAST"})}render(){return H`
+ `}}e([ee()],re.prototype,"hass",void 0),e([ee()],re.prototype,"dirty",void 0),customElements.define("browser-mod-browser-settings-card",re);class ae extends Z{firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}unregister_browser(e){const t=e.currentTarget.browserID;window.browser_mod.showPopup("Unregister browser",`Are you sure you want to unregister Browser ${t}?`,{right_button:"Yes",right_button_action:()=>{t===window.browser_mod.browserID?window.browser_mod.registered=!1:window.browser_mod.connection.sendMessage({type:"browser_mod/unregister",browserID:t})},left_button:"No"})}register_cast(){window.browser_mod.connection.sendMessage({type:"browser_mod/register",browserID:"CAST"})}render(){return k`
- ${Object.keys(window.browser_mod.browsers).map((e=>H`
+ ${Object.keys(window.browser_mod.browsers).map((e=>k`
${e}
Last connected:
@@ -154,7 +154,7 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
`))}
- ${void 0===window.browser_mod.browsers.CAST?H`
+ ${void 0===window.browser_mod.browsers.CAST?k`
Register CAST Browser
@@ -162,196 +162,182 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
`:""}
- `}static get styles(){return r`
+ `}static get styles(){return n`
ha-icon-button > * {
display: flex;
}
- `}}e([ee()],se.prototype,"hass",void 0),customElements.define("browser-mod-registered-browsers-card",se),(async()=>{var e,t,i,s,o,r,n;await customElements.whenDefined("partial-panel-resolver"),await customElements.whenDefined("partial-panel-resolver");const a=document.createElement("partial-panel-resolver").getRoutes([{component_name:"developer-tools",url_path:"a"}]);await(null===(i=null===(t=null===(e=null==a?void 0:a.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===i?void 0:i.call(t));const l=document.createElement("developer-tools-router");await(null===(n=null===(r=null===(o=null===(s=null==l?void 0:l.routerOptions)||void 0===s?void 0:s.routes)||void 0===o?void 0:o.template)||void 0===r?void 0:r.load)||void 0===n?void 0:n.call(r)),await customElements.whenDefined("developer-tools-template")})();class oe extends Z{constructor(){super(...arguments),this._selectedTab=0}firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate())),window.browser_mod.addEventListener("browser-mod-favicon-update",(()=>this.requestUpdate()))}_handleSwitchTab(e){this._selectedTab=parseInt(e.detail.index,10)}render(){const e=["user","browser","global"][this._selectedTab];return H`
+ `}}e([ee()],ae.prototype,"hass",void 0),customElements.define("browser-mod-registered-browsers-card",ae);class le extends Z{constructor(){super(...arguments),this.settingSelector={template:{}},this.tableData=[],this._users=void 0}firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.updateTable()))}updated(e){e.has("settingKey")&&this.updateTable(),e.has("hass")&&void 0===e.get("hass")&&this.updateTable()}async fetchUsers(){return void 0===this._users&&(this._users=await this.hass.callWS({type:"config/auth/list"})),this._users}clearSetting(e,t){var s;null===(s=window.browser_mod)||void 0===s||s.showPopup("Are you sure","Do you wish to clear this setting?",{right_button:"Yes",right_button_action:async()=>{if("sidebarPanelOrder"===this.settingKey)return await ne(document,"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"),window.browser_mod.setSetting(e,t,{sidebarHiddenPanels:"[]",sidebarPanelOrder:"[]"}),void window.browser_mod.setSetting(e,t,{sidebarHiddenPanels:void 0,sidebarPanelOrder:void 0});this.default&&window.browser_mod.setSetting(e,t,{[this.settingKey]:this.default}),window.browser_mod.setSetting(e,t,{[this.settingKey]:void 0})},left_button:"No"})}changeSetting(e,t){var s,i,o,n,r,a;const l=null===(i=null===(s=window.browser_mod)||void 0===s?void 0:s.getSetting)||void 0===i?void 0:i.call(s,this.settingKey),d=null!==(o="global"===e?l.global:l[e][t])&&void 0!==o?o:this.default;null===(n=window.browser_mod)||void 0===n||n.showPopup("Change value",null!==(r=this.settingSelector.plaintext)&&void 0!==r?r:[{name:"value",label:null!==(a=this.settingSelector.label)&&void 0!==a?a:"",default:d,selector:this.settingSelector}],{right_button:"OK",right_button_action:async s=>{if("sidebarPanelOrder"===this.settingKey){const s=await ne(document,"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar");return window.browser_mod.setSetting(e,t,{sidebarHiddenPanels:JSON.stringify(s._hiddenPanels),sidebarPanelOrder:JSON.stringify(s._panelOrder)}),void console.log(s._hiddenPanels,s._panelOrder)}let i=s.value;window.browser_mod.setSetting(e,t,{[this.settingKey]:i})},left_button:"Cancel"})}addBrowserSetting(){var e,t;const s=null===(t=null===(e=window.browser_mod)||void 0===e?void 0:e.getSetting)||void 0===t?void 0:t.call(e,this.settingKey),i=window.browser_mod._data.browsers,o=[];for(const e of Object.keys(i))null==s.browser[e]&&o.push(e);0!==o.length?window.browser_mod.showPopup("Select browser to configure",[{name:"browser",label:"",selector:{select:{options:o}}}],{right_button:"Next",right_button_action:e=>this.changeSetting("browser",e.browser),left_button:"Cancel"}):window.browser_mod.showPopup("No browsers to configure","All registered browsers have already been configured.",{right_button:"OK"})}async addUserSetting(){var e,t;const s=null===(t=null===(e=window.browser_mod)||void 0===e?void 0:e.getSetting)||void 0===t?void 0:t.call(e,this.settingKey),i=await this.fetchUsers(),o=[];for(const e of i)e.username&&null==s.user[e.id]&&o.push({label:e.name,value:e.id});0!==o.length?window.browser_mod.showPopup("Select user to configure",[{name:"user",label:"",selector:{select:{options:o}}}],{right_button:"Next",right_button_action:e=>this.changeSetting("user",e.user),left_button:"Cancel"}):window.browser_mod.showPopup("No users to configure","All users have already been configured.",{right_button:"OK"})}async updateTable(){var e,t;if(void 0===this.hass)return;const s=await this.fetchUsers(),i=null===(t=null===(e=window.browser_mod)||void 0===e?void 0:e.getSetting)||void 0===t?void 0:t.call(e,this.settingKey),o=[];for(const[e,t]of Object.entries(i.user)){const i=s.find((t=>t.id===e));o.push({name:`User: ${i.name}`,value:String(t),controls:k`
+ this.changeSetting("user",e)}>
+
+
+ this.clearSetting("user",e)}>
+
+
+ `})}o.push({name:"",value:k`
+ this.addUserSetting()}>
+
+ Add user setting
+
+ `});for(const[e,t]of Object.entries(i.browser))o.push({name:`Browser: ${e}`,value:String(t),controls:k`
+ this.changeSetting("browser",e)}>
+
+
+ this.clearSetting("browser",e)}>
+
+
+ `});o.push({name:"",value:k`
+ this.addBrowserSetting()}>
+
+ Add browser setting
+
+ `}),o.push({name:"GLOBAL",value:null!=i.global?String(i.global):k`DEFAULT `,controls:k`
+ this.changeSetting("global",null)}>
+
+
+ this.clearSetting("global",null)}>
+
+
+ `}),this.tableData=o}render(){var e,t;null===(t=null===(e=window.browser_mod)||void 0===e?void 0:e.global_settings)||void 0===t||t[this.settingKey];return k`
+
+
+ `}static get styles(){return n`
+ :host {
+ display: block;
+ }
+ `}}e([ee()],le.prototype,"settingKey",void 0),e([ee()],le.prototype,"settingSelector",void 0),e([ee()],le.prototype,"hass",void 0),e([ee()],le.prototype,"default",void 0),e([ee()],le.prototype,"tableData",void 0),customElements.define("browser-mod-settings-table",le),(async()=>{var e,t,s,i,o,n,r;await customElements.whenDefined("partial-panel-resolver"),await customElements.whenDefined("partial-panel-resolver");const a=document.createElement("partial-panel-resolver").getRoutes([{component_name:"developer-tools",url_path:"a"}]);await(null===(s=null===(t=null===(e=null==a?void 0:a.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===s?void 0:s.call(t));const l=document.createElement("developer-tools-router");await(null===(r=null===(n=null===(o=null===(i=null==l?void 0:l.routerOptions)||void 0===i?void 0:i.routes)||void 0===o?void 0:o.template)||void 0===n?void 0:n.load)||void 0===r?void 0:r.call(n)),await customElements.whenDefined("developer-tools-template")})();class de extends Z{constructor(){super(...arguments),this._dashboards=[],this._editSidebar=!1,this._savedSidebar={panelOrder:[],hiddenPanels:[]}}firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}updated(e){e.has("hass")&&void 0===e.get("hass")&&(async()=>{this._dashboards=await this.hass.callWS({type:"lovelace/dashboards/list"})})()}async toggleEditSidebar(){var e,t;const s=await ne(document,"home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar");s.editMode=!s.editMode,this._editSidebar=s.editMode,this._editSidebar?this._savedSidebar={panelOrder:s._panelOrder,hiddenPanels:s._hiddenPanels}:(s._panelOrder=null!==(e=this._savedSidebar.panelOrder)&&void 0!==e?e:[],s._hiddenPanels=null!==(t=this._savedSidebar.hiddenPanels)&&void 0!==t?t:[],this._savedSidebar={panelOrder:[],hiddenPanels:[]})}render(){const e=this._dashboards.map((e=>({value:e.url_path,label:e.title}))),t={select:{options:[{value:"lovelace",label:"lovelace (default)"},...e],custom_value:!0}};return k`
-
-
- Please note: The settings in this section severely change the way the Home
+
+ The settings in this section severely change the way the Home
Assistant frontend works and looks. It is very easy to forget that
you made a setting here when you switch devices or user.
-
-
- Do not report any issues to Home Assistant before clearing
- EVERY setting here and thouroghly clearing all your browser
- caches. Failure to do so means you risk wasting a lot of peoples
- time, and you will be severly and rightfully ridiculed.
-
+
+ Do not report any issues to Home Assistant before clearing
+ EVERY setting here and thouroghly clearing all your browser
+ caches. Failure to do so means you risk wasting a lot of peoples
+ time, and you will be severly and rightfully ridiculed.
+
- Global settings are applied for all users and browsers.
- User settings are applied to the current user and overrides any Global settings.
- Browser settings are applied for the current browser and overrides any User or Global settings.
+ Settings below are applied by first match. I.e. if a matching User
+ setting exists, it will be applied. Otherwise any matching Browser
+ setting and otherwise the GLOBAL setting if that differs from
+ DEFAULT.
-
-
-
-
-
-
-
- ${this._render_settings(e)}
+
+
+
+ Title template
+
+ Jinja template for the browser window/tab title
+
+
+
+
+
+
+
+ Favicon template
+
+ Jinja template for the browser favicon
+
+
+
+
+
+
+
+ Hide sidebar
+
+ Completely remove the sidebar from all panels
+
+
+
+
+
+
+
+ Hide header
+
+ Completely remove the header from all panels
+
+
+
+
+
+
+
+ Default dashboard
+
+ The dashboard that is showed when navigating to
+ ${location.origin}/
+
+
+
+
+
+
+
+ Sidebar order
+
+ Order and visibility of sidebar items. Click EDIT and set
+ the sidebar up as you want. Then save the settings and finally
+ click RESTORE.
+
+ this.toggleEditSidebar()}>
+ ${this._editSidebar?"Restore":"Edit"}
+
+
+
+
+
+
+
+ Sidebar title
+
+ The title at the top of the sidebar
+
+
+
- `}_render_settings(e){const t=window.browser_mod.global_settings,i=window.browser_mod.browser_settings,s=window.browser_mod.user_settings,o={global:t,browser:i,user:s}[e],r=e=>({true:"Enabled",false:"Disabled",undefined:"Unset"}[String(e)]),n=e=>void 0===e?"Unset":"Set",a=t=>"browser"!==e&&void 0!==i[t]?H` Overridden by browser setting`:"global"===e&&void 0!==s[t]?H` Overridden by user setting`:void 0;return H`
-
-
- Favicon template
- ${a("faviconTemplate")}
-
-
-
{const i=t.detail.value||void 0;window.browser_mod.set_setting("faviconTemplate",i,e)}}
- >
-
- window.browser_mod.set_setting("faviconTemplate",void 0,e)}
- >
- Clear
-
-
-
-
-
-
- Title template
- ${a("titleTemplate")}
-
-
{const i=t.detail.value||void 0;window.browser_mod.set_setting("titleTemplate",i,e)}}
- >
-
- window.browser_mod.set_setting("titleTemplate",void 0,e)}
- >
- Clear
-
-
-
-
-
-
- Hide Sidebar
- Hide the sidebar and hamburger menu
- Currently: ${r(o.hideSidebar)}
- ${a("hideSidebar")}
-
-
- window.browser_mod.set_setting("hideSidebar",!0,e)}
- >
- Enable
-
- window.browser_mod.set_setting("hideSidebar",!1,e)}
- >
- Disable
-
- window.browser_mod.set_setting("hideSidebar",void 0,e)}
- >
- Clear
-
-
-
-
-
-
- Hide Header
- Hide the header on all pages
- Currently: ${r(o.hideHeader)}
- ${a("hideHeader")}
-
-
- window.browser_mod.set_setting("hideHeader",!0,e)}
- >
- Enable
-
- window.browser_mod.set_setting("hideHeader",!1,e)}
- >
- Disable
-
- window.browser_mod.set_setting("hideHeader",void 0,e)}
- >
- Clear
-
-
-
-
-
-
- Sidebar order
-
- Order and visibility of sidebar buttons
-
- Currently: ${n(o.sidebarPanelOrder)}
- ${a("sidebarPanelOrder")}
-
-
-
- Clearing this does NOT restore the original default order.
-
- {window.browser_mod.set_setting("sidebarPanelOrder",localStorage.getItem("sidebarPanelOrder"),e),window.browser_mod.set_setting("sidebarHiddenPanels",localStorage.getItem("sidebarHiddenPanels"),e)}}
- >
- Set
-
- {window.browser_mod.set_setting("sidebarPanelOrder",void 0,e),window.browser_mod.set_setting("sidebarHiddenPanels",void 0,e)}}
- >
- Clear
-
-
-
-
-
-
- Default dashboard
- The dashboard that's displayed by default
- Currently: ${n(o.defaultPanel)}
- ${a("defaultPanel")}
-
-
-
- Clearing this does NOT restore the original default dashboard.
-
- {window.browser_mod.set_setting("defaultPanel",localStorage.getItem("defaultPanel"),e)}}
- >
- Set
-
- {window.browser_mod.set_setting("defaultPanel",void 0,e)}}
- >
- Clear
-
-
-
- `}static get styles(){return r`
+ `}static get styles(){return n`
.box {
border: 1px solid var(--divider-color);
padding: 8px;
}
.separator {
border-bottom: 1px solid var(--divider-color);
- margin: 0 -8px;
+ margin: 16px -16px 0px;
}
img.favicon {
width: 64px;
@@ -362,7 +348,7 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
display: flex;
align-items: center;
}
- `}}e([ee()],oe.prototype,"hass",void 0),e([function(e){return ee({...e,state:!0})}()],oe.prototype,"_selectedTab",void 0),customElements.define("browser-mod-frontend-settings-card",oe),(async()=>{var e,t,i,s,o,r,n,a,l,d,h;await customElements.whenDefined("partial-panel-resolver");const c=document.createElement("partial-panel-resolver").getRoutes([{component_name:"config",url_path:"a"}]);await(null===(i=null===(t=null===(e=null==c?void 0:c.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===i?void 0:i.call(t)),await customElements.whenDefined("ha-panel-config");const u=document.createElement("ha-panel-config");await(null===(n=null===(r=null===(o=null===(s=null==u?void 0:u.routerOptions)||void 0===s?void 0:s.routes)||void 0===o?void 0:o.dashboard)||void 0===r?void 0:r.load)||void 0===n?void 0:n.call(r)),await(null===(h=null===(d=null===(l=null===(a=null==u?void 0:u.routerOptions)||void 0===a?void 0:a.routes)||void 0===l?void 0:l.cloud)||void 0===d?void 0:d.load)||void 0===h?void 0:h.call(d)),await customElements.whenDefined("ha-config-dashboard")})().then((()=>{class t extends Z{firstUpdated(){window.browser_mod.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}render(){return H`
+ `}}e([ee()],de.prototype,"hass",void 0),e([te()],de.prototype,"_dashboards",void 0),e([te()],de.prototype,"_editSidebar",void 0),customElements.define("browser-mod-frontend-settings-card",de),(async()=>{var e,t,s,i,o,n,r,a,l,d,h,c,u,p,w;await customElements.whenDefined("partial-panel-resolver");const g=document.createElement("partial-panel-resolver").getRoutes([{component_name:"config",url_path:"a"}]);await(null===(s=null===(t=null===(e=null==g?void 0:g.routes)||void 0===e?void 0:e.a)||void 0===t?void 0:t.load)||void 0===s?void 0:s.call(t)),await customElements.whenDefined("ha-panel-config");const v=document.createElement("ha-panel-config");await(null===(r=null===(n=null===(o=null===(i=null==v?void 0:v.routerOptions)||void 0===i?void 0:i.routes)||void 0===o?void 0:o.dashboard)||void 0===n?void 0:n.load)||void 0===r?void 0:r.call(n)),await(null===(h=null===(d=null===(l=null===(a=null==v?void 0:v.routerOptions)||void 0===a?void 0:a.routes)||void 0===l?void 0:l.cloud)||void 0===d?void 0:d.load)||void 0===h?void 0:h.call(d)),await(null===(w=null===(p=null===(u=null===(c=null==v?void 0:v.routerOptions)||void 0===c?void 0:c.routes)||void 0===u?void 0:u.entities)||void 0===p?void 0:p.load)||void 0===w?void 0:w.call(p)),await customElements.whenDefined("ha-config-dashboard")})().then((()=>{class t extends Z{firstUpdated(){window.addEventListener("browser-mod-config-update",(()=>this.requestUpdate()))}render(){return window.browser_mod?k`
@@ -388,7 +374,7 @@ function e(e,t,i,s){var o,r=arguments.length,n=r<3?t:null===s?s=Object.getOwnPro
>
- `}static get styles(){var e,t;return[...null!==(t=null===(e=customElements.get("ha-config-dashboard"))||void 0===e?void 0:e.styles)&&void 0!==t?t:[],r`
+ `:k``}static get styles(){var e,t;return[...null!==(t=null===(e=customElements.get("ha-config-dashboard"))||void 0===e?void 0:e.styles)&&void 0!==t?t:[],n`
:host {
--app-header-background-color: var(--sidebar-background-color);
--app-header-text-color: var(--sidebar-text-color);
diff --git a/custom_components/browser_mod/manifest.json b/custom_components/browser_mod/manifest.json
index edc90c0..e5846d4 100644
--- a/custom_components/browser_mod/manifest.json
+++ b/custom_components/browser_mod/manifest.json
@@ -5,7 +5,7 @@
"dependencies": ["panel_custom", "websocket_api", "http", "frontend", "lovelace"],
"codeowners": [],
"requirements": [],
- "version": "2.0.0b4",
+ "version": "2.0.0b5",
"iot_class": "local_push",
"config_flow": true
}
diff --git a/custom_components/browser_mod/store.py b/custom_components/browser_mod/store.py
index 648aa38..8a24554 100644
--- a/custom_components/browser_mod/store.py
+++ b/custom_components/browser_mod/store.py
@@ -16,6 +16,7 @@ class SettingsStoreData:
defaultPanel = attr.ib(type=str, default=None)
sidebarPanelOrder = attr.ib(type=list, default=None)
sidebarHiddenPanels = attr.ib(type=list, default=None)
+ sidebarTitle = attr.ib(type=str, default=None)
faviconTemplate = attr.ib(type=str, default=None)
titleTemplate = attr.ib(type=str, default=None)
diff --git a/js/config_panel/browser-mod-settings-table.ts b/js/config_panel/browser-mod-settings-table.ts
new file mode 100644
index 0000000..d0d0821
--- /dev/null
+++ b/js/config_panel/browser-mod-settings-table.ts
@@ -0,0 +1,294 @@
+import { LitElement, html, css } from "lit";
+import { property } from "lit/decorators.js";
+import { selectTree } from "../helpers";
+
+class BrowserModSettingsTable extends LitElement {
+ @property() settingKey;
+ @property() settingSelector = {
+ template: {},
+ };
+
+ @property() hass;
+ @property() default;
+
+ @property() tableData = [];
+
+ _users = undefined;
+
+ firstUpdated() {
+ window.browser_mod.addEventListener("browser-mod-config-update", () =>
+ this.updateTable()
+ );
+ }
+
+ updated(changedProperties) {
+ if (changedProperties.has("settingKey")) this.updateTable();
+ if (
+ changedProperties.has("hass") &&
+ changedProperties.get("hass") === undefined
+ )
+ this.updateTable();
+ }
+
+ async fetchUsers(): Promise {
+ if (this._users === undefined)
+ this._users = await this.hass.callWS({ type: "config/auth/list" });
+ return this._users;
+ }
+
+ clearSetting(type, target) {
+ const clearSettingCallback = async () => {
+ if (this.settingKey === "sidebarPanelOrder") {
+ const sideBar: any = await selectTree(
+ document,
+ "home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
+ );
+ window.browser_mod.setSetting(type, target, {
+ sidebarHiddenPanels: "[]",
+ sidebarPanelOrder: "[]",
+ });
+ window.browser_mod.setSetting(type, target, {
+ sidebarHiddenPanels: undefined,
+ sidebarPanelOrder: undefined,
+ });
+ return;
+ }
+ if (this.default)
+ window.browser_mod.setSetting(type, target, {
+ [this.settingKey]: this.default,
+ });
+ window.browser_mod.setSetting(type, target, {
+ [this.settingKey]: undefined,
+ });
+ };
+ window.browser_mod?.showPopup(
+ "Are you sure",
+ "Do you wish to clear this setting?",
+ {
+ right_button: "Yes",
+ right_button_action: clearSettingCallback,
+ left_button: "No",
+ }
+ );
+ }
+
+ changeSetting(type, target) {
+ const changeSettingCallback = async (newValue) => {
+ if (this.settingKey === "sidebarPanelOrder") {
+ const sideBar: any = await selectTree(
+ document,
+ "home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
+ );
+
+ window.browser_mod.setSetting(type, target, {
+ sidebarHiddenPanels: JSON.stringify(sideBar._hiddenPanels),
+ sidebarPanelOrder: JSON.stringify(sideBar._panelOrder),
+ });
+
+ console.log(sideBar._hiddenPanels, sideBar._panelOrder);
+ return;
+ }
+ let value = newValue.value;
+ window.browser_mod.setSetting(type, target, { [this.settingKey]: value });
+ };
+
+ const settings = window.browser_mod?.getSetting?.(this.settingKey);
+ const def =
+ (type === "global" ? settings.global : settings[type][target]) ??
+ this.default;
+ window.browser_mod?.showPopup(
+ "Change value",
+ (this.settingSelector as any).plaintext ?? [
+ {
+ name: "value",
+ label: (this.settingSelector as any).label ?? "",
+ default: def,
+ selector: this.settingSelector,
+ },
+ ],
+ {
+ right_button: "OK",
+ right_button_action: changeSettingCallback,
+ left_button: "Cancel",
+ }
+ );
+ }
+
+ addBrowserSetting() {
+ const settings = window.browser_mod?.getSetting?.(this.settingKey);
+ const allBrowsers = window.browser_mod._data.browsers;
+ const browsers = [];
+ for (const target of Object.keys(allBrowsers)) {
+ if (settings.browser[target] == null) browsers.push(target);
+ }
+
+ if (browsers.length === 0) {
+ window.browser_mod.showPopup(
+ "No browsers to configure",
+ "All registered browsers have already been configured.",
+ { right_button: "OK" }
+ );
+ return;
+ }
+
+ window.browser_mod.showPopup(
+ "Select browser to configure",
+ [
+ {
+ name: "browser",
+ label: "",
+ selector: {
+ select: { options: browsers },
+ },
+ },
+ ],
+ {
+ right_button: "Next",
+ right_button_action: (value) =>
+ this.changeSetting("browser", value.browser),
+ left_button: "Cancel",
+ }
+ );
+ }
+
+ async addUserSetting() {
+ const settings = window.browser_mod?.getSetting?.(this.settingKey);
+ const allUsers = await this.fetchUsers();
+ const users = [];
+ for (const target of allUsers) {
+ if (target.username && settings.user[target.id] == null)
+ users.push({ label: target.name, value: target.id });
+ }
+
+ if (users.length === 0) {
+ window.browser_mod.showPopup(
+ "No users to configure",
+ "All users have already been configured.",
+ { right_button: "OK" }
+ );
+ return;
+ }
+
+ window.browser_mod.showPopup(
+ "Select user to configure",
+ [
+ {
+ name: "user",
+ label: "",
+ selector: {
+ select: { options: users },
+ },
+ },
+ ],
+ {
+ right_button: "Next",
+ right_button_action: (value) => this.changeSetting("user", value.user),
+ left_button: "Cancel",
+ }
+ );
+ }
+
+ async updateTable() {
+ if (this.hass === undefined) return;
+ const users = await this.fetchUsers();
+ const settings = window.browser_mod?.getSetting?.(this.settingKey);
+ const data = [];
+ for (const [k, v] of Object.entries(settings.user)) {
+ const user = users.find((usr) => usr.id === k);
+ data.push({
+ name: `User: ${user.name}`,
+ value: String(v),
+ controls: html`
+ this.changeSetting("user", k)}>
+
+
+ this.clearSetting("user", k)}>
+
+
+ `,
+ });
+ }
+
+ data.push({
+ name: "",
+ value: html`
+ this.addUserSetting()}>
+
+ Add user setting
+
+ `,
+ });
+
+ for (const [k, v] of Object.entries(settings.browser)) {
+ data.push({
+ name: `Browser: ${k}`,
+ value: String(v),
+ controls: html`
+ this.changeSetting("browser", k)}>
+
+
+ this.clearSetting("browser", k)}>
+
+
+ `,
+ });
+ }
+
+ data.push({
+ name: "",
+ value: html`
+ this.addBrowserSetting()}>
+
+ Add browser setting
+
+ `,
+ });
+
+ data.push({
+ name: "GLOBAL",
+ value:
+ settings.global != null
+ ? String(settings.global)
+ : html`DEFAULT `,
+ controls: html`
+ this.changeSetting("global", null)}>
+
+
+ this.clearSetting("global", null)}>
+
+
+ `,
+ });
+ this.tableData = data;
+ }
+
+ render() {
+ const global = window.browser_mod?.global_settings?.[this.settingKey];
+ const columns = {
+ name: {
+ title: "Name",
+ grows: true,
+ },
+ value: {
+ title: "Value",
+ grows: true,
+ },
+ controls: {},
+ };
+
+ return html`
+
+
+ `;
+ }
+
+ static get styles() {
+ return css`
+ :host {
+ display: block;
+ }
+ `;
+ }
+}
+
+customElements.define("browser-mod-settings-table", BrowserModSettingsTable);
diff --git a/js/config_panel/browser-settings-card.ts b/js/config_panel/browser-settings-card.ts
index 2e8632c..2ebcf9c 100644
--- a/js/config_panel/browser-settings-card.ts
+++ b/js/config_panel/browser-settings-card.ts
@@ -136,7 +136,7 @@ class BrowserModRegisteredBrowsersCard extends LitElement {
private _renderInteractionAlert() {
return html`
- For security reasons many browsers require the user to interact with a
+ For privacy reasons many browsers require the user to interact with a
webpage before allowing audio playback or video capture. This may affect
the
media_player and camera components of Browser
diff --git a/js/config_panel/frontend-settings-card.ts b/js/config_panel/frontend-settings-card.ts
index 4782d3f..0c479fc 100644
--- a/js/config_panel/frontend-settings-card.ts
+++ b/js/config_panel/frontend-settings-card.ts
@@ -1,277 +1,197 @@
import { LitElement, html, css } from "lit";
import { property, state } from "lit/decorators.js";
-import { loadDeveloperToolsTemplate } from "../helpers";
+import { loadDeveloperToolsTemplate, selectTree } from "../helpers";
+
+import "./browser-mod-settings-table";
loadDeveloperToolsTemplate();
class BrowserModFrontendSettingsCard extends LitElement {
@property() hass;
- @state() _selectedTab = 0;
+ @state() _dashboards = [];
+
+ @state() _editSidebar = false;
+ _savedSidebar = { panelOrder: [], hiddenPanels: [] };
firstUpdated() {
window.browser_mod.addEventListener("browser-mod-config-update", () =>
this.requestUpdate()
);
- window.browser_mod.addEventListener("browser-mod-favicon-update", () =>
- this.requestUpdate()
- );
}
- _handleSwitchTab(ev: CustomEvent) {
- this._selectedTab = parseInt(ev.detail.index, 10);
+ updated(changedProperties) {
+ if (
+ changedProperties.has("hass") &&
+ changedProperties.get("hass") === undefined
+ ) {
+ (async () =>
+ (this._dashboards = await this.hass.callWS({
+ type: "lovelace/dashboards/list",
+ })))();
+ }
+ }
+
+ async toggleEditSidebar() {
+ const sideBar: any = await selectTree(
+ document,
+ "home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar"
+ );
+ sideBar.editMode = !sideBar.editMode;
+ this._editSidebar = sideBar.editMode;
+ if (this._editSidebar) {
+ this._savedSidebar = {
+ panelOrder: sideBar._panelOrder,
+ hiddenPanels: sideBar._hiddenPanels,
+ };
+ } else {
+ sideBar._panelOrder = this._savedSidebar.panelOrder ?? [];
+ sideBar._hiddenPanels = this._savedSidebar.hiddenPanels ?? [];
+ this._savedSidebar = { panelOrder: [], hiddenPanels: [] };
+ }
}
render() {
- const level = ["user", "browser", "global"][this._selectedTab];
+ const db = this._dashboards.map((d) => {
+ return { value: d.url_path, label: d.title };
+ });
+ const dashboardSelector = {
+ select: {
+ options: [{ value: "lovelace", label: "lovelace (default)" }, ...db],
+ custom_value: true,
+ },
+ };
return html`
-
-
- Please note: The settings in this section severely change the way the Home
+
+ The settings in this section severely change the way the Home
Assistant frontend works and looks. It is very easy to forget that
you made a setting here when you switch devices or user.
-
-
- Do not report any issues to Home Assistant before clearing
- EVERY setting here and thouroghly clearing all your browser
- caches. Failure to do so means you risk wasting a lot of peoples
- time, and you will be severly and rightfully ridiculed.
-
+
+ Do not report any issues to Home Assistant before clearing
+ EVERY setting here and thouroghly clearing all your browser
+ caches. Failure to do so means you risk wasting a lot of peoples
+ time, and you will be severly and rightfully ridiculed.
+
- Global settings are applied for all users and browsers.
- User settings are applied to the current user and overrides any Global settings.
- Browser settings are applied for the current browser and overrides any User or Global settings.
+ Settings below are applied by first match. I.e. if a matching User
+ setting exists, it will be applied. Otherwise any matching Browser
+ setting and otherwise the GLOBAL setting if that differs from
+ DEFAULT.
-
-
-
-
-
-
-
- ${this._render_settings(level)}
+
+
+
+ Title template
+
+ Jinja template for the browser window/tab title
+
+
+
+
+
+
+
+ Favicon template
+
+ Jinja template for the browser favicon
+
+
+
+
+
+
+
+ Hide sidebar
+
+ Completely remove the sidebar from all panels
+
+
+
+
+
+
+
+ Hide header
+
+ Completely remove the header from all panels
+
+
+
+
+
+
+
+ Default dashboard
+
+ The dashboard that is showed when navigating to
+ ${location.origin}/
+
+
+
+
+
+
+
+ Sidebar order
+
+ Order and visibility of sidebar items. Click EDIT and set
+ the sidebar up as you want. Then save the settings and finally
+ click RESTORE.
+
+ this.toggleEditSidebar()}>
+ ${this._editSidebar ? "Restore" : "Edit"}
+
+
+
+
+
+
+
+ Sidebar title
+
+ The title at the top of the sidebar
+
+
+
`;
}
- _render_settings(level) {
- const global = window.browser_mod.global_settings;
- const browser = window.browser_mod.browser_settings;
- const user = window.browser_mod.user_settings;
- const current = { global, browser, user }[level];
-
- const DESC_BOOLEAN = (val) =>
- ({ true: "Enabled", false: "Disabled", undefined: "Unset" }[String(val)]);
- const DESC_SET_UNSET = (val) => (val === undefined ? "Unset" : "Set");
- const OVERRIDDEN = (key) => {
- if (level !== "browser" && browser[key] !== undefined)
- return html` Overridden by browser setting`;
- if (level === "global" && user[key] !== undefined)
- return html` Overridden by user setting`;
- };
-
- return html`
-
-
- Favicon template
- ${OVERRIDDEN("faviconTemplate")}
-
-
-
{
- const tpl = ev.detail.value || undefined;
- window.browser_mod.set_setting("faviconTemplate", tpl, level);
- }}
- >
-
-
- window.browser_mod.set_setting(
- "faviconTemplate",
- undefined,
- level
- )}
- >
- Clear
-
-
-
-
-
-
- Title template
- ${OVERRIDDEN("titleTemplate")}
-
-
{
- const tpl = ev.detail.value || undefined;
- window.browser_mod.set_setting("titleTemplate", tpl, level);
- }}
- >
-
-
- window.browser_mod.set_setting("titleTemplate", undefined, level)}
- >
- Clear
-
-
-
-
-
-
- Hide Sidebar
- Hide the sidebar and hamburger menu
- Currently: ${DESC_BOOLEAN(current.hideSidebar)}
- ${OVERRIDDEN("hideSidebar")}
-
-
-
- window.browser_mod.set_setting("hideSidebar", true, level)}
- >
- Enable
-
-
- window.browser_mod.set_setting("hideSidebar", false, level)}
- >
- Disable
-
-
- window.browser_mod.set_setting("hideSidebar", undefined, level)}
- >
- Clear
-
-
-
-
-
-
- Hide Header
- Hide the header on all pages
- Currently: ${DESC_BOOLEAN(current.hideHeader)}
- ${OVERRIDDEN("hideHeader")}
-
-
-
- window.browser_mod.set_setting("hideHeader", true, level)}
- >
- Enable
-
-
- window.browser_mod.set_setting("hideHeader", false, level)}
- >
- Disable
-
-
- window.browser_mod.set_setting("hideHeader", undefined, level)}
- >
- Clear
-
-
-
-
-
-
- Sidebar order
-
- Order and visibility of sidebar buttons
-
- Currently: ${DESC_SET_UNSET(current.sidebarPanelOrder)}
- ${OVERRIDDEN("sidebarPanelOrder")}
-
-
-
- Clearing this does NOT restore the original default order.
-
- {
- window.browser_mod.set_setting(
- "sidebarPanelOrder",
- localStorage.getItem("sidebarPanelOrder"),
- level
- );
- window.browser_mod.set_setting(
- "sidebarHiddenPanels",
- localStorage.getItem("sidebarHiddenPanels"),
- level
- );
- }}
- >
- Set
-
- {
- window.browser_mod.set_setting(
- "sidebarPanelOrder",
- undefined,
- level
- );
- window.browser_mod.set_setting(
- "sidebarHiddenPanels",
- undefined,
- level
- );
- }}
- >
- Clear
-
-
-
-
-
-
- Default dashboard
- The dashboard that's displayed by default
- Currently: ${DESC_SET_UNSET(current.defaultPanel)}
- ${OVERRIDDEN("defaultPanel")}
-
-
-
- Clearing this does NOT restore the original default dashboard.
-
- {
- window.browser_mod.set_setting(
- "defaultPanel",
- localStorage.getItem("defaultPanel"),
- level
- );
- }}
- >
- Set
-
- {
- window.browser_mod.set_setting("defaultPanel", undefined, level);
- }}
- >
- Clear
-
-
-
- `;
- }
-
static get styles() {
return css`
.box {
@@ -280,7 +200,7 @@ class BrowserModFrontendSettingsCard extends LitElement {
}
.separator {
border-bottom: 1px solid var(--divider-color);
- margin: 0 -8px;
+ margin: 16px -16px 0px;
}
img.favicon {
width: 64px;
diff --git a/js/config_panel/main.ts b/js/config_panel/main.ts
index c804af9..64ab46f 100644
--- a/js/config_panel/main.ts
+++ b/js/config_panel/main.ts
@@ -15,12 +15,13 @@ loadConfigDashboard().then(() => {
@property() connection;
firstUpdated() {
- window.browser_mod.addEventListener("browser-mod-config-update", () =>
+ window.addEventListener("browser-mod-config-update", () =>
this.requestUpdate()
);
}
render() {
+ if (!window.browser_mod) return html``;
return html`
diff --git a/js/helpers.ts b/js/helpers.ts
index a621e7c..13e4677 100644
--- a/js/helpers.ts
+++ b/js/helpers.ts
@@ -1,9 +1,17 @@
const TIMEOUT_ERROR = "SELECTTREE-TIMEOUT";
-async function _await_el(el) {
+export async function await_element(el, hard = false) {
if (el.localName?.includes("-"))
await customElements.whenDefined(el.localName);
if (el.updateComplete) await el.updateComplete;
+ if (hard) {
+ if (el.pageRendered) await el.pageRendered;
+ if (el._panelState) {
+ let rounds = 0;
+ while (el._panelState !== "loaded" && rounds++ < 5)
+ await new Promise((r) => setTimeout(r, 100));
+ }
+ }
}
async function _selectTree(root, path, all = false) {
@@ -18,7 +26,7 @@ async function _selectTree(root, path, all = false) {
if (!p.trim().length) continue;
- _await_el(e);
+ await_element(e);
el = p === "$" ? [e.shadowRoot] : e.querySelectorAll(p);
}
return all ? el : el[0];
@@ -102,6 +110,7 @@ export const loadConfigDashboard = async () => {
const configRouter: any = document.createElement("ha-panel-config");
await configRouter?.routerOptions?.routes?.dashboard?.load?.(); // Load ha-config-dashboard
await configRouter?.routerOptions?.routes?.cloud?.load?.(); // Load ha-settings-row
+ await configRouter?.routerOptions?.routes?.entities?.load?.(); // Load ha-data-table
await customElements.whenDefined("ha-config-dashboard");
};
@@ -132,3 +141,32 @@ export function throttle(timeout) {
};
};
}
+
+export function runOnce(restart = false) {
+ return function (target, propertyKey, descriptor) {
+ const fn = descriptor.value;
+ let running = undefined;
+ const newfn = function (...rest) {
+ if (restart && running === false) running = true;
+ if (running !== undefined) return;
+ running = false;
+
+ const retval = fn.bind(this)(...rest);
+ if (running) {
+ running = undefined;
+ return newfn.bind(this)(...rest);
+ } else {
+ running = undefined;
+ return retval;
+ }
+ };
+ descriptor.value = newfn;
+ };
+}
+
+export async function waitRepeat(fn, times, delay) {
+ while (times--) {
+ fn();
+ await new Promise((r) => setTimeout(r, delay));
+ }
+}
diff --git a/js/plugin/connection.ts b/js/plugin/connection.ts
index b5620ef..db4b8ff 100644
--- a/js/plugin/connection.ts
+++ b/js/plugin/connection.ts
@@ -24,7 +24,7 @@ export const ConnectionMixin = (SuperClass) => {
}
private fireEvent(event, detail = undefined) {
- this.dispatchEvent(new CustomEvent(event, { detail }));
+ this.dispatchEvent(new CustomEvent(event, { detail, bubbles: true }));
}
private incoming_message(msg) {
diff --git a/js/plugin/frontend-settings.ts b/js/plugin/frontend-settings.ts
index d796248..325aa00 100644
--- a/js/plugin/frontend-settings.ts
+++ b/js/plugin/frontend-settings.ts
@@ -1,25 +1,37 @@
-import { selectTree } from "../helpers";
+import { await_element, waitRepeat, runOnce, selectTree } from "../helpers";
export const AutoSettingsMixin = (SuperClass) => {
- return class AutoSettingsMixinClass extends SuperClass {
+ class AutoSettingsMixinClass extends SuperClass {
_faviconTemplateSubscription;
_titleTemplateSubscription;
__currentTitle = undefined;
+ @runOnce()
+ async runHideHeader() {
+ while (!(await this._hideHeader()))
+ await new Promise((r) => setTimeout(r, 500));
+ }
+
+ @runOnce(true)
+ async runUpdateTitle() {
+ await waitRepeat(() => this._updateTitle(), 3, 500);
+ }
+
constructor() {
super();
- this._auto_settings_setup();
- this.addEventListener("browser-mod-config-update", () =>
- this._auto_settings_setup()
- );
+ const runUpdates = async () => {
+ this.runUpdateTitle();
+ this.runHideHeader();
+ };
- window.addEventListener("location-changed", () => {
- this._updateTitle();
- setTimeout(() => this._updateTitle(), 500);
- setTimeout(() => this._updateTitle(), 1000);
- setTimeout(() => this._updateTitle(), 5000);
+ this._auto_settings_setup();
+ this.addEventListener("browser-mod-config-update", () => {
+ this._auto_settings_setup();
+ runUpdates();
});
+
+ window.addEventListener("location-changed", runUpdates);
}
async _auto_settings_setup() {
@@ -40,7 +52,7 @@ export const AutoSettingsMixin = (SuperClass) => {
// Default panel
if (settings.defaultPanel) {
- localStorage.setItem("defaultPanel", settings.defaultPanel);
+ localStorage.setItem("defaultPanel", `"${settings.defaultPanel}"`);
}
// Hide sidebar
@@ -55,18 +67,18 @@ export const AutoSettingsMixin = (SuperClass) => {
).then((el) => el?.remove?.());
}
- // Hide header
- if (settings.hideHeader === true) {
- customElements.whenDefined("app-header-layout").then(() => {
- const appHeader = customElements.get("app-header").prototype;
- const _attached = appHeader.attached;
- appHeader.attached = function () {
- _attached.bind(this)();
- this.style.setProperty("display", "none");
- };
+ // Sidebar title
+ if (settings.sidebarTitle) {
+ selectTree(
+ document,
+ "home-assistant $ home-assistant-main $ app-drawer-layout app-drawer ha-sidebar $ .title"
+ ).then((el) => {
+ if (el) (el as HTMLElement).innerHTML = settings.sidebarTitle;
});
}
+ // Hide header
+
// Favicon template
if (settings.faviconTemplate !== undefined) {
(async () => {
@@ -111,7 +123,6 @@ export const AutoSettingsMixin = (SuperClass) => {
_updateFavicon({ result }) {
const link: any = document.head.querySelector("link[rel~='icon']");
link.href = result;
- window.browser_mod.fireEvent("browser-mod-favicon-update");
}
get _currentTitle() {
@@ -121,7 +132,77 @@ export const AutoSettingsMixin = (SuperClass) => {
_updateTitle(data = undefined) {
if (data) this.__currentTitle = data.result;
if (this.__currentTitle) document.title = this.__currentTitle;
- window.browser_mod.fireEvent("browser-mod-favicon-update");
}
- };
+
+ async _hideHeader() {
+ if (this.settings.hideHeader !== true) return true;
+ let el = await selectTree(
+ document,
+ "home-assistant $ home-assistant-main $ app-drawer-layout partial-panel-resolver"
+ );
+ if (!el) return false;
+ let steps = 0;
+ while (el && el.localName !== "ha-app-layout" && steps++ < 5) {
+ await await_element(el, true);
+ const next =
+ el.querySelector("ha-app-layout") ??
+ el.firstElementChild ??
+ el.shadowRoot;
+ el = next;
+ }
+ if (el?.localName !== "ha-app-layout") return false;
+ if (el.header) {
+ el.header.style.setProperty("display", "none");
+ setTimeout(() => el._updateLayoutStates(), 0);
+ return true;
+ }
+ return false;
+ }
+
+ getSetting(key) {
+ const retval = { global: undefined, browser: {}, user: {} };
+ retval.global = this._data.settings?.[key];
+ for (const [k, v] of Object.entries(this._data.browsers ?? {})) {
+ if ((v as any).settings?.[key] != null)
+ retval.browser[k] = (v as any).settings[key];
+ }
+ for (const [k, v] of Object.entries(this._data.user_settings ?? {})) {
+ if (v[key] != null) retval.user[k] = v[key];
+ }
+ return retval;
+ }
+
+ setSetting(type, target, settings) {
+ if (type === "global") {
+ for (const [key, value] of Object.entries(settings))
+ this.connection.sendMessage({
+ type: "browser_mod/settings",
+ key,
+ value,
+ });
+ } else if (type === "browser") {
+ const browser = this._data.browsers[target];
+ const newsettings = { ...browser.settings, ...settings };
+ console.log(newsettings);
+ this.connection.sendMessage({
+ type: "browser_mod/register",
+ browserID: target,
+ data: {
+ ...browser,
+ settings: newsettings,
+ },
+ });
+ } else if (type === "user") {
+ const user = target;
+ for (const [key, value] of Object.entries(settings))
+ this.connection.sendMessage({
+ type: "browser_mod/settings",
+ user,
+ key,
+ value,
+ });
+ }
+ }
+ }
+ return AutoSettingsMixinClass;
};
diff --git a/package.json b/package.json
index 0e95a58..49d3714 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "browser_mod",
"private": true,
- "version": "2.0.0b4",
+ "version": "2.0.0b5",
"description": "",
"scripts": {
"build": "rollup -c",
diff --git a/test/automations.yaml b/test/automations.yaml
index bd94fc2..0b5b6f1 100644
--- a/test/automations.yaml
+++ b/test/automations.yaml
@@ -17,15 +17,9 @@
- platform: state
entity_id: light.kitchen_lights
action:
- - service: browser_mod.sequence
+ - service: browser_mod.popup
data:
- sequence:
- - service: delay
- data:
- time: 5000
- - service: browser_mod.popup
- data:
- title: automation
- content:
- type: markdown
- content: "{%raw%}{{states('light.bed_light')}}{%endraw%}"
+ title: automation
+ content:
+ type: markdown
+ content: "{%raw%}{{states('light.bed_light')}}{%endraw%}"