From f412fd499976bf405fae489f001c025623c899a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Thu, 29 Aug 2019 19:30:58 +0200 Subject: [PATCH] Don't render stuff that doesn't have templates... --- card-mod.js | 2 +- src/main.js | 111 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 77 insertions(+), 36 deletions(-) diff --git a/card-mod.js b/card-mod.js index 0c8dd41..86076ce 100644 --- a/card-mod.js +++ b/card-mod.js @@ -1 +1 @@ -!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);const o=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view"));o.prototype.html,o.prototype.css;function i(e,t,n=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},n)n.dispatchEvent(e);else{var o=document.querySelector("home-assistant");(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=o&&o.shadowRoot)&&o.querySelector("home-assistant-main"))&&o.shadowRoot)&&o.querySelector("app-drawer-layout partial-panel-resolver"))&&o.shadowRoot||o)&&o.querySelector("ha-panel-lovelace"))&&o.shadowRoot)&&o.querySelector("hui-root"))&&o.shadowRoot)&&o.querySelector("ha-app-layout #view"))&&o.firstElementChild)&&o.dispatchEvent(e)}}function r(){return document.querySelector("home-assistant").hass}let a=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();const l=async function(e,t,n,o){const i=function(e){o&&("string"==typeof e?console.log(" ".repeat(2*(o-1))+e):console.log(e))};if(e&&t)if(e.updateComplete&&await e.updateComplete,"string"==typeof t){const o=e.querySelector(".card-mod-style");o&&(o.cancelSubscription&&await o.cancelSubscription,e.removeChild(o));const l=document.createElement("style");l.classList="card-mod-style",l.cancelSubscription=async function(e,t,n){e||(e=r().connection);let o={user:r().user.name,browser:a,hash:location.hash.substr(1)||" ",...n.variables},i=n.template,l=n.entity_ids;return e.subscribeMessage(e=>t(e.result),{type:"render_template",template:i,variables:o,entity_ids:l})}(null,e=>{l.innerHTML=e},{template:t,variables:n.variables,entity_ids:n.entity_ids}),e.appendChild(l),i("Applied styles to:"),i(e)}else Object.keys(t).forEach(r=>"."===r?(i(`Stepping into root of ${e.tagName}`),l(e,t[r],n,o?o+1:0)):"$"===r?(i(`Stepping into ShadowRoot of ${e.tagName}`),l(e.shadowRoot,t[r],n,o?o+1:0)):(i(`Searching for: "${r}". ${e.querySelectorAll(r).length} matches.`),void e.querySelectorAll(`${r}`).forEach(e=>{i(`Stepping into ${e.tagName}`),l(e,t[r],n,o?o+1:0)})))},s=function(e){return"string"==typeof e?e.includes("config.entity"):Object.values(e).some(s)};customElements.whenDefined("ha-card").then(()=>{const e=customElements.get("ha-card"),t=function(e){return e.config?e.config:e._config?e._config:e.host?t(e.host):e.parentElement?t(e.parentElement):e.parentNode?t(e.parentNode):null};e.prototype.firstUpdated=function(){const e=this.shadowRoot.querySelector(".card-header");e&&this.insertBefore(e,this.children[0]);const n=t(this);if(!n||!n.style)return;let o=n.entity_ids;!o&&s(n.style)&&(o=[n.entity]);const i=()=>{l(this,n.style,{variables:{config:n},entity_ids:o},!!n.debug_cardmod)};i(),window.addEventListener("location-changed",()=>i())},i("ll-rebuild",{})}),customElements.whenDefined("hui-entities-card").then(()=>{const e=customElements.get("hui-entities-card"),t=e.prototype.renderEntity;e.prototype.renderEntity=function(e){const n=t.bind(this)(e);if(!e.style)return n;if(!n.values)return n;const o=n.values[0];if(!o||!o.updateComplete)return n;let i=e.entity_ids;!i&&s(e.style)&&(i=[e.entity]);const r=()=>{l(o.shadowRoot,e.style,{variables:{config:e},entity_ids:i},!!e.debug_cardmod)};return o.updateComplete.then(r),window.addEventListener("location-changed",r),n},i("ll-rebuild",{})}),customElements.whenDefined("hui-glance-card").then(()=>{customElements.get("hui-glance-card").prototype.firstUpdated=function(){this.shadowRoot.querySelectorAll("ha-card div.entity").forEach(e=>{const t=e.attachShadow({mode:"open"});[...e.children].forEach(e=>t.appendChild(e));const n=document.createElement("style");t.appendChild(n),n.innerHTML="\n :host {\n box-sizing: border-box;\n padding: 0 4px;\n display: flex;\n flex-direction: column;\n align-items: center;\n cursor: pointer;\n margin-bottom: 12px;\n width: var(--glance-column-width, 20%);\n }\n div {\n width: 100%;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .name {\n min-height: var(--paper-font-body1_-_line-height, 20px);\n }\n state-badge {\n margin: 8px 0;\n }\n ";const o=e.entityConf;if(!o.style)return;let i=o.entity_ids;!i&&s(o.style)&&(i=[o.entity]);const r=()=>{l(t,o.style,{variables:{config:o},entity_ids:i},!!o.debug_cardmod)};r(),window.addEventListener("location-changed",r)})},i("ll-rebuild",{})})}]); \ No newline at end of file +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var i=t[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(o,i,function(t){return e[t]}.bind(null,i));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);const o=customElements.get("home-assistant-main")?Object.getPrototypeOf(customElements.get("home-assistant-main")):Object.getPrototypeOf(customElements.get("hui-view"));o.prototype.html,o.prototype.css;function i(e,t,n=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},n)n.dispatchEvent(e);else{var o=document.querySelector("home-assistant");(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=o&&o.shadowRoot)&&o.querySelector("home-assistant-main"))&&o.shadowRoot)&&o.querySelector("app-drawer-layout partial-panel-resolver"))&&o.shadowRoot||o)&&o.querySelector("ha-panel-lovelace"))&&o.shadowRoot)&&o.querySelector("hui-root"))&&o.shadowRoot)&&o.querySelector("ha-app-layout #view"))&&o.firstElementChild)&&o.dispatchEvent(e)}}function a(){return document.querySelector("home-assistant").hass}let s=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();customElements.define("card-mod",class extends HTMLElement{disconnectedCallback(){this._disconnect()}connectedCallback(){this._connect()}_has_template(e){return!!e.template.includes("{%")||!!e.template.includes("{{")}set template(e){this._data=e,this._has_template(e)&&!this._data.entity_ids&&this._data.template.includes("config.entity")&&this._data.variables.config&&this._data.variables.config.entity&&(this._data.entity_ids=[this._data.variables.config.entity])}update(){this._disconnect().then(()=>this._connect())}async _connect(){this._data&&(this._has_template(this._data)||(this.innerHTML=``),this._unsubRenderTemplate||(this._unsubRenderTemplate=function(e,t,n){e||(e=a().connection);let o={user:a().user.name,browser:s,hash:location.hash.substr(1)||" ",...n.variables},i=n.template,r=n.entity_ids;return e.subscribeMessage(e=>t(e.result),{type:"render_template",template:i,variables:o,entity_ids:r})}(null,e=>this.innerHTML=``,this._data),this._unsubRenderTemplate.catch(()=>{this.innerHTML=``,this._unsubRenderTemplate=void 0})))}async _disconnect(){if(this._unsubRenderTemplate)try{const e=await this._unsubRenderTemplate;this._unsubRenderTemplate=void 0,await e()}catch(e){if("not_found"!==e.code)throw e}}});const r=async function(e,t,n,o){const i=function(e){o&&("string"==typeof e?console.log(" ".repeat(2*(o-1))+e):console.log(e))};if(e&&t)if(e.updateComplete&&await e.updateComplete,"string"==typeof t){const o=e.querySelector("card-mod");if(o)return void o.update();const a=document.createElement("card-mod");a.template={template:t,variables:n.variables,entity_ids:n.entity_ids},e.appendChild(a),i("Applied styles to:"),i(e)}else Object.keys(t).forEach(a=>"."===a?(i(`Stepping into root of ${e.tagName}`),r(e,t[a],n,o?o+1:0)):"$"===a?(i(`Stepping into ShadowRoot of ${e.tagName}`),r(e.shadowRoot,t[a],n,o?o+1:0)):(i(`Searching for: "${a}". ${e.querySelectorAll(a).length} matches.`),void e.querySelectorAll(`${a}`).forEach(e=>{i(`Stepping into ${e.tagName}`),r(e,t[a],n,o?o+1:0)})))};customElements.whenDefined("ha-card").then(()=>{const e=customElements.get("ha-card"),t=function(e){return e.config?e.config:e._config?e._config:e.host?t(e.host):e.parentElement?t(e.parentElement):e.parentNode?t(e.parentNode):null};e.prototype.firstUpdated=function(){const e=this.shadowRoot.querySelector(".card-header");e&&this.insertBefore(e,this.children[0]);const n=t(this);if(!n||!n.style)return;let o=n.entity_ids;const i=()=>{r(this,n.style,{variables:{config:n},entity_ids:o},!!n.debug_cardmod)};i(),window.addEventListener("location-changed",()=>i())},i("ll-rebuild",{})}),customElements.whenDefined("hui-entities-card").then(()=>{const e=customElements.get("hui-entities-card"),t=e.prototype.renderEntity;e.prototype.renderEntity=function(e){const n=t.bind(this)(e);if(!e.style)return n;if(!n.values)return n;const o=n.values[0];if(!o||!o.updateComplete)return n;let i=e.entity_ids;const a=()=>{r(o.shadowRoot,e.style,{variables:{config:e},entity_ids:i},!!e.debug_cardmod)};return o.updateComplete.then(a),window.addEventListener("location-changed",a),n},i("ll-rebuild",{})}),customElements.whenDefined("hui-glance-card").then(()=>{customElements.get("hui-glance-card").prototype.firstUpdated=function(){this.shadowRoot.querySelectorAll("ha-card div.entity").forEach(e=>{const t=e.attachShadow({mode:"open"});[...e.children].forEach(e=>t.appendChild(e));const n=document.createElement("style");t.appendChild(n),n.innerHTML="\n :host {\n box-sizing: border-box;\n padding: 0 4px;\n display: flex;\n flex-direction: column;\n align-items: center;\n cursor: pointer;\n margin-bottom: 12px;\n width: var(--glance-column-width, 20%);\n }\n div {\n width: 100%;\n text-align: center;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n .name {\n min-height: var(--paper-font-body1_-_line-height, 20px);\n }\n state-badge {\n margin: 8px 0;\n }\n ";const o=e.entityConf;if(!o.style)return;let i=o.entity_ids;const a=()=>{r(t,o.style,{variables:{config:o},entity_ids:i},!!o.debug_cardmod)};a(),window.addEventListener("location-changed",a)})},i("ll-rebuild",{})})}]); \ No newline at end of file diff --git a/src/main.js b/src/main.js index 8fc58c1..2af62f2 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,72 @@ import {html, css} from "/card-tools/lit-element.js"; import {fireEvent} from "/card-tools/event.js"; import {subscribeRenderTemplate} from "/card-tools/templates.js"; +class CardMod extends HTMLElement { + + disconnectedCallback() { + this._disconnect(); + } + connectedCallback() { + this._connect(); + } + + _has_template(data) { + if(data.template.includes("{%")) return true; + if(data.template.includes("{{")) return true; + return false; + } + + set template(data) { + this._data = data; + if(!this._has_template(data)) return; + + if(!this._data.entity_ids && this._data.template.includes("config.entity")) { + if(this._data.variables.config && this._data.variables.config.entity) { + this._data.entity_ids = [this._data.variables.config.entity]; + } + } + } + + update() { + this._disconnect().then(() => this._connect()); + } + + async _connect() { + if(!this._data) return; + + if(!this._has_template(this._data)) { + this.innerHTML = ``; + } + + if(this._unsubRenderTemplate) return; + this._unsubRenderTemplate = subscribeRenderTemplate(null, + (result) => this.innerHTML = ``, + this._data); + + this._unsubRenderTemplate.catch(() => { + this.innerHTML = ``; + this._unsubRenderTemplate = undefined; + }); + } + + async _disconnect() { + if(this._unsubRenderTemplate) { + try { + const unsub = await this._unsubRenderTemplate; + this._unsubRenderTemplate = undefined; + await unsub(); + } catch (e) { + if(e.code !== "not_found") + throw e; + } + } + } + +} + +customElements.define("card-mod", CardMod); + + const applyStyle = async function(root, style, params, debug) { const debugPrint = function(str){ @@ -18,31 +84,19 @@ const applyStyle = async function(root, style, params, debug) { await root.updateComplete; if(typeof style === "string") { - const oldStyleEl = root.querySelector(".card-mod-style"); - if(oldStyleEl) - { - // Remove old styles and cancel template subscriptions - if(oldStyleEl.cancelSubscription) - { - await oldStyleEl.cancelSubscription; - } - root.removeChild(oldStyleEl) + const oldStyleEl = root.querySelector("card-mod"); + if(oldStyleEl) { + oldStyleEl.update(); + return; } // Add new style tag to the root element - const styleEl = document.createElement('style'); - styleEl.classList = "card-mod-style"; - styleEl.cancelSubscription = subscribeRenderTemplate( - null, - (result) => { - styleEl.innerHTML = result; - }, - { - template: style, - variables: params.variables, - entity_ids: params.entity_ids, - } - ); + const styleEl = document.createElement('card-mod'); + styleEl.template = { + template: style, + variables: params.variables, + entity_ids: params.entity_ids, + }; root.appendChild(styleEl); debugPrint("Applied styles to:"); debugPrint(root); @@ -66,13 +120,6 @@ const applyStyle = async function(root, style, params, debug) { } } -const find_entity_ids = function(data) { - if(typeof(data) === "string") { - return data.includes("config.entity"); - } - return Object.values(data).some(find_entity_ids); -} - customElements.whenDefined('ha-card').then(() => { const HaCard = customElements.get('ha-card'); @@ -105,8 +152,6 @@ customElements.whenDefined('ha-card').then(() => { if(!config || !config.style) return; let entity_ids = config.entity_ids; - if(!entity_ids && find_entity_ids(config.style)) - entity_ids = [config.entity]; const apply = () => { applyStyle(this, config.style, { @@ -137,8 +182,6 @@ customElements.whenDefined('hui-entities-card').then(() => { if(!row || !row.updateComplete) return retval; let entity_ids = config.entity_ids; - if (!entity_ids && find_entity_ids(config.style)) - entity_ids = [config.entity]; const apply = () => { applyStyle(row.shadowRoot, config.style, { @@ -194,8 +237,6 @@ customElements.whenDefined('hui-glance-card').then(() => { const config = e.entityConf; if(!config.style) return; let entity_ids = config.entity_ids; - if (!entity_ids && find_entity_ids(config.style)) - entity_ids = [config.entity]; const apply = () => { applyStyle(root, config.style, {