decor-6-expe/maquette-tests/csspageweaver/plugins/inlineNotes/inlineNotes.js

208 lines
5.8 KiB
JavaScript
Raw Normal View History

2026-02-23 11:35:07 +01:00
/**
* @name Inline Notes
* @author Julien Bidoret
* @author Julie Blanc <contact@julie-blanc.fr>
* @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);
2026-03-10 14:17:49 +01:00
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;
2026-02-23 11:35:07 +01:00
}
beforeParsed(content) {
inlineNotesHandler({
content: content,
input: this.input,
containerNotes: this.containerNotes,
type: this.newClass
});
2026-03-10 14:17:49 +01:00
let notesClass = "." + this.newClass;
resetCounter(content, this.reset, notesClass);
createCallandMarker(content, notesClass, this.newNotesClass);
2026-02-23 11:35:07 +01:00
}
}
function inlineNotesHandler(params){
let content = params.content;
let input = params.input;
let type = params.type;
2026-02-24 09:11:23 +01:00
createNotes(content, input, type);
2026-02-23 11:35:07 +01:00
2026-02-24 09:11:23 +01:00
let noteContainer = content.querySelector(params.containerNotes);
if(noteContainer){
2026-02-23 11:35:07 +01:00
noteContainer.remove();
2026-02-24 09:11:23 +01:00
}
2026-02-23 11:35:07 +01:00
}
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();
}
2026-03-10 14:17:49 +01:00
let inline_note = document.createElement('div');
2026-02-23 11:35:07 +01:00
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);
})
}
2026-03-10 14:17:49 +01:00
/// 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);
});
}