diff --git a/books b/books
index 950c742..ab9755a 160000
--- a/books
+++ b/books
@@ -1 +1 @@
-Subproject commit 950c742b3d66cc7ac53bd0663a41315f001da1c4
+Subproject commit ab9755a74714b647290c861f666515de220935d8
diff --git a/src/book.js b/src/book.js
index f465cd5..9d6f328 100644
--- a/src/book.js
+++ b/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(){
if(this.settings.restore && localStorage) {
diff --git a/src/chapter.js b/src/chapter.js
index b4fbf72..4b6cb92 100644
--- a/src/chapter.js
+++ b/src/chapter.js
@@ -10,18 +10,26 @@ EPUBJS.Chapter = function(spineObject, store){
this.pages = 1;
this.store = store;
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 promise;
// if(this.store && (!this.book.online || this.book.contained))
if(store){
- return store.get(href);
+ promise = store.get(this.href);
}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){
@@ -71,13 +79,27 @@ EPUBJS.Chapter.prototype.getID = function(){
};
EPUBJS.Chapter.prototype.unload = function(store){
- this.contents = null;
+ this.document = null;
if(this.tempUrl && store) {
store.revokeUrl(this.tempUrl);
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) {
var range;
var startXpath, endXpath;
@@ -85,17 +107,17 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
var cleanTextContent, cleanEndTextContent;
// Check for Contents
- if(!this.contents) return;
+ if(!this.document) return;
startXpath = EPUBJS.core.getElementXPath(_range.startContainer);
// console.log(startContainer)
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) {
- 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
if(startContainer) {
try {
@@ -116,7 +138,7 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
cleanStartTextContent = EPUBJS.core.cleanStringForXpath(_range.startContainer.textContent);
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){
// console.log("Found with Fuzzy");
@@ -125,7 +147,7 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
if(!_range.collapsed) {
cleanEndTextContent = EPUBJS.core.cleanStringForXpath(_range.endContainer.textContent);
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) {
range.setEnd(endContainer, _range.endOffset);
}
@@ -137,3 +159,71 @@ EPUBJS.Chapter.prototype.cfiFromRange = function(_range) {
// Generate the Cfi
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);
+ }
+
+};
\ No newline at end of file
diff --git a/src/renderer.js b/src/renderer.js
index 4a731dd..071eb57 100644
--- a/src/renderer.js
+++ b/src/renderer.js
@@ -153,7 +153,7 @@ EPUBJS.Renderer.prototype.load = function(url){
render.then(function(contents) {
var formated;
- this.currentChapter.contents = this.render.document;
+ this.currentChapter.setDocument(this.render.document);
this.contents = contents;
this.doc = this.render.document;
diff --git a/tests/chapter.js b/tests/chapter.js
new file mode 100644
index 0000000..d59fd87
--- /dev/null
+++ b/tests/chapter.js
@@ -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();
+ });
+
+
+ });
+
+});
\ No newline at end of file
diff --git a/tests/index.html b/tests/index.html
index 8da01a2..77b0579 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -51,6 +51,7 @@
+