Commit 9fc20fcf authored by Fred Chasen's avatar Fred Chasen

Merge branch 'eslint' into 'master'

Track average length of text for checking for overflow & Eslint

See merge request tools/pagedjs!35
parents f7ba5416 6c883e30
module.exports = {
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"globals": {
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 9
},
"rules": {
"indent": [
"error",
"tab",
{
"VariableDeclarator": { "var": 2, "let": 2, "const": 3 },
"SwitchCase" : 1
}
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"warn",
"double"
],
"semi": [
"error",
"always"
],
"no-unused-vars" : ["warn"],
"no-console" : ["error", { allow: ["warn", "error"] }],
"no-unused-vars": [
"error",
{ "vars": "all", "args": "none" }
],
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
"valid-jsdoc": ["warn"]
}
};
......@@ -9,6 +9,11 @@
<link rel="coverpage" href="assets/aurorae/images/cover.jpg" />
<script>
window.PagedConfig = {
after: (flow) => console.log(flow.performance)
}
</script>
<script src="../dist/paged.polyfill.js"></script>
<link href="assets/aurorae/book.css" rel="stylesheet" type='text/css'>
......
This diff is collapsed.
......@@ -24,6 +24,7 @@
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"chalk": "^2.4.1",
"eslint": "^5.9.0",
"express": "^4.16.3",
"ghostscript4js": "^3.0.0",
"jest": "^23.4.1",
......@@ -48,7 +49,8 @@
"compile": "./node_modules/.bin/babel src/ -d lib/",
"pretest": "npm run build",
"prepublishOnly": "npm run build && npm run compile && npm run legacy",
"watch": "./node_modules/.bin/rollup -w -c"
"watch": "./node_modules/.bin/rollup -w -c",
"lint": "./node_modules/.bin/eslint -c .eslintrc.js src; exit 0"
},
"repository": {
"type": "git",
......
......@@ -4,12 +4,7 @@ import EventEmitter from "event-emitter";
import Hook from "../utils/hook";
import Queue from "../utils/queue";
import {
needsBreakBefore,
needsBreakAfter
} from "../utils/dom";
import {
requestIdleCallback,
defer
requestIdleCallback
} from "../utils/utils";
const MAX_PAGES = false;
......@@ -81,6 +76,9 @@ class Chunker {
this.content = content;
this.charsPerBreak = [];
this.maxChars;
if (content) {
this.flow(content, renderTo);
}
......@@ -174,7 +172,7 @@ class Chunker {
let result;
while (!done) {
result = await this.q.enqueue(async () => { return this.renderOnIdle(renderer) });
result = await this.q.enqueue(() => { return this.renderAsync(renderer); });
done = result.done;
}
......@@ -207,6 +205,18 @@ class Chunker {
});
}
async renderAsync(renderer) {
if (this.stopped) {
return { done: true, canceled: true };
}
let result = await renderer.next();
if (this.stopped) {
return { done: true, canceled: true };
} else {
return result;
}
}
async handleBreaks(node) {
let currentPage = this.total + 1;
let currentPosition = currentPage % 2 === 0 ? "left" : "right";
......@@ -276,17 +286,34 @@ class Chunker {
this.emit("page", page);
// Layout content in the page, starting from the breakToken
breakToken = await page.layout(content, breakToken);
breakToken = await page.layout(content, breakToken, this.maxChars);
await this.hooks.afterPageLayout.trigger(page.element, page, breakToken, this);
this.emit("renderedPage", page);
this.recoredCharLength(page.wrapper.textContent.length);
yield breakToken;
// Stop if we get undefined, showing we have reached the end of the content
}
}
recoredCharLength(length) {
if (length === 0) {
return;
}
this.charsPerBreak.push(length);
// Keep the length of the last few breaks
if (this.charsPerBreak.length > 4) {
this.charsPerBreak.shift();
}
this.maxChars = this.charsPerBreak.reduce((a, b) => a + b, 0) / (this.charsPerBreak.length);
}
removePages(fromIndex=0) {
if (fromIndex >= this.pages.length) {
......@@ -309,7 +336,8 @@ class Chunker {
let lastPage = this.pages[this.pages.length - 1];
// Create a new page from the template
let page = new Page(this.pagesArea, this.pageTemplate, blank, this.hooks);
let total = this.pages.push(page);
this.pages.push(page);
// Create the pages
page.create(undefined, lastPage && lastPage.element);
......@@ -397,7 +425,7 @@ class Chunker {
}
set total(num) {
this.pagesArea.style.setProperty('--page-count', num);
this.pagesArea.style.setProperty("--page-count", num);
this._total = num;
}
......@@ -410,17 +438,17 @@ class Chunker {
}, (r) => {
console.warn("Failed to preload font-family:", fontFace.family);
return fontFace.family;
})
});
fontPromises.push(fontLoaded);
}
});
return Promise.all(fontPromises).catch((err) => {
console.warn(err)
})
console.warn(err);
});
}
destroy() {
this.pagesArea.remove()
this.pagesArea.remove();
this.pageTemplate.remove();
}
......
This diff is collapsed.
This diff is collapsed.
import htmlparser2 from 'htmlparser2';
/**
* Render a flow of text offscreen
* @class
*/
class Parser {
constructor(content, cb) {
// this.text = text;
// this.nodes = [];
this.refs = {};
this.sections = [];
if (content && content.nodeType) {
// handle dom
} else if(typeof content === "object") {
this.add(content);
} else if (typeof content === "string") {
this.dom = this.parse(content);
}
}
parse(data) {
let options = {};
let process = (node) => {
let uuid = this.uuid();
this.refs[uuid] = node;
node.dataset.ref = uuid; // Refs for all nodes
node.dataset.ref = uuid;
node.dataset.children = node.children.length;
if (node.data) {
node.dataset.text = node.data.length;
}
if (node.name === "section") {
this.sections.push(node);
}
}
let handler = new htmlparser2.DomHandler(undefined, options, process.bind(this));
new htmlparser2.Parser(handler, options).end(data);
return handler.dom;
}
add(contents) {
this.dom = [contents];
let walker = this.walk(this.dom[0]);
let next, done, node;
while (!done) {
next = walker.next();
node = next.value;
done = next.done;
if (node && node.dataset && node.dataset.ref) {
this.refs[node.dataset.ref] = node;
}
}
}
find(ref) {
return this.refs[ref];
}
*walk(start) {
let node = start || this.dom[0];
while (node) {
yield node;
if (node.children && node.children.length) {
node = node.children[0];
} else if (node.next) {
node = node.next;
} else {
while (node) {
node = node.parent;
if (node && node.next) {
node = node.next;
break;
}
}
}
}
}
// isWrapper(element) {
// return wrappersRegex.test(element.nodeName);
// }
isText(node) {
return node.name === "tag";
}
isElement(node) {
return node.name === "text";
}
hasChildren(node) {
return node.children && node.children.length;
}
after(node) {
let after = node;
if (after.next) {
after = after.next;
} else {
while (after) {
after = after.parent;
if (after && after.next) {
after = after.next;
break;
}
}
}
return after;
}
/**
* Generates a UUID
* based on: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
* @returns {string} uuid
*/
uuid() {
var d = new Date().getTime();
if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
d += performance.now(); //use high-precision timer if available
}
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (d + Math.random() * 16) % 16 | 0;
d = Math.floor(d / 16);
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
destroy() {
this.refs = undefined;
this.dom = undefined;
}
}
export default Parser;
......@@ -19,8 +19,6 @@ class ContentParser {
}
parse(markup, mime) {
let parser = new DOMParser();
let range = document.createRange();
let fragment = range.createContextualFragment(markup);
......@@ -49,12 +47,12 @@ class ContentParser {
var treeWalker = document.createTreeWalker(
content,
NodeFilter.SHOW_ELEMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
);
let node;
while(node = treeWalker.nextNode()) {
let node = treeWalker.nextNode();
while(node) {
if (!node.hasAttribute("data-ref")) {
let uuid = UUID();
......@@ -68,6 +66,7 @@ class ContentParser {
// node.setAttribute("data-children", node.childNodes.length);
// node.setAttribute("data-text", node.textContent.trim().length);
node = treeWalker.nextNode();
}
}
......
import Chunker from './chunker/chunker';
import Polisher from './polisher/polisher';
import Previewer from './polyfill/previewer';
import Handler from './modules/handler';
import { registerHandlers, initializeHandlers } from './utils/handlers';
import Chunker from "./chunker/chunker";
import Polisher from "./polisher/polisher";
import Previewer from "./polyfill/previewer";
import Handler from "./modules/handler";
import { registerHandlers, initializeHandlers } from "./utils/handlers";
export {
Chunker,
Polisher,
Previewer,
Handler,
registerHandlers,
initializeHandlers
Chunker,
Polisher,
Previewer,
Handler,
registerHandlers,
initializeHandlers
};
import RunningHeaders from './running-headers';
import StringSets from './string-sets';
import TargetCounters from './target-counters';
import TargetText from './target-text';
import RunningHeaders from "./running-headers";
import StringSets from "./string-sets";
import TargetCounters from "./target-counters";
import TargetText from "./target-text";
export default [
RunningHeaders,
StringSets,
TargetCounters,
TargetText
]
];
import Handler from "../handler";
import csstree from 'css-tree';
import csstree from "css-tree";
class RunningHeaders extends Handler {
constructor(chunker, polisher, caller) {
......@@ -12,12 +12,12 @@ class RunningHeaders extends Handler {
onDeclaration(declaration, dItem, dList, rule) {
if (declaration.property === "position") {
let selector = csstree.generate(rule.ruleNode.prelude);
let identifier = declaration.value.children.first().name
let identifier = declaration.value.children.first().name;
if (identifier === "running") {
let value;
csstree.walk(declaration, {
visit: 'Function',
visit: "Function",
enter: (node, item, list) => {
value = node.children.first().name;
}
......@@ -27,14 +27,14 @@ class RunningHeaders extends Handler {
identifier: identifier,
value: value,
selector: selector
}
};
}
}
if (declaration.property === "content") {
csstree.walk(declaration, {
visit: 'Function',
visit: "Function",
enter: (funcNode, fItem, fList) => {
if (funcNode.name.indexOf("element") > -1) {
......@@ -61,7 +61,7 @@ class RunningHeaders extends Handler {
style: style || "first",
selector: s,
fullSelector: selector
}
};
});
}
......@@ -89,14 +89,14 @@ class RunningHeaders extends Handler {
let set = this.runningSelectors[name];
let selected = fragment.querySelector(set.selector);
if (selected) {
let cssVar;
// let cssVar;
if (set.identifier === "running") {
// cssVar = selected.textContent.replace(/\\([\s\S])|(["|'])/g,"\\$1$2");
// this.styleSheet.insertRule(`:root { --string-${name}: "${cssVar}"; }`, this.styleSheet.cssRules.length);
// fragment.style.setProperty(`--string-${name}`, `"${cssVar}"`);
set.first = selected;
} else {
console.log(set.value + "needs css replacement");
console.warn(set.value + "needs css replacement");
}
}
}
......@@ -134,13 +134,15 @@ class RunningHeaders extends Handler {
* 5) named page
* 6) named left & right
* 7) named first & nth
* @param {string} [s] selector string
* @return {int} weight
*/
pageWeight(s) {
let weight = 1;
let selector = s.split(" ");
let parts = selector.length && selector[0].split(".");
parts.shift() // remove empty first part
parts.shift(); // remove empty first part
switch (parts.length) {
case 4:
......@@ -184,6 +186,8 @@ class RunningHeaders extends Handler {
*
* Does not try to deduplicate base on specifity of the selector
* Previous matched selector will just be overwritten
* @param {obj} [obj] selectors object
* @return {Array} orderedSelectors
*/
orderSelectors(obj) {
let selectors = Object.keys(obj);
......@@ -213,7 +217,7 @@ class RunningHeaders extends Handler {
beforeTreeParse(text, sheet) {
// element(x) is parsed as image element selector, so update element to element-ident
sheet.text = text.replace(/element[\s]*\(([^\|^#)]*)\)/g, "element-ident($1)");
sheet.text = text.replace(/element[\s]*\(([^|^#)]*)\)/g, "element-ident($1)");
}
}
......
import Handler from "../handler";
import csstree from 'css-tree';
import csstree from "css-tree";
class StringSets extends Handler {
constructor(chunker, polisher, caller) {
......@@ -12,11 +12,11 @@ class StringSets extends Handler {
if (declaration.property === "string-set") {
let selector = csstree.generate(rule.ruleNode.prelude);
let identifier = declaration.value.children.first().name
let identifier = declaration.value.children.first().name;
let value;
csstree.walk(declaration, {
visit: 'Function',
visit: "Function",
enter: (node, item, list) => {
value = csstree.generate(node);
}
......@@ -26,7 +26,7 @@ class StringSets extends Handler {
identifier: identifier,
value: value,
selector: selector
}
};
}
}
......@@ -57,7 +57,7 @@ class StringSets extends Handler {
set.first = cssVar;
fragment.style.setProperty(`--string-${name}`, `"${set.first}"`);
} else {
console.log(set.value + "needs css replacement");
console.warn(set.value + "needs css replacement");
}
} else {
// Use the previous values
......
import Handler from "../handler";
import { UUID, attr, querySelectorEscape } from "../../utils/utils";
import csstree from 'css-tree';
import csstree from "css-tree";
class TargetCounters extends Handler {
constructor(chunker, polisher, caller) {
......@@ -15,12 +15,11 @@ class TargetCounters extends Handler {
if (funcNode.name === "target-counter") {
let selector = csstree.generate(rule.ruleNode.prelude);
let first = funcNode.children.first();
let last = funcNode.children.last();
let func = first.name;
let value = csstree.generate(funcNode);
let args = []
let args = [];
first.children.forEach((child) => {
if (child.type === "Identifier") {
......@@ -41,7 +40,7 @@ class TargetCounters extends Handler {
style = child.name;
}
}
})
});
let variable = "target-counter-" + UUID();
......@@ -55,12 +54,12 @@ class TargetCounters extends Handler {
selector: s,
fullSelector: selector,
variable: variable
}
};
});
// Replace with counter
funcNode.name = "counter";
funcNode.children = new csstree.List()
funcNode.children = new csstree.List();
funcNode.children.appendData({
type: "Identifier",
loc: 0,
......@@ -74,7 +73,7 @@ class TargetCounters extends Handler {
}
afterPageLayout(fragment, page, breakToken, chunker) {
Object.keys(this.counterTargets).forEach((name) => {
Object.keys(this.counterTargets).forEach((name) => {
let target = this.counterTargets[name];
let split = target.selector.split("::");
let query = split[0];
......@@ -110,10 +109,10 @@ class TargetCounters extends Handler {
}
}
let psuedo = "";
if (split.length > 1) {
psuedo += "::" + split[1];
}
// let psuedo = "";
// if (split.length > 1) {
// psuedo += "::" + split[1];
// }
this.styleSheet.insertRule(`[data-${target.variable}="${selector}"] { counter-increment: ${target.variable} ${pg}; }`, this.styleSheet.cssRules.length);
} else {
......
import Handler from "../handler";
import { UUID, attr, querySelectorEscape } from "../../utils/utils";
import csstree from 'css-tree';
import csstree from "css-tree";
class TargetText extends Handler {
constructor(chunker, polisher, caller) {
......@@ -19,7 +19,7 @@ class TargetText extends Handler {
let value = csstree.generate(funcNode);
let args = []
let args = [];
first.children.forEach((child) => {
if (child.type === "Identifier") {
......@@ -43,12 +43,12 @@ class TargetText extends Handler {
selector: s,
fullSelector: selector,
variable: variable
}
};
});
// Replace with variable
funcNode.name = "var";
funcNode.children = new csstree.List()
funcNode.children = new csstree.List();
funcNode.children.appendData({
type: "Identifier",
loc: 0,
......@@ -68,7 +68,6 @@ class TargetText extends Handler {
let element = fragment.querySelector(querySelectorEscape(val));
if (element) {
if (target.style === "content") {
let text = element.textContent;
let selector = UUID();
selected.setAttribute("data-target-text", selector);
......@@ -77,7 +76,7 @@ class TargetText extends Handler {
psuedo += "::" + split[1];
}
let textContent = element.textContent.trim().replace(/[\"\']/g, (match) => {
let textContent = element.textContent.trim().replace(/["']/g, (match) => {
return "\\" + match;
}).replace(/[\n]/g, (match) => {
return "\\00000A";
......
This diff is collapsed.
import Handler from "../handler";
import csstree from 'css-tree';
import { rebuildAncestors, elementAfter } from "../../utils/dom";
import csstree from "css-tree";
import { elementAfter } from "../../utils/dom";
class Breaks extends Handler {
constructor(chunker, polisher, caller) {
......@@ -31,7 +31,7 @@ class Breaks extends Handler {
} else {
this.breaks[s].push(breaker);
}
})
});
dList.remove(dItem);
}
......@@ -63,7 +63,7 @@ class Breaks extends Handler {
} else {
this.breaks[s].push(breaker);
}
})
});
// Remove from CSS -- handle right / left in module
dList.remove(dItem);
......
import Handler from "../handler";
import csstree from 'css-tree';
import { rebuildAncestors, elementAfter } from "../../utils/dom";
import csstree from "css-tree";