update sequence nav to use new ui-sequence-nav component
This commit is contained in:
+359
-29
@@ -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();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user