StaticApps/src/app/Core/CustomElements.js

258 lines
8.1 KiB
JavaScript

(() => {
class NavItem extends HTMLElement {
constructor() {
super()
if (!this.hasAttribute('tabindex')) {
this.setAttribute('tabindex', '0');
}
}
}
class VInput extends HTMLElement {
constructor() {
super();
let self = this;
self.id = self.id || VUtils.tempId();
let val = self.innerHTML;
self.innerHTML = '';
let input = self.input = self.createNew('input', {id: self.id})
let label = self.createNew('label', {content: self.dataset.label});
self.createNew('span', {classes: 'error', content: self.dataset.error});
label.setAttribute('for', self.id);
input.type = self.getAttribute('type') || 'text';
input.value = val.trim();
input.required = self.hasAttribute('required');
input.name = self.getAttribute('name');
input.addMultiListener('change input', self.cb.bind(self));
}
get value() {
return this.input.value;
}
connectedCallback() {
this.cb({currentTarget: this.input}, true);
}
cb(e, noInvalid) {
let el = e.currentTarget
let errorMessage = $('.error-message', el.find('form'));
if (errorMessage) {
errorMessage.classList.add('hide')
}
let cl = this.classList;
if (el.value === "") {
cl.remove('focus')
} else {
cl.add('focus')
}
if (el.checkValidity()) {
cl.add('valid');
cl.remove('invalid');
} else {
if (!noInvalid) {
cl.remove('valid');
cl.add('invalid');
}
}
}
}
class VSwitch extends HTMLElement {
constructor() {
super();
const id = this.dataset.id || VUtils.tempId();
$('input', this).id = id;
$('label', this).setAttribute('for', id);
}
}
class VSlider extends HTMLElement {
constructor() {
super();
this.input = $('input', this);
this.input.id = this.dataset.id || VUtils.tempId();
this.input.addEventListener('input', this.changeValue.bind(this));
this.cur = $('.current', this);
this.cur.addEventListener('input', this.onChange.bind(this));
this.cur.addEventListener('keypress', this.onKey.bind(this));
this.cur.addEventListener('focusout', this.onChange.bind(this));
this.checkStepSize();
this.minLabel = $('.min', this);
this.maxLabel = $('.max', this);
}
checkStepSize() {
const stepSize = this.input.getAttribute('step');
const max = parseFloat(this.input.getAttribute('max'));
const min = parseFloat(this.input.getAttribute('min'));
if (stepSize === "" && max - min <= 1) {
this.input.setAttribute('step', "0.05");
}
}
set value(value) {
this.input.value = value;
this.changeValue();
this.dispatchEvent(new Event('input'));
}
get value() {
return this.input.value;
}
set max(value) {
this.input.max = value;
this.maxLabel.innerHTML = value;
}
get max() {
return this.input.max;
}
set min(value) {
this.input.min = value;
this.minLabel.innerHTML = value;
}
get min() {
return this.input.min;
}
onKey(evt) {
const code = evt.keyCode;
if (code === 44 || code === 46) return;
if (code < 48 || code > 57 || code === 13) evt.preventDefault();
}
changeValue() {
this.cur.innerText = this.input.value;
}
onChange(e) {
if (e.type === 'focusout') {
this.cur.innerText = this.input.value;
return;
}
try {
const text = this.cur.innerText.trim();
if (text === '') {
this.cur.innerText = 0;
}
let val = parseFloat(text.replace(",", "."));
let min = parseFloat(this.input.getAttribute('min'));
let max = parseFloat(this.input.getAttribute('max'));
if (val < min) val = min;
if (val > max) val = max;
if (isNaN(val)) {
val = this.input.value;
}
let step = this.input.step || 1;
if (Math.floor(step) === step) {
val = Math.round(val);
}
this.input.value = val;
} catch (err) {
this.cur.innerText = this.input.value;
PrettyConsole.error(VSlider, err);
}
}
}
class VColor extends HTMLElement {
constructor() {
super();
this.input = $('input', this);
this.blob = $('.colorBlob', this);
this.addEventListener('input', this.onChange.bind(this));
}
onChange() {
requestAnimationFrame(() => {
this.blob.style.backgroundColor = this.input.value;
});
}
set value(value) {
this.input.value = value;
this.onChange();
this.dispatchEvent(new Event('input'));
}
get value() {
return this.input.value;
}
}
class VCollapseHead extends HTMLElement {
constructor() {
super();
if (!$('.btn-ripple', this)) {
this.createNew('div', {
classes: ['ripple']
});
}
}
}
class GUIItem extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
requestAnimationFrame(() => {
this.update();
})
}
update() {
let bindItem = $('[data-bind]', this);
if (bindItem && bindItem.dataset.bind && bindItem.dataset.bind.trim() !== '') {
let bind = bindItem.dataset.bind;
if (bindItem.nodeName === 'INPUT' && bindItem.type === 'checkbox') {
bindItem.checked = config.get(bind, bindItem.checked);
} else if (bindItem.nodeName === 'V-SELECT') {
this.initVSelect(bindItem, bind);
} else {
bindItem.value = config.get(bind, bindItem.value);
}
if (!bindItem._hasEvent) {
bindItem.addEventListener('input', () => {
if (bindItem.nodeName === 'INPUT' && bindItem.type === 'checkbox') {
config.set(bind, bindItem.checked);
} else if (bindItem.nodeName === 'V-SELECT') {
config.set(bind, bindItem.rawValue);
} else {
config.set(bind, bindItem.value);
}
bindItem._hasEvent = true;
});
}
}
}
initVSelect(bindItem, bind) {
let value = config.get(bind, bindItem.rawValue).toString().split(", ");
bindItem.options.forEach(item => {
if (value.indexOf(item.value) === -1) {
item.removeAttribute('selected');
} else {
item.setAttribute('selected', value.indexOf(item.value) !== -1);
}
})
}
}
customElements.define("v-input", VInput);
customElements.define("v-switch", VSwitch);
customElements.define("v-slider", VSlider);
customElements.define("v-color", VColor);
customElements.define("nav-item", NavItem);
customElements.define("v-gui-item", GUIItem);
customElements.define("v-collapse-head", VCollapseHead);
})();