const S = Symbol(); customElements.define('local-services', class extends HTMLElement { static get observedAttributes() { return ['filter'] } constructor() { super(); const shadow = this[S] = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = `
`; { const filter = shadow.querySelector('#filter'); let t = null; filter.addEventListener('change', ev => { ev.stopPropagation(); this.filter = ev.target.value; }); filter.addEventListener('keyup', ev => { ev.stopPropagation(); if (t) clearTimeout(t); t = setTimeout(() => { this.filter = ev.target.value; t = null; }, 1000 / 3); }); } } connectedCallback() { this.filter = this.getAttribute('filter'); } attributeChangedCallback(name, oldV, newV) { if (oldV == newV) return; switch (name) { case 'filter': return this.filter = newV; } } get filter() { return this.getAttribute('filter'); } set filter(value) { this.setAttribute('filter', value); for (const el of this.querySelectorAll('local-service')) { if (!el.name) continue; if (el.name.includes(value)) { el.setAttribute('local-services-visible', 'visible'); } else { el.setAttribute('local-services-visible', 'invisible'); } } } }); customElements.define('local-service', class extends HTMLElement { static get observedAttributes() { return ['name', 'service-id', 'state'] } constructor() { super(); const shadow = this[S] = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = `

`; } connectedCallback() { this[S].querySelector('#name').textContent = this.getAttribute('name'); } attributeChangedCallback(name, oldV, newV) { switch (name) { case 'name': return this[S].querySelector('#name').textContent = newV; } } get name() { return this.getAttribute('name') || '' } }); customElements.define('local-service-item', class extends HTMLElement { static get observedAttributes() { return ['name', 'price'] } constructor() { super(); const shadow = this[S] = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = `

`; } connectedCallback() { this[S].querySelector('#name').textContent = this.getAttribute('name'); this[S].querySelector('#price').value = this.price(); } attributeChangedCallback(name, oldV, newV) { switch (name) { case 'name': return this[S].querySelector('#name').textContent = newV; case 'price': return this[S].querySelector('#price').value = newV; } } price(s) { const n = parseInt(s || this.getAttribute('price')); return isNaN(n) ? 0 : n; } }); customElements.define('ow-price', class extends HTMLElement { static get observedAttributes() { return ['value', 'currency'] } constructor() { super(); const shadow = this[S] = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = ` `; } connectedCallback() { this[S].querySelector('#price').textContent = this.formatted; } attributeChangedCallback(name, oldV, newV) { switch (name) { case 'price': { this.value = newV; this[S].querySelector('#price').textContent = this.formatted; break; } } } get formatted() { let v = this.value; let major = Math.ceil(v / 100); let minor = v % 100; let formatted = `${major},${ minor < 10 ? `0${minor}` : minor }`; return `${formatted}${this.currency}` } get value() { const n = parseInt(this.getAttribute('value')); return isNaN(n) ? 0 : n; } set value(v) { this.setAttribute('value', v) } get currency() { return this.getAttribute('currency') || 'PLN' } });