updated gui
This commit is contained in:
@@ -8,7 +8,11 @@
|
||||
cipherEl: null,
|
||||
inputEl: null,
|
||||
resultEl: null,
|
||||
breakdownEl: null
|
||||
breakdownEl: null,
|
||||
modeToggleEl: null,
|
||||
matchesEl: null,
|
||||
inputLabelEl: null,
|
||||
cipherLabelEl: null
|
||||
})
|
||||
};
|
||||
|
||||
@@ -17,8 +21,12 @@
|
||||
db: null,
|
||||
listenersBound: false,
|
||||
activeCipherId: "",
|
||||
inputText: "",
|
||||
scriptCharMap: new Map()
|
||||
forwardInputText: "",
|
||||
reverseInputText: "",
|
||||
activeMode: "forward",
|
||||
scriptCharMap: new Map(),
|
||||
reverseLookupCache: new Map(),
|
||||
reverseRequestId: 0
|
||||
};
|
||||
|
||||
function getAlphabets() {
|
||||
@@ -34,10 +42,32 @@
|
||||
cipherEl: null,
|
||||
inputEl: null,
|
||||
resultEl: null,
|
||||
breakdownEl: null
|
||||
breakdownEl: null,
|
||||
modeToggleEl: null,
|
||||
matchesEl: null,
|
||||
inputLabelEl: null,
|
||||
cipherLabelEl: null
|
||||
};
|
||||
}
|
||||
|
||||
function isReverseMode() {
|
||||
return state.activeMode === "reverse";
|
||||
}
|
||||
|
||||
function getCurrentInputText() {
|
||||
return isReverseMode()
|
||||
? state.reverseInputText
|
||||
: state.forwardInputText;
|
||||
}
|
||||
|
||||
function formatCount(value) {
|
||||
const numericValue = Number(value);
|
||||
if (!Number.isFinite(numericValue)) {
|
||||
return "0";
|
||||
}
|
||||
return numericValue.toLocaleString();
|
||||
}
|
||||
|
||||
function getFallbackGematriaDb() {
|
||||
return {
|
||||
baseAlphabet: "abcdefghijklmnopqrstuvwxyz",
|
||||
@@ -47,6 +77,12 @@
|
||||
name: "Simple Ordinal",
|
||||
description: "A=1 ... Z=26",
|
||||
values: Array.from({ length: 26 }, (_, index) => index + 1)
|
||||
},
|
||||
{
|
||||
id: "decadic-cipher",
|
||||
name: "Decadic Cipher",
|
||||
description: "A=1 ... I=9, J=10 ... R=90, S=100 ... Z=800",
|
||||
values: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 200, 300, 400, 500, 600, 700, 800]
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -238,6 +274,221 @@
|
||||
cipherEl.value = state.activeCipherId;
|
||||
}
|
||||
|
||||
function setMatchesMessage(matchesEl, message) {
|
||||
if (!matchesEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
matchesEl.replaceChildren();
|
||||
const emptyEl = document.createElement("div");
|
||||
emptyEl.className = "alpha-gematria-match-empty";
|
||||
emptyEl.textContent = message;
|
||||
matchesEl.appendChild(emptyEl);
|
||||
}
|
||||
|
||||
function clearReverseMatches(matchesEl) {
|
||||
if (!matchesEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
matchesEl.replaceChildren();
|
||||
matchesEl.hidden = true;
|
||||
}
|
||||
|
||||
function updateModeUi() {
|
||||
const {
|
||||
cipherEl,
|
||||
inputEl,
|
||||
modeToggleEl,
|
||||
matchesEl,
|
||||
inputLabelEl,
|
||||
cipherLabelEl
|
||||
} = getElements();
|
||||
|
||||
const reverseMode = isReverseMode();
|
||||
|
||||
if (modeToggleEl) {
|
||||
modeToggleEl.checked = reverseMode;
|
||||
}
|
||||
|
||||
if (inputLabelEl) {
|
||||
inputLabelEl.textContent = reverseMode ? "Value" : "Text";
|
||||
}
|
||||
|
||||
if (cipherLabelEl) {
|
||||
cipherLabelEl.textContent = reverseMode ? "Cipher (disabled in reverse mode)" : "Cipher";
|
||||
}
|
||||
|
||||
if (cipherEl) {
|
||||
cipherEl.disabled = reverseMode;
|
||||
cipherEl.closest(".alpha-gematria-field")?.classList.toggle("is-disabled", reverseMode);
|
||||
}
|
||||
|
||||
if (inputEl) {
|
||||
inputEl.placeholder = reverseMode ? "Enter a whole number, e.g. 33" : "Type or paste text";
|
||||
inputEl.inputMode = reverseMode ? "numeric" : "text";
|
||||
inputEl.spellcheck = !reverseMode;
|
||||
|
||||
const nextValue = getCurrentInputText();
|
||||
if (inputEl.value !== nextValue) {
|
||||
inputEl.value = nextValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!reverseMode) {
|
||||
clearReverseMatches(matchesEl);
|
||||
}
|
||||
}
|
||||
|
||||
function parseReverseLookupValue(rawValue) {
|
||||
const normalizedValue = String(rawValue || "").trim();
|
||||
if (!normalizedValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!/^\d+$/.test(normalizedValue)) {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
const numericValue = Number(normalizedValue);
|
||||
if (!Number.isSafeInteger(numericValue)) {
|
||||
return Number.NaN;
|
||||
}
|
||||
|
||||
return numericValue;
|
||||
}
|
||||
|
||||
async function loadReverseLookup(value) {
|
||||
const cacheKey = String(value);
|
||||
if (state.reverseLookupCache.has(cacheKey)) {
|
||||
return state.reverseLookupCache.get(cacheKey);
|
||||
}
|
||||
|
||||
const payload = await window.TarotDataService?.loadGematriaWordsByValue?.(value);
|
||||
state.reverseLookupCache.set(cacheKey, payload);
|
||||
return payload;
|
||||
}
|
||||
|
||||
function renderReverseLookupMatches(payload, numericValue) {
|
||||
const { resultEl, breakdownEl, matchesEl } = getElements();
|
||||
if (!resultEl || !breakdownEl || !matchesEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matches = Array.isArray(payload?.matches) ? payload.matches : [];
|
||||
const count = Number(payload?.count);
|
||||
const displayCount = Number.isFinite(count) ? count : matches.length;
|
||||
const ciphers = Array.isArray(payload?.ciphers) ? payload.ciphers : [];
|
||||
const cipherCount = Number(payload?.cipherCount);
|
||||
const displayCipherCount = Number.isFinite(cipherCount) ? cipherCount : ciphers.length;
|
||||
const visibleMatches = matches.slice(0, 120);
|
||||
|
||||
resultEl.textContent = `Value: ${formatCount(numericValue)}`;
|
||||
|
||||
if (!displayCount) {
|
||||
breakdownEl.textContent = "No words matched this reverse gematria value.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "No matches found in the reverse gematria index.");
|
||||
return;
|
||||
}
|
||||
|
||||
const topCipherSummary = ciphers
|
||||
.slice(0, 6)
|
||||
.map((cipher) => `${String(cipher?.name || cipher?.id || "Unknown")} ${formatCount(cipher?.count)}`)
|
||||
.join(" · ");
|
||||
|
||||
breakdownEl.textContent = `Found ${formatCount(displayCount)} matches across ${formatCount(displayCipherCount)} ciphers.${topCipherSummary ? ` Top ciphers: ${topCipherSummary}.` : ""}${displayCount > visibleMatches.length ? ` Showing first ${formatCount(visibleMatches.length)}.` : ""}`;
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
visibleMatches.forEach((match) => {
|
||||
const cardEl = document.createElement("article");
|
||||
cardEl.className = "alpha-gematria-match";
|
||||
|
||||
const wordEl = document.createElement("div");
|
||||
wordEl.className = "alpha-gematria-match-word";
|
||||
wordEl.textContent = String(match?.word || "--");
|
||||
cardEl.appendChild(wordEl);
|
||||
|
||||
const definition = String(match?.definition || "").trim();
|
||||
if (definition) {
|
||||
const definitionEl = document.createElement("div");
|
||||
definitionEl.className = "alpha-gematria-match-definition";
|
||||
definitionEl.textContent = definition;
|
||||
cardEl.appendChild(definitionEl);
|
||||
}
|
||||
|
||||
const ciphersEl = document.createElement("div");
|
||||
ciphersEl.className = "alpha-gematria-match-ciphers";
|
||||
const matchCiphers = Array.isArray(match?.ciphers) ? match.ciphers : [];
|
||||
matchCiphers.slice(0, 6).forEach((cipher) => {
|
||||
const chipEl = document.createElement("span");
|
||||
chipEl.className = "alpha-gematria-match-cipher";
|
||||
chipEl.textContent = String(cipher?.name || cipher?.id || "Unknown");
|
||||
ciphersEl.appendChild(chipEl);
|
||||
});
|
||||
if (matchCiphers.length > 6) {
|
||||
const extraEl = document.createElement("span");
|
||||
extraEl.className = "alpha-gematria-match-cipher";
|
||||
extraEl.textContent = `+${matchCiphers.length - 6} more`;
|
||||
ciphersEl.appendChild(extraEl);
|
||||
}
|
||||
cardEl.appendChild(ciphersEl);
|
||||
|
||||
fragment.appendChild(cardEl);
|
||||
});
|
||||
|
||||
matchesEl.replaceChildren(fragment);
|
||||
matchesEl.hidden = false;
|
||||
}
|
||||
|
||||
async function renderReverseLookupResult() {
|
||||
const { resultEl, breakdownEl, matchesEl } = getElements();
|
||||
if (!resultEl || !breakdownEl || !matchesEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const rawValue = state.reverseInputText;
|
||||
if (!String(rawValue || "").trim()) {
|
||||
resultEl.textContent = "Value: --";
|
||||
breakdownEl.textContent = "Enter a whole number to find words across all available ciphers.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Reverse lookup searches the API-backed gematria word index.");
|
||||
return;
|
||||
}
|
||||
|
||||
const numericValue = parseReverseLookupValue(rawValue);
|
||||
if (!Number.isFinite(numericValue)) {
|
||||
resultEl.textContent = "Value: --";
|
||||
breakdownEl.textContent = "Enter digits only to search the reverse gematria index.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Use a whole number such as 33 or 418.");
|
||||
return;
|
||||
}
|
||||
|
||||
const requestId = state.reverseRequestId + 1;
|
||||
state.reverseRequestId = requestId;
|
||||
resultEl.textContent = `Value: ${formatCount(numericValue)}`;
|
||||
breakdownEl.textContent = "Searching reverse gematria index...";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Loading matching words...");
|
||||
|
||||
try {
|
||||
const payload = await loadReverseLookup(numericValue);
|
||||
if (requestId !== state.reverseRequestId || !isReverseMode()) {
|
||||
return;
|
||||
}
|
||||
renderReverseLookupMatches(payload, numericValue);
|
||||
} catch {
|
||||
if (requestId !== state.reverseRequestId || !isReverseMode()) {
|
||||
return;
|
||||
}
|
||||
resultEl.textContent = `Value: ${formatCount(numericValue)}`;
|
||||
breakdownEl.textContent = "Reverse lookup is unavailable right now.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Unable to load reverse gematria words from the API.");
|
||||
}
|
||||
}
|
||||
|
||||
function computeGematria(text, cipher, baseAlphabet) {
|
||||
const normalizedInput = normalizeGematriaText(text);
|
||||
const scriptMap = state.scriptCharMap instanceof Map
|
||||
@@ -281,7 +532,7 @@
|
||||
};
|
||||
}
|
||||
|
||||
function renderGematriaResult() {
|
||||
function renderForwardGematriaResult() {
|
||||
const { resultEl, breakdownEl } = getElements();
|
||||
if (!resultEl || !breakdownEl) {
|
||||
return;
|
||||
@@ -299,7 +550,7 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const { total, count, breakdown } = computeGematria(state.inputText, cipher, db.baseAlphabet);
|
||||
const { total, count, breakdown } = computeGematria(state.forwardInputText, cipher, db.baseAlphabet);
|
||||
|
||||
resultEl.textContent = `Total: ${total}`;
|
||||
if (!count) {
|
||||
@@ -310,8 +561,19 @@
|
||||
breakdownEl.textContent = `${cipher.name} · ${count} letters · ${breakdown} = ${total}`;
|
||||
}
|
||||
|
||||
function renderGematriaResult() {
|
||||
updateModeUi();
|
||||
|
||||
if (isReverseMode()) {
|
||||
void renderReverseLookupResult();
|
||||
return;
|
||||
}
|
||||
|
||||
renderForwardGematriaResult();
|
||||
}
|
||||
|
||||
function bindGematriaListeners() {
|
||||
const { cipherEl, inputEl } = getElements();
|
||||
const { cipherEl, inputEl, modeToggleEl } = getElements();
|
||||
if (state.listenersBound || !cipherEl || !inputEl) {
|
||||
return;
|
||||
}
|
||||
@@ -322,7 +584,17 @@
|
||||
});
|
||||
|
||||
inputEl.addEventListener("input", () => {
|
||||
state.inputText = inputEl.value || "";
|
||||
if (isReverseMode()) {
|
||||
state.reverseInputText = inputEl.value || "";
|
||||
} else {
|
||||
state.forwardInputText = inputEl.value || "";
|
||||
}
|
||||
renderGematriaResult();
|
||||
});
|
||||
|
||||
modeToggleEl?.addEventListener("change", () => {
|
||||
state.activeMode = modeToggleEl.checked ? "reverse" : "forward";
|
||||
updateModeUi();
|
||||
renderGematriaResult();
|
||||
});
|
||||
|
||||
@@ -336,10 +608,7 @@
|
||||
}
|
||||
|
||||
bindGematriaListeners();
|
||||
|
||||
if (inputEl.value !== state.inputText) {
|
||||
inputEl.value = state.inputText;
|
||||
}
|
||||
updateModeUi();
|
||||
|
||||
void loadGematriaDb().then(() => {
|
||||
refreshScriptMap((state.db || getFallbackGematriaDb()).baseAlphabet);
|
||||
|
||||
Reference in New Issue
Block a user