mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-05 15:32:55 +02:00
Updated Chapter to use cloned document, added find method to get cfi of a string within the chapter, Added Book.chapter method to load a chapter from URL
This commit is contained in:
parent
8829d14186
commit
02fba7d148
6 changed files with 197 additions and 13 deletions
2
books
2
books
|
@ -1 +1 @@
|
||||||
Subproject commit 950c742b3d66cc7ac53bd0663a41315f001da1c4
|
Subproject commit ab9755a74714b647290c861f666515de220935d8
|
13
src/book.js
13
src/book.js
|
@ -1129,6 +1129,19 @@ EPUBJS.Book.prototype.setGap = function(gap) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EPUBJS.Book.prototype.chapter = function(path) {
|
||||||
|
var spinePos = this.spineIndexByURL[path];
|
||||||
|
var spineItem;
|
||||||
|
var chapter;
|
||||||
|
|
||||||
|
if(spinePos){
|
||||||
|
spineItem = this.spine[spinePos];
|
||||||
|
chapter = new EPUBJS.Chapter(spineItem, this.store);
|
||||||
|
chapter.load();
|
||||||
|
}
|
||||||
|
return chapter;
|
||||||
|
};
|
||||||
|
|
||||||
EPUBJS.Book.prototype.unload = function(){
|
EPUBJS.Book.prototype.unload = function(){
|
||||||
|
|
||||||
if(this.settings.restore && localStorage) {
|
if(this.settings.restore && localStorage) {
|
||||||
|
|
112
src/chapter.js
112
src/chapter.js
|
@ -10,18 +10,26 @@ EPUBJS.Chapter = function(spineObject, store){
|
||||||
this.pages = 1;
|
this.pages = 1;
|
||||||
this.store = store;
|
this.store = store;
|
||||||
this.epubcfi = new EPUBJS.EpubCFI();
|
this.epubcfi = new EPUBJS.EpubCFI();
|
||||||
|
this.deferred = new RSVP.defer();
|
||||||
|
this.loaded = this.deferred.promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
EPUBJS.Chapter.prototype.contents = function(_store){
|
EPUBJS.Chapter.prototype.load = function(_store){
|
||||||
var store = _store || this.store;
|
var store = _store || this.store;
|
||||||
|
var promise;
|
||||||
// if(this.store && (!this.book.online || this.book.contained))
|
// if(this.store && (!this.book.online || this.book.contained))
|
||||||
if(store){
|
if(store){
|
||||||
return store.get(href);
|
promise = store.get(this.href);
|
||||||
}else{
|
}else{
|
||||||
return EPUBJS.core.request(href, 'xml');
|
promise = EPUBJS.core.request(this.absolute, 'xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
promise.then(function(xml){
|
||||||
|
this.setDocument(xml);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return promise;
|
||||||
};
|
};
|
||||||
|
|
||||||
EPUBJS.Chapter.prototype.url = function(_store){
|
EPUBJS.Chapter.prototype.url = function(_store){
|
||||||
|
@ -71,13 +79,27 @@ EPUBJS.Chapter.prototype.getID = function(){
|
||||||
};
|
};
|
||||||
|
|
||||||
EPUBJS.Chapter.prototype.unload = function(store){
|
EPUBJS.Chapter.prototype.unload = function(store){
|
||||||
this.contents = null;
|
this.document = null;
|
||||||
if(this.tempUrl && store) {
|
if(this.tempUrl && store) {
|
||||||
store.revokeUrl(this.tempUrl);
|
store.revokeUrl(this.tempUrl);
|
||||||
this.tempUrl = false;
|
this.tempUrl = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EPUBJS.Chapter.prototype.setDocument = function(_document){
|
||||||
|
this.document = _document.implementation.createDocument(
|
||||||
|
_document.namespaceURI, //namespace to use
|
||||||
|
null, //empty document
|
||||||
|
_document.doctype //doctype (null for XML)
|
||||||
|
);
|
||||||
|
this.contents = this.document.importNode(
|
||||||
|
_document.documentElement, //node to import
|
||||||
|
true //clone its descendants
|
||||||
|
);
|
||||||
|
this.document.appendChild(this.contents);
|
||||||
|
this.deferred.resolve(this.contents);
|
||||||
|
};
|
||||||
|
|
||||||
EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
||||||
var range;
|
var range;
|
||||||
var startXpath, endXpath;
|
var startXpath, endXpath;
|
||||||
|
@ -85,17 +107,17 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
||||||
var cleanTextContent, cleanEndTextContent;
|
var cleanTextContent, cleanEndTextContent;
|
||||||
|
|
||||||
// Check for Contents
|
// Check for Contents
|
||||||
if(!this.contents) return;
|
if(!this.document) return;
|
||||||
startXpath = EPUBJS.core.getElementXPath(_range.startContainer);
|
startXpath = EPUBJS.core.getElementXPath(_range.startContainer);
|
||||||
// console.log(startContainer)
|
// console.log(startContainer)
|
||||||
endXpath = EPUBJS.core.getElementXPath(_range.endContainer);
|
endXpath = EPUBJS.core.getElementXPath(_range.endContainer);
|
||||||
startContainer = this.contents.evaluate(startXpath, this.contents, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
startContainer = this.document.evaluate(startXpath, this.document, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||||
|
|
||||||
if(!_range.collapsed) {
|
if(!_range.collapsed) {
|
||||||
endContainer = this.contents.evaluate(endXpath, this.contents, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
endContainer = this.document.evaluate(endXpath, this.document, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
range = this.contents.createRange();
|
range = this.document.createRange();
|
||||||
// Find Exact Range in original document
|
// Find Exact Range in original document
|
||||||
if(startContainer) {
|
if(startContainer) {
|
||||||
try {
|
try {
|
||||||
|
@ -116,7 +138,7 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
||||||
cleanStartTextContent = EPUBJS.core.cleanStringForXpath(_range.startContainer.textContent);
|
cleanStartTextContent = EPUBJS.core.cleanStringForXpath(_range.startContainer.textContent);
|
||||||
startXpath = "//text()[contains(.," + cleanStartTextContent + ")]";
|
startXpath = "//text()[contains(.," + cleanStartTextContent + ")]";
|
||||||
|
|
||||||
startContainer = this.contents.evaluate(startXpath, this.contents, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
startContainer = this.document.evaluate(startXpath, this.document, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||||
|
|
||||||
if(startContainer){
|
if(startContainer){
|
||||||
// console.log("Found with Fuzzy");
|
// console.log("Found with Fuzzy");
|
||||||
|
@ -125,7 +147,7 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
||||||
if(!_range.collapsed) {
|
if(!_range.collapsed) {
|
||||||
cleanEndTextContent = EPUBJS.core.cleanStringForXpath(_range.endContainer.textContent);
|
cleanEndTextContent = EPUBJS.core.cleanStringForXpath(_range.endContainer.textContent);
|
||||||
endXpath = "//text()[contains(.," + cleanEndTextContent + ")]";
|
endXpath = "//text()[contains(.," + cleanEndTextContent + ")]";
|
||||||
endContainer = this.contents.evaluate(endXpath, this.contents, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
endContainer = this.document.evaluate(endXpath, this.document, EPUBJS.core.nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||||
if(endContainer) {
|
if(endContainer) {
|
||||||
range.setEnd(endContainer, _range.endOffset);
|
range.setEnd(endContainer, _range.endOffset);
|
||||||
}
|
}
|
||||||
|
@ -137,3 +159,71 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
|
||||||
// Generate the Cfi
|
// Generate the Cfi
|
||||||
return this.epubcfi.generateCfiFromRange(range, this.cfiBase);
|
return this.epubcfi.generateCfiFromRange(range, this.cfiBase);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
EPUBJS.Chapter.prototype.find = function(_query){
|
||||||
|
var chapter = this;
|
||||||
|
var matches = [];
|
||||||
|
var query = _query.toLowerCase();
|
||||||
|
//var xpath = this.document.evaluate(".//text()[contains(translate(., '"+query.toUpperCase()+"', '"+query+"'),'"+query+"')]", this.document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
||||||
|
var find = function(node){
|
||||||
|
// Search String
|
||||||
|
var text = node.textContent.toLowerCase();
|
||||||
|
var range = chapter.document.createRange();
|
||||||
|
var cfi;
|
||||||
|
var pos;
|
||||||
|
var last = -1;
|
||||||
|
|
||||||
|
while (pos != -1) {
|
||||||
|
pos = text.indexOf(query, last + 1);
|
||||||
|
|
||||||
|
if(pos != -1) {
|
||||||
|
// If Found, Create Range
|
||||||
|
range = chapter.document.createRange();
|
||||||
|
range.setStart(node, pos);
|
||||||
|
range.setEnd(node, pos + query.length);
|
||||||
|
|
||||||
|
//Generate CFI
|
||||||
|
cfi = chapter.cfiFromRange(range);
|
||||||
|
//Add CFI to list
|
||||||
|
matches.push(cfi);
|
||||||
|
}
|
||||||
|
|
||||||
|
last = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab text nodes
|
||||||
|
|
||||||
|
/*
|
||||||
|
for ( var i=0 ; i < xpath.snapshotLength; i++ ) {
|
||||||
|
find(xpath.snapshotItem(i));
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.textSprint(this.document, function(node){
|
||||||
|
find(node);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Return List of CFIs
|
||||||
|
return matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
EPUBJS.Chapter.prototype.textSprint = function(root, func) {
|
||||||
|
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
|
||||||
|
acceptNode: function (node) {
|
||||||
|
if ( ! /^\s*$/.test(node.data) ) {
|
||||||
|
return NodeFilter.FILTER_ACCEPT;
|
||||||
|
} else {
|
||||||
|
return NodeFilter.FILTER_REJECT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
var node;
|
||||||
|
while ((node = treeWalker.nextNode())) {
|
||||||
|
func(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -153,7 +153,7 @@ EPUBJS.Renderer.prototype.load = function(url){
|
||||||
|
|
||||||
render.then(function(contents) {
|
render.then(function(contents) {
|
||||||
var formated;
|
var formated;
|
||||||
this.currentChapter.contents = this.render.document;
|
this.currentChapter.setDocument(this.render.document);
|
||||||
this.contents = contents;
|
this.contents = contents;
|
||||||
this.doc = this.render.document;
|
this.doc = this.render.document;
|
||||||
|
|
||||||
|
|
80
tests/chapter.js
Normal file
80
tests/chapter.js
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
module('Chapter');
|
||||||
|
asyncTest("Create a Chapter", 2, function() {
|
||||||
|
var book = ePub('/reader/moby-dick/', { width: 400, height: 600 });
|
||||||
|
|
||||||
|
book.ready.all.then(function(){
|
||||||
|
var chapter = book.chapter("chapter_001.xhtml");
|
||||||
|
equal(chapter.spinePos, 6, "Chapter Pos is correct" );
|
||||||
|
equal(chapter.href, "chapter_001.xhtml", "Chapter href is correct" );
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("Load a Chapter", 2, function() {
|
||||||
|
var book = ePub('/reader/moby-dick/', { width: 400, height: 600 });
|
||||||
|
|
||||||
|
book.ready.all.then(function(){
|
||||||
|
var chapter = book.chapter("chapter_001.xhtml");
|
||||||
|
// var loaded = chapter.load();
|
||||||
|
start();
|
||||||
|
equal(chapter.href, "chapter_001.xhtml", "Chapter href is correct" );
|
||||||
|
stop();
|
||||||
|
|
||||||
|
chapter.loaded.then(function(){
|
||||||
|
equal(chapter.document.firstChild.nodeName, "html", "Document HTML is loaded" );
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("Find a single query in a Chapter", 3, function() {
|
||||||
|
var book = ePub('/reader/moby-dick/', { width: 400, height: 600 });
|
||||||
|
|
||||||
|
book.ready.all.then(function(){
|
||||||
|
var chapter = book.chapter("chapter_001.xhtml");
|
||||||
|
// var loaded = chapter.load();
|
||||||
|
start();
|
||||||
|
equal(chapter.href, "chapter_001.xhtml", "Chapter href is correct" );
|
||||||
|
stop();
|
||||||
|
|
||||||
|
chapter.loaded.then(function(){
|
||||||
|
var results = chapter.find("pythagorean maxim");
|
||||||
|
|
||||||
|
equal(results.length, 1, "Results are returned" );
|
||||||
|
equal(results[0], "epubcfi(/6/14[xchapter_001]!4/2/24/2[c001p0011]/1:227,4/2/24/2[c001p0011]/1:244)", "CFI is generated");
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("Find a query with several results in a Chapter", 3, function() {
|
||||||
|
var book = ePub('/reader/moby-dick/', { width: 400, height: 600 });
|
||||||
|
|
||||||
|
book.ready.all.then(function(){
|
||||||
|
var chapter = book.chapter("chapter_001.xhtml");
|
||||||
|
// var loaded = chapter.load();
|
||||||
|
start();
|
||||||
|
equal(chapter.href, "chapter_001.xhtml", "Chapter href is correct");
|
||||||
|
stop();
|
||||||
|
|
||||||
|
chapter.loaded.then(function(){
|
||||||
|
var results = chapter.find("yet");
|
||||||
|
|
||||||
|
equal(results.length, 4, "Results are returned" );
|
||||||
|
equal(results[3], "epubcfi(/6/14[xchapter_001]!4/2/28/2[c001p0015]/1:314,4/2/28/2[c001p0015]/1:317)", "CFI is generated");
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -51,6 +51,7 @@
|
||||||
<script src="unarchiver.js"></script>
|
<script src="unarchiver.js"></script>
|
||||||
<script src="pagination.js"></script>
|
<script src="pagination.js"></script>
|
||||||
<script src="epubcfi.js"></script>
|
<script src="epubcfi.js"></script>
|
||||||
|
<script src="chapter.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue