Custom sessions now draw their own bead ring matching the builder sequence

present.php extracts the ordered bead types (small/large/crucifix) from
custom session slides and passes them as CUSTOM_BEADS to the JS layer.

rosary.js reads CUSTOM_BEADS on init: if present, it draws exactly those
N beads (with their correct types) instead of the standard 60-bead ring.
The three hardcoded 60s and the fixed type Sets are now dynamic so any
sequence length works. Standard sessions are unchanged (CUSTOM_BEADS=null).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-13 21:34:24 -07:00
parent 3cc002a6da
commit 76a5061fba
2 changed files with 44 additions and 9 deletions
+30 -9
View File
@@ -42,15 +42,36 @@ var RosaryRing = (function () {
var COLOR_PRAYED = '#990000';
var svg = null;
var beadEls = []; // SVG <circle> elements, indexed 0-59
var beadEls = []; // SVG elements, one per bead
var polyline = null;
var beadPositions = []; // [{x, y}] for each bead
var _beadClickHandler = null; // registered by presenter.js
// Which bead indices are "large" (Our Father) beads
// Bead configuration — set by configure(), either from CUSTOM_BEADS or standard rosary
var TOTAL_BEADS = 60;
var LARGE_BEADS = new Set([1, 5, 16, 27, 38, 49]);
var CRUCIFIX_BEADS = new Set([0]);
// Read window.CUSTOM_BEADS (set by present.php for builder sessions).
// CUSTOM_BEADS is an ordered array of bead types, e.g. ['crucifix','large','small',...].
// If null/absent, fall back to the standard 60-bead rosary layout.
function configure() {
var cb = window.CUSTOM_BEADS;
if (cb && cb.length) {
TOTAL_BEADS = cb.length;
LARGE_BEADS = new Set();
CRUCIFIX_BEADS = new Set();
cb.forEach(function (type, i) {
if (type === 'large') LARGE_BEADS.add(i);
if (type === 'crucifix') CRUCIFIX_BEADS.add(i);
});
} else {
TOTAL_BEADS = 60;
LARGE_BEADS = new Set([1, 5, 16, 27, 38, 49]);
CRUCIFIX_BEADS = new Set([0]);
}
}
// --------------------------------------------------------------------------
// Calculate bead positions around the viewport edges
// --------------------------------------------------------------------------
@@ -74,9 +95,9 @@ var RosaryRing = (function () {
var positions = [];
for (var i = 0; i < 60; i++) {
for (var i = 0; i < TOTAL_BEADS; i++) {
// Fraction of the perimeter for this bead (clockwise from bottom-center)
var frac = i / 60;
var frac = i / TOTAL_BEADS;
var dist = frac * perimeter;
var pt = pointOnRect(dist, startX, startY, m, W, H, innerW, innerH, perimeter);
@@ -193,7 +214,7 @@ var RosaryRing = (function () {
// Draw beads
beadEls = [];
for (var i = 0; i < 60; i++) {
for (var i = 0; i < TOTAL_BEADS; i++) {
var pos = beadPositions[i];
var isCrucifix = CRUCIFIX_BEADS.has(i);
var isLarge = LARGE_BEADS.has(i);
@@ -281,10 +302,9 @@ var RosaryRing = (function () {
var last = (lastPrayedBeadIndex !== null && lastPrayedBeadIndex !== undefined)
? lastPrayedBeadIndex : -1;
// Once the final bead of decade 5 (index 59) has been prayed and there is
// no active bead, the cross turns gold and stays gold for the rest of the
// presentation (litanies, novena prayer, closing slide).
var allDecadesDone = (last >= 59) &&
// Once the final bead has been prayed and there is no active bead,
// the last element turns gold and stays gold for the rest of the presentation.
var allDecadesDone = (last >= TOTAL_BEADS - 1) &&
(currentBeadIndex === null || currentBeadIndex === undefined);
beadEls.forEach(function (el, i) {
@@ -342,6 +362,7 @@ var RosaryRing = (function () {
// Initialize
// --------------------------------------------------------------------------
function init() {
configure();
build();
window.addEventListener('resize', function () {
build();