363 lines
12 KiB
JavaScript
363 lines
12 KiB
JavaScript
/**
|
|
* @file 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
|
|
* @author Originally developped by Julien Bidoret,Quentin Juhel and Julien Taquet,
|
|
* @author adapted for this project by Julie Blanc
|
|
* @see { @link https://gitlab.coko.foundation/pagedjs/pagedjs-plugins/booklet-imposition }
|
|
* @see { @link https://gitlab.com/csspageweaver/plugins/imposition/}
|
|
*/
|
|
|
|
import { Handler } from '/csspageweaver/lib/paged.esm.js';
|
|
|
|
export default class booklet extends Handler {
|
|
|
|
constructor(chunker, polisher, caller) {
|
|
super(chunker, polisher, caller);
|
|
this.pagedbooklet;
|
|
this.pagedspread;
|
|
this.sourceSize;
|
|
this.pageStart;
|
|
this.pageEnd;
|
|
}
|
|
|
|
afterRendered(pages) {
|
|
|
|
/* Launch when printing */
|
|
window.addEventListener("beforeprint", (evenement) => {
|
|
|
|
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 onePage = width + bleedNum*2;
|
|
|
|
// get values
|
|
let inputBooklet = document.querySelector("#input-booklet");
|
|
let inputSpread = document.querySelector("#input-spread");
|
|
let inputRange = document.querySelector("#imposition-range");
|
|
let inputBookletStart = document.querySelector("#booklet-start").value;
|
|
let inputBookletEnd = document.querySelector("#booklet-end").value;
|
|
|
|
let containerPages = document.querySelector(".pagedjs_pages");
|
|
|
|
|
|
|
|
if(inputBooklet.checked){
|
|
this.pagedbooklet = true;
|
|
this.pageStart = 1;
|
|
this.pageEnd = pages.length;
|
|
|
|
if(inputRange.checked){
|
|
this.pageStart = parseInt(inputBookletStart);
|
|
this.pageEnd = parseInt(inputBookletEnd);
|
|
}
|
|
}else if(inputSpread.checked){
|
|
this.pagedspread = true;
|
|
this.pageStart = 1;
|
|
this.pageEnd = pages.length;
|
|
|
|
if(inputRange.checked){
|
|
this.pageStart = parseInt(inputBookletStart);
|
|
this.pageEnd = parseInt(inputBookletEnd);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Delete pages we don't want*/
|
|
pages.forEach(page => {
|
|
let id = parseInt(page.id.replace('page-', ''));
|
|
if(id < this.pageStart || id > this.pageEnd){
|
|
let pageSelect = document.querySelector('#'+ page.id);
|
|
pageSelect.remove();
|
|
}
|
|
});
|
|
|
|
/* Reset page counter */
|
|
let reset = parseInt(this.pageStart) - 1;
|
|
containerPages.style.counterReset = "page " + reset;
|
|
|
|
|
|
|
|
|
|
// Add CSS to have pages in spread
|
|
//
|
|
// - change size of the page when printing (actually, sheet size)
|
|
// - flex properties
|
|
// - delete bleeds inside spread */
|
|
|
|
var newSize =
|
|
`@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_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;
|
|
}
|
|
.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;
|
|
}
|
|
|
|
`;
|
|
|
|
var twoPageView = `.pagedjs_page:nth-of-type(1){
|
|
bakground-color: red;
|
|
margin-left: ${spreadHalf}mm!important;
|
|
}`;
|
|
|
|
// Add style for the arrangement of the pages
|
|
|
|
if (this.pagedbooklet == true) {
|
|
let style = document.createElement("style");
|
|
style.textContent = newSize;
|
|
document
|
|
.head
|
|
.appendChild(style);
|
|
|
|
var number_of_pages = document.getElementsByClassName("pagedjs_page").length;
|
|
var pages_array = [];
|
|
|
|
// If the page count isn't a multiple of 4, we need to pad the array with blank
|
|
// pages so we have the correct number of pages for a booklet.
|
|
//
|
|
// ex. [1, 2, 3, 4, 5, 6, 7, 8, 9, blank, blank, blank]
|
|
|
|
let modulo = number_of_pages % 4;
|
|
let additional_pages = 0;
|
|
if (modulo != 0) {
|
|
additional_pages = 4 - modulo;
|
|
}
|
|
|
|
for (i = 0; i < additional_pages; i++) {
|
|
let added_page = document.createElement("div");
|
|
added_page
|
|
.classList
|
|
.add("pagedjs_page", "added");
|
|
added_page.id = `page-${this.pageEnd + i + 1}`;
|
|
document
|
|
.querySelector(".pagedjs_pages")
|
|
.appendChild(added_page);
|
|
}
|
|
|
|
// Push each page in the array
|
|
|
|
for (var i = number_of_pages + additional_pages; i >= 1; i--) {
|
|
pages_array.push(i);
|
|
}
|
|
|
|
|
|
// Split the array in half
|
|
//
|
|
// ex. [1, 2, 3, 4, 5, 6], [7, 8, 9, blank, blank, blank]
|
|
|
|
var split_start = pages_array.length / 2;
|
|
|
|
var split_end = pages_array.length;
|
|
|
|
var first_array = pages_array.slice(0, split_start);
|
|
var second_array = pages_array.slice(split_start, split_end);
|
|
|
|
// Reverse the second half of the array. This is the beginning of the back half
|
|
// of the booklet (from the center fold, back to the outside last page)
|
|
//
|
|
// ex. [blank, blank, blank, 9, 8, 7]
|
|
|
|
var second_array_reversed = second_array.reverse();
|
|
|
|
// Zip the two arrays together in groups of 2 These will end up being each '2-up
|
|
// side' of the final document So, the sub-array at index zero will be the first
|
|
// side of physical page one and index 1 will be the back side. However, they
|
|
// won't yet be in the proper order.
|
|
//
|
|
// ex. [[1, blank], [2, blank], [3, blank], [4, 9], [5, 8], [6, 7]]
|
|
|
|
var page_groups = [];
|
|
for (var i = 0; i < first_array.length; i++) {
|
|
page_groups[i] = [
|
|
first_array[i], second_array_reversed[i]
|
|
];
|
|
}
|
|
|
|
// We need to reverse every other sub-array starting with the first side. This
|
|
// is the final step of aligning our booklet pages in the order with which the
|
|
// booklet gets printed and bound.
|
|
//
|
|
// ex. [[blank, 1], [2, blank], [blank, 3], [4, 9], [8, 5], [6, 7]] final_groups
|
|
// = page_groups.each_with_index { |group, index| group.reverse! if (index %
|
|
// 2).zero? }
|
|
var final_groups = [];
|
|
for (var i = 0; i < page_groups.length; i++) {
|
|
var group = page_groups[i];
|
|
if (i % 2 != 0) {
|
|
final_groups[i] = page_groups[i].reverse();
|
|
} else {
|
|
final_groups[i] = page_groups[i];
|
|
}
|
|
}
|
|
console.log("Final Imposition Order: " + final_groups);
|
|
|
|
var allPages = document.querySelectorAll(".pagedjs_page");
|
|
|
|
var final_flat = final_groups.flat();
|
|
|
|
final_flat.forEach((folio, i) => {
|
|
folio = folio + reset;
|
|
document.querySelector(`#page-${folio}`).style.order = i;
|
|
});
|
|
}
|
|
|
|
|
|
if (this.pagedspread == true) {
|
|
console.log("double page view please");
|
|
let style = document.createElement("style");
|
|
style.textContent = newSize;
|
|
document
|
|
.head
|
|
.appendChild(style);
|
|
let styleBis = document.createElement("style");
|
|
styleBis.textContent = twoPageView;
|
|
document
|
|
.head
|
|
.appendChild(styleBis);
|
|
|
|
|
|
}
|
|
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 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;
|
|
};
|