Add bead separator support to Rosary Builder
- Bead Markers section in library panel with Small, Large, Crucifix cards - Bead steps render as amber-tinted cards in the sequence (no attribution) - migrate_v5.php: adds step_type/bead_type columns, makes prayer_id nullable - Bead steps produce slides with proper bead+bead_index so the ring advances during presentation — allows participants to follow along on physical beads - Prayer steps between beads still show bead_index=null (ring stays on last bead) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+46
-10
@@ -23,8 +23,12 @@
|
||||
// Populate existing steps when editing a session
|
||||
if (window.EXISTING_STEPS && window.EXISTING_STEPS.length) {
|
||||
window.EXISTING_STEPS.forEach(function (s) {
|
||||
const prayer = PRAYERS.find(p => String(p.id) === String(s.prayer_id));
|
||||
if (prayer) STEPS.push({ prayer_id: s.prayer_id, attribution: s.attribution, _prayer: prayer });
|
||||
if (s.step_type === 'bead') {
|
||||
STEPS.push({ step_type: 'bead', bead_type: s.bead_type });
|
||||
} else {
|
||||
const prayer = PRAYERS.find(p => String(p.id) === String(s.prayer_id));
|
||||
if (prayer) STEPS.push({ step_type: 'prayer', prayer_id: s.prayer_id, attribution: s.attribution, _prayer: prayer });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -146,8 +150,30 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const beadMeta = {
|
||||
small: { icon: '○', label: 'Small Bead', sub: 'Hail Mary bead' },
|
||||
large: { icon: '●', label: 'Large Bead', sub: 'Our Father bead' },
|
||||
crucifix: { icon: '✝', label: 'Crucifix', sub: 'Cross bead' },
|
||||
};
|
||||
|
||||
list.innerHTML = STEPS.map(function (step, i) {
|
||||
const p = step._prayer;
|
||||
const moveUp = `<button class="btn-icon" title="Move up" onclick="builderMove(${i},-1)" ${i===0?'disabled':''}>↑</button>`;
|
||||
const moveDn = `<button class="btn-icon" title="Move down" onclick="builderMove(${i}, 1)" ${i===STEPS.length-1?'disabled':''}>↓</button>`;
|
||||
const remove = `<button class="btn-icon remove" title="Remove" onclick="builderRemove(${i})">✕</button>`;
|
||||
|
||||
if (step.step_type === 'bead') {
|
||||
const m = beadMeta[step.bead_type] || beadMeta.small;
|
||||
return `<div class="step-card bead-step">
|
||||
<div class="step-num">${i + 1}</div>
|
||||
<div class="step-body">
|
||||
<div class="bead-step-name">${m.icon} ${m.label}</div>
|
||||
<div class="bead-step-sub">${m.sub}</div>
|
||||
</div>
|
||||
<div class="step-actions">${moveUp}${moveDn}${remove}</div>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
const p = step._prayer;
|
||||
const leaderPrev = (p.leader_text || '').replace(/\n/g, ' ').substring(0, 60);
|
||||
const allPrev = (p.all_text || '').replace(/\n/g, ' ').substring(0, 60);
|
||||
|
||||
@@ -164,11 +190,7 @@
|
||||
<option value="none" ${step.attribution==='none' ? 'selected':''}>No attribution</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="step-actions">
|
||||
<button class="btn-icon" title="Move up" onclick="builderMove(${i}, -1)" ${i===0 ? 'disabled' : ''}>↑</button>
|
||||
<button class="btn-icon" title="Move down" onclick="builderMove(${i}, 1)" ${i===STEPS.length-1 ? 'disabled' : ''}>↓</button>
|
||||
<button class="btn-icon remove" title="Remove" onclick="builderRemove(${i})">✕</button>
|
||||
</div>
|
||||
<div class="step-actions">${moveUp}${moveDn}${remove}</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
}
|
||||
@@ -176,6 +198,18 @@
|
||||
/* ─────────────────────────────────────────────────────────
|
||||
Step manipulation (exposed globally)
|
||||
───────────────────────────────────────────────────────── */
|
||||
window.builderAddBead = function (beadType) {
|
||||
STEPS.push({ step_type: 'bead', bead_type: beadType });
|
||||
renderSequence();
|
||||
const cards = document.querySelectorAll('#step-list .step-card');
|
||||
const last = cards[cards.length - 1];
|
||||
if (last) {
|
||||
last.style.outline = '2px solid #f59e0b';
|
||||
setTimeout(() => { last.style.outline = ''; }, 800);
|
||||
last.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
||||
}
|
||||
};
|
||||
|
||||
window.builderAddPrayer = function (prayerId) {
|
||||
const prayer = PRAYERS.find(p => String(p.id) === String(prayerId));
|
||||
if (!prayer) return;
|
||||
@@ -186,7 +220,7 @@
|
||||
else if (!prayer.all_text) attr = 'leader_only';
|
||||
else if (!prayer.leader_text) attr = 'all_only';
|
||||
|
||||
STEPS.push({ prayer_id: prayerId, attribution: attr, _prayer: prayer });
|
||||
STEPS.push({ step_type: 'prayer', prayer_id: prayerId, attribution: attr, _prayer: prayer });
|
||||
renderSequence();
|
||||
// Briefly highlight the new step
|
||||
const list = document.getElementById('step-list');
|
||||
@@ -381,7 +415,9 @@
|
||||
subject_name: document.getElementById('subject-name').value.trim(),
|
||||
subject_pronoun: document.getElementById('subject-pronoun').value,
|
||||
subject_dates: document.getElementById('subject-dates').value.trim(),
|
||||
steps: STEPS.map(s => ({ prayer_id: s.prayer_id, attribution: s.attribution })),
|
||||
steps: STEPS.map(s => s.step_type === 'bead'
|
||||
? { step_type: 'bead', bead_type: s.bead_type }
|
||||
: { step_type: 'prayer', prayer_id: s.prayer_id, attribution: s.attribution }),
|
||||
};
|
||||
|
||||
const btn = document.getElementById('btn-save');
|
||||
|
||||
Reference in New Issue
Block a user