fixed linking
This commit is contained in:
405
app/ui-alphabet-browser.js
Normal file
405
app/ui-alphabet-browser.js
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const ARABIC_DISPLAY_NAMES = {
|
||||||
|
alif: "Alif", ba: "Ba", jeem: "Jeem", dal: "Dal", ha: "Ha",
|
||||||
|
waw: "Waw", zayn: "Zayn", ha_khaa: "Haa", ta_tay: "Tta", ya: "Ya",
|
||||||
|
kaf: "Kaf", lam: "Lam", meem: "Meem", nun: "Nun", seen: "Seen",
|
||||||
|
ayn: "Ayn", fa: "Fa", sad: "Sad", qaf: "Qaf", ra: "Ra",
|
||||||
|
sheen: "Sheen", ta: "Ta", tha: "Tha", kha: "Kha",
|
||||||
|
dhal: "Dhal", dad: "Dad", dha: "Dha", ghayn: "Ghayn"
|
||||||
|
};
|
||||||
|
|
||||||
|
function createAlphabetBrowser(dependencies) {
|
||||||
|
const {
|
||||||
|
state,
|
||||||
|
normalizeId,
|
||||||
|
getDomRefs,
|
||||||
|
renderDetail
|
||||||
|
} = dependencies || {};
|
||||||
|
|
||||||
|
function capitalize(value) {
|
||||||
|
return value ? value.charAt(0).toUpperCase() + value.slice(1) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function arabicDisplayName(letter) {
|
||||||
|
return ARABIC_DISPLAY_NAMES[letter && letter.name]
|
||||||
|
|| (String(letter && letter.name || "").charAt(0).toUpperCase() + String(letter && letter.name || "").slice(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLetters() {
|
||||||
|
if (!state.alphabets) return [];
|
||||||
|
if (state.activeAlphabet === "all") {
|
||||||
|
const alphabetOrder = ["hebrew", "greek", "english", "arabic", "enochian"];
|
||||||
|
return alphabetOrder.flatMap((alphabet) => {
|
||||||
|
const rows = Array.isArray(state.alphabets?.[alphabet]) ? state.alphabets[alphabet] : [];
|
||||||
|
return rows.map((row) => ({ ...row, __alphabet: alphabet }));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return state.alphabets[state.activeAlphabet] || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function alphabetForLetter(letter) {
|
||||||
|
if (state.activeAlphabet === "all") {
|
||||||
|
return String(letter?.__alphabet || "").trim().toLowerCase();
|
||||||
|
}
|
||||||
|
return state.activeAlphabet;
|
||||||
|
}
|
||||||
|
|
||||||
|
function letterKeyByAlphabet(alphabet, letter) {
|
||||||
|
if (alphabet === "hebrew") return letter.hebrewLetterId;
|
||||||
|
if (alphabet === "greek") return letter.name;
|
||||||
|
if (alphabet === "english") return letter.letter;
|
||||||
|
if (alphabet === "arabic") return letter.name;
|
||||||
|
if (alphabet === "enochian") return letter.id;
|
||||||
|
return String(letter.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
function letterKey(letter) {
|
||||||
|
const alphabet = alphabetForLetter(letter);
|
||||||
|
const key = letterKeyByAlphabet(alphabet, letter);
|
||||||
|
if (state.activeAlphabet === "all") {
|
||||||
|
return `${alphabet}:${key}`;
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayGlyph(letter) {
|
||||||
|
const alphabet = alphabetForLetter(letter);
|
||||||
|
if (alphabet === "hebrew") return letter.char;
|
||||||
|
if (alphabet === "greek") return letter.char;
|
||||||
|
if (alphabet === "english") return letter.letter;
|
||||||
|
if (alphabet === "arabic") return letter.char;
|
||||||
|
if (alphabet === "enochian") return letter.char;
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayLabel(letter) {
|
||||||
|
const alphabet = alphabetForLetter(letter);
|
||||||
|
if (alphabet === "hebrew") return letter.name;
|
||||||
|
if (alphabet === "greek") return letter.displayName;
|
||||||
|
if (alphabet === "english") return letter.letter;
|
||||||
|
if (alphabet === "arabic") return arabicDisplayName(letter);
|
||||||
|
if (alphabet === "enochian") return letter.title;
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
function displaySub(letter) {
|
||||||
|
const alphabet = alphabetForLetter(letter);
|
||||||
|
if (alphabet === "hebrew") return `${letter.transliteration} · ${letter.letterType} · ${letter.numerology}`;
|
||||||
|
if (alphabet === "greek") return `${letter.transliteration} · isopsephy ${letter.numerology}${letter.archaic ? " · archaic" : ""}`;
|
||||||
|
if (alphabet === "english") return `Pythagorean ${letter.pythagorean}`;
|
||||||
|
if (alphabet === "arabic") return `${letter.transliteration} · abjad ${letter.abjad} · ${letter.nameArabic}`;
|
||||||
|
if (alphabet === "enochian") return `${letter.transliteration} · ${Array.isArray(letter.englishLetters) ? letter.englishLetters.join("/") : ""} · value ${letter.numerology}`;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLetterType(value) {
|
||||||
|
const key = String(value || "").trim().toLowerCase();
|
||||||
|
if (["mother", "double", "simple"].includes(key)) {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHebrewLetterTypeMap() {
|
||||||
|
const map = new Map();
|
||||||
|
const hebrewLetters = Array.isArray(state.alphabets?.hebrew) ? state.alphabets.hebrew : [];
|
||||||
|
hebrewLetters.forEach((entry) => {
|
||||||
|
const hebrewId = normalizeId(entry?.hebrewLetterId);
|
||||||
|
const letterType = normalizeLetterType(entry?.letterType);
|
||||||
|
if (hebrewId && letterType) {
|
||||||
|
map.set(hebrewId, letterType);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveLetterType(letter) {
|
||||||
|
const direct = normalizeLetterType(letter?.letterType);
|
||||||
|
if (direct) {
|
||||||
|
return direct;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hebrewId = normalizeId(letter?.hebrewLetterId);
|
||||||
|
if (!hebrewId) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return getHebrewLetterTypeMap().get(hebrewId) || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildLetterSearchText(letter) {
|
||||||
|
const chunks = [];
|
||||||
|
|
||||||
|
chunks.push(String(displayLabel(letter) || ""));
|
||||||
|
chunks.push(String(displayGlyph(letter) || ""));
|
||||||
|
chunks.push(String(displaySub(letter) || ""));
|
||||||
|
chunks.push(String(letter?.transliteration || ""));
|
||||||
|
chunks.push(String(letter?.meaning || ""));
|
||||||
|
chunks.push(String(letter?.nameArabic || ""));
|
||||||
|
chunks.push(String(letter?.title || ""));
|
||||||
|
chunks.push(String(letter?.letter || ""));
|
||||||
|
chunks.push(String(letter?.displayName || ""));
|
||||||
|
chunks.push(String(letter?.name || ""));
|
||||||
|
chunks.push(String(letter?.index || ""));
|
||||||
|
chunks.push(String(resolveLetterType(letter) || ""));
|
||||||
|
|
||||||
|
return chunks.join(" ").toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFilteredLetters() {
|
||||||
|
const letters = getLetters();
|
||||||
|
const query = String(state.filters.query || "").trim().toLowerCase();
|
||||||
|
const letterTypeFilter = normalizeLetterType(state.filters.letterType);
|
||||||
|
const numericPosition = /^\d+$/.test(query) ? Number(query) : null;
|
||||||
|
|
||||||
|
return letters.filter((letter) => {
|
||||||
|
if (letterTypeFilter) {
|
||||||
|
const entryType = resolveLetterType(letter);
|
||||||
|
if (entryType !== letterTypeFilter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = Number(letter?.index);
|
||||||
|
if (Number.isFinite(numericPosition) && Number.isFinite(index) && index === numericPosition) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildLetterSearchText(letter).includes(query);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncFilterControls() {
|
||||||
|
const { searchInputEl, typeFilterEl, searchClearEl } = getDomRefs();
|
||||||
|
|
||||||
|
if (searchInputEl && searchInputEl.value !== state.filters.query) {
|
||||||
|
searchInputEl.value = state.filters.query;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeFilterEl && typeFilterEl.value !== state.filters.letterType) {
|
||||||
|
typeFilterEl.value = state.filters.letterType;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchClearEl) {
|
||||||
|
const hasFilter = Boolean(String(state.filters.query || "").trim()) || Boolean(state.filters.letterType);
|
||||||
|
searchClearEl.disabled = !hasFilter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFiltersAndRender() {
|
||||||
|
const filteredLetters = getFilteredLetters();
|
||||||
|
const selectedInFiltered = filteredLetters.some((letter) => letterKey(letter) === state.selectedKey);
|
||||||
|
|
||||||
|
if (!selectedInFiltered) {
|
||||||
|
state.selectedKey = filteredLetters[0] ? letterKey(filteredLetters[0]) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderList();
|
||||||
|
|
||||||
|
const selected = filteredLetters.find((letter) => letterKey(letter) === state.selectedKey)
|
||||||
|
|| filteredLetters[0]
|
||||||
|
|| null;
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
renderDetail(selected);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resetDetail();
|
||||||
|
const { detailSubEl } = getDomRefs();
|
||||||
|
if (detailSubEl) {
|
||||||
|
detailSubEl.textContent = "No letters match the current filter.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindFilterControls() {
|
||||||
|
const { searchInputEl, typeFilterEl, searchClearEl } = getDomRefs();
|
||||||
|
|
||||||
|
if (searchInputEl) {
|
||||||
|
searchInputEl.addEventListener("input", () => {
|
||||||
|
state.filters.query = String(searchInputEl.value || "");
|
||||||
|
syncFilterControls();
|
||||||
|
applyFiltersAndRender();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeFilterEl) {
|
||||||
|
typeFilterEl.addEventListener("change", () => {
|
||||||
|
state.filters.letterType = normalizeLetterType(typeFilterEl.value);
|
||||||
|
syncFilterControls();
|
||||||
|
applyFiltersAndRender();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchClearEl) {
|
||||||
|
searchClearEl.addEventListener("click", () => {
|
||||||
|
state.filters.query = "";
|
||||||
|
state.filters.letterType = "";
|
||||||
|
syncFilterControls();
|
||||||
|
applyFiltersAndRender();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function enochianGlyphKey(letter) {
|
||||||
|
return String(letter?.id || letter?.char || "").trim().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
function enochianGlyphCode(letter) {
|
||||||
|
const key = enochianGlyphKey(letter);
|
||||||
|
return key ? key.codePointAt(0) || 0 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function enochianGlyphUrl(letter) {
|
||||||
|
const code = enochianGlyphCode(letter);
|
||||||
|
return code ? `asset/img/enochian/char(${code}).png` : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function enochianGlyphImageHtml(letter, className) {
|
||||||
|
const src = enochianGlyphUrl(letter);
|
||||||
|
const key = enochianGlyphKey(letter) || "?";
|
||||||
|
if (!src) {
|
||||||
|
return `<span class="${className}">${key}</span>`;
|
||||||
|
}
|
||||||
|
return `<img class="${className}" src="${src}" alt="Enochian ${key}" loading="lazy" decoding="async">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderList() {
|
||||||
|
const { listEl, countEl } = getDomRefs();
|
||||||
|
if (!listEl) return;
|
||||||
|
const allLetters = getLetters();
|
||||||
|
const letters = getFilteredLetters();
|
||||||
|
if (countEl) {
|
||||||
|
countEl.textContent = letters.length === allLetters.length
|
||||||
|
? `${letters.length}`
|
||||||
|
: `${letters.length}/${allLetters.length}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
listEl.innerHTML = "";
|
||||||
|
letters.forEach((letter) => {
|
||||||
|
const key = letterKey(letter);
|
||||||
|
const item = document.createElement("div");
|
||||||
|
item.className = "planet-list-item alpha-list-item" + (key === state.selectedKey ? " is-selected" : "");
|
||||||
|
item.setAttribute("role", "option");
|
||||||
|
item.setAttribute("aria-selected", key === state.selectedKey ? "true" : "false");
|
||||||
|
item.dataset.key = key;
|
||||||
|
|
||||||
|
const glyph = document.createElement("span");
|
||||||
|
const alphabet = alphabetForLetter(letter);
|
||||||
|
const glyphVariantClass = alphabet === "arabic"
|
||||||
|
? " alpha-list-glyph--arabic"
|
||||||
|
: alphabet === "enochian"
|
||||||
|
? " alpha-list-glyph--enochian"
|
||||||
|
: "";
|
||||||
|
glyph.className = "alpha-list-glyph" + glyphVariantClass;
|
||||||
|
if (alphabet === "enochian") {
|
||||||
|
const image = document.createElement("img");
|
||||||
|
image.className = "alpha-enochian-glyph-img alpha-enochian-glyph-img--list";
|
||||||
|
image.src = enochianGlyphUrl(letter);
|
||||||
|
image.alt = `Enochian ${enochianGlyphKey(letter) || "?"}`;
|
||||||
|
image.loading = "lazy";
|
||||||
|
image.decoding = "async";
|
||||||
|
image.addEventListener("error", () => {
|
||||||
|
glyph.textContent = enochianGlyphKey(letter) || "?";
|
||||||
|
});
|
||||||
|
glyph.appendChild(image);
|
||||||
|
} else {
|
||||||
|
glyph.textContent = displayGlyph(letter);
|
||||||
|
}
|
||||||
|
|
||||||
|
const meta = document.createElement("span");
|
||||||
|
meta.className = "alpha-list-meta";
|
||||||
|
const alphaLabel = alphabet ? `${capitalize(alphabet)} · ` : "";
|
||||||
|
meta.innerHTML = `<strong>${alphaLabel}${displayLabel(letter)}</strong><br><span class="alpha-list-sub">${displaySub(letter)}</span>`;
|
||||||
|
|
||||||
|
item.appendChild(glyph);
|
||||||
|
item.appendChild(meta);
|
||||||
|
item.addEventListener("click", () => selectLetter(key));
|
||||||
|
listEl.appendChild(item);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetDetail() {
|
||||||
|
const { detailNameEl, detailSubEl, detailBodyEl } = getDomRefs();
|
||||||
|
if (detailNameEl) {
|
||||||
|
detailNameEl.textContent = "--";
|
||||||
|
detailNameEl.classList.remove("alpha-detail-glyph");
|
||||||
|
}
|
||||||
|
if (detailSubEl) detailSubEl.textContent = "Select a letter to explore";
|
||||||
|
if (detailBodyEl) detailBodyEl.innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectLetter(key) {
|
||||||
|
state.selectedKey = key;
|
||||||
|
renderList();
|
||||||
|
const letters = getFilteredLetters();
|
||||||
|
const letter = letters.find((entry) => letterKey(entry) === key) || getLetters().find((entry) => letterKey(entry) === key);
|
||||||
|
if (letter) {
|
||||||
|
renderDetail(letter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateTabs() {
|
||||||
|
const { tabAll, tabHebrew, tabGreek, tabEnglish, tabArabic, tabEnochian } = getDomRefs();
|
||||||
|
[tabAll, tabHebrew, tabGreek, tabEnglish, tabArabic, tabEnochian].forEach((btn) => {
|
||||||
|
if (!btn) return;
|
||||||
|
btn.classList.toggle("alpha-tab-active", btn.dataset.alpha === state.activeAlphabet);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchAlphabet(alpha, selectKey) {
|
||||||
|
state.activeAlphabet = alpha;
|
||||||
|
state.selectedKey = selectKey || null;
|
||||||
|
updateTabs();
|
||||||
|
syncFilterControls();
|
||||||
|
renderList();
|
||||||
|
if (selectKey) {
|
||||||
|
const letters = getFilteredLetters();
|
||||||
|
const letter = letters.find((entry) => letterKey(entry) === selectKey) || getLetters().find((entry) => letterKey(entry) === selectKey);
|
||||||
|
if (letter) {
|
||||||
|
renderDetail(letter);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resetDetail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
arabicDisplayName,
|
||||||
|
getLetters,
|
||||||
|
alphabetForLetter,
|
||||||
|
letterKeyByAlphabet,
|
||||||
|
letterKey,
|
||||||
|
displayGlyph,
|
||||||
|
displayLabel,
|
||||||
|
displaySub,
|
||||||
|
normalizeLetterType,
|
||||||
|
getHebrewLetterTypeMap,
|
||||||
|
resolveLetterType,
|
||||||
|
buildLetterSearchText,
|
||||||
|
getFilteredLetters,
|
||||||
|
syncFilterControls,
|
||||||
|
applyFiltersAndRender,
|
||||||
|
bindFilterControls,
|
||||||
|
enochianGlyphKey,
|
||||||
|
enochianGlyphCode,
|
||||||
|
enochianGlyphUrl,
|
||||||
|
enochianGlyphImageHtml,
|
||||||
|
renderList,
|
||||||
|
resetDetail,
|
||||||
|
selectLetter,
|
||||||
|
switchAlphabet,
|
||||||
|
updateTabs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.AlphabetBrowserUi = {
|
||||||
|
createAlphabetBrowser
|
||||||
|
};
|
||||||
|
})();
|
||||||
@@ -3,12 +3,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const alphabetGematriaUi = window.AlphabetGematriaUi || {};
|
const alphabetGematriaUi = window.AlphabetGematriaUi || {};
|
||||||
|
const alphabetBrowserUi = window.AlphabetBrowserUi || {};
|
||||||
const alphabetKabbalahUi = window.AlphabetKabbalahUi || {};
|
const alphabetKabbalahUi = window.AlphabetKabbalahUi || {};
|
||||||
const alphabetReferenceBuilders = window.AlphabetReferenceBuilders || {};
|
const alphabetReferenceBuilders = window.AlphabetReferenceBuilders || {};
|
||||||
const alphabetDetailUi = window.AlphabetDetailUi || {};
|
const alphabetDetailUi = window.AlphabetDetailUi || {};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof alphabetKabbalahUi.buildCubePlacementButton !== "function"
|
typeof alphabetBrowserUi.createAlphabetBrowser !== "function"
|
||||||
|
|| typeof alphabetKabbalahUi.buildCubePlacementButton !== "function"
|
||||||
|| typeof alphabetKabbalahUi.buildFourWorldLayersFromDataset !== "function"
|
|| typeof alphabetKabbalahUi.buildFourWorldLayersFromDataset !== "function"
|
||||||
|| typeof alphabetKabbalahUi.createEmptyCubeRefs !== "function"
|
|| typeof alphabetKabbalahUi.createEmptyCubeRefs !== "function"
|
||||||
|| typeof alphabetKabbalahUi.getCubePlacementForHebrewLetter !== "function"
|
|| typeof alphabetKabbalahUi.getCubePlacementForHebrewLetter !== "function"
|
||||||
@@ -18,7 +20,7 @@
|
|||||||
|| typeof alphabetKabbalahUi.normalizeLetterId !== "function"
|
|| typeof alphabetKabbalahUi.normalizeLetterId !== "function"
|
||||||
|| typeof alphabetKabbalahUi.titleCase !== "function"
|
|| typeof alphabetKabbalahUi.titleCase !== "function"
|
||||||
) {
|
) {
|
||||||
throw new Error("AlphabetKabbalahUi module must load before ui-alphabet.js");
|
throw new Error("AlphabetBrowserUi and AlphabetKabbalahUi modules must load before ui-alphabet.js");
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = {
|
const state = {
|
||||||
@@ -40,18 +42,8 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ── Arabic display name table ─────────────────────────────────────────
|
|
||||||
const ARABIC_DISPLAY_NAMES = {
|
|
||||||
alif: "Alif", ba: "Ba", jeem: "Jeem", dal: "Dal", ha: "H\u0101",
|
|
||||||
waw: "W\u0101w", zayn: "Zayn", ha_khaa: "\u1e24\u0101", ta_tay: "\u1e6c\u0101", ya: "Y\u0101",
|
|
||||||
kaf: "K\u0101f", lam: "L\u0101m", meem: "M\u012bm", nun: "N\u016bn", seen: "S\u012bn",
|
|
||||||
ayn: "\u02bfAyn", fa: "F\u0101", sad: "\u1e62\u0101d", qaf: "Q\u0101f", ra: "R\u0101",
|
|
||||||
sheen: "Sh\u012bn", ta: "T\u0101", tha: "Th\u0101", kha: "Kh\u0101",
|
|
||||||
dhal: "Dh\u0101l", dad: "\u1e0c\u0101d", dha: "\u1e92\u0101", ghayn: "Ghayn"
|
|
||||||
};
|
|
||||||
|
|
||||||
function arabicDisplayName(letter) {
|
function arabicDisplayName(letter) {
|
||||||
return ARABIC_DISPLAY_NAMES[letter && letter.name] || (String(letter && letter.name || "").charAt(0).toUpperCase() + String(letter && letter.name || "").slice(1));
|
return browserUi.arabicDisplayName(letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Element cache ────────────────────────────────────────────────────
|
// ── Element cache ────────────────────────────────────────────────────
|
||||||
@@ -101,299 +93,84 @@
|
|||||||
|
|
||||||
// ── Data helpers ─────────────────────────────────────────────────────
|
// ── Data helpers ─────────────────────────────────────────────────────
|
||||||
function getLetters() {
|
function getLetters() {
|
||||||
if (!state.alphabets) return [];
|
return browserUi.getLetters();
|
||||||
if (state.activeAlphabet === "all") {
|
|
||||||
const alphabetOrder = ["hebrew", "greek", "english", "arabic", "enochian"];
|
|
||||||
return alphabetOrder.flatMap((alphabet) => {
|
|
||||||
const rows = Array.isArray(state.alphabets?.[alphabet]) ? state.alphabets[alphabet] : [];
|
|
||||||
return rows.map((row) => ({ ...row, __alphabet: alphabet }));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return state.alphabets[state.activeAlphabet] || [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function alphabetForLetter(letter) {
|
function alphabetForLetter(letter) {
|
||||||
if (state.activeAlphabet === "all") {
|
return browserUi.alphabetForLetter(letter);
|
||||||
return String(letter?.__alphabet || "").trim().toLowerCase();
|
|
||||||
}
|
|
||||||
return state.activeAlphabet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function letterKeyByAlphabet(alphabet, letter) {
|
function letterKeyByAlphabet(alphabet, letter) {
|
||||||
if (alphabet === "hebrew") return letter.hebrewLetterId;
|
return browserUi.letterKeyByAlphabet(alphabet, letter);
|
||||||
if (alphabet === "greek") return letter.name;
|
|
||||||
if (alphabet === "english") return letter.letter;
|
|
||||||
if (alphabet === "arabic") return letter.name;
|
|
||||||
if (alphabet === "enochian") return letter.id;
|
|
||||||
return String(letter.index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function letterKey(letter) {
|
function letterKey(letter) {
|
||||||
// Stable unique key per alphabet + entry
|
return browserUi.letterKey(letter);
|
||||||
const alphabet = alphabetForLetter(letter);
|
|
||||||
const key = letterKeyByAlphabet(alphabet, letter);
|
|
||||||
if (state.activeAlphabet === "all") {
|
|
||||||
return `${alphabet}:${key}`;
|
|
||||||
}
|
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayGlyph(letter) {
|
function displayGlyph(letter) {
|
||||||
const alphabet = alphabetForLetter(letter);
|
return browserUi.displayGlyph(letter);
|
||||||
if (alphabet === "hebrew") return letter.char;
|
|
||||||
if (alphabet === "greek") return letter.char;
|
|
||||||
if (alphabet === "english") return letter.letter;
|
|
||||||
if (alphabet === "arabic") return letter.char;
|
|
||||||
if (alphabet === "enochian") return letter.char;
|
|
||||||
return "?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayLabel(letter) {
|
function displayLabel(letter) {
|
||||||
const alphabet = alphabetForLetter(letter);
|
return browserUi.displayLabel(letter);
|
||||||
if (alphabet === "hebrew") return letter.name;
|
|
||||||
if (alphabet === "greek") return letter.displayName;
|
|
||||||
if (alphabet === "english") return letter.letter;
|
|
||||||
if (alphabet === "arabic") return arabicDisplayName(letter);
|
|
||||||
if (alphabet === "enochian") return letter.title;
|
|
||||||
return "?";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function displaySub(letter) {
|
function displaySub(letter) {
|
||||||
const alphabet = alphabetForLetter(letter);
|
return browserUi.displaySub(letter);
|
||||||
if (alphabet === "hebrew") return `${letter.transliteration} · ${letter.letterType} · ${letter.numerology}`;
|
|
||||||
if (alphabet === "greek") return `${letter.transliteration} · isopsephy ${letter.numerology}${letter.archaic ? " · archaic" : ""}`;
|
|
||||||
if (alphabet === "english") return `Pythagorean ${letter.pythagorean}`;
|
|
||||||
if (alphabet === "arabic") return `${letter.transliteration} · abjad ${letter.abjad} · ${letter.nameArabic}`;
|
|
||||||
if (alphabet === "enochian") return `${letter.transliteration} · ${Array.isArray(letter.englishLetters) ? letter.englishLetters.join("/") : ""} · value ${letter.numerology}`;
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeLetterType(value) {
|
function normalizeLetterType(value) {
|
||||||
const key = String(value || "").trim().toLowerCase();
|
return browserUi.normalizeLetterType(value);
|
||||||
if (["mother", "double", "simple"].includes(key)) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHebrewLetterTypeMap() {
|
function getHebrewLetterTypeMap() {
|
||||||
const map = new Map();
|
return browserUi.getHebrewLetterTypeMap();
|
||||||
const hebrewLetters = Array.isArray(state.alphabets?.hebrew) ? state.alphabets.hebrew : [];
|
|
||||||
hebrewLetters.forEach((entry) => {
|
|
||||||
const hebrewId = normalizeId(entry?.hebrewLetterId);
|
|
||||||
const letterType = normalizeLetterType(entry?.letterType);
|
|
||||||
if (hebrewId && letterType) {
|
|
||||||
map.set(hebrewId, letterType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveLetterType(letter) {
|
function resolveLetterType(letter) {
|
||||||
const direct = normalizeLetterType(letter?.letterType);
|
return browserUi.resolveLetterType(letter);
|
||||||
if (direct) {
|
|
||||||
return direct;
|
|
||||||
}
|
|
||||||
|
|
||||||
const hebrewId = normalizeId(letter?.hebrewLetterId);
|
|
||||||
if (!hebrewId) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return getHebrewLetterTypeMap().get(hebrewId) || "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildLetterSearchText(letter) {
|
function buildLetterSearchText(letter) {
|
||||||
const chunks = [];
|
return browserUi.buildLetterSearchText(letter);
|
||||||
|
|
||||||
chunks.push(String(displayLabel(letter) || ""));
|
|
||||||
chunks.push(String(displayGlyph(letter) || ""));
|
|
||||||
chunks.push(String(displaySub(letter) || ""));
|
|
||||||
chunks.push(String(letter?.transliteration || ""));
|
|
||||||
chunks.push(String(letter?.meaning || ""));
|
|
||||||
chunks.push(String(letter?.nameArabic || ""));
|
|
||||||
chunks.push(String(letter?.title || ""));
|
|
||||||
chunks.push(String(letter?.letter || ""));
|
|
||||||
chunks.push(String(letter?.displayName || ""));
|
|
||||||
chunks.push(String(letter?.name || ""));
|
|
||||||
chunks.push(String(letter?.index || ""));
|
|
||||||
chunks.push(String(resolveLetterType(letter) || ""));
|
|
||||||
|
|
||||||
return chunks
|
|
||||||
.join(" ")
|
|
||||||
.toLowerCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFilteredLetters() {
|
function getFilteredLetters() {
|
||||||
const letters = getLetters();
|
return browserUi.getFilteredLetters();
|
||||||
const query = String(state.filters.query || "").trim().toLowerCase();
|
|
||||||
const letterTypeFilter = normalizeLetterType(state.filters.letterType);
|
|
||||||
const numericPosition = /^\d+$/.test(query) ? Number(query) : null;
|
|
||||||
|
|
||||||
return letters.filter((letter) => {
|
|
||||||
if (letterTypeFilter) {
|
|
||||||
const entryType = resolveLetterType(letter);
|
|
||||||
if (entryType !== letterTypeFilter) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const index = Number(letter?.index);
|
|
||||||
if (Number.isFinite(numericPosition) && Number.isFinite(index) && index === numericPosition) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buildLetterSearchText(letter).includes(query);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncFilterControls() {
|
function syncFilterControls() {
|
||||||
if (searchInputEl && searchInputEl.value !== state.filters.query) {
|
browserUi.syncFilterControls();
|
||||||
searchInputEl.value = state.filters.query;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeFilterEl && typeFilterEl.value !== state.filters.letterType) {
|
|
||||||
typeFilterEl.value = state.filters.letterType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchClearEl) {
|
|
||||||
const hasFilter = Boolean(String(state.filters.query || "").trim()) || Boolean(state.filters.letterType);
|
|
||||||
searchClearEl.disabled = !hasFilter;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyFiltersAndRender() {
|
function applyFiltersAndRender() {
|
||||||
const filteredLetters = getFilteredLetters();
|
browserUi.applyFiltersAndRender();
|
||||||
const selectedInFiltered = filteredLetters.some((letter) => letterKey(letter) === state.selectedKey);
|
|
||||||
|
|
||||||
if (!selectedInFiltered) {
|
|
||||||
state.selectedKey = filteredLetters[0] ? letterKey(filteredLetters[0]) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderList();
|
|
||||||
|
|
||||||
const selected = filteredLetters.find((letter) => letterKey(letter) === state.selectedKey)
|
|
||||||
|| filteredLetters[0]
|
|
||||||
|| null;
|
|
||||||
|
|
||||||
if (selected) {
|
|
||||||
renderDetail(selected);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resetDetail();
|
|
||||||
if (detailSubEl) {
|
|
||||||
detailSubEl.textContent = "No letters match the current filter.";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindFilterControls() {
|
function bindFilterControls() {
|
||||||
if (searchInputEl) {
|
browserUi.bindFilterControls();
|
||||||
searchInputEl.addEventListener("input", () => {
|
|
||||||
state.filters.query = String(searchInputEl.value || "");
|
|
||||||
syncFilterControls();
|
|
||||||
applyFiltersAndRender();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeFilterEl) {
|
|
||||||
typeFilterEl.addEventListener("change", () => {
|
|
||||||
state.filters.letterType = normalizeLetterType(typeFilterEl.value);
|
|
||||||
syncFilterControls();
|
|
||||||
applyFiltersAndRender();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchClearEl) {
|
|
||||||
searchClearEl.addEventListener("click", () => {
|
|
||||||
state.filters.query = "";
|
|
||||||
state.filters.letterType = "";
|
|
||||||
syncFilterControls();
|
|
||||||
applyFiltersAndRender();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function enochianGlyphKey(letter) {
|
function enochianGlyphKey(letter) {
|
||||||
return String(letter?.id || letter?.char || "").trim().toUpperCase();
|
return browserUi.enochianGlyphKey(letter);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enochianGlyphCode(letter) {
|
function enochianGlyphCode(letter) {
|
||||||
const key = enochianGlyphKey(letter);
|
return browserUi.enochianGlyphCode(letter);
|
||||||
return key ? key.codePointAt(0) || 0 : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function enochianGlyphUrl(letter) {
|
function enochianGlyphUrl(letter) {
|
||||||
const code = enochianGlyphCode(letter);
|
return browserUi.enochianGlyphUrl(letter);
|
||||||
return code ? `asset/img/enochian/char(${code}).png` : "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function enochianGlyphImageHtml(letter, className) {
|
function enochianGlyphImageHtml(letter, className) {
|
||||||
const src = enochianGlyphUrl(letter);
|
return browserUi.enochianGlyphImageHtml(letter, className);
|
||||||
const key = enochianGlyphKey(letter) || "?";
|
|
||||||
if (!src) {
|
|
||||||
return `<span class="${className}">${key}</span>`;
|
|
||||||
}
|
|
||||||
return `<img class="${className}" src="${src}" alt="Enochian ${key}" loading="lazy" decoding="async">`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── List rendering ────────────────────────────────────────────────────
|
// ── List rendering ────────────────────────────────────────────────────
|
||||||
function renderList() {
|
function renderList() {
|
||||||
if (!listEl) return;
|
browserUi.renderList();
|
||||||
const allLetters = getLetters();
|
|
||||||
const letters = getFilteredLetters();
|
|
||||||
if (countEl) {
|
|
||||||
countEl.textContent = letters.length === allLetters.length
|
|
||||||
? `${letters.length}`
|
|
||||||
: `${letters.length}/${allLetters.length}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
listEl.innerHTML = "";
|
|
||||||
letters.forEach((letter) => {
|
|
||||||
const key = letterKey(letter);
|
|
||||||
const item = document.createElement("div");
|
|
||||||
item.className = "planet-list-item alpha-list-item" + (key === state.selectedKey ? " is-selected" : "");
|
|
||||||
item.setAttribute("role", "option");
|
|
||||||
item.setAttribute("aria-selected", key === state.selectedKey ? "true" : "false");
|
|
||||||
item.dataset.key = key;
|
|
||||||
|
|
||||||
const glyph = document.createElement("span");
|
|
||||||
const alphabet = alphabetForLetter(letter);
|
|
||||||
const glyphVariantClass = alphabet === "arabic"
|
|
||||||
? " alpha-list-glyph--arabic"
|
|
||||||
: alphabet === "enochian"
|
|
||||||
? " alpha-list-glyph--enochian"
|
|
||||||
: "";
|
|
||||||
glyph.className = "alpha-list-glyph" + glyphVariantClass;
|
|
||||||
if (alphabet === "enochian") {
|
|
||||||
const image = document.createElement("img");
|
|
||||||
image.className = "alpha-enochian-glyph-img alpha-enochian-glyph-img--list";
|
|
||||||
image.src = enochianGlyphUrl(letter);
|
|
||||||
image.alt = `Enochian ${enochianGlyphKey(letter) || "?"}`;
|
|
||||||
image.loading = "lazy";
|
|
||||||
image.decoding = "async";
|
|
||||||
image.addEventListener("error", () => {
|
|
||||||
glyph.textContent = enochianGlyphKey(letter) || "?";
|
|
||||||
});
|
|
||||||
glyph.appendChild(image);
|
|
||||||
} else {
|
|
||||||
glyph.textContent = displayGlyph(letter);
|
|
||||||
}
|
|
||||||
|
|
||||||
const meta = document.createElement("span");
|
|
||||||
meta.className = "alpha-list-meta";
|
|
||||||
const alphaLabel = alphabet ? `${cap(alphabet)} · ` : "";
|
|
||||||
meta.innerHTML = `<strong>${alphaLabel}${displayLabel(letter)}</strong><br><span class="alpha-list-sub">${displaySub(letter)}</span>`;
|
|
||||||
|
|
||||||
item.appendChild(glyph);
|
|
||||||
item.appendChild(meta);
|
|
||||||
item.addEventListener("click", () => selectLetter(key));
|
|
||||||
listEl.appendChild(item);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Detail rendering ──────────────────────────────────────────────────
|
// ── Detail rendering ──────────────────────────────────────────────────
|
||||||
@@ -537,6 +314,28 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const browserUi = alphabetBrowserUi.createAlphabetBrowser({
|
||||||
|
state,
|
||||||
|
normalizeId,
|
||||||
|
getDomRefs: () => ({
|
||||||
|
listEl,
|
||||||
|
countEl,
|
||||||
|
detailNameEl,
|
||||||
|
detailSubEl,
|
||||||
|
detailBodyEl,
|
||||||
|
tabAll,
|
||||||
|
tabHebrew,
|
||||||
|
tabGreek,
|
||||||
|
tabEnglish,
|
||||||
|
tabArabic,
|
||||||
|
tabEnochian,
|
||||||
|
searchInputEl,
|
||||||
|
searchClearEl,
|
||||||
|
typeFilterEl
|
||||||
|
}),
|
||||||
|
renderDetail
|
||||||
|
});
|
||||||
|
|
||||||
// ── Event delegation on detail body ──────────────────────────────────
|
// ── Event delegation on detail body ──────────────────────────────────
|
||||||
function attachDetailListeners() {
|
function attachDetailListeners() {
|
||||||
if (!detailBodyEl) return;
|
if (!detailBodyEl) return;
|
||||||
@@ -568,43 +367,20 @@
|
|||||||
|
|
||||||
// ── Selection ─────────────────────────────────────────────────────────
|
// ── Selection ─────────────────────────────────────────────────────────
|
||||||
function selectLetter(key) {
|
function selectLetter(key) {
|
||||||
state.selectedKey = key;
|
browserUi.selectLetter(key);
|
||||||
renderList();
|
|
||||||
const letters = getFilteredLetters();
|
|
||||||
const letter = letters.find((l) => letterKey(l) === key) || getLetters().find((l) => letterKey(l) === key);
|
|
||||||
if (letter) renderDetail(letter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Alphabet switching ────────────────────────────────────────────────
|
// ── Alphabet switching ────────────────────────────────────────────────
|
||||||
function switchAlphabet(alpha, selectKey) {
|
function switchAlphabet(alpha, selectKey) {
|
||||||
state.activeAlphabet = alpha;
|
browserUi.switchAlphabet(alpha, selectKey);
|
||||||
state.selectedKey = selectKey || null;
|
|
||||||
updateTabs();
|
|
||||||
syncFilterControls();
|
|
||||||
renderList();
|
|
||||||
if (selectKey) {
|
|
||||||
const letters = getFilteredLetters();
|
|
||||||
const letter = letters.find((l) => letterKey(l) === selectKey) || getLetters().find((l) => letterKey(l) === selectKey);
|
|
||||||
if (letter) renderDetail(letter);
|
|
||||||
} else {
|
|
||||||
resetDetail();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTabs() {
|
function updateTabs() {
|
||||||
[tabAll, tabHebrew, tabGreek, tabEnglish, tabArabic, tabEnochian].forEach((btn) => {
|
browserUi.updateTabs();
|
||||||
if (!btn) return;
|
|
||||||
btn.classList.toggle("alpha-tab-active", btn.dataset.alpha === state.activeAlphabet);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetDetail() {
|
function resetDetail() {
|
||||||
if (detailNameEl) {
|
browserUi.resetDetail();
|
||||||
detailNameEl.textContent = "--";
|
|
||||||
detailNameEl.classList.remove("alpha-detail-glyph");
|
|
||||||
}
|
|
||||||
if (detailSubEl) detailSubEl.textContent = "Select a letter to explore";
|
|
||||||
if (detailBodyEl) detailBodyEl.innerHTML = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Public init ───────────────────────────────────────────────────────
|
// ── Public init ───────────────────────────────────────────────────────
|
||||||
|
|||||||
277
app/ui-cube-selection.js
Normal file
277
app/ui-cube-selection.js
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
(function () {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
function createCubeSelectionHelpers(dependencies) {
|
||||||
|
const {
|
||||||
|
state,
|
||||||
|
normalizeId,
|
||||||
|
normalizeEdgeId,
|
||||||
|
normalizeLetterKey,
|
||||||
|
toFiniteNumber,
|
||||||
|
getWalls,
|
||||||
|
getWallById,
|
||||||
|
getEdges,
|
||||||
|
getEdgeById,
|
||||||
|
getEdgeWalls,
|
||||||
|
getEdgesForWall,
|
||||||
|
getEdgeLetterId,
|
||||||
|
getWallFaceLetterId,
|
||||||
|
getEdgePathEntry,
|
||||||
|
getConnectorById,
|
||||||
|
snapRotationToWall,
|
||||||
|
render,
|
||||||
|
getElements
|
||||||
|
} = dependencies || {};
|
||||||
|
|
||||||
|
function applyPlacement(placement) {
|
||||||
|
const fallbackWallId = normalizeId(getWalls()[0]?.id);
|
||||||
|
const nextWallId = normalizeId(placement?.wallId || placement?.wall?.id || state.selectedWallId || fallbackWallId);
|
||||||
|
const wall = getWallById(nextWallId);
|
||||||
|
if (!wall) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.selectedWallId = normalizeId(wall.id);
|
||||||
|
|
||||||
|
const candidateEdgeId = normalizeEdgeId(placement?.edgeId || placement?.edge?.id);
|
||||||
|
const wallEdges = getEdgesForWall(state.selectedWallId);
|
||||||
|
const resolvedEdgeId = candidateEdgeId && getEdgeById(candidateEdgeId)
|
||||||
|
? candidateEdgeId
|
||||||
|
: normalizeEdgeId(wallEdges[0]?.id || getEdges()[0]?.id);
|
||||||
|
|
||||||
|
state.selectedEdgeId = resolvedEdgeId;
|
||||||
|
state.selectedNodeType = "wall";
|
||||||
|
state.selectedConnectorId = null;
|
||||||
|
render(getElements());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectEdgeById(edgeId, preferredWallId = "") {
|
||||||
|
const edge = getEdgeById(edgeId);
|
||||||
|
if (!edge) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentWallId = normalizeId(state.selectedWallId);
|
||||||
|
const preferredId = normalizeId(preferredWallId);
|
||||||
|
const edgeWalls = getEdgeWalls(edge);
|
||||||
|
const nextWallId = preferredId && edgeWalls.includes(preferredId)
|
||||||
|
? preferredId
|
||||||
|
: (edgeWalls.includes(currentWallId) ? currentWallId : (edgeWalls[0] || currentWallId));
|
||||||
|
|
||||||
|
state.selectedEdgeId = normalizeEdgeId(edge.id);
|
||||||
|
state.selectedNodeType = "wall";
|
||||||
|
state.selectedConnectorId = null;
|
||||||
|
|
||||||
|
if (nextWallId) {
|
||||||
|
if (nextWallId !== currentWallId) {
|
||||||
|
state.selectedWallId = nextWallId;
|
||||||
|
snapRotationToWall(nextWallId);
|
||||||
|
} else if (!state.selectedWallId) {
|
||||||
|
state.selectedWallId = nextWallId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render(getElements());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectWallById(wallId) {
|
||||||
|
if (!state.initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wall = getWallById(wallId);
|
||||||
|
if (!wall) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.selectedWallId = normalizeId(wall.id);
|
||||||
|
state.selectedEdgeId = normalizeEdgeId(getEdgesForWall(state.selectedWallId)[0]?.id || getEdges()[0]?.id);
|
||||||
|
state.selectedNodeType = "wall";
|
||||||
|
state.selectedConnectorId = null;
|
||||||
|
snapRotationToWall(state.selectedWallId);
|
||||||
|
render(getElements());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectConnectorById(connectorId) {
|
||||||
|
if (!state.initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const connector = getConnectorById(connectorId);
|
||||||
|
if (!connector) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fromWallId = normalizeId(connector.fromWallId);
|
||||||
|
if (fromWallId && getWallById(fromWallId)) {
|
||||||
|
state.selectedWallId = fromWallId;
|
||||||
|
state.selectedEdgeId = normalizeEdgeId(getEdgesForWall(fromWallId)[0]?.id || getEdges()[0]?.id);
|
||||||
|
snapRotationToWall(fromWallId);
|
||||||
|
}
|
||||||
|
|
||||||
|
state.showConnectorLines = true;
|
||||||
|
state.selectedNodeType = "connector";
|
||||||
|
state.selectedConnectorId = normalizeId(connector.id);
|
||||||
|
render(getElements());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectCenterNode() {
|
||||||
|
if (!state.initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.showPrimalPoint = true;
|
||||||
|
state.selectedNodeType = "center";
|
||||||
|
state.selectedConnectorId = null;
|
||||||
|
render(getElements());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPlacement(criteria = {}) {
|
||||||
|
if (!state.initialized) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wallId = normalizeId(criteria.wallId);
|
||||||
|
const connectorId = normalizeId(criteria.connectorId);
|
||||||
|
const edgeId = normalizeEdgeId(criteria.edgeId || criteria.directionId);
|
||||||
|
const hebrewLetterId = normalizeLetterKey(criteria.hebrewLetterId);
|
||||||
|
const signId = normalizeId(criteria.signId || criteria.zodiacSignId);
|
||||||
|
const planetId = normalizeId(criteria.planetId);
|
||||||
|
const pathNo = toFiniteNumber(criteria.pathNo || criteria.kabbalahPathNumber);
|
||||||
|
const trumpNo = toFiniteNumber(criteria.trumpNumber || criteria.tarotTrumpNumber);
|
||||||
|
const nodeType = normalizeId(criteria.nodeType);
|
||||||
|
const centerRequested = nodeType === "center"
|
||||||
|
|| Boolean(criteria.center)
|
||||||
|
|| Boolean(criteria.primalPoint)
|
||||||
|
|| normalizeId(criteria.centerId) === "primal-point";
|
||||||
|
const edges = getEdges();
|
||||||
|
|
||||||
|
const findEdgeBy = (predicate) => edges.find((edge) => predicate(edge)) || null;
|
||||||
|
|
||||||
|
const findWallForEdge = (edge, preferredWallId) => {
|
||||||
|
const edgeWalls = getEdgeWalls(edge);
|
||||||
|
if (preferredWallId && edgeWalls.includes(preferredWallId)) {
|
||||||
|
return preferredWallId;
|
||||||
|
}
|
||||||
|
return edgeWalls[0] || normalizeId(getWalls()[0]?.id);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (connectorId) {
|
||||||
|
return selectConnectorById(connectorId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (centerRequested) {
|
||||||
|
return selectCenterNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (edgeId) {
|
||||||
|
const edge = getEdgeById(edgeId);
|
||||||
|
if (!edge) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: findWallForEdge(edge, wallId),
|
||||||
|
edgeId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wallId) {
|
||||||
|
const wall = getWallById(wallId);
|
||||||
|
if (!wall) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!edgeId) {
|
||||||
|
return selectWallById(wallId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstEdge = getEdgesForWall(wallId)[0] || null;
|
||||||
|
return applyPlacement({ wallId, edgeId: firstEdge?.id });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hebrewLetterId) {
|
||||||
|
const byHebrew = findEdgeBy((edge) => getEdgeLetterId(edge) === hebrewLetterId);
|
||||||
|
if (byHebrew) {
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: findWallForEdge(byHebrew),
|
||||||
|
edgeId: byHebrew.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const byWallFace = getWalls().find((wall) => getWallFaceLetterId(wall) === hebrewLetterId) || null;
|
||||||
|
if (byWallFace) {
|
||||||
|
const byWallFaceId = normalizeId(byWallFace.id);
|
||||||
|
const firstEdge = getEdgesForWall(byWallFaceId)[0] || null;
|
||||||
|
return applyPlacement({ wallId: byWallFaceId, edgeId: firstEdge?.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signId) {
|
||||||
|
const bySign = findEdgeBy((edge) => {
|
||||||
|
const astrology = getEdgePathEntry(edge)?.astrology || {};
|
||||||
|
return normalizeId(astrology.type) === "zodiac" && normalizeId(astrology.name) === signId;
|
||||||
|
});
|
||||||
|
if (bySign) {
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: findWallForEdge(bySign),
|
||||||
|
edgeId: bySign.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pathNo != null) {
|
||||||
|
const byPath = findEdgeBy((edge) => toFiniteNumber(getEdgePathEntry(edge)?.pathNumber) === pathNo);
|
||||||
|
if (byPath) {
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: findWallForEdge(byPath),
|
||||||
|
edgeId: byPath.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trumpNo != null) {
|
||||||
|
const byTrump = findEdgeBy((edge) => {
|
||||||
|
const tarot = getEdgePathEntry(edge)?.tarot || {};
|
||||||
|
return toFiniteNumber(tarot.trumpNumber) === trumpNo;
|
||||||
|
});
|
||||||
|
if (byTrump) {
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: findWallForEdge(byTrump),
|
||||||
|
edgeId: byTrump.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (planetId) {
|
||||||
|
const wall = getWalls().find((entry) => normalizeId(entry?.associations?.planetId) === planetId);
|
||||||
|
if (wall) {
|
||||||
|
const wallIdByPlanet = normalizeId(wall.id);
|
||||||
|
return applyPlacement({
|
||||||
|
wallId: wallIdByPlanet,
|
||||||
|
edgeId: getEdgesForWall(wallIdByPlanet)[0]?.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
applyPlacement,
|
||||||
|
selectEdgeById,
|
||||||
|
selectWallById,
|
||||||
|
selectConnectorById,
|
||||||
|
selectCenterNode,
|
||||||
|
selectPlacement
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
window.CubeSelectionHelpers = {
|
||||||
|
createCubeSelectionHelpers
|
||||||
|
};
|
||||||
|
})();
|
||||||
259
app/ui-cube.js
259
app/ui-cube.js
@@ -122,6 +122,7 @@
|
|||||||
const cubeDetailUi = window.CubeDetailUi || {};
|
const cubeDetailUi = window.CubeDetailUi || {};
|
||||||
const cubeChassisUi = window.CubeChassisUi || {};
|
const cubeChassisUi = window.CubeChassisUi || {};
|
||||||
const cubeMathHelpers = window.CubeMathHelpers || {};
|
const cubeMathHelpers = window.CubeMathHelpers || {};
|
||||||
|
const cubeSelectionHelpers = window.CubeSelectionHelpers || {};
|
||||||
|
|
||||||
function getElements() {
|
function getElements() {
|
||||||
return {
|
return {
|
||||||
@@ -256,6 +257,10 @@
|
|||||||
throw new Error("CubeMathHelpers.createCubeMathHelpers is unavailable. Ensure app/ui-cube-math.js loads before app/ui-cube.js.");
|
throw new Error("CubeMathHelpers.createCubeMathHelpers is unavailable. Ensure app/ui-cube-math.js loads before app/ui-cube.js.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof cubeSelectionHelpers.createCubeSelectionHelpers !== "function") {
|
||||||
|
throw new Error("CubeSelectionHelpers.createCubeSelectionHelpers is unavailable. Ensure app/ui-cube-selection.js loads before app/ui-cube.js.");
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeAngle(angle) {
|
function normalizeAngle(angle) {
|
||||||
return cubeMathUi.normalizeAngle(angle);
|
return cubeMathUi.normalizeAngle(angle);
|
||||||
}
|
}
|
||||||
@@ -432,6 +437,27 @@
|
|||||||
getCubeCenterData
|
getCubeCenterData
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const cubeSelectionUi = cubeSelectionHelpers.createCubeSelectionHelpers({
|
||||||
|
state,
|
||||||
|
normalizeId,
|
||||||
|
normalizeEdgeId,
|
||||||
|
normalizeLetterKey,
|
||||||
|
toFiniteNumber,
|
||||||
|
getWalls,
|
||||||
|
getWallById,
|
||||||
|
getEdges,
|
||||||
|
getEdgeById,
|
||||||
|
getEdgeWalls,
|
||||||
|
getEdgesForWall,
|
||||||
|
getEdgeLetterId,
|
||||||
|
getWallFaceLetterId,
|
||||||
|
getEdgePathEntry,
|
||||||
|
getConnectorById,
|
||||||
|
snapRotationToWall,
|
||||||
|
render,
|
||||||
|
getElements
|
||||||
|
});
|
||||||
|
|
||||||
function getEdgeAstrologySymbol(edge) {
|
function getEdgeAstrologySymbol(edge) {
|
||||||
return cubeMathUi.getEdgeAstrologySymbol(edge);
|
return cubeMathUi.getEdgeAstrologySymbol(edge);
|
||||||
}
|
}
|
||||||
@@ -488,26 +514,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function applyPlacement(placement) {
|
function applyPlacement(placement) {
|
||||||
const fallbackWallId = normalizeId(getWalls()[0]?.id);
|
return cubeSelectionUi.applyPlacement(placement);
|
||||||
const nextWallId = normalizeId(placement?.wallId || placement?.wall?.id || state.selectedWallId || fallbackWallId);
|
|
||||||
const wall = getWallById(nextWallId);
|
|
||||||
if (!wall) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.selectedWallId = normalizeId(wall.id);
|
|
||||||
|
|
||||||
const candidateEdgeId = normalizeEdgeId(placement?.edgeId || placement?.edge?.id);
|
|
||||||
const wallEdges = getEdgesForWall(state.selectedWallId);
|
|
||||||
const resolvedEdgeId = candidateEdgeId && getEdgeById(candidateEdgeId)
|
|
||||||
? candidateEdgeId
|
|
||||||
: normalizeEdgeId(wallEdges[0]?.id || getEdges()[0]?.id);
|
|
||||||
|
|
||||||
state.selectedEdgeId = resolvedEdgeId;
|
|
||||||
state.selectedNodeType = "wall";
|
|
||||||
state.selectedConnectorId = null;
|
|
||||||
render(getElements());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toDisplayText(value) {
|
function toDisplayText(value) {
|
||||||
@@ -559,33 +566,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectEdgeById(edgeId, preferredWallId = "") {
|
function selectEdgeById(edgeId, preferredWallId = "") {
|
||||||
const edge = getEdgeById(edgeId);
|
return cubeSelectionUi.selectEdgeById(edgeId, preferredWallId);
|
||||||
if (!edge) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentWallId = normalizeId(state.selectedWallId);
|
|
||||||
const preferredId = normalizeId(preferredWallId);
|
|
||||||
const edgeWalls = getEdgeWalls(edge);
|
|
||||||
const nextWallId = preferredId && edgeWalls.includes(preferredId)
|
|
||||||
? preferredId
|
|
||||||
: (edgeWalls.includes(currentWallId) ? currentWallId : (edgeWalls[0] || currentWallId));
|
|
||||||
|
|
||||||
state.selectedEdgeId = normalizeEdgeId(edge.id);
|
|
||||||
state.selectedNodeType = "wall";
|
|
||||||
state.selectedConnectorId = null;
|
|
||||||
|
|
||||||
if (nextWallId) {
|
|
||||||
if (nextWallId !== currentWallId) {
|
|
||||||
state.selectedWallId = nextWallId;
|
|
||||||
snapRotationToWall(nextWallId);
|
|
||||||
} else if (!state.selectedWallId) {
|
|
||||||
state.selectedWallId = nextWallId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render(getElements());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDetail(elements, walls) {
|
function renderDetail(elements, walls) {
|
||||||
@@ -710,195 +691,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function selectWallById(wallId) {
|
function selectWallById(wallId) {
|
||||||
if (!state.initialized) {
|
return cubeSelectionUi.selectWallById(wallId);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wall = getWallById(wallId);
|
|
||||||
if (!wall) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.selectedWallId = normalizeId(wall.id);
|
|
||||||
state.selectedEdgeId = normalizeEdgeId(getEdgesForWall(state.selectedWallId)[0]?.id || getEdges()[0]?.id);
|
|
||||||
state.selectedNodeType = "wall";
|
|
||||||
state.selectedConnectorId = null;
|
|
||||||
snapRotationToWall(state.selectedWallId);
|
|
||||||
render(getElements());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectConnectorById(connectorId) {
|
function selectConnectorById(connectorId) {
|
||||||
if (!state.initialized) {
|
return cubeSelectionUi.selectConnectorById(connectorId);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const connector = getConnectorById(connectorId);
|
|
||||||
if (!connector) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fromWallId = normalizeId(connector.fromWallId);
|
|
||||||
if (fromWallId && getWallById(fromWallId)) {
|
|
||||||
state.selectedWallId = fromWallId;
|
|
||||||
state.selectedEdgeId = normalizeEdgeId(getEdgesForWall(fromWallId)[0]?.id || getEdges()[0]?.id);
|
|
||||||
snapRotationToWall(fromWallId);
|
|
||||||
}
|
|
||||||
|
|
||||||
state.showConnectorLines = true;
|
|
||||||
state.selectedNodeType = "connector";
|
|
||||||
state.selectedConnectorId = normalizeId(connector.id);
|
|
||||||
render(getElements());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectCenterNode() {
|
function selectCenterNode() {
|
||||||
if (!state.initialized) {
|
return cubeSelectionUi.selectCenterNode();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
state.showPrimalPoint = true;
|
|
||||||
state.selectedNodeType = "center";
|
|
||||||
state.selectedConnectorId = null;
|
|
||||||
render(getElements());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPlacement(criteria = {}) {
|
function selectPlacement(criteria = {}) {
|
||||||
if (!state.initialized) {
|
return cubeSelectionUi.selectPlacement(criteria);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wallId = normalizeId(criteria.wallId);
|
|
||||||
const connectorId = normalizeId(criteria.connectorId);
|
|
||||||
const edgeId = normalizeEdgeId(criteria.edgeId || criteria.directionId);
|
|
||||||
const hebrewLetterId = normalizeLetterKey(criteria.hebrewLetterId);
|
|
||||||
const signId = normalizeId(criteria.signId || criteria.zodiacSignId);
|
|
||||||
const planetId = normalizeId(criteria.planetId);
|
|
||||||
const pathNo = toFiniteNumber(criteria.pathNo || criteria.kabbalahPathNumber);
|
|
||||||
const trumpNo = toFiniteNumber(criteria.trumpNumber || criteria.tarotTrumpNumber);
|
|
||||||
const nodeType = normalizeId(criteria.nodeType);
|
|
||||||
const centerRequested = nodeType === "center"
|
|
||||||
|| Boolean(criteria.center)
|
|
||||||
|| Boolean(criteria.primalPoint)
|
|
||||||
|| normalizeId(criteria.centerId) === "primal-point";
|
|
||||||
const edges = getEdges();
|
|
||||||
|
|
||||||
const findEdgeBy = (predicate) => edges.find((edge) => predicate(edge)) || null;
|
|
||||||
|
|
||||||
const findWallForEdge = (edge, preferredWallId) => {
|
|
||||||
const edgeWalls = getEdgeWalls(edge);
|
|
||||||
if (preferredWallId && edgeWalls.includes(preferredWallId)) {
|
|
||||||
return preferredWallId;
|
|
||||||
}
|
|
||||||
return edgeWalls[0] || normalizeId(getWalls()[0]?.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (connectorId) {
|
|
||||||
return selectConnectorById(connectorId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (centerRequested) {
|
|
||||||
return selectCenterNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (edgeId) {
|
|
||||||
const edge = getEdgeById(edgeId);
|
|
||||||
if (!edge) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: findWallForEdge(edge, wallId),
|
|
||||||
edgeId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wallId) {
|
|
||||||
const wall = getWallById(wallId);
|
|
||||||
if (!wall) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if an explicit edge id was not provided (or was empty) we treat this
|
|
||||||
// as a request to show the wall/face itself rather than any particular
|
|
||||||
// edge direction. `applyPlacement` only knows how to highlight edges,
|
|
||||||
// so we fall back to selecting the wall directly in that case. this
|
|
||||||
// is the behaviour we want when navigating from a "face" letter like
|
|
||||||
// dalet, where the placement computed by ui-alphabet leaves edgeId
|
|
||||||
// blank.
|
|
||||||
if (!edgeId) {
|
|
||||||
return selectWallById(wallId);
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstEdge = getEdgesForWall(wallId)[0] || null;
|
|
||||||
return applyPlacement({ wallId, edgeId: firstEdge?.id });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hebrewLetterId) {
|
|
||||||
const byHebrew = findEdgeBy((edge) => getEdgeLetterId(edge) === hebrewLetterId);
|
|
||||||
if (byHebrew) {
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: findWallForEdge(byHebrew),
|
|
||||||
edgeId: byHebrew.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const byWallFace = getWalls().find((wall) => getWallFaceLetterId(wall) === hebrewLetterId) || null;
|
|
||||||
if (byWallFace) {
|
|
||||||
const byWallFaceId = normalizeId(byWallFace.id);
|
|
||||||
const firstEdge = getEdgesForWall(byWallFaceId)[0] || null;
|
|
||||||
return applyPlacement({ wallId: byWallFaceId, edgeId: firstEdge?.id });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signId) {
|
|
||||||
const bySign = findEdgeBy((edge) => {
|
|
||||||
const astrology = getEdgePathEntry(edge)?.astrology || {};
|
|
||||||
return normalizeId(astrology.type) === "zodiac" && normalizeId(astrology.name) === signId;
|
|
||||||
});
|
|
||||||
if (bySign) {
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: findWallForEdge(bySign),
|
|
||||||
edgeId: bySign.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pathNo != null) {
|
|
||||||
const byPath = findEdgeBy((edge) => toFiniteNumber(getEdgePathEntry(edge)?.pathNumber) === pathNo);
|
|
||||||
if (byPath) {
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: findWallForEdge(byPath),
|
|
||||||
edgeId: byPath.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trumpNo != null) {
|
|
||||||
const byTrump = findEdgeBy((edge) => {
|
|
||||||
const tarot = getEdgePathEntry(edge)?.tarot || {};
|
|
||||||
return toFiniteNumber(tarot.trumpNumber) === trumpNo;
|
|
||||||
});
|
|
||||||
if (byTrump) {
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: findWallForEdge(byTrump),
|
|
||||||
edgeId: byTrump.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (planetId) {
|
|
||||||
const wall = getWalls().find((entry) => normalizeId(entry?.associations?.planetId) === planetId);
|
|
||||||
if (wall) {
|
|
||||||
const wallIdByPlanet = normalizeId(wall.id);
|
|
||||||
return applyPlacement({
|
|
||||||
wallId: wallIdByPlanet,
|
|
||||||
edgeId: getEdgesForWall(wallIdByPlanet)[0]?.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectByHebrewLetterId(hebrewLetterId) {
|
function selectByHebrewLetterId(hebrewLetterId) {
|
||||||
|
|||||||
@@ -509,6 +509,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
window.NowUiHelpers = {
|
window.NowUiHelpers = {
|
||||||
|
getSignStartDate,
|
||||||
findNextDecanTransition,
|
findNextDecanTransition,
|
||||||
findNextMoonPhaseTransition,
|
findNextMoonPhaseTransition,
|
||||||
formatCountdown,
|
formatCountdown,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
const {
|
const {
|
||||||
DAY_IN_MS,
|
DAY_IN_MS,
|
||||||
getDateKey,
|
getDateKey,
|
||||||
|
getDecanForDate,
|
||||||
getMoonPhaseName,
|
getMoonPhaseName,
|
||||||
calcPlanetaryHoursForDayAndLocation
|
calcPlanetaryHoursForDayAndLocation
|
||||||
} = window.TarotCalc;
|
} = window.TarotCalc;
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
typeof nowUiHelpers.findNextDecanTransition !== "function"
|
typeof nowUiHelpers.findNextDecanTransition !== "function"
|
||||||
|| typeof nowUiHelpers.findNextMoonPhaseTransition !== "function"
|
|| typeof nowUiHelpers.findNextMoonPhaseTransition !== "function"
|
||||||
|| typeof nowUiHelpers.formatCountdown !== "function"
|
|| typeof nowUiHelpers.formatCountdown !== "function"
|
||||||
|
|| typeof nowUiHelpers.getSignStartDate !== "function"
|
||||||
|| typeof nowUiHelpers.getDisplayTarotName !== "function"
|
|| typeof nowUiHelpers.getDisplayTarotName !== "function"
|
||||||
|| typeof nowUiHelpers.setNowCardImage !== "function"
|
|| typeof nowUiHelpers.setNowCardImage !== "function"
|
||||||
|| typeof nowUiHelpers.updateNowStats !== "function"
|
|| typeof nowUiHelpers.updateNowStats !== "function"
|
||||||
@@ -128,7 +130,7 @@
|
|||||||
? `${sunInfo.sign.id}-${sunInfo.decan?.index || 1}`
|
? `${sunInfo.sign.id}-${sunInfo.decan?.index || 1}`
|
||||||
: "no-decan";
|
: "no-decan";
|
||||||
if (sunInfo?.sign) {
|
if (sunInfo?.sign) {
|
||||||
const signStartDate = getSignStartDate(now, sunInfo.sign);
|
const signStartDate = nowUiHelpers.getSignStartDate(now, sunInfo.sign);
|
||||||
const daysSinceSignStart = (now.getTime() - signStartDate.getTime()) / DAY_IN_MS;
|
const daysSinceSignStart = (now.getTime() - signStartDate.getTime()) / DAY_IN_MS;
|
||||||
const signDegree = Math.min(29.9, Math.max(0, daysSinceSignStart));
|
const signDegree = Math.min(29.9, Math.max(0, daysSinceSignStart));
|
||||||
const signMajorName = nowUiHelpers.getDisplayTarotName(sunInfo.sign.tarot.majorArcana, sunInfo.sign.tarot.trumpNumber);
|
const signMajorName = nowUiHelpers.getDisplayTarotName(sunInfo.sign.tarot.majorArcana, sunInfo.sign.tarot.trumpNumber);
|
||||||
|
|||||||
@@ -188,6 +188,19 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const MINOR_PLURAL_BY_RANK = {
|
||||||
|
ace: "aces",
|
||||||
|
two: "twos",
|
||||||
|
three: "threes",
|
||||||
|
four: "fours",
|
||||||
|
five: "fives",
|
||||||
|
six: "sixes",
|
||||||
|
seven: "sevens",
|
||||||
|
eight: "eights",
|
||||||
|
nine: "nines",
|
||||||
|
ten: "tens"
|
||||||
|
};
|
||||||
|
|
||||||
function slugify(value) {
|
function slugify(value) {
|
||||||
return String(value || "")
|
return String(value || "")
|
||||||
.trim()
|
.trim()
|
||||||
@@ -473,19 +486,6 @@
|
|||||||
return tarotCardDerivationsUi.buildTypeLabel(card);
|
return tarotCardDerivationsUi.buildTypeLabel(card);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MINOR_PLURAL_BY_RANK = {
|
|
||||||
ace: "aces",
|
|
||||||
two: "twos",
|
|
||||||
three: "threes",
|
|
||||||
four: "fours",
|
|
||||||
five: "fives",
|
|
||||||
six: "sixes",
|
|
||||||
seven: "sevens",
|
|
||||||
eight: "eights",
|
|
||||||
nine: "nines",
|
|
||||||
ten: "tens"
|
|
||||||
};
|
|
||||||
|
|
||||||
function findSephirahForMinorCard(card, kabTree) {
|
function findSephirahForMinorCard(card, kabTree) {
|
||||||
return tarotCardDerivationsUi.findSephirahForMinorCard(card, kabTree);
|
return tarotCardDerivationsUi.findSephirahForMinorCard(card, kabTree);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -804,8 +804,10 @@
|
|||||||
<script src="app/ui-cube-detail.js"></script>
|
<script src="app/ui-cube-detail.js"></script>
|
||||||
<script src="app/ui-cube-chassis.js"></script>
|
<script src="app/ui-cube-chassis.js"></script>
|
||||||
<script src="app/ui-cube-math.js"></script>
|
<script src="app/ui-cube-math.js"></script>
|
||||||
|
<script src="app/ui-cube-selection.js"></script>
|
||||||
<script src="app/ui-cube.js"></script>
|
<script src="app/ui-cube.js"></script>
|
||||||
<script src="app/ui-alphabet-gematria.js"></script>
|
<script src="app/ui-alphabet-gematria.js"></script>
|
||||||
|
<script src="app/ui-alphabet-browser.js"></script>
|
||||||
<script src="app/ui-alphabet-references.js"></script>
|
<script src="app/ui-alphabet-references.js"></script>
|
||||||
<script src="app/ui-alphabet-detail.js"></script>
|
<script src="app/ui-alphabet-detail.js"></script>
|
||||||
<script src="app/ui-alphabet-kabbalah.js"></script>
|
<script src="app/ui-alphabet-kabbalah.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user