PageSourceSearch

https://surewordbible.com/js/sync/sync-store.js?v=P48fxhPJ_baT9pptBl7pCRYZzl5Rt3GTjD-h5xZ12aw

js surewordbible.com collected 2026-10-02 01:45:08 UTC 11,532 bytes, 305 lines download raw bytes

1(function () {
2    'use strict';
3
4    var DB_NAME = 'surewordbible_sync';
5    var DB_VERSION = 1;
6    var dbPromise = null;
7
8    function openDb() {
9        if (dbPromise) return dbPromise;
10        dbPromise = new Promise(function (resolve, reject) {
11            var request = indexedDB.open(DB_NAME, DB_VERSION);
12            request.onupgradeneeded = function (event) {
13                var db = event.target.result;
14                if (!db.objectStoreNames.contains('meta')) {
15                    db.createObjectStore('meta', { keyPath: 'key' });
16                }
17                ['favourites', 'highlights', 'verseNotes', 'linkedVerses'].forEach(function (store) {
18                    if (!db.objectStoreNames.contains(store)) {
19                        db.createObjectStore(store, { keyPath: 'bibleId' });
20                    }
21                });
22            };
23            request.onsuccess = function () { resolve(request.result); };
24            request.onerror = function () { reject(request.error); };
25        });
26        return dbPromise;
27    }
28
29    function txStore(storeName, mode) {
30        return openDb().then(function (db) {
31            return db.transaction(storeName, mode).objectStore(storeName);
32        });
33    }
34
35    function putAll(storeName, rows) {
36        return openDb().then(function (db) {
37            return new Promise(function (resolve, reject) {
38                var tx = db.transaction(storeName, 'readwrite');
39                var store = tx.objectStore(storeName);
40                rows.forEach(function (row) { store.put(row); });
41                tx.oncomplete = function () { resolve(); };
42                tx.onerror = function () { reject(tx.error); };
43            });
44        });
45    }
46
47    window.SwbSyncStore = {
48        normalizeHighlightColor: normalizeHighlightColor,
49
50        getMeta: function () {
51            return txStore('meta', 'readonly').then(function (store) {
52                return new Promise(function (resolve) {
53                    var req = store.get('sync');
54                    req.onsuccess = function () {
55                        resolve(req.result || { key: 'sync', revision: 0, userId: null });
56                    };
57                });
58            });
59        },
60        setMeta: function (meta) {
61            return txStore('meta', 'readwrite').then(function (store) {
62                meta.key = 'sync';
63                store.put(meta);
64            });
65        },
66        getAll: function (storeName) {
67            return txStore(storeName, 'readonly').then(function (store) {
68                return new Promise(function (resolve) {
69                    var req = store.getAll();
70                    req.onsuccess = function () { resolve(req.result || []); };
71                });
72            });
73        },
74        putRow: function (storeName, row) {
75            return txStore(storeName, 'readwrite').then(function (store) {
76                store.put(row);
77            });
78        },
79        applyPullPayload: function (payload) {
80            var tasks = [];
81            if (payload.favourites) {
82                tasks.push(putAll('favourites', payload.favourites.filter(function (r) { return !r.isDeleted; }).map(toFavouriteRow)));
83            }
84            if (payload.highlights) {
85                tasks.push(putAll('highlights', payload.highlights.filter(function (r) { return !r.isDeleted; }).map(toHighlightRow)));
86            }
87            if (payload.verseNotes) {
88                tasks.push(putAll('verseNotes', payload.verseNotes.filter(function (r) { return !r.isDeleted; }).map(toVerseNoteRow)));
89            }
90            if (payload.linkedVerses) {
91                tasks.push(putAll('linkedVerses', payload.linkedVerses.filter(function (r) { return !r.isDeleted; }).map(toLinkedVerseRow)));
92            }
93            return Promise.all(tasks).then(function () {
94                return window.SwbSyncStore.setMeta({ revision: payload.revision || 0 });
95            });
96        },
97        mergePullPayload: function (payload) {
98            var stores = [
99                ['favourites', payload.favourites, toFavouriteRow],
100                ['highlights', payload.highlights, toHighlightRow],
101                ['verseNotes', payload.verseNotes, toVerseNoteRow],
102                ['linkedVerses', payload.linkedVerses, toLinkedVerseRow]
103            ];
104            return window.SwbSyncStore.getMeta().then(function (meta) {
105                return Promise.all(stores.map(function (entry) {
106                    return mergeStore(entry[0], entry[1] || [], entry[2]);
107                })).then(function () {
108                    var revision = Math.max(meta.revision || 0, payload.revision || 0);
109                    return window.SwbSyncStore.setMeta({ revision: revision, userId: meta.userId });
110                });
111            });
112        },
113        getChapterOverlay: function (book, chapter) {
114            return Promise.all([
115                window.SwbSyncStore.getAll('favourites'),
116                window.SwbSyncStore.getAll('highlights'),
117                window.SwbSyncStore.getAll('verseNotes'),
118                window.SwbSyncStore.getAll('linkedVerses')
119            ]).then(function (results) {
120                return {
121                    favourites: filterChapter(results[0], book, chapter),
122                    highlights: filterChapter(results[1], book, chapter).map(function (row) {
123                        return {
124                            bibleId: row.bibleId,
125                            book: row.book,
126                            chapter: row.chapter,
127                            verse: row.verse,
128                            colorName: normalizeHighlightColor(row.colorName),
129                            isDeleted: row.isDeleted,
130                            updatedAt: row.updatedAt,
131                            revision: row.revision
132                        };
133                    }),
134                    verseNotes: filterChapter(results[2], book, chapter),
135                    linkedVerses: filterChapter(results[3], book, chapter)
136                };
137            });
138        },
139        buildPushPayload: function () {
140            return Promise.all([
141                window.SwbSyncStore.getAll('favourites'),
142                window.SwbSyncStore.getAll('highlights'),
143                window.SwbSyncStore.getAll('verseNotes'),
144                window.SwbSyncStore.getAll('linkedVerses')
145            ]).then(function (results) {
146                return {
147                    favourites: results[0].map(fromFavouriteRow),
148                    highlights: results[1].map(fromHighlightRow),
149                    verseNotes: results[2].map(fromVerseNoteRow),
150                    linkedVerses: results[3].map(fromLinkedVerseRow)
151                };
152            });
153        }
154    };
155
156    function mergeStore(storeName, rows, mapper) {
157        return Promise.all(rows.map(function (row) {
158            if (row.isDeleted) {
159                return txStore(storeName, 'readwrite').then(function (store) {
160                    store.delete(row.bibleId || toBibleId(row.book, row.chapter, row.verse));
161                });
162            }
163            var mapped = mapper(row);
164            return window.SwbSyncStore.putRow(storeName, mapped);
165        }));
166    }
167
168    function filterChapter(rows, book, chapter) {
169        return rows.filter(function (row) {
170            return row.book === book && row.chapter === chapter && !row.isDeleted;
171        });
172    }
173
174    function toBibleId(book, chapter, verse) {
175        return book * 1000000 + chapter * 1000 + verse;
176    }
177
178    function nowMs() { return Date.now(); }
179
180    function toFavouriteRow(dto) {
181        return {
182            bibleId: dto.bibleId || toBibleId(dto.book, dto.chapter, dto.verse),
183            book: dto.book,
184            chapter: dto.chapter,
185            verse: dto.verse,
186            isStarred: dto.isStarred !== false,
187            isDeleted: !!dto.isDeleted,
188            updatedAt: dto.updatedAt || nowMs(),
189            revision: dto.revision || 0
190        };
191    }
192
193    var legacyHighlightColors = {
194        highlightLemon: 'slot_1',
195        highlightPeach: 'slot_2',
196        highlightMint: 'slot_3',
197        highlightLavender: 'slot_4',
198        highlightSky: 'slot_5',
199        highlightOrchid: 'slot_6',
200        highlightCoral: 'slot_7',
201        highlightAmberDeep: 'slot_8'
202    };
203
204    function normalizeHighlightColor(colorName) {
205        if (!colorName || colorName === 'Reset') return 'slot_1';
206        if (legacyHighlightColors[colorName]) return legacyHighlightColors[colorName];
207        if (/^slot_\d+$/.test(colorName)) return colorName;
208        return 'slot_1';
209    }
210
211    function toHighlightRow(dto) {
212        return {
213            bibleId: dto.bibleId || toBibleId(dto.book, dto.chapter, dto.verse),
214            book: dto.book,
215            chapter: dto.chapter,
216            verse: dto.verse,
217            colorName: normalizeHighlightColor(dto.colorName),
218            isDeleted: !!dto.isDeleted,
219            updatedAt: dto.updatedAt || nowMs(),
220            revision: dto.revision || 0
221        };
222    }
223
224    function toVerseNoteRow(dto) {
225        return {
226            bibleId: dto.bibleId || toBibleId(dto.book, dto.chapter, dto.verse),
227            book: dto.book,
228            chapter: dto.chapter,
229            verse: dto.verse,
230            note: dto.note || '',
231            audioPath: dto.audioPath || null,
232            isDeleted: !!dto.isDeleted,
233            updatedAt: dto.updatedAt || nowMs(),
234            revision: dto.revision || 0
235        };
236    }
237
238    function toLinkedVerseRow(dto) {
239        return {
240            bibleId: dto.bibleId || toBibleId(dto.book, dto.chapter, dto.verse),
241            book: dto.book,
242            chapter: dto.chapter,
243            verse: dto.verse,
244            reference: dto.reference || '',
245            systemReference: dto.systemReference || '',
246            isDeleted: !!dto.isDeleted,
247            updatedAt: dto.updatedAt || nowMs(),
248            revision: dto.revision || 0
249        };
250    }
251
252    function fromFavouriteRow(row) {
253        return {
254            bibleId: row.bibleId,
255            book: row.book,
256            chapter: row.chapter,
257            verse: row.verse,
258            isStarred: row.isStarred !== false,
259            isDeleted: !!row.isDeleted,
260            updatedAt: row.updatedAt || nowMs(),
261            revision: row.revision || 0
262        };
263    }
264
265    function fromHighlightRow(row) {
266        return {
267            bibleId: row.bibleId,
268            book: row.book,
269            chapter: row.chapter,
270            verse: row.verse,
271            colorName: row.colorName,
272            isDeleted: !!row.isDeleted,
273            updatedAt: row.updatedAt || nowMs(),
274            revision: row.revision || 0
275        };
276    }
277
278    function fromVerseNoteRow(row) {
279        return {
280            bibleId: row.bibleId,
281            book: row.book,
282            chapter: row.chapter,
283            verse: row.verse,
284            note: row.note,
285            audioPath: row.audioPath,
286            isDeleted: !!row.isDeleted,
287            updatedAt: row.updatedAt || nowMs(),
288            revision: row.revision || 0
289        };
290    }
291
292    function fromLinkedVerseRow(row) {
293        return {
294            bibleId: row.bibleId,
295            book: row.book,
296            chapter: row.chapter,
297            verse: row.verse,
298            reference: row.reference,
299            systemReference: row.systemReference,
300            isDeleted: !!row.isDeleted,
301            updatedAt: row.updatedAt || nowMs(),
302            revision: row.revision || 0
303        };
304    }
305})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.