updated tarot frame for mobile and desktop usability
This commit is contained in:
+144
-13
@@ -12,7 +12,9 @@
|
||||
modeEls: [],
|
||||
matchesEl: null,
|
||||
inputLabelEl: null,
|
||||
cipherLabelEl: null
|
||||
cipherLabelEl: null,
|
||||
reverseCiphersEl: null,
|
||||
reverseCipherHintEl: null
|
||||
})
|
||||
};
|
||||
|
||||
@@ -23,6 +25,7 @@
|
||||
activeCipherId: "",
|
||||
forwardInputText: "",
|
||||
reverseInputText: "",
|
||||
reverseSelectedCipherIds: null,
|
||||
anagramInputText: "",
|
||||
dictionaryInputText: "",
|
||||
activeMode: "forward",
|
||||
@@ -52,7 +55,9 @@
|
||||
modeEls: [],
|
||||
matchesEl: null,
|
||||
inputLabelEl: null,
|
||||
cipherLabelEl: null
|
||||
cipherLabelEl: null,
|
||||
reverseCiphersEl: null,
|
||||
reverseCipherHintEl: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -273,6 +278,80 @@
|
||||
return ciphers.find((cipher) => cipher.id === selectedId) || ciphers[0];
|
||||
}
|
||||
|
||||
function getGematriaCiphers() {
|
||||
const db = state.db || getFallbackGematriaDb();
|
||||
return Array.isArray(db.ciphers) ? db.ciphers : [];
|
||||
}
|
||||
|
||||
function normalizeSelectedReverseCipherIds(rawCipherIds) {
|
||||
const ciphers = getGematriaCiphers();
|
||||
const requestedIds = Array.isArray(rawCipherIds)
|
||||
? rawCipherIds.map((cipherId) => String(cipherId || "").trim()).filter(Boolean)
|
||||
: [];
|
||||
const requestedIdSet = new Set(requestedIds);
|
||||
|
||||
return ciphers
|
||||
.map((cipher) => cipher.id)
|
||||
.filter((cipherId) => requestedIdSet.has(cipherId));
|
||||
}
|
||||
|
||||
function getDefaultReverseCipherIds() {
|
||||
const activeCipher = getActiveGematriaCipher();
|
||||
if (activeCipher?.id) {
|
||||
return [activeCipher.id];
|
||||
}
|
||||
|
||||
const firstCipher = getGematriaCiphers()[0];
|
||||
return firstCipher?.id ? [firstCipher.id] : [];
|
||||
}
|
||||
|
||||
function getSelectedReverseCipherIds() {
|
||||
if (state.reverseSelectedCipherIds === null) {
|
||||
return getDefaultReverseCipherIds();
|
||||
}
|
||||
|
||||
return normalizeSelectedReverseCipherIds(state.reverseSelectedCipherIds);
|
||||
}
|
||||
|
||||
function setSelectedReverseCipherIds(rawCipherIds) {
|
||||
state.reverseSelectedCipherIds = normalizeSelectedReverseCipherIds(rawCipherIds);
|
||||
}
|
||||
|
||||
function renderReverseCipherOptions() {
|
||||
const { reverseCiphersEl } = getElements();
|
||||
if (!reverseCiphersEl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ciphers = getGematriaCiphers();
|
||||
const selectedCipherIds = new Set(getSelectedReverseCipherIds());
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
ciphers.forEach((cipher) => {
|
||||
const optionEl = document.createElement("label");
|
||||
optionEl.className = "alpha-gematria-reverse-cipher-option";
|
||||
|
||||
const checkboxEl = document.createElement("input");
|
||||
checkboxEl.type = "checkbox";
|
||||
checkboxEl.value = cipher.id;
|
||||
checkboxEl.checked = selectedCipherIds.has(cipher.id);
|
||||
checkboxEl.setAttribute("aria-label", cipher.name);
|
||||
optionEl.appendChild(checkboxEl);
|
||||
|
||||
const textEl = document.createElement("span");
|
||||
textEl.className = "alpha-gematria-reverse-cipher-name";
|
||||
textEl.textContent = cipher.name;
|
||||
if (cipher.description) {
|
||||
textEl.title = cipher.description;
|
||||
}
|
||||
optionEl.appendChild(textEl);
|
||||
|
||||
fragment.appendChild(optionEl);
|
||||
});
|
||||
|
||||
reverseCiphersEl.replaceChildren(fragment);
|
||||
}
|
||||
|
||||
function renderGematriaCipherOptions() {
|
||||
const { cipherEl } = getElements();
|
||||
if (!cipherEl) {
|
||||
@@ -296,6 +375,14 @@
|
||||
const activeCipher = getActiveGematriaCipher();
|
||||
state.activeCipherId = activeCipher?.id || "";
|
||||
cipherEl.value = state.activeCipherId;
|
||||
|
||||
if (state.reverseSelectedCipherIds === null) {
|
||||
state.reverseSelectedCipherIds = getDefaultReverseCipherIds();
|
||||
} else {
|
||||
state.reverseSelectedCipherIds = normalizeSelectedReverseCipherIds(state.reverseSelectedCipherIds);
|
||||
}
|
||||
|
||||
renderReverseCipherOptions();
|
||||
}
|
||||
|
||||
function setMatchesMessage(matchesEl, message) {
|
||||
@@ -332,12 +419,14 @@
|
||||
modeEls,
|
||||
matchesEl,
|
||||
inputLabelEl,
|
||||
cipherLabelEl
|
||||
cipherLabelEl,
|
||||
reverseCiphersEl,
|
||||
reverseCipherHintEl
|
||||
} = getElements();
|
||||
|
||||
const reverseMode = isReverseMode();
|
||||
const anagramMode = isAnagramMode();
|
||||
const dictionaryMode = isDictionaryMode();
|
||||
const dictionaryMode = isDictionaryMode();
|
||||
const radioEls = getModeElements(modeEls);
|
||||
|
||||
radioEls.forEach((element) => {
|
||||
@@ -351,16 +440,32 @@
|
||||
}
|
||||
|
||||
if (cipherLabelEl) {
|
||||
cipherLabelEl.textContent = (reverseMode || anagramMode || dictionaryMode) ? "Cipher (not used in this mode)" : "Cipher";
|
||||
cipherLabelEl.textContent = reverseMode
|
||||
? "Ciphers"
|
||||
: ((anagramMode || dictionaryMode) ? "Cipher (not used in this mode)" : "Cipher");
|
||||
}
|
||||
|
||||
if (cipherEl) {
|
||||
const disableCipher = reverseMode || anagramMode || dictionaryMode;
|
||||
const hideCipherField = anagramMode || dictionaryMode;
|
||||
cipherEl.disabled = disableCipher;
|
||||
cipherEl.hidden = reverseMode;
|
||||
const cipherFieldEl = cipherEl.closest(".alpha-gematria-field");
|
||||
const controlsEl = cipherEl.closest(".alpha-gematria-controls");
|
||||
cipherFieldEl?.classList.toggle("is-disabled", disableCipher);
|
||||
controlsEl?.classList.toggle("is-input-priority-mode", disableCipher);
|
||||
cipherFieldEl?.classList.toggle("is-disabled", hideCipherField);
|
||||
controlsEl?.classList.toggle("is-input-priority-mode", hideCipherField);
|
||||
controlsEl?.classList.toggle("is-reverse-cipher-mode", reverseMode);
|
||||
}
|
||||
|
||||
if (reverseCiphersEl) {
|
||||
if (reverseMode) {
|
||||
renderReverseCipherOptions();
|
||||
}
|
||||
reverseCiphersEl.hidden = !reverseMode;
|
||||
}
|
||||
|
||||
if (reverseCipherHintEl) {
|
||||
reverseCipherHintEl.hidden = !reverseMode;
|
||||
}
|
||||
|
||||
if (inputEl) {
|
||||
@@ -400,12 +505,15 @@
|
||||
}
|
||||
|
||||
async function loadReverseLookup(value) {
|
||||
const cacheKey = String(value);
|
||||
const selectedCipherIds = getSelectedReverseCipherIds();
|
||||
const cacheKey = `${String(value)}::${selectedCipherIds.join(",")}`;
|
||||
if (state.reverseLookupCache.has(cacheKey)) {
|
||||
return state.reverseLookupCache.get(cacheKey);
|
||||
}
|
||||
|
||||
const payload = await window.TarotDataService?.loadGematriaWordsByValue?.(value);
|
||||
const payload = await window.TarotDataService?.loadGematriaWordsByValue?.(value, {
|
||||
ciphers: selectedCipherIds
|
||||
});
|
||||
state.reverseLookupCache.set(cacheKey, payload);
|
||||
return payload;
|
||||
}
|
||||
@@ -493,7 +601,7 @@
|
||||
.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)}.` : ""}`;
|
||||
breakdownEl.textContent = `Found ${formatCount(displayCount)} matches across ${formatCount(displayCipherCount)} selected ciphers.${topCipherSummary ? ` Top ciphers: ${topCipherSummary}.` : ""}${displayCount > visibleMatches.length ? ` Showing first ${formatCount(visibleMatches.length)}.` : ""}`;
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
visibleMatches.forEach((match) => {
|
||||
@@ -546,11 +654,20 @@
|
||||
}
|
||||
|
||||
const rawValue = state.reverseInputText;
|
||||
const selectedCipherIds = getSelectedReverseCipherIds();
|
||||
if (!String(rawValue || "").trim()) {
|
||||
resultEl.textContent = "Value: --";
|
||||
breakdownEl.textContent = "Enter a whole number to find words across all available ciphers.";
|
||||
breakdownEl.textContent = "Enter a whole number and choose one or more ciphers to narrow reverse matches.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Reverse lookup searches the API-backed gematria word index.");
|
||||
setMatchesMessage(matchesEl, "Reverse lookup searches the API-backed gematria word index using the selected ciphers only.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selectedCipherIds.length) {
|
||||
resultEl.textContent = "Value: --";
|
||||
breakdownEl.textContent = "Choose at least one cipher before running reverse lookup.";
|
||||
matchesEl.hidden = false;
|
||||
setMatchesMessage(matchesEl, "Select one or more ciphers to limit reverse gematria matches.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -865,7 +982,7 @@
|
||||
}
|
||||
|
||||
function bindGematriaListeners() {
|
||||
const { cipherEl, inputEl, modeEls } = getElements();
|
||||
const { cipherEl, inputEl, modeEls, reverseCiphersEl } = getElements();
|
||||
if (state.listenersBound || !cipherEl || !inputEl) {
|
||||
return;
|
||||
}
|
||||
@@ -900,6 +1017,20 @@
|
||||
});
|
||||
});
|
||||
|
||||
reverseCiphersEl?.addEventListener("change", (event) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof HTMLInputElement) || target.type !== "checkbox") {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextSelectedCipherIds = Array.from(reverseCiphersEl.querySelectorAll("input[type='checkbox']:checked"))
|
||||
.map((element) => String(element.value || "").trim())
|
||||
.filter(Boolean);
|
||||
setSelectedReverseCipherIds(nextSelectedCipherIds);
|
||||
renderReverseCipherOptions();
|
||||
renderGematriaResult();
|
||||
});
|
||||
|
||||
state.listenersBound = true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user