mirror of
				https://github.com/CCOSTAN/Home-AssistantConfig.git
				synced 2025-10-31 02:37:25 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| customElements.whenDefined('card-tools').then(() => {
 | |
| var ct = customElements.get('card-tools');
 | |
| 
 | |
| const BUILTIN_ACTIONS = [
 | |
|   {
 | |
|     matches: '^((magnet:.*)|(.*\.torrent.*))$',
 | |
|     name: 'Add to Transmission',
 | |
|     icon: 'mdi:progress-download',
 | |
|     service: 'transmission.add_torrent',
 | |
|     service_data: {
 | |
|       torrent: '{1}'
 | |
|     },
 | |
|   }
 | |
| ];
 | |
| 
 | |
| const matchAndReplace = (text, matches) => {
 | |
|   for (var i = 0; i < matches.length; i++) {
 | |
|     text = text.replace('{' + i + '}', matches[i]);
 | |
|   }
 | |
|   return text;
 | |
| }
 | |
| 
 | |
| class SearchCard extends ct.LitElement {
 | |
| 
 | |
|   static get properties() {
 | |
|     return {
 | |
|       config: {},
 | |
|       hass: {},
 | |
|     };
 | |
|   }
 | |
| 
 | |
|   setConfig(config) {
 | |
|     this.results = [];
 | |
|     this.config = config;
 | |
| 
 | |
|     this.active_actions = [];
 | |
|     this.max_results = this.config.max_results || 10;
 | |
|     
 | |
|     this.search_text = this.config.search_text || "Type to search...";
 | |
| 
 | |
|     this.actions = BUILTIN_ACTIONS.concat(this.config.actions || []);
 | |
|   }
 | |
| 
 | |
|   getCardSize() {
 | |
|     return 4;
 | |
|   }
 | |
| 
 | |
|   render() {
 | |
|       var results = this.results.slice(0, this.max_results).sort();
 | |
|       var rows = results.map((entity_id) => this._createResultRow(entity_id));
 | |
|       var actions = this.active_actions.map((x) => this._createActionRow(x[0], x[1]));
 | |
|       return ct.LitHtml `
 | |
|       <ha-card>
 | |
|         <div id="searchContainer">
 | |
|           <paper-input id="searchText"
 | |
|                        @value-changed="${this._valueChanged}"
 | |
|                        no-label-float type="text" autocomplete="off"
 | |
|                        label="${this.search_text}">
 | |
|             <ha-icon icon="mdi:magnify" id="searchIcon"
 | |
|                        slot="prefix"></ha-icon>
 | |
|             <ha-icon-button slot="suffix"
 | |
|                                @click="${this._clearInput}"
 | |
|                                icon="mdi:close"
 | |
|                                alt="Clear"
 | |
|                                title="Clear"></ha-icon-button>
 | |
|           </paper-input>
 | |
|           ${results.length > 0 ?
 | |
|               ct.LitHtml `<div id="count">Showing ${results.length} of ${this.results.length} results</div>`
 | |
|             : ''}
 | |
|         </div>
 | |
|         ${(rows.length > 0 || actions.length > 0) ?
 | |
|               ct.LitHtml `<div id="results">${actions}${rows}</div>`
 | |
|             : ''}
 | |
|       </ha-card>
 | |
|     `;
 | |
|   }
 | |
| 
 | |
|   _createResultRow(entity_id) {
 | |
|     var row = ct.createEntityRow({entity: entity_id});
 | |
|     row.addEventListener("click", () => ct.moreInfo(entity_id));
 | |
|     row.hass = this.hass;
 | |
|     return row;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   _createActionRow(action, matches) {
 | |
|     var service_data = action.service_data;
 | |
|     for (var key in service_data) {
 | |
|       service_data[key] = matchAndReplace(service_data[key], matches);
 | |
|     }
 | |
| 
 | |
|     const elem = cardTools.createThing("service-row", {
 | |
|       type: "call",
 | |
|       name: matchAndReplace(action.name, matches),
 | |
|       icon: action.icon || 'mdi:lamp',
 | |
|       service: action.service,
 | |
|       service_data: service_data,
 | |
|     });
 | |
|     elem.hass = this.hass;
 | |
|     return elem;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   _clearInput()
 | |
|   {
 | |
|     this.shadowRoot.getElementById('searchText').value = '';
 | |
|     super.update()
 | |
|   }
 | |
| 
 | |
|   _valueChanged(ev) {
 | |
|     var searchText = ev.target.value;
 | |
| 
 | |
|     this.results = [];
 | |
|     this.active_actions = [];
 | |
| 
 | |
|     if (!this.config || !this.hass || searchText === "") {
 | |
|       this.update();
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     try {
 | |
|       var searchRegex = new RegExp(searchText, 'i');
 | |
|       for (var entity_id in this.hass.states) {
 | |
|         if (
 | |
|             (entity_id.search(searchRegex) >= 0) ||
 | |
|             (
 | |
|               "friendly_name" in this.hass.states[entity_id].attributes &&
 | |
|               this.hass.states[entity_id].attributes.friendly_name.search(searchRegex) >= 0
 | |
|             )
 | |
|           ) {
 | |
|           this.results.push(entity_id);
 | |
|         }
 | |
|       }
 | |
|     } catch (err) {
 | |
|     }
 | |
| 
 | |
|     this.active_actions = this._getActivatedActions(searchText);
 | |
| 
 | |
|     this.update();
 | |
|   }
 | |
| 
 | |
|   _getActivatedActions(searchText) {
 | |
|     var active = [];
 | |
| 
 | |
|     for (const action of this.actions) {
 | |
|       if (this._serviceExists(action.service)) {
 | |
|         var matches = searchText.match(action.matches);
 | |
|         if (matches != null) {
 | |
|           active.push([action, matches]);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     return active;
 | |
|   }
 | |
| 
 | |
|   _serviceExists(serviceCall) {
 | |
|       var [domain, service] = serviceCall.split('.');
 | |
|       var servicesForDomain = this.hass.services[domain];
 | |
|       return servicesForDomain && service in servicesForDomain;
 | |
|   }
 | |
| 
 | |
|   static get styles() {
 | |
|     return ct.LitCSS `
 | |
|       #searchContainer {
 | |
|         width: 90%;
 | |
|         display: block;
 | |
|         margin-left: auto;
 | |
|         margin-right: auto;
 | |
|       }
 | |
|       #count {
 | |
|         text-align: right;
 | |
|         font-style: italic;
 | |
|       }
 | |
|       #results {
 | |
|         width: 90%;
 | |
|         display: block;
 | |
|         padding-bottom: 15px;
 | |
|         margin-top: 15px;
 | |
|         margin-left: auto;
 | |
|         margin-right: auto;
 | |
|       }
 | |
|       #searchIcon {
 | |
|         padding: 10px;
 | |
|       }
 | |
|     `;
 | |
|   }
 | |
| }
 | |
| 
 | |
| customElements.define('search-card', SearchCard);
 | |
| 
 | |
| });
 | |
| 
 | |
| setTimeout(() => {
 | |
|   if(customElements.get('card-tools')) return;
 | |
|   customElements.define('search-card', class extends HTMLElement{
 | |
|     setConfig() { throw new Error("Can't find card-tools. See https://github.com/thomasloven/lovelace-card-tools");}
 | |
|   });
 | |
| }, 2000);
 |