mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 09:35:49 +02:00
207 lines
No EOL
5.3 KiB
JavaScript
207 lines
No EOL
5.3 KiB
JavaScript
const DEFAULT_OPTIONS = {
|
|
true: "true",
|
|
false: "false",
|
|
null: "indeterminate",
|
|
};
|
|
|
|
/**
|
|
* A simple tristate checkbox
|
|
*/
|
|
export default class TristateCheckbox {
|
|
|
|
static instances = new Map();
|
|
|
|
/**
|
|
*
|
|
* @type {null|boolean}
|
|
* @private
|
|
*/
|
|
_state = false;
|
|
|
|
/**
|
|
* The element representing the checkbox.
|
|
* @type {HTMLInputElement}
|
|
* @private
|
|
*/
|
|
_element = null;
|
|
|
|
/**
|
|
* The hidden input element representing the value of the checkbox
|
|
* @type {HTMLInputElement}
|
|
* @private
|
|
*/
|
|
_hiddenInput = null;
|
|
|
|
/**
|
|
* The values of the checkbox.
|
|
* @type {{null: string, true: string, false: string}}
|
|
* @private
|
|
*/
|
|
_options = DEFAULT_OPTIONS;
|
|
|
|
/**
|
|
* Retrieve the instance of the TristateCheckbox for the given element if already existing, otherwise a new one is created.
|
|
* @param element
|
|
* @param options
|
|
* @return {any}
|
|
*/
|
|
static getInstance(element, options = {})
|
|
{
|
|
if(!TristateCheckbox.instances.has(element)) {
|
|
TristateCheckbox.instances.set(element, new TristateCheckbox(element, options));
|
|
}
|
|
|
|
return TristateCheckbox.instances.get(element);
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} element
|
|
*/
|
|
constructor(element, options = {})
|
|
{
|
|
if(!element instanceof HTMLInputElement || !(element.tagName === 'INPUT' && element.type === 'checkbox')) {
|
|
throw new Error("The given element is not an input checkbox");
|
|
}
|
|
|
|
//Apply options
|
|
this._options = Object.assign(this._options, options);
|
|
|
|
this._element = element;
|
|
|
|
//Set the state of our element to the value of the passed input value
|
|
this._parseInitialState();
|
|
|
|
//Create a hidden input field to store the value of the checkbox, because this will be always be submitted in the form
|
|
this._hiddenInput = document.createElement('input');
|
|
this._hiddenInput.type = 'hidden';
|
|
this._hiddenInput.name = this._element.name;
|
|
this._hiddenInput.value = this._element.value;
|
|
|
|
//Insert the hidden input field after the checkbox and remove the checkbox from form submission (by removing the name property)
|
|
element.after(this._hiddenInput);
|
|
this._element.removeAttribute('name');
|
|
|
|
//Do a refresh to set the correct styling of the checkbox
|
|
this._refresh();
|
|
|
|
this._element.addEventListener('click', this.click.bind(this));
|
|
}
|
|
|
|
/**
|
|
* Parse the attributes of the checkbox and set the correct state.
|
|
* @private
|
|
*/
|
|
_parseInitialState()
|
|
{
|
|
if(this._element.hasAttribute('value')) {
|
|
this._state = this._stringToState(this._element.getAttribute('value'));
|
|
return;
|
|
}
|
|
|
|
if(this._element.checked) {
|
|
this._state = true;
|
|
return;
|
|
}
|
|
|
|
if(this._element.indeterminate) {
|
|
this._state = null;
|
|
return;
|
|
}
|
|
|
|
this._state = false;
|
|
}
|
|
|
|
_refresh()
|
|
{
|
|
this._element.indeterminate = this._state === null;
|
|
this._element.checked = this._state === true;
|
|
//Set the value field of the checkbox and the hidden input to correct value
|
|
this._element.value = this._stateToString(this._state);
|
|
this._hiddenInput.value = this._stateToString(this._state);
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns the current state of the checkbox. True if checked, false if unchecked, null if indeterminate.
|
|
* @return {boolean|null}
|
|
*/
|
|
get state() {
|
|
return this._state;
|
|
}
|
|
|
|
/**
|
|
* Sets the state of the checkbox. True if checked, false if unchecked, null if indeterminate.
|
|
* @param state
|
|
*/
|
|
set state(state) {
|
|
this._state = state;
|
|
this._refresh();
|
|
}
|
|
|
|
/**
|
|
* Returns the current state of the checkbox as string, according to the options.
|
|
* @return {string}
|
|
*/
|
|
get stateString() {
|
|
return this._stateToString(this._state);
|
|
}
|
|
|
|
set stateString(string) {
|
|
this.state = this._stringToState(string);
|
|
this._refresh();
|
|
}
|
|
|
|
/**
|
|
* @param {boolean|null} state
|
|
* @return string
|
|
* @private
|
|
*/
|
|
_stateToString(state)
|
|
{
|
|
if (this.state === null) {
|
|
return this._options.null;
|
|
} else if (this.state === true) {
|
|
return this._options.true;
|
|
} else if (this.state === false) {
|
|
return this._options.false;
|
|
}
|
|
|
|
throw new Error("Invalid state " + state);
|
|
}
|
|
|
|
/**
|
|
* Converts a string to a state according to the options.
|
|
* @param string
|
|
* @param throwError
|
|
* @return {null|boolean}
|
|
* @private
|
|
*/
|
|
_stringToState(string, throwError = true)
|
|
{
|
|
if (string === this._options.true) {
|
|
return true;
|
|
} else if (string === this._options.false) {
|
|
return false;
|
|
} else if (string === this._options.null) {
|
|
return null;
|
|
}
|
|
|
|
if(throwError) {
|
|
throw new Error("Invalid state string " + string);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
click()
|
|
{
|
|
switch (this._state) {
|
|
case true: this._state = false; break;
|
|
case false: this._state = null; break;
|
|
default: this._state = true; break;
|
|
}
|
|
|
|
this._refresh();
|
|
}
|
|
|
|
} |