Allow toggling of separator of ASCII
This commit is contained in:
parent
7ec5171adc
commit
567b364a59
|
@ -1,7 +1,6 @@
|
||||||
#inputs {
|
#inputs {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
align-items: start;
|
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
/*noinspection CssUnresolvedCustomProperty*/
|
/*noinspection CssUnresolvedCustomProperty*/
|
||||||
gap: var(--spacing);
|
gap: var(--spacing);
|
||||||
|
@ -9,10 +8,14 @@
|
||||||
|
|
||||||
#inputs article {
|
#inputs article {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
|
/* Make `textarea`s expand automatically */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
#inputs textarea {
|
#inputs textarea {
|
||||||
display: block;
|
display: block;
|
||||||
width: 25em;
|
width: 25em;
|
||||||
height: 5em;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
<meta name="fwd:footer:target" content="#footer" />
|
<meta name="fwd:footer:target" content="#footer" />
|
||||||
<meta name="fwd:footer:vcs-url" content="https://git.fwdekker.com/tools/converter/" />
|
<meta name="fwd:footer:vcs-url" content="https://git.fwdekker.com/tools/converter/" />
|
||||||
<meta name="fwd:footer:version" content="v%%VERSION_NUMBER%%" />
|
<meta name="fwd:footer:version" content="v%%VERSION_NUMBER%%" />
|
||||||
|
<meta name="fwd:validation:load-forms" />
|
||||||
|
|
||||||
<title>Converter | FWDekker</title>
|
<title>Converter | FWDekker</title>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
// noinspection JSUnresolvedVariable
|
// noinspection JSUnresolvedVariable
|
||||||
const {$, doAfterLoad, stringToHtml} = window.fwdekker;
|
const {$, doAfterLoad, stringToHtml} = window.fwdekker;
|
||||||
|
// noinspection JSUnresolvedVariable
|
||||||
|
const {clearInputValidity, showInputInvalid} = window.fwdekker.validation;
|
||||||
import bigInt from "big-integer";
|
import bigInt from "big-integer";
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,7 +79,7 @@ class NumeralSystem {
|
||||||
* @returns {string[]} the representations of `decimalNumbers` in this system
|
* @returns {string[]} the representations of `decimalNumbers` in this system
|
||||||
*/
|
*/
|
||||||
decimalsToBases(decimalNumbers) {
|
decimalsToBases(decimalNumbers) {
|
||||||
return decimalNumbers.map((it) => this.decimalToBase(it));
|
return decimalNumbers.map(it => this.decimalToBase(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +99,7 @@ class NumeralSystem {
|
||||||
* @returns {bigInt[]} the decimal representations of `baseStrings`
|
* @returns {bigInt[]} the decimal representations of `baseStrings`
|
||||||
*/
|
*/
|
||||||
basesToDecimals(baseStrings) {
|
basesToDecimals(baseStrings) {
|
||||||
return baseStrings.map((it) => this.baseToDecimal(it));
|
return baseStrings.map(it => this.baseToDecimal(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,22 +132,24 @@ class NumeralSystemInput {
|
||||||
constructor(name, numeralSystem) {
|
constructor(name, numeralSystem) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.numeralSystem = numeralSystem;
|
this.numeralSystem = numeralSystem;
|
||||||
const base = this.numeralSystem.base;
|
|
||||||
|
|
||||||
this.label = stringToHtml(`<label for="b${base}-input">${this.name} <small>(base ${base})</small></label>`);
|
|
||||||
|
|
||||||
this.textarea = stringToHtml(`<textarea id="b${base}-input" class="number-input"></textarea>`);
|
|
||||||
this.textarea.oninput = () => {
|
|
||||||
if (this.textarea.value == null || this.textarea.value === "")
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
|
||||||
updateAllInputs(this, this.numeralSystem.basesToDecimals(this.textarea.value.split(",")));
|
|
||||||
};
|
|
||||||
|
|
||||||
this.wrapper = document.createElement("article");
|
this.wrapper = document.createElement("article");
|
||||||
this.wrapper.appendChild(this.label);
|
const base = this.numeralSystem.base;
|
||||||
|
|
||||||
|
const label = stringToHtml(`<label for="b${base}-input">${this.name} <small>(base ${base})</small></label>`);
|
||||||
|
this.wrapper.appendChild(label);
|
||||||
|
|
||||||
|
this.textarea = stringToHtml(`<textarea id="b${base}-input" class="number-input"></textarea>`);
|
||||||
|
this.textarea.addEventListener("input", () => {
|
||||||
|
if (this.textarea.value === "") return;
|
||||||
|
|
||||||
|
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
||||||
|
updateAllInputs(this, this.numeralSystem.basesToDecimals(this.getValues()));
|
||||||
|
});
|
||||||
this.wrapper.appendChild(this.textarea);
|
this.wrapper.appendChild(this.textarea);
|
||||||
|
|
||||||
|
const hint = stringToHtml(`<small id="b${base}-input-hint" data-hint-for="b${base}-input"></small>`);
|
||||||
|
this.wrapper.appendChild(hint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,12 +162,21 @@ class NumeralSystemInput {
|
||||||
parent.appendChild(this.wrapper);
|
parent.appendChild(this.wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the input's values.
|
||||||
|
*
|
||||||
|
* @returns {string[]} the input's values expressed in the associated numeral system
|
||||||
|
*/
|
||||||
|
getValues() {
|
||||||
|
return this.textarea.value.split(",");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the input's value to contain this input's numeral system's representation of `decimalNumbers`.
|
* Updates the input's value to contain this input's numeral system's representation of `decimalNumbers`.
|
||||||
*
|
*
|
||||||
* @param decimalNumbers {bigInt[]} the decimal numbers to represent in the input
|
* @param decimalNumbers {bigInt[]} the decimal numbers to represent in the input
|
||||||
*/
|
*/
|
||||||
update(decimalNumbers) {
|
setValues(decimalNumbers) {
|
||||||
this.textarea.value = this.numeralSystem.decimalsToBases(decimalNumbers).join(",");
|
this.textarea.value = this.numeralSystem.decimalsToBases(decimalNumbers).join(",");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,21 +261,20 @@ class Base64NumeralSystemInput extends NumeralSystemInput {
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
super(name, new Base64NumeralSystem(Base64NumeralSystem.defaultAlphabet()));
|
super(name, new Base64NumeralSystem(Base64NumeralSystem.defaultAlphabet()));
|
||||||
|
|
||||||
this.dropdown = stringToHtml(`<select id="${this.numeralSystem.base}-dropdown"></select>`);
|
const dropdown = stringToHtml(`<select id="${this.numeralSystem.base}-dropdown"></select>`);
|
||||||
this.dropdown.onchange = () => {
|
dropdown.addEventListener("change", () => {
|
||||||
const selectedOption = Base64NumeralSystemInput.dropdownOptions()[this.dropdown.value];
|
const selectedOption = Base64NumeralSystemInput.dropdownOptions()[dropdown.value];
|
||||||
this.setLastDigits(selectedOption[0], selectedOption[1]);
|
this.setLastDigits(selectedOption[0], selectedOption[1]);
|
||||||
};
|
});
|
||||||
|
this.wrapper.appendChild(dropdown);
|
||||||
|
|
||||||
Object
|
Object
|
||||||
.keys(Base64NumeralSystemInput.dropdownOptions())
|
.keys(Base64NumeralSystemInput.dropdownOptions())
|
||||||
.forEach(key => {
|
.map(key => {
|
||||||
const text = key + ": " + Base64NumeralSystemInput.dropdownOptions()[key].join("");
|
const text = key + ": " + Base64NumeralSystemInput.dropdownOptions()[key].join("");
|
||||||
const option = stringToHtml(`<option value="${key}">${text}</option>`);
|
return stringToHtml(`<option value="${key}">${text}</option>`);
|
||||||
this.dropdown.appendChild(option);
|
})
|
||||||
});
|
.forEach(option => dropdown.appendChild(option));
|
||||||
|
|
||||||
this.wrapper.appendChild(this.dropdown);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -282,6 +294,64 @@ class Base64NumeralSystemInput extends NumeralSystemInput {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input field that contains a value in some numeral system, and can optionally interpret the separator symbol
|
||||||
|
* literally as part of its alphabet.
|
||||||
|
*
|
||||||
|
* Useful for numeral systems with separators in their alphabet. Lets the user decide whether to interpret those values
|
||||||
|
* as literals or as separators.
|
||||||
|
*/
|
||||||
|
class NumeralSystemInputWithToggleableSeparator extends NumeralSystemInput {
|
||||||
|
/**
|
||||||
|
* Constructs a new numeral system input, including HTML elements.
|
||||||
|
*
|
||||||
|
* @param name {string} the human-readable name of the system
|
||||||
|
* @param numeralSystem {NumeralSystem} the numeral system in which values in this input are expressed
|
||||||
|
*/
|
||||||
|
constructor(name, numeralSystem) {
|
||||||
|
if (!numeralSystem.alphabet.includes(","))
|
||||||
|
console.warn("Toggleable separator input incorrectly used on numeral system without comma in alphabet.");
|
||||||
|
|
||||||
|
super(name, numeralSystem);
|
||||||
|
this.textarea.addEventListener("input", () => clearInputValidity(this.textarea));
|
||||||
|
|
||||||
|
const id = `b${this.numeralSystem.base}-separator-toggle`;
|
||||||
|
const checkboxContainer = document.createElement("div");
|
||||||
|
this.wrapper.appendChild(checkboxContainer);
|
||||||
|
|
||||||
|
this.separatorCheckbox = stringToHtml(`<input type="checkbox" role="switch" id="${id}" checked />`);
|
||||||
|
this.separatorCheckbox.addEventListener("change", () => this.textarea.dispatchEvent(new InputEvent("input")));
|
||||||
|
checkboxContainer.appendChild(this.separatorCheckbox);
|
||||||
|
|
||||||
|
const label = stringToHtml(`<label for="${id}">Comma separates values</label>`);
|
||||||
|
checkboxContainer.appendChild(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getValues() {
|
||||||
|
if (this.separatorCheckbox.checked)
|
||||||
|
return super.getValues();
|
||||||
|
else
|
||||||
|
return [this.textarea.value];
|
||||||
|
}
|
||||||
|
|
||||||
|
setValues(decimalNumbers) {
|
||||||
|
clearInputValidity(this.textarea);
|
||||||
|
|
||||||
|
const baseStrings = this.numeralSystem.decimalsToBases(decimalNumbers);
|
||||||
|
if (baseStrings.length === 1) {
|
||||||
|
this.separatorCheckbox.checked = !baseStrings[0].includes(",");
|
||||||
|
this.textarea.value = baseStrings[0];
|
||||||
|
} else {
|
||||||
|
if (baseStrings.some(it => it.includes(",")))
|
||||||
|
showInputInvalid(this.textarea, "Contains a mixture of literal commas and separator commas.", false);
|
||||||
|
|
||||||
|
this.textarea.value = baseStrings.join(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All the inputs to display.
|
* All the inputs to display.
|
||||||
*
|
*
|
||||||
|
@ -294,7 +364,7 @@ const inputs = [
|
||||||
new NumeralSystemInput("Duodecimal", new NumeralSystem(12, "0123456789ab", false)),
|
new NumeralSystemInput("Duodecimal", new NumeralSystem(12, "0123456789ab", false)),
|
||||||
new NumeralSystemInput("Hexadecimal", new NumeralSystem(16, "0123456789abcdef", false)),
|
new NumeralSystemInput("Hexadecimal", new NumeralSystem(16, "0123456789abcdef", false)),
|
||||||
new Base64NumeralSystemInput("Base64"),
|
new Base64NumeralSystemInput("Base64"),
|
||||||
new NumeralSystemInput(
|
new NumeralSystemInputWithToggleableSeparator(
|
||||||
"ASCII",
|
"ASCII",
|
||||||
new NumeralSystem(
|
new NumeralSystem(
|
||||||
256,
|
256,
|
||||||
|
@ -313,7 +383,7 @@ const inputs = [
|
||||||
function updateAllInputs(source, newDecimalValues) {
|
function updateAllInputs(source, newDecimalValues) {
|
||||||
for (const input of inputs)
|
for (const input of inputs)
|
||||||
if (input !== source)
|
if (input !== source)
|
||||||
input.update(newDecimalValues);
|
input.setValues(newDecimalValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue