mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
Allow location to use XMLDom, add locations tests
This commit is contained in:
parent
662a3e1079
commit
db798e7934
9 changed files with 254 additions and 100 deletions
|
@ -77,7 +77,7 @@
|
||||||
book.ready.then(function(){
|
book.ready.then(function(){
|
||||||
// Load in stored locations from json or local storage
|
// Load in stored locations from json or local storage
|
||||||
var key = book.key()+'-locations';
|
var key = book.key()+'-locations';
|
||||||
var stored = false;//localStorage.getItem(key);
|
var stored = localStorage.getItem(key);
|
||||||
if (stored) {
|
if (stored) {
|
||||||
return book.locations.load(stored);
|
return book.locations.load(stored);
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,7 +88,6 @@
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(function(locations){
|
.then(function(locations){
|
||||||
|
|
||||||
controls.style.display = "block";
|
controls.style.display = "block";
|
||||||
slider.setAttribute("type", "range");
|
slider.setAttribute("type", "range");
|
||||||
slider.setAttribute("min", 0);
|
slider.setAttribute("min", 0);
|
||||||
|
|
|
@ -45,8 +45,8 @@ module.exports = function(config) {
|
||||||
|
|
||||||
webpack:{
|
webpack:{
|
||||||
externals: {
|
externals: {
|
||||||
"jszip": "JSZip",
|
"jszip": "JSZip"
|
||||||
"xmldom": "xmldom"
|
// "xmldom": "xmldom"
|
||||||
},
|
},
|
||||||
devtool: 'inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
79
src/core.js
79
src/core.js
|
@ -485,11 +485,10 @@ function type(obj){
|
||||||
return Object.prototype.toString.call(obj).slice(8, -1);
|
return Object.prototype.toString.call(obj).slice(8, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parse(markup, mime) {
|
function parse(markup, mime, forceXMLDom) {
|
||||||
var doc;
|
var doc;
|
||||||
// console.log("parse", markup);
|
|
||||||
|
|
||||||
if (typeof DOMParser === "undefined") {
|
if (typeof DOMParser === "undefined" || forceXMLDom) {
|
||||||
DOMParser = require('xmldom').DOMParser;
|
DOMParser = require('xmldom').DOMParser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -501,6 +500,9 @@ function parse(markup, mime) {
|
||||||
|
|
||||||
function qs(el, sel) {
|
function qs(el, sel) {
|
||||||
var elements;
|
var elements;
|
||||||
|
if (!el) {
|
||||||
|
throw new Error('No Element Provided');
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof el.querySelector != "undefined") {
|
if (typeof el.querySelector != "undefined") {
|
||||||
return el.querySelector(sel);
|
return el.querySelector(sel);
|
||||||
|
@ -547,6 +549,61 @@ function qsp(el, sel, props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sprint through all text nodes in a document
|
||||||
|
* @param {element} root element to start with
|
||||||
|
* @param {function} func function to run on each element
|
||||||
|
*/
|
||||||
|
function sprint(root, func) {
|
||||||
|
var doc = root.ownerDocument || root;
|
||||||
|
if (typeof(doc.createTreeWalker) !== "undefined") {
|
||||||
|
treeWalker(root, func, NodeFilter.SHOW_TEXT);
|
||||||
|
} else {
|
||||||
|
walk(root, function(node) {
|
||||||
|
if (node && node.nodeType === 3) { // Node.TEXT_NODE
|
||||||
|
func(node);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function treeWalker(root, func, filter) {
|
||||||
|
var treeWalker = document.createTreeWalker(root, filter, null, false);
|
||||||
|
while ((node = treeWalker.nextNode())) {
|
||||||
|
func(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function walk(root, func, onlyText) {
|
||||||
|
// var node = root;
|
||||||
|
//
|
||||||
|
// if (node && !onlyText || node.nodeType === 3) { // Node.TEXT_NODE
|
||||||
|
// func(node);
|
||||||
|
// }
|
||||||
|
// console.log(root);
|
||||||
|
//
|
||||||
|
// node = node.firstChild;
|
||||||
|
// while(node) {
|
||||||
|
// walk(node, func, onlyText);
|
||||||
|
// node = node.nextSibling;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param callback return false for continue,true for break
|
||||||
|
* @return boolean true: break visit;
|
||||||
|
*/
|
||||||
|
function walk(node,callback){
|
||||||
|
if(callback(node)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(node = node.firstChild){
|
||||||
|
do{
|
||||||
|
if(walk(node,callback)){return true}
|
||||||
|
}while(node=node.nextSibling)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function blob2base64(blob, cb) {
|
function blob2base64(blob, cb) {
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
reader.readAsDataURL(blob);
|
reader.readAsDataURL(blob);
|
||||||
|
@ -605,7 +662,17 @@ function defer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function children(el) {
|
||||||
|
var children = [];
|
||||||
|
var childNodes = el.parentNode.childNodes;
|
||||||
|
for (var i = 0; i < childNodes.length; i++) {
|
||||||
|
node = childNodes[i];
|
||||||
|
if (node.nodeType === 1) {
|
||||||
|
children.push(node);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
'isElement': isElement,
|
'isElement': isElement,
|
||||||
|
@ -640,5 +707,7 @@ module.exports = {
|
||||||
'defer': defer,
|
'defer': defer,
|
||||||
'Url': Url,
|
'Url': Url,
|
||||||
'Path': Path,
|
'Path': Path,
|
||||||
'querySelectorByType': querySelectorByType
|
'querySelectorByType': querySelectorByType,
|
||||||
|
'sprint' : sprint,
|
||||||
|
'children' : children
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,6 +14,11 @@ var core = require('./core');
|
||||||
- Text Location Assertion ([)
|
- Text Location Assertion ([)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
var ELEMENT_NODE = 1;
|
||||||
|
var TEXT_NODE = 3;
|
||||||
|
var COMMENT_NODE = 8;
|
||||||
|
var DOCUMENT_NODE = 9;
|
||||||
|
|
||||||
function EpubCFI(cfiFrom, base, ignoreClass){
|
function EpubCFI(cfiFrom, base, ignoreClass){
|
||||||
var type;
|
var type;
|
||||||
|
|
||||||
|
@ -64,7 +69,7 @@ EpubCFI.prototype.checkType = function(cfi) {
|
||||||
if (this.isCfiString(cfi)) {
|
if (this.isCfiString(cfi)) {
|
||||||
return 'string';
|
return 'string';
|
||||||
// Is a range object
|
// Is a range object
|
||||||
} else if (typeof cfi === 'object' && core.type(cfi) === "Range"){
|
} else if (typeof cfi === 'object' && (core.type(cfi) === "Range" || typeof(cfi.startContainer) != "undefined")){
|
||||||
return 'range';
|
return 'range';
|
||||||
} else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function'
|
} else if (typeof cfi === 'object' && typeof(cfi.nodeType) != "undefined" ){ // || typeof cfi === 'function'
|
||||||
return 'node';
|
return 'node';
|
||||||
|
@ -372,7 +377,7 @@ EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
|
||||||
};
|
};
|
||||||
|
|
||||||
EpubCFI.prototype.step = function(node) {
|
EpubCFI.prototype.step = function(node) {
|
||||||
var nodeType = (node.nodeType === Node.TEXT_NODE) ? 'text' : 'element';
|
var nodeType = (node.nodeType === TEXT_NODE) ? 'text' : 'element';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id' : node.id,
|
'id' : node.id,
|
||||||
|
@ -392,7 +397,7 @@ EpubCFI.prototype.filteredStep = function(node, ignoreClass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise add the filter node in
|
// Otherwise add the filter node in
|
||||||
nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element';
|
nodeType = (filteredNode.nodeType === TEXT_NODE) ? 'text' : 'element';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id' : filteredNode.id,
|
'id' : filteredNode.id,
|
||||||
|
@ -414,7 +419,7 @@ EpubCFI.prototype.pathTo = function(node, offset, ignoreClass) {
|
||||||
var step;
|
var step;
|
||||||
|
|
||||||
while(currentNode && currentNode.parentNode &&
|
while(currentNode && currentNode.parentNode &&
|
||||||
currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) {
|
currentNode.parentNode.nodeType != DOCUMENT_NODE) {
|
||||||
|
|
||||||
if (ignoreClass) {
|
if (ignoreClass) {
|
||||||
step = this.filteredStep(currentNode, ignoreClass);
|
step = this.filteredStep(currentNode, ignoreClass);
|
||||||
|
@ -461,6 +466,7 @@ EpubCFI.prototype.equalStep = function(stepA, stepB) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
EpubCFI.prototype.fromRange = function(range, base, ignoreClass) {
|
EpubCFI.prototype.fromRange = function(range, base, ignoreClass) {
|
||||||
var cfi = {
|
var cfi = {
|
||||||
range: false,
|
range: false,
|
||||||
|
@ -576,14 +582,13 @@ EpubCFI.prototype.fromNode = function(anchor, base, ignoreClass) {
|
||||||
return cfi;
|
return cfi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
EpubCFI.prototype.filter = function(anchor, ignoreClass) {
|
EpubCFI.prototype.filter = function(anchor, ignoreClass) {
|
||||||
var needsIgnoring;
|
var needsIgnoring;
|
||||||
var sibling; // to join with
|
var sibling; // to join with
|
||||||
var parent, prevSibling, nextSibling;
|
var parent, prevSibling, nextSibling;
|
||||||
var isText = false;
|
var isText = false;
|
||||||
|
|
||||||
if (anchor.nodeType === Node.TEXT_NODE) {
|
if (anchor.nodeType === TEXT_NODE) {
|
||||||
isText = true;
|
isText = true;
|
||||||
parent = anchor.parentNode;
|
parent = anchor.parentNode;
|
||||||
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
|
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
|
||||||
|
@ -597,9 +602,9 @@ EpubCFI.prototype.filter = function(anchor, ignoreClass) {
|
||||||
nextSibling = parent.nextSibling;
|
nextSibling = parent.nextSibling;
|
||||||
|
|
||||||
// If the sibling is a text node, join the nodes
|
// If the sibling is a text node, join the nodes
|
||||||
if (previousSibling && previousSibling.nodeType === Node.TEXT_NODE) {
|
if (previousSibling && previousSibling.nodeType === TEXT_NODE) {
|
||||||
sibling = previousSibling;
|
sibling = previousSibling;
|
||||||
} else if (nextSibling && nextSibling.nodeType === Node.TEXT_NODE) {
|
} else if (nextSibling && nextSibling.nodeType === TEXT_NODE) {
|
||||||
sibling = nextSibling;
|
sibling = nextSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -624,7 +629,7 @@ EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {
|
||||||
var needsIgnoring;
|
var needsIgnoring;
|
||||||
var sibling;
|
var sibling;
|
||||||
|
|
||||||
if (anchor.nodeType != Node.TEXT_NODE) {
|
if (anchor.nodeType != TEXT_NODE) {
|
||||||
console.error("Anchor must be a text node");
|
console.error("Anchor must be a text node");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -638,7 +643,7 @@ EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (curr.previousSibling) {
|
while (curr.previousSibling) {
|
||||||
if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) {
|
if(curr.previousSibling.nodeType === ELEMENT_NODE) {
|
||||||
// Originally a text node, so join
|
// Originally a text node, so join
|
||||||
if(curr.previousSibling.classList.contains(ignoreClass)){
|
if(curr.previousSibling.classList.contains(ignoreClass)){
|
||||||
totalOffset += curr.previousSibling.textContent.length;
|
totalOffset += curr.previousSibling.textContent.length;
|
||||||
|
@ -669,14 +674,14 @@ EpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) {
|
||||||
currNodeType = children[i].nodeType;
|
currNodeType = children[i].nodeType;
|
||||||
|
|
||||||
// Check if needs ignoring
|
// Check if needs ignoring
|
||||||
if (currNodeType === Node.ELEMENT_NODE &&
|
if (currNodeType === ELEMENT_NODE &&
|
||||||
children[i].classList.contains(ignoreClass)) {
|
children[i].classList.contains(ignoreClass)) {
|
||||||
currNodeType = Node.TEXT_NODE;
|
currNodeType = TEXT_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i > 0 &&
|
if (i > 0 &&
|
||||||
currNodeType === Node.TEXT_NODE &&
|
currNodeType === TEXT_NODE &&
|
||||||
prevNodeType === Node.TEXT_NODE) {
|
prevNodeType === TEXT_NODE) {
|
||||||
// join text nodes
|
// join text nodes
|
||||||
output[i] = prevIndex;
|
output[i] = prevIndex;
|
||||||
} else if (nodeType === currNodeType){
|
} else if (nodeType === currNodeType){
|
||||||
|
@ -693,9 +698,12 @@ EpubCFI.prototype.normalizedMap = function(children, nodeType, ignoreClass) {
|
||||||
|
|
||||||
EpubCFI.prototype.position = function(anchor) {
|
EpubCFI.prototype.position = function(anchor) {
|
||||||
var children, index, map;
|
var children, index, map;
|
||||||
|
var childNodes, node;
|
||||||
if (anchor.nodeType === Node.ELEMENT_NODE) {
|
if (anchor.nodeType === ELEMENT_NODE) {
|
||||||
children = anchor.parentNode.children;
|
children = anchor.parentNode.children;
|
||||||
|
if (!children) {
|
||||||
|
children = core.children(anchor.parentNode);
|
||||||
|
}
|
||||||
index = Array.prototype.indexOf.call(children, anchor);
|
index = Array.prototype.indexOf.call(children, anchor);
|
||||||
} else {
|
} else {
|
||||||
children = this.textNodes(anchor.parentNode);
|
children = this.textNodes(anchor.parentNode);
|
||||||
|
@ -708,9 +716,9 @@ EpubCFI.prototype.position = function(anchor) {
|
||||||
EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {
|
EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {
|
||||||
var children, index, map;
|
var children, index, map;
|
||||||
|
|
||||||
if (anchor.nodeType === Node.ELEMENT_NODE) {
|
if (anchor.nodeType === ELEMENT_NODE) {
|
||||||
children = anchor.parentNode.children;
|
children = anchor.parentNode.children;
|
||||||
map = this.normalizedMap(children, Node.ELEMENT_NODE, ignoreClass);
|
map = this.normalizedMap(children, ELEMENT_NODE, ignoreClass);
|
||||||
} else {
|
} else {
|
||||||
children = anchor.parentNode.childNodes;
|
children = anchor.parentNode.childNodes;
|
||||||
// Inside an ignored node
|
// Inside an ignored node
|
||||||
|
@ -718,7 +726,7 @@ EpubCFI.prototype.filteredPosition = function(anchor, ignoreClass) {
|
||||||
anchor = anchor.parentNode;
|
anchor = anchor.parentNode;
|
||||||
children = anchor.parentNode.childNodes;
|
children = anchor.parentNode.childNodes;
|
||||||
}
|
}
|
||||||
map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);
|
map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -784,7 +792,7 @@ EpubCFI.prototype.stepsToQuerySelector = function(steps) {
|
||||||
EpubCFI.prototype.textNodes = function(container, ignoreClass) {
|
EpubCFI.prototype.textNodes = function(container, ignoreClass) {
|
||||||
return Array.prototype.slice.call(container.childNodes).
|
return Array.prototype.slice.call(container.childNodes).
|
||||||
filter(function (node) {
|
filter(function (node) {
|
||||||
if (node.nodeType === Node.TEXT_NODE) {
|
if (node.nodeType === TEXT_NODE) {
|
||||||
return true;
|
return true;
|
||||||
} else if (ignoreClass && node.classList.contains(ignoreClass)) {
|
} else if (ignoreClass && node.classList.contains(ignoreClass)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -834,7 +842,7 @@ EpubCFI.prototype.findNode = function(steps, _doc, ignoreClass) {
|
||||||
EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {
|
EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {
|
||||||
var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);
|
var container = this.findNode(steps.slice(0,-1), _doc, ignoreClass);
|
||||||
var children = container.childNodes;
|
var children = container.childNodes;
|
||||||
var map = this.normalizedMap(children, Node.TEXT_NODE, ignoreClass);
|
var map = this.normalizedMap(children, TEXT_NODE, ignoreClass);
|
||||||
var i;
|
var i;
|
||||||
var child;
|
var child;
|
||||||
var len;
|
var len;
|
||||||
|
@ -850,7 +858,7 @@ EpubCFI.prototype.fixMiss = function(steps, offset, _doc, ignoreClass) {
|
||||||
if(offset > len) {
|
if(offset > len) {
|
||||||
offset = offset - len;
|
offset = offset - len;
|
||||||
} else {
|
} else {
|
||||||
if (child.nodeType === Node.ELEMENT_NODE) {
|
if (child.nodeType === ELEMENT_NODE) {
|
||||||
container = child.childNodes[0];
|
container = child.childNodes[0];
|
||||||
} else {
|
} else {
|
||||||
container = child;
|
container = child;
|
||||||
|
|
153
src/locations.js
153
src/locations.js
|
@ -39,7 +39,7 @@ Locations.prototype.generate = function(chars) {
|
||||||
|
|
||||||
this.spine.each(function(section) {
|
this.spine.each(function(section) {
|
||||||
|
|
||||||
this.q.enqueue(this.process, section);
|
this.q.enqueue(this.process.bind(this), section);
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
@ -56,85 +56,100 @@ Locations.prototype.generate = function(chars) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Locations.prototype.createRange = function () {
|
||||||
|
return {
|
||||||
|
startContainer: undefined,
|
||||||
|
startOffset: undefined,
|
||||||
|
endContainer: undefined,
|
||||||
|
endOffset: undefined
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Locations.prototype.process = function(section) {
|
Locations.prototype.process = function(section) {
|
||||||
|
|
||||||
return section.load(this.request)
|
return section.load(this.request)
|
||||||
.then(function(contents) {
|
.then(function(contents) {
|
||||||
|
var locations = this.parse(contents, section.cfiBase);
|
||||||
var range;
|
this._locations = this._locations.concat(locations);
|
||||||
var doc = contents.ownerDocument;
|
|
||||||
var body = core.qs(doc, 'body');
|
|
||||||
var counter = 0;
|
|
||||||
|
|
||||||
this.sprint(body, function(node) {
|
|
||||||
var len = node.length;
|
|
||||||
var dist;
|
|
||||||
var pos = 0;
|
|
||||||
console.log(counter);
|
|
||||||
// Start range
|
|
||||||
if (counter == 0) {
|
|
||||||
range = doc.createRange();
|
|
||||||
range.setStart(node, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
dist = this.break - counter;
|
|
||||||
|
|
||||||
// Node is smaller than a break
|
|
||||||
if(dist > len){
|
|
||||||
counter += len;
|
|
||||||
pos = len;
|
|
||||||
}
|
|
||||||
console.log(counter);
|
|
||||||
|
|
||||||
while (pos < len) {
|
|
||||||
counter = this.break;
|
|
||||||
pos += this.break;
|
|
||||||
|
|
||||||
// Gone over
|
|
||||||
if(pos >= len){
|
|
||||||
// Continue counter for next node
|
|
||||||
counter = len - (pos - this.break);
|
|
||||||
|
|
||||||
// At End
|
|
||||||
} else {
|
|
||||||
// End the previous range
|
|
||||||
range.setEnd(node, pos);
|
|
||||||
cfi = section.cfiFromRange(range);
|
|
||||||
this._locations.push(cfi);
|
|
||||||
counter = 0;
|
|
||||||
console.log(cfi);
|
|
||||||
|
|
||||||
// Start new range
|
|
||||||
pos += 1;
|
|
||||||
range = doc.createRange();
|
|
||||||
range.setStart(node, pos);
|
|
||||||
}
|
|
||||||
console.log(counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}.bind(this));
|
|
||||||
|
|
||||||
// Close remaining
|
|
||||||
if (range) {
|
|
||||||
range.setEnd(prev, prev.length);
|
|
||||||
cfi = section.cfiFromRange(range);
|
|
||||||
this._locations.push(cfi)
|
|
||||||
counter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Locations.prototype.sprint = function(root, func) {
|
Locations.prototype.parse = function(contents, cfiBase, chars) {
|
||||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
|
var locations = [];
|
||||||
|
var range;
|
||||||
|
var doc = contents.ownerDocument;
|
||||||
|
var body = core.qs(doc, 'body');
|
||||||
|
var counter = 0;
|
||||||
|
var prev;
|
||||||
|
var _break = chars || this.break;
|
||||||
|
var parser = function(node) {
|
||||||
|
var len = node.length;
|
||||||
|
var dist;
|
||||||
|
var pos = 0;
|
||||||
|
|
||||||
while ((node = treeWalker.nextNode())) {
|
if (node.textContent.trim().length === 0) {
|
||||||
func(node);
|
return false; // continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start range
|
||||||
|
if (counter == 0) {
|
||||||
|
range = this.createRange();
|
||||||
|
range.startContainer = node;
|
||||||
|
range.startOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dist = _break - counter;
|
||||||
|
|
||||||
|
// Node is smaller than a break,
|
||||||
|
// skip over it
|
||||||
|
if(dist > len){
|
||||||
|
counter += len;
|
||||||
|
pos = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (pos < len) {
|
||||||
|
// counter = this.break;
|
||||||
|
pos += dist;
|
||||||
|
// Gone over
|
||||||
|
if(pos >= len){
|
||||||
|
// Continue counter for next node
|
||||||
|
counter = len - (pos - _break);
|
||||||
|
// At End
|
||||||
|
} else {
|
||||||
|
// End the previous range
|
||||||
|
range.endContainer = node;
|
||||||
|
range.endOffset = pos;
|
||||||
|
// cfi = section.cfiFromRange(range);
|
||||||
|
cfi = new EpubCFI(range, cfiBase).toString();
|
||||||
|
locations.push(cfi);
|
||||||
|
counter = 0;
|
||||||
|
|
||||||
|
// Start new range
|
||||||
|
pos += 1;
|
||||||
|
range = this.createRange();
|
||||||
|
range.startContainer = node;
|
||||||
|
range.startOffset = pos;
|
||||||
|
|
||||||
|
dist = _break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
};
|
||||||
|
|
||||||
|
core.sprint(body, parser.bind(this));
|
||||||
|
|
||||||
|
// Close remaining
|
||||||
|
if (range && range.startContainer && prev) {
|
||||||
|
range.endContainer = prev;
|
||||||
|
range.endOffset = prev.length;
|
||||||
|
// cfi = section.cfiFromRange(range);
|
||||||
|
cfi = new EpubCFI(range, cfiBase).toString();
|
||||||
|
locations.push(cfi);
|
||||||
|
counter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return locations;
|
||||||
};
|
};
|
||||||
|
|
||||||
Locations.prototype.locationFromCfi = function(cfi){
|
Locations.prototype.locationFromCfi = function(cfi){
|
||||||
|
|
28
test/fixtures/locations.xhtml
vendored
Normal file
28
test/fixtures/locations.xhtml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops">
|
||||||
|
<head>
|
||||||
|
<title>
|
||||||
|
Moby-Dick</title>
|
||||||
|
<link rel="stylesheet" href="css/stylesheet.css" type="text/css"></link>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<section class="body-rw Chapter-rw" epub:type="bodymatter chapter">
|
||||||
|
<header>
|
||||||
|
<!-- 20 -->
|
||||||
|
<h1>Chapter 1. Loomings.</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- 1107 -->
|
||||||
|
<p>Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world.
|
||||||
|
It is a way I have of driving off the spleen and regulating the circulation.
|
||||||
|
Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can.
|
||||||
|
This is my substitute for pistol and ball.
|
||||||
|
With a philosophical flourish Cato throws himself upon his sword; I quietly take to the ship.
|
||||||
|
There is nothing surprising in this.
|
||||||
|
If they but knew it, almost all men in their degree, some time or other, cherish very nearly the same feelings towards the ocean with me.</p>
|
||||||
|
|
||||||
|
<!-- 387 -->
|
||||||
|
<p>There now is your insular city of the Manhattoes, belted round by wharves as Indian isles by coral reefs—commerce surrounds it with her surf. Right and left, the streets take you waterward. Its extreme downtown is the battery, where that noble mole is washed by waves, and cooled by breezes, which a few hours previous were out of sight of land. Look at the crowds of water-gazers there.</p>
|
||||||
|
|
||||||
|
</section></body></html>
|
35
test/locations.js
Normal file
35
test/locations.js
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
describe('Locations', function() {
|
||||||
|
var Locations = require('../src/locations');
|
||||||
|
var core = require('../src/core');
|
||||||
|
var chapter = require('raw-loader!./fixtures/locations.xhtml');
|
||||||
|
|
||||||
|
describe('#parse', function() {
|
||||||
|
var Locations = require('../src/locations');
|
||||||
|
var core = require('../src/core');
|
||||||
|
var chapter = require('raw-loader!./fixtures/locations.xhtml');
|
||||||
|
|
||||||
|
it('parse locations from a document', function() {
|
||||||
|
var doc = core.parse(chapter, "application/xhtml+xml");
|
||||||
|
var contents = doc.documentElement;
|
||||||
|
var locations = new Locations();
|
||||||
|
var result = locations.parse(contents, "/6/4[chap01ref]", 100);
|
||||||
|
assert.equal(result.length, 15);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parse locations from xmldom', function() {
|
||||||
|
var doc = core.parse(chapter, "application/xhtml+xml", true);
|
||||||
|
var contents = doc.documentElement;
|
||||||
|
|
||||||
|
var locations = new Locations();
|
||||||
|
var result = locations.parse(contents, "/6/4[chap01ref]", 100);
|
||||||
|
console.log(result);
|
||||||
|
assert.equal(result.length, 15);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue