lure-2026/public/csspageweaver/plugins/floatPage/floatPage.js

153 lines
4.6 KiB
JavaScript
Raw Normal View History

2026-01-10 18:33:22 +01:00
/**
* @name Float Page v1.0
* @author Julie Blanc <contact@julie-blanc.fr>
* @see { @link https://gitlab.com/csspageweaver/plugins/floatPage }
*/
import { Handler } from '/csspageweaver/lib/paged.esm.js';
export class floatPage extends Handler {
constructor(chunker, polisher, caller) {
super(chunker, polisher, caller);
this.selectorBottom = new Set();
this.selectorTop = new Set();
this.selectorNextPage = new Set();
this.nextPageElem = new Set();
this.nextPageElemTemp = new Set();
}
onDeclaration(declaration, dItem, dList, rule) {
// Read customs properties
if (declaration.property == "--pagedjs-float-page") {
// get selector of the declaration (NOTE: need csstree.js)
let selector = csstree.generate(rule.ruleNode.prelude);
// Push selector in correct set
if(declaration.value.value.includes("bottom")) {
this.selectorBottom.add(selector);
}else if(declaration.value.value.includes("top")) {
this.selectorTop.add(selector);
}else if(declaration.value.value.includes("next-page")) {
this.selectorNextPage.add(selector);
}
}
}
afterParsed(parsed){
// bottom
for (let item of this.selectorBottom) {
let elems = parsed.querySelectorAll(item);
for (let elem of elems) {
elem.classList.add("float-page_bottom");
}
}
// top
for (let item of this.selectorTop) {
let elems = parsed.querySelectorAll(item);
for (let elem of elems) {
elem.classList.add("float-page_top");
}
}
// next-page
for (let item of this.selectorNextPage) {
let elems = parsed.querySelectorAll(item);
for (let elem of elems) {
elem.classList.add("float-page_next-page");
}
}
}
afterPageLayout(pageElement, page, breakToken){
// TOP (positionning)
let floatTopPage = pageElement.querySelector(".float-page_top");
if(floatTopPage){
let selector = buildCssSelector(floatTopPage.parentNode);
parent = pageElement.querySelector(selector)
parent.insertBefore(floatTopPage, parent.firstChild);
}
//BOTTOM (positionning)
let floatBottomPage = pageElement.querySelector(".float-page_bottom");
if(floatBottomPage){
let selector = buildCssSelector(floatBottomPage.parentNode);
parent = pageElement.querySelector(selector);
parent.insertBefore(floatBottomPage, parent.firstChild);
floatBottomPage.style.position = "absolute";
floatBottomPage.style.bottom = "0px";
}
// NEXT PAGE (positionning into parent section)
for (let elem of this.nextPageElemTemp) {
let cleanedSelector = elem.parentSelector.replace(/^#document-fragment\s*>\s*/, '');
let parent = pageElement.querySelector(cleanedSelector);
let node = elem.elem;
if(parent){
parent.insertBefore(node, parent.firstChild);
}
}
this.nextPageElemTemp.clear();
}
// NEXTPAGE (pass to next page) -------------------
renderNode(clone, node) {
if (node.nodeType == 1 && node.classList.contains("float-page_next-page")) {
clone.remove();
this.nextPageElem.add({ elem: node, parentSelector: buildCssSelector(node.parentNode) });
}
}
onPageLayout(page, Token, layout) {
for (let elem of this.nextPageElem) {
page.insertBefore(elem.elem, page.firstChild);
this.nextPageElemTemp.add(elem);
}
this.nextPageElem.clear();
}
}
// FONCTIONS --------------------------------------------------------------------------
// Function to build the CSS selector from the element and its parents
function buildCssSelector(element) {
let selector = [];
let current = element;
while (current) {
if (current.classList && current.classList.contains('pagedjs_page_content')) {
break; // Stop if the parent with class 'pagedjs_page_content' is found
}
let currentSelector = current.nodeName.toLowerCase();
if (current.id) {
currentSelector += `[data-id="${current.id}"]`;
}
if (current.className) {
currentSelector += `.${current.className.split(' ').join('.')}`;
}
selector.unshift(currentSelector);
current = current.parentNode;
}
selector = selector.join(' > ');
// selector = selector.replace(/#document-fragment( > )?/g, ''); // Clean the CSS selector by removing '#document-fragment'
return selector;
}