Files
TaroTime/app/ui-cube.js

932 lines
26 KiB
JavaScript
Raw Normal View History

2026-03-07 01:09:00 -08:00
(function () {
"use strict";
const state = {
initialized: false,
controlsBound: false,
cube: null,
hebrewLetters: null,
kabbalahPathsByLetterId: new Map(),
markerDisplayMode: "both",
rotationX: 18,
rotationY: -28,
selectedNodeType: "wall",
showConnectorLines: true,
showPrimalPoint: true,
selectedConnectorId: null,
selectedWallId: null,
selectedEdgeId: null
};
const CUBE_VERTICES = [
[-1, -1, -1],
[1, -1, -1],
[1, 1, -1],
[-1, 1, -1],
[-1, -1, 1],
[1, -1, 1],
[1, 1, 1],
[-1, 1, 1]
];
const FACE_GEOMETRY = {
north: [4, 5, 6, 7],
south: [1, 0, 3, 2],
east: [5, 1, 2, 6],
west: [0, 4, 7, 3],
above: [0, 1, 5, 4],
below: [7, 6, 2, 3]
};
const EDGE_GEOMETRY = [
[0, 1], [1, 2], [2, 3], [3, 0],
[4, 5], [5, 6], [6, 7], [7, 4],
[0, 4], [1, 5], [2, 6], [3, 7]
];
const WALL_ORDER = ["north", "south", "east", "west", "above", "below"];
const EDGE_ORDER = [
"north-east",
"south-east",
"east-above",
"east-below",
"north-above",
"north-below",
"north-west",
"south-west",
"west-above",
"west-below",
"south-above",
"south-below"
];
const EDGE_GEOMETRY_KEYS = [
"south-above",
"south-east",
"south-below",
"south-west",
"north-above",
"north-east",
"north-below",
"north-west",
"west-above",
"east-above",
"east-below",
"west-below"
];
const CUBE_VIEW_CENTER = { x: 110, y: 108 };
const LOCAL_DIRECTION_ORDER = ["east", "south", "west", "north"];
const LOCAL_DIRECTION_RANK = {
east: 0,
south: 1,
west: 2,
north: 3
};
const LOCAL_DIRECTION_VIEW_MAP = {
north: "east",
east: "south",
south: "west",
west: "north"
};
const MOTHER_CONNECTORS = [
{
id: "above-below",
fromWallId: "above",
toWallId: "below",
hebrewLetterId: "alef",
name: "Above ↔ Below"
},
{
id: "east-west",
fromWallId: "east",
toWallId: "west",
hebrewLetterId: "mem",
name: "East ↔ West"
},
{
id: "south-north",
fromWallId: "south",
toWallId: "north",
hebrewLetterId: "shin",
name: "South ↔ North"
}
];
const WALL_FRONT_ROTATIONS = {
north: { x: 0, y: 0 },
south: { x: 0, y: 180 },
east: { x: 0, y: -90 },
west: { x: 0, y: 90 },
above: { x: -90, y: 0 },
below: { x: 90, y: 0 }
};
2026-03-07 05:17:50 -08:00
const cubeDetailUi = window.CubeDetailUi || {};
2026-03-07 13:38:13 -08:00
const cubeChassisUi = window.CubeChassisUi || {};
const cubeMathHelpers = window.CubeMathHelpers || {};
2026-03-07 01:09:00 -08:00
function getElements() {
return {
viewContainerEl: document.getElementById("cube-view-container"),
rotateLeftEl: document.getElementById("cube-rotate-left"),
rotateRightEl: document.getElementById("cube-rotate-right"),
rotateUpEl: document.getElementById("cube-rotate-up"),
rotateDownEl: document.getElementById("cube-rotate-down"),
rotateResetEl: document.getElementById("cube-rotate-reset"),
markerModeEl: document.getElementById("cube-marker-mode"),
connectorToggleEl: document.getElementById("cube-connector-toggle"),
primalToggleEl: document.getElementById("cube-primal-toggle"),
rotationReadoutEl: document.getElementById("cube-rotation-readout"),
detailNameEl: document.getElementById("cube-detail-name"),
detailSubEl: document.getElementById("cube-detail-sub"),
detailBodyEl: document.getElementById("cube-detail-body")
};
}
function normalizeId(value) {
return String(value || "").trim().toLowerCase();
}
function normalizeLetterKey(value) {
const key = normalizeId(value).replace(/[^a-z]/g, "");
const aliases = {
aleph: "alef",
beth: "bet",
zain: "zayin",
cheth: "het",
chet: "het",
daleth: "dalet",
kaf: "kaf",
kaph: "kaf",
teth: "tet",
peh: "pe",
tzaddi: "tsadi",
tzadi: "tsadi",
tzade: "tsadi",
tsaddi: "tsadi",
qoph: "qof",
taw: "tav",
tau: "tav"
};
return aliases[key] || key;
}
function asRecord(value) {
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
}
function getWalls() {
const walls = Array.isArray(state.cube?.walls) ? state.cube.walls : [];
return walls
.slice()
.sort((left, right) => WALL_ORDER.indexOf(normalizeId(left?.id)) - WALL_ORDER.indexOf(normalizeId(right?.id)));
}
function getWallById(wallId) {
const target = normalizeId(wallId);
return getWalls().find((wall) => normalizeId(wall?.id) === target) || null;
}
function normalizeEdgeId(value) {
return normalizeId(value).replace(/[\s_]+/g, "-");
}
function formatEdgeName(edgeId) {
return normalizeEdgeId(edgeId)
.split("-")
.filter(Boolean)
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
.join(" ");
}
function formatDirectionName(direction) {
const key = normalizeId(direction);
return key ? `${key.charAt(0).toUpperCase()}${key.slice(1)}` : "";
}
function getEdges() {
const configuredEdges = Array.isArray(state.cube?.edges) ? state.cube.edges : [];
const byId = new Map(
configuredEdges.map((edge) => [normalizeEdgeId(edge?.id), edge])
);
return EDGE_ORDER.map((edgeId) => {
const configured = byId.get(edgeId);
if (configured) {
return configured;
}
return {
id: edgeId,
name: formatEdgeName(edgeId),
walls: edgeId.split("-")
};
});
}
function getEdgeById(edgeId) {
const target = normalizeEdgeId(edgeId);
return getEdges().find((edge) => normalizeEdgeId(edge?.id) === target) || null;
}
function getEdgeWalls(edge) {
const explicitWalls = Array.isArray(edge?.walls)
? edge.walls.map((wallId) => normalizeId(wallId)).filter(Boolean)
: [];
if (explicitWalls.length >= 2) {
return explicitWalls.slice(0, 2);
}
return normalizeEdgeId(edge?.id)
.split("-")
.map((wallId) => normalizeId(wallId))
.filter(Boolean)
.slice(0, 2);
}
function getEdgesForWall(wallOrWallId) {
const wallId = normalizeId(typeof wallOrWallId === "string" ? wallOrWallId : wallOrWallId?.id);
return getEdges().filter((edge) => getEdgeWalls(edge).includes(wallId));
}
function toFiniteNumber(value) {
const numeric = Number(value);
return Number.isFinite(numeric) ? numeric : null;
}
2026-03-07 13:38:13 -08:00
if (typeof cubeMathHelpers.createCubeMathHelpers !== "function") {
throw new Error("CubeMathHelpers.createCubeMathHelpers is unavailable. Ensure app/ui-cube-math.js loads before app/ui-cube.js.");
}
2026-03-07 01:09:00 -08:00
function normalizeAngle(angle) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.normalizeAngle(angle);
2026-03-07 01:09:00 -08:00
}
function setRotation(nextX, nextY) {
2026-03-07 13:38:13 -08:00
cubeMathUi.setRotation(nextX, nextY);
2026-03-07 01:09:00 -08:00
}
function snapRotationToWall(wallId) {
2026-03-07 13:38:13 -08:00
cubeMathUi.snapRotationToWall(wallId);
2026-03-07 01:09:00 -08:00
}
function facePoint(quad, u, v) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.facePoint(quad, u, v);
2026-03-07 01:09:00 -08:00
}
function projectVerticesForRotation(rotationX, rotationY) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.projectVerticesForRotation(rotationX, rotationY);
2026-03-07 01:09:00 -08:00
}
function projectVertices() {
2026-03-07 13:38:13 -08:00
return cubeMathUi.projectVertices();
2026-03-07 01:09:00 -08:00
}
function getEdgeGeometryById(edgeId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeGeometryById(edgeId);
2026-03-07 01:09:00 -08:00
}
function getWallEdgeDirections(wallOrWallId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getWallEdgeDirections(wallOrWallId);
2026-03-07 01:09:00 -08:00
}
function getEdgeDirectionForWall(wallId, edgeId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeDirectionForWall(wallId, edgeId);
2026-03-07 01:09:00 -08:00
}
function getEdgeDirectionLabelForWall(wallId, edgeId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeDirectionLabelForWall(wallId, edgeId);
2026-03-07 01:09:00 -08:00
}
function bindRotationControls(elements) {
if (state.controlsBound) {
return;
}
const rotateAndRender = (deltaX, deltaY) => {
setRotation(state.rotationX + deltaX, state.rotationY + deltaY);
render(getElements());
};
elements.rotateLeftEl?.addEventListener("click", () => rotateAndRender(0, -9));
elements.rotateRightEl?.addEventListener("click", () => rotateAndRender(0, 9));
elements.rotateUpEl?.addEventListener("click", () => rotateAndRender(-9, 0));
elements.rotateDownEl?.addEventListener("click", () => rotateAndRender(9, 0));
elements.rotateResetEl?.addEventListener("click", () => {
setRotation(18, -28);
render(getElements());
});
elements.markerModeEl?.addEventListener("change", (event) => {
const nextMode = normalizeId(event?.target?.value);
state.markerDisplayMode = ["both", "letter", "astro", "tarot"].includes(nextMode)
? nextMode
: "both";
render(getElements());
});
if (elements.connectorToggleEl) {
elements.connectorToggleEl.checked = state.showConnectorLines;
elements.connectorToggleEl.addEventListener("change", () => {
state.showConnectorLines = Boolean(elements.connectorToggleEl.checked);
if (!state.showConnectorLines && state.selectedNodeType === "connector") {
state.selectedNodeType = "wall";
state.selectedConnectorId = null;
}
render(getElements());
});
}
if (elements.primalToggleEl) {
elements.primalToggleEl.checked = state.showPrimalPoint;
elements.primalToggleEl.addEventListener("change", () => {
state.showPrimalPoint = Boolean(elements.primalToggleEl.checked);
if (!state.showPrimalPoint && state.selectedNodeType === "center") {
state.selectedNodeType = "wall";
}
render(getElements());
});
}
state.controlsBound = true;
}
function getHebrewLetterSymbol(hebrewLetterId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getHebrewLetterSymbol(hebrewLetterId);
2026-03-07 01:09:00 -08:00
}
function getHebrewLetterName(hebrewLetterId) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getHebrewLetterName(hebrewLetterId);
2026-03-07 01:09:00 -08:00
}
function getAstrologySymbol(type, name) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getAstrologySymbol(type, name);
2026-03-07 01:09:00 -08:00
}
function getEdgeLetterId(edge) {
return normalizeLetterKey(edge?.hebrewLetterId || edge?.associations?.hebrewLetterId);
}
function getWallFaceLetterId(wall) {
return normalizeLetterKey(wall?.hebrewLetterId || wall?.associations?.hebrewLetterId);
}
function getWallFaceLetter(wall) {
const hebrewLetterId = getWallFaceLetterId(wall);
if (!hebrewLetterId) {
return "";
}
return getHebrewLetterSymbol(hebrewLetterId);
}
function getCubeCenterData() {
const center = state.cube?.center;
return center && typeof center === "object" ? center : null;
}
function getCenterLetterId(center = null) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getCenterLetterId(center);
2026-03-07 01:09:00 -08:00
}
function getCenterLetterSymbol(center = null) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getCenterLetterSymbol(center);
2026-03-07 01:09:00 -08:00
}
function getConnectorById(connectorId) {
const target = normalizeId(connectorId);
return MOTHER_CONNECTORS.find((entry) => normalizeId(entry?.id) === target) || null;
}
function getConnectorPathEntry(connector) {
const letterId = normalizeLetterKey(connector?.hebrewLetterId);
if (!letterId) {
return null;
}
return state.kabbalahPathsByLetterId.get(letterId) || null;
}
function getEdgePathEntry(edge) {
const hebrewLetterId = getEdgeLetterId(edge);
if (!hebrewLetterId) {
return null;
}
return state.kabbalahPathsByLetterId.get(hebrewLetterId) || null;
}
2026-03-07 13:38:13 -08:00
const cubeMathUi = cubeMathHelpers.createCubeMathHelpers({
state,
CUBE_VERTICES,
FACE_GEOMETRY,
EDGE_GEOMETRY,
EDGE_GEOMETRY_KEYS,
CUBE_VIEW_CENTER,
WALL_FRONT_ROTATIONS,
LOCAL_DIRECTION_VIEW_MAP,
normalizeId,
normalizeLetterKey,
normalizeEdgeId,
formatDirectionName,
getEdgesForWall,
getEdgePathEntry,
getEdgeLetterId,
getCubeCenterData
});
2026-03-07 01:09:00 -08:00
function getEdgeAstrologySymbol(edge) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeAstrologySymbol(edge);
2026-03-07 01:09:00 -08:00
}
function getEdgeMarkerDisplay(edge) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeMarkerDisplay(edge);
2026-03-07 01:09:00 -08:00
}
function getEdgeLetter(edge) {
2026-03-07 13:38:13 -08:00
return cubeMathUi.getEdgeLetter(edge);
2026-03-07 01:09:00 -08:00
}
function getWallTarotCard(wall) {
return toDisplayText(wall?.associations?.tarotCard || wall?.tarotCard);
}
function getEdgeTarotCard(edge) {
const pathEntry = getEdgePathEntry(edge);
return toDisplayText(pathEntry?.tarot?.card);
}
function getConnectorTarotCard(connector) {
const pathEntry = getConnectorPathEntry(connector);
return toDisplayText(pathEntry?.tarot?.card);
}
function getCenterTarotCard(center = null) {
const entry = center || getCubeCenterData();
return toDisplayText(entry?.associations?.tarotCard || entry?.tarotCard);
}
function resolveCardImageUrl(cardName) {
const name = toDisplayText(cardName);
if (!name || typeof window.TarotCardImages?.resolveTarotCardImage !== "function") {
return null;
}
return window.TarotCardImages.resolveTarotCardImage(name) || null;
}
2026-03-07 05:17:50 -08:00
function openTarotCardLightbox(cardName, fallbackSrc = "", fallbackLabel = "") {
const openLightbox = window.TarotUiLightbox?.open;
if (typeof openLightbox !== "function") {
return false;
}
const src = toDisplayText(fallbackSrc) || resolveCardImageUrl(cardName);
if (!src) {
return false;
}
const label = toDisplayText(cardName) || toDisplayText(fallbackLabel) || "Tarot card";
openLightbox(src, label);
return true;
}
2026-03-07 01:09:00 -08:00
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 toDisplayText(value) {
return String(value ?? "").trim();
}
function renderFaceSvg(containerEl, walls) {
2026-03-07 13:38:13 -08:00
if (typeof cubeChassisUi.renderFaceSvg !== "function") {
if (containerEl) {
containerEl.replaceChildren();
}
2026-03-07 01:09:00 -08:00
return;
}
2026-03-07 13:38:13 -08:00
cubeChassisUi.renderFaceSvg({
state,
containerEl,
walls,
normalizeId,
projectVertices,
FACE_GEOMETRY,
facePoint,
normalizeEdgeId,
getEdges,
getEdgesForWall,
EDGE_GEOMETRY,
EDGE_GEOMETRY_KEYS,
formatEdgeName,
getEdgeWalls,
getElements,
render,
snapRotationToWall,
getWallFaceLetter,
getWallTarotCard,
resolveCardImageUrl,
openTarotCardLightbox,
MOTHER_CONNECTORS,
formatDirectionName,
getConnectorTarotCard,
getHebrewLetterSymbol,
toDisplayText,
CUBE_VIEW_CENTER,
getEdgeMarkerDisplay,
getEdgeTarotCard,
getCubeCenterData,
getCenterTarotCard,
getCenterLetterSymbol
2026-03-07 01:09:00 -08:00
});
}
2026-03-07 05:17:50 -08:00
function selectEdgeById(edgeId, preferredWallId = "") {
const edge = getEdgeById(edgeId);
if (!edge) {
2026-03-07 01:09:00 -08:00
return false;
}
2026-03-07 05:17:50 -08:00
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));
2026-03-07 01:09:00 -08:00
2026-03-07 05:17:50 -08:00
state.selectedEdgeId = normalizeEdgeId(edge.id);
state.selectedNodeType = "wall";
state.selectedConnectorId = null;
2026-03-07 01:09:00 -08:00
2026-03-07 05:17:50 -08:00
if (nextWallId) {
if (nextWallId !== currentWallId) {
state.selectedWallId = nextWallId;
snapRotationToWall(nextWallId);
} else if (!state.selectedWallId) {
state.selectedWallId = nextWallId;
}
2026-03-07 01:09:00 -08:00
}
2026-03-07 05:17:50 -08:00
render(getElements());
2026-03-07 01:09:00 -08:00
return true;
}
function renderDetail(elements, walls) {
2026-03-07 05:17:50 -08:00
if (typeof cubeDetailUi.renderDetail !== "function") {
2026-03-07 01:09:00 -08:00
if (elements?.detailNameEl) {
elements.detailNameEl.textContent = "Cube data unavailable";
}
if (elements?.detailSubEl) {
2026-03-07 05:17:50 -08:00
elements.detailSubEl.textContent = "Cube detail renderer missing.";
2026-03-07 01:09:00 -08:00
}
if (elements?.detailBodyEl) {
elements.detailBodyEl.innerHTML = "";
}
return;
}
2026-03-07 05:17:50 -08:00
cubeDetailUi.renderDetail({
state,
elements,
walls,
normalizeId,
normalizeEdgeId,
normalizeLetterKey,
formatDirectionName,
formatEdgeName,
toFiniteNumber,
getWallById,
getEdgeById,
getEdges,
getEdgeWalls,
getEdgesForWall,
getWallEdgeDirections,
getConnectorById,
getConnectorPathEntry,
getCubeCenterData,
getCenterLetterId,
getCenterLetterSymbol,
getEdgeLetterId,
getEdgeLetter,
getEdgePathEntry,
getEdgeAstrologySymbol,
getWallFaceLetterId,
getWallFaceLetter,
getHebrewLetterName,
getHebrewLetterSymbol,
localDirectionOrder: LOCAL_DIRECTION_ORDER,
localDirectionRank: LOCAL_DIRECTION_RANK,
onSelectWall: selectWallById,
onSelectEdge: selectEdgeById
2026-03-07 01:09:00 -08:00
});
}
function render(elements) {
if (elements?.markerModeEl) {
elements.markerModeEl.value = state.markerDisplayMode;
}
if (elements?.connectorToggleEl) {
elements.connectorToggleEl.checked = state.showConnectorLines;
}
if (elements?.primalToggleEl) {
elements.primalToggleEl.checked = state.showPrimalPoint;
}
if (elements?.rotationReadoutEl) {
elements.rotationReadoutEl.textContent = `X ${Math.round(state.rotationX)}° · Y ${Math.round(state.rotationY)}°`;
}
const walls = getWalls();
renderFaceSvg(elements.viewContainerEl, walls);
renderDetail(elements, walls);
}
function ensureCubeSection(magickDataset) {
const cubeData = magickDataset?.grouped?.kabbalah?.cube;
const elements = getElements();
state.cube = cubeData || null;
state.hebrewLetters =
asRecord(magickDataset?.grouped?.hebrewLetters)
|| asRecord(magickDataset?.grouped?.alphabets?.hebrew)
|| null;
const pathList = Array.isArray(magickDataset?.grouped?.kabbalah?.["kabbalah-tree"]?.paths)
? magickDataset.grouped.kabbalah["kabbalah-tree"].paths
: [];
const letterEntries = state.hebrewLetters && typeof state.hebrewLetters === "object"
? Object.values(state.hebrewLetters)
: [];
const letterIdsByChar = new Map(
letterEntries
.map((letterEntry) => [String(letterEntry?.letter?.he || "").trim(), normalizeLetterKey(letterEntry?.id)])
.filter(([character, letterId]) => Boolean(character) && Boolean(letterId))
);
state.kabbalahPathsByLetterId = new Map(
pathList
.map((pathEntry) => {
const transliterationId = normalizeLetterKey(pathEntry?.hebrewLetter?.transliteration);
const char = String(pathEntry?.hebrewLetter?.char || "").trim();
const charId = letterIdsByChar.get(char) || "";
return [charId || transliterationId, pathEntry];
})
.filter(([letterId]) => Boolean(letterId))
);
if (!state.selectedWallId) {
state.selectedWallId = normalizeId(getWalls()[0]?.id);
}
const initialEdge = getEdgesForWall(state.selectedWallId)[0] || getEdges()[0] || null;
if (!state.selectedEdgeId || !getEdgeById(state.selectedEdgeId)) {
state.selectedEdgeId = normalizeEdgeId(initialEdge?.id);
}
bindRotationControls(elements);
render(elements);
state.initialized = 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 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) {
return selectPlacement({ hebrewLetterId });
}
function selectBySignId(signId) {
return selectPlacement({ signId });
}
function selectByPlanetId(planetId) {
return selectPlacement({ planetId });
}
function selectByPathNo(pathNo) {
return selectPlacement({ pathNo });
}
window.CubeSectionUi = {
ensureCubeSection,
selectWallById,
selectPlacement,
selectByHebrewLetterId,
selectBySignId,
selectByPlanetId,
selectByPathNo,
getEdgeDirectionForWall,
getEdgeDirectionLabelForWall
};
})();