mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
Update epubcfi use xpath when available and generation fixes
This commit is contained in:
parent
08886428e2
commit
adf0464cf6
10 changed files with 193 additions and 33 deletions
|
@ -58,7 +58,6 @@
|
|||
<script src="https://static.hypothes.is/lib/jquery.ui.widget.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.autocomplete.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.core.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.widget.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.menu.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.position.min.js"></script>
|
||||
<script src="https://static.hypothes.is/lib/jquery.ui.effect.min.js"></script>
|
||||
|
|
|
@ -105,16 +105,16 @@ EPUBJS.reader.NotesController = function() {
|
|||
|
||||
marker.style.verticalAlign = "super";
|
||||
marker.style.fontSize = ".75em";
|
||||
marker.style.position = "relative";
|
||||
// marker.style.position = "relative";
|
||||
marker.style.lineHeight = "1em";
|
||||
|
||||
mark.style.display = "inline-block";
|
||||
// mark.style.display = "inline-block";
|
||||
mark.style.padding = "2px";
|
||||
mark.style.backgroundColor = "#fffa96";
|
||||
mark.style.borderRadius = "5px";
|
||||
mark.style.cursor = "pointer";
|
||||
|
||||
marker.id = annotation.anchor;
|
||||
marker.id = "note-"+EPUBJS.core.uuid();
|
||||
mark.innerHTML = annotations.indexOf(annotation) + 1 + "[Reader]";
|
||||
|
||||
marker.appendChild(mark);
|
||||
|
|
|
@ -101,6 +101,14 @@ EPUBJS.reader.ReaderController = function(book) {
|
|||
}
|
||||
});
|
||||
|
||||
// book.on("book:atStart", function(){
|
||||
// $prev.addClass("disabled");
|
||||
// });
|
||||
//
|
||||
// book.on("book:atEnd", function(){
|
||||
// $next.addClass("disabled");
|
||||
// });
|
||||
|
||||
return {
|
||||
"slideOut" : slideOut,
|
||||
"slideIn" : slideIn,
|
||||
|
|
|
@ -33,17 +33,6 @@ EPUBJS.Reader = function(bookPath, _options) {
|
|||
var $viewer = $("#viewer");
|
||||
var search = window.location.search;
|
||||
var parameters;
|
||||
|
||||
// Overide options with search parameters
|
||||
if(search) {
|
||||
parameters = search.slice(1).split("&");
|
||||
parameters.forEach(function(p){
|
||||
var split = p.split("=");
|
||||
var name = split[0];
|
||||
var value = split[1] || '';
|
||||
_options[name] = value;
|
||||
});
|
||||
}
|
||||
|
||||
this.settings = _.defaults(_options || {}, {
|
||||
bookPath : bookPath,
|
||||
|
@ -58,8 +47,19 @@ EPUBJS.Reader = function(bookPath, _options) {
|
|||
generatePagination: false,
|
||||
history: true
|
||||
});
|
||||
|
||||
this.setBookKey(bookPath); //-- This could be username + path or any unique string
|
||||
|
||||
// Overide options with search parameters
|
||||
if(search) {
|
||||
parameters = search.slice(1).split("&");
|
||||
parameters.forEach(function(p){
|
||||
var split = p.split("=");
|
||||
var name = split[0];
|
||||
var value = split[1] || '';
|
||||
reader.settings[name] = value;
|
||||
});
|
||||
}
|
||||
|
||||
this.setBookKey(this.settings.bookPath); //-- This could be username + path or any unique string
|
||||
|
||||
if(this.settings.restore && this.isSaved()) {
|
||||
this.applySavedSettings();
|
||||
|
|
|
@ -121,7 +121,7 @@ EPUBJS.EpubCFI.prototype.parse = function(cfiStr) {
|
|||
|
||||
cfi.str = cfiStr;
|
||||
|
||||
if(cfiStr.indexOf("epubcfi(") === 0) {
|
||||
if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") {
|
||||
// Remove intial epubcfi( and ending )
|
||||
cfiStr = cfiStr.slice(8, cfiStr.length-1);
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ EPUBJS.EpubCFI.prototype.parse = function(cfiStr) {
|
|||
} else {
|
||||
cfi.steps.push({
|
||||
"type" : "text",
|
||||
'index' : parseInt(end) - 1,
|
||||
'index' : (endInt - 1 ) / 2
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -384,7 +384,7 @@ EPUBJS.EpubCFI.prototype.generateCfiFromTextNode = function(anchor, offset, base
|
|||
var parent = anchor.parentElement;
|
||||
var steps = this.pathTo(parent);
|
||||
var path = this.generatePathComponent(steps);
|
||||
var index = [].slice.apply(parent.childNodes).indexOf(anchor) + 1;
|
||||
var index = 1 + (2 * Array.prototype.indexOf.call(parent.childNodes, anchor));
|
||||
return "epubcfi(" + base + "!" + path + "/"+index+":"+(offset || 0)+")";
|
||||
};
|
||||
|
||||
|
@ -394,3 +394,64 @@ EPUBJS.EpubCFI.prototype.generateCfiFromRangeAnchor = function(range, base) {
|
|||
return this.generateCfiFromTextNode(anchor, offset, base);
|
||||
};
|
||||
|
||||
EPUBJS.EpubCFI.prototype.generateXpathFromSteps = function(steps) {
|
||||
var xpath = [".", "*"];
|
||||
|
||||
steps.forEach(function(step){
|
||||
var position = step.index + 1;
|
||||
|
||||
if(step.id){
|
||||
xpath.push("*[position()=" + position + " and @id='" + step.id + "']");
|
||||
} else if(step.type === "text") {
|
||||
xpath.push("text()[" + position + "]");
|
||||
} else {
|
||||
xpath.push("*[" + position + "]");
|
||||
}
|
||||
});
|
||||
|
||||
return xpath.join("/");
|
||||
};
|
||||
|
||||
|
||||
EPUBJS.EpubCFI.prototype.generateRangeFromCfi = function(cfi, _doc) {
|
||||
var doc = _doc || document;
|
||||
var range = doc.createRange();
|
||||
var lastStep;
|
||||
var xpath;
|
||||
var startContainer;
|
||||
var textLength;
|
||||
|
||||
if(typeof cfi === 'string') {
|
||||
cfi = this.parse(cfi);
|
||||
}
|
||||
|
||||
// check spinePos
|
||||
if(cfi.spinePos === -1) {
|
||||
// Not a valid CFI
|
||||
return false;
|
||||
}
|
||||
|
||||
xpath = this.generateXpathFromSteps(cfi.steps);
|
||||
|
||||
// Get the terminal step
|
||||
lastStep = cfi.steps[cfi.steps.length-1];
|
||||
startContainer = doc.evaluate(xpath, doc, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
||||
if(!startContainer) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if(startContainer && cfi.characterOffset >= 0) {
|
||||
textLength = startContainer.length;
|
||||
if(cfi.characterOffset < textLength) {
|
||||
range.setStart(startContainer, cfi.characterOffset);
|
||||
range.setEnd(startContainer, textLength );
|
||||
} else {
|
||||
range.setStart(startContainer, cfi.characterOffset - 1 );
|
||||
range.setEnd(startContainer, cfi.characterOffset );
|
||||
}
|
||||
} else if(startContainer) {
|
||||
range.selectNode(startContainer);
|
||||
}
|
||||
// doc.defaultView.getSelection().addRange(range);
|
||||
return range;
|
||||
};
|
||||
|
|
|
@ -12,11 +12,10 @@ EPUBJS.Layout.Reflowable.prototype.format = function(documentElement, _width, _h
|
|||
var columnWidth = EPUBJS.core.prefixed('columnWidth');
|
||||
|
||||
//-- Check the width and create even width columns
|
||||
var fullWidth = Math.floor(_width);
|
||||
var width = (fullWidth % 2 === 0) ? fullWidth : fullWidth - 1;
|
||||
var width = Math.floor(_width);
|
||||
// var width = (fullWidth % 2 === 0) ? fullWidth : fullWidth - 0; // Not needed for single
|
||||
var section = Math.floor(width / 8);
|
||||
var gap = (section % 2 === 0) ? section : section - 1;
|
||||
|
||||
this.documentElement = documentElement;
|
||||
//-- Single Page
|
||||
this.spreadWidth = (width + gap);
|
||||
|
@ -32,8 +31,8 @@ EPUBJS.Layout.Reflowable.prototype.format = function(documentElement, _width, _h
|
|||
|
||||
//-- Add columns
|
||||
documentElement.style[columnAxis] = "horizontal";
|
||||
documentElement.style[columnGap] = gap+"px";
|
||||
documentElement.style[columnWidth] = width+"px";
|
||||
documentElement.style[columnGap] = gap+"px";
|
||||
|
||||
return {
|
||||
pageWidth : this.spreadWidth,
|
||||
|
@ -69,6 +68,7 @@ EPUBJS.Layout.ReflowableSpreads.prototype.format = function(documentElement, _wi
|
|||
//-- Check the width and create even width columns
|
||||
var fullWidth = Math.floor(_width);
|
||||
var width = (fullWidth % 2 === 0) ? fullWidth : fullWidth - 1;
|
||||
|
||||
var section = Math.floor(width / 8);
|
||||
var gap = (section % 2 === 0) ? section : section - 1;
|
||||
//-- Double Page
|
||||
|
|
|
@ -163,6 +163,16 @@ EPUBJS.Render.Iframe.prototype.getPageNumberByElement = function(el){
|
|||
return pg;
|
||||
};
|
||||
|
||||
//-- Show the page containing an Element
|
||||
EPUBJS.Render.Iframe.prototype.getPageNumberByRect = function(boundingClientRect){
|
||||
var left, pg;
|
||||
|
||||
left = this.leftPos + boundingClientRect.left; //-- Calculate left offset compaired to scrolled position
|
||||
pg = Math.floor(left / this.pageWidth) + 1; //-- pages start at 1
|
||||
|
||||
return pg;
|
||||
};
|
||||
|
||||
// Return the root element of the content
|
||||
EPUBJS.Render.Iframe.prototype.getBaseElement = function(){
|
||||
return this.bodyEl;
|
||||
|
|
|
@ -452,19 +452,28 @@ EPUBJS.Renderer.prototype.getPageCfi = function(prevEl){
|
|||
|
||||
// Goto a cfi position in the current chapter
|
||||
EPUBJS.Renderer.prototype.gotoCfi = function(cfi){
|
||||
var element;
|
||||
var pg;
|
||||
var marker;
|
||||
var range;
|
||||
|
||||
if(_.isString(cfi)){
|
||||
cfi = this.epubcfi.parse(cfi);
|
||||
}
|
||||
|
||||
marker = this.epubcfi.addMarker(cfi, this.doc);
|
||||
if(marker) {
|
||||
pg = this.render.getPageNumberByElement(marker);
|
||||
// Must Clean up Marker before going to page
|
||||
this.epubcfi.removeMarker(marker, this.doc);
|
||||
this.page(pg);
|
||||
|
||||
if(typeof document.evaluate === 'undefined') {
|
||||
marker = this.epubcfi.addMarker(cfi, this.doc);
|
||||
if(marker) {
|
||||
pg = this.render.getPageNumberByElement(marker);
|
||||
// Must Clean up Marker before going to page
|
||||
this.epubcfi.removeMarker(marker, this.doc);
|
||||
this.page(pg);
|
||||
}
|
||||
} else {
|
||||
var range = this.epubcfi.generateRangeFromCfi(cfi, this.doc);
|
||||
if(range) {
|
||||
pg = this.render.getPageNumberByRect(range.getBoundingClientRect());
|
||||
this.page(pg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -78,4 +78,32 @@ test("Compare CFI's", null, function() {
|
|||
equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/8/5:1)", "epubcfi(/6/2[cover]!/4/6/15:2)"), 1, "First Element is greater");
|
||||
equal(epubcfi.compare("epubcfi(/6/2[cover]!/4/8/1:0)", "epubcfi(/6/2[cover]!/4/8/1:0)"), 0, "All Equal");
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
test("Generate XPath from Steps", null, function() {
|
||||
var epubcfi = new EPUBJS.EpubCFI();
|
||||
var cfi = epubcfi.parse("epubcfi(/6/12[xepigraph_001]!4/2/8[extracts]/1:0)");
|
||||
var xpath = epubcfi.generateXpathFromSteps(cfi.steps);
|
||||
|
||||
equal(xpath, "./*/*[2]/*[1]/*[position()=4 and @id='extracts']/text()[1]", "Correct Xpath Generated");
|
||||
|
||||
});
|
||||
|
||||
|
||||
asyncTest("Generate Range from CFI", 1, function() {
|
||||
var book = ePub('/reader/moby-dick/', { width: 400, height: 600 });
|
||||
|
||||
var render = book.renderTo("qunit-fixture");
|
||||
|
||||
var result = function(){
|
||||
var displayed = book.gotoHref("epigraph_001.xhtml");
|
||||
displayed.then(function(){
|
||||
var epubcfi = new EPUBJS.EpubCFI();
|
||||
var range = epubcfi.generateRangeFromCfi("epubcfi(/6/12[xepigraph_001]!4/2/8[extracts]/1:0)", book.renderer.doc);
|
||||
equal( range.startContainer.data, "Extracts.", "Anchor is correct" );
|
||||
start();
|
||||
});
|
||||
};
|
||||
|
||||
render.then(result);
|
||||
});
|
45
tools/server
Executable file
45
tools/server
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
var connect = require('connect'),
|
||||
colors = require('colors'),
|
||||
argv = require('optimist').argv,
|
||||
portfinder = require('portfinder');
|
||||
|
||||
var port = argv.p,
|
||||
logger = argv.l,
|
||||
log = console.log;
|
||||
|
||||
if (!argv.p) {
|
||||
portfinder.basePort = 8080;
|
||||
portfinder.getPort(function (err, port) {
|
||||
if (err) throw err;
|
||||
listen(port);
|
||||
});
|
||||
} else {
|
||||
listen(port);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function listen(port) {
|
||||
var server = connect();
|
||||
server.use(connect.static(__dirname + "../../"))
|
||||
|
||||
if(!logger) server.use(connect.logger(logger))
|
||||
|
||||
server.listen(port);
|
||||
|
||||
log('Starting up Server, serving '.yellow
|
||||
+ __dirname.replace("tools", '').green
|
||||
+ ' on port: '.yellow
|
||||
+ port.toString().cyan);
|
||||
log('Hit CTRL-C to stop the server');
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
process.on('SIGINT', function () {
|
||||
log('http-server stopped.'.red);
|
||||
process.exit();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue