177 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| class VerticalStackInCard extends HTMLElement {
 | |
|     constructor() {
 | |
|         super();
 | |
|         // Make use of shadowRoot to avoid conflicts when reusing
 | |
|         this.attachShadow({ mode: 'open' });
 | |
|     }
 | |
| 
 | |
|     setConfig(config) {
 | |
|         if (!config || !config.cards || !Array.isArray(config.cards)) {
 | |
|             throw new Error('Card config incorrect');
 | |
|         }
 | |
|         
 | |
|         const shadow = this.shadowRoot;
 | |
|         while (shadow.hasChildNodes()) {
 | |
|             shadow.removeChild(shadow.lastChild);
 | |
|         }
 | |
|         
 | |
|         const card = document.createElement("ha-card");
 | |
|         const cardContent = document.createElement("div");
 | |
|         
 | |
|         card.header = config.title;
 | |
|         this._refCards = [];
 | |
|         
 | |
|         const _createThing = (tag, config) => {
 | |
|             const element = document.createElement(tag);
 | |
|             try {
 | |
|                 element.setConfig(config);
 | |
|             } catch (err) {
 | |
|                 console.error(tag, err);
 | |
|                 return _createError(err.message, config);
 | |
|             }
 | |
|             return element;
 | |
|         };
 | |
| 
 | |
|         const _createError = (error, config) => {
 | |
|             return _createThing("hui-error-card", {
 | |
|                 type: "error",
 | |
|                 error,
 | |
|                 config,
 | |
|             });
 | |
|         };
 | |
| 
 | |
|         const _fireEvent = (ev, detail, entity=null) => {
 | |
|             ev = new Event(ev, {
 | |
|                 bubbles: true,
 | |
|                 cancelable: false,
 | |
|                 composed: true,
 | |
|             });
 | |
|             ev.detail = detail || {};
 | |
| 
 | |
|             if (entity) {
 | |
|                 entity.dispatchEvent(ev);
 | |
|             } else {
 | |
|                 document
 | |
|                     .querySelector("home-assistant")
 | |
|                     .shadowRoot.querySelector("home-assistant-main")
 | |
|                     .shadowRoot.querySelector("app-drawer-layout partial-panel-resolver")
 | |
|                     .shadowRoot.querySelector("ha-panel-lovelace")
 | |
|                     .shadowRoot.querySelector("hui-root")
 | |
|                     .shadowRoot.querySelector("ha-app-layout #view")
 | |
|                     .firstElementChild
 | |
|                     .dispatchEvent(ev);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         config.cards.forEach((item) => {
 | |
|             let tag = item.type;
 | |
| 
 | |
|             if (tag.startsWith("divider")) {
 | |
|                 tag = `hui-divider-row`;
 | |
|             } else if (tag.startsWith("custom:")) {
 | |
|                 tag = tag.substr("custom:".length);
 | |
|             } else {
 | |
|                 tag = `hui-${tag}-card`;
 | |
|             }
 | |
| 
 | |
|             if (customElements.get(tag)) {
 | |
|                 const element = _createThing(tag, item);
 | |
|                 cardContent.appendChild(element);
 | |
|                 this._refCards.push(element);
 | |
|             } else {
 | |
|                 // If element doesn't exist (yet) create an error
 | |
|                 const element = _createError(
 | |
|                     `Custom element doesn't exist: ${tag}.`,
 | |
|                     item
 | |
|                 );
 | |
|                 element.style.display = "None";
 | |
| 
 | |
|                 const time = setTimeout(() => {
 | |
|                     element.style.display = "";
 | |
|                 }, 2000);
 | |
| 
 | |
|                 // Remove error if element is defined later
 | |
|                 customElements.whenDefined(tag).then(() => {
 | |
|                     clearTimeout(time);
 | |
|                     _fireEvent("ll-rebuild", {}, element);
 | |
|                 });
 | |
| 
 | |
|                 cardContent.appendChild(element);
 | |
|                 this._refCards.push(element);
 | |
|             }
 | |
|         });
 | |
|         card.appendChild(cardContent);
 | |
|         shadow.appendChild(card);
 | |
|     }
 | |
| 
 | |
|     set hass(hass) {
 | |
|         if (this._refCards) {
 | |
|             this._refCards.forEach((card) => {
 | |
|                 card.hass = hass;
 | |
|             });
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     connectedCallback() {
 | |
|         this._refCards.forEach((element) => {
 | |
|             let fn = () => {
 | |
|                 this._card(element);
 | |
|             };
 | |
| 
 | |
|             if(element.updateComplete) {
 | |
|                 element.updateComplete.then(fn);
 | |
|             } else {
 | |
|                 fn();
 | |
|             }
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     _card(element) {
 | |
|         if (element.shadowRoot) {
 | |
|             if (!element.shadowRoot.querySelector('ha-card')) {
 | |
|                 let searchEles = element.shadowRoot.getElementById("root");
 | |
|                 if (!searchEles) {
 | |
|                     searchEles = element.shadowRoot.getElementById("card");
 | |
|                 }
 | |
|                 if (!searchEles) return;
 | |
|                 searchEles = searchEles.childNodes;
 | |
|                 for (let i = 0; i < searchEles.length; i++) {
 | |
|                     if(searchEles[i].style !== undefined){
 | |
|                         searchEles[i].style.margin = "0px";
 | |
|                     }
 | |
|                     this._card(searchEles[i]);
 | |
|                 }
 | |
|             } else {
 | |
|                 let ele = element.shadowRoot.querySelector('ha-card')
 | |
|                 ele.style.boxShadow = 'none';
 | |
|                 ele.style.background = 'transparent';
 | |
|                 ele.style.borderRadius = '0';
 | |
|             }
 | |
|         } else {
 | |
|             if (typeof element.querySelector === 'function' && element.querySelector('ha-card')) {
 | |
|                 let ele = element.querySelector('ha-card')
 | |
|                 ele.style.boxShadow = 'none';
 | |
|                 ele.style.background = 'transparent';
 | |
|                 ele.style.borderRadius = '0';
 | |
|             }
 | |
|             let searchEles = element.childNodes;
 | |
|             for (let i = 0; i < searchEles.length; i++) {
 | |
|                 if (searchEles[i] && searchEles[i].style) {
 | |
|                     searchEles[i].style.margin = "0px";
 | |
|                 }
 | |
|                 this._card(searchEles[i]);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     getCardSize() {
 | |
|         let totalSize = 0;
 | |
|         this._refCards.forEach((element) => {
 | |
|             totalSize += typeof element.getCardSize === 'function' ? element.getCardSize() : 1;
 | |
|         });
 | |
|         return totalSize;
 | |
|     }
 | |
| }
 | |
| 
 | |
| customElements.define('vertical-stack-in-card', VerticalStackInCard);
 | 
