...
 
Commits (18)
This diff is collapsed.
{
"name": "pagedjs",
"version": "0.1.43",
"version": "0.2.0",
"description": "Chunks up a document into paged media flows and applies print styles",
"author": "Fred Chasen",
"license": "MIT",
......@@ -10,32 +10,32 @@
"browser": "dist/paged.js",
"dependencies": {
"@babel/polyfill": "^7.10.1",
"@babel/runtime": "^7.12.5",
"@babel/runtime": "^7.14.0",
"clear-cut": "^2.0.2",
"css-tree": "1.1.2",
"css-tree": "^1.1.3",
"event-emitter": "^0.3.5"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/plugin-proposal-async-generator-functions": "^7.12.12",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"chalk": "^4.1.0",
"eslint": "^7.19.0",
"@babel/cli": "^7.14.3",
"@babel/core": "^7.14.3",
"@babel/plugin-proposal-async-generator-functions": "^7.14.2",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@rollup/plugin-commonjs": "^19.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"chalk": "^4.1.1",
"eslint": "^7.27.0",
"express": "^4.17.1",
"ghostscript4js": "^3.2.1",
"jest": "^26.6.3",
"jest-image-snapshot": "^4.3.0",
"puppeteer": "^5.5.0",
"jest-image-snapshot": "^4.5.0",
"puppeteer": "^9.1.1",
"rimraf": "^3.0.2",
"rollup": "^2.38.3",
"rollup-plugin-commonjs": "^10.1.0",
"rollup-plugin-json": "^4.0.0",
"rollup-plugin-license": "^2.1.0",
"rollup-plugin-livereload": "^2.0.0",
"rollup-plugin-node-builtins": "^2.1.2",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-serve": "^1.1.0"
},
"scripts": {
......
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import json from "rollup-plugin-json";
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import license from "rollup-plugin-license";
import pkg from "./package.json";
const plugins = [
resolve(),
nodeResolve(),
commonjs({
include: "node_modules/**"
}),
......
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
import pkg from './package.json';
const plugins = [
resolve(),
nodeResolve(),
commonjs(),
json()
];
......
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import json from 'rollup-plugin-json';
import { nodeResolve } from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import json from "@rollup/plugin-json";
// import builtins from 'rollup-plugin-node-builtins';
// import globals from 'rollup-plugin-node-globals';
......@@ -11,7 +10,7 @@ import serve from 'rollup-plugin-serve'
import livereload from 'rollup-plugin-livereload'
const plugins = [
resolve(),
nodeResolve(),
commonjs(),
json(),
// globals(),
......
<!DOCTYPE html>
<html lang="en">
<head>
<title>table-avoid-break-rowspan</title>
<meta charset="UTF-8">
<script src="../../../dist/paged.polyfill.js"></script>
<style>
@page {
size: A5;
margin: 1cm;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
tr {
break-inside: avoid;
}
.table td, .table th {
border: 1px solid #dbdbdb;
padding: .5em .75em;
vertical-align: top;
}
/* interface */
@media screen {
body {
background-color: whitesmoke;
}
.pagedjs_page {
margin-bottom: 20px;
flex: none;
box-shadow: 0 0 0 1px rgba(0, 0,0,0.2);
background-color: white;
}
}
</style>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<main>
<section>
<table class="table is-bordered">
<thead>
<tr>
<th>id</th>
<th>first_name</th>
<th>last_name</th>
<th colspan="2">email + score</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Magdalen</td>
<td>Holtaway</td>
<td>Flowdesk</td>
<td rowspan="3">37.67</td>
</tr>
<tr>
<td>2</td>
<td>Olenka</td>
<td>Tuckett</td>
<td>Subin</td>
</tr>
<tr>
<td>3</td>
<td>Towny</td>
<td>Calverley</td>
<td>Fintone</td>
</tr>
<tr>
<td>4</td>
<td>Maribeth</td>
<td>Caskie</td>
<td>Tresom</td>
<td rowspan="3">13.64</td>
</tr>
<tr>
<td>5</td>
<td>Roldan</td>
<td>Whitham</td>
<td>Flowdesk</td>
</tr>
<tr>
<td>6</td>
<td>Melody</td>
<td>Gentle</td>
<td>Asoka</td>
</tr>
<tr>
<td>7</td>
<td>Aida</td>
<td>Holtum</td>
<td>Bigtax</td>
<td rowspan="3">84.10</td>
</tr>
<tr>
<td>8</td>
<td>Angelia</td>
<td>O'Farrell</td>
<td>Bamity</td>
</tr>
<tr>
<td>9</td>
<td>Puff</td>
<td>Stennet</td>
<td>Aerified</td>
</tr>
<tr>
<td>10</td>
<td>Carmel</td>
<td>Ennion</td>
<td>Kanlam</td>
<td rowspan="3">59.44</td>
</tr>
<tr>
<td>11</td>
<td>Phyllida</td>
<td>Sarra</td>
<td>Toughjoyfax</td>
</tr>
<tr>
<td>12</td>
<td>Dulcy</td>
<td>Lamb-shine</td>
<td>Tresom</td>
</tr>
<tr>
<td>13</td>
<td>Piggy</td>
<td>Junifer</td>
<td>Bitchip</td>
<td rowspan="3">23.64</td>
</tr>
<tr>
<td>14</td>
<td>Adrianna</td>
<td>Millichap</td>
<td>It</td>
</tr>
<tr>
<td>15</td>
<td>Celeste</td>
<td>Milleton</td>
<td>Daltfresh</td>
</tr>
<tr>
<td>16</td>
<td>Ted</td>
<td>Slyde</td>
<td>Treeflex</td>
<td rowspan="3">74.64</td>
</tr>
<tr>
<td>17</td>
<td>Maurene</td>
<td>Sylvester</td>
<td>Tres-Zap</td>
</tr>
<tr>
<td>18</td>
<td>Monte</td>
<td>Tingley</td>
<td>Redhold</td>
</tr>
<tr>
<td>19</td>
<td>Louise</td>
<td>McMichell</td>
<td>Latlux</td>
<td rowspan="3">18.86</td>
</tr>
<tr>
<td>20</td>
<td>Turner</td>
<td>McQuirter</td>
<td>Keylex</td>
</tr>
<tr>
<td>21</td>
<td>Alvin</td>
<td>Emilien</td>
<td>Cardguard</td>
</tr>
<tr>
<td>22</td>
<td>Joanne</td>
<td>Obey</td>
<td>Regrant</td>
<td rowspan="3">25.32</td>
</tr>
<tr>
<td>23</td>
<td>Lorne</td>
<td>Lescop</td>
<td>Home Ing</td>
</tr>
<tr>
<td>24</td>
<td>Zara</td>
<td>Jillett</td>
<td>Matsoft</td>
</tr>
<tr>
<td>25</td>
<td>Delmore</td>
<td>Hellis</td>
<td>Regrant</td>
<td>42.33</td>
</tr>
</tbody>
</table>
</section>
</main>
</body>
</html>
const TIMEOUT = 10000;
describe("breaks-table-avoid-break-rowspan", () => {
let page;
beforeAll(async () => {
page = await loadPage("breaks/table/avoid-break-rowspan.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(2);
});
}
});
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>Preformatted Text element</title>
<script src="../../../dist/paged.polyfill.js"></script>
<style>
@page {
size: 220mm 15mm;
margin: 0;
}
/* interface */
@media screen {
body {
background-color: whitesmoke;
}
.pagedjs_page {
margin-bottom: 0;
flex: none;
border-left: 1px solid rgba(0, 0,0,0.2);
border-right: 1px solid rgba(0, 0,0,0.2);
border-bottom: 1px dashed rgba(0, 0,0,0.1);
background-color: white;
}
.pagedjs_page:first-child {
border-top: 1px solid rgba(0, 0,0,0.2);
}
.pagedjs_page:last-child {
border-bottom: 1px solid rgba(0, 0,0,0.2);
}
}
</style>
</head>
<body>
<section>
<pre>
88888888ba 88 88
88 "8b 88 ""
88 ,8P 88
88aaaaaa8P' ,adPPYYba, ,adPPYb,d8 ,adPPYba, ,adPPYb,88 88 ,adPPYba,
88""""""' "" `Y8 a8" `Y88 a8P_____88 a8" `Y88 88 I8[ ""
88 ,adPPPPP88 8b 88 8PP""""""" 8b 88 88 `"Y8ba,
88 88, ,88 "8a, ,d88 "8b, ,aa "8a, ,d88 888 88 aa ]8I
88 `"8bbdP"Y8 `"YbbdP"Y8 `"Ybbd8"' `"8bbdP"Y8 888 88 `"YbbdP"'
aa, ,88 ,88
"Y8bbdP" 888P"
</pre>
</section>
</body>
</html>
const TIMEOUT = 10000;
describe("pre", () => {
let page;
beforeAll(async () => {
page = await loadPage("splits/pre/pre.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
it("should render 4 pages", async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => r.length);
expect(pages).toBe(4);
});
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);
});
}
});
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>exceeding-rowspan-table</title>
<script src="../../../dist/paged.polyfill.js"></script>
<style>
@page {
size: 600px 600px;
border: 1px solid #cfc2c2;
}
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
tr, td {
break-inside: avoid;
}
</style>
</head>
<body>
<table>
<colgroup>
<col style="width: 15%;">
<col style="width: 10%;">
<col style="width: 25%;">
<col style="width: 15%;">
<col style="width: 10%;">
<col style="width: 25%;">
</colgroup>
<tbody>
<tr>
<td colspan="6"><p><strong>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Aenean dignissim odio eget justo lacinia, vel accumsan nulla interdum.
Nunc dapibus dapibus pulvinar. Aliquam pellentesque leo et ullamcorper euismod.
Proin nec hendrerit augue. Integer sit amet congue ex.
Integer sollicitudin condimentum ultricies.</strong></p></td>
</tr>
<tr>
<td colspan="6"><p><strong>5. Lorem ipsum dolor sit amet</strong></p></td>
</tr>
<tr>
<td colspan="2"><p>5.1. Lorem ipsum dolor sit amet</p></td>
<td colspan="4"><p>Aenean dignissim odio eget justo lacinia, vel accumsan nulla interdum.</p></td>
</tr>
<tr>
<td colspan="6"><p>6. Nunc dapibus dapibus pulvinar. Aliquam pellentesque leo et ullamcorper euismod.</p></td>
</tr>
<tr>
<td colspan="2"><p>hendrerit</p></td>
<td colspan="2"><p>condimentum</p></td>
<td colspan="2"><p>ultricies</p></td>
</tr>
<tr>
<td colspan="2"><p>nec hendrerit augue</p></td>
<td colspan="2"><p>Aliquam pellentesque leo</p></td>
<td><p><em><em></em></em></p></td>
<td><p>vel accumsan nulla </p></td>
</tr>
<tr>
<td colspan="2"><p>psum dolor sit amet</p></td>
<td colspan="2"><p>(зав. № <em><em>_ ), инв. № </em><em></em></em></p></td>
<td><p><em><em></em></em></p></td>
<td><p>ullamcorper</p></td>
</tr>
<tr>
<td colspan="2"><p>dignissim odio</p></td>
<td colspan="2"><p> ullamcorper euismod</p></td>
<td><p><em><em></em></em></p></td>
<td><p>justo lacinia</p></td>
</tr>
<tr>
<td colspan="6"><p><strong>7. Integer sit amet congue ex.</strong></p></td>
</tr>
<tr>
<td colspan="2"><p>7.1. Dignissim odio eget justo lacinia.</p></td>
<td colspan="4"><p>Nunc dapibus dapibus pulvinar. Aliquam pellentesque leo et ullamcorper euismod.
Proin nec hendrerit augue. Integer sit amet congue ex.</p></td>
</tr>
</tbody>
</table>
</body>
</html>
const TIMEOUT = 10000;
describe("rowspan uneven table", () => {
let page;
beforeAll(async () => {
page = await loadPage("splits/tables/exceeding-rowspan-table.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(2);
});
}
});
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>rowspan-table</title>
<script src="../../../dist/paged.polyfill.js"></script>
<style>
@page {
size: 600px 300px;
border: 1px solid #cfc2c2;
}
table {
border-collapse: collapse;
}
table, th, td {
border: 1px solid black;
}
tr, td {
break-inside: avoid;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td rowspan="4">1.1</td>
<td rowspan="4">This is a long description</td>
<td>First row, third column</td>
<td rowspan="4">1.4</td>
<td>First row, fifth column</td>
<td rowspan="4">1.6</td>
</tr>
<tr>
<td>Second row, third column</td>
<td>Second row, fifth column</td>
</tr>
<tr>
<td>Third row, third column</td>
<td>Third row, fifth column</td>
</tr>
<tr>
<td>Fourth row, third column</td>
<td>Fourth row, fifth column</td>
</tr>
</tbody>
</table>
</body>
</html>
const TIMEOUT = 10000;
describe("rowspan table", () => {
let page;
beforeAll(async () => {
page = await loadPage("splits/tables/rowspan-table.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
expect(pdf).toMatchPDFSnapshot(2);
});
}
});
h1 {
color: blue;
}
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>preserve style order</title>
<script src="../../dist/paged.polyfill.js"></script>
<style>
h1 {
color: red;
}
</style>
<link href="./green.css" rel="stylesheet">
<link href="./blue.css" rel="stylesheet">
</head>
<body>
<section>
<h1>aaa</h1>
</section>
</body>
</html>
h1 {
color: green;
}
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>preserve style order</title>
<script src="../../dist/paged.polyfill.js"></script>
<style>
h1 {
color: red;
}
</style>
<link href="./blue.css" rel="stylesheet">
</head>
<body>
<section>
<style>
h1 {
color: purple;
}
</style>
<h1>aaa</h1>
</section>
</body>
</html>
<!DOCTYPE html PUBLIC>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>preserve style order</title>
<script src="../../dist/paged.polyfill.js"></script>
<style>
h1 {
color: red;
}
</style>
<style>
h1 {
color: deeppink;
}
</style>
</head>
<body>
<section>
<h1>aaa</h1>
</section>
</body>
</html>
const TIMEOUT = 10000; // Some page might take longer than this to renderer
describe("style-order-simple", () => {
let page;
beforeAll(async () => {
page = await loadPage("styles/simple.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
});
}
});
describe("style-order-consecutive", () => {
let page;
beforeAll(async () => {
page = await loadPage("styles/consecutive.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
});
}
});
describe("style-order-scattered", () => {
let page;
beforeAll(async () => {
page = await loadPage("styles/scattered.html");
return page.rendered;
}, TIMEOUT);
afterAll(async () => {
if (!DEBUG) {
await page.close();
}
});
if (!DEBUG) {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
});
}
});
import {getBoundingClientRect, getClientRects} from "../utils/utils";
import { getBoundingClientRect, getClientRects } from "../utils/utils";
import {
breakInsideAvoidParentNode,
child,
......@@ -24,7 +24,8 @@ import {
walk,
words
} from "../utils/dom";
import BreakToken from "./breaktoken";
import BreakToken from "./breaktoken";
import RenderResult, { OverflowContentError } from "./renderresult";
import EventEmitter from "event-emitter";
import Hook from "../utils/hook";
......@@ -94,9 +95,9 @@ class Layout {
if (newBreakToken && newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", prevNode);
return undefined;
return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [prevNode]));
}
return newBreakToken;
return new RenderResult(newBreakToken);
}
this.hooks && this.hooks.layoutNode.trigger(node);
......@@ -118,7 +119,7 @@ class Layout {
if (newBreakToken && newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", node);
return undefined;
return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [node]));
}
length = 0;
......@@ -172,7 +173,7 @@ class Layout {
if (newBreakToken && newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", node);
return undefined;
return new RenderResult(undefined, new OverflowContentError("Unable to layout item", [node]));
}
if (newBreakToken) {
......@@ -182,7 +183,7 @@ class Layout {
}
return newBreakToken;
return new RenderResult(newBreakToken);
}
breakAt(node, offset = 0) {
......@@ -498,6 +499,40 @@ class Layout {
br = node.tagName === "BR" || node.tagName === "WBR";
}
let tableRow;
if (node.nodeName === "TR") {
tableRow = node;
} else {
tableRow = parentOf(node, "TR", rendered);
}
if (tableRow) {
// Check if the node is inside a row with a rowspan
const table = parentOf(tableRow, "TABLE", rendered);
if (table) {
let columnCount = 0;
for (const cell of Array.from(table.rows[0].cells)) {
columnCount += parseInt(cell.getAttribute("COLSPAN") || "1");
}
if (tableRow.cells.length !== columnCount) {
let previousRow = tableRow.previousSibling;
let previousRowColumnCount;
while (previousRow !== null) {
previousRowColumnCount = 0;
for (const cell of Array.from(previousRow.cells)) {
previousRowColumnCount += parseInt(cell.getAttribute("COLSPAN") || "1");
}
if (previousRowColumnCount === columnCount) {
break;
}
previousRow = previousRow.previousSibling;
}
if (previousRowColumnCount === columnCount) {
prev = previousRow;
}
}
}
}
if (prev) {
range = document.createRange();
range.selectNode(prev);
......
......@@ -127,8 +127,9 @@ class Page {
this.layoutMethod = new Layout(this.area, this.hooks, maxChars);
let newBreakToken = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken);
let renderResult = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken);
let newBreakToken = renderResult.breakToken;
this.addListeners(contents);
this.endToken = newBreakToken;
......@@ -142,7 +143,8 @@ class Page {
return this.layout(contents, breakToken);
}
let newBreakToken = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken);
let renderResult = await this.layoutMethod.renderTo(this.wrapper, contents, breakToken);
let newBreakToken = renderResult.breakToken;
this.endToken = newBreakToken;
......
/**
* Render result.
* @class
*/
class RenderResult {
constructor(breakToken, error) {
this.breakToken = breakToken;
this.error = error;
}
}
export class OverflowContentError extends Error {
constructor(message, items) {
super(message);
this.items = items;
}
}
export default RenderResult;
......@@ -761,20 +761,20 @@ class AtPage extends Handler {
addBorderVars(border, list, item) {
// variables for borders
for (let b in border) {
if (typeof border[b] !== "undefined") {
let value = border[b];
let bVar = list.createItem({
for (const name of Object.keys(border)) {
const value = border[name];
// value is an empty object when undefined
if (typeof value === "string") {
const borderItem = list.createItem({
type: "Declaration",
property: "--pagedjs-border-" + b,
property: "--pagedjs-border-" + name,
value: {
type: "Raw",
value: value
}
});
list.append(bVar, item);
list.append(borderItem, item);
}
}
}
......
......@@ -104,7 +104,6 @@ class Polisher {
insert(text){
let head = document.querySelector("head");
let style = document.createElement("style");
style.type = "text/css";
style.setAttribute("data-pagedjs-inserted-styles", "true");
style.appendChild(document.createTextNode(text));
......
......@@ -4,7 +4,7 @@ import Hook from "../utils/hook";
import Chunker from "../chunker/chunker";
import Polisher from "../polisher/polisher";
import { registerHandlers, initializeHandlers } from "../utils/handlers";
import { initializeHandlers, registerHandlers } from "../utils/handlers";
class Previewer {
constructor(options) {
......@@ -101,22 +101,36 @@ class Previewer {
removeStyles(doc=document) {
// Get all stylesheets
let stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']"));
let hrefs = stylesheets.map((sheet) => {
sheet.remove();
return sheet.href;
});
const stylesheets = Array.from(doc.querySelectorAll("link[rel='stylesheet']"));
// Get inline styles
let inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles])"));
inlineStyles.forEach((inlineStyle) => {
let obj = {};
obj[window.location.href] = inlineStyle.textContent;
hrefs.push(obj);
inlineStyle.remove();
});
return hrefs;
const inlineStyles = Array.from(doc.querySelectorAll("style:not([data-pagedjs-inserted-styles])"));
const elements = [...stylesheets, ...inlineStyles];
return elements
// preserve order
.sort(function (element1, element2) {
const position = element1.compareDocumentPosition(element2);
if (position === Node.DOCUMENT_POSITION_PRECEDING) {
return 1;
} else if (position === Node.DOCUMENT_POSITION_FOLLOWING) {
return -1;
}
return 0;
})
// extract the href
.map((element) => {
if (element.nodeName === "STYLE") {
const obj = {};
obj[window.location.href] = element.textContent;
element.remove();
return obj;
}
if (element.nodeName === "LINK") {
element.remove();
return element.href;
}
// ignore
console.warn(`Unable to process: ${element}, ignoring.`);
});
}
async preview(content, stylesheets, renderTo) {
......
......@@ -140,6 +140,41 @@ export function rebuildAncestors(node) {
let fragment = document.createDocumentFragment();
// Handle rowspan on table
if (node.nodeName === "TR") {
let previousRow = node.previousElementSibling;
let previousRowDistance = 1;
while (previousRow) {
// previous row has more columns, might indicate a rowspan.
if (previousRow.childElementCount > node.childElementCount) {
const initialColumns = Array.from(node.children);
while (node.firstChild) {
node.firstChild.remove();
}
let k = 0;
for (let j = 0; j < previousRow.children.length; j++) {
let column = previousRow.children[j];
if (column.rowSpan && column.rowSpan > previousRowDistance) {
const duplicatedColumn = column.cloneNode(true);
// Adjust rowspan value
duplicatedColumn.rowSpan = column.rowSpan - previousRowDistance;
// Add the column to the row
node.appendChild(duplicatedColumn);
} else {
// Fill the gap with the initial columns (if exists)
const initialColumn = initialColumns[k++];
// The initial column can be undefined if the newly created table has less columns than the original table
if (initialColumn) {
node.appendChild(initialColumn);
}
}
}
}
previousRow = previousRow.previousElementSibling;
previousRowDistance++;
}
}
// Gather all ancestors
let element = node;
while(element.parentNode && element.parentNode.nodeType === 1) {
......@@ -301,10 +336,11 @@ export function *words(node) {
let currentLetter;
let range;
const significantWhitespaces = node.parentElement && node.parentElement.nodeName === 'PRE';
while(currentOffset < max) {
while (currentOffset < max) {
currentLetter = currentText[currentOffset];
if (/^[\S\u202F\u00A0]$/.test(currentLetter)) {
if (/^[\S\u202F\u00A0]$/.test(currentLetter) || significantWhitespaces) {
if (!range) {
range = document.createRange();
range.setStart(node, currentOffset);
......@@ -323,7 +359,6 @@ export function *words(node) {
if (range) {
range.setEnd(node, currentOffset);
yield range;
range = undefined;
}
}
......