171 lines
4.2 KiB
JavaScript
171 lines
4.2 KiB
JavaScript
/**
|
|
* @typedef {'Y' | 'N'} ExactFigure
|
|
* @typedef {ExactFigure | 'indeterminate'} Figure
|
|
* @typedef {Record<string, Figure>} LanguageFigureMapping
|
|
*/
|
|
|
|
/**
|
|
* @param {string} lang
|
|
* @return {HTMLButtonElement}
|
|
*/
|
|
function createButton(lang) {
|
|
const btn = document.createElement('button');
|
|
btn.type = 'button';
|
|
btn.dataset.lang = lang;
|
|
btn.innerText = lang;
|
|
|
|
return btn;
|
|
}
|
|
|
|
/**
|
|
* @param {string} lang
|
|
* @param {string|undefined} namePrefix
|
|
* @return {HTMLInputElement}
|
|
*/
|
|
function createInput(lang, namePrefix = undefined) {
|
|
const ipt = document.createElement('input');
|
|
ipt.type = 'hidden';
|
|
ipt.name = `${namePrefix}[${lang}]`;
|
|
ipt.dataset.lang = lang;
|
|
|
|
return ipt;
|
|
}
|
|
|
|
/**
|
|
* @param {Figure} figure
|
|
* @param {ExactFigure|undefined} parentFigure
|
|
* @return {string}
|
|
*/
|
|
function resolveFigureClassName(figure, parentFigure = undefined) {
|
|
switch (figure) {
|
|
case 'Y': return 'btn-success';
|
|
case 'N': return 'btn-danger';
|
|
case 'indeterminate':
|
|
if (!parentFigure) {
|
|
throw new Error('Parent figure is undefined');
|
|
}
|
|
return `${resolveFigureClassName(parentFigure)}-indeterminate`;
|
|
}
|
|
}
|
|
|
|
export class WpjTranslationsFigure {
|
|
/** @type {ExactFigure} */
|
|
#parentFigure;
|
|
|
|
/** @type {LanguageFigureMapping} */
|
|
#initialState;
|
|
|
|
/** @type {string} */
|
|
inputNamePrefix;
|
|
|
|
/** @type {HTMLButtonElement[]} */
|
|
buttons = [];
|
|
|
|
/** @type {Map<string, HTMLInputElement>} */
|
|
inputs = new Map();
|
|
|
|
/**
|
|
* @param {string[]} languages
|
|
* @param {string} inputNamePrefix
|
|
* @param {ExactFigure} parentFigure
|
|
*/
|
|
constructor(languages, inputNamePrefix, parentFigure = 'Y') {
|
|
this.#initialState = Object.fromEntries(languages.map(l => [l, 'indeterminate']));
|
|
this.inputNamePrefix = inputNamePrefix;
|
|
this.#parentFigure = parentFigure;
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} target
|
|
*/
|
|
render(target) {
|
|
for (const lang of this.languages) {
|
|
const btn = createButton(lang);
|
|
const ipt = createInput(lang, this.inputNamePrefix);
|
|
ipt.value = this.#initialState[lang] ?? 'indeterminate';
|
|
|
|
btn.insertAdjacentElement('beforeend', ipt);
|
|
btn.addEventListener('click', this.handleValueChange.bind(this));
|
|
|
|
this.buttons.push(btn);
|
|
this.inputs.set(lang, ipt);
|
|
|
|
target.insertAdjacentElement('beforeend', btn);
|
|
}
|
|
|
|
this.applyStyles();
|
|
}
|
|
|
|
/** @param {MouseEvent} ev */
|
|
handleValueChange(ev) {
|
|
const lang = ev.currentTarget.dataset.lang;
|
|
const ipt = this.inputs.get(lang);
|
|
|
|
switch (ipt.value) {
|
|
case 'Y': ipt.value = 'N'; break;
|
|
case 'N': ipt.value = 'indeterminate'; break;
|
|
case 'indeterminate': ipt.value = 'Y'; break;
|
|
}
|
|
|
|
ipt.dispatchEvent(new Event('change'));
|
|
window.somethingChanged = true;
|
|
this.applyStyles();
|
|
}
|
|
|
|
applyStyles() {
|
|
for (const btn of this.buttons) {
|
|
const lang = btn.dataset.lang;
|
|
const input = this.inputs.get(lang);
|
|
if (!input) {
|
|
return;
|
|
}
|
|
|
|
btn.className = 'btn ' + resolveFigureClassName(input.value, this.parentFigure);
|
|
}
|
|
}
|
|
|
|
/** @param {ExactFigure} figure */
|
|
set parentFigure(figure) {
|
|
this.#parentFigure = figure;
|
|
this.applyStyles();
|
|
}
|
|
|
|
get parentFigure() {
|
|
return this.#parentFigure;
|
|
}
|
|
|
|
get languages() {
|
|
return Object.keys(this.#initialState);
|
|
}
|
|
|
|
/** @param {string} language */
|
|
valueOf(language) {
|
|
return this.inputs.get(language)?.value;
|
|
}
|
|
|
|
get values() {
|
|
return Object.fromEntries([...this.inputs.entries()].map(([k, v]) => [k, v.value]));
|
|
}
|
|
|
|
/**
|
|
* @param {LanguageFigureMapping} state
|
|
*/
|
|
setState(state) {
|
|
for (const lang in state) {
|
|
if (!(lang in this.#initialState)) {
|
|
continue;
|
|
}
|
|
|
|
this.#initialState[lang] = state[lang];
|
|
}
|
|
}
|
|
|
|
toggleParentFigure() {
|
|
return this.parentFigure = this.parentFigure === 'Y' ? 'N' :'Y';
|
|
}
|
|
}
|
|
|
|
$(() => {
|
|
wpj.TranslationsFigure = WpjTranslationsFigure;
|
|
});
|