diff --git a/examples/hypothesis.html b/examples/hypothesis.html index 3af9ad6..0cf17ae 100755 --- a/examples/hypothesis.html +++ b/examples/hypothesis.html @@ -58,7 +58,6 @@ - diff --git a/reader_src/controllers/notes_controller.js b/reader_src/controllers/notes_controller.js index b0c6e5a..fe88dd9 100644 --- a/reader_src/controllers/notes_controller.js +++ b/reader_src/controllers/notes_controller.js @@ -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); diff --git a/reader_src/controllers/reader_controller.js b/reader_src/controllers/reader_controller.js index c44c3d9..ece295b 100644 --- a/reader_src/controllers/reader_controller.js +++ b/reader_src/controllers/reader_controller.js @@ -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, diff --git a/reader_src/reader.js b/reader_src/reader.js index 5c1061c..3ec82e5 100644 --- a/reader_src/reader.js +++ b/reader_src/reader.js @@ -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(); diff --git a/src/epubcfi.js b/src/epubcfi.js index f566209..55e3c6a 100644 --- a/src/epubcfi.js +++ b/src/epubcfi.js @@ -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; +}; diff --git a/src/layout.js b/src/layout.js index d28e875..5118457 100644 --- a/src/layout.js +++ b/src/layout.js @@ -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 diff --git a/src/render_iframe.js b/src/render_iframe.js index 8af29e0..f4bf40b 100644 --- a/src/render_iframe.js +++ b/src/render_iframe.js @@ -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; diff --git a/src/renderer.js b/src/renderer.js index ee4c615..3b33fb8 100644 --- a/src/renderer.js +++ b/src/renderer.js @@ -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); + } } }; diff --git a/tests/epubcfi.js b/tests/epubcfi.js index 8fdfe19..d234a07 100644 --- a/tests/epubcfi.js +++ b/tests/epubcfi.js @@ -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"); -}) \ No newline at end of file +}); + +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); +}); \ No newline at end of file diff --git a/tools/server b/tools/server new file mode 100755 index 0000000..ca55cda --- /dev/null +++ b/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(); +});