Skip to content

Commit e4a136d

Browse files
Reif TauatiReif Tauati
authored andcommitted
[task] T-0127: annotate_entity_spans --books job (exit 0)
1 parent 22810a0 commit e4a136d

2 files changed

Lines changed: 72 additions & 22 deletions

File tree

library/index.html

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5062,6 +5062,37 @@
50625062
if (block) { openSourceParaDiscovery(block, para); return; }
50635063
}
50645064

5065+
// Source reader: clickable word → semantic channel (words JSON)
5066+
var wSpanSrc = e.target.closest('span.w[data-st]');
5067+
if (wSpanSrc && !wSpanSrc.closest('div.verse')) {
5068+
var srcBlock = wSpanSrc.closest('.chapter-block[data-source-doc-id]');
5069+
if (srcBlock) {
5070+
closeTocPanel();
5071+
var srcDocId = srcBlock.dataset.sourceDocId;
5072+
var srcParaIdx = String(wSpanSrc.dataset.v || '1');
5073+
var srcStem = wSpanSrc.dataset.st || '';
5074+
var ctxEl = wSpanSrc.closest('p.source-para') || srcBlock;
5075+
activeContextText = ctxEl ? (ctxEl.textContent || '') : '';
5076+
if (channelActiveSpan) {
5077+
channelActiveSpan.classList.remove('cw-active');
5078+
}
5079+
channelActiveSpan = wSpanSrc;
5080+
wSpanSrc.classList.add('cw-active');
5081+
loadSourceWordIndex(srcDocId).then(function(idx) {
5082+
var pack = idx && (idx[srcParaIdx] || idx[String(parseInt(srcParaIdx, 10) || 1)]);
5083+
var wdata = pack && pack[srcStem];
5084+
var raw = wdata && (wdata.matches || []);
5085+
var label = (wdata && wdata.forms && wdata.forms[0]) || (wSpanSrc.textContent || '').trim() || srcStem;
5086+
if (!raw || !raw.length) {
5087+
openChannelEmpty(label);
5088+
return;
5089+
}
5090+
openChannel(label, raw);
5091+
});
5092+
return;
5093+
}
5094+
}
5095+
50655096
var verse = e.target.closest('div.verse');
50665097
if (!verse) return;
50675098
closeTocPanel();
@@ -5145,7 +5176,9 @@
51455176
channelWord = word;
51465177
channelMorsels = [];
51475178
channelIdx = 0;
5148-
document.getElementById('ch-word').textContent = word;
5179+
var chW0 = document.getElementById('ch-word');
5180+
chW0.textContent = word;
5181+
chW0.style.display = 'block';
51495182
var pb = document.getElementById('panel-body');
51505183
pb.innerHTML = '<div class="ch-empty">No connections found for this word.</div>';
51515184
pb.dataset.panelMode = 'channel';
@@ -5159,7 +5192,9 @@
51595192
channelIdx = 0;
51605193
channelOpen = true;
51615194

5162-
document.getElementById('ch-word').textContent = word;
5195+
var chW1 = document.getElementById('ch-word');
5196+
chW1.textContent = word;
5197+
chW1.style.display = 'block';
51635198
document.getElementById('channel').classList.add('open');
51645199
renderChannelList();
51655200
}

