oxe
Version:
A mighty tiny web components framework/library
115 lines (93 loc) • 4.6 kB
JavaScript
import format from './format.js';
import dates from './dates.js';
console.warn('value: setter/getter issue with multiselect');
const defaultInputEvent = new Event('input');
const parseable = function (value) {
return !isNaN(value) && value !== null && value !== undefined && typeof value !== 'string';
};
const stampFromView = function (data) {
const date = new Date(data);
return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds()).getTime();
};
const stampToView = function (data) {
const date = new Date(data);
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(),
date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds())).getTime();
};
const input = function (binder, event) {
let value, checked;
if (binder.node.type === 'select-one') {
const [ option ] = binder.node.selectedOptions;
value = option ? '$value' in option ? option.$value : option.value : undefined;
} else if (binder.node.type === 'select-multiple') {
value = [];
for (const option of binder.node.selectedOptions) {
value.push('$value' in option ? option.$value : option.value);
}
} else if (binder.node.type === 'number' || binder.node.type === 'range') {
value = binder.node.valueAsNumber;
} else if (dates.includes(binder.node.type)) {
value = typeof binder.node.$value === 'string' ? binder.node.value : stampFromView(binder.node.valueAsNumber);
} else {
value = '$value' in binder.node && parseable(binder.node.$value) ? JSON.parse(binder.node.value) : binder.node.value;
checked = '$value' in binder.node && parseable(binder.node.$value) ? JSON.parse(binder.node.checked) : binder.node.checked;
}
binder.compute({ $event: event, $value: value, $checked: checked, $assignment: true });
};
const valueRender = function (binder) {
if (!binder.setup) {
binder.setup = true;
binder.node.addEventListener('input', function valueRenderInputEvent (event) {
input(binder, event);
});
}
const computed = binder.compute({ $event: undefined, $value: undefined, $checked: undefined, $assignment: false });
let display;
if (binder.node.type === 'select-one') {
binder.node.value = undefined;
for (const option of binder.node.options) {
const optionValue = '$value' in option ? option.$value : option.value;
if (option.selected = optionValue === computed) break;
}
if (computed === undefined && binder.node.options.length && !binder.node.selectedOptions.length) {
const [ option ] = binder.node.options;
option.selected = true;
return binder.node.dispatchEvent(defaultInputEvent);
}
display = format(computed);
binder.node.value = display;
} else if (binder.node.type === 'select-multiple') {
for (const option of binder.node.options) {
const optionValue = '$value' in option ? option.$value : option.value;
option.selected = computed?.includes(optionValue);
}
display = format(computed);
} else if (binder.node.type === 'number' || binder.node.type === 'range') {
if (typeof computed === 'number' && computed !== Infinity) binder.node.valueAsNumber = computed;
else binder.node.value = computed;
display = binder.node.value;
} else if (dates.includes(binder.node.type)) {
if (typeof computed === 'string') binder.node.value = computed;
else binder.node.valueAsNumber = stampToView(computed);
display = binder.node.value;
} else {
display = format(computed);
binder.node.value = display;
}
binder.node.$value = computed;
if (binder.node.type === 'checked' || binder.node.type === 'radio') binder.node.$checked = computed;
binder.node.setAttribute('value', display);
};
const valueDerender = function (binder) {
if (binder.node.type === 'select-one' || binder.node.type === 'select-multiple') {
for (const option of binder.node.options) {
option.selected = false;
}
}
binder.node.value = undefined;
binder.node.$value = undefined;
if (binder.node.type === 'checked' || binder.node.type === 'radio') binder.node.$checked = undefined;
binder.node.setAttribute('value', '');
};
export default { render: valueRender, derender: valueDerender };