(function () { function parseInitialState(rawState) { if (!rawState || typeof rawState !== 'object') { return { revealed_stages: [], revealed_cells: [], reveal_log: [] }; } return { revealed_stages: Array.isArray(rawState.revealed_stages) ? rawState.revealed_stages : [], revealed_cells: Array.isArray(rawState.revealed_cells) ? rawState.revealed_cells : [], reveal_log: Array.isArray(rawState.reveal_log) ? rawState.reveal_log : [], }; } function cellKey(candidate, stage) { return `${candidate}:${stage}`; } function uniqueStagesFromCells(cells) { const stages = []; ['resume', 'zoom', 'inperson'].forEach(stage => { if (cells.some(key => key.endsWith(`:${stage}`))) { stages.push(stage); } }); return stages; } function normalizeExistingEvent(entry, fallbackIndex, config) { const candidate = entry && entry.candidate ? String(entry.candidate) : ''; const stage = entry && entry.stage ? String(entry.stage) : ''; const key = entry && entry.cell_key ? String(entry.cell_key) : (candidate && stage ? cellKey(candidate, stage) : ''); return { event_index: Number.isInteger(entry && entry.event_index) ? entry.event_index : fallbackIndex, round_number: entry && entry.round_number !== undefined ? entry.round_number : config.roundNumber, display_round: entry && entry.display_round !== undefined ? entry.display_round : config.displayRound, condition: entry && entry.condition ? entry.condition : config.condition, gate: entry && entry.gate ? entry.gate : config.gate, candidate: candidate, stage: stage, cell_key: key, event_type: entry && entry.event_type ? entry.event_type : 'reveal', client_timestamp_ms: entry && entry.client_timestamp_ms !== undefined ? entry.client_timestamp_ms : null, elapsed_ms_on_page: entry && entry.elapsed_ms_on_page !== undefined ? entry.elapsed_ms_on_page : (entry && entry.t_ms !== undefined ? entry.t_ms : null), was_already_revealed: Boolean(entry && entry.was_already_revealed), is_first_reveal_for_cell: entry && entry.is_first_reveal_for_cell !== undefined ? Boolean(entry.is_first_reveal_for_cell) : true, }; } window.initRevealLogging = function initRevealLogging(config) { const initialState = parseInitialState(config.initialState); const allowedStages = config.allowedStages || ['resume', 'zoom', 'inperson']; const revealedCells = new Set(initialState.revealed_cells || []); const pageLoadTime = Date.now(); const hiddenInputs = (config.hiddenInputIds || []) .map(id => document.getElementById(id)) .filter(Boolean); // reveal_log is the ordered event log. revealed_cells/revealed_stages are // final state summaries derived from first reveal events. const revealLog = []; const seenEventCells = new Set(); (initialState.reveal_log || []).forEach((entry) => { const normalized = normalizeExistingEvent(entry, revealLog.length + 1, config); if (!normalized.candidate || !normalized.stage || !normalized.cell_key) return; if (allowedStages.indexOf(normalized.stage) === -1) return; if (seenEventCells.has(normalized.cell_key)) return; normalized.event_index = revealLog.length + 1; normalized.was_already_revealed = false; normalized.is_first_reveal_for_cell = true; revealLog.push(normalized); seenEventCells.add(normalized.cell_key); revealedCells.add(normalized.cell_key); }); function currentCells() { return Array.from(revealedCells); } function payload() { const cells = currentCells(); return { revealed_stages: uniqueStagesFromCells(cells), revealed_cells: cells, reveal_log: revealLog, }; } function updateRevealLog() { const serialized = JSON.stringify(payload()); hiddenInputs.forEach(input => { input.value = serialized; }); (config.stageInputIds || []).forEach(id => { const input = document.getElementById(id); if (input) input.value = JSON.stringify(payload().revealed_stages); }); } function applyRevealState() { document.querySelectorAll(config.cellSelector || '.score-cell[data-candidate][data-stage]').forEach(cell => { const key = cellKey(cell.dataset.candidate, cell.dataset.stage); const visible = revealedCells.has(key); const content = cell.querySelector('.score-bar-track'); const placeholder = cell.querySelector('.score-placeholder'); if (content) content.style.display = visible ? 'flex' : 'none'; if (placeholder) placeholder.style.display = visible ? 'none' : 'flex'; cell.classList.toggle('score-hidden', !visible); cell.classList.toggle('score-revealed', visible); }); } function revealCell(cell) { const candidate = cell.dataset.candidate; const stage = cell.dataset.stage; const key = cellKey(candidate, stage); const alreadyRevealed = revealedCells.has(key); if (alreadyRevealed || allowedStages.indexOf(stage) === -1) { return; } revealedCells.add(key); revealLog.push({ event_index: revealLog.length + 1, round_number: config.roundNumber, display_round: config.displayRound, condition: config.condition, gate: config.gate, candidate: candidate, stage: stage, cell_key: key, event_type: 'reveal', client_timestamp_ms: Date.now(), elapsed_ms_on_page: Date.now() - pageLoadTime, was_already_revealed: alreadyRevealed, is_first_reveal_for_cell: true, }); applyRevealState(); updateRevealLog(); } document.querySelectorAll(config.cellSelector || '.score-cell[data-candidate][data-stage]').forEach(cell => { cell.addEventListener('click', function () { revealCell(cell); }); }); applyRevealState(); updateRevealLog(); return { revealCell: revealCell, updateRevealLog: updateRevealLog, payload: payload, }; }; })();