import { Handler } from '/csspageweaver/lib/paged.esm.js'; export default class beforeAll extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } beforeParsed(content){ numParagraph(content); thesis(content); wrapChapterAndIntro(content); } afterPageLayout(pageElement, page, breakToken){ let intro = pageElement.querySelector('.intro'); let pageContent = pageElement.querySelector('.pagedjs_page_content'); if(intro && pageContent){ let introBottom = intro.getBoundingClientRect().bottom; let pageContentBottom = pageContent.getBoundingClientRect().bottom; let gap = pageContentBottom - introBottom; gap = gap - 4; // snap on baseline intro.style.paddingTop = gap + "px"; } let thesisList = pageElement.querySelectorAll('.thesis'); if(thesisList.length > 0 && pageContent){ let lastThesis = thesisList[thesisList.length - 1]; let firstThesis = thesisList[0]; let lastThesisBottom = lastThesis.getBoundingClientRect().bottom; let pageContentBottom = pageContent.getBoundingClientRect().bottom; let gap = pageContentBottom - lastThesisBottom; gap = gap - 4; // snap on baseline firstThesis.style.marginTop = gap + "px"; } } } function numParagraph(content){ let numParagraphs = content.querySelectorAll('ol[type="1"]'); numParagraphs.forEach(function (num, index) { let start = num.getAttribute('start'); num.querySelector('li').innerHTML = start; }); } function wrapChapterAndIntro(content){ // Wrap h1 and following content in .chapter sections const sectionContent = content.querySelector('#section__content'); if (sectionContent) { const h1s = sectionContent.querySelectorAll(':scope > h1'); h1s.forEach(h1 => { // Create chapter section const chapter = document.createElement('section'); chapter.classList.add('chapter'); // Insert chapter before h1 h1.parentNode.insertBefore(chapter, h1); // Move h1 into chapter chapter.appendChild(h1); // Move following siblings until next h1 or end let nextElement = chapter.nextElementSibling; while (nextElement && nextElement.tagName.toLowerCase() !== 'h1') { const current = nextElement; nextElement = nextElement.nextElementSibling; chapter.appendChild(current); } let divEnd = document.createElement('div'); divEnd.classList.add("chapter-end"); // need to avoid to add new page chapter.appendChild(divEnd); }); // Wrap content between h1 and h2 in .intro if chapter doesn't contain .thesis const chapters = sectionContent.querySelectorAll('.chapter'); chapters.forEach(chapter => { if (chapter.querySelector('.thesis')) { // Case 1: Chapter has thesis chapter.classList.add('has-thesis'); } else { const h1 = chapter.querySelector('h1'); if (h1) { // Calculate chapter content length excluding notes const chapterClone = chapter.cloneNode(true); // Remove notes (common note selectors) chapterClone.querySelectorAll('.note, .footnote, .sidenote, aside, [role="note"]').forEach(note => note.remove()); const contentLength = chapterClone.textContent.trim().length; const intro = document.createElement('div'); intro.classList.add('intro'); if (contentLength < 5000) { // Case 2: Short chapter, wrap all content after h1 h1.parentNode.insertBefore(intro, h1.nextSibling); let current = intro.nextSibling; while (current) { const next = current.nextSibling; intro.appendChild(current); current = next; } chapter.classList.add('has-only-intro'); } else { const nextHeading = chapter.querySelector('h2, h3, h4, h5, h6'); if (nextHeading) { // Case 3: Has heading, wrap all content between h1 and that heading h1.parentNode.insertBefore(intro, h1.nextSibling); let current = intro.nextSibling; while (current && current !== nextHeading) { const next = current.nextSibling; intro.appendChild(current); current = next; } chapter.classList.add('has-intro'); } else { // Case 4: No heading, wrap first ol[type="1"] and first p after h1 h1.parentNode.insertBefore(intro, h1.nextSibling); let foundOl = false; let foundP = false; let current = intro.nextSibling; while (current && (!foundOl || !foundP)) { const next = current.nextSibling; // Skip text nodes (whitespace) if (current.nodeType !== 1) { current = next; continue; } const isOlType1 = current.tagName.toLowerCase() === 'ol' && current.getAttribute('type') === '1'; const isP = current.tagName.toLowerCase() === 'p'; if (isOlType1 && !foundOl) { intro.appendChild(current); foundOl = true; current = next; } else if (isP && !foundP) { intro.appendChild(current); foundP = true; current = next; } else if (!isOlType1 && !isP) { break; } else { current = next; } } if (intro.children.length > 0) { chapter.classList.add('has-intro-1-paragraph'); } } } } } }); } } function thesis(content){ const strongs = content.querySelectorAll('strong'); const thesisElements = []; strongs.forEach(strong => { if (/^these\s+\d+/i.test(strong.textContent.trim())) { const parent = strong.closest('p'); if (parent) { // Create thesis wrapper const thesisWrapper = document.createElement('div'); thesisWrapper.classList.add('thesis'); // Find preceding ol if it exists let prev = parent.previousElementSibling; let olElement = null; if (prev && prev.tagName.toLowerCase() === 'ol') { olElement = prev; } // Insert thesis wrapper before ol or before p if (olElement) { olElement.parentNode.insertBefore(thesisWrapper, olElement); thesisWrapper.appendChild(olElement); } else { parent.parentNode.insertBefore(thesisWrapper, parent); } // Create thesis-title const thesisTitleDiv = document.createElement('div'); thesisTitleDiv.classList.add('thesis-title'); const thesisP = document.createElement('p'); thesisP.textContent = strong.textContent; var line = document.createElement('div'); line.classList.add('thesis-line'); thesisTitleDiv.appendChild(thesisP); thesisTitleDiv.appendChild(line) thesisWrapper.appendChild(thesisTitleDiv); // Transform parent p into thesis-content strong.remove(); parent.classList.add('thesis-content'); thesisWrapper.appendChild(parent); thesisElements.push(thesisWrapper); } } }); // Mark first and last thesis if (thesisElements.length > 0) { thesisElements[0].classList.add('thesis-first'); thesisElements[thesisElements.length - 1].classList.add('thesis-last'); } }