...
 
Commits (7)
This diff is collapsed.
const TIMEOUT = 10000;
describe("footnotes", () => {
let page;
beforeAll(async () => {
page = await loadPage("notes/footnotes-lastpage/footnotes-lastpage.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
it("should render 6 pages", async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => {
return r.length;
});
expect(pages).toEqual(6);
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(2);
expect(pdf).toMatchPDFSnapshot(3);
expect(pdf).toMatchPDFSnapshot(4);
expect(pdf).toMatchPDFSnapshot(5);
expect(pdf).toMatchPDFSnapshot(6);
});
}
}
);
This diff is collapsed.
const TIMEOUT = 10000;
describe("footnotes", () => {
let page;
beforeAll(async () => {
page = await loadPage("notes/footnotes-padding/footnotes-padding.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
it("should render 14 pages", async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => {
return r.length;
});
expect(pages).toEqual(14);
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(2);
expect(pdf).toMatchPDFSnapshot(7);
expect(pdf).toMatchPDFSnapshot(8);
});
}
}
);
This diff is collapsed.
const TIMEOUT = 10000;
describe("footnotes", () => {
let page;
beforeAll(async () => {
page = await loadPage("notes/footnotes/footnotes.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
it("should render 14 pages", async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => {
return r.length;
});
expect(pages).toEqual(14);
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(2);
expect(pdf).toMatchPDFSnapshot(3);
expect(pdf).toMatchPDFSnapshot(4);
});
}
}
);
......@@ -74,6 +74,11 @@ const TEMPLATE = `
</div>
<div class="pagedjs_area">
<div class="pagedjs_page_content"></div>
<div class="pagedjs_footnote_area">
<div class="pagedjs_footnote_content">
<div class="pagedjs_footnote_inner_content"></div>
</div>
</div>
</div>
</div>
</div>
......@@ -265,7 +270,7 @@ class Chunker {
}
}
async handleBreaks(node) {
async handleBreaks(node, force) {
let currentPage = this.total + 1;
let currentPosition = currentPage % 2 === 0 ? "left" : "right";
// TODO: Recto and Verso should reverse for rtl languages
......@@ -290,7 +295,9 @@ class Chunker {
breakBefore = node.dataset.breakBefore;
}
if( previousBreakAfter &&
if (force) {
page = this.addPage(true);
} else if( previousBreakAfter &&
(previousBreakAfter === "left" || previousBreakAfter === "right") &&
previousBreakAfter !== currentPosition) {
page = this.addPage(true);
......@@ -485,7 +492,28 @@ class Chunker {
}
*/
async clonePage(originalPage) {
let lastPage = this.pages[this.pages.length - 1];
let page = new Page(this.pagesArea, this.pageTemplate, false, this.hooks);
this.pages.push(page);
// Create the pages
page.create(undefined, lastPage && lastPage.element);
page.index(this.total);
await this.hooks.beforePageLayout.trigger(page, undefined, undefined, this);
this.emit("page", page);
for (const className of originalPage.element.classList) {
page.element.classList.add(className);
}
await this.hooks.afterPageLayout.trigger(page.element, page, undefined, this);
this.emit("renderedPage", page);
}
loadFonts() {
let fontPromises = [];
......
......@@ -14,7 +14,8 @@ import {
needsPageBreak,
needsPreviousBreakAfter,
nodeAfter,
displayedElementBefore, previousSignificantNode,
nodeBefore,
previousSignificantNode,
prevValidNode,
rebuildAncestors,
validNode,
......@@ -452,7 +453,7 @@ class Layout {
isFloat = styles.getPropertyValue("float") !== "none";
skip = styles.getPropertyValue("break-inside") === "avoid";
breakAvoid = node.dataset.breakBefore === "avoid" || node.dataset.previousBreakAfter === "avoid";
prev = breakAvoid && displayedElementBefore(node, rendered);
prev = breakAvoid && nodeBefore(node);
br = node.tagName === "BR" || node.tagName === "WBR";
}
......
......@@ -36,6 +36,7 @@ class Page {
let pagebox = page.querySelector(".pagedjs_pagebox");
let area = page.querySelector(".pagedjs_page_content");
let footnotesArea = page.querySelector(".pagedjs_footnote_area");
let size = area.getBoundingClientRect();
......@@ -51,6 +52,7 @@ class Page {
this.element = page;
this.pagebox = pagebox;
this.area = area;
this.footnotesArea = footnotesArea;
return page;
}
......
......@@ -40,7 +40,8 @@ class AtPage extends Handler {
bottom: {}
},
block: {},
marks: undefined
marks: undefined,
notes: undefined
};
}
......@@ -84,6 +85,9 @@ class AtPage extends Handler {
page.marginalia = marginalia;
}
let notes = this.replaceNotes(node);
page.notes = notes;
let declarations = this.replaceDeclarations(node);
if (declarations.size) {
......@@ -193,15 +197,15 @@ class AtPage extends Handler {
let bleedrecto = undefined;
if (":left" in this.pages) {
bleedverso = this.pages[":left"].bleed;
}
bleedverso = this.pages[":left"].bleed;
}
if (":right" in this.pages) {
bleedrecto = this.pages[":right"].bleed;
}
if (":right" in this.pages) {
bleedrecto = this.pages[":right"].bleed;
}
if ((width && height) &&
(this.width !== width || this.height !== height)) {
(this.width !== width || this.height !== height)) {
this.width = width;
this.height = height;
this.format = format;
......@@ -264,25 +268,49 @@ class AtPage extends Handler {
replaceMarginalia(ast) {
let parsed = {};
const MARGINS = [
"top-left-corner", "top-left", "top", "top-center", "top-right", "top-right-corner",
"bottom-left-corner", "bottom-left", "bottom", "bottom-center", "bottom-right", "bottom-right-corner",
"left-top", "left-middle", "left", "left-bottom", "top-right-corner",
"right-top", "right-middle", "right", "right-bottom", "right-right-corner"
];
csstree.walk(ast.block, {
visit: "Atrule",
enter: (node, item, list) => {
let name = node.name;
if (name === "top") {
name = "top-center";
}
if (name === "right") {
name = "right-middle";
}
if (name === "left") {
name = "left-middle";
if (MARGINS.includes(name)) {
if (name === "top") {
name = "top-center";
}
if (name === "right") {
name = "right-middle";
}
if (name === "left") {
name = "left-middle";
}
if (name === "bottom") {
name = "bottom-center";
}
parsed[name] = node.block;
list.remove(item);
}
if (name === "bottom") {
name = "bottom-center";
}
});
return parsed;
}
replaceNotes(ast) {
let parsed = {};
csstree.walk(ast.block, {
visit: "Atrule",
enter: (node, item, list) => {
let name = node.name;
if (name === "footnote") {
parsed[name] = node.block;
list.remove(item);
}
parsed[name] = node.block;
list.remove(item);
}
});
......@@ -607,6 +635,10 @@ class AtPage extends Handler {
this.addMarginaliaContent(page, ruleList, rule, sheet);
}
if(page.notes) {
this.addNotesStyles(page.notes, page, ruleList, rule, sheet);
}
return rule;
}
......@@ -895,7 +927,7 @@ class AtPage extends Handler {
bleedLeftVerso = this.createVariable("--pagedjs-bleed-left-left", CSSValueToString(bleedverso.left));
widthStringLeft = `calc( ${CSSValueToString(width)} + ${CSSValueToString(bleedverso.left)} + ${CSSValueToString(bleedverso.right)} )`;
heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedverso.top)} + ${CSSValueToString(bleedverso.bottom)} )`;
heightStringLeft = `calc( ${CSSValueToString(height)} + ${CSSValueToString(bleedverso.top)} + ${CSSValueToString(bleedverso.bottom)} )`;
}
let pageWidthVar = this.createVariable("--pagedjs-width", CSSValueToString(width));
......@@ -955,6 +987,29 @@ class AtPage extends Handler {
ast.children.appendData(rule);
}
addNotesStyles(notes, page, list, item, sheet) {
for (const note in notes) {
let selectors = this.selectorsForPage(page);
selectors.insertData({
type: "Combinator",
name: " "
});
selectors.insertData({
type: "ClassSelector",
name: "pagedjs_" + note + "_content"
});
let notesRule = this.createRule(selectors, notes[note]);
list.appendData(notesRule);
}
}
/*
@page {
size: var(--pagedjs-width) var(--pagedjs-height);
......
......@@ -19,7 +19,8 @@ class Counters extends Handler {
}
} else if (property === "counter-reset") {
let reset = this.handleReset(declaration, rule);
if (reset) {
if (reset && reset.selector.includes("pagedjs_") === false) {
dList.remove(dItem);
}
}
......@@ -80,8 +81,19 @@ class Counters extends Handler {
let number = declaration.value.children.getSize() > 1
&& declaration.value.children.last().value;
let name = identifier && identifier.name;
let selector = csstree.generate(rule.ruleNode.prelude);
let counter;
let selector;
let prelude = rule.ruleNode.prelude;
if (rule.ruleNode.type === "Atrule" && rule.ruleNode.name === "page") {
selector = ".pagedjs_page";
} else {
selector = csstree.generate(prelude || rule.ruleNode);
}
if (name === "footnote") {
this.addFootnoteMarkerCounter(declaration.value.children);
}
if (!(name in this.counters)) {
counter = this.addCounter(name);
......@@ -111,7 +123,7 @@ class Counters extends Handler {
countersArray.push(`${counters[c].name} 0`);
}
// Add to pages to allow cross page scope
this.insertRule(`.pagedjs_pages { counter-reset: ${countersArray.join(" ")}}`);
this.insertRule(`.pagedjs_pages { counter-reset: ${countersArray.join(" ")} pages var(--pagedjs-page-count) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-count)}`);
}
insertRule(rule) {
......@@ -155,7 +167,7 @@ class Counters extends Handler {
let increment, reset;
let resetValue, incrementValue, resetDelta;
let incrementArray;
for (var i = 0; i < elements.length; i++) {
element = elements[i];
resetDelta = 0;
......@@ -191,6 +203,41 @@ class Counters extends Handler {
}
}
addFootnoteMarkerCounter(list) {
let markers = [];
csstree.walk(list, {
visit: "Identifier",
enter: (identNode, iItem, iList) => {
markers.push(identNode.name);
}
});
// Already added
if (markers.includes("footnote-maker")) {
return;
}
list.insertData({
type: "WhiteSpace",
value: " "
});
list.insertData({
type: "Identifier",
name: "footnote-marker"
});
list.insertData({
type: "WhiteSpace",
value: " "
});
list.insertData({
type: "Number",
value: 0
});
}
incrementCounterForElement(element, incrementArray) {
if (!element || !incrementArray || incrementArray.length === 0) return;
......@@ -216,9 +263,15 @@ class Counters extends Handler {
afterPageLayout(pageElement, page) {
let pgreset = pageElement.querySelectorAll("[data-counter-page-reset]");
pgreset.forEach((reset) => {
let value = reset.datasetCounterPageReset;
let value = reset.dataset.counterPageReset - 1; // subtract the current page increment
this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] { counter-reset: page ${value} }`, this.styleSheet.cssRules.length);
});
let notereset = pageElement.querySelectorAll("[data-counter-footnote-reset]");
notereset.forEach((reset) => {
let value = reset.dataset.counterFootnoteReset;
this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] .pagedjs_area { counter-reset: footnote ${value} footnote-marker ${value} }`, this.styleSheet.cssRules.length);
});
}
}
......
This diff is collapsed.
......@@ -5,6 +5,7 @@ import Splits from "./splits";
import Counters from "./counters";
import Lists from "./lists";
import PositionFixed from "./position-fixed";
import Footnotes from "./footnotes";
export default [
AtPage,
......@@ -13,5 +14,6 @@ export default [
Splits,
Counters,
Lists,
PositionFixed
PositionFixed,
Footnotes
];
......@@ -8,6 +8,7 @@ export default `
--pagedjs-height-left: 11in;
--pagedjs-pagebox-width: 8.5in;
--pagedjs-pagebox-height: 11in;
--pagedjs-footnotes-height: 0mm;
--pagedjs-margin-top: 1in;
--pagedjs-margin-right: 1in;
--pagedjs-margin-bottom: 1in;
......@@ -35,6 +36,7 @@ export default `
--pagedjs-mark-cross-display: none;
--pagedjs-mark-crop-display: none;
--pagedjs-page-count: 0;
--pagedjs-footnotes-count: 0;
}
@page {
......@@ -358,17 +360,65 @@ export default `
grid-row: page;
width: 100%;
height: 100%;
padding: var(--pagedjs-padding-top) var(--pagedjs-padding-right) var(--pagedjs-padding-bottom) var(--pagedjs-padding-left)
padding: var(--pagedjs-padding-top) var(--pagedjs-padding-right) var(--pagedjs-padding-bottom) var(--pagedjs-padding-left)
}
.pagedjs_pagebox > .pagedjs_area > .pagedjs_page_content {
width: 100%;
height: 100%;
height: calc(100% - var(--pagedjs-footnotes-height));
position: relative;
column-fill: auto;
}
.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area {
position: relative;
overflow: hidden;
height: var(--pagedjs-footnotes-height);
}
.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_content {
overflow: hidden;
}
.pagedjs_pagebox > .pagedjs_area > .pagedjs_footnote_area > .pagedjs_footnote_inner_content {
overflow: hidden;
}
.pagedjs_area [data-footnote-call] {
counter-increment: footnote;
}
.pagedjs_area [data-split-from] {
counter-increment: unset;
counter-reset: unset;
}
.pagedjs_area [data-footnote-call]::after {
content: counter(footnote);
vertical-align: super;
font-size: 65%;
}
@supports ( font-variant-position: super ) {
.pagedjs_area [data-footnote-call]::after {
content: counter(footnote);
vertical-align: baseline;
font-size: 100%;
line-height: inherit;
font-variant-position: super;
}
}
.pagedjs_area [data-footnote-marker]:not([data-split-from]) {
counter-increment: footnote-marker;
text-indent: 0;
display: block;
}
.pagedjs_area [data-footnote-marker]:not([data-split-from])::before {
content: counter(footnote-marker) ". ";
}
.pagedjs_page {
counter-increment: page;
width: var(--pagedjs-width);
......@@ -388,7 +438,7 @@ export default `
}
.pagedjs_pages {
counter-reset: pages var(--pagedjs-page-count);
counter-reset: pages var(--pagedjs-page-count) footnote var(--pagedjs-footnotes-count) footnote-marker var(--pagedjs-footnotes-count);
}
......@@ -517,13 +567,13 @@ export default `
margin: unset;
}
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:after,
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]::after {
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:not([data-footnote-call]):after,
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-to]:not([data-footnote-call])::after {
content: unset;
}
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:before,
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]::before {
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call]):before,
.pagedjs_pages > .pagedjs_page > .pagedjs_sheet > .pagedjs_pagebox > .pagedjs_area > div [data-split-from]:not([data-footnote-call])::before {
content: unset;
}
......