(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 `${key}`;
}
return `
`;
}
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 = `${alphaLabel}${displayLabel(letter)}
${displaySub(letter)}`;
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
};
})();