/* * red-letter.js — Words of Christ (red-letter) support. Isolated + additive. * * Loads the bundled verse-level dataset (red-letter.json, derived from the public-domain World * English Bible \wj markers), merges any user reference overrides, and toggles visibility via a * body class (body.red-letter-on) so on/off is instant with no re-render. The actual per-word * marking lives in app.js (window.applyRedLetterMarks), which this module re-invokes once the data * has loaded. Exposed on window.redLetter for the Settings page and (Phase 3) OSC. */ (function () { 'use strict'; var ENABLED_KEY = 'redLetterEnabled'; // 'true' | 'false' (default off) var OVERRIDES_KEY = 'redLetterOverrides'; // free text, one reference per line var BOOKS = ['Genesis','Exodus','Leviticus','Numbers','Deuteronomy','Joshua','Judges','Ruth', '1 Samuel','2 Samuel','1 Kings','2 Kings','1 Chronicles','2 Chronicles','Ezra','Nehemiah','Esther', 'Job','Psalms','Proverbs','Ecclesiastes','Song of Solomon','Isaiah','Jeremiah','Lamentations', 'Ezekiel','Daniel','Hosea','Joel','Amos','Obadiah','Jonah','Micah','Nahum','Habakkuk','Zephaniah', 'Haggai','Zechariah','Malachi','Matthew','Mark','Luke','John','Acts','Romans','1 Corinthians', '2 Corinthians','Galatians','Ephesians','Philippians','Colossians','1 Thessalonians','2 Thessalonians', '1 Timothy','2 Timothy','Titus','Philemon','Hebrews','James','1 Peter','2 Peter','1 John','2 John', '3 John','Jude','Revelation']; function isEnabled() { try { return localStorage.getItem(ENABLED_KEY) === 'true'; } catch (_) { return false; } } function applyBodyClass() { try { document.body.classList.toggle('red-letter-on', isEnabled()); } catch (_) {} } function normalizeBook(name) { var n = String(name || '').trim().toLowerCase(); for (var i = 0; i < BOOKS.length; i++) if (BOOKS[i].toLowerCase() === n) return BOOKS[i]; // loose match (e.g. "song of songs", "psalm") if (n === 'song of songs') return 'Song of Solomon'; if (n === 'psalm') return 'Psalms'; return null; } // Merge user overrides ("John 3:16", "Matthew 5:3-12", one per line) into the dataset. function mergeOverrides(data) { var raw = ''; try { raw = localStorage.getItem(OVERRIDES_KEY) || ''; } catch (_) {} if (!raw.trim()) return; raw.split(/\r?\n/).forEach(function (line) { line = line.trim(); if (!line) return; var m = line.match(/^(.+?)\s+(\d+):(\d+)(?:\s*-\s*(\d+))?$/); if (!m) return; var book = normalizeBook(m[1]); if (!book) return; var chapter = m[2], vStart = parseInt(m[3], 10), vEnd = m[4] ? parseInt(m[4], 10) : vStart; if (!data[book]) data[book] = {}; if (!Array.isArray(data[book][chapter])) data[book][chapter] = []; for (var v = vStart; v <= vEnd; v++) if (data[book][chapter].indexOf(v) === -1) data[book][chapter].push(v); }); } function reapply() { try { var app = window.bibleApp; if (app && app.activeTabId != null && typeof window.applyRedLetterMarks === 'function') { window.applyRedLetterMarks(app.activeTabId); } } catch (_) {} } function load() { fetch('/red-letter.json', { cache: 'no-store' }) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (data) { if (!data || typeof data !== 'object') return; try { mergeOverrides(data); } catch (_) {} window.__redLetterData = data; reapply(); // mark any already-rendered chapter now that data exists }) .catch(function () { /* offline-safe: red-letter simply stays inactive */ }); } // Public API (Settings + OSC) window.redLetter = { isEnabled: isEnabled, setEnabled: function (on) { try { localStorage.setItem(ENABLED_KEY, on ? 'true' : 'false'); } catch (_) {} applyBodyClass(); }, toggle: function () { window.redLetter.setEnabled(!isEnabled()); return isEnabled(); }, // Re-read overrides + re-merge + re-mark (called after Settings saves references live, if ever) reloadData: function () { load(); } }; function init() { applyBodyClass(); load(); } if (document.readyState !== 'loading') init(); else document.addEventListener('DOMContentLoaded', init); })();