Commit 93c1e649 authored by Fred Chasen's avatar Fred Chasen

Add target-text and set-string

parent 56f5c613
......@@ -2,7 +2,7 @@
size: 8.5in 11in;
margin: 20mm 25mm;
marks: crop;
@footnote {
margin: 0.6em 0 0 0;
padding: 0.3em 0 0 0;
......@@ -48,10 +48,16 @@
@bottom-right-corner {
content: counter(page);
}
@top-center{
content: string(booktitle);
}
}
@page cover {
size: 'letter'; /* measured from scanned book */
@top-center{
content: none;
}
}
......@@ -79,8 +85,8 @@ font-weight: bold;
font-style: italic;
}
#c001s0000 {
string-set: booktitle "hi";
section:nth-child(1) h1 {
string-set: booktitle content(text);
}
......
......@@ -50,20 +50,23 @@
preview = (pair[1] === "true");
}
}
let flowText = document.querySelector("#flow");
// styles
let styles = new Paged.Styler();
let moby = await styles.add("book.css", "paged-js/layout-pagedjs.css");
let styleText = await styles.add("book.css", "paged-js/layout-pagedjs.css");
styles.contents(flowText.content);
// console.log(moby);
let flowText = document.querySelector("#flow");
let t0 = performance.now();
let flow = new Paged.Chunker(flowText.content, undefined, styles.breaks, preview).then((flow) => {
let t1 = performance.now();
console.log("Rendering " + flow.total + " pages took " + (t1 - t0) + " milliseconds.");
// let pages = document.querySelector(".pages");
// styles.counters(pages);
});
let resizer = () => {
......
......@@ -20,11 +20,14 @@ html{
@page {
size: 148mm 210mm portait;
}
background-image: repeating-linear-gradient(180deg, transparent 0, transparent 14px , rgba(0,255,0,0.7) var(--baseline)) ;
background-size: cover;
background-position: 0 -3px , 0 0
@media screen {
.page {
background-image: repeating-linear-gradient(180deg, transparent 0, transparent 14px , rgba(0,255,0,0.7) var(--baseline)) ;
background-size: cover;
background-position: 0 -3px , 0 0
}
}
/*@page:first {
......@@ -212,7 +215,7 @@ html{
.toc-chap a[href]::before,
.toc-part-app a[href]::before,
.toc-app a[href]::before {
content: target-text(attr(href), content);
content: target-text(attr(href url), content);
}
.toc-chap{
......
......@@ -10,7 +10,7 @@
<script src="../dist/paged.js"></script>
<link rel="stylesheet" type="text/css" href="assets/styles/index.css">
<!-- <link rel="stylesheet" type="text/css" href="assets/styles/mody-dick.css"> -->
<!-- <link rel="stylesheet" type="text/css" href="assets/styles/moby-dick.css"> -->
</head>
<body>
<script>
......@@ -69,32 +69,40 @@
return text;
}
function addStyles(resources) {
function addStyles(styles, resources) {
let head = document.querySelector("head");
let styles = resources.filter((r) => {
let stylesArray = resources.filter((r) => {
return r.type === "text/css";
});
for (let style of styles) {
let link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = style.href;
head.appendChild(link);
let toAdd = ["assets/styles/moby-dick.css"];
for (let style of stylesArray) {
// let link = document.createElement("link");
// link.rel = "stylesheet";
// link.type = "text/css";
// link.href = style.href;
// head.appendChild(link);
toAdd.push(style.href);
}
return styles.add.apply(styles, toAdd);
}
function openBook(e){
async function openBook(e){
var bookData = e.target.result;
let epub = ePub(bookData, {replacements: true} ).then((book) => {
this.book = book;
addStyles(this.book.resources)
return book;
}).then((book) => {
let styles = new Paged.Styler();
return addStyles(styles, this.book.resources);
}).then(() => {
return sections(this.book.spine);
}).then((text) => {
let t0 = performance.now();
let viewer = document.querySelector("#viewer");
// let moby = await styles.add("assets/styles/moby-dick.css");
let flow = new Paged.Chunker(text, viewer, preview).then((flow) => {
let t1 = performance.now();
......
......@@ -8,7 +8,7 @@
<script src="../dist/paged.js"></script>
<link rel="stylesheet" type="text/css" href="assets/styles/index.css">
<!-- <link rel="stylesheet" type="text/css" href="assets/styles/mody-dick.css"> -->
<!-- <link rel="stylesheet" type="text/css" href="assets/styles/moby-dick.css"> -->
</head>
<body>
<script>
......@@ -24,8 +24,7 @@
// styles
let styles = new Paged.Styler();
let moby = await styles.add("assets/styles/mody-dick.css");
console.log(moby);
let moby = await styles.add("assets/styles/moby-dick.css");
let flowText = document.querySelector("#flow");
......
This diff is collapsed.
......@@ -248,12 +248,12 @@ class Layout {
if (currentNode.childNodes.length === 0) {
// Check in original
let original = currentNode.getAttribute("children");
let original = currentNode.getAttribute("data-children");
if (original != 0) {
currentNode.remove();
}
} else if (currentNode.textContent.trim().length === 0) {
let original = currentNode.getAttribute("text");
let original = currentNode.getAttribute("data-text");
if (original != 0) {
currentNode.remove();
}
......
......@@ -55,9 +55,9 @@ class ContentParser {
let uuid = UUID();
node.setAttribute("ref", uuid);
node.setAttribute("children", node.childNodes.length);
node.setAttribute("data-children", node.childNodes.length);
node.setAttribute("text", node.textContent.trim().length);
node.setAttribute("data-text", node.textContent.trim().length);
}
}
......
export default `
:root {
--width: 8.5in;
--height: 11in;
--margin-top: 1in;
--margin-right: 1in;
--margin-bottom: 1in;
--margin-left: 1in;
}
.page {
box-sizing: border-box;
width: var(--width);
......
......@@ -27,6 +27,14 @@ class Sheet {
this.addRootVars(this.ast, this.pages["*"].width, this.pages["*"].height);
this.addRootPage(this.ast, this.pages["*"].width, this.pages["*"].height);
}
this.stringSets = this.getStringSets(this.ast);
let targets = this.getTargets(this.ast);
this.counterTargets = targets.counterTargets;
this.textTargets = targets.textTargets;
this.replaceContents(this.ast);
}
// parse
......@@ -542,8 +550,172 @@ class Sheet {
}
}
addPageResets(ast, width, height) {
getStringSets(ast) {
let stringSetSelectors = {};
csstree.walk(ast, {
visit: 'Rule',
enter: (node, item, list) => {
csstree.walk(node, {
visit: 'Declaration',
enter: (declaration, dItem, dList) => {
if (declaration.property === "string-set") {
let selector = csstree.generate(node.prelude);
let identifier = declaration.value.children.first().name
let value;
csstree.walk(declaration, {
visit: 'Function',
enter: (node, item, list) => {
value = csstree.generate(node);
}
});
stringSetSelectors[identifier] = {
identifier: identifier,
value: value,
selector: selector
}
}
}
});
}
});
return stringSetSelectors;
}
getTargets(ast) {
let textTargets = {};
let counterTargets = {};
csstree.walk(ast, {
visit: 'Rule',
enter: (node, item, list) => {
csstree.walk(node, {
visit: 'Declaration',
enter: (declaration, dItem, dList) => {
if (declaration.property === "content") {
csstree.walk(declaration, {
visit: 'Function',
enter: (funcNode, fItem, fList) => {
if (funcNode.name === "target-text") {
let selector = csstree.generate(node.prelude);
let first = funcNode.children.first();
let last = funcNode.children.last();
let func = first.name;
let value = csstree.generate(funcNode);
let args = []
first.children.forEach((child) => {
if (child.type === "Identifier") {
args.push(child.name);
}
});
let style;
if (last !== first) {
style = last.name;
}
selector.split(",").forEach((s) => {
textTargets[s] = {
func: func,
args: args,
value: value,
style: style,
selector: s,
fullSelector: selector
}
});
}
if (funcNode.name === "target-counter") {
let selector = csstree.generate(node.prelude);
let first = funcNode.children.first();
let last = funcNode.children.last();
let func = first.name;
let value = csstree.generate(funcNode);
let args = []
first.children.forEach((child) => {
if (child.type === "Identifier") {
args.push(child.name);
}
});
let counter;
if (last !== first) {
counter = last.name;
}
selector.split(",").forEach((s) => {
counterTargets[s] = {
func: func,
args: args,
value: value,
counter: counter,
selector: s,
fullSelector: selector
}
});
}
}
});
}
}
});
}
});
return {
textTargets,
counterTargets
};
}
replaceContents(ast) {
csstree.walk(ast, {
visit: 'Declaration',
enter: (declaration, dItem, dList) => {
if (declaration.property === "content") {
csstree.walk(declaration, {
visit: 'Function',
enter: (func, fItem, fList) => {
// console.log(func);
if (func.name === "string") {
let identifier = func.children && func.children.first().name;
func.name = "var";
func.children = new csstree.List();
func.children.append(func.children.createItem({
type: "Identifier",
loc: null,
name: "--string-" + identifier
}));
}
if (func.name === "target-text") {
// console.log(func);
}
if (func.name === "target-counter") {
// console.log(func);
}
}
});
}
}
});
}
addRootVars(ast, width, height) {
......
import Sheet from './sheet.js';
import baseStyles from './base.js';
import Sheet from './sheet';
import baseStyles from './base';
import { UUID } from '../utils/utils';
class Styler {
constructor() {
this.sheets = [];
this.addBase();
this.styleEl = document.createElement("style");
document.head.appendChild(this.styleEl);
this.styleSheet = this.styleEl.sheet;
}
async add() {
......@@ -20,6 +24,9 @@ class Styler {
.then((originals) => {
let text = "";
let pageBreaks = {};
let stringSets = {};
let textTargets = {};
let counterTargets = {};
originals.forEach((original, index) => {
let href = arguments[index];
......@@ -28,6 +35,9 @@ class Styler {
this.sheets.push(sheet);
this.mergeBreaks(pageBreaks, sheet.pageBreaks);
stringSets = Object.assign(stringSets, sheet.stringSets);
textTargets = Object.assign(textTargets, sheet.textTargets);
counterTargets = Object.assign(counterTargets, sheet.counterTargets);
text += sheet.toString();
})
......@@ -36,6 +46,11 @@ class Styler {
this.breaks = pageBreaks;
this.stringSets = stringSets;
this.textTargets = textTargets;
this.counterTargets = counterTargets;
return text;
});
}
......@@ -65,6 +80,77 @@ class Styler {
head.appendChild(style);
}
contents(fragment) {
// console.log(fragment);
for (let name of Object.keys(this.stringSets)) {
let set = this.stringSets[name];
let selected = fragment.querySelector(set.selector);
if (selected) {
let cssVar;
if (set.value === "content" || set.value === "content(text)") {
cssVar = selected.textContent.replace(/\\([\s\S])|(["|'])/g,"\\$1$2");
this.styleSheet.insertRule(`:root { --string-${name}: "${cssVar}"; }`, this.styleSheet.cssRules.length);
} else {
console.log(set.value + "needs css replacement");
}
}
}
Object.keys(this.textTargets).forEach((name) => {
let target = this.textTargets[name];
let split = target.selector.split("::");
let query = split[0];
let queried = fragment.querySelectorAll(query);
queried.forEach((selected, index) => {
let val = this.attr(selected, target.args);
let element = fragment.querySelector(val);
if (element) {
if (target.style === "content") {
let text = element.textContent;
let selector = UUID();
selected.setAttribute("data-target-text", selector);
let psuedo = "";
if (split.length > 1) {
psuedo += "::" + split[1];
}
this.styleSheet.insertRule(`[data-target-text="${selector}"]${psuedo} { content: "${element.textContent}"; }`, this.styleSheet.cssRules.length);
}
}
});
});
}
counters(root) {
Object.keys(this.counterTargets).forEach((name) => {
let target = this.counterTargets[name];
let split = target.selector.split("::");
let query = split[0];
let queried = root.querySelectorAll(query);
queried.forEach((selected, index) => {
let val = this.attr(selected, target.args);
let element = fragment.querySelector(val);
if (element) {
console.log("element", element);
}
});
});
}
attr(element, attributes) {
for (var i = 0; i < attributes.length; i++) {
if(element.hasAttribute(attributes[i])) {
return element.getAttribute(attributes[i]);
}
}
}
}
export default Styler;
......@@ -29,3 +29,87 @@ export function UUID() {
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
// From: https://hg.mozilla.org/mozilla-central/file/tip/toolkit/modules/css-selector.js#l52
/**
* Find the position of [element] in [nodeList].
* @returns an index of the match, or -1 if there is no match
*/
export function positionInNodeList(element, nodeList) {
for (let i = 0; i < nodeList.length; i++) {
if (element === nodeList[i]) {
return i;
}
}
return -1;
}
/**
* Find a unique CSS selector for a given element
* @returns a string such that ele.ownerDocument.querySelector(reply) === ele
* and ele.ownerDocument.querySelectorAll(reply).length === 1
*/
export function findCssSelector(ele) {
let document = ele.ownerDocument;
// Fred: commented out to allow for parsing in fragments
// if (!document || !document.contains(ele)) {
// throw new Error("findCssSelector received element not inside document");
// }
let cssEscape = window.CSS.escape;
// document.querySelectorAll("#id") returns multiple if elements share an ID
if (ele.id &&
document.querySelectorAll("#" + cssEscape(ele.id)).length === 1) {
return "#" + cssEscape(ele.id);
}
// Inherently unique by tag name
let tagName = ele.localName;
if (tagName === "html") {
return "html";
}
if (tagName === "head") {
return "head";
}
if (tagName === "body") {
return "body";
}
// We might be able to find a unique class name
let selector, index, matches;
if (ele.classList.length > 0) {
for (let i = 0; i < ele.classList.length; i++) {
// Is this className unique by itself?
selector = "." + cssEscape(ele.classList.item(i));
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
// Maybe it's unique with a tag name?
selector = cssEscape(tagName) + selector;
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
// Maybe it's unique using a tag name and nth-child
index = positionInNodeList(ele, ele.parentNode.children) + 1;
selector = selector + ":nth-child(" + index + ")";
matches = document.querySelectorAll(selector);
if (matches.length === 1) {
return selector;
}
}
}
// Not unique enough yet. As long as it's not a child of the document,
// continue recursing up until it is unique enough.
if (ele.parentNode !== document && ele.parentNode.nodeType === 1) {
index = positionInNodeList(ele, ele.parentNode.children) + 1;
selector = findCssSelector(ele.parentNode) + " > " +
cssEscape(tagName) + ":nth-child(" + index + ")";
}
return selector;
};
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