Reformat JavaScript
This commit is contained in:
parent
b2154c3bd4
commit
e44bfa1c36
350
index.html
350
index.html
|
@ -19,199 +19,197 @@
|
||||||
<link rel="stylesheet" href="https://static.fwdekker.com/css/milligram-common.css" crossorigin="anonymous" />
|
<link rel="stylesheet" href="https://static.fwdekker.com/css/milligram-common.css" crossorigin="anonymous" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main class="wrapper">
|
<main class="wrapper">
|
||||||
<!-- Header -->
|
<!-- Header -->
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<section class="container">
|
|
||||||
<h1>Converter</h1>
|
|
||||||
<blockquote>
|
|
||||||
<p><em>Convert numbers to and from various bases.</em></p>
|
|
||||||
</blockquote>
|
|
||||||
</section>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Input -->
|
|
||||||
<section class="container">
|
<section class="container">
|
||||||
<div class="row">
|
<h1>Converter</h1>
|
||||||
<div class="column">
|
<blockquote>
|
||||||
<form>
|
<p><em>Convert numbers to and from various bases.</em></p>
|
||||||
<fieldset id="inputs">
|
</blockquote>
|
||||||
</fieldset>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<!-- Footer -->
|
<!-- Input -->
|
||||||
<footer class="footer">
|
<section class="container">
|
||||||
<section class="container">
|
<div class="row">
|
||||||
Made by <a href="https://fwdekker.com/">Felix W. Dekker</a>.
|
<div class="column">
|
||||||
Licensed under the
|
<form>
|
||||||
<a href="https://git.fwdekker.com/FWDekker/converter/src/branch/master/LICENSE">MIT License</a>.
|
<fieldset id="inputs">
|
||||||
Source code available on <a href="https://git.fwdekker.com/FWDekker/converter/">git</a>.
|
</fieldset>
|
||||||
</section>
|
</form>
|
||||||
</footer>
|
</div>
|
||||||
</main>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
<!-- Footer -->
|
||||||
<script src="https://static.fwdekker.com/js/common.js" crossorigin="anonymous"></script>
|
<footer class="footer">
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.44/BigInteger.min.js"
|
<section class="container">
|
||||||
integrity="sha256-es+ex6Oj344uak+VnCPyaHY2nzQkqhr7ByWVQgdjATA=" crossorigin="anonymous"></script>
|
Made by <a href="https://fwdekker.com/">Felix W. Dekker</a>.
|
||||||
<script>
|
Licensed under the
|
||||||
const stringReplaceAt = function (str, index, replacement) {
|
<a href="https://git.fwdekker.com/FWDekker/converter/src/branch/master/LICENSE">MIT License</a>.
|
||||||
return str.substr(0, index) + replacement + str.substr(index + replacement.length);
|
Source code available on <a href="https://git.fwdekker.com/FWDekker/converter/">git</a>.
|
||||||
};
|
</section>
|
||||||
|
</footer>
|
||||||
const stringReplaceAll = function (str, target, replacement) {
|
</main>
|
||||||
return str.split(target).join(replacement);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class NumeralSystem {
|
<!-- Scripts -->
|
||||||
constructor(base, alphabet, caseSensitive) {
|
<script src="https://static.fwdekker.com/js/common.js" crossorigin="anonymous"></script>
|
||||||
this.base = base;
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.44/BigInteger.min.js"
|
||||||
this.alphabet = alphabet;
|
integrity="sha256-es+ex6Oj344uak+VnCPyaHY2nzQkqhr7ByWVQgdjATA=" crossorigin="anonymous"></script>
|
||||||
this.caseSensitive = caseSensitive;
|
<script>
|
||||||
}
|
const stringReplaceAt =
|
||||||
|
(str, index, replacement) => str.substr(0, index) + replacement + str.substr(index + replacement.length);
|
||||||
|
|
||||||
|
const stringReplaceAll =
|
||||||
|
(str, target, replacement) => str.split(target).join(replacement);
|
||||||
|
|
||||||
|
|
||||||
decimalToBase(decimalNumber) {
|
class NumeralSystem {
|
||||||
return decimalNumber.toString(this.base, this.alphabet);
|
constructor(base, alphabet, caseSensitive) {
|
||||||
}
|
this.base = base;
|
||||||
|
this.alphabet = alphabet;
|
||||||
baseToDecimal(baseString) {
|
this.caseSensitive = caseSensitive;
|
||||||
return bigInt(baseString, this.base, this.alphabet, this.caseSensitive);
|
|
||||||
}
|
|
||||||
|
|
||||||
filterBaseString(baseString) {
|
|
||||||
// Regex from https://stackoverflow.com/a/3561711/
|
|
||||||
const regexSafeAlphabet = this.alphabet.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
||||||
return baseString.replace(new RegExp(`[^${regexSafeAlphabet}]`), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumeralSystemInput {
|
|
||||||
constructor(name, numeralSystem) {
|
|
||||||
this.name = name;
|
|
||||||
this.numeralSystem = numeralSystem;
|
|
||||||
|
|
||||||
this.label = document.createElement("label");
|
|
||||||
this.label.setAttribute("for", `${this.name}Input`);
|
|
||||||
this.label.innerHTML = this.name;
|
|
||||||
|
|
||||||
this.textarea = document.createElement("textarea");
|
|
||||||
this.textarea.id = `${this.name}Input`;
|
|
||||||
this.textarea.className = "numberInput";
|
|
||||||
this.textarea.oninput = () => {
|
|
||||||
if (this.textarea.value === undefined || this.textarea.value === null || this.textarea.value === "")
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
|
||||||
updateAllInputs(this.numeralSystem.baseToDecimal(this.textarea.value));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
addToParent(parent) {
|
|
||||||
parent.appendChild(this.label);
|
|
||||||
parent.appendChild(this.textarea);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(decimalNumber) {
|
|
||||||
this.textarea.value = this.numeralSystem.decimalToBase(decimalNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Base64NumeralSystemInput extends NumeralSystemInput {
|
|
||||||
static defaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
static dropdownOptions = {"Standard": ['+', '/'], "Filename": ['-', '_'], "IMAP": ['+', ',']};
|
|
||||||
|
|
||||||
|
|
||||||
constructor(name) {
|
|
||||||
super(name, new NumeralSystem(64, Base64NumeralSystemInput.defaultAlphabet, true));
|
|
||||||
|
|
||||||
this.dropdownLabel = document.createElement("label");
|
|
||||||
this.dropdownLabel.setAttribute("for", `${this.name}Dropdown`);
|
|
||||||
this.dropdownLabel.innerHTML = "Character set";
|
|
||||||
this.dropdownLabel.classList.add("label-inline");
|
|
||||||
|
|
||||||
this.dropdown = document.createElement("select");
|
|
||||||
this.dropdown.id = `${this.name}Dropdown`;
|
|
||||||
this.dropdown.onchange = () => {
|
|
||||||
const selectedOption = Base64NumeralSystemInput.dropdownOptions[this.dropdown.value];
|
|
||||||
this.setLastDigits(selectedOption[0], selectedOption[1]);
|
|
||||||
};
|
|
||||||
|
|
||||||
this.dropdownDiv = document.createElement("div");
|
|
||||||
this.dropdownDiv.classList.add("float-right");
|
|
||||||
|
|
||||||
this.options =
|
|
||||||
Object.keys(Base64NumeralSystemInput.dropdownOptions).map(key => {
|
|
||||||
const option = document.createElement("option");
|
|
||||||
option.value = key;
|
|
||||||
option.text = key + ": " + Base64NumeralSystemInput.dropdownOptions[key].join("");
|
|
||||||
return option;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setLastDigits(c62, c63) {
|
|
||||||
const oc62 = this.numeralSystem.alphabet[62];
|
|
||||||
const oc63 = this.numeralSystem.alphabet[63];
|
|
||||||
|
|
||||||
this.numeralSystem.alphabet =
|
|
||||||
stringReplaceAt(stringReplaceAt(this.numeralSystem.alphabet, 62, c62), 63, c63);
|
|
||||||
this.textarea.value =
|
|
||||||
stringReplaceAll(stringReplaceAll(this.textarea.value, oc62, c62), oc63, c63);
|
|
||||||
}
|
|
||||||
|
|
||||||
addToParent(parent) {
|
|
||||||
this.dropdownDiv.appendChild(this.dropdownLabel);
|
|
||||||
this.options.forEach(option => this.dropdown.appendChild(option));
|
|
||||||
this.dropdownDiv.appendChild(this.dropdown);
|
|
||||||
parent.appendChild(this.dropdownDiv);
|
|
||||||
|
|
||||||
parent.appendChild(this.label);
|
|
||||||
parent.appendChild(this.textarea);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const inputs = [
|
decimalToBase(decimalNumber) {
|
||||||
new NumeralSystemInput("Binary", new NumeralSystem(2, "01")),
|
return decimalNumber.toString(this.base, this.alphabet);
|
||||||
new NumeralSystemInput("Octal", new NumeralSystem(8, "01234567")),
|
}
|
||||||
new NumeralSystemInput("Decimal", new NumeralSystem(10, "0123456789")),
|
|
||||||
new NumeralSystemInput("Duodecimal", new NumeralSystem(12, "0123456789ab", caseSensitive = false)),
|
|
||||||
new NumeralSystemInput("Hexadecimal", new NumeralSystem(16, "0123456789abcdef", caseSensitive = false)),
|
|
||||||
new Base64NumeralSystemInput("Base64"),
|
|
||||||
new NumeralSystemInput(
|
|
||||||
"ASCII",
|
|
||||||
new NumeralSystem(
|
|
||||||
256,
|
|
||||||
new Array(256).fill(0).map((_, it) => String.fromCharCode(it)).join(""),
|
|
||||||
caseSensitive = true
|
|
||||||
)
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
const updateAllInputs = newValue => {
|
baseToDecimal(baseString) {
|
||||||
for (const input of inputs)
|
return bigInt(baseString, this.base, this.alphabet, this.caseSensitive);
|
||||||
input.update(newValue);
|
}
|
||||||
};
|
|
||||||
|
filterBaseString(baseString) {
|
||||||
|
// Regex from https://stackoverflow.com/a/3561711/
|
||||||
|
const regexSafeAlphabet = this.alphabet.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||||
|
return baseString.replace(new RegExp(`[^${regexSafeAlphabet}]`), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NumeralSystemInput {
|
||||||
|
constructor(name, numeralSystem) {
|
||||||
|
this.name = name;
|
||||||
|
this.numeralSystem = numeralSystem;
|
||||||
|
|
||||||
|
this.label = document.createElement("label");
|
||||||
|
this.label.setAttribute("for", `${this.name}Input`);
|
||||||
|
this.label.innerHTML = this.name;
|
||||||
|
|
||||||
|
this.textarea = document.createElement("textarea");
|
||||||
|
this.textarea.id = `${this.name}Input`;
|
||||||
|
this.textarea.className = "numberInput";
|
||||||
|
this.textarea.oninput = () => {
|
||||||
|
if (this.textarea.value === undefined || this.textarea.value === null || this.textarea.value === "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
||||||
|
updateAllInputs(this.numeralSystem.baseToDecimal(this.textarea.value));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
doAfterLoad(() => {
|
addToParent(parent) {
|
||||||
const inputParent = $("#inputs");
|
parent.appendChild(this.label);
|
||||||
|
parent.appendChild(this.textarea);
|
||||||
|
}
|
||||||
|
|
||||||
for (const input of inputs)
|
update(decimalNumber) {
|
||||||
input.addToParent(inputParent);
|
this.textarea.value = this.numeralSystem.decimalToBase(decimalNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updateAllInputs(bigInt(42));
|
class Base64NumeralSystemInput extends NumeralSystemInput {
|
||||||
inputs[0].textarea.focus();
|
static defaultAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||||
});
|
static dropdownOptions = {"Standard": ['+', '/'], "Filename": ['-', '_'], "IMAP": ['+', ',']};
|
||||||
</script>
|
|
||||||
|
|
||||||
|
constructor(name) {
|
||||||
|
super(name, new NumeralSystem(64, Base64NumeralSystemInput.defaultAlphabet, true));
|
||||||
|
|
||||||
|
this.dropdownLabel = document.createElement("label");
|
||||||
|
this.dropdownLabel.setAttribute("for", `${this.name}Dropdown`);
|
||||||
|
this.dropdownLabel.innerHTML = "Character set";
|
||||||
|
this.dropdownLabel.classList.add("label-inline");
|
||||||
|
|
||||||
|
this.dropdown = document.createElement("select");
|
||||||
|
this.dropdown.id = `${this.name}Dropdown`;
|
||||||
|
this.dropdown.onchange = () => {
|
||||||
|
const selectedOption = Base64NumeralSystemInput.dropdownOptions[this.dropdown.value];
|
||||||
|
this.setLastDigits(selectedOption[0], selectedOption[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dropdownDiv = document.createElement("div");
|
||||||
|
this.dropdownDiv.classList.add("float-right");
|
||||||
|
|
||||||
|
this.options =
|
||||||
|
Object.keys(Base64NumeralSystemInput.dropdownOptions).map(key => {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = key;
|
||||||
|
option.text = key + ": " + Base64NumeralSystemInput.dropdownOptions[key].join("");
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setLastDigits(c62, c63) {
|
||||||
|
const oc62 = this.numeralSystem.alphabet[62];
|
||||||
|
const oc63 = this.numeralSystem.alphabet[63];
|
||||||
|
|
||||||
|
this.numeralSystem.alphabet =
|
||||||
|
stringReplaceAt(stringReplaceAt(this.numeralSystem.alphabet, 62, c62), 63, c63);
|
||||||
|
this.textarea.value =
|
||||||
|
stringReplaceAll(stringReplaceAll(this.textarea.value, oc62, c62), oc63, c63);
|
||||||
|
}
|
||||||
|
|
||||||
|
addToParent(parent) {
|
||||||
|
this.dropdownDiv.appendChild(this.dropdownLabel);
|
||||||
|
this.options.forEach(option => this.dropdown.appendChild(option));
|
||||||
|
this.dropdownDiv.appendChild(this.dropdown);
|
||||||
|
parent.appendChild(this.dropdownDiv);
|
||||||
|
|
||||||
|
parent.appendChild(this.label);
|
||||||
|
parent.appendChild(this.textarea);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const inputs = [
|
||||||
|
new NumeralSystemInput("Binary", new NumeralSystem(2, "01")),
|
||||||
|
new NumeralSystemInput("Octal", new NumeralSystem(8, "01234567")),
|
||||||
|
new NumeralSystemInput("Decimal", new NumeralSystem(10, "0123456789")),
|
||||||
|
new NumeralSystemInput("Duodecimal", new NumeralSystem(12, "0123456789ab", caseSensitive = false)),
|
||||||
|
new NumeralSystemInput("Hexadecimal", new NumeralSystem(16, "0123456789abcdef", caseSensitive = false)),
|
||||||
|
new Base64NumeralSystemInput("Base64"),
|
||||||
|
new NumeralSystemInput(
|
||||||
|
"ASCII",
|
||||||
|
new NumeralSystem(
|
||||||
|
256,
|
||||||
|
new Array(256).fill(0).map((_, it) => String.fromCharCode(it)).join(""),
|
||||||
|
caseSensitive = true
|
||||||
|
)
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
const updateAllInputs = newValue => {
|
||||||
|
for (const input of inputs)
|
||||||
|
input.update(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
doAfterLoad(() => {
|
||||||
|
const inputParent = $("#inputs");
|
||||||
|
|
||||||
|
for (const input of inputs)
|
||||||
|
input.addToParent(inputParent);
|
||||||
|
|
||||||
|
updateAllInputs(bigInt(42));
|
||||||
|
inputs[0].textarea.focus();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in New Issue