mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
284 lines
No EOL
5.6 KiB
JavaScript
284 lines
No EOL
5.6 KiB
JavaScript
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;
|
|
}; |