let classNotes = "margin-note"; // ← Change the CLASS of the notes here let notesFloat = "outside"; // ← Change the POSITION of the notes here class marginNotes extends Paged.Handler { constructor(chunker, polisher, caller) { super(chunker, polisher, caller); } beforeParsed(content) { let notes = content.querySelectorAll("." + classNotes); for (let i = 0; i < notes.length; ++i) { // Add call notes var spanCall = document.createElement("span"); spanCall.classList.add("note-call"); spanCall.classList.add("note-call_" + classNotes); spanCall.dataset.noteCall = classNotes + '-' + i + 1; notes[i].parentNode.insertBefore(spanCall, notes[i]); // Add marker notes var spanMarker = document.createElement("span"); spanMarker.classList.add("note-marker"); spanMarker.classList.add("note-marker_" + classNotes); spanMarker.dataset.noteMarker = classNotes + '-' + i + 1; notes[i].prepend(spanMarker); // Hide notes to avoid rendering problems notes[i].style.display = "none"; } /* NOTE FLOAT ---------------------------------------------------------------------------------- */ let positionRight = 'left: calc(var(--pagedjs-pagebox-width) - var(--pagedjs-margin-left) - var(--pagedjs-margin-right) - 1px); width: var(--pagedjs-margin-right);'; let positionLeft = 'left: calc(var(--pagedjs-margin-left)*-1 - 1px); width: var(--pagedjs-margin-left);' let notePosition; switch (notesFloat) { case 'inside': notePosition = '.pagedjs_left_page .' + classNotes + '{' + positionRight + '} \ .pagedjs_right_page .' + classNotes + '{' + positionLeft + '}'; break; case 'left': notePosition = '.pagedjs_left_page .' + classNotes + '{' + positionLeft + '} \ .pagedjs_right_page .' + classNotes + '{' + positionLeft + '}'; break; case 'right': notePosition = '.pagedjs_left_page .' + classNotes + '{' + positionRight + '} \ .pagedjs_right_page .' + classNotes + '{' + positionRight + '}'; break; default: notePosition = '.pagedjs_left_page .' + classNotes + '{' + positionLeft + '} \ .pagedjs_right_page .' + classNotes + '{' + positionRight + '}'; } /* SPECIFIC CSS ---------------------------------------------------------------------------------- */ addcss('\ body {\ counter-reset: callNote_' + toCamelClassNote(classNotes) + ' markerNote_' + toCamelClassNote(classNotes) + ';\ }\ \ .' + classNotes + '{\ position: absolute;\ text-align-last: initial;\ box-sizing: border-box;\ }\ \ .note-call_' + classNotes + ' {\ counter-increment: callNote_' + toCamelClassNote(classNotes) + ';\ }\ \ .note-call_' + classNotes + '::after {\ content: counter(callNote_' + toCamelClassNote(classNotes) + ');\ }\ \ .note-marker_' + classNotes + ' {\ counter-increment: markerNote_' + toCamelClassNote(classNotes) + ';\ }\ .note-marker_' + classNotes + '::before {\ content: counter(markerNote_' + toCamelClassNote(classNotes) + ') ". ";\ }\ ' + notePosition); } /* end beforeParsed*/ afterPageLayout(pageElement, page, breakToken) { let notes = pageElement.querySelectorAll("." + classNotes); let noteOverflow = false; let notesHeightAll = []; if (typeof (notes) != 'undefined' && notes != null && notes.length != 0) { for (let n = 0; n < notes.length; ++n) { // Display notes of the page notes[n].style.display = "inline-block"; // Add height of the notes to array notesHeightAll let noteHeight = notes[n].offsetHeight; notesHeightAll.push(noteHeight); // Add margins of the notes to array notesHeightAll if (n >= 1) { let margins = biggestMargin(notes[n - 1], notes[n]); notesHeightAll.push(margins); } } /* FIT PAGE ------------------------------------------------------------------------------------- */ // Calculate if all notes fit on the page; let reducer = (accumulator, currentValue) => accumulator + currentValue; let allHeight = notesHeightAll.reduce(reducer); let maxHeight = pageElement.querySelectorAll(".pagedjs_page_content")[0].offsetHeight; if (allHeight > maxHeight) { /* IF DOESN'T FIT ----------------------------------------------------------------------------- */ // positions all the notes one after the other starting from the top notes[0].style.top = parseInt(window.getComputedStyle(notes[0]).marginBottom, 10) * -1 + "px"; for (let a = 1; a < notes.length; ++a) { let notePrev = notes[a - 1]; let newMargin = biggestMargin(notePrev, notes[a]); let newTop = notePrev.offsetTop + notePrev.offsetHeight - marginNoteTop(notes[a]) + newMargin; notes[a].style.top = newTop + "px"; } // alert let pageNumber = pageElement.dataset.pageNumber; alert("Rendering issue \n ☞ A marginal note overflow on page " + pageNumber + " (this is because there is too many on this page and paged.js can't breaks notes between pages for now.)"); noteOverflow = true; } else { /* PUSH DOWN ---------------------------------------------------- */ for (let i = 0; i < notes.length; ++i) { if (i >= 1) { let noteTop = notes[i].offsetTop; let notePrev = notes[i - 1]; let newMargin = biggestMargin(notes[i], notePrev); let notePrevBottom = notePrev.offsetTop - marginNoteTop(notePrev) + notePrev.offsetHeight + newMargin; // Push down the note to bottom if it's over the previous one if (notePrevBottom > noteTop) { notes[i].style.top = notePrevBottom + "px"; } } } /* PUSH UP ---------------------------------------------- */ // Height of the page content let contentHeight = pageElement.querySelectorAll(".pagedjs_page_content")[0].querySelectorAll("div")[0].offsetHeight; // Check if last note overflow let nbrLength = notes.length - 1; let lastNote = notes[nbrLength]; let lastNoteHeight = lastNote.offsetHeight + marginNoteTop(lastNote); let noteBottom = lastNote.offsetTop + lastNoteHeight; if (noteBottom > contentHeight) { // Push up the last note lastNote.style.top = contentHeight - lastNoteHeight + "px"; // Push up previous note(s) if if it's over the note for (let i = nbrLength; i >= 1; --i) { let noteLastTop = notes[i].offsetTop; let notePrev = notes[i - 1]; let notePrevHeight = notePrev.offsetHeight; let newMargin = biggestMargin(notePrev, notes[i]); let notePrevBottom = notePrev.offsetTop + notePrev.offsetHeight + newMargin; if (notePrevBottom > noteLastTop) { notePrev.style.top = notes[i].offsetTop - marginNoteTop(notePrev) - notePrevHeight - newMargin + "px"; } } } /* end push up */ } } }/* end afterPageLayout*/ } Paged.registerHandlers(marginNotes); /* FUNCTIONS -------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------- */ // MARGINS function marginNoteTop(elem) { let marginTop = parseInt(window.getComputedStyle(elem).marginTop, 10) return marginTop; } function marginNoteBottom(elem) { let marginBottom = parseInt(window.getComputedStyle(elem).marginBottom, 10) return marginBottom; } function biggestMargin(a, b) { let margin; let marginBottom = marginNoteBottom(a); let marginTop = marginNoteTop(b); if (marginBottom > marginTop) { margin = marginBottom; } else { margin = marginTop; } return margin; } // ADD CSS function addcss(css) { var head = document.getElementsByTagName('head')[0]; var s = document.createElement('style'); s.setAttribute('type', 'text/css'); if (s.styleSheet) { // IE s.styleSheet.cssText = css; } else {// the world s.appendChild(document.createTextNode(css)); } head.appendChild(s); } // CAMEL CLASS NOTE function toCamelClassNote(elem) { let splitClass = elem.split("-"); if (splitClass.length > 1) { for (let s = 1; s < splitClass.length; ++s) { let strCapilize = splitClass[s].charAt(0).toUpperCase() + splitClass[s].slice(1) splitClass[s] = strCapilize; } } let reducer = (accumulator, currentValue) => accumulator + currentValue; let classCamel = splitClass.reduce(reducer); return classCamel; }