1
0
Fork 0
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:
Fred Chasen 2016-01-02 23:42:35 -05:00
parent 7cad24b414
commit 1c5e7c03fd
17 changed files with 836 additions and 497 deletions

752
dist/epub.js vendored

File diff suppressed because it is too large Load diff

2
dist/epub.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -123,7 +123,7 @@
margin: 10px auto; margin: 10px auto;
} }
#hypothesis { #hypothesis-custom {
overflow: hidden; overflow: hidden;
/*position: absolute;*/ /*position: absolute;*/
right: 0; right: 0;
@ -133,13 +133,13 @@
/*z-index: -2;*/ /*z-index: -2;*/
} }
#hypothesis iframe { #hypothesis-custom iframe {
position: absolute; position: absolute;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
#annotation-controls { /*#annotation-controls {
position: absolute; position: absolute;
top: -7px; top: -7px;
left: 0px; left: 0px;
@ -163,7 +163,7 @@
#annotation-controls ul li button:focus { #annotation-controls ul li button:focus {
border: none !important; border: none !important;
} }*/
</style> </style>
</head> </head>
<body> <body>
@ -179,7 +179,7 @@
<a id="next" href="#next" class="arrow">...</a> <a id="next" href="#next" class="arrow">...</a>
</div> </div>
</div> </div>
<div id="annotation-controls"></div> <!-- <div id="annotation-controls"></div> -->
<!-- <div id="hypothesis"> <!-- <div id="hypothesis">
<iframe src="//hypothes.is/app.html" seamless></iframe> <iframe src="//hypothes.is/app.html" seamless></iframe>
</div> --> </div> -->
@ -241,7 +241,7 @@
// Add CFI fragment to the history // Add CFI fragment to the history
// history.pushState({}, '', section.href); // history.pushState({}, '', section.href);
window.location.hash = "#/"+section.href // window.location.hash = "#/"+section.href
}); });
book.loaded.navigation.then(function(toc){ book.loaded.navigation.then(function(toc){

View file

@ -64,7 +64,12 @@ gulp.task('test', function(cb) {
mochify('./test/*.js', { mochify('./test/*.js', {
reporter: 'spec', reporter: 'spec',
transform: 'brfs', transform: 'brfs',
watch: true "web-security": false,
"webSecurityEnabled": false,
// "localUrlAccess": true,
watch: true,
wd: false,
debug: false
}) })
.bundle(); .bundle();
}); });

View file

@ -36,6 +36,7 @@
"portfinder": "^0.2.1", "portfinder": "^0.2.1",
"qunitjs": "^1.14.0", "qunitjs": "^1.14.0",
"serve-static": "^1.3.1", "serve-static": "^1.3.1",
"sinon": "^1.17.2",
"uglify": "^0.1.5", "uglify": "^0.1.5",
"vinyl-buffer": "^1.0.0", "vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0", "vinyl-source-stream": "^1.1.0",

View file

@ -108,7 +108,11 @@ Book.prototype.open = function(_url){
this.containerUrl = this.url + containerPath; 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) { if (epubContainer) {
@ -140,7 +144,6 @@ Book.prototype.open = function(_url){
}); });
} }
epubPackage.then(function(packageXml) { epubPackage.then(function(packageXml) {
// Get package information from epub opf // Get package information from epub opf
book.unpack(packageXml); book.unpack(packageXml);
@ -172,6 +175,10 @@ Book.prototype.unpack = function(packageXml){
parse = new Parser(); parse = new Parser();
book.package = parse.packageContents(packageXml); // Extract info from contents 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 book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths
this.spine.load(book.package); this.spine.load(book.package);

View file

@ -46,7 +46,7 @@ Continuous.prototype.attachListeners = function(){
Continuous.prototype.parseTarget = function(target){ Continuous.prototype.parseTarget = function(target){
if(this.epubcfi.isCfiString(target)) { if(this.epubcfi.isCfiString(target)) {
cfi = this.epubcfi.parse(target); cfi = new EpubCFI(target);
spinePos = cfi.spinePos; spinePos = cfi.spinePos;
section = this.book.spine.get(spinePos); section = this.book.spine.get(spinePos);
} else { } else {

View file

@ -407,6 +407,10 @@ function createBlobUrl(content, mime){
return tempUrl; return tempUrl;
}; };
function type(obj){
return Object.prototype.toString.call(obj).slice(8, -1);
}
module.exports = { module.exports = {
// 'uri': uri, // 'uri': uri,
// 'folder': folder, // 'folder': folder,
@ -430,5 +434,6 @@ module.exports = {
'cleanStringForXpath': cleanStringForXpath, 'cleanStringForXpath': cleanStringForXpath,
'indexOfTextNode': indexOfTextNode, 'indexOfTextNode': indexOfTextNode,
'isXml': isXml, 'isXml': isXml,
'createBlobUrl': createBlobUrl 'createBlobUrl': createBlobUrl,
'type': type
}; };

View file

@ -69,7 +69,7 @@ function EpubCFI(cfiFrom, base, options){
return core.extend(this, this.fromRange(cfiFrom, this.base)); return core.extend(this, this.fromRange(cfiFrom, this.base));
} else if (type === 'node') { } else if (type === 'node') {
return core.extend(this, this.fromNode(cfiFrom, this.base)); return core.extend(this, this.fromNode(cfiFrom, this.base));
} else if (type === 'EpubCFI') { } else if (type === 'EpubCFI' && cfiFrom.path) {
return cfiFrom; return cfiFrom;
} else if (!cfiFrom) { } else if (!cfiFrom) {
return this; return this;
@ -80,13 +80,11 @@ function EpubCFI(cfiFrom, base, options){
}; };
EpubCFI.prototype.checkType = function(cfi) { EpubCFI.prototype.checkType = function(cfi) {
// is a cfi string, should be wrapped with "epubcfi()"
if (typeof cfi === 'string' && if (this.isCfiString(cfi)) {
cfi.indexOf("epubcfi(") === 0 &&
cfi[cfi.length-1] === ")") {
return 'string'; return 'string';
// Is a range object // Is a range object
} else if (typeof cfi === 'object' && cfi instanceof window.Range){ } else if (typeof cfi === 'object' && core.type(cfi) === "Range"){
return 'range'; return 'range';
} else if (typeof cfi === 'object' && cfi instanceof window.Node ){ // || typeof cfi === 'function' } else if (typeof cfi === 'object' && cfi instanceof window.Node ){ // || typeof cfi === 'function'
return 'node'; return 'node';
@ -149,7 +147,10 @@ EpubCFI.prototype.parse = function(cfiStr) {
EpubCFI.prototype.parseComponent = function(componentStr){ EpubCFI.prototype.parseComponent = function(componentStr){
var component = { var component = {
steps: [], steps: [],
terminal: null terminal: {
offset: null,
assertion: null
}
}; };
var parts = componentStr.split(':'); var parts = componentStr.split(':');
var steps = parts[0].split('/'); var steps = parts[0].split('/');
@ -206,10 +207,10 @@ EpubCFI.prototype.parseTerminal = function(termialStr){
var assertion = termialStr.match(/\[(.*)\]/); var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){ if(assertion && assertion[1]){
characterOffset = parseInt(termialStr.split('[')[0]); characterOffset = parseInt(termialStr.split('[')[0]) || null;
textLocationAssertion = assertion[1]; textLocationAssertion = assertion[1];
} else { } else {
characterOffset = parseInt(termialStr); characterOffset = parseInt(termialStr) || null;
} }
return { return {
@ -283,11 +284,11 @@ EpubCFI.prototype.segmentString = function(segment) {
segmentString += this.joinSteps(segment.steps); segmentString += this.joinSteps(segment.steps);
if(segment.terminal && segment.terminal.offset){ if(segment.terminal && segment.terminal.offset != null){
segmentString += ':' + segment.terminal.offset; segmentString += ':' + segment.terminal.offset;
} }
if(segment.terminal && segment.terminal.assertion){ if(segment.terminal && segment.terminal.assertion != null){
segmentString += '[' + segment.terminal.assertion + ']'; segmentString += '[' + segment.terminal.assertion + ']';
} }
@ -348,9 +349,9 @@ EpubCFI.prototype.compare = function(cfiOne, cfiTwo) {
// Otherwise continue checking // 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) { if(cfiOne.path.steps.length < cfiTwo.path.steps.length) {
return -1; return 1;
} }
// Compare the charecter offset of the text node // Compare the charecter offset of the text node
@ -382,21 +383,22 @@ EpubCFI.prototype.pathTo = function(node, offset) {
currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) { currentNode.parentNode.nodeType != Node.DOCUMENT_NODE) {
filteredNode = this.filter(currentNode, this.options.ignoreClass); filteredNode = this.filter(currentNode, this.options.ignoreClass);
if (filteredNode) {
nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element'; nodeType = (filteredNode.nodeType === Node.TEXT_NODE) ? 'text' : 'element';
segment.steps.unshift({ segment.steps.unshift({
'id' : this.filterId(filteredNode, this.options.ignoreClass), 'id' : filteredNode.id,
'tagName' : filteredNode.tagName, 'tagName' : filteredNode.tagName,
'type' : nodeType, '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; segment.terminal.offset = offset;
@ -450,15 +452,15 @@ EpubCFI.prototype.fromRange = function(range, base) {
} }
if (range.collapsed) { 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); cfi.path = this.pathTo(start, startOffset);
} else { } else {
cfi.range = true; 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); 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); cfi.end = this.pathTo(end, endOffset);
// Create a new empty path // Create a new empty path
@ -522,109 +524,140 @@ EpubCFI.prototype.fromNode = function(anchor, base) {
EpubCFI.prototype.filter = function(anchor, ignoreClass) { EpubCFI.prototype.filter = function(anchor, ignoreClass) {
var needsIgnoring; var needsIgnoring;
var sibling; var sibling;
var isText;
if (anchor.nodeType === Node.TEXT_NODE) { if (anchor.nodeType === Node.TEXT_NODE) {
isText = true;
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); needsIgnoring = anchor.parentNode.classList.contains(ignoreClass);
sibling = anchor.parentNode.previousSibling;
} else { } else {
isText = false;
needsIgnoring = anchor.classList.contains(ignoreClass); needsIgnoring = anchor.classList.contains(ignoreClass);
sibling = anchor.previousSibling;
} }
if (needsIgnoring) { if (needsIgnoring && isText) {
if (sibling && sibling.nodeType === Node.TEXT_NODE) { // If the sibling is a text node, join the nodes
// If the previous 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; return sibling;
} else if (anchor.nodeType === Node.TEXT_NODE) {
return anchor.parentNode.childNodes[0];
} else { } else {
// Otherwise just ignore the node by getting the path to its parent // Parent will be ignored on next step
return anchor.parentNode; return anchor;
} }
} else if (needsIgnoring && !isText) {
// Otherwise just skip the element node
return false;
} else { } else {
// No need to filter
return anchor; return anchor;
} }
}; };
EpubCFI.prototype.filterId = function(anchor, ignoreClass) { EpubCFI.prototype.patchOffset = function(anchor, offset, 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) {
var needsIgnoring; var needsIgnoring;
var sibling; var sibling;
if (anchor.nodeType === Node.TEXT_NODE) { if (anchor.nodeType != Node.TEXT_NODE) {
needsIgnoring = anchor.parentNode.classList.contains(ignoreClass); console.error("Anchor must be a text node");
sibling = anchor.parentNode.previousSibling; return;
} else {
needsIgnoring = anchor.classList.contains(ignoreClass);
sibling = anchor.previousSibling;
} }
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 // If the previous sibling is a text node, join the nodes
return sibling.textContent.length + offset; totalOffset += curr.previousSibling.textContent.length;
} else { }
// Otherwise just ignore the node
return offset;
} }
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 { } 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) { EpubCFI.prototype.position = function(anchor, ignoreClass) {
var needsIgnoring; var children, index, map;
var sibling;
var indexed = -1;
var ignored;
var e = [];
if (anchor.nodeType === Node.TEXT_NODE) { if (anchor.nodeType === Node.ELEMENT_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;
children = anchor.parentNode.children; 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) { EpubCFI.prototype.stepsToXpath = function(steps) {
@ -780,7 +813,7 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
if(startContainer) { if(startContainer) {
try { try {
if(start.terminal.offset) { if(start.terminal.offset != null) {
range.setStart(startContainer, start.terminal.offset); range.setStart(startContainer, start.terminal.offset);
} else { } else {
range.setStart(startContainer, 0); range.setStart(startContainer, 0);
@ -793,18 +826,17 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
} }
if (endContainer) { if (endContainer) {
try { try {
if(end.terminal.offset) { if(end.terminal.offset != null) {
range.setEnd(endContainer, end.terminal.offset); range.setEnd(endContainer, end.terminal.offset);
} else { } else {
range.setEnd(endContainer, 0); range.setEnd(endContainer, 0);
} }
} catch (e) { } 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); range.setEnd(missed.container, missed.offset);
} }
} }
@ -814,4 +846,29 @@ EpubCFI.prototype.toRange = function(_doc, _cfi) {
return range; 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; module.exports = EpubCFI;

View file

@ -208,11 +208,10 @@ Rendition.prototype._display = function(target){
visible = this.views.find(section); visible = this.views.find(section);
if(visible) { if(visible) {
offset = view.locationOf(target); offset = visible.locationOf(target);
displayed = this.moveTo(offset) this.moveTo(offset);
.then(function(){ displaying.resolve();
return this.check();
});
} else { } else {
// Hide all current views // Hide all current views
@ -262,7 +261,7 @@ Rendition.prototype._display = function(target){
// Takes a cfi, fragment or page? // Takes a cfi, fragment or page?
Rendition.prototype.moveTo = function(offset){ Rendition.prototype.moveTo = function(offset){
this.scrollBy(offset.left, offset.top); this.scrollTo(offset.left, offset.top);
}; };
Rendition.prototype.render = function(view, show) { Rendition.prototype.render = function(view, show) {

View file

@ -3,7 +3,7 @@ var URI = require('urijs');
var core = require('./core'); var core = require('./core');
function request(url, type, withCredentials, headers) { 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 BLOB_RESPONSE = supportsURL ? "blob" : "arraybuffer";
var uri; var uri;
@ -27,13 +27,18 @@ function request(url, type, withCredentials, headers) {
xhr.withCredentials = true; xhr.withCredentials = true;
} }
xhr.onreadystatechange = handler;
xhr.onerror = err;
xhr.open("GET", url, true); xhr.open("GET", url, true);
for(header in headers) { for(header in headers) {
xhr.setRequestHeader(header, headers[header]); 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 isn't set, determine it from the file extension
if(!type) { if(!type) {
@ -45,13 +50,10 @@ function request(url, type, withCredentials, headers) {
xhr.responseType = BLOB_RESPONSE; xhr.responseType = BLOB_RESPONSE;
} }
if(type == "json") {
xhr.setRequestHeader("Accept", "application/json");
}
if(core.isXml(type)) { if(core.isXml(type)) {
xhr.responseType = "document"; xhr.responseType = "document";
xhr.overrideMimeType('text/xml'); // for OPF parsing // xhr.overrideMimeType('text/xml'); // for OPF parsing
} }
if(type == 'xhtml') { if(type == 'xhtml') {
@ -68,8 +70,14 @@ function request(url, type, withCredentials, headers) {
xhr.send(); xhr.send();
function err(e) {
console.error(e);
deferred.reject(e);
}
function handler() { 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 if (this.status === 200 || this.responseXML ) { //-- Firefox is reporting 0 for blob urls
var r; var r;
@ -78,6 +86,7 @@ function request(url, type, withCredentials, headers) {
r = this.responseXML; r = this.responseXML;
} else } else
if(core.isXml(type)){ 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 // If this.responseXML wasn't set, try to parse using a DOMParser from text
r = new DOMParser().parseFromString(this.response, "text/xml"); r = new DOMParser().parseFromString(this.response, "text/xml");
}else }else
@ -105,11 +114,13 @@ function request(url, type, withCredentials, headers) {
deferred.resolve(r); deferred.resolve(r);
} else { } else {
deferred.reject({ deferred.reject({
status: this.status, status: this.status,
message : this.response, message : this.response,
stack : new Error().stack stack : new Error().stack
}); });
} }
} }
} }

View file

@ -15,7 +15,6 @@ function Section(item, hooks){
this.next = item.next; this.next = item.next;
this.prev = item.prev; this.prev = item.prev;
this.epubcfi = new EpubCFI();
this.cfiBase = item.cfiBase; this.cfiBase = item.cfiBase;
this.hooks = {}; this.hooks = {};
@ -140,11 +139,11 @@ Section.prototype.reconcileLayoutSettings = function(global){
}; };
Section.prototype.cfiFromRange = function(_range) { Section.prototype.cfiFromRange = function(_range) {
return this.epubcfi.generateCfiFromRange(_range, this.cfiBase); return new EpubCFI(_range, this.cfiBase).toString();
}; };
Section.prototype.cfiFromElement = function(el) { Section.prototype.cfiFromElement = function(el) {
return this.epubcfi.generateCfiFromElement(el, this.cfiBase); return new EpubCFI(el, this.cfiBase).toString();
}; };
module.exports = Section; module.exports = Section;

View file

@ -24,6 +24,7 @@ Spine.prototype.load = function(_package) {
var href, url; var href, url;
var manifestItem = this.manifest[item.idref]; var manifestItem = this.manifest[item.idref];
var spineItem; var spineItem;
item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref); item.cfiBase = this.epubcfi.generateChapterComponent(this.spineNodeIndex, item.index, item.idref);
if(manifestItem) { if(manifestItem) {
@ -59,7 +60,7 @@ Spine.prototype.get = function(target) {
var index = 0; var index = 0;
if(this.epubcfi.isCfiString(target)) { if(this.epubcfi.isCfiString(target)) {
cfi = this.epubcfi.parse(target); cfi = new EpubCFI(target);
index = cfi.spinePos; index = cfi.spinePos;
} else if(target && (typeof target === "number" || isNaN(target) === false)){ } else if(target && (typeof target === "number" || isNaN(target) === false)){
index = target; index = target;

View file

@ -576,22 +576,28 @@ View.prototype.locationOf = function(target) {
if(!this.document) return; if(!this.document) return;
if(this.epubcfi.isCfiString(target)) { 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') { range = new EpubCFI(cfi).toRange(this.document);
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) { if(range) {
targetPos = range.getBoundingClientRect(); targetPos = range.getBoundingClientRect();
} }
}
} else if(typeof target === "string" && } else if(typeof target === "string" &&
target.indexOf("#") > -1) { target.indexOf("#") > -1) {
@ -750,10 +756,13 @@ View.prototype.onSelectionChange = function(e){
}; };
View.prototype.triggerSelectedEvent = function(selection){ View.prototype.triggerSelectedEvent = function(selection){
var range = selection.getRangeAt(0); var range;
if (selection && selection.rangeCount > 0) {
range = selection.getRangeAt(0);
console.log(range); console.log(range);
var cfirange = this.section.cfiFromRange(range); var cfirange = this.section.cfiFromRange(range);
this.trigger("selected", cfirange); this.trigger("selected", cfirange);
}
}; };
RSVP.EventTarget.mixin(View.prototype); RSVP.EventTarget.mixin(View.prototype);

View file

@ -1,28 +1,39 @@
// var test = require('tape');
var assert = require('assert'); var assert = require('assert');
var sinon = require('sinon');
// describe("Create new ePub(/path/to/epub/)", function(t) { var fs = require('fs');
//
// 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" );
// });
//
// });
describe('ePub', function() { describe('ePub', function() {
var ePub = require('../src/epub'); 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() { server = sinon.fakeServer.create();
xit('should save without error', function(done) { server.autoRespond = true;
var book = ePub("../books/moby-dick/");
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(){ 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(); done();
}); });
}); });
}); });
});

View file

@ -111,7 +111,7 @@ describe('EpubCFI', function() {
// Second is deeper // 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]!/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/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 // Same Depth
assert.equal(epubcfi.compare("epubcfi(/6/2[cover]!/6/8)", "epubcfi(/6/2[cover]!/6/2)"), 1, "First Element is greater"); 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); var cfi = new EpubCFI(t, base);
assert.equal(t.nodeType, Node.ELEMENT_NODE, "provided a highlight node"); 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 contents = fs.readFileSync(__dirname + '/fixtures/chapter1.xhtml', 'utf8');
var doc = new DOMParser().parseFromString(contents, "application/xhtml+xml"); 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() { it('get a cfi from a collapsed range', function() {
var t1 = doc.getElementById('c001p0004').childNodes[0]; var t1 = doc.getElementById('c001p0004').childNodes[0];
var t2 = doc.getElementById('c001p0007').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() { it('get a cfi from a range inside a highlight', function() {
var t1 = doc.getElementById('highlight-1').childNodes[0]; var t1 = doc.getElementById('highlight-1').childNodes[0];
var range = doc.createRange(); var range = doc.createRange();
@ -236,7 +254,20 @@ describe('EpubCFI', function() {
cfi = new EpubCFI(range, base); 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); 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 // Check the range
newRange = cfi.toRange(doc); newRange = cfi.toRange(doc);

19
test/fixtures/highlight.xhtml vendored Normal file
View 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>