mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
Added a search method to Section object for find out result spanning multiple document nodes.
This commit is contained in:
parent
be24ab8b39
commit
f5022af53e
2 changed files with 124 additions and 11 deletions
|
@ -173,6 +173,75 @@ class Section {
|
||||||
return matches;
|
return matches;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search a string in multiple sequential Element of the section. If the document.createTreeWalker api is missed(eg: IE8), use `find` as a fallback.
|
||||||
|
* @param {string} _query The query string to search
|
||||||
|
* @param {int} maxSeqEle The maximum number of Element that are combined for search, defualt value is 5.
|
||||||
|
* @return {object[]} A list of matches, with form {cfi, excerpt}
|
||||||
|
*/
|
||||||
|
search(_query , maxSeqEle = 5){
|
||||||
|
if (typeof(document.createTreeWalker) == "undefined") {
|
||||||
|
return this.find(_query);
|
||||||
|
}
|
||||||
|
let matches = [];
|
||||||
|
const excerptLimit = 150;
|
||||||
|
const section = this;
|
||||||
|
const query = _query.toLowerCase();
|
||||||
|
const search = function(nodeList){
|
||||||
|
const textWithCase = nodeList.reduce((acc ,current)=>{
|
||||||
|
return acc + current.textContent;
|
||||||
|
},"");
|
||||||
|
const text = textWithCase.toLowerCase();
|
||||||
|
const pos = text.indexOf(query);
|
||||||
|
if (pos != -1){
|
||||||
|
const startNodeIndex = 0 , endPos = pos + query.length;
|
||||||
|
let endNodeIndex = 0 , l = 0;
|
||||||
|
if (pos < nodeList[startNodeIndex].length){
|
||||||
|
let cfi;
|
||||||
|
while( endNodeIndex < nodeList.length - 1 ){
|
||||||
|
l += nodeList[endNodeIndex].length;
|
||||||
|
if ( endPos <= l){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
endNodeIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let startNode = nodeList[startNodeIndex] , endNode = nodeList[endNodeIndex];
|
||||||
|
let range = section.document.createRange();
|
||||||
|
range.setStart(startNode,pos);
|
||||||
|
let beforeEndLengthCount = nodeList.slice(0, endNodeIndex).reduce((acc,current)=>{return acc+current.textContent.length;},0) ;
|
||||||
|
range.setEnd(endNode, beforeEndLengthCount > endPos ? endPos : endPos - beforeEndLengthCount );
|
||||||
|
cfi = section.cfiFromRange(range);
|
||||||
|
|
||||||
|
let excerpt = nodeList.slice(0, endNodeIndex+1).reduce((acc,current)=>{return acc+current.textContent ;},"");
|
||||||
|
if (excerpt.length > excerptLimit){
|
||||||
|
excerpt = excerpt.substring(pos - excerptLimit/2, pos + excerptLimit/2);
|
||||||
|
excerpt = "..." + excerpt + "...";
|
||||||
|
}
|
||||||
|
matches.push({
|
||||||
|
cfi: cfi,
|
||||||
|
excerpt: excerpt
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeWalker = document.createTreeWalker(section.document, NodeFilter.SHOW_TEXT, null, false);
|
||||||
|
let node , nodeList = [];
|
||||||
|
while (node = treeWalker.nextNode()) {
|
||||||
|
nodeList.push(node);
|
||||||
|
if (nodeList.length == maxSeqEle){
|
||||||
|
search(nodeList.slice(0 , maxSeqEle));
|
||||||
|
nodeList = nodeList.slice(1, maxSeqEle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nodeList.length > 0){
|
||||||
|
search(nodeList);
|
||||||
|
}
|
||||||
|
return matches;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reconciles the current chapters layout properies with
|
* Reconciles the current chapters layout properies with
|
||||||
* the global layout properities.
|
* the global layout properities.
|
||||||
|
|
|
@ -7,10 +7,14 @@ describe("section", function() {
|
||||||
return book.ready.then(function() {
|
return book.ready.then(function() {
|
||||||
var section = book.section("chapter_001.xhtml");
|
var section = book.section("chapter_001.xhtml");
|
||||||
return section.load().then(function() {
|
return section.load().then(function() {
|
||||||
var results = section.find("they were filled with cupboards and book-shelves");
|
const queryString = "they were filled with cupboards and book-shelves";
|
||||||
assert.equal(results.length, 1);
|
const findResults = section.find(queryString);
|
||||||
assert.equal(results[0].cfi, "epubcfi(/6/8[chapter_001]!/4/2/16,/1:275,/1:323)");
|
const searchResults = section.search(queryString);
|
||||||
assert.equal(results[0].excerpt, "... see anything; then she looked at the sides of the well and\n\t\tnoticed that they were filled with cupboards and book-shelves; here and there she saw\n\t\t...");
|
[findResults , searchResults].forEach( (results)=>{
|
||||||
|
assert.equal(results.length, 1);
|
||||||
|
assert.equal(results[0].cfi, "epubcfi(/6/8[chapter_001]!/4/2/16,/1:275,/1:323)");
|
||||||
|
assert.equal(results[0].excerpt, "... see anything; then she looked at the sides of the well and\n\t\tnoticed that they were filled with cupboards and book-shelves; here and there she saw\n\t\t...");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -20,14 +24,54 @@ describe("section", function() {
|
||||||
return book.ready.then(function() {
|
return book.ready.then(function() {
|
||||||
var section = book.section("chapter_001.xhtml");
|
var section = book.section("chapter_001.xhtml");
|
||||||
return section.load().then(function() {
|
return section.load().then(function() {
|
||||||
var results = section.find("white rabbit");
|
const queryString = "white rabbit";
|
||||||
assert.equal(results.length, 2);
|
const findResults = section.find(queryString);
|
||||||
assert.equal(results[0].cfi, "epubcfi(/6/8[chapter_001]!/4/2/8,/1:240,/1:252)");
|
const searchResults = section.search(queryString);
|
||||||
assert.equal(results[0].excerpt, "...e worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her....");
|
[findResults , searchResults].forEach( (results)=>{
|
||||||
assert.equal(results[1].cfi, "epubcfi(/6/8[chapter_001]!/4/2/20,/1:148,/1:160)");
|
assert.equal(results.length, 2);
|
||||||
assert.equal(results[1].excerpt, "...ut it was\n\t\tall dark overhead; before her was another long passage and the White Rabbit was still\n\t\tin sight, hurrying down it. There was not a moment...");
|
assert.equal(results[0].cfi, "epubcfi(/6/8[chapter_001]!/4/2/8,/1:240,/1:252)");
|
||||||
});
|
assert.equal(results[0].excerpt, "...e worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit with pink eyes ran close by her....");
|
||||||
|
assert.equal(results[1].cfi, "epubcfi(/6/8[chapter_001]!/4/2/20,/1:148,/1:160)");
|
||||||
|
assert.equal(results[1].excerpt, "...ut it was\n\t\tall dark overhead; before her was another long passage and the White Rabbit was still\n\t\tin sight, hurrying down it. There was not a moment...");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("finds result that spanning multiple document nodes, tag at ending", function() {
|
||||||
|
var book = ePub("./fixtures/alice/", {width: 400, height: 400});
|
||||||
|
return book.ready.then(function() {
|
||||||
|
var section = book.section("chapter_010.xhtml");
|
||||||
|
return section.load().then(function() {
|
||||||
|
const queryString = "I beg";
|
||||||
|
|
||||||
|
const findResult = section.find(queryString);
|
||||||
|
assert.equal(findResult.length, 0);
|
||||||
|
|
||||||
|
const searchResults = section.search(queryString);
|
||||||
|
assert.equal(searchResults.length, 1);
|
||||||
|
assert.equal(searchResults[0].cfi, "epubcfi(/6/26[chapter_010]!/4/2/6,/1:5,/2/1:3)");
|
||||||
|
assert.equal(searchResults[0].excerpt,'"Oh, I beg');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("finds result that spanning multiple document nodes, tag at middle", function() {
|
||||||
|
var book = ePub("./fixtures/alice/", {width: 400, height: 400});
|
||||||
|
return book.ready.then(function() {
|
||||||
|
var section = book.section("chapter_010.xhtml");
|
||||||
|
return section.load().then(function() {
|
||||||
|
const queryString = "I beg your pardon";
|
||||||
|
|
||||||
|
const findResult = section.find(queryString);
|
||||||
|
assert.equal(findResult.length, 0);
|
||||||
|
|
||||||
|
const searchResults = section.search(queryString);
|
||||||
|
assert.equal(searchResults.length, 1);
|
||||||
|
assert.equal(searchResults[0].cfi, "epubcfi(/6/26[chapter_010]!/4/2/6,/1:5,/3:12)");
|
||||||
|
assert.equal(searchResults[0].excerpt,'"Oh, I beg your pardon!" she exclaimed in a tone of great dismay.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue