class asciiTextFill extends Paged.Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } afterRendered(pages) { const PAD = 5; const chars = ["-", "+", "{", "[", "}", "]", ";", "<", ">"]; /* ── 1. Mesurer charW et lineH avec une pre cachée ── */ const probe = document.createElement('pre'); probe.style.cssText = [ 'position:absolute', 'visibility:hidden', 'top:0', 'left:0', 'font-family:"Courier New",monospace', 'font-size:9pt', 'line-height:1.5', 'white-space:pre' ].join(';'); probe.textContent = Array(10).fill('-'.repeat(100)).join('\n'); document.body.appendChild(probe); const pr = probe.getBoundingClientRect(); const charW = pr.width / 200; const lineH = pr.height / 20; document.body.removeChild(probe); /* ── 2. COLS = nb de caractères par ligne dans la zone imprimable ── */ const COLS = Math.floor(pages[0].width / charW); const DASH = '-'.repeat(COLS); /* ── 3. makeBox centré dans COLS ── */ function makeBox(lines, char) { const maxLen = Math.max(...lines.map(l => l.length)); const innerW = maxLen + PAD * 2; const border = '|' + char.repeat(innerW) + '|'; const empty = ' '.repeat(innerW + 2); const rows = lines.map(l => ' '.repeat(PAD) + l + ' '.repeat(innerW - PAD - l.length) ); const offset = Math.max(0, Math.floor((COLS - (innerW + 2)) / 10)); const sp = ' '.repeat(offset); return [sp + border, sp + empty, ...rows.map(r => sp + r), sp + empty, sp + border].join('\n'); } /* ── 4. Itérer sur chaque .chapter ── */ document.querySelectorAll('.chapter-title').forEach(titleEl => { let randomChar = chars[Math.floor(Math.random() * chars.length)]; const DASH = randomChar.repeat(COLS); if(titleEl){ const titleLinesH3 = Array.from(titleEl.querySelectorAll('h3')) .map(n => n.textContent.trim()).filter(Boolean); if (titleLinesH3.length) { // Supprimer les h2/h3 originaux titleEl.querySelectorAll('h3').forEach(el => el.remove()); const preH3 = document.createElement('pre'); preH3.textContent = makeBox(titleLinesH3, randomChar); // Insérer la boîte juste après fill-top const fillTop = titleEl.querySelector('.fill-top'); fillTop.insertAdjacentElement('afterend', preH3); } const titleLinesH2 = Array.from(titleEl.querySelectorAll('h2')) .map(n => n.textContent.trim()).filter(Boolean); if (titleLinesH2.length) { // Supprimer les h2/h3 originaux titleEl.querySelectorAll('h2').forEach(el => el.remove()); const pre = document.createElement('pre'); pre.textContent = makeBox(titleLinesH2, randomChar); // Insérer la boîte juste après fill-top const fillTop = titleEl.querySelector('.fill-top'); fillTop.insertAdjacentElement('afterend', pre); } const bioEl = titleEl.querySelector('.biographie'); if(bioEl){ const bioText = Array.from(bioEl.querySelectorAll('p')) .map(p => p.textContent.trim()).join(' '); const bioInnerW = COLS - 50; if (bioText) { const wrapped = []; let cur = ''; bioText.split(/\s+/).forEach(w => { const test = cur ? cur + ' ' + w : w; if (test.length <= bioInnerW) { cur = test; } else { if (cur) wrapped.push(cur); cur = w; } }); if (cur) wrapped.push(cur); const border = '|' + randomChar.repeat(bioInnerW) + '|'; const pre = document.createElement('pre'); pre.textContent = border + '\n\n' + wrapped.join('\n') + '\n\n' + border; bioEl.innerHTML = ''; bioEl.appendChild(pre); } } const totalH = pages[0].height; const fixedH = titleEl.offsetHeight; // const fixedH = (titleEl ? titleEl.offsetHeight : 0) + (bioEl ? bioEl.offsetHeight : 0); const spare = Math.max(0, totalH - fixedH); const ratios = [1/3, 1/3, 1/3]; const fills = ['.fill-top', '.fill-mid', '.fill-bottom']; fills.forEach((sel, i) => { const el = titleEl.querySelector(sel); if (!el) return; const n = Math.max(0, Math.floor((spare * ratios[i]) / lineH)); el.textContent = Array(n).fill(DASH).join('\n'); }); } }); // document.querySelectorAll('.chapter').forEach(chapter => { // // /* ── Titre : h2 + h3 dans .chapter-title ── */ // // const titleEl = chapter.querySelector('.chapter-title'); // // if(titleEl){ // // const titleLinesH3 = Array.from(titleEl.querySelectorAll('h3')) // // .map(n => n.textContent.trim()).filter(Boolean); // // if (titleLinesH3.length) { // // // Supprimer les h2/h3 originaux // // titleEl.querySelectorAll('h3').forEach(el => el.remove()); // // const preH3 = document.createElement('pre'); // // preH3.textContent = makeBox(titleLinesH3); // // // Insérer la boîte juste après fill-top // // const fillTop = titleEl.querySelector('.fill-top'); // // fillTop.insertAdjacentElement('afterend', preH3); // // } // // const titleLinesH2 = Array.from(titleEl.querySelectorAll('h2')) // // .map(n => n.textContent.trim()).filter(Boolean); // // if (titleLinesH2.length) { // // // Supprimer les h2/h3 originaux // // titleEl.querySelectorAll('h2').forEach(el => el.remove()); // // const pre = document.createElement('pre'); // // pre.textContent = makeBox(titleLinesH2); // // // Insérer la boîte juste après fill-top // // const fillTop = titleEl.querySelector('.fill-top'); // // fillTop.insertAdjacentElement('afterend', pre); // // } // // } // // /* ── Bio : .biographie dans ce chapter ── */ // // const bioEl = chapter.querySelector('.biographie'); // // if(bioEl){ // // const bioText = Array.from(bioEl.querySelectorAll('p')) // // .map(p => p.textContent.trim()).join(' '); // // const bioInnerW = COLS - 50; // // if (bioText) { // // const wrapped = []; // // let cur = ''; // // bioText.split(/\s+/).forEach(w => { // // const test = cur ? cur + ' ' + w : w; // // if (test.length <= bioInnerW) { cur = test; } // // else { if (cur) wrapped.push(cur); cur = w; } // // }); // // if (cur) wrapped.push(cur); // // const border = '|' + '-'.repeat(bioInnerW) + '|'; // // const pre = document.createElement('pre'); // // pre.textContent = border + '\n\n' + wrapped.join('\n') + '\n\n' + border; // // bioEl.innerHTML = ''; // // bioEl.appendChild(pre); // // } // // } // const totalH = pages[0].height; // // const fixedH = titleEl.offsetHeight + bioEl.offsetHeight; // const fixedH = (titleEl ? titleEl.offsetHeight : 0) + (bioEl ? bioEl.offsetHeight : 0); // const spare = Math.max(0, totalH - fixedH); // const ratios = [1/3, 1/3, 1/3]; // const fills = ['.fill-top', '.fill-mid', '.fill-bottom']; // fills.forEach((sel, i) => { // const spare = Math.max(0, totalH - fixedH); // const el = chapter.querySelector(sel); // if (!el) return; // const n = Math.max(0, Math.floor((spare * ratios[i]) / lineH)); // el.textContent = Array(n).fill(DASH).join('\n'); // }); // }); } } Paged.registerHandlers(asciiTextFill);