Skip to content

Commit

Permalink
Update epubcfi use xpath when available and generation fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
fchasen committed Apr 9, 2014
1 parent 0888642 commit adf0464
Show file tree
Hide file tree
Showing 10 changed files with 193 additions and 33 deletions.
1 change: 0 additions & 1 deletion examples/hypothesis.html
Expand Up @@ -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>
Expand Down
6 changes: 3 additions & 3 deletions reader_src/controllers/notes_controller.js
Expand Up @@ -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);
Expand Down
8 changes: 8 additions & 0 deletions reader_src/controllers/reader_controller.js
Expand Up @@ -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,
Expand Down
26 changes: 13 additions & 13 deletions reader_src/reader.js
Expand Up @@ -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,
Expand All @@ -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();
Expand Down
67 changes: 64 additions & 3 deletions src/epubcfi.js
Expand Up @@ -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);
}
Expand Down Expand Up @@ -172,7 +172,7 @@ EPUBJS.EpubCFI.prototype.parse = function(cfiStr) {
} else {
cfi.steps.push({
"type" : "text",
'index' : parseInt(end) - 1,
'index' : (endInt - 1 ) / 2
});
}

Expand Down Expand Up @@ -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)+")";
};

Expand All @@ -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;
};
8 changes: 4 additions & 4 deletions src/layout.js
Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions src/render_iframe.js
Expand Up @@ -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;
Expand Down
25 changes: 17 additions & 8 deletions src/renderer.js
Expand Up @@ -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);
}
}
};

Expand Down
30 changes: 29 additions & 1 deletion tests/epubcfi.js
Expand Up @@ -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 changes: 45 additions & 0 deletions tools/server
@@ -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();
});

0 comments on commit adf0464

Please sign in to comment.