211 lines
6.3 KiB
JavaScript
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);
|
|
})();
|
|
|
|
|