Commit 5dadba71 authored by Fred Chasen's avatar Fred Chasen

Merge branch 'update_target_counters' into 'master'

Update target counters

Closes #74

See merge request tools/pagedjs!32
parents ee171cbb f88af9d5
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>
Reset counter page
</title>
<script src="../../../dist/paged.polyfill.js"></script>
<style>
:root{
font-size: 18px;
}
@page {
size: 6in 8in;
margin: 20mm 20mm;
}
@page frontmatter {
@bottom-right {
content: counter(page, lower-roman);
}
}
@page main {
@top-right {
content: counter(page);
}
}
/* @page main:first {
counter-reset: page;
} */
.front-matter, .toc {
page: frontmatter;
}
.chapter {
page: main;
}
#first-chapter {
counter-reset: page 1;
}
p {
line-height: 22px;
}
h1 {
font-size: 24px;
margin-top: 0;
}
a {
text-decoration: none;
color: currentColor;
}
nav a::after {
content: target-counter(attr(href), page);
float: right;
}
nav a.roman::after {
float: right;
content: target-counter(attr(href), page, lower-roman);
}
</style>
<style>
/* interface */
@media screen {
body {
background: whitesmoke;
}
.pagedjs_page {
background: white;
margin-bottom: 10px;
box-shadow: 0 0 0 1px rgba(0, 0,0,0.2);
}
.pagedjs_pages {
width: calc(var(--width) * 2);
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-start;
margin: 0 auto;
}
.pagedjs_first_page {
margin-left: 50%;
}
}
</style>
</head>
<body>
<section class="front-matter" id="foreword">
<h1>Foreword</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eros sapien, iaculis eget
egestas eu, tempus eu tellus. Aliquam in facilisis sapien. Nulla blandit, ligula vel auctor
facilisis, quam felis rhoncus arcu, non rhoncus nulla felis sed est. Pellentesque ac velit
arcu, placerat dignissim augue. Nulla vitae tortor in elit ultrices dictum. Quisque eget
massa at nisl malesuada sodales sed id est. Pellentesque vehicula venenatis justo, sit amet
vehicula leo laoreet eget. Donec vel urna quis metus feugiat vulputate eget ut urna. In
tristique semper diam ut adipiscing. Fusce sagittis congue purus scelerisque hendrerit.
Donec sit amet interdum massa.</p>
</section>
<section class="toc" id="TOC">
<nav>
<h1>Table of contents</h1>
<ul>
<li><a id="toc-preface" href="#preface" class="roman">Preface</a></li>
<li><a id="toc-first-chapter" href="#first-chapter">First Chapter</a></li>
<li><a href="#second-chapter">Second Chapter</a></li>
</ul>
</nav>
</section>
<section class="front-matter" id="preface">
<h1>Preface</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eros sapien, iaculis eget
egestas eu, tempus eu tellus. Aliquam in facilisis sapien. Nulla blandit, ligula vel auctor
facilisis, quam felis rhoncus arcu, non rhoncus nulla felis sed est. Pellentesque ac velit
arcu, placerat dignissim augue. Nulla vitae tortor in elit ultrices dictum. Quisque eget
massa at nisl malesuada sodales sed id est. Pellentesque vehicula venenatis justo, sit amet
vehicula leo laoreet eget. Donec vel urna quis metus feugiat vulputate eget ut urna. In
tristique semper diam ut adipiscing. Fusce sagittis congue purus scelerisque hendrerit.
Donec sit amet interdum massa.</p>
</section>
<section class="chapter" id="first-chapter">
<h1>First Chapter</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eros sapien, iaculis eget
egestas eu, tempus eu tellus. Aliquam in facilisis sapien. Nulla blandit, ligula vel auctor
facilisis, quam felis rhoncus arcu, non rhoncus nulla felis sed est. Pellentesque ac velit
arcu, placerat dignissim augue. Nulla vitae tortor in elit ultrices dictum. Quisque eget
massa at nisl malesuada sodales sed id est. Pellentesque vehicula venenatis justo, sit amet
vehicula leo laoreet eget. Donec vel urna quis metus feugiat vulputate eget ut urna. In
tristique semper diam ut adipiscing. Fusce sagittis congue purus scelerisque hendrerit.
Donec sit amet interdum massa.</p>
</section>
<section class="chapter" id="second-chapter">
<h1>Second Chapter</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eros sapien, iaculis eget
egestas eu, tempus eu tellus. Aliquam in facilisis sapien. Nulla blandit, ligula vel auctor
facilisis, quam felis rhoncus arcu, non rhoncus nulla felis sed est. Pellentesque ac velit
arcu, placerat dignissim augue. Nulla vitae tortor in elit ultrices dictum. Quisque eget
massa at nisl malesuada sodales sed id est. Pellentesque vehicula venenatis justo, sit amet
vehicula leo laoreet eget. Donec vel urna quis metus feugiat vulputate eget ut urna. In
tristique semper diam ut adipiscing. Fusce sagittis congue purus scelerisque hendrerit.
Donec sit amet interdum massa.</p>
</section>
</body>
</html>
const TIMEOUT = 10000;
describe('roman-numerals', async () => {
let page;
let rendered;
beforeAll(async () => {
page = await loadPage('issues/roman-numerals/roman-numerals.html')
return page.rendered;
}, TIMEOUT)
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
})
it('should render 5 pages', async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => {
return r.length;
});
console.log("pages", pages)
expect(pages).toEqual(5);
})
it('Preface should be in Roman numerals', async () => {
let text = await page.$eval("#toc-preface", (r) => window.getComputedStyle(r, '::after').content);
expect(text).toContain("lower-roman");
})
it('First Chapter should be 1', async () => {
let text = await page.$eval("#toc-first-chapter", (r) => window.getComputedStyle(r, '::after').content);
expect(text).toContain("counter(target-counter");
})
if (!DEBUG) {
it('should create a pdf', async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(4);
})
}
}
)
......@@ -45,15 +45,26 @@ class PuppeteerEnvironment extends NodeEnvironment {
async loadPage(path) {
let page = await this.global.browser.newPage();
page.addListener('pageerror', this.handleError);
page.addListener('error', this.handleError);
let renderedResolve, renderedReject;
page.rendered = new Promise(function(resolve, reject) {
renderedResolve = resolve;
renderedReject = reject;
});
page.addListener('pageerror', (error) => {
this.handleError(error);
renderedReject(error);
});
page.addListener('error', (error) => {
this.handleError(error);
renderedReject(error);
});
// await page.exposeFunction('PuppeteerLogger', (msg, counter) => {
// console.log(msg, counter);
// });
await page.exposeFunction('onPagesRendered', (msg, width, height, orientation) => {
renderedResolve(msg, width, height, orientation);
});
......
......@@ -29,11 +29,21 @@ class TargetCounters extends Handler {
});
let counter;
if (last !== first) {
counter = last.name;
}
let style;
let styleIdentifier;
funcNode.children.forEach((child) => {
if (child.type === "Identifier") {
if (!counter) {
counter = child.name;
} else if (!style) {
styleIdentifier = csstree.clone(child);
style = child.name;
}
}
})
let variable = "--" + UUID();
let variable = "target-counter-" + UUID();
selector.split(",").forEach((s) => {
this.counterTargets[s] = {
......@@ -41,20 +51,25 @@ class TargetCounters extends Handler {
args: args,
value: value,
counter: counter,
style: style,
selector: s,
fullSelector: selector,
variable: variable
}
});
// Replace with variable
funcNode.name = "var";
// Replace with counter
funcNode.name = "counter";
funcNode.children = new csstree.List()
funcNode.children.appendData({
type: "Identifier",
loc: 0,
name: variable
});
if (styleIdentifier) {
funcNode.children.appendData({type: "Operator", loc: null, value: ","});
funcNode.children.appendData(styleIdentifier);
}
}
}
......@@ -63,7 +78,8 @@ class TargetCounters extends Handler {
let target = this.counterTargets[name];
let split = target.selector.split("::");
let query = split[0];
let queried = chunker.pagesArea.querySelectorAll(query + ":not([data-target-counter])");
let queried = chunker.pagesArea.querySelectorAll(query + ":not([data-" + target.variable + "])");
queried.forEach((selected, index) => {
// TODO: handle func other than attr
......@@ -75,13 +91,20 @@ class TargetCounters extends Handler {
if (element) {
let selector = UUID();
selected.setAttribute("data-target-counter", selector);
selected.setAttribute("data-" + target.variable, selector);
// TODO: handle other counter types (by query)
if (target.counter === "page") {
let pages = chunker.pagesArea.querySelectorAll(".pagedjs_page");
let pg = 0;
for (var i = 0; i < pages.length; i++) {
let styles = window.getComputedStyle(pages[i]);
let reset = styles["counter-reset"].replace("page", "").trim();
if (reset !== "none") {
pg = parseInt(reset);
}
pg += 1;
if (pages[i].contains( element )){
break;
}
......@@ -92,8 +115,12 @@ class TargetCounters extends Handler {
psuedo += "::" + split[1];
}
// this.styleSheet.insertRule(`[data-target-counter="${selector}"]${psuedo} { content: "${pg}"; }`, this.styleSheet.cssRules.length);
this.styleSheet.insertRule(`[data-target-counter="${selector}"]${psuedo} { ${target.variable}: "${pg}" }`, this.styleSheet.cssRules.length);
this.styleSheet.insertRule(`[data-${target.variable}="${selector}"] { counter-increment: ${target.variable} ${pg}; }`, this.styleSheet.cssRules.length);
} else {
let value = element.getAttribute(`data-counter-${target.counter}-value`);
if (value) {
this.styleSheet.insertRule(`[data-${target.variable}="${selector}"] { counter-increment: ${target.variable} ${parseInt(value)}; }`, this.styleSheet.cssRules.length);
}
}
}
});
......
......@@ -790,6 +790,7 @@ class AtPage extends Handler {
addPageAttributes(page, start, pages) {
let named = start.dataset.page;
let index = pages.indexOf(page);
if (named) {
page.name = named;
......
......@@ -117,28 +117,28 @@ class Breaks extends Handler {
return pageBreaks;
}
addBreakAttributes(page) {
let before = page.wrapper.querySelector("[data-break-before]");
let after = page.wrapper.querySelector("[data-break-after]");
let previousBreakAfter = page.wrapper.querySelector("[data-previous-break-after]");
addBreakAttributes(pageElement, page) {
let before = pageElement.querySelector("[data-break-before]");
let after = pageElement.querySelector("[data-break-after]");
let previousBreakAfter = pageElement.querySelector("[data-previous-break-after]");
if (before) {
if (before.dataset.splitFrom) {
page.splitFrom = before.dataset.splitFrom;
page.element.setAttribute("data-split-from", before.dataset.splitFrom);
pageElement.setAttribute("data-split-from", before.dataset.splitFrom);
} else if (before.dataset.breakBefore && before.dataset.breakBefore !== "avoid") {
page.breakBefore = before.dataset.breakBefore;
page.element.setAttribute("data-break-before", before.dataset.breakBefore);
pageElement.setAttribute("data-break-before", before.dataset.breakBefore);
}
}
if (after && after.dataset) {
if (after.dataset.splitTo) {
page.splitTo = after.dataset.splitTo;
page.element.setAttribute("data-split-to", after.dataset.splitTo);
pageElement.setAttribute("data-split-to", after.dataset.splitTo);
} else if (after.dataset.breakAfter && after.dataset.breakAfter !== "avoid") {
page.breakAfter = after.dataset.breakAfter;
page.element.setAttribute("data-break-after", after.dataset.breakAfter);
pageElement.setAttribute("data-break-after", after.dataset.breakAfter);
}
}
......@@ -149,8 +149,8 @@ class Breaks extends Handler {
}
}
afterLayout(pageElement, page) {
this.addBreakAttributes(page);
afterPageLayout(pageElement, page) {
this.addBreakAttributes(pageElement, page);
}
}
......
......@@ -14,11 +14,15 @@ class Counters extends Handler {
let property = declaration.property;
if (property === "counter-increment") {
this.handleIncrement(declaration, rule);
dList.remove(dItem);
let inc = this.handleIncrement(declaration, rule);
if (inc) {
dList.remove(dItem);
}
} else if (property === "counter-reset") {
this.handleReset(declaration, rule);
dList.remove(dItem);
let reset = this.handleReset(declaration, rule);
if (reset) {
dList.remove(dItem);
}
}
}
......@@ -51,6 +55,11 @@ class Counters extends Handler {
let number = declaration.value.children.getSize() > 1
&& declaration.value.children.last().value;
let name = identifier && identifier.name;
if (name === "page" || name.indexOf("target-counter-") === 0) {
return;
}
let selector = csstree.generate(rule.ruleNode.prelude);
let counter;
......@@ -60,7 +69,7 @@ class Counters extends Handler {
counter = this.counters[name];
}
counter.increments[selector] = {
return counter.increments[selector] = {
selector: selector,
number: number || 1
};
......@@ -72,15 +81,15 @@ class Counters extends Handler {
&& declaration.value.children.last().value;
let name = identifier && identifier.name;
let selector = csstree.generate(rule.ruleNode.prelude);
let counter;
if (!(name in this.counters)) {
counter = this.addCounter(name);
} else {
counter = this.counters[name];
}
counter.resets[selector] = {
return counter.resets[selector] = {
selector: selector,
number: number || 0
};
......@@ -153,6 +162,14 @@ class Counters extends Handler {
}
}
afterPageLayout(pageElement, page) {
let pgreset = pageElement.querySelectorAll("[data-counter-page-reset]");
pgreset.forEach((reset) => {
let value = reset.datasetCounterPageReset;
this.styleSheet.insertRule(`[data-page-number="${pageElement.dataset.pageNumber}"] { counter-reset: page ${value} }`, this.styleSheet.cssRules.length);
});
}
}
export default Counters;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment