StaticApps/src/app/External/SelectJs.js

211 lines
6.3 KiB
JavaScript

(function () {
window._openVSelect = null;
requestAnimationFrame(e => {
document.body.addEventListener('click', ev => {
if (window._openVSelect && ev.target.closest('v-select') !== window._openVSelect) {
window._openVSelect.toggle(false);
}
})
})
class VSelectElement extends HTMLElement {
constructor() {
super();
let self = this;
self.rawValue = "";
self.setAttribute('tabindex', '0');
requestAnimationFrame(() => {
self.update();
})
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
this.dispatchEvent(new Event('input'));
}
get required() {
return this.hasAttribute('required');
}
set required(flag) {
this.toggleAttribute('required', Boolean(flag));
}
get name() {
return this.getAttribute('name');
}
set name(val) {
this.toggleAttribute('name', val);
}
get form() {
return this.closest('form');
}
get options() {
return $$('v-options v-option', this);
}
get selected() {
return $$('v-options v-option[selected]', this);
}
connectedCallback() {
/* const selected = this.selected;
if (selected) return;*/
const options = Array.prototype.slice.call(this.options);
const values = this.dataset.value ? this.dataset.value.split(",") : [""];
if (values.length === 1 && values[0].trim() === '') {
return;
}
options
.filter(item => values.indexOf(item.getAttribute('value')) !== -1)
.forEach(item => item.setAttribute('selected', 'true'));
}
update() {
let selected = [],
lbl = $('v-label', this),
fd = new FormData();
this.selected.forEach(e => {
selected.push(e.innerText);
fd.append(this.name, e.value);
})
if (lbl.attributeChangedCallback) {
lbl.attributeChangedCallback('value', '', selected.join(", "));
}
this.isValid = !(this.required && selected.length === 0);
this.rawValue = selected.join(", ");
this.value = fd;
}
checkValidity() {
return this.isValid;
}
toggle(open) {
if (window._openVSelect && window._openVSelect.toggleSelect && open) {
window._openVSelect.toggleSelect(false);
}
const options = $('v-options', this);
if (!open || this.isOpen) {
options.style.maxHeight = '0';
window._openVSelect = false;
this.isOpen = false;
this.update();
} else {
options.focus();
let height = 0,
children = options.children;
for (let i = 0; i < children.length; i++) {
height += children[i].offsetHeight;
}
options.style.maxHeight = height + 'px';
window._openVSelect = this;
this.isOpen = true;
}
let l = $('v-label', this).classList;
if (this.isOpen) {
l.add('open');
} else {
l.remove('open');
}
}
}
class VSelectOptionElement extends HTMLElement {
constructor() {
super();
this._value = this.getAttribute('value');
this.addEventListener('click', e => {
let parent = this.parentNode.parentNode,
select = !this.selected;
if (!parent.hasAttribute('multiple')) {
parent.toggle(false);
for (let item of parent.selected) {
if (item !== this) {
item.removeAttribute('selected');
}
}
}
if (!this.disabled) {
this.attributeChangedCallback('selected', false, select, true);
this.parentNode.parentNode.update();
}
});
this.createNew('div', {classes: ['ripple']});
}
static get observedAttributes() {
return ['selected', 'disabled', 'value'];
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
}
attributeChangedCallback(name, oldValue, newValue, force) {
if (name === 'selected' && this.hasAttribute('disabled')) {
this.removeAttribute(name);
return;
}
if (name === 'disabled' && newValue === true && this.hasAttribute('selected')) {
this.attributeChangedCallback('selected', false, false);
}
if (force) {
if (newValue) {
this.setAttribute(name, newValue);
} else {
this.removeAttribute(name);
}
}
this[name] = newValue;
}
}
class VLabel extends HTMLElement {
constructor() {
super();
this.span = this.createNew('span');
this.createNew('div', {classes: ['ripple']});
this.empty = this.getAttribute('empty') || "";
this.span.innerHTML = this.getAttribute("value") || this.empty;
this.addEventListener('click', this.openPopUp.bind(this));
}
static get observedAttributes() {
return ['empty', 'value'];
}
openPopUp() {
this.parentNode.toggle(true);
}
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'value') {
this.span.innerHTML = newValue || this.empty;
}
this[name] = newValue;
}
}
customElements.define("v-label", VLabel);
customElements.define("v-option", VSelectOptionElement);
customElements.define("v-select", VSelectElement);
})();