diff --git a/examples/annotator.html b/examples/annotator.html index 8c59def..da11eca 100644 --- a/examples/annotator.html +++ b/examples/annotator.html @@ -60,7 +60,7 @@ rendition.on("keyup", keyListener); document.addEventListener("keyup", keyListener, false); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ // console.log(location); }); diff --git a/examples/continuous-spreads.html b/examples/continuous-spreads.html index 532edfc..9d77cd2 100644 --- a/examples/continuous-spreads.html +++ b/examples/continuous-spreads.html @@ -70,7 +70,7 @@ console.log("selected", range); }); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/examples/highlights.html b/examples/highlights.html index 26e0b31..34f9029 100644 --- a/examples/highlights.html +++ b/examples/highlights.html @@ -99,7 +99,7 @@ rendition.on("keyup", keyListener); document.addEventListener("keyup", keyListener, false); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ // console.log(location); }); diff --git a/examples/input.html b/examples/input.html index 2f1d140..9bc9db9 100644 --- a/examples/input.html +++ b/examples/input.html @@ -49,7 +49,7 @@ rendition.display(); rendition.on("keyup", keyListener); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/examples/locations.html b/examples/locations.html index c23d1ae..a7d516c 100644 --- a/examples/locations.html +++ b/examples/locations.html @@ -69,10 +69,7 @@ rendition.on("keyup", keyListener); document.addEventListener("keyup", keyListener, false); - - rendition.on("locationChanged", function(location){ - console.log(location); - }); + book.ready.then(function(){ // Load in stored locations from json or local storage @@ -109,7 +106,7 @@ // Get the current CFI var currentLocation = rendition.currentLocation(); // Get the Percentage (or location) from that CFI - var currentPage = book.locations.percentageFromCfi(currentLocation.start); + var currentPage = book.locations.percentageFromCfi(currentLocation.start.cfi); slider.value = currentPage; currentPage.value = currentPage; }); @@ -122,13 +119,14 @@ }, false); // Listen for location changed event, get percentage from CFI - rendition.on('locationChanged', function(location){ - var percent = book.locations.percentageFromCfi(location.start); + rendition.on('relocated', function(location){ + var percent = book.locations.percentageFromCfi(location.start.cfi); var percentage = Math.floor(percent * 100); if(!mouseDown) { slider.value = percentage; } currentPage.value = percentage; + console.log(location); }); // Save out the generated locations to JSON diff --git a/examples/manifest.html b/examples/manifest.html index f8f713b..b6eb2f5 100644 --- a/examples/manifest.html +++ b/examples/manifest.html @@ -160,7 +160,7 @@ }); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ var current = book.navigation.get(location.href); if (current) { diff --git a/examples/marks.html b/examples/marks.html index 5875ce1..b5152d3 100644 --- a/examples/marks.html +++ b/examples/marks.html @@ -61,7 +61,7 @@ rendition.on("keyup", keyListener); document.addEventListener("keyup", keyListener, false); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ // console.log(location); }); diff --git a/examples/scrolled.html b/examples/scrolled.html index 72a3497..419f3c0 100644 --- a/examples/scrolled.html +++ b/examples/scrolled.html @@ -38,7 +38,7 @@ e.preventDefault(); }, false); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/examples/single-full.html b/examples/single-full.html index 194e47b..d1fdc38 100644 --- a/examples/single-full.html +++ b/examples/single-full.html @@ -5,6 +5,7 @@ EPUB.js Scrolled Full Example + @@ -161,7 +162,7 @@ }); var hash = window.location.hash.slice(2); console.log(hash); - rendition.display(hash || 1); + rendition.display(hash || undefined); var next = document.getElementById("next"); @@ -215,7 +216,7 @@ window.location.hash = "#/"+section.href }); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/examples/spreads.html b/examples/spreads.html index cab12b3..616abdc 100644 --- a/examples/spreads.html +++ b/examples/spreads.html @@ -89,7 +89,7 @@ }); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/examples/themes.html b/examples/themes.html index 4286d2c..629c6f2 100644 --- a/examples/themes.html +++ b/examples/themes.html @@ -86,7 +86,7 @@ }); - rendition.on("locationChanged", function(location){ + rendition.on("relocated", function(location){ console.log(location); }); diff --git a/src/layout.js b/src/layout.js index 8924144..1d4230e 100644 --- a/src/layout.js +++ b/src/layout.js @@ -180,14 +180,28 @@ class Layout { * @return {number} spreads * @return {number} pages */ - count(totalWidth) { + count(totalLength, pageLength) { // var totalWidth = contents.scrollWidth(); - var spreads = Math.ceil( totalWidth / this.delta); + let spreads, pages; + + if (this.name === "pre-paginated") { + spreads = 1; + pages = 1; + } else if (this._flow === "paginated") { + pageLength = pageLength || this.delta; + spreads = Math.ceil( totalLength / pageLength); + pages = spreads * this.divisor; + } else { // scrolled + pageLength = pageLength || this.height; + spreads = Math.ceil( totalLength / pageLength); + pages = spreads; + } return { - spreads : spreads, - pages : spreads * this.divisor + spreads, + pages }; + } } diff --git a/src/managers/default/index.js b/src/managers/default/index.js index f15b7c6..266888b 100644 --- a/src/managers/default/index.js +++ b/src/managers/default/index.js @@ -407,7 +407,7 @@ class DefaultViewManager { } return this.location; } - + /* scrolledLocation(){ var visible = this.visible(); @@ -456,14 +456,91 @@ class DefaultViewManager { } } + */ + scrolledLocation() { + let visible = this.visible(); + var container = this.container.getBoundingClientRect(); + var pageHeight = (container.height < window.innerHeight) ? container.height : window.innerHeight; + + var offset = 0; + + if(!this.settings.height) { + offset = window.scrollY; + } + + let sections = visible.map((view) => { + let {index, href} = view.section; + let position = view.position(); + let startPos = position.top - container.top + offset; + let endPos = startPos + pageHeight; + if (endPos > position.bottom - container.top + offset) { + endPos = position.bottom - container.top + offset; + } + + let totalPages = this.layout.count(view._height, pageHeight).pages; + let currPage = Math.round(startPos / pageHeight); + let pages = []; + let numPages = (endPos - startPos) / pageHeight; + for (var i = 1; i <= numPages; i++) { + let pg = currPage + i; + pages.push(pg); + } + + let mapping = this.mapping.page(view.contents, view.section.cfiBase, startPos, endPos); + + return { + index, + href, + pages, + totalPages, + mapping + } + }); + + return sections; + } paginatedLocation(){ - var visible = this.visible(); - var startA, startB, endA, endB; - var pageLeft, pageRight; + let visible = this.visible(); var container = this.container.getBoundingClientRect(); - var last; + let sections = visible.map((view) => { + let {index, href} = view.section; + let offset = view.offset().left; + let position = view.position().left; + let width = view.width(); + + let startPos = this.container.scrollLeft + offset; + let endPos = startPos + this.layout.spreadWidth + this.layout.gap; + if (endPos > this.container.scrollLeft + offset + width) { + endPos = this.container.scrollLeft + offset + width; + } + + let totalPages = this.layout.count(width).pages; + let currPage = Math.ceil((startPos - offset) / this.layout.spreadWidth); + let pages = []; + let numPages = (endPos - startPos) / (this.layout.columnWidth + (this.layout.gap / 2)); + for (var i = 1; i <= numPages; i++) { + let pg = currPage + i; + pages.push(pg); + } + + let start = container.left - position; + let end = start + this.layout.spreadWidth + this.layout.gap; + let mapping = this.mapping.page(view.contents, view.section.cfiBase, start, end); + + return { + index, + href, + pages, + totalPages, + mapping + } + }); + + return sections; + + /* if(visible.length === 1) { startA = container.left - visible[0].position().left; endA = startA + this.layout.spreadWidth + this.layout.gap; @@ -498,6 +575,7 @@ class DefaultViewManager { end: pageRight.end }; } + */ } isVisible(view, offsetPrev, offsetNext, _container){ diff --git a/src/managers/helpers/stage.js b/src/managers/helpers/stage.js index 4e45ac3..ebed632 100644 --- a/src/managers/helpers/stage.js +++ b/src/managers/helpers/stage.js @@ -42,6 +42,7 @@ class Stage { container.style.wordSpacing = "0"; container.style.lineHeight = "0"; container.style.verticalAlign = "top"; + container.style.position = "relative"; if(axis === "horizontal") { container.style.whiteSpace = "nowrap"; diff --git a/src/managers/views/iframe.js b/src/managers/views/iframe.js index fda1257..ecd3dc6 100644 --- a/src/managers/views/iframe.js +++ b/src/managers/views/iframe.js @@ -24,8 +24,8 @@ class IframeView { this.displayed = false; this.rendered = false; - this.width = this.settings.width; - this.height = this.settings.height; + // this.width = this.settings.width; + // this.height = this.settings.height; this.fixedWidth = 0; this.fixedHeight = 0; @@ -536,6 +536,21 @@ class IframeView { this.emit("hidden", this); } + offset() { + return { + top: this.element.offsetTop, + left: this.element.offsetLeft + } + } + + width() { + return this._width; + } + + height() { + return this._height; + } + position() { return this.element.getBoundingClientRect(); } diff --git a/src/mapping.js b/src/mapping.js index 1147f5a..0fe89e5 100644 --- a/src/mapping.js +++ b/src/mapping.js @@ -169,8 +169,8 @@ class Mapping { elPos = node.getBoundingClientRect(); } - left = this.horizontal ? elPos.left : elPos.top; - right = this.horizontal ? elPos.right : elPos.bottom; + left = Math.round(this.horizontal ? elPos.left : elPos.top); + right = Math.round(this.horizontal ? elPos.right : elPos.bottom); if(left > end && $prev) { return $prev; diff --git a/src/rendition.js b/src/rendition.js index ab43084..2a25502 100644 --- a/src/rendition.js +++ b/src/rendition.js @@ -490,23 +490,31 @@ class Rendition { var location = this.manager.currentLocation(); if (location && location.then && typeof location.then === "function") { location.then(function(result) { - this.location = result; + let located = this.located(result); + this.location = located; + this.emit("locationChanged", { + index: this.location.start.index, + href: this.location.start.href, + start: this.location.start.cfi, + end: this.location.end.cfi, + percentage: this.location.start.percentage + }); - this.percentage = this.book.locations.percentageFromCfi(result.start); - if (this.percentage != null) { - this.location.percentage = this.percentage; - } - - this.emit("locationChanged", this.location); + this.emit("relocated", this.location); }.bind(this)); } else if (location) { - this.location = location; - this.percentage = this.book.locations.percentageFromCfi(location.start); - if (this.percentage != null) { - this.location.percentage = this.percentage; - } + let located = this.located(location); + this.location = located; - this.emit("locationChanged", this.location); + this.emit("locationChanged", { + index: this.location.start.index, + href: this.location.start.href, + start: this.location.start.cfi, + end: this.location.end.cfi, + percentage: this.location.start.percentage + }); + + this.emit("relocated", this.location); } }.bind(this)); @@ -520,21 +528,75 @@ class Rendition { var location = this.manager.currentLocation(); if (location && location.then && typeof location.then === "function") { location.then(function(result) { - var percentage = this.book.locations.percentageFromCfi(result.start); - if (percentage != null) { - result.percentage = percentage; - } - return result; + let located = this.located(result); + return located; }.bind(this)); } else if (location) { - var percentage = this.book.locations.percentageFromCfi(location.start); - if (percentage != null) { - location.percentage = percentage; - } - return location; + let located = this.located(location); + return located; } } + located(location){ + let start = location[0]; + let end = location[location.length-1] + + let located = { + start: { + index: start.index, + href: start.href, + cfi: start.mapping.start, + displayed: { + page: start.pages[0], + total: start.totalPages + } + }, + end: { + index: end.index, + href: end.href, + cfi: end.mapping.end, + displayed: { + page: end.pages[end.pages.length-1], + totalPages: end.totalPages + } + } + }; + + let locationStart = this.book.locations.locationFromCfi(start.mapping.start); + let locationEnd = this.book.locations.locationFromCfi(end.mapping.end); + + if (locationStart != null) { + located.start.location = locationStart; + located.start.percentage = this.book.locations.percentageFromLocation(locationStart); + } + if (locationEnd != null) { + located.end.location = locationEnd; + located.end.percentage = this.book.locations.percentageFromLocation(locationEnd); + } + + let pageStart = this.book.pageList.pageFromCfi(start.mapping.start); + let pageEnd = this.book.pageList.pageFromCfi(end.mapping.end); + + if (pageStart != -1) { + located.start.page = pageStart; + } + if (pageEnd != -1) { + located.end.page = pageEnd; + } + + if (end.index === this.book.spine.last().index && + located.end.displayed.page === located.end.displayed.totalPages) { + located.atEnd = true; + } + + if (start.index === this.book.spine.first().index && + located.start.displayed.page === 1) { + located.atStart = true; + } + + return located; + } + /** * Remove and Clean Up the Rendition */ @@ -644,7 +706,7 @@ class Rendition { contents.addStylesheetRules({ "img" : { "max-width": (this._layout.columnWidth ? this._layout.columnWidth + "px" : "100%") + "!important", - "max-height": (this._layout.height ? this._layout.height + "px" : "50%") + "!important", + "max-height": (this._layout.height ? (this._layout.height * 0.6) + "px" : "60%") + "!important", "object-fit": "contain", "page-break-inside": "avoid" } diff --git a/src/spine.js b/src/spine.js index acd4b04..3636998 100644 --- a/src/spine.js +++ b/src/spine.js @@ -76,7 +76,6 @@ class Spine { } return; }.bind(this); - item.next = function() { let nextIndex = item.index; while (nextIndex < this.spineItems.length-1) { @@ -133,9 +132,9 @@ class Spine { index = cfi.spinePos; } else if(typeof target === "number" || isNaN(target) === false){ index = target; - } else if(target && target.indexOf("#") === 0) { + } else if(typeof target === "string" && target.indexOf("#") === 0) { index = this.spineById[target.substring(1)]; - } else if(target) { + } else if(typeof target === "string") { // Remove fragments target = target.split("#")[0]; index = this.spineByHref[target]; @@ -207,6 +206,30 @@ class Spine { return this.spineItems.forEach.apply(this.spineItems, arguments); } + first() { + let index = 0; + + while (index < this.spineItems.length-1) { + let next = this.get(index); + if (next && next.linear) { + return next; + } + index += 1; + } + } + + last() { + let index = this.spineItems.length-1; + + while (index > 0) { + let prev = this.get(index); + if (prev && prev.linear) { + return prev; + } + index -= 1; + } + } + destroy() { this.each((section) => section.destroy());