mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
ignore working for simple highlights
This commit is contained in:
parent
7cad24b414
commit
1c5e7c03fd
17 changed files with 836 additions and 497 deletions
752
dist/epub.js
vendored
752
dist/epub.js
vendored
File diff suppressed because it is too large
Load diff
2
dist/epub.js.map
vendored
2
dist/epub.js.map
vendored
File diff suppressed because one or more lines are too long
|
@ -123,7 +123,7 @@
|
|||
margin: 10px auto;
|
||||
}
|
||||
|
||||
#hypothesis {
|
||||
#hypothesis-custom {
|
||||
overflow: hidden;
|
||||
/*position: absolute;*/
|
||||
right: 0;
|
||||
|
@ -133,13 +133,13 @@
|
|||
/*z-index: -2;*/
|
||||
}
|
||||
|
||||
#hypothesis iframe {
|
||||
#hypothesis-custom iframe {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#annotation-controls {
|
||||
/*#annotation-controls {
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: 0px;
|
||||
|
@ -163,7 +163,7 @@
|
|||
|
||||
#annotation-controls ul li button:focus {
|
||||
border: none !important;
|
||||
}
|
||||
}*/
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -179,7 +179,7 @@
|
|||
<a id="next" href="#next" class="arrow">...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="annotation-controls"></div>
|
||||
<!-- <div id="annotation-controls"></div> -->
|
||||
<!-- <div id="hypothesis">
|
||||
<iframe src="//hypothes.is/app.html" seamless></iframe>
|
||||
</div> -->
|
||||
|
@ -241,7 +241,7 @@
|
|||
|
||||
// Add CFI fragment to the history
|
||||
// history.pushState({}, '', section.href);
|
||||
window.location.hash = "#/"+section.href
|
||||
// window.location.hash = "#/"+section.href
|
||||
});
|
||||
|
||||
book.loaded.navigation.then(function(toc){
|
||||
|
|
|
@ -64,7 +64,12 @@ gulp.task('test', function(cb) {
|
|||
mochify('./test/*.js', {
|
||||
reporter: 'spec',
|
||||
transform: 'brfs',
|
||||
watch: true
|
||||
"web-security": false,
|
||||
"webSecurityEnabled": false,
|
||||
// "localUrlAccess": true,
|
||||
watch: true,
|
||||
wd: false,
|
||||
debug: false
|
||||
})
|
||||
.bundle();
|
||||
});
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
"portfinder": "^0.2.1",
|
||||
"qunitjs": "^1.14.0",
|
||||
"serve-static": "^1.3.1",
|
||||
"sinon": "^1.17.2",
|
||||
"uglify": "^0.1.5",
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
|
|
11
src/book.js
11
src/book.js
|
@ -108,7 +108,11 @@ Book.prototype.open = function(_url){
|
|||
|
||||
this.containerUrl = this.url + containerPath;
|
||||
|
||||
epubContainer = this.request(this.containerUrl);
|
||||
epubContainer = this.request(this.containerUrl)
|
||||
.catch(function(error) {
|
||||
// handle errors in loading container
|
||||
book.opening.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
if (epubContainer) {
|
||||
|
@ -140,7 +144,6 @@ Book.prototype.open = function(_url){
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
epubPackage.then(function(packageXml) {
|
||||
// Get package information from epub opf
|
||||
book.unpack(packageXml);
|
||||
|
@ -172,6 +175,10 @@ Book.prototype.unpack = function(packageXml){
|
|||
parse = new Parser();
|
||||
|
||||
book.package = parse.packageContents(packageXml); // Extract info from contents
|
||||
if(!book.package) {
|
||||
return;
|
||||
}
|
||||
|
||||
book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths
|
||||
|
||||
this.spine.load(book.package);
|
||||
|
|
|
@ -46,7 +46,7 @@ Continuous.prototype.attachListeners = function(){
|
|||
|
||||
Continuous.prototype.parseTarget = function(target){
|
||||
if(this.epubcfi.isCfiString(target)) {
|
||||
cfi = this.epubcfi.parse(target);
|
||||
cfi = new EpubCFI(target);
|
||||
spinePos = cfi.spinePos;
|
||||
section = this.book.spine.get(spinePos);
|
||||
} else {
|
||||
|
|
|
@ -407,6 +407,10 @@ function createBlobUrl(content, mime){
|
|||
return tempUrl;
|
||||
};
|
||||
|
||||
function type(obj){
|
||||
return Object.prototype.toString.call(obj).slice(8, -1);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
// 'uri': uri,
|
||||
// 'folder': folder,
|
||||
|
@ -430,5 +434,6 @@ module.exports = {
|
|||
'cleanStringForXpath': cleanStringForXpath,
|
||||
'indexOfTextNode': indexOfTextNode,
|
||||
'isXml': isXml,
|
||||
'createBlobUrl': createBlobUrl
|
||||
'createBlobUrl': createBlobUrl,
|
||||
'type': type
|
||||
};
|
||||
|
|
235
src/epubcfi.js
235
src/epubcfi.js
|
@ -69,7 +69,7 @@ function EpubCFI(cfiFrom, base, options){
|
|||
return core.extend(this, this.fromRange(cfiFrom, this.base));
|
||||
} else if (type === 'node') {
|
||||
return core.extend(this, this.fromNode(cfiFrom, this.base));
|
||||
} else if (type === 'EpubCFI') {
|
||||
} else if (type === 'EpubCFI' && cfiFrom.path) {
|
||||
return cfiFrom;
|
||||
} else if (!cfiFrom) {
|
||||
return this;
|
||||
|
@ -80,13 +80,11 @@ function EpubCFI(cfiFrom, base, options){
|
|||
};
|
||||
|
||||
EpubCFI.prototype.checkType = function(cfi) {
|
||||
// is a cfi string, should be wrapped with "epubcfi()"
|
||||
if (typeof cfi === 'string' &&
|
||||
cfi.indexOf("epubcfi(") === 0 &&
|
||||
cfi[cfi.length-1] === ")") {
|
||||
|
||||
if (this.isCfiString(cfi)) {
|
||||
return 'string';
|
||||
// Is a range object
|
||||
} else if (typeof cfi === 'object' && cfi instanceof window.Range){
|
||||
} else if (typeof cfi === 'object' && core.type(cfi) === "Range"){
|
||||
return 'range';
|
||||
} else if (typeof cfi === 'object' && cfi instanceof window.Node ){ // || typeof cfi === 'function'
|
||||
return 'node';
|
||||
|
@ -149,7 +147,10 @@ EpubCFI.prototype.parse = function(cfiStr) {
|
|||
EpubCFI.prototype.parseComponent = function(componentStr){
|
||||
var component = {
|
||||
steps: [],
|
||||
terminal: null
|
||||
terminal: {
|
||||
offset: null,
|
||||
assertion: null
|
||||
}
|
||||
};
|
||||
var parts = componentStr.split(':');
|
||||
var steps = parts[0].split('/');
|
||||
|
@ -206,10 +207,10 @@ EpubCFI.prototype.parseTerminal = function(termialStr){
|
|||
var assertion = termialStr.match(/\[(.*)\]/);
|
||||
|
||||
if(assertion && assertion[1]){
|
||||
characterOffset = parseInt(termialStr.split('[')[0]);
|
||||
characterOffset = parseInt(termialStr.split('[')[0]) || null;
|
||||
textLocationAssertion = assertion[1];
|
||||
} else {
|
||||
characterOffset = parseInt(termialStr);
|
||||
characterOffset = parseInt(termialStr) || null;
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -283,11 +284,11 @@ EpubCFI.prototype.segmentString = function(segment) {
|
|||
|
||||
segmentString += this.joinSteps(segment.steps);
|
||||
|
||||
if(segment.terminal && segment.terminal.offset){
|
||||
if(segment.terminal && segment.terminal.offset != null){
|
||||
segmentString += ':' + segment.terminal.offset;
|
||||
}
|
||||
|
||||
if(segment.terminal && segment.terminal.assertion){
|
||||
if(segment.terminal && segment.terminal.assertion != null){
|
||||
segmentString += '[' + segment.terminal.assertion + ']';
|
||||
}
|
||||
|
||||
|
@ -348,9 +349,9 @@ EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
|
|||
// Otherwise continue checking
|
||||
}
|
||||
|
||||
// All steps in First present in Second
|
||||
// All steps in First equal to Second and First is Less Specific
|
||||
if(cfiOne.path.steps.length < cfiTwo.path.steps.length) {
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Compare the charecter offset of the text node
|
||||
|
@ -382,21 +383,22 @@ EpubCFI.prototype.pathTo = function(node, offset) {
|
|||
currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) {
|
||||
|
||||
filteredNode = this.filter(currentNode, this.options.ignoreClass);
|
||||
if (filteredNode) {
|
||||
nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element';
|
||||
|
||||
segment.steps.unshift({
|
||||
'id' : this.filterId(filteredNode, this.options.ignoreClass),
|
||||
'id' : filteredNode.id,
|
||||
'tagName' : filteredNode.tagName,
|
||||
'type' : nodeType,
|
||||
'index' : this.position(currentNode, this.options.ignoreClass) //Array.prototype.indexOf.call(children, currentNode)
|
||||
'index' : this.position(filteredNode, this.options.ignoreClass) //Array.prototype.indexOf.call(children, currentNode)
|
||||
});
|
||||
// console.log(segment);
|
||||
}
|
||||
|
||||
currentNode = filteredNode.parentNode;
|
||||
currentNode = currentNode.parentNode;
|
||||
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
if (offset >= 0) {
|
||||
|
||||
segment.terminal.offset = offset;
|
||||
|
||||
|
@ -450,15 +452,15 @@ EpubCFI.prototype.fromRange = function(range, base) {
|
|||
}
|
||||
|
||||
if (range.collapsed) {
|
||||
startOffset = this.patch(start, startOffset, this.options.ignoreClass);
|
||||
startOffset = this.patchOffset(start, startOffset, this.options.ignoreClass);
|
||||
cfi.path = this.pathTo(start, startOffset);
|
||||
} else {
|
||||
cfi.range = true;
|
||||
|
||||
startOffset = this.patch(start, startOffset, this.options.ignoreClass);
|
||||
startOffset = this.patchOffset(start, startOffset, this.options.ignoreClass);
|
||||
cfi.start = this.pathTo(start, startOffset);
|
||||
|
||||
endOffset = this.patch(end, endOffset, this.options.ignoreClass);
|
||||
endOffset = this.patchOffset(end, endOffset, this.options.ignoreClass);
|
||||
cfi.end = this.pathTo(end, endOffset);
|
||||
|
||||
// Create a new empty path
|
||||
|
@ -522,109 +524,140 @@ EpubCFI.prototype.fromNode = function(anchor, base) {
|
|||
EpubCFI.prototype.filter = function(anchor, ignoreClass) {
|
||||
var needsIgnoring;
|
||||
var sibling;
|
||||
var isText;
|
||||
|
||||
if (anchor.nodeType === Node.TEXT_NODE) {
|
||||
isText = true;
|
||||
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
|
||||
sibling = anchor.parentNode.previousSibling;
|
||||
} else {
|
||||
isText = false;
|
||||
needsIgnoring = anchor.classList.contains(ignoreClass);
|
||||
sibling = anchor.previousSibling;
|
||||
}
|
||||
|
||||
if (needsIgnoring) {
|
||||
if (needsIgnoring && isText) {
|
||||
|
||||
if (sibling && sibling.nodeType === Node.TEXT_NODE) {
|
||||
// If the previous sibling is a text node, join the nodes
|
||||
// If the sibling is a text node, join the nodes
|
||||
if (anchor.parentNode.previousSibling && anchor.parentNode.previousSibling.nodeType === Node.TEXT_NODE) {
|
||||
sibling = anchor.parentNode.previousSibling;
|
||||
} else if (anchor.parentNode.nextSibling && anchor.parentNode.nextSibling.nodeType === Node.TEXT_NODE) {
|
||||
sibling = anchor.parentNode.nextSibling;
|
||||
}
|
||||
|
||||
if (sibling) {
|
||||
return sibling;
|
||||
} else if (anchor.nodeType === Node.TEXT_NODE) {
|
||||
return anchor.parentNode.childNodes[0];
|
||||
} else {
|
||||
// Otherwise just ignore the node by getting the path to its parent
|
||||
return anchor.parentNode;
|
||||
// Parent will be ignored on next step
|
||||
return anchor;
|
||||
}
|
||||
|
||||
} else if (needsIgnoring && !isText) {
|
||||
// Otherwise just skip the element node
|
||||
return false;
|
||||
} else {
|
||||
// No need to filter
|
||||
return anchor;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EpubCFI.prototype.filterId = function(anchor, ignoreClass) {
|
||||
var needsIgnoring;
|
||||
|
||||
if (anchor.nodeType === Node.ELEMENT_NODE) {
|
||||
needsIgnoring = anchor.classList.contains(ignoreClass);
|
||||
if(!needsIgnoring) {
|
||||
return anchor.id;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EpubCFI.prototype.patch = function(anchor, offset, ignoreClass) {
|
||||
EpubCFI.prototype.patchOffset = function(anchor, offset, ignoreClass) {
|
||||
var needsIgnoring;
|
||||
var sibling;
|
||||
|
||||
if (anchor.nodeType === Node.TEXT_NODE) {
|
||||
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
|
||||
sibling = anchor.parentNode.previousSibling;
|
||||
} else {
|
||||
needsIgnoring = anchor.classList.contains(ignoreClass);
|
||||
sibling = anchor.previousSibling;
|
||||
if (anchor.nodeType != Node.TEXT_NODE) {
|
||||
console.error("Anchor must be a text node");
|
||||
return;
|
||||
}
|
||||
|
||||
if (needsIgnoring) {
|
||||
var curr = anchor;
|
||||
var totalOffset = offset;
|
||||
|
||||
if (sibling && sibling.nodeType === Node.TEXT_NODE) {
|
||||
if (anchor.parentNode.classList.contains(ignoreClass)) {
|
||||
curr = anchor.parentNode;
|
||||
|
||||
if (curr.previousSibling && curr.previousSibling.nodeType === Node.TEXT_NODE) {
|
||||
// If the previous sibling is a text node, join the nodes
|
||||
return sibling.textContent.length + offset;
|
||||
} else {
|
||||
// Otherwise just ignore the node
|
||||
return offset;
|
||||
totalOffset += curr.previousSibling.textContent.length;
|
||||
}
|
||||
}
|
||||
|
||||
while (curr.previousSibling) {
|
||||
if(curr.previousSibling.nodeType === Node.ELEMENT_NODE) {
|
||||
// Originally a text node, so join
|
||||
if(curr.previousSibling.classList.contains(ignoreClass)){
|
||||
totalOffset += curr.previousSibling.textContent.length;
|
||||
} else {
|
||||
return offset;
|
||||
break; // Normal node, dont join
|
||||
}
|
||||
}
|
||||
|
||||
curr = curr.previousSibling;
|
||||
}
|
||||
|
||||
return totalOffset;
|
||||
|
||||
};
|
||||
|
||||
EpubCFI.prototype.flatten = function(children, ignoreClass) {
|
||||
// var children = parent.childNodes;
|
||||
var output = {};
|
||||
// var input = Array.prototype.slice.call(children);
|
||||
|
||||
// input = Array.prototype.slice.call(children).map(function(node) {
|
||||
// var ignore = node.classList.contains(ignoreClass);
|
||||
// // span -> text
|
||||
// if (ignore && node.hasChildNodes()) {
|
||||
// return node.childNodes[0];
|
||||
// }
|
||||
//
|
||||
// return node;
|
||||
// });
|
||||
|
||||
// Join text nodes
|
||||
var prevIndex = -1;
|
||||
var i, len = children.length;
|
||||
var ignore;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
|
||||
if (children[i].nodeType === Node.ELEMENT_NODE) {
|
||||
ignore = children[i].classList.contains(ignoreClass);
|
||||
}
|
||||
|
||||
if (i > 0 &&
|
||||
(ignore || children[i].nodeType === Node.TEXT_NODE) &&
|
||||
(children[i-1].nodeType === Node.TEXT_NODE || children[i-1].classList.contains(ignoreClass))) {
|
||||
// join text nodes
|
||||
output[i] = prevIndex;
|
||||
} else {
|
||||
prevIndex = prevIndex + 1;
|
||||
output[i] = prevIndex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
EpubCFI.prototype.position = function(anchor, ignoreClass) {
|
||||
var needsIgnoring;
|
||||
var sibling;
|
||||
var indexed = -1;
|
||||
var ignored;
|
||||
var e = [];
|
||||
var children, index, map;
|
||||
|
||||
if (anchor.nodeType === Node.TEXT_NODE) {
|
||||
|
||||
ignored = Array.prototype.slice.call(anchor.parentNode.querySelectorAll("."+ignoreClass));
|
||||
e = ignored.map(function(item) {
|
||||
return Array.prototype.indexOf.call(anchor.parentNode.childNodes, item)
|
||||
});
|
||||
|
||||
if (ignored.length) {
|
||||
needsIgnoring = true;
|
||||
}
|
||||
|
||||
sibling = anchor.parentNode.previousSibling;
|
||||
children = anchor.parentNode.childNodes;
|
||||
} else {
|
||||
needsIgnoring = anchor.classList.contains(ignoreClass);
|
||||
sibling = anchor.previousSibling;
|
||||
if (anchor.nodeType === Node.ELEMENT_NODE) {
|
||||
children = anchor.parentNode.children;
|
||||
} else {
|
||||
children = anchor.parentNode.childNodes;
|
||||
// Inside an ignored node
|
||||
if(anchor.parentNode.classList.contains(ignoreClass)) {
|
||||
anchor = anchor.parentNode;
|
||||
children = anchor.parentNode.childNodes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
indexed = Array.prototype.indexOf.call(children, anchor);
|
||||
|
||||
e.forEach(function(item) {
|
||||
if(item < indexed) {
|
||||
indexed--;
|
||||
}
|
||||
});
|
||||
|
||||
return indexed;
|
||||
|
||||
index = Array.prototype.indexOf.call(children, anchor);
|
||||
map = this.flatten(children, ignoreClass);
|
||||
return map[index];
|
||||
};
|
||||
|
||||
EpubCFI.prototype.stepsToXpath = function(steps) {
|
||||
|
@ -780,7 +813,7 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
|
|||
if(startContainer) {
|
||||
try {
|
||||
|
||||
if(start.terminal.offset) {
|
||||
if(start.terminal.offset != null) {
|
||||
range.setStart(startContainer, start.terminal.offset);
|
||||
} else {
|
||||
range.setStart(startContainer, 0);
|
||||
|
@ -793,18 +826,17 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
if (endContainer) {
|
||||
try {
|
||||
|
||||
if(end.terminal.offset) {
|
||||
if(end.terminal.offset != null) {
|
||||
range.setEnd(endContainer, end.terminal.offset);
|
||||
} else {
|
||||
range.setEnd(endContainer, 0);
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
missed = this.fixMiss(endSteps, end.terminal.offset, doc);
|
||||
missed = this.fixMiss(endSteps, cfi.end.terminal.offset, doc);
|
||||
range.setEnd(missed.container, missed.offset);
|
||||
}
|
||||
}
|
||||
|
@ -814,4 +846,29 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
|
|||
return range;
|
||||
};
|
||||
|
||||
// is a cfi string, should be wrapped with "epubcfi()"
|
||||
EpubCFI.prototype.isCfiString = function(str) {
|
||||
if(typeof str === 'string' &&
|
||||
str.indexOf("epubcfi(") === 0 &&
|
||||
str[str.length-1] === ")") {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
EpubCFI.prototype.generateChapterComponent = function(_spineNodeIndex, _pos, id) {
|
||||
var pos = parseInt(_pos),
|
||||
spineNodeIndex = _spineNodeIndex + 1,
|
||||
cfi = '/'+spineNodeIndex+'/';
|
||||
|
||||
cfi += (pos + 1) * 2;
|
||||
|
||||
if(id) {
|
||||
cfi += "[" + id + "]";
|
||||
}
|
||||
|
||||
return cfi;
|
||||
};
|
||||
|
||||
module.exports = EpubCFI;
|
||||
|
|
|
@ -208,11 +208,10 @@ Rendition.prototype._display = function(target){
|
|||
visible = this.views.find(section);
|
||||
|
||||
if(visible) {
|
||||
offset = view.locationOf(target);
|
||||
displayed = this.moveTo(offset)
|
||||
.then(function(){
|
||||
return this.check();
|
||||
});
|
||||
offset = visible.locationOf(target);
|
||||
this.moveTo(offset);
|
||||
displaying.resolve();
|
||||
|
||||
} else {
|
||||
|
||||
// Hide all current views
|
||||
|
@ -262,7 +261,7 @@ Rendition.prototype._display = function(target){
|
|||
|
||||
// Takes a cfi, fragment or page?
|
||||
Rendition.prototype.moveTo = function(offset){
|
||||
this.scrollBy(offset.left, offset.top);
|
||||
this.scrollTo(offset.left, offset.top);
|
||||
};
|
||||
|
||||
Rendition.prototype.render = function(view, show) {
|
||||
|
|
|
@ -3,7 +3,7 @@ var URI = require('urijs');
|
|||
var core = require('./core');
|
||||
|
||||
function request(url, type, withCredentials, headers) {
|
||||
var supportsURL = window.URL;
|
||||
var supportsURL = (typeof window != "undefined") ? window.URL : false; // TODO: fallback for url if window isn't defined
|
||||
var BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
|
||||
var uri;
|
||||
|
||||
|
@ -27,13 +27,18 @@ function request(url, type, withCredentials, headers) {
|
|||
xhr.withCredentials = true;
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = handler;
|
||||
xhr.onerror = err;
|
||||
|
||||
xhr.open("GET", url, true);
|
||||
|
||||
for(header in headers) {
|
||||
xhr.setRequestHeader(header, headers[header]);
|
||||
}
|
||||
|
||||
xhr.onreadystatechange = handler;
|
||||
if(type == "json") {
|
||||
xhr.setRequestHeader("Accept", "application/json");
|
||||
}
|
||||
|
||||
// If type isn't set, determine it from the file extension
|
||||
if(!type) {
|
||||
|
@ -45,13 +50,10 @@ function request(url, type, withCredentials, headers) {
|
|||
xhr.responseType = BLOB_RESPONSE;
|
||||
}
|
||||
|
||||
if(type == "json") {
|
||||
xhr.setRequestHeader("Accept", "application/json");
|
||||
}
|
||||
|
||||
if(core.isXml(type)) {
|
||||
xhr.responseType = "document";
|
||||
xhr.overrideMimeType('text/xml'); // for OPF parsing
|
||||
// xhr.overrideMimeType('text/xml'); // for OPF parsing
|
||||
}
|
||||
|
||||
if(type == 'xhtml') {
|
||||
|
@ -68,8 +70,14 @@ function request(url, type, withCredentials, headers) {
|
|||
|
||||
xhr.send();
|
||||
|
||||
function err(e) {
|
||||
console.error(e);
|
||||
deferred.reject(e);
|
||||
}
|
||||
|
||||
function handler() {
|
||||
if (this.readyState === this.DONE) {
|
||||
if (this.readyState === XMLHttpRequest.DONE) {
|
||||
|
||||
if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls
|
||||
var r;
|
||||
|
||||
|
@ -78,6 +86,7 @@ function request(url, type, withCredentials, headers) {
|
|||
r = this.responseXML;
|
||||
} else
|
||||
if(core.isXml(type)){
|
||||
// xhr.overrideMimeType('text/xml'); // for OPF parsing
|
||||
// If this.responseXML wasn't set, try to parse using a DOMParser from text
|
||||
r = new DOMParser().parseFromString(this.response, "text/xml");
|
||||
}else
|
||||
|
@ -105,11 +114,13 @@ function request(url, type, withCredentials, headers) {
|
|||
|
||||
deferred.resolve(r);
|
||||
} else {
|
||||
|
||||
deferred.reject({
|
||||
status: this.status,
|
||||
message : this.response,
|
||||
stack : new Error().stack
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ function Section(item, hooks){
|
|||
this.next = item.next;
|
||||
this.prev = item.prev;
|
||||
|
||||
this.epubcfi = new EpubCFI();
|
||||
this.cfiBase = item.cfiBase;
|
||||
|
||||
this.hooks = {};
|
||||
|
@ -140,11 +139,11 @@ Section.prototype.reconcileLayoutSettings = function(global){
|
|||
};
|
||||
|
||||
Section.prototype.cfiFromRange = function(_range) {
|
||||
return this.epubcfi.generateCfiFromRange(_range, this.cfiBase);
|
||||
return new EpubCFI(_range, this.cfiBase).toString();
|
||||
};
|
||||
|
||||
Section.prototype.cfiFromElement = function(el) {
|
||||
return this.epubcfi.generateCfiFromElement(el, this.cfiBase);
|
||||
return new EpubCFI(el, this.cfiBase).toString();
|
||||
};
|
||||
|
||||
module.exports = Section;
|
||||
|
|
|
@ -24,6 +24,7 @@ Spine.prototype.load = function(_package) {
|
|||
var href, url;
|
||||
var manifestItem = this.manifest[item.idref];
|
||||
var spineItem;
|
||||
|
||||
item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
|
||||
|
||||
if(manifestItem) {
|
||||
|
@ -59,7 +60,7 @@ Spine.prototype.get = function(target) {
|
|||
var index = 0;
|
||||
|
||||
if(this.epubcfi.isCfiString(target)) {
|
||||
cfi = this.epubcfi.parse(target);
|
||||
cfi = new EpubCFI(target);
|
||||
index = cfi.spinePos;
|
||||
} else if(target && (typeof target === "number" || isNaN(target) === false)){
|
||||
index = target;
|
||||
|
|
35
src/view.js
35
src/view.js
|
@ -576,22 +576,28 @@ View.prototype.locationOf = function(target) {
|
|||
if(!this.document) return;
|
||||
|
||||
if(this.epubcfi.isCfiString(target)) {
|
||||
cfi = this.epubcfi.parse(target);
|
||||
// cfi = this.epubcfi.parse(target);
|
||||
//
|
||||
// if(typeof document.evaluate === 'undefined') {
|
||||
// marker = this.epubcfi.addMarker(cfi, this.document);
|
||||
// if(marker) {
|
||||
// // Must Clean up Marker before going to page
|
||||
// this.epubcfi.removeMarker(marker, this.document);
|
||||
//
|
||||
// targetPos = marker.getBoundingClientRect();
|
||||
// }
|
||||
// } else {
|
||||
// range = this.epubcfi.generateRangeFromCfi(cfi, this.document);
|
||||
// if(range) {
|
||||
// targetPos = range.getBoundingClientRect();
|
||||
// }
|
||||
// }
|
||||
|
||||
if(typeof document.evaluate === 'undefined') {
|
||||
marker = this.epubcfi.addMarker(cfi, this.document);
|
||||
if(marker) {
|
||||
// Must Clean up Marker before going to page
|
||||
this.epubcfi.removeMarker(marker, this.document);
|
||||
|
||||
targetPos = marker.getBoundingClientRect();
|
||||
}
|
||||
} else {
|
||||
range = this.epubcfi.generateRangeFromCfi(cfi, this.document);
|
||||
range = new EpubCFI(cfi).toRange(this.document);
|
||||
if(range) {
|
||||
targetPos = range.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
|
||||
} else if(typeof target === "string" &&
|
||||
target.indexOf("#") > -1) {
|
||||
|
||||
|
@ -750,10 +756,13 @@ View.prototype.onSelectionChange = function(e){
|
|||
};
|
||||
|
||||
View.prototype.triggerSelectedEvent = function(selection){
|
||||
var range = selection.getRangeAt(0);
|
||||
var range;
|
||||
if (selection && selection.rangeCount > 0) {
|
||||
range = selection.getRangeAt(0);
|
||||
console.log(range);
|
||||
var cfirange = this.section.cfiFromRange(range);
|
||||
this.trigger("selected", cfirange);
|
||||
}
|
||||
};
|
||||
|
||||
RSVP.EventTarget.mixin(View.prototype);
|
||||
|
|
43
test/epub.js
43
test/epub.js
|
@ -1,28 +1,39 @@
|
|||
// var test = require('tape');
|
||||
var assert = require('assert');
|
||||
|
||||
// describe("Create new ePub(/path/to/epub/)", function(t) {
|
||||
//
|
||||
// var book = ePub("../books/moby-dick/");
|
||||
//
|
||||
// book.opened.then(function(){
|
||||
// assert.equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" );
|
||||
// });
|
||||
//
|
||||
// });
|
||||
var sinon = require('sinon');
|
||||
var fs = require('fs');
|
||||
|
||||
|
||||
describe('ePub', function() {
|
||||
var ePub = require('../src/epub');
|
||||
var server;
|
||||
before(function(){
|
||||
var packageContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/package.opf', 'utf8');
|
||||
var tocContents = fs.readFileSync(__dirname + '/../books/moby-dick/OPS/toc.xhtml', 'utf8');
|
||||
|
||||
describe('#ePub()', function() {
|
||||
xit('should save without error', function(done) {
|
||||
var book = ePub("../books/moby-dick/");
|
||||
server = sinon.fakeServer.create();
|
||||
server.autoRespond = true;
|
||||
|
||||
server.respondWith("moby-dick/OPS/package.opf", [200, {
|
||||
"Content-Type": "text/xml"
|
||||
}, packageContents]);
|
||||
|
||||
server.respondWith("moby-dick/OPS/toc.xhtml", [200, {
|
||||
"Content-Type": "application/xhtml+xml"
|
||||
}, tocContents]);
|
||||
|
||||
|
||||
});
|
||||
after(function(){
|
||||
server.restore();
|
||||
});
|
||||
|
||||
it('should open a epub', function(done) {
|
||||
var book = ePub("moby-dick/OPS/package.opf");
|
||||
|
||||
book.opened.then(function(){
|
||||
assert.equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" );
|
||||
assert.equal( book.isOpen, true, "book is opened" );
|
||||
assert.equal( book.url, "moby-dick/OPS/package.opf", "book url is passed to new Book" );
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -111,7 +111,7 @@ describe('EpubCFI', function() {
|
|||
// Second is deeper
|
||||
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/8/2)", "epubcfi(/6/2[cover]!/6/4/2/2)"), 1, "First Element is greater");
|
||||
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/4)", "epubcfi(/6/2[cover]!/6/4/2/2)"), -1, "Second Element is greater");
|
||||
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/6)", "epubcfi(/6/2[cover]!/4/6/8/1:0)"), -1, "Second");
|
||||
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/6)", "epubcfi(/6/2[cover]!/4/6/8/1:0)"), 1, "First is less specific, so is first");
|
||||
|
||||
// Same Depth
|
||||
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/6/8)", "epubcfi(/6/2[cover]!/6/2)"), 1, "First Element is greater");
|
||||
|
@ -172,7 +172,7 @@ describe('EpubCFI', function() {
|
|||
var cfi = new EpubCFI(t, base);
|
||||
|
||||
assert.equal(t.nodeType, Node.ELEMENT_NODE, "provided a highlight node");
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017]/1)" );
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/32/2[c001p0017])" );
|
||||
|
||||
});
|
||||
|
||||
|
@ -183,6 +183,9 @@ describe('EpubCFI', function() {
|
|||
var contents = fs.readFileSync(__dirname + '/fixtures/chapter1.xhtml', 'utf8');
|
||||
var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml");
|
||||
|
||||
var highlightContents = fs.readFileSync(__dirname + '/fixtures/highlight.xhtml', 'utf8');
|
||||
var hdoc = new DOMParser().parseFromString(highlightContents, "application/xhtml+xml");
|
||||
|
||||
it('get a cfi from a collapsed range', function() {
|
||||
var t1 = doc.getElementById('c001p0004').childNodes[0];
|
||||
var t2 = doc.getElementById('c001p0007').childNodes[0];
|
||||
|
@ -214,6 +217,21 @@ describe('EpubCFI', function() {
|
|||
|
||||
});
|
||||
|
||||
it('get a cfi from a range with offset 0', function() {
|
||||
var t1 = doc.getElementById('c001p0004').childNodes[0];
|
||||
var range = doc.createRange();
|
||||
var cfi;
|
||||
|
||||
range.setStart(t1, 0);
|
||||
range.setEnd(t1, 1);
|
||||
|
||||
cfi = new EpubCFI(range, base);
|
||||
|
||||
assert.equal( cfi.range, true);
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/10/2[c001p0004],/1:0,/1:1)" );
|
||||
|
||||
});
|
||||
|
||||
it('get a cfi from a range inside a highlight', function() {
|
||||
var t1 = doc.getElementById('highlight-1').childNodes[0];
|
||||
var range = doc.createRange();
|
||||
|
@ -236,7 +254,20 @@ describe('EpubCFI', function() {
|
|||
|
||||
cfi = new EpubCFI(range, base);
|
||||
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001]/1:25)" );
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001]/1:41)" );
|
||||
|
||||
});
|
||||
|
||||
it('get a cfi from a range inbetween two highlights', function() {
|
||||
var t1 = hdoc.getElementById('p2').childNodes[1];
|
||||
var range = hdoc.createRange();
|
||||
var cfi;
|
||||
|
||||
range.setStart(t1, 4);
|
||||
|
||||
cfi = new EpubCFI(range, base);
|
||||
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/4[p2]/1:123)" );
|
||||
|
||||
});
|
||||
|
||||
|
@ -336,7 +367,7 @@ describe('EpubCFI', function() {
|
|||
|
||||
cfi = new EpubCFI(ogRange, base);
|
||||
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001],/1:5,/1:25)" );
|
||||
assert.equal( cfi.toString(), "epubcfi(/6/4[chap01ref]!/4/2/4/2[c001s0001],/1:5,/1:41)" );
|
||||
|
||||
// Check the range
|
||||
newRange = cfi.toRange(doc);
|
||||
|
|
19
test/fixtures/highlight.xhtml
vendored
Normal file
19
test/fixtures/highlight.xhtml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Highlight Test</title>
|
||||
</head>
|
||||
<body>
|
||||
<p id="p1">Alice was beginning to get very tired of sitting by her
|
||||
sister on the bank, and of having nothing to do. Once or twice she had peeped into the
|
||||
book her sister was reading, but it had no pictures or conversations in it, "and what
|
||||
is the use of a book," thought Alice, "without pictures or conversations?"</p>
|
||||
<p id="p2"><span class="annotator-hl" id="a1">So she was considering in her own mind (as well as she could, for the day made her
|
||||
feel very sleepy and stupid)</span>, whether the <span class="annotator-hl" id="a2">pleasure of making a daisy-chain</span> would be
|
||||
worth the trouble of getting up and picking the daisies, when suddenly a White Rabbit
|
||||
with pink eyes ran close by her.</p>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue