/** * @name Inline Notes * @author Julien Bidoret * @author Julie Blanc * @see { @link https://gitlab.com/csspageweaver/plugins/inlineNotes } */ import { Handler } from '/csspageweaver/lib/paged.esm.js'; export default class inlineNotes extends Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); const params = cssPageWeaver.features.inlineNotes.parameters; this.input = params?.input || ".footnote-ref"; // ← CSS selector of the call element this.containerNotes = params?.containerNotes || "#footnotes"; // ← CSS selector of the container of the footnote this.newClass = params?.newClass || "inline-note"; // ← Class of the span create for the note this.newNotesClass = params?.newNotesClass || "float-note"; this.reset = params?.reset; } beforeParsed(content) { inlineNotesHandler({ content: content, input: this.input, containerNotes: this.containerNotes, type: this.newClass }); let notesClass = "." + this.newClass; resetCounter(content, this.reset, notesClass); createCallandMarker(content, notesClass, this.newNotesClass); } } function inlineNotesHandler(params){ let content = params.content; let input = params.input; let type = params.type; createNotes(content, input, type); let noteContainer = content.querySelector(params.containerNotes); if(noteContainer){ noteContainer.remove(); } } function getBlocks(element){ return element.querySelectorAll('div,p,blockquote,section,article,h1,h2,h3,h4,h5,h6,figure'); } // get only inline-level tags function unwrapBlockChildren(element) { let blocks = getBlocks(element); blocks.forEach(block => { block.insertAdjacentHTML("beforebegin", block.innerHTML); block.remove(); }); let remainingblocks = getBlocks(element); if(remainingblocks.length) unwrapBlockChildren(element); return element; } function createNotes(content, input, type){ let calls = content.querySelectorAll(input); calls.forEach( (call, index) => { let href = call.getAttribute('href'); let hashIndex = href.indexOf('#'); let selector = href.slice(hashIndex); let note = content.querySelector(selector); if (!note) { console.warn('Note non trouvée pour', selector); return; } let back = note.querySelector(".footnote-back"); if(back){ back.remove(); } let inline_note = document.createElement('div'); inline_note.className = type; let num = index + 1; inline_note.dataset.counterNote = num; inline_note.innerHTML = unwrapBlockChildren(note).innerHTML; call.after(inline_note); call.parentElement.removeChild(call); }) } /// FUNCTIONS ----------------------------------------------------- // RESET COUNTER function resetCounter(content, reset, notesClass){ if(reset && reset != ""){ const elements = content.querySelectorAll(reset + ", " + notesClass); let resetEligible = false; elements.forEach(element => { if (element.matches(reset)) { resetEligible = true; } else if (resetEligible && element.matches(notesClass)) { element.dataset.resetCounterFollowingNote = true; resetEligible = false; } }); } } // CALL & MARKER function createCallandMarker(content, notesClass, newNotesClass){ let notes = content.querySelectorAll(notesClass); let resetNum = 0; notes.forEach(function (note, index) { if (note.dataset.resetCounterFollowingNote === "true") { resetNum = index; } let num = index + 1 - resetNum; note.classList.remove(...note.classList); note.classList.add(newNotesClass); note.dataset.counterNote = num; // call let ref_note = document.createElement('span'); ref_note.className = newNotesClass + "_call"; ref_note.dataset.counterNote = num; ref_note.innerHTML = num; // wrap preceding word + call in .wrapper__note-call let wrapper = document.createElement('span'); wrapper.className = 'wrapper__note-call'; let prevSibling = note.previousSibling; if (prevSibling && prevSibling.nodeType === Node.TEXT_NODE) { let text = prevSibling.textContent; let m = text.match(/^([\s\S]*\s)(\S+\s*)$/); if (m) { let before = m[1]; let extracted = m[2]; // Si le dernier mot extrait est uniquement », prendre aussi le mot d'avant if (/^»\s*$/.test(extracted)) { let m2 = before.trimEnd().match(/^([\s\S]*\s|)(\S+)$/); if (m2) { let spaceBetween = before.slice(m2[1].length + m2[2].length); before = m2[1]; extracted = m2[2] + spaceBetween + extracted; } } prevSibling.textContent = before; wrapper.appendChild(document.createTextNode(extracted)); } else { prevSibling.textContent = ''; wrapper.appendChild(document.createTextNode(text)); } } wrapper.appendChild(ref_note); note.before(wrapper); // marker + content note wrapped in float-note_body let marker_note = document.createElement('span'); marker_note.className = newNotesClass + "_marker"; //marker_note.innerHTML = num + ". "; marker_note.innerHTML = num; let noteBody = document.createElement('div'); noteBody.className = 'float-note_body'; while (note.firstChild) { noteBody.appendChild(note.firstChild); } note.appendChild(marker_note); note.appendChild(noteBody); }); }