367 lines
15 KiB
JavaScript
367 lines
15 KiB
JavaScript
// Imposition for booklet(s)
|
|
//
|
|
// This script re-arrange the pages of your document in order to make an imposed sheet layouts for printing.
|
|
// Two pages per sheet, double-sided
|
|
|
|
class Booklet extends Paged.Handler {
|
|
constructor(chunker, polisher, caller) {
|
|
super(chunker, polisher, caller);
|
|
this.pagedbooklet;
|
|
this.sourceSize;
|
|
this.pageStart;
|
|
this.pageEnd;
|
|
}
|
|
onAtPage(node, item, list) {}
|
|
onDeclaration(declaration, dItem, dList, rule) {
|
|
if (declaration.property == "--paged-layout") {
|
|
if (declaration.value.value.includes("booklet")) {
|
|
this.pagedbooklet = true;
|
|
let valuesBooklet = declaration.value.value.split(' ');
|
|
let index = valuesBooklet.indexOf("booklet");
|
|
|
|
/* Set first page of the imposition */
|
|
if(valuesBooklet[index + 1]){
|
|
this.pageStart = parseInt(valuesBooklet[index + 1]);
|
|
}else{
|
|
this.pageStart = 1;
|
|
}
|
|
|
|
/* Set last page of the imposition */
|
|
if(valuesBooklet[index + 2]){
|
|
this.pageEnd = parseInt(valuesBooklet[index + 2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
afterRendered(pages) {
|
|
|
|
/* Verify this.pageEnd */
|
|
if(!this.pageEnd){
|
|
let allPagesBefore = document.querySelectorAll(".pagedjs_page").length;
|
|
this.pageEnd = allPagesBefore;
|
|
}
|
|
|
|
/* Verify this.pageStart */
|
|
if(this.pageStart == 0){
|
|
this.pageStart = 1;
|
|
}else if(this.pageStart % 2 == 0){
|
|
this.pageStart = this.pageStart - 1;
|
|
}
|
|
|
|
|
|
// Bouton pour activer/désactiver l'imposition
|
|
const imposeButton = document.querySelector("#imposition-toggle");
|
|
let styleElement; // Variable pour stocker l'élément <style>
|
|
|
|
imposeButton.addEventListener("click", () => {
|
|
if (imposeButton.checked) {
|
|
imposeBooklet();
|
|
} else {
|
|
resetOrder();
|
|
}
|
|
});
|
|
|
|
function imposeBooklet() {
|
|
const allPages = Array.from(document.querySelectorAll(".pagedjs_page"));
|
|
const totalPages = allPages.length;
|
|
|
|
// Ajouter des pages vierges pour arriver à un multiple de 4
|
|
const pagesToAdd = (4 - (totalPages % 4)) % 4;
|
|
for (let i = 0; i < pagesToAdd; i++) {
|
|
const blankPage = document.createElement("div");
|
|
blankPage.classList.add("pagedjs_page", "blank");
|
|
blankPage.innerText = "Blank Page";
|
|
document.querySelector(".pagedjs_pages").appendChild(blankPage);
|
|
}
|
|
|
|
// Répartition des pages pour booklet
|
|
const pages = Array.from(document.querySelectorAll(".pagedjs_page"));
|
|
const totalBookletPages = pages.length;
|
|
|
|
const bookletOrder = [];
|
|
const half = totalBookletPages / 2;
|
|
|
|
for (let i = 0; i < half; i++) {
|
|
bookletOrder.push(totalBookletPages - i); // Dernière page
|
|
bookletOrder.push(i + 1); // Première page
|
|
}
|
|
|
|
// Réordonner les pages dans le DOM
|
|
bookletOrder.forEach((pageNumber, index) => {
|
|
const pageElement = document.querySelector(`#page-${pageNumber}`);
|
|
if (pageElement) {
|
|
pageElement.style.order = index; // Affecter un ordre CSS
|
|
}
|
|
});
|
|
|
|
// Injecter le CSS pour les styles booklet
|
|
injectCSS();
|
|
console.log("Booklet imposition completed.");
|
|
}
|
|
|
|
function resetOrder() {
|
|
// Réinitialiser l'ordre des pages
|
|
const allPages = document.querySelectorAll(".pagedjs_page");
|
|
allPages.forEach((page, index) => {
|
|
page.style.order = index; // Remettre à l'ordre initial
|
|
});
|
|
|
|
// Supprimer les styles injectés
|
|
removeCSS();
|
|
console.log("Order reset to default.");
|
|
}
|
|
|
|
function injectCSS() {
|
|
let format = document.querySelector(".pagedjs_page");
|
|
|
|
/* Width of page without bleed, extract the first number of calc() function */
|
|
let width = getCSSCustomProp("--pagedjs-width", format);
|
|
let numbers = width
|
|
.match(/[0-9]+/g)
|
|
.map(function (n) {
|
|
return + (n);
|
|
});
|
|
width = parseInt(numbers[0]);
|
|
|
|
/* Height of page with bleed, addition of all the numbers of calc() function*/
|
|
let height = getCSSCustomProp("--pagedjs-height", format);
|
|
numbers = height
|
|
.match(/[0-9]+/g)
|
|
.map(function (n) {
|
|
return + (n);
|
|
});
|
|
const reducer = (previousValue, currentValue) => previousValue + currentValue;
|
|
height = numbers.reduce(reducer);
|
|
|
|
/* Bleed of the page */
|
|
let bleed = getCSSCustomProp("--pagedjs-bleed-top", format);
|
|
let bleedNum = parseInt(bleed);
|
|
|
|
/* Spread and half-spread*/
|
|
let spread = width * 2 + bleedNum * 2;
|
|
|
|
let spreadHalf = width + bleedNum;
|
|
|
|
let numberOfPages = getCSSCustomProp("--pagedjs-page-count", format);
|
|
let halfNumberOfPages = numberOfPages / 2;
|
|
|
|
// Créer un élément <style> avec les styles CSS pour l'imposition
|
|
styleElement = document.createElement("style");
|
|
styleElement.textContent = `
|
|
@media print{
|
|
@page{
|
|
size: ${spread}mm ${height}mm;
|
|
}
|
|
pagedjs_pages {
|
|
width: auto;
|
|
}
|
|
}
|
|
@media screen{
|
|
.pagedjs_pages{
|
|
max-width: calc(var(--pagedjs-width) * 2);
|
|
}
|
|
}
|
|
.pagedjs_pages {
|
|
display: flex !important;
|
|
flex-wrap: wrap;
|
|
transform: none !important;
|
|
height: 100% !important;
|
|
min-height: 100%;
|
|
max-height: 100%;
|
|
overflow: visible;
|
|
}
|
|
|
|
.pagedjs_page {
|
|
margin: 0;
|
|
padding: 0;
|
|
max-height: 100%;
|
|
min-height: 100%;
|
|
height: 100% !important;
|
|
|
|
}
|
|
|
|
.pagedjs_sheet {
|
|
margin: 0;
|
|
padding: 0;
|
|
max-height: 100%;
|
|
min-height: 100%;
|
|
height: 100% !important;
|
|
}
|
|
body{
|
|
--pagedjs-bleed-right-left: 0mm;
|
|
}
|
|
|
|
.pagedjs_left_page{
|
|
z-index: 20;
|
|
width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width))!important;
|
|
}
|
|
|
|
.pagedjs_right_page {
|
|
left: 0;
|
|
}
|
|
|
|
.pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop {
|
|
border-color: transparent;
|
|
}
|
|
|
|
.pagedjs_right_page,
|
|
.pagedjs_right_page .pagedjs_sheet{
|
|
width: calc(var(--pagedjs-bleed-right-right) + var(--pagedjs-pagebox-width))!important;
|
|
}
|
|
|
|
.pagedjs_right_page .pagedjs_sheet{
|
|
grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] 1fr [bleed-right] var(--pagedjs-bleed-right-right);
|
|
}
|
|
|
|
/*.pagedjs_right_page .pagedjs_bleed-left{
|
|
display: none;
|
|
}*/
|
|
|
|
.pagedjs_right_page .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1),
|
|
.pagedjs_right_page .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1){
|
|
width: 0!important;
|
|
}
|
|
|
|
/* 10 dernières pages de droite (qui sont en réalité à gauche) */
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}){
|
|
left:0;
|
|
z-index: 10;
|
|
width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width))!important;
|
|
}
|
|
|
|
/*.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-right .pagedjs_marks-crop {
|
|
border-color: transparent;
|
|
}*/
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}),
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_sheet{
|
|
width: calc(var(--pagedjs-bleed-right-right) + var(--pagedjs-pagebox-width))!important;
|
|
}
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) {
|
|
z-index: 10;
|
|
position: relative;
|
|
left: 0;
|
|
}
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_sheet{
|
|
grid-template-columns: [bleed-left] var(--pagedjs-bleed-left) [sheet-center] calc(var(--pagedjs-width) - var(--pagedjs-bleed-left) - var(--pagedjs-bleed-right)) [bleed-right] var(--pagedjs-bleed-right);
|
|
}
|
|
/*.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-left{
|
|
display: none;
|
|
}*/
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1),
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1){
|
|
width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-stroke)) !important;
|
|
}
|
|
|
|
.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(1),.pagedjs_right_page:nth-child(n+${halfNumberOfPages}) .pagedjs_bleed-left .pagedjs_marks-crop:nth-child(3){
|
|
width: calc(var(--pagedjs-bleed-left-left) - var(--pagedjs-crop-stroke) - 5px) !important;
|
|
}
|
|
|
|
/* 10 premières pages de gauche (qui sont en réalité à droite) */
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}),
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_sheet{
|
|
width: calc(var(--pagedjs-bleed-right-right) + var(--pagedjs-pagebox-width))!important;
|
|
}
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) {
|
|
z-index: 10;
|
|
position: relative;
|
|
left: 0;
|
|
}
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_sheet{
|
|
grid-template-columns: [bleed-left] var(--pagedjs-bleed-right-left) [sheet-center] 1fr [bleed-right] var(--pagedjs-bleed-right-right);
|
|
}
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_bleed-left{
|
|
display: none;
|
|
}
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_bleed-top .pagedjs_marks-crop:nth-child(1),
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_bleed-bottom .pagedjs_marks-crop:nth-child(1){
|
|
width: 0!important;
|
|
}
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_bleed-left{
|
|
display: block;
|
|
}
|
|
|
|
.pagedjs_left_page:nth-child(-n+${halfNumberOfPages}) .pagedjs_bleed-right .pagedjs_marks-crop{
|
|
border-color: var(--pagedjs-crop-color);
|
|
}
|
|
|
|
.pagedjs_first_page {
|
|
margin-left: 0;
|
|
}
|
|
body{
|
|
margin: 0
|
|
}
|
|
.pagedjs_page:nth-of-type(even){
|
|
break-after: always;
|
|
}
|
|
.pagedjs_page,
|
|
.pagedjs_sheet{
|
|
width: ${spreadHalf - 0.1}mm!important;
|
|
}
|
|
|
|
`;
|
|
|
|
// Ajouter l'élément <style> au <head> du document
|
|
document.head.appendChild(styleElement);
|
|
|
|
}
|
|
|
|
function removeCSS() {
|
|
if (styleElement && styleElement.parentNode) {
|
|
styleElement.parentNode.removeChild(styleElement);
|
|
styleElement = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
Paged.registerHandlers(Booklet);
|
|
|
|
/**
|
|
* Pass in an element and its CSS Custom Property that you want the value of.
|
|
* Optionally, you can determine what datatype you get back.
|
|
*
|
|
* @param {String} propKey
|
|
* @param {HTMLELement} element=document.documentElement
|
|
* @param {String} castAs='string'
|
|
* @returns {*}
|
|
*/
|
|
const getCSSCustomProp = (
|
|
propKey,
|
|
element = document.documentElement,
|
|
castAs = "string"
|
|
) => {
|
|
let response = getComputedStyle(element).getPropertyValue(propKey);
|
|
|
|
// Tidy up the string if there's something to work with
|
|
if (response.length) {
|
|
response = response
|
|
.replace(/\'|"/g, "")
|
|
.trim();
|
|
}
|
|
|
|
// Convert the response into a whatever type we wanted
|
|
switch (castAs) {
|
|
case "number":
|
|
case "int":
|
|
return parseInt(response, 10);
|
|
case "float":
|
|
return parseFloat(response, 10);
|
|
case "boolean":
|
|
case "bool":
|
|
return response === "true" || response === "1";
|
|
}
|
|
|
|
// Return the string response by default
|
|
return response;
|
|
};
|