mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-04 15:09:16 +02:00
Add map for sections and pages, update queue to handle function without promise
This commit is contained in:
parent
f998e5be0a
commit
5c33f9c52b
14 changed files with 1044 additions and 93 deletions
284
lib/epubjs/map.js
Normal file
284
lib/epubjs/map.js
Normal file
|
@ -0,0 +1,284 @@
|
|||
EPUBJS.Map = function(layout){
|
||||
this.layout = layout;
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.section = function(view) {
|
||||
var ranges = this.findRanges(view);
|
||||
var map = this.rangeListToCfiList(view, ranges);
|
||||
|
||||
return map;
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.page = function(view, start, end) {
|
||||
var root = view.document.body;
|
||||
return this.rangePairToCfiPair(view.section, {
|
||||
start: this.findStart(root, start, end),
|
||||
end: this.findEnd(root, start, end)
|
||||
});
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.walk = function(root, func) {
|
||||
//var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT, null, false);
|
||||
var treeWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
|
||||
acceptNode: function (node) {
|
||||
if ( node.data.trim().length > 0 ) {
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
} else {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
var node;
|
||||
var result;
|
||||
while ((node = treeWalker.nextNode())) {
|
||||
result = func(node);
|
||||
if(result) break;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.findRanges = function(view){
|
||||
var columns = [];
|
||||
var count = this.layout.count(view);
|
||||
var column = this.layout.column;
|
||||
var gap = this.layout.gap;
|
||||
var start, end;
|
||||
|
||||
for (var i = 0; i < count.pages; i++) {
|
||||
start = (column + gap) * i;
|
||||
end = (column * (i+1)) + (gap * i);
|
||||
columns.push({
|
||||
start: this.findStart(view.document.body, start, end),
|
||||
end: this.findEnd(view.document.body, start, end)
|
||||
});
|
||||
};
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.findStart = function(root, start, end){
|
||||
var stack = [root];
|
||||
var $el;
|
||||
var found;
|
||||
var $prev;
|
||||
while (stack.length) {
|
||||
|
||||
$el = stack.shift();
|
||||
|
||||
found = this.walk($el, function(node){
|
||||
var left, right;
|
||||
var elPos
|
||||
var elRange;
|
||||
|
||||
|
||||
if(node.nodeType == Node.TEXT_NODE){
|
||||
elRange = document.createRange();
|
||||
elRange.selectNodeContents(node);
|
||||
elPos = elRange.getBoundingClientRect();
|
||||
} else {
|
||||
elPos = node.getBoundingClientRect();
|
||||
}
|
||||
|
||||
left = elPos.left;
|
||||
right = elPos.right;
|
||||
|
||||
if( left >= start && left <= end ) {
|
||||
return node;
|
||||
} else if (right > start) {
|
||||
return node;
|
||||
} else {
|
||||
$prev = node;
|
||||
stack.push(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if(found) {
|
||||
return this.findTextStartRange(found, start, end);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return last element
|
||||
return this.findTextStartRange($prev, start, end);
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.findEnd = function(root, start, end){
|
||||
var stack = [root];
|
||||
var $el;
|
||||
var $prev;
|
||||
var found;
|
||||
|
||||
while (stack.length) {
|
||||
|
||||
$el = stack.shift();
|
||||
|
||||
found = this.walk($el, function(node){
|
||||
|
||||
var left, right;
|
||||
var elPos
|
||||
var elRange;
|
||||
|
||||
|
||||
if(node.nodeType == Node.TEXT_NODE){
|
||||
elRange = document.createRange();
|
||||
elRange.selectNodeContents(node);
|
||||
elPos = elRange.getBoundingClientRect();
|
||||
} else {
|
||||
elPos = node.getBoundingClientRect();
|
||||
}
|
||||
|
||||
left = elPos.left;
|
||||
right = elPos.right;
|
||||
|
||||
if(left > end && $prev) {
|
||||
return $prev
|
||||
} else if(right > end) {
|
||||
return node;
|
||||
} else {
|
||||
$prev = node;
|
||||
stack.push(node);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
if(found){
|
||||
return this.findTextEndRange(found, start, end);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end of chapter
|
||||
return this.findTextEndRange($prev, start, end);
|
||||
};
|
||||
|
||||
|
||||
EPUBJS.Map.prototype.findTextStartRange = function(node, start, end){
|
||||
var ranges = this.splitTextNodeIntoRanges(node);
|
||||
var prev;
|
||||
var range;
|
||||
var pos;
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
range = ranges[i];
|
||||
|
||||
pos = range.getBoundingClientRect();
|
||||
|
||||
if( pos.left >= start ) {
|
||||
return range;
|
||||
}
|
||||
|
||||
prev = range;
|
||||
|
||||
};
|
||||
|
||||
return ranges[0];
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.findTextEndRange = function(node, start, end){
|
||||
var ranges = this.splitTextNodeIntoRanges(node);
|
||||
var prev;
|
||||
var range;
|
||||
var pos;
|
||||
|
||||
for (var i = 0; i < ranges.length; i++) {
|
||||
range = ranges[i];
|
||||
|
||||
pos = range.getBoundingClientRect();
|
||||
|
||||
if(pos.left > end) {
|
||||
return prev;
|
||||
} else if(pos.right > end) {
|
||||
return range;
|
||||
}
|
||||
|
||||
prev = range;
|
||||
|
||||
};
|
||||
|
||||
// Ends before limit
|
||||
return ranges[ranges.length-1];
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.splitTextNodeIntoRanges = function(node, _splitter){
|
||||
var ranges = [];
|
||||
var text = node.textContent.trim();
|
||||
var range;
|
||||
var rect;
|
||||
var list;
|
||||
var doc = node.ownerDocument;
|
||||
var splitter = _splitter || " ";
|
||||
|
||||
pos = text.indexOf(splitter);
|
||||
|
||||
if(pos === -1) {
|
||||
range = doc.createRange();
|
||||
range.selectNodeContents(node);
|
||||
return [range];
|
||||
}
|
||||
|
||||
range = doc.createRange();
|
||||
range.setStart(node, 0);
|
||||
range.setEnd(node, pos);
|
||||
ranges.push(range);
|
||||
range = false;
|
||||
|
||||
while ( pos != -1 ) {
|
||||
|
||||
pos = text.indexOf(splitter, pos + 1);
|
||||
if(pos > 0) {
|
||||
|
||||
if(range) {
|
||||
range.setEnd(node, pos);
|
||||
ranges.push(range);
|
||||
}
|
||||
|
||||
range = doc.createRange();
|
||||
range.setStart(node, pos+1);
|
||||
}
|
||||
}
|
||||
|
||||
if(range) {
|
||||
range.setEnd(node, text.length);
|
||||
ranges.push(range);
|
||||
}
|
||||
|
||||
return ranges;
|
||||
};
|
||||
|
||||
|
||||
|
||||
EPUBJS.Map.prototype.rangePairToCfiPair = function(section, rangePair){
|
||||
|
||||
var startRange = rangePair.start;
|
||||
var endRange = rangePair.end;
|
||||
|
||||
startRange.collapse(true);
|
||||
endRange.collapse(true);
|
||||
|
||||
startCfi = section.cfiFromRange(startRange);
|
||||
endCfi = section.cfiFromRange(endRange);
|
||||
|
||||
return {
|
||||
start: startCfi,
|
||||
end: endCfi
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.Map.prototype.rangeListToCfiList = function(view, columns){
|
||||
var map = [];
|
||||
var rangePair, cifPair;
|
||||
|
||||
for (var i = 0; i < columns.length; i++) {
|
||||
cifPair = this.rangePairToCfiPair(view.section, columns[i]);
|
||||
|
||||
map.push(cifPair);
|
||||
|
||||
};
|
||||
|
||||
return map;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue