From: Thomas Walker Lynch Date: Wed, 5 Aug 2026 15:27:47 +0000 (+0000) Subject: fighting pagination bugs X-Git-Url: https://git.reasoningtechnology.com/?a=commitdiff_plain;h=f96bfd42c465abeafb3422d7219927ffd6aeb3e9;p=RT-Style fighting pagination bugs --- diff --git a/developer/authored/Manuscript.copy/Element/TOC.js b/developer/authored/Manuscript.copy/Element/TOC.js index b1c6df1..80c1105 100644 --- a/developer/authored/Manuscript.copy/Element/TOC.js +++ b/developer/authored/Manuscript.copy/Element/TOC.js @@ -1,15 +1,15 @@ /* Element/TOC.js Processes tags. - Iterates nested boundaries, evaluates tree depth, + Iterates nested RT_section boundaries, evaluates tree depth, and duplicates the title payload for automated navigation. */ -(function() { +(function(){ - if (!window.RT) return; + if(!window.RT) return; - const apply_style = function(a ,config) { + const apply_style = function(a ,config){ a.style.textDecoration = 'none'; a.style.color = 'inherit'; a.style.display = 'block'; @@ -18,28 +18,28 @@ a.onmouseout = () => a.style.color = 'inherit'; }; - RT.Element.add( function() { + RT.Element.add(function(){ const debug = window.RT.Debug || { log: function(){} }; - if (debug.log) debug.log('TOC' ,'Generating Table of Contents from nested sections'); + if(debug.log) debug.log('TOC' ,'Generating Table of Contents from expanded section steps'); const config = window.RT.layout_config || {}; - const TOC_seq = document.querySelectorAll('rt·toc, RT·TOC'); + const TOC_seq = document.querySelectorAll('RT·TOC, rt·toc'); - TOC_seq.forEach( (container ,TOC_index) => { + TOC_seq.forEach((container ,TOC_index) => { container.style.display = 'block'; const attr_val = container.getAttribute('level'); let start_level = 1; let end_level = 6; - if (attr_val) { - const rangeMatch = attr_val.match(/^(\d)-(\d)$/); - if (rangeMatch) { - start_level = parseInt(rangeMatch[1]); - end_level = parseInt(rangeMatch[2]); - } else { + if(attr_val){ + const range_match = attr_val.match(/^(\d)-(\d)$/); + if(range_match){ + start_level = parseInt(range_match[1]); + end_level = parseInt(range_match[2]); + }else{ const single = parseInt(attr_val); - if (!isNaN(single)) { + if(!isNaN(single)){ start_level = single; end_level = single; } @@ -47,26 +47,25 @@ } const sections = []; - const all_sections = document.querySelectorAll('rt·section, RT·section'); + const all_sections = document.querySelectorAll('RT·counter·step[counter="RT_section"], rt·counter·step[counter="RT_section"]'); all_sections.forEach(section => { let depth = 0; let curr = section.parentElement; - while (curr) { - if (curr.tagName && curr.tagName.toLowerCase() === 'rt·section') { + while(curr){ + const tag = (curr.tagName || '').toLowerCase(); + if(tag === 'rt·counter·step' && curr.getAttribute('counter') === 'RT_section'){ depth++; } curr = curr.parentElement; } const level = depth + 1; - if (level >= start_level && level <= end_level) { - - // Use querySelector to safely find the title regardless of nested wrapper logic + if(level >= start_level && level <= end_level){ const title_node = section.querySelector('.RT·section-title'); - if (title_node) { + if(title_node){ sections.push({ id: section.id ,level: level @@ -87,35 +86,35 @@ title.style.color = config.brand_primary || '#000'; container.appendChild(title); - if (sections.length === 0) return; + if(sections.length === 0) return; - const topList = document.createElement('ul'); - topList.style.listStyle = 'none'; - topList.style.paddingLeft = '0'; - topList.style.marginBottom = '0'; - container.appendChild(topList); + const top_list = document.createElement('ul'); + top_list.style.listStyle = 'none'; + top_list.style.paddingLeft = '0'; + top_list.style.marginBottom = '0'; + container.appendChild(top_list); - const listStack = [topList]; + const list_stack = [top_list]; - for (const item of sections) { + for(const item of sections){ const depth = item.level - start_level; - while (listStack.length - 1 > depth) { - listStack.pop(); + while(list_stack.length - 1 > depth){ + list_stack.pop(); } - while (listStack.length - 1 < depth) { - const parentList = listStack[listStack.length - 1]; - const lastLi = parentList.lastElementChild; - - if (lastLi) { - const subList = document.createElement('ul'); - subList.style.listStyle = 'none'; - subList.style.paddingLeft = '1.5rem'; - subList.style.marginBottom = '0'; - lastLi.appendChild(subList); - listStack.push(subList); - } else { + while(list_stack.length - 1 < depth){ + const parent_list = list_stack[list_stack.length - 1]; + const last_li = parent_list.lastElementChild; + + if(last_li){ + const sub_list = document.createElement('ul'); + sub_list.style.listStyle = 'none'; + sub_list.style.paddingLeft = '1.5rem'; + sub_list.style.marginBottom = '0'; + last_li.appendChild(sub_list); + list_stack.push(sub_list); + }else{ break; } } @@ -131,7 +130,7 @@ apply_style(a ,config); li.appendChild(a); - listStack[listStack.length - 1].appendChild(li); + list_stack[list_stack.length - 1].appendChild(li); } }); }); diff --git a/developer/authored/Manuscript.copy/Element/section.js b/developer/authored/Manuscript.copy/Element/section.js index 7fd9361..b03500a 100644 --- a/developer/authored/Manuscript.copy/Element/section.js +++ b/developer/authored/Manuscript.copy/Element/section.js @@ -1,26 +1,23 @@ /* Element/section.js - Processes tags. - Applies counting hierarchical numbering, conditional alignment/indents, - subdued dark red borders for top-level elements, and universal page breaks for chapters. + Expands macros into primitives. */ -(function() { +(function(){ - if (!window.RT) return; + if(!window.RT) return; - const apply_style = function(title_node ,depth ,config) { + const apply_style = function(title_node ,depth ,config){ const base_size = 2.25; const size = Math.max(1.1 ,base_size - (depth * 0.35)); const fade_opacity = Math.max(0.5 ,1 - (depth * 0.2)); - if (depth === 0) { + if(depth === 0){ title_node.style.textAlign = 'center'; title_node.style.paddingLeft = '0'; - // Firebrick provides sufficient chroma contrast against dark backgrounds title_node.style.borderBottom = '2px solid #B22222'; title_node.style.paddingBottom = '0.5rem'; - } else { + }else{ title_node.style.textAlign = 'left'; title_node.style.paddingLeft = (depth * 1.5) + 'rem'; } @@ -34,20 +31,19 @@ title_node.style.lineHeight = '1.2'; }; - RT.Element.add(function() { + RT.Element.add(function(){ const debug = window.RT.Debug || { log: function(){} }; - if (debug.log) debug.log('section' ,'Processing scoped sections with counting numbering'); + if(debug.log) debug.log('section' ,'Expanding section macros'); const config = window.RT.layout_config || {}; const section_seq = document.querySelectorAll('RT·section, rt·section'); - if (section_seq.length === 0) return; + if(section_seq.length === 0) return; const article = document.querySelector('RT·article, rt·article, RT·memo, rt·memo'); - if (article && !document.querySelector('rt·counter·make[counter="RT_section"]')) { - const make = document.createElement('rt·counter·make'); + if(article && !document.querySelector('RT·counter·make[counter="RT_section"], rt·counter·make[counter="RT_section"]')){ + const make = document.createElement('RT·counter·make'); make.setAttribute('counter' ,'RT_section'); - // Utilizing CountingNumber to output 1.1.1 rather than 0.0.0 make.setAttribute('style' ,'CountingNumber'); make.setAttribute('mode' ,'scoped'); make.setAttribute('on-first-step' ,'0'); @@ -57,68 +53,64 @@ let section_idx = 0; section_seq.forEach(section => { - section.style.display = 'block'; - let depth = 0; let curr = section.parentElement; - while (curr) { - if (curr.tagName && curr.tagName.toLowerCase() === 'rt·section') { + while(curr){ + const tag = (curr.tagName || '').toLowerCase(); + if(tag === 'rt·section' || (tag === 'rt·counter·step' && curr.getAttribute('counter') === 'RT_section')){ depth++; } curr = curr.parentElement; } - // Force ALL top-level sections to start on a new page - if (depth === 0) { - if (!section.previousElementSibling?.tagName?.toLowerCase().includes('page-break')) { - const pb = document.createElement('rt·page-break'); - section.parentNode.insertBefore(pb, section); + if(depth === 0){ + if(!section.previousElementSibling?.tagName?.toLowerCase().includes('page-break')){ + const pb = document.createElement('RT·page-break'); + section.parentNode.insertBefore(pb ,section); } } - const names = []; - const children = Array.from(section.children); - children.forEach(child => { - if (child.tagName && child.tagName.toLowerCase() === 'rt·name') { - names.push(child.innerHTML.trim()); - child.remove(); - } - }); - - const title_text = names.length > 0 ? names.join('
') : '•'; - - const step = document.createElement('rt·counter·step'); + const snap_id = section.id || ('section_snap_' + section_idx++); + + const step = document.createElement('RT·counter·step'); step.setAttribute('counter' ,'RT_section'); + step.setAttribute('splitable' ,'true'); + step.id = snap_id; - while (section.firstChild) { - step.appendChild(section.firstChild); - } - - const snap_id = 'section_snap_' + section_idx++; - const snap = document.createElement('rt·counter·snapshot'); + const snap = document.createElement('RT·counter·snapshot'); snap.setAttribute('counter' ,'RT_section'); snap.setAttribute('snapshot' ,snap_id); + step.appendChild(snap); const title_node = document.createElement('div'); title_node.className = 'RT·section-title'; - if (!section.id) section.id = snap_id; - const read = document.createElement('rt·counter·read'); - read.setAttribute('snapshot' ,snap_id); - + const read_count = document.createElement('RT·counter·read'); + read_count.setAttribute('snapshot' ,snap_id); + const title_content = document.createElement('span'); title_content.style.marginLeft = '0.75rem'; - title_content.innerHTML = title_text; + + const read_name = document.createElement('RT·counter·read'); + read_name.setAttribute('snapshot' ,snap_id); + read_name.setAttribute('key' ,'name'); + title_content.appendChild(read_name); - title_node.appendChild(read); + title_node.appendChild(read_count); title_node.appendChild(title_content); apply_style(title_node ,depth ,config); + step.appendChild(title_node); - step.insertBefore(title_node ,step.firstChild); - step.insertBefore(snap ,step.firstChild); + while(section.firstChild){ + const child = section.firstChild; + if((child.tagName || '').toLowerCase() === 'rt·name'){ + child.style.display = 'none'; + } + step.appendChild(child); + } - section.appendChild(step); + section.parentNode.replaceChild(step ,section); }); }); diff --git a/developer/authored/Manuscript.copy/Layout/paginate.js b/developer/authored/Manuscript.copy/Layout/paginate.js index 8f105cf..03cdc31 100644 --- a/developer/authored/Manuscript.copy/Layout/paginate.js +++ b/developer/authored/Manuscript.copy/Layout/paginate.js @@ -7,7 +7,7 @@ (function(){ if(!window.RT){ - console.error("RT not defined - was RT-Style_make run?"); + console.error("RT not defined. Was RT-Manuscript_make run?"); return; } @@ -16,84 +16,77 @@ const page_conf = (RT.config && RT.config.page) ? RT.config.page : {}; const page_height_limit = page_conf.height_limit || 1000; - let measureContainer = null; + let measure_container = null; - // ========================================================= // 1. DOM Measurement Utilities - // ========================================================= - function getElHeight(el){ - const wasInDOM = el.parentNode !== null; - if(!wasInDOM) document.body.appendChild(el); + function get_el_height(el){ + const was_in_DOM = el.parentNode !== null; + if(!was_in_DOM) document.body.appendChild(el); const rect = el.getBoundingClientRect(); const style = window.getComputedStyle(el); const margin = parseFloat(style.marginTop) + parseFloat(style.marginBottom); - if(!wasInDOM) el.remove(); + if(!was_in_DOM) el.remove(); return (rect.height || 0) + (margin || 0); } - function getMeasureContainer(){ - if(measureContainer && measureContainer.parentNode) return measureContainer; - const article = document.querySelector('RT·article'); + function get_measure_container(){ + if(measure_container && measure_container.parentNode) return measure_container; + const article = document.querySelector('RT·article, rt·article'); if(!article){ const temp = document.createElement('div'); temp.style.visibility = 'hidden'; temp.style.position = 'absolute'; temp.style.width = '100%'; document.body.appendChild(temp); - measureContainer = temp; + measure_container = temp; return temp; } const container = document.createElement('div'); - const articleStyle = window.getComputedStyle(article); + const article_style = window.getComputedStyle(article); container.style.visibility = 'hidden'; container.style.position = 'absolute'; - container.style.width = articleStyle.width; - container.style.fontFamily = articleStyle.fontFamily; - container.style.fontSize = articleStyle.fontSize; - container.style.lineHeight = articleStyle.lineHeight; - container.style.fontWeight = articleStyle.fontWeight; + container.style.width = article_style.width; + container.style.fontFamily = article_style.fontFamily; + container.style.fontSize = article_style.fontSize; + container.style.lineHeight = article_style.lineHeight; + container.style.fontWeight = article_style.fontWeight; document.body.appendChild(container); - measureContainer = container; + measure_container = container; return container; } - function measureFragment(frag){ - const container = getMeasureContainer(); + function measure_fragment(frag){ + const container = get_measure_container(); container.appendChild(frag); - const h = getElHeight(frag); + const h = get_el_height(frag); container.removeChild(frag); return h; } - // ========================================================= // Splitting Logic - // ========================================================= - function isSplittable(el){ + function is_splittable(el){ + if(!el || el.nodeType !== Node.ELEMENT_NODE) return null; - // Component Dictionary Execution - const componentId = el.getAttribute('data-rt-component'); - if (componentId && window.RT.Component && window.RT.Component[componentId] && window.RT.Component[componentId].split) { - return (remaining) => window.RT.Component[componentId].split(el, remaining, measureFragment); + const component_id = el.getAttribute('data-rt-component'); + if(component_id && window.RT.Component && window.RT.Component[component_id] && window.RT.Component[component_id].split){ + return (remaining) => window.RT.Component[component_id].split(el ,remaining ,measure_fragment); } - // Custom RT splitable attribute delegation - if (el.hasAttribute('splitable') && window.RT.Splitter && window.RT.Splitter[el.tagName.toLowerCase()]) { - return (remaining) => window.RT.Splitter[el.tagName.toLowerCase()](el, remaining, measureFragment, isSplittable); + if(el.hasAttribute('splitable') && window.RT.Splitter && window.RT.Splitter[(el.tagName || '').toLowerCase()]){ + return (remaining) => window.RT.Splitter[(el.tagName || '').toLowerCase()](el ,remaining ,measure_fragment ,is_splittable); } - // Native HTML Fallbacks - - const tag = el.tagName; + const tag = (el.tagName || '').toUpperCase(); if(tag === 'UL' || tag === 'OL'){ - const items = Array.from(el.children).filter(c => c.tagName === 'LI'); + const items = Array.from(el.children).filter(c => (c.tagName || '').toUpperCase() === 'LI'); if(items.length === 0) return null; - const itemHeights = items.map(li => getElHeight(li)); - const emptyClone = el.cloneNode(false); - const overhead = getElHeight(emptyClone); + const item_heights = items.map(li => get_el_height(li)); + const empty_clone = el.cloneNode(false); + const overhead = get_el_height(empty_clone); - el._splitInfo = { type: 'list' ,itemHeights ,overhead ,offset: 0 }; - return makeListSplitter(el ,el._splitInfo); + el._splitInfo = { type: 'list' ,itemHeights: item_heights ,overhead: overhead ,offset: 0 }; + return make_list_splitter(el ,el._splitInfo); } if(tag === 'TABLE'){ @@ -102,80 +95,80 @@ const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); if(rows.length === 0) return null; - const theadHeight = thead ? getElHeight(thead) : 0; - const rowHeights = rows.map(row => getElHeight(row)); + const thead_height = thead ? get_el_height(thead) : 0; + const row_heights = rows.map(row => get_el_height(row)); - const emptyClone = el.cloneNode(false); - if(thead) emptyClone.appendChild(thead.cloneNode(true)); - emptyClone.appendChild(document.createElement('tbody')); - const overhead = getElHeight(emptyClone) - theadHeight; + const empty_clone = el.cloneNode(false); + if(thead) empty_clone.appendChild(thead.cloneNode(true)); + empty_clone.appendChild(document.createElement('tbody')); + const overhead = get_el_height(empty_clone) - thead_height; - el._splitInfo = { type: 'table' ,rowHeights ,overhead ,theadHeight ,offset: 0 }; - return makeTableSplitter(el ,el._splitInfo); + el._splitInfo = { type: 'table' ,rowHeights: row_heights ,overhead: overhead ,theadHeight: thead_height ,offset: 0 }; + return make_table_splitter(el ,el._splitInfo); } return null; } - function makeListSplitter(el ,info){ + function make_list_splitter(el ,info){ return (remaining) => { - const children = Array.from(el.children).filter(c => c.tagName === 'LI'); + const children = Array.from(el.children).filter(c => (c.tagName || '').toUpperCase() === 'LI'); const start = info.offset; - let bestCount = 0; - let bestHeight = 0; - const tempList = el.cloneNode(false); + let best_count = 0; + let best_height = 0; + const temp_list = el.cloneNode(false); for(let i = 0; i < children.length; i++){ - const itemClone = children[i].cloneNode(true); - tempList.appendChild(itemClone); - const fragHeight = measureFragment(tempList); - if(fragHeight <= remaining){ - bestCount = i + 1; - bestHeight = fragHeight; - } else { - tempList.removeChild(itemClone); + const item_clone = children[i].cloneNode(true); + temp_list.appendChild(item_clone); + const frag_height = measure_fragment(temp_list); + if(frag_height <= remaining){ + best_count = i + 1; + best_height = frag_height; + }else{ + temp_list.removeChild(item_clone); break; } } - if(bestCount === 0) return { first: null ,rest: el ,firstHeight: 0 }; + if(best_count === 0) return { first: null ,rest: el ,firstHeight: 0 }; const first = el.cloneNode(false); - for(let i = 0; i < bestCount; i++){ + for(let i = 0; i < best_count; i++){ first.appendChild(children[i].cloneNode(true)); } let rest = null; - if(bestCount < children.length){ + if(best_count < children.length){ rest = el.cloneNode(false); - for(let i = bestCount; i < children.length; i++){ + for(let i = best_count; i < children.length; i++){ rest.appendChild(children[i].cloneNode(true)); } - if(el.tagName === 'OL'){ - const currentStart = parseInt(el.getAttribute('start') ,10) || 1; - rest.setAttribute('start' ,currentStart + bestCount); + if((el.tagName || '').toUpperCase() === 'OL'){ + const current_start = parseInt(el.getAttribute('start') ,10) || 1; + rest.setAttribute('start' ,current_start + best_count); } rest._splitInfo = { type: 'list' ,itemHeights: info.itemHeights ,overhead: info.overhead - ,offset: start + bestCount + ,offset: start + best_count }; } - return { first ,rest ,firstHeight: bestHeight }; + return { first: first ,rest: rest ,firstHeight: best_height }; }; } - function makeTableSplitter(el ,info){ + function make_table_splitter(el ,info){ const thead = el.querySelector('thead'); - const createShell = () => { + const create_shell = () => { const shell = el.cloneNode(false); if(thead) shell.appendChild(thead.cloneNode(true)); - const newTbody = document.createElement('tbody'); - shell.appendChild(newTbody); + const new_tbody = document.createElement('tbody'); + shell.appendChild(new_tbody); return shell; }; @@ -184,37 +177,37 @@ const rows = tbody ? Array.from(tbody.rows) : Array.from(el.rows); const start = info.offset; - let bestCount = 0; - let bestHeight = 0; - const tempTable = createShell(); - const tempBody = tempTable.querySelector('tbody'); + let best_count = 0; + let best_height = 0; + const temp_table = create_shell(); + const temp_body = temp_table.querySelector('tbody'); for(let i = 0; i < rows.length; i++){ - tempBody.appendChild(rows[i].cloneNode(true)); - const h = measureFragment(tempTable); + temp_body.appendChild(rows[i].cloneNode(true)); + const h = measure_fragment(temp_table); if(h <= remaining){ - bestCount = i + 1; - bestHeight = h; - } else { - tempBody.removeChild(tempBody.lastChild); + best_count = i + 1; + best_height = h; + }else{ + temp_body.removeChild(temp_body.lastChild); break; } } - if(bestCount === 0) return { first: null ,rest: el ,firstHeight: 0 }; + if(best_count === 0) return { first: null ,rest: el ,firstHeight: 0 }; - const first = createShell(); - const firstBody = first.querySelector('tbody'); - for(let i = 0; i < bestCount; i++){ - firstBody.appendChild(rows[i].cloneNode(true)); + const first = create_shell(); + const first_body = first.querySelector('tbody'); + for(let i = 0; i < best_count; i++){ + first_body.appendChild(rows[i].cloneNode(true)); } let rest = null; - if(bestCount < rows.length){ - rest = createShell(); - const restBody = rest.querySelector('tbody'); - for(let i = bestCount; i < rows.length; i++){ - restBody.appendChild(rows[i].cloneNode(true)); + if(best_count < rows.length){ + rest = create_shell(); + const rest_body = rest.querySelector('tbody'); + for(let i = best_count; i < rows.length; i++){ + rest_body.appendChild(rows[i].cloneNode(true)); } rest._splitInfo = { @@ -222,101 +215,103 @@ ,rowHeights: info.rowHeights ,overhead: info.overhead ,theadHeight: info.theadHeight - ,offset: start + bestCount + ,offset: start + best_count }; } - return { first ,rest ,firstHeight: bestHeight }; + return { first: first ,rest: rest ,firstHeight: best_height }; }; } - - // ========================================================= // RT ELEMENT SPLITTERS - // ========================================================= window.RT.Splitter = window.RT.Splitter || {}; - window.RT.Splitter['rt·counter·step'] = function(el, remaining, measureFn, isSplittableFn) { - const children = Array.from(el.children); - let bestCount = 0; - let bestHeight = 0; - const tempContainer = el.cloneNode(false); - let splitChildResult = null; - let forcedBreak = false; + window.RT.Splitter['rt·counter·step'] = function(el ,remaining ,measure_fn ,is_splittable_fn){ + const children = Array.from(el.childNodes); + let best_count = 0; + let best_height = 0; + const temp_container = el.cloneNode(false); + let split_child_result = null; + let forced_break = false; - for (let i = 0; i < children.length; i++) { + for(let i = 0; i < children.length; i++){ const child = children[i]; - // Break on explicit splitting break - if (child.tagName && child.tagName.toLowerCase() === 'rt·page-break') { - forcedBreak = true; - bestCount = i; + const tag = child.nodeType === Node.ELEMENT_NODE ? (child.tagName || '').toLowerCase() : ''; + if(tag === 'rt·page-break' || tag === 'rt·page-break-primitive'){ + forced_break = true; + best_count = i; break; } - tempContainer.appendChild(child.cloneNode(true)); - const fragHeight = measureFn(tempContainer); - - if (fragHeight <= remaining) { - bestCount = i + 1; - bestHeight = fragHeight; - } else { - tempContainer.removeChild(tempContainer.lastChild); - const childSplitter = isSplittableFn(child); - if (childSplitter) { - const childSplit = childSplitter(remaining - bestHeight); - if (childSplit && childSplit.first) { - splitChildResult = childSplit; - bestHeight += childSplit.firstHeight; - bestCount = i; + temp_container.appendChild(child.cloneNode(true)); + const frag_height = measure_fn(temp_container); + + if(frag_height <= remaining){ + best_count = i + 1; + best_height = frag_height; + }else{ + temp_container.removeChild(temp_container.lastChild); + const child_splitter = child.nodeType === Node.ELEMENT_NODE ? is_splittable_fn(child) : null; + if(child_splitter){ + const child_split = child_splitter(remaining - best_height); + if(child_split && child_split.first){ + split_child_result = child_split; + best_height += child_split.firstHeight; + best_count = i; } } break; } } - if (bestCount === 0 && !splitChildResult && !forcedBreak) { - return { first: null, rest: el, firstHeight: 0 }; + if(best_count === 0 && !split_child_result && !forced_break){ + return { first: null ,rest: el ,firstHeight: 0 }; } const first = el.cloneNode(false); - first.setAttribute('continued', 'true'); - const splitId = 'split_' + Math.random().toString(36).substr(2, 9); - first.setAttribute('split-id', splitId); + first.setAttribute('continued' ,'true'); + const split_id = 'split_' + Math.random().toString(36).substr(2 ,9); + first.setAttribute('split-id' ,split_id); - for (let i = 0; i < bestCount; i++) { + for(let i = 0; i < best_count; i++){ first.appendChild(children[i].cloneNode(true)); } - if (splitChildResult) first.appendChild(splitChildResult.first); + if(split_child_result) first.appendChild(split_child_result.first); let rest = null; - if (bestCount < children.length || splitChildResult || forcedBreak) { + if(best_count < children.length || split_child_result || forced_break){ rest = el.cloneNode(false); - rest.setAttribute('continuation', 'true'); - if (splitChildResult && splitChildResult.rest) rest.appendChild(splitChildResult.rest); + rest.setAttribute('continuation' ,'true'); + + if(split_child_result && split_child_result.rest){ + if(Array.isArray(split_child_result.rest)){ + split_child_result.rest.forEach(r_node => rest.appendChild(r_node)); + }else{ + rest.appendChild(split_child_result.rest); + } + } - const startIndex = forcedBreak ? bestCount + 1 : (splitChildResult ? bestCount + 1 : bestCount); - for (let i = startIndex; i < children.length; i++) { + const start_index = forced_break ? best_count + 1 : (split_child_result ? best_count + 1 : best_count); + for(let i = start_index; i < children.length; i++){ rest.appendChild(children[i].cloneNode(true)); } - const makeTag = document.createElement('rt·counter·make'); - makeTag.setAttribute('counter', el.getAttribute('counter')); - makeTag.setAttribute('continues', splitId); + const make_tag = document.createElement('RT·counter·make'); + make_tag.setAttribute('counter' ,el.getAttribute('counter')); + make_tag.setAttribute('continues' ,split_id); - rest = [makeTag, rest]; + rest = [make_tag ,rest]; } - return { first, rest, firstHeight: bestHeight }; + return { first: first ,rest: rest ,firstHeight: best_height }; }; - // ========================================================= // PAGINATE 0: CHUNKING & INJECTING STRUCTURE - // ========================================================= function paginate_0(){ if(debug.log) debug.log('paginate_0' ,'Running initial document chunking'); - const article_seq = document.querySelectorAll('RT·article'); + const article_seq = document.querySelectorAll('RT·article, rt·article, RT·memo, rt·memo'); if(article_seq.length === 0){ debug.error('pagination' ,'No elements found. Pagination aborted.'); return; @@ -325,10 +320,9 @@ const footnote_registry = {}; let footnote_counter = 1; - // Strip and tag footnotes Array.from(article_seq).forEach(article => { const all_nodes = Array.from(article.querySelectorAll('*')); - const raw_footnotes = all_nodes.filter(node => node.tagName.toLowerCase() === 'rt·footnote'); + const raw_footnotes = all_nodes.filter(node => (node.tagName || '').toLowerCase() === 'rt·footnote'); raw_footnotes.forEach(fn => { const id = footnote_counter++; @@ -348,11 +342,13 @@ }); }); - function paginateArticle(article){ + function paginate_article(article){ const raw_element_seq = Array.from(article.children).filter(el => - !['SCRIPT' ,'STYLE' ,'RT·PAGE'].includes((el.tagName || '').toUpperCase()) + !['SCRIPT' ,'STYLE' ,'RT·PAGE' ,'RT·COUNTER·MAKE'].includes((el.tagName || '').toUpperCase()) ); + const global_makes = Array.from(article.children).filter(el => (el.tagName || '').toUpperCase() === 'RT·COUNTER·MAKE'); + if(raw_element_seq.length === 0) return; const page_seq = []; @@ -362,7 +358,7 @@ while(i < raw_element_seq.length){ const el = raw_element_seq[i]; - const splitter = isSplittable(el); + const splitter = is_splittable(el); if(splitter){ const remaining = page_height_limit - current_h; @@ -373,22 +369,24 @@ current_h += firstHeight; if(rest){ - if (Array.isArray(rest)) { - raw_element_seq.splice(i, 1, ...rest); - } else { - raw_element_seq.splice(i, 1, rest); + if(Array.isArray(rest)){ + raw_element_seq.splice(i ,1 ,...rest); + }else{ + raw_element_seq.splice(i ,1 ,rest); + } + + if(current_h > 0){ + page_seq.push(current_batch_seq); + current_batch_seq = []; + current_h = 0; } - // Force page boundary push because element spanned boundary - page_seq.push(current_batch_seq); - current_batch_seq = []; - current_h = 0; - continue; - } else { - raw_element_seq.splice(i, 1); continue; + }else{ + raw_element_seq.splice(i ,1); + continue; } - } else { - if(current_batch_seq.length === 0){ + }else{ + if(current_h === 0){ const frame = document.createElement('RT·scroll-frame'); frame.style.display = 'block'; frame.style.overflowY = 'auto'; @@ -396,35 +394,31 @@ frame.appendChild(el); current_batch_seq.push(frame); i++; - } else { - // Element is split but first chunk fails to fit. Evict any stranded headings. + }else{ let backtrack_seq = []; let backtrack_h = 0; while(current_batch_seq.length > 0){ const last = current_batch_seq[current_batch_seq.length - 1]; - if(!/^H[1-6]$/i.test(last.tagName)) break; + if(!last.tagName || !/^H[1-6]$/i.test(last.tagName)) break; const popped = current_batch_seq.pop(); backtrack_seq.unshift(popped); - backtrack_h += getElHeight(popped); + backtrack_h += get_el_height(popped); } - if(current_batch_seq.length > 0){ + if(current_h - backtrack_h > 0){ page_seq.push(current_batch_seq); current_batch_seq = backtrack_seq; current_h = backtrack_h; - // Leave 'i' alone to re-evaluate 'el' against the fresh page sequence - } else { - // If only headings existed, accept the massive frame inline to avoid loops + }else{ + current_batch_seq.push(...backtrack_seq); + current_h += backtrack_h; + const frame = document.createElement('RT·scroll-frame'); frame.style.display = 'block'; frame.style.overflowY = 'auto'; frame.style.maxHeight = page_height_limit + 'px'; frame.appendChild(el); - - current_batch_seq = backtrack_seq; - current_h = backtrack_h; - current_batch_seq.push(frame); i++; } @@ -433,13 +427,12 @@ continue; } - const h = getElHeight(el); - const is_RT_page_break = el.tagName && el.tagName.toLowerCase() === 'rt·page-break'; - const is_RT_page_break_primitive = el.tagName && el.tagName.toLowerCase() === 'rt·page-break-primitive'; + const h = get_el_height(el); + const tag = (el.tagName || '').toLowerCase(); + const is_RT_page_break = tag === 'rt·page-break' || tag === 'rt·page-break-primitive'; - // Explicit Page Break Logic - Execute immediately without backward traversal - if(is_RT_page_break || is_RT_page_break_primitive){ - if(current_batch_seq.length > 0){ + if(is_RT_page_break){ + if(current_h > 0){ page_seq.push(current_batch_seq); current_batch_seq = []; current_h = 0; @@ -448,27 +441,25 @@ continue; } - // Standard Dimension Overflow Logic - Check for orphaned headers - if( current_h + h > page_height_limit && current_batch_seq.length > 0 ){ + if(current_h + h > page_height_limit && current_h > 0){ let backtrack_seq = []; let backtrack_h = 0; while(current_batch_seq.length > 0){ const last = current_batch_seq[current_batch_seq.length - 1]; - if(!/^H[1-6]$/i.test(last.tagName)) break; + if(!last.tagName || !/^H[1-6]$/i.test(last.tagName)) break; const popped = current_batch_seq.pop(); backtrack_seq.unshift(popped); - backtrack_h += getElHeight(popped); + backtrack_h += get_el_height(popped); } - if(current_batch_seq.length > 0){ + if(current_h - backtrack_h > 0){ page_seq.push(current_batch_seq); current_batch_seq = backtrack_seq; current_h = backtrack_h; - } else { - // Document structure resolved entirely to sequential headings that breached bounds. - current_batch_seq = backtrack_seq; - current_h = backtrack_h; + }else{ + current_batch_seq.push(...backtrack_seq); + current_h += backtrack_h; } } @@ -483,8 +474,9 @@ article.innerHTML = ''; - // Inject global page counter initialization - const page_counter_make = document.createElement('rt·counter·make'); + global_makes.forEach(make => article.appendChild(make)); + + const page_counter_make = document.createElement('RT·counter·make'); page_counter_make.setAttribute('counter' ,'RT_page_number'); page_counter_make.setAttribute('style' ,'NaturalNumber'); page_counter_make.setAttribute('on-first-step' ,'1'); @@ -496,23 +488,32 @@ const batch = page_seq[p]; const page_el = document.createElement('RT·page'); + page_el.style.minHeight = page_height_limit + 'px'; + page_el.style.position = 'relative'; + page_el.style.paddingBottom = '5rem'; + page_el.style.boxSizing = 'border-box'; + batch.forEach(item => page_el.appendChild(item)); - // Inject step and snapshot tags into the page - const page_step = document.createElement('rt·counter·step'); + const page_step = document.createElement('RT·counter·step'); page_step.setAttribute('counter' ,'RT_page_number'); page_el.appendChild(page_step); const snapshot_name = `page_snap_${p + 1}`; - const page_snap = document.createElement('rt·counter·snapshot'); + const page_snap = document.createElement('RT·counter·snapshot'); page_snap.setAttribute('counter' ,'RT_page_number'); page_snap.setAttribute('snapshot' ,snapshot_name); page_el.appendChild(page_snap); - // Optional footer text injection reading the counter snapshot const page_footer = document.createElement('div'); page_footer.className = 'RT·page-footer'; - const page_read = document.createElement('rt·counter·read'); + page_footer.style.position = 'absolute'; + page_footer.style.bottom = '1.5rem'; + page_footer.style.left = '0'; + page_footer.style.width = '100%'; + page_footer.style.textAlign = 'center'; + + const page_read = document.createElement('RT·counter·read'); page_read.setAttribute('snapshot' ,snapshot_name); page_footer.appendChild(page_read); page_el.appendChild(page_footer); @@ -522,15 +523,14 @@ } } - Array.from(article_seq).forEach(article => paginateArticle(article)); + Array.from(article_seq).forEach(article => paginate_article(article)); - // Resolve footnotes inside the generated pages Array.from(article_seq).forEach(article => { - const rendered_pages = article.querySelectorAll('RT·page'); + const rendered_pages = article.querySelectorAll('RT·page, rt·page'); Array.from(rendered_pages).forEach(page => { const all_page_nodes = Array.from(page.querySelectorAll('*')); - const markers = all_page_nodes.filter(node => node.tagName.toLowerCase() === 'rt·fn-marker'); + const markers = all_page_nodes.filter(node => (node.tagName || '').toLowerCase() === 'rt·fn-marker'); if(markers.length === 0) return; @@ -563,19 +563,16 @@ }); }); - if(measureContainer && measureContainer.parentNode){ - measureContainer.remove(); - measureContainer = null; + if(measure_container && measure_container.parentNode){ + measure_container.remove(); + measure_container = null; } } - // ========================================================= - // PAGINATE 1: ABSORB DIMENSIONAL DELTA - // ========================================================= function paginate_1(){ if(debug.log) debug.log('paginate_1' ,'Adjusting final page heights after component injections'); - const rendered_pages = document.querySelectorAll('RT·page'); + const rendered_pages = document.querySelectorAll('RT·page, rt·page'); Array.from(rendered_pages).forEach(page => { const actual_height = page.scrollHeight; if(actual_height > page_height_limit){ @@ -584,12 +581,7 @@ }); } - //---------------------------------------- - // Registration upon load - // - window.RT.paginate_0 = paginate_0; window.RT.paginate_1 = paginate_1; - })();