1
0
Fork 0
upl/web/src/derive.js

93 lines
1.9 KiB
JavaScript

import * as time from './time';
class InvalidInputError extends Error {
constructor(problems) {
super(`Invalid input: ${problems.join(', ')}`);
this.problems = problems;
}
}
class Deriver {
constructor(output, inputs, notice=null) {
this.output = output;
this.inputs = inputs;
this.notice = notice;
}
get values() {
return this.inputs.map(input => input.value);
}
bind() {
this.inputs.forEach(input => {
input.addEventListener('input', () => {
this.update();
});
});
}
update() {
try {
const output = this.derive();
this.output.value = output;
this.showError();
} catch (e) {
console.error(e);
this.showError(e);
}
}
showError(error='') {
if (!this.notice) {
return;
}
let message = error.message || error.toString();
if (Array.isArray(error.problems)) {
message = 'Invalid input: ' + error.problems.join(', ');
}
this.notice.innerText = message;
}
}
class DurationDeriver extends Deriver {
derive() {
const [ number, units ] = this.values;
const n = parseInt(number, 10);
if (!isFinite(n)) {
throw new InvalidInputError([`provided duration is not a number`]);
}
switch (units) {
case 's':
return n * time.SECOND;
case 'm':
return n * time.MINUTE;
case 'h':
return n * time.HOUR;
case 'd':
return n * 24 * time.HOUR;
}
throw new InvalidInputError([`unit ${units} is not valid`]);
}
}
const derivers = {
duration: DurationDeriver,
};
const deriveInputs = document.querySelectorAll('[data-derive]');
deriveInputs.forEach(deriveInput => {
const [ type, ...inputNames ] = deriveInput.dataset.derive.split(',');
if (!type in derivers) {
return;
}
const inputs = inputNames.map(inputName => document.querySelector(`[name="${inputName}"]`));
const notice = document.querySelector(deriveInput.dataset.deriveNotice);
const deriver = new derivers[type](deriveInput, inputs, notice);
deriver.bind();
deriver.update();
});