mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-22 12:23:04 -07:00
139 lines
2.6 KiB
JavaScript
139 lines
2.6 KiB
JavaScript
const FIXED_PRIVATE_TEXT = "*****";
|
|
|
|
let hidden = false;
|
|
const effects = /** @type {RedactionEffect[]} */ ([]);
|
|
|
|
/**
|
|
* @typedef {"exact" | "fixed"} RedactionMode
|
|
*
|
|
* @typedef {Object} RedactionEffect
|
|
* @property {HTMLElement} element
|
|
* @property {() => void} sync
|
|
*/
|
|
|
|
function isHidden() {
|
|
return hidden;
|
|
}
|
|
|
|
/**
|
|
* @param {string} value
|
|
*/
|
|
function createText(value) {
|
|
return [...value].map((character) => {
|
|
return character === " " ? " " : "*";
|
|
}).join("");
|
|
}
|
|
|
|
/**
|
|
* @param {string} value
|
|
* @param {RedactionMode} mode
|
|
*/
|
|
function mask(value, mode) {
|
|
return mode === "fixed" ? FIXED_PRIVATE_TEXT : createText(value);
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} element
|
|
* @param {() => void} sync
|
|
*/
|
|
function addEffect(element, sync) {
|
|
effects.push({ element, sync });
|
|
sync();
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} element
|
|
* @param {string} value
|
|
* @param {RedactionMode} [mode]
|
|
*/
|
|
function setValue(element, value, mode = "exact") {
|
|
addEffect(element, () => {
|
|
element.textContent = hidden ? mask(value, mode) : value;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} element
|
|
* @param {string} value
|
|
*/
|
|
function setTitle(element, value) {
|
|
addEffect(element, () => {
|
|
element.title = hidden ? createText(value) : value;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLElement} element
|
|
* @param {string} value
|
|
* @param {(text: string) => void} render
|
|
*/
|
|
function setAddress(element, value, render) {
|
|
addEffect(element, () => {
|
|
render(hidden ? createText(value) : value);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLInputElement} input
|
|
*/
|
|
function setInput(input) {
|
|
addEffect(input, () => {
|
|
input.type = hidden ? "password" : "text";
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @template {keyof HTMLElementTagNameMap} Tag
|
|
* @param {Tag} tag
|
|
* @param {string} value
|
|
* @param {RedactionMode} [mode]
|
|
*/
|
|
function createValue(tag, value, mode = "exact") {
|
|
const element = document.createElement(tag);
|
|
|
|
setValue(element, value, mode);
|
|
|
|
return element;
|
|
}
|
|
|
|
function sync() {
|
|
for (let index = effects.length - 1; index >= 0; index -= 1) {
|
|
const effect = effects[index];
|
|
|
|
if (!effect.element.isConnected) {
|
|
effects.splice(index, 1);
|
|
} else {
|
|
effect.sync();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLButtonElement} button
|
|
*/
|
|
function syncButton(button) {
|
|
button.textContent = hidden ? "Reveal" : "Privacy";
|
|
button.setAttribute("aria-pressed", hidden ? "true" : "false");
|
|
}
|
|
|
|
/**
|
|
* @param {HTMLButtonElement} button
|
|
*/
|
|
function toggle(button) {
|
|
hidden = !hidden;
|
|
sync();
|
|
syncButton(button);
|
|
}
|
|
|
|
export const redaction = /** @type {const} */ ({
|
|
isHidden,
|
|
createText,
|
|
setValue,
|
|
setTitle,
|
|
setAddress,
|
|
setInput,
|
|
createValue,
|
|
syncButton,
|
|
toggle,
|
|
});
|