test-library-sources.js

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,14 @@ async function run() {
121121
const hocState = await page.evaluate(() => ({
122122
title: document.querySelector('.source-doc .source-title')?.textContent.trim() || '',
123123
subtitle: document.querySelector('.source-doc .source-subtitle')?.textContent.trim() || '',
124-
location: document.querySelector('#location-label')?.textContent.trim() || '',
124+
location: document.getElementById('breadcrumbs')?.innerText.replace(/\s+/g, ' ').trim() || '',
125125
}));
126126
assert(hocState.title === 'Volume 1', 'History of the Church title did not load');
127127
assert(hocState.subtitle === 'History of the Church', 'History of the Church subtitle did not load');
128-
assert(hocState.location === 'History of the Church · Volume 1', 'History of the Church location label went stale after source navigation');
128+
assert(
129+
/History of the Church/.test(hocState.location) && /Volume\s*1/.test(hocState.location),
130+
'History of the Church breadcrumbs did not reflect the open document'
131+
);
129132
await tocBackToSourcesShelf(page);
130133

131134
await page.waitForSelector('.toc-tile[data-action="source-collection"][data-collection="times_and_seasons"]', { timeout: 10000 });
@@ -284,15 +287,18 @@ async function run() {
284287
const sourceState = await page.evaluate(() => ({
285288
title: document.querySelector('.source-doc .source-title')?.textContent.trim(),
286289
subtitle: document.querySelector('.source-doc .source-subtitle')?.textContent.trim(),
287-
location: document.querySelector('#location-label')?.textContent.trim(),
290+
location: document.getElementById('breadcrumbs')?.innerText.replace(/\s+/g, ' ').trim() || '',
288291
activeTile: document.querySelector('.toc-tile.active .toc-tile-title')?.textContent.trim(),
289292
activeMeta: document.querySelector('.toc-tile.active .toc-tile-meta')?.textContent.trim(),
290293
paragraphs: document.querySelectorAll('.source-doc .source-para').length,
291294
}));
292295

293296
assert(sourceState.title === 'Volume 1', 'source title did not load');
294297
assert(sourceState.subtitle === 'Journal of Discourses', 'source subtitle did not load');
295-
assert(sourceState.location === 'Journal of Discourses · Volume 1', 'source location label mismatch');
298+
assert(
299+
/Journal of Discourses/i.test(sourceState.location) && /Volume\s*1/i.test(sourceState.location),
300+
'source breadcrumbs did not reflect Journal of Discourses Volume 1'
301+
);
296302
assert(sourceState.activeTile === 'Volume 1', 'source tile did not become active');
297303
assert(sourceState.activeMeta === 'Journal of Discourses', 'source tile meta did not render');
298304
assert(sourceState.paragraphs > 50, 'source document rendered too few paragraphs');
@@ -303,8 +309,8 @@ async function run() {
303309

304310
const jdWordState = await page.evaluate(() => ({
305311
word: document.querySelector('#ch-word')?.textContent.trim(),
306-
morsels: document.querySelectorAll('.ch-morsel').length,
307-
firstSource: document.querySelector('.ch-morsel .ch-src-name')?.textContent.trim(),
312+
morsels: document.querySelectorAll('#panel-body .ch-morsel').length,
313+
firstSource: document.querySelector('#panel-body .ch-morsel .ch-src-name')?.textContent.trim(),
308314
}));
309315

310316
assert(jdWordState.word, 'JD word click did not set channel word');
@@ -347,9 +353,9 @@ async function run() {
347353

348354
const hocWordState = await page.evaluate(() => ({
349355
word: document.querySelector('#ch-word')?.textContent.trim(),
350-
morsels: document.querySelectorAll('.ch-morsel').length,
351-
firstSource: document.querySelector('.ch-morsel .ch-src-name')?.textContent.trim(),
352-
firstText: document.querySelector('.ch-morsel .ch-morsel-text')?.textContent.trim() || '',
356+
morsels: document.querySelectorAll('#panel-body .ch-morsel').length,
357+
firstSource: document.querySelector('#panel-body .ch-morsel .ch-src-name')?.textContent.trim(),
358+
firstText: document.querySelector('#panel-body .ch-morsel .ch-morsel-text')?.textContent.trim() || '',
353359
}));
354360

355361
assert(hocWordState.word, 'HoC word click did not set channel word');
@@ -368,13 +374,16 @@ async function run() {
368374
const scriptureState = await page.evaluate(() => ({
369375
sourceVisible: !!document.querySelector('.source-doc'),
370376
chapterVisible: !!document.querySelector('#ch-john_3'),
371-
location: document.querySelector('#location-label')?.textContent.trim(),
377+
location: document.getElementById('breadcrumbs')?.innerText.replace(/\s+/g, ' ').trim() || '',
372378
tocSubtitle: document.querySelector('#toc-subtitle')?.textContent.trim(),
373379
}));
374380

375381
assert(!scriptureState.sourceVisible, 'source reader remained visible after returning to scripture');
376382
assert(scriptureState.chapterVisible, 'John 3 did not render after switching back from source');
377-
assert(scriptureState.location === 'John · 3', 'scripture location label did not recover after source view');
383+
assert(
384+
/John/i.test(scriptureState.location) && /\b3\b/.test(scriptureState.location),
385+
'scripture breadcrumbs did not recover after source view'
386+
);
378387
assert(scriptureState.tocSubtitle === 'John', 'TOC did not return to scripture chapter view');
379388

380389
await page.click('#v1');
@@ -386,13 +395,13 @@ async function run() {
386395
});
387396
await page.waitForFunction(() => document.querySelector('#channel').classList.contains('open'), { timeout: 15000 });
388397
await page.waitForFunction(() => {
389-
return Array.from(document.querySelectorAll('.ch-morsel .ch-src-name')).some((el) =>
398+
return Array.from(document.querySelectorAll('#panel-body .ch-morsel .ch-src-name')).some((el) =>
390399
/Journal of Discourses|General Conference|History of the Church/i.test(el.textContent || '')
391400
);
392401
}, { timeout: 15000 });
393402

394403
const sourceMorselIndex = await page.evaluate(() => {
395-
const morsels = Array.from(document.querySelectorAll('.ch-morsel'));
404+
const morsels = Array.from(document.querySelectorAll('#panel-body .ch-morsel'));
396405
return morsels.findIndex((el) =>
397406
/Journal of Discourses|General Conference|History of the Church/i.test(
398407
el.querySelector('.ch-src-name')?.textContent || ''
@@ -401,7 +410,7 @@ async function run() {
401410
});
402411
assert(sourceMorselIndex >= 0, 'scripture word click did not surface a source morsel');
403412

404-
await page.$eval(`.ch-morsel[data-idx="${sourceMorselIndex}"]`, (el) => el.click());
413+
await page.$eval(`#panel-body .ch-morsel[data-idx="${sourceMorselIndex}"]`, (el) => el.click());
405414
await page.waitForSelector('.source-doc .source-title', { timeout: 20000 });
406415
await page.waitForFunction(() => {
407416
const focused = document.querySelector('.source-para-focus');
@@ -411,7 +420,7 @@ async function run() {
411420
const scriptureToSourceState = await page.evaluate(() => ({
412421
sourceTitle: document.querySelector('.source-doc .source-title')?.textContent.trim(),
413422
sourceSubtitle: document.querySelector('.source-doc .source-subtitle')?.textContent.trim(),
414-
location: document.querySelector('#location-label')?.textContent.trim(),
423+
location: document.getElementById('breadcrumbs')?.innerText.replace(/\s+/g, ' ').trim() || '',
415424
activeTile: document.querySelector('.toc-tile.active .toc-tile-title')?.textContent.trim(),
416425
activeMeta: document.querySelector('.toc-tile.active .toc-tile-meta')?.textContent.trim(),
417426
previewHidden: document.querySelector('#morsel-preview')?.hidden,
@@ -421,7 +430,10 @@ async function run() {
421430

422431
assert(scriptureToSourceState.sourceTitle, 'source morsel click did not open a source doc');
423432
assert(scriptureToSourceState.sourceSubtitle, 'source morsel click did not preserve the source subtitle');
424-
assert(scriptureToSourceState.location.endsWith(scriptureToSourceState.sourceTitle), 'source morsel click did not preserve the clean location label');
433+
assert(
434+
scriptureToSourceState.location.indexOf(scriptureToSourceState.sourceTitle) !== -1,
435+
'source morsel click did not preserve breadcrumbs for the opened document'
436+
);
425437
assert(scriptureToSourceState.activeTile === scriptureToSourceState.sourceTitle, 'source morsel click did not preserve the active source title tile');
426438
assert(scriptureToSourceState.activeMeta === scriptureToSourceState.sourceSubtitle, 'source morsel click did not preserve the active source meta tile');
427439
assert(scriptureToSourceState.previewHidden, 'source morsel click fell back to the preview card');
@@ -436,27 +448,30 @@ async function run() {
436448
});
437449
await page.waitForFunction(() => document.querySelector('#channel').classList.contains('open'), { timeout: 15000 });
438450
const secondSourceMorselIndex = await page.evaluate(() => {
439-
const morsels = Array.from(document.querySelectorAll('.ch-morsel'));
451+
const morsels = Array.from(document.querySelectorAll('#panel-body .ch-morsel'));
440452
return morsels.findIndex((el) =>
441453
/Journal of Discourses|History of the Church|General Conference/i.test(
442454
el.querySelector('.ch-src-name')?.textContent || ''
443455
)
444456
);
445457
});
446458
assert(secondSourceMorselIndex >= 0, 'source word click did not surface a second source morsel');
447-
await page.$eval(`.ch-morsel[data-idx="${secondSourceMorselIndex}"]`, (el) => el.click());
459+
await page.$eval(`#panel-body .ch-morsel[data-idx="${secondSourceMorselIndex}"]`, (el) => el.click());
448460
await page.waitForSelector('.source-doc .source-title', { timeout: 20000 });
449461
const sourceToSourceState = await page.evaluate(() => ({
450462
sourceTitle: document.querySelector('.source-doc .source-title')?.textContent.trim() || '',
451463
sourceSubtitle: document.querySelector('.source-doc .source-subtitle')?.textContent.trim() || '',
452-
location: document.querySelector('#location-label')?.textContent.trim() || '',
464+
location: document.getElementById('breadcrumbs')?.innerText.replace(/\s+/g, ' ').trim() || '',
453465
activeTile: document.querySelector('.toc-tile.active .toc-tile-title')?.textContent.trim() || '',
454466
activeMeta: document.querySelector('.toc-tile.active .toc-tile-meta')?.textContent.trim() || '',
455467
focusedText: document.querySelector('.source-para-focus')?.textContent.trim() || '',
456468
}));
457469
assert(sourceToSourceState.sourceTitle, 'second source morsel click did not open a source doc');
458470
assert(sourceToSourceState.sourceSubtitle, 'second source morsel click did not preserve the source subtitle');
459-
assert(sourceToSourceState.location.endsWith(sourceToSourceState.sourceTitle), 'second source morsel click did not preserve the clean location label');
471+
assert(
472+
sourceToSourceState.location.indexOf(sourceToSourceState.sourceTitle) !== -1,
473+
'second source morsel click did not preserve breadcrumbs for the opened document'
474+
);
460475
assert(sourceToSourceState.activeTile === sourceToSourceState.sourceTitle, 'second source morsel click did not preserve the active source title tile');
461476
assert(sourceToSourceState.activeMeta === sourceToSourceState.sourceSubtitle, 'second source morsel click did not preserve the active source meta tile');
462477
assert(sourceToSourceState.focusedText.length > 80, 'second source morsel click did not focus a relevant paragraph');

0 commit comments

Comments
 (0)