update sequence nav to use new ui-sequence-nav component

This commit is contained in:
2026-07-06 19:38:49 -07:00
parent 5b1df48883
commit 3b666611c6
8 changed files with 1106 additions and 119 deletions
+359 -29
View File
@@ -14,7 +14,11 @@
inputLabelEl: null,
cipherLabelEl: null,
reverseCiphersEl: null,
reverseCipherHintEl: null
reverseCipherHintEl: null,
keyboardEl: null,
keyboardScriptEl: null,
keyboardGridEl: null,
keyboardActionsEl: null
})
};
@@ -35,7 +39,8 @@
dictionaryLookupCache: new Map(),
reverseRequestId: 0,
anagramRequestId: 0,
dictionaryRequestId: 0
dictionaryRequestId: 0,
keyboardScriptId: "english"
};
function getAlphabets() {
@@ -57,10 +62,184 @@
inputLabelEl: null,
cipherLabelEl: null,
reverseCiphersEl: null,
reverseCipherHintEl: null
reverseCipherHintEl: null,
keyboardEl: null,
keyboardScriptEl: null,
keyboardGridEl: null,
keyboardActionsEl: null
};
}
function uniqueChars(values) {
return Array.from(new Set((Array.isArray(values) ? values : [])
.map((value) => String(value || "").trim())
.filter(Boolean)));
}
function collectAlphabetChars(entries, keys) {
const sourceEntries = Array.isArray(entries) ? entries : [];
const sourceKeys = Array.isArray(keys) ? keys : [];
const chars = [];
sourceEntries.forEach((entry) => {
sourceKeys.forEach((key) => {
const value = String(entry?.[key] || "").trim();
if (!value) {
return;
}
const firstChar = [...value][0] || "";
if (firstChar) {
chars.push(firstChar);
}
});
});
return uniqueChars(chars);
}
function getKeyboardLayouts() {
const db = state.db || getFallbackGematriaDb();
const alphabets = getAlphabets() || {};
const englishChars = uniqueChars(String(db.baseAlphabet || "abcdefghijklmnopqrstuvwxyz").toLowerCase().split(""));
const hebrewChars = collectAlphabetChars(alphabets.hebrew, ["char"]);
const greekChars = collectAlphabetChars([...(alphabets.greek || []), ...(alphabets.greekArchaic || [])], ["charLower", "char", "charFinal"]);
const arabicChars = collectAlphabetChars(alphabets.arabic, ["char"]);
const enochianChars = collectAlphabetChars(alphabets.enochian, ["char"]);
return [
{ id: "english", label: "English", chars: englishChars },
{ id: "hebrew", label: "Hebrew", chars: hebrewChars },
{ id: "greek", label: "Greek", chars: greekChars },
{ id: "arabic", label: "Arabic", chars: arabicChars },
{ id: "enochian", label: "Enochian", chars: enochianChars }
].filter((layout) => layout.chars.length > 0);
}
function setGematriaInputValue(nextValue) {
const { inputEl } = getElements();
if (!(inputEl instanceof HTMLTextAreaElement)) {
return;
}
inputEl.value = String(nextValue || "");
inputEl.dispatchEvent(new Event("input", { bubbles: true }));
inputEl.focus({ preventScroll: true });
}
function insertGematriaText(insertValue) {
const { inputEl } = getElements();
if (!(inputEl instanceof HTMLTextAreaElement)) {
return;
}
const text = String(insertValue || "");
if (!text) {
return;
}
const start = Number.isFinite(inputEl.selectionStart) ? inputEl.selectionStart : inputEl.value.length;
const end = Number.isFinite(inputEl.selectionEnd) ? inputEl.selectionEnd : start;
const nextValue = `${inputEl.value.slice(0, start)}${text}${inputEl.value.slice(end)}`;
setGematriaInputValue(nextValue);
const nextCaret = start + text.length;
inputEl.setSelectionRange(nextCaret, nextCaret);
}
function backspaceGematriaText() {
const { inputEl } = getElements();
if (!(inputEl instanceof HTMLTextAreaElement)) {
return;
}
const start = Number.isFinite(inputEl.selectionStart) ? inputEl.selectionStart : inputEl.value.length;
const end = Number.isFinite(inputEl.selectionEnd) ? inputEl.selectionEnd : start;
if (start === 0 && end === 0) {
return;
}
let nextStart = start;
let nextEnd = end;
if (start === end) {
nextStart = Math.max(0, start - 1);
}
const nextValue = `${inputEl.value.slice(0, nextStart)}${inputEl.value.slice(nextEnd)}`;
setGematriaInputValue(nextValue);
inputEl.setSelectionRange(nextStart, nextStart);
}
function renderKeyboardLayout() {
const { keyboardScriptEl, keyboardGridEl } = getElements();
if (!(keyboardScriptEl instanceof HTMLSelectElement) || !(keyboardGridEl instanceof HTMLElement)) {
return;
}
const layouts = getKeyboardLayouts();
if (!layouts.length) {
keyboardScriptEl.replaceChildren();
keyboardGridEl.replaceChildren();
return;
}
const preferredLayoutId = String(state.keyboardScriptId || "english").trim();
const activeLayout = layouts.find((layout) => layout.id === preferredLayoutId) || layouts[0];
state.keyboardScriptId = activeLayout.id;
keyboardScriptEl.replaceChildren();
layouts.forEach((layout) => {
const optionEl = document.createElement("option");
optionEl.value = layout.id;
optionEl.textContent = layout.label;
keyboardScriptEl.appendChild(optionEl);
});
keyboardScriptEl.value = state.keyboardScriptId;
const fragment = document.createDocumentFragment();
activeLayout.chars.forEach((char) => {
const buttonEl = document.createElement("button");
buttonEl.type = "button";
buttonEl.className = "alpha-gematria-keyboard-key";
buttonEl.dataset.keyboardInsert = char;
buttonEl.textContent = char;
fragment.appendChild(buttonEl);
});
keyboardGridEl.replaceChildren(fragment);
keyboardGridEl.setAttribute("lang", state.keyboardScriptId);
}
function handleKeyboardAction(action) {
const normalizedAction = String(action || "").trim().toLowerCase();
if (!normalizedAction) {
return;
}
if (normalizedAction === "backspace") {
backspaceGematriaText();
return;
}
if (normalizedAction === "space") {
insertGematriaText(" ");
return;
}
if (normalizedAction === "star") {
insertGematriaText("*");
return;
}
if (normalizedAction === "question") {
insertGematriaText("?");
return;
}
if (normalizedAction === "clear") {
setGematriaInputValue("");
}
}
function isReverseMode() {
return state.activeMode === "reverse";
}
@@ -142,14 +321,57 @@
function addScriptCharMapEntry(map, scriptChar, mappedLetters) {
const key = String(scriptChar || "").trim();
const value = String(mappedLetters || "").trim();
if (!key || !value) {
if (!key) {
return;
}
const value = typeof mappedLetters === "string"
? { mappedLetters: String(mappedLetters || "").trim() }
: mappedLetters;
if (!value || (typeof value === "object" && !Number.isFinite(Number(value.ordinal)) && !String(value.mappedLetters || "").trim())) {
return;
}
map.set(key, value);
}
function getEntryOrdinal(entry, fallbackOrdinal) {
const explicitOrdinal = Number(entry?.index);
if (Number.isFinite(explicitOrdinal) && explicitOrdinal > 0) {
return Math.trunc(explicitOrdinal);
}
return Math.trunc(Number(fallbackOrdinal) || 0);
}
function addScriptOrdinalEntries(map, entries, charKeys) {
const sourceEntries = Array.isArray(entries) ? entries : [];
const sourceCharKeys = Array.isArray(charKeys) ? charKeys : [];
sourceEntries.forEach((entry, entryIndex) => {
const ordinal = getEntryOrdinal(entry, entryIndex + 1);
if (!ordinal) {
return;
}
sourceCharKeys.forEach((charKey) => {
const charValue = String(entry?.[charKey] || "").trim();
if (!charValue) {
return;
}
const firstChar = [...charValue][0] || "";
if (!firstChar) {
return;
}
addScriptCharMapEntry(map, firstChar, {
ordinal,
displayChar: firstChar
});
});
});
}
function buildGematriaScriptMap(baseAlphabet) {
const map = new Map();
const alphabets = getAlphabets() || {};
@@ -157,35 +379,51 @@
const greekClassicalLetters = Array.isArray(alphabets.greek) ? alphabets.greek : [];
const greekArchaicLetters = Array.isArray(alphabets.greekArchaic) ? alphabets.greekArchaic : [];
const greekLetters = [...greekClassicalLetters, ...greekArchaicLetters];
const arabicLetters = Array.isArray(alphabets.arabic) ? alphabets.arabic : [];
const enochianLetters = Array.isArray(alphabets.enochian) ? alphabets.enochian : [];
addScriptOrdinalEntries(map, hebrewLetters, ["char"]);
addScriptOrdinalEntries(map, greekLetters, ["char", "charLower", "charFinal"]);
addScriptOrdinalEntries(map, arabicLetters, ["char"]);
addScriptOrdinalEntries(map, enochianLetters, ["char"]);
hebrewLetters.forEach((entry) => {
const mapped = transliterationToBaseLetters(entry?.transliteration, baseAlphabet);
addScriptCharMapEntry(map, entry?.char, mapped);
if (!map.has(String(entry?.char || "").trim())) {
addScriptCharMapEntry(map, entry?.char, mapped);
}
});
greekLetters.forEach((entry) => {
const mapped = transliterationToBaseLetters(entry?.transliteration, baseAlphabet);
addScriptCharMapEntry(map, entry?.char, mapped);
addScriptCharMapEntry(map, entry?.charLower, mapped);
addScriptCharMapEntry(map, entry?.charFinal, mapped);
});
const hebrewFinalForms = {
ך: "k",
ם: "m",
ן: "n",
ף: "p",
ץ: "t"
};
Object.entries(hebrewFinalForms).forEach(([char, mapped]) => {
if (!map.has(char) && baseAlphabet.includes(mapped)) {
addScriptCharMapEntry(map, char, mapped);
if (!map.has(String(entry?.char || "").trim())) {
addScriptCharMapEntry(map, entry?.char, mapped);
}
if (!map.has(String(entry?.charLower || "").trim())) {
addScriptCharMapEntry(map, entry?.charLower, mapped);
}
if (!map.has(String(entry?.charFinal || "").trim())) {
addScriptCharMapEntry(map, entry?.charFinal, mapped);
}
});
if (!map.has("ς") && baseAlphabet.includes("s")) {
addScriptCharMapEntry(map, "ς", "s");
const hebrewFinalForms = {
ך: "כ",
ם: "מ",
ן: "נ",
ף: "פ",
ץ: "צ"
};
Object.entries(hebrewFinalForms).forEach(([char, sourceChar]) => {
const sourceEntry = map.get(sourceChar);
if (!map.has(char) && sourceEntry) {
addScriptCharMapEntry(map, char, sourceEntry);
}
});
if (!map.has("ς") && map.has("σ")) {
addScriptCharMapEntry(map, "ς", map.get("σ"));
}
return map;
@@ -423,7 +661,11 @@
inputLabelEl,
cipherLabelEl,
reverseCiphersEl,
reverseCipherHintEl
reverseCipherHintEl,
keyboardEl,
keyboardScriptEl,
keyboardGridEl,
keyboardActionsEl
} = getElements();
const reverseMode = isReverseMode();
@@ -483,9 +725,29 @@
}
}
if (keyboardEl) {
keyboardEl.hidden = reverseMode;
}
if (keyboardScriptEl) {
keyboardScriptEl.disabled = reverseMode;
}
if (keyboardGridEl) {
keyboardGridEl.classList.toggle("is-disabled", reverseMode);
}
if (keyboardActionsEl) {
keyboardActionsEl.classList.toggle("is-disabled", reverseMode);
}
if (!reverseMode && !anagramMode && !dictionaryMode) {
clearReverseMatches(matchesEl);
}
if (!reverseMode) {
renderKeyboardLayout();
}
}
function parseReverseLookupValue(rawValue) {
@@ -901,10 +1163,44 @@
let count = 0;
[...normalizedInput].forEach((char) => {
const mappedLetters = baseAlphabet.includes(char)
? char
: (scriptMap.get(char) || "");
if (baseAlphabet.includes(char)) {
const index = baseAlphabet.indexOf(char);
if (index < 0) {
return;
}
const value = Number(cipher.values[index]);
if (!Number.isFinite(value)) {
return;
}
count += 1;
total += value;
letterParts.push(`${char.toUpperCase()}(${value})`);
return;
}
const mappedEntry = scriptMap.get(char);
if (!mappedEntry) {
return;
}
const ordinal = Number(mappedEntry.ordinal);
if (Number.isFinite(ordinal) && ordinal > 0) {
const index = Math.trunc(ordinal) - 1;
const value = Number(cipher.values[index]);
if (!Number.isFinite(value)) {
return;
}
const displayChar = String(mappedEntry.displayChar || char || "").trim() || char;
count += 1;
total += value;
letterParts.push(`${displayChar}(${value})`);
return;
}
const mappedLetters = String(mappedEntry.mappedLetters || "");
if (!mappedLetters) {
return;
}
@@ -984,7 +1280,7 @@
}
function bindGematriaListeners() {
const { cipherEl, inputEl, modeEls, reverseCiphersEl } = getElements();
const { cipherEl, inputEl, modeEls, reverseCiphersEl, keyboardScriptEl, keyboardGridEl, keyboardActionsEl } = getElements();
if (state.listenersBound || !cipherEl || !inputEl) {
return;
}
@@ -1033,6 +1329,39 @@
renderGematriaResult();
});
keyboardScriptEl?.addEventListener("change", () => {
state.keyboardScriptId = String(keyboardScriptEl.value || "english").trim() || "english";
renderKeyboardLayout();
});
keyboardGridEl?.addEventListener("click", (event) => {
const target = event.target;
if (!(target instanceof Element)) {
return;
}
const keyButton = target.closest("[data-keyboard-insert]");
if (!(keyButton instanceof HTMLButtonElement) || keyButton.disabled) {
return;
}
insertGematriaText(String(keyButton.dataset.keyboardInsert || ""));
});
keyboardActionsEl?.addEventListener("click", (event) => {
const target = event.target;
if (!(target instanceof Element)) {
return;
}
const actionButton = target.closest("[data-keyboard-action]");
if (!(actionButton instanceof HTMLButtonElement) || actionButton.disabled) {
return;
}
handleKeyboardAction(actionButton.dataset.keyboardAction);
});
state.listenersBound = true;
}
@@ -1048,6 +1377,7 @@
void loadGematriaDb().then(() => {
refreshScriptMap((state.db || getFallbackGematriaDb()).baseAlphabet);
renderGematriaCipherOptions();
renderKeyboardLayout();
renderGematriaResult();
});
}