/* ui-holidays-render.js - Render/search helpers for the holiday repository */
(function () {
"use strict";
function planetLabel(planetId, context) {
const { state, cap } = context;
if (!planetId) {
return "Planet";
}
const planet = state.planetsById.get(planetId);
if (!planet) {
return cap(planetId);
}
return `${planet.symbol || ""} ${planet.name || cap(planetId)}`.trim();
}
function zodiacLabel(signId, context) {
const { state, cap } = context;
if (!signId) {
return "Zodiac";
}
const sign = state.signsById.get(signId);
if (!sign) {
return cap(signId);
}
return `${sign.symbol || ""} ${sign.name || cap(signId)}`.trim();
}
function godLabel(godId, godName, context) {
const { state, cap } = context;
if (godName) {
return godName;
}
if (!godId) {
return "Deity";
}
const god = state.godsById.get(godId);
return god?.name || cap(godId);
}
function hebrewLabel(hebrewLetterId, context) {
const { state, cap } = context;
if (!hebrewLetterId) {
return "Hebrew Letter";
}
const letter = state.hebrewById.get(hebrewLetterId);
if (!letter) {
return cap(hebrewLetterId);
}
return `${letter.char || ""} ${letter.name || cap(hebrewLetterId)}`.trim();
}
function computeDigitalRoot(value) {
let current = Math.abs(Math.trunc(Number(value)));
if (!Number.isFinite(current)) {
return null;
}
while (current >= 10) {
current = String(current)
.split("")
.reduce((sum, digit) => sum + Number(digit), 0);
}
return current;
}
function buildAssociationButtons(associations, context) {
const { getDisplayTarotName, resolveTarotTrumpNumber } = context;
if (!associations || typeof associations !== "object") {
return '
--
';
}
const buttons = [];
if (associations.planetId) {
buttons.push(
``
);
}
if (associations.zodiacSignId) {
buttons.push(
``
);
}
if (Number.isFinite(Number(associations.numberValue))) {
const rawNumber = Math.trunc(Number(associations.numberValue));
if (rawNumber >= 0) {
const numberValue = computeDigitalRoot(rawNumber);
if (numberValue != null) {
const label = rawNumber === numberValue
? `Number ${numberValue}`
: `Number ${numberValue} (from ${rawNumber})`;
buttons.push(
``
);
}
}
}
if (associations.tarotCard) {
const trumpNumber = resolveTarotTrumpNumber(associations.tarotCard);
const explicitTrumpNumber = Number(associations.tarotTrumpNumber);
const tarotTrumpNumber = Number.isFinite(explicitTrumpNumber) ? explicitTrumpNumber : trumpNumber;
const tarotLabel = getDisplayTarotName(associations.tarotCard, tarotTrumpNumber);
buttons.push(
``
);
}
if (associations.godId || associations.godName) {
const label = godLabel(associations.godId, associations.godName, context);
buttons.push(
``
);
}
if (associations.hebrewLetterId) {
buttons.push(
``
);
}
if (associations.kabbalahPathNumber != null) {
buttons.push(
``
);
}
if (associations.iChingPlanetaryInfluence) {
buttons.push(
``
);
}
if (!buttons.length) {
return '--
';
}
return `${buttons.join("")}
`;
}
function associationSearchText(associations, context) {
const { getTarotCardSearchAliases } = context;
if (!associations || typeof associations !== "object") {
return "";
}
const tarotAliases = associations.tarotCard && typeof getTarotCardSearchAliases === "function"
? getTarotCardSearchAliases(associations.tarotCard, { trumpNumber: associations.tarotTrumpNumber })
: [];
return [
associations.planetId,
associations.zodiacSignId,
associations.numberValue,
associations.tarotCard,
associations.tarotTrumpNumber,
...tarotAliases,
associations.godId,
associations.godName,
associations.hebrewLetterId,
associations.kabbalahPathNumber,
associations.iChingPlanetaryInfluence
].filter(Boolean).join(" ");
}
function holidaySearchText(holiday, context) {
const { normalizeSearchValue } = context;
return normalizeSearchValue([
holiday?.name,
holiday?.kind,
holiday?.date,
holiday?.dateRange,
holiday?.dateText,
holiday?.monthDayStart,
holiday?.calendarId,
holiday?.description,
associationSearchText(holiday?.associations, context)
].filter(Boolean).join(" "));
}
function renderList(context) {
const {
elements,
state,
filterBySource,
normalizeSourceFilter,
calendarLabel,
monthLabelForCalendar,
selectByHolidayId
} = context;
const { listEl, countEl } = elements;
if (!listEl) {
return;
}
listEl.innerHTML = "";
state.filteredHolidays.forEach((holiday) => {
const isSelected = holiday.id === state.selectedHolidayId;
const itemEl = document.createElement("div");
itemEl.className = `planet-list-item${isSelected ? " is-selected" : ""}`;
itemEl.setAttribute("role", "option");
itemEl.setAttribute("aria-selected", isSelected ? "true" : "false");
itemEl.dataset.holidayId = holiday.id;
const sourceCalendar = calendarLabel(holiday.calendarId);
const sourceMonth = monthLabelForCalendar(holiday.calendarId, holiday.monthId);
const sourceDate = holiday?.dateText || holiday?.date || holiday?.dateRange || "--";
itemEl.innerHTML = `
${holiday?.name || holiday?.id || "Holiday"}
${sourceCalendar} - ${sourceMonth} - ${sourceDate}
`;
itemEl.addEventListener("click", () => {
selectByHolidayId(holiday.id, elements);
});
listEl.appendChild(itemEl);
});
if (countEl) {
const sourceFiltered = filterBySource(state.holidays);
const activeFilter = normalizeSourceFilter(state.selectedSource);
const sourceLabel = activeFilter === "all"
? ""
: ` (${calendarLabel(activeFilter)})`;
countEl.textContent = state.searchQuery
? `${state.filteredHolidays.length} of ${sourceFiltered.length} holidays${sourceLabel}`
: `${sourceFiltered.length} holidays${sourceLabel}`;
}
}
function renderHolidayDetail(holiday, context) {
const {
state,
calendarLabel,
monthLabelForCalendar,
resolveHolidayGregorianDate,
formatGregorianReferenceDate,
formatCalendarDateFromGregorian
} = context;
const gregorianDate = resolveHolidayGregorianDate(holiday);
const gregorianRef = formatGregorianReferenceDate(gregorianDate);
const hebrewRef = formatCalendarDateFromGregorian(gregorianDate, "hebrew");
const islamicRef = formatCalendarDateFromGregorian(gregorianDate, "islamic");
const confidence = String(holiday?.conversionConfidence || holiday?.datePrecision || "approximate").toLowerCase();
const confidenceLabel = (!(gregorianDate instanceof Date) || Number.isNaN(gregorianDate.getTime()))
? "unresolved"
: (confidence === "exact" ? "exact" : "approximate");
const monthName = monthLabelForCalendar(holiday?.calendarId, holiday?.monthId);
const holidayDate = holiday?.dateText || holiday?.date || holiday?.dateRange || "--";
const sourceMonthLink = holiday?.monthId
? ``
: "";
return `
`;
}
window.HolidayRenderUi = {
holidaySearchText,
renderList,
renderHolidayDetail
};
})();