oswilno/assets/js/app.js

208 lines
4.5 KiB
JavaScript
Raw Normal View History

2022-07-04 08:31:12 +02:00
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 = `
<style>
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
::slotted(local-service[local-services-visible="invisible"]) {
display: none;
}
</style>
<section>
<input type="text" id="filter" />
</section>
<section id="items">
<slot name="services"></slot>
</section>
`;
{
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 = `
<style>
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
</style>
<h2 id="name"></h2>
<slot name="description"></slot>
<section id="items">
<slot name="item"></slot>
</section>
`;
}
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 = `
<style>
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
#item {
display: flex;
justify-content: space-between;
}
h3 {
font-weight: normal;
}
#price {
font-weight: bold;
}
</style>
<section id="item">
<h3 id="name"></h3>
<ow-price id="price" />
</section>
`;
}
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 = `
<style>
:host { display: block; }
* { font-family: 'Noto Sans', sans-serif; }
#price {
font-weight: bold;
}
</style>
<span id="price"></span>
`;
}
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'
}
});