diff --git a/examples/continuous-scrolled.html b/examples/continuous-scrolled.html index c4aac15..518abcd 100644 --- a/examples/continuous-scrolled.html +++ b/examples/continuous-scrolled.html @@ -14,13 +14,14 @@ .epub-container { min-width: 320px; margin: 0 auto; + position: relative; } .epub-container .epub-view > iframe { background: white; box-shadow: 0 0 4px #ccc; - margin: 10px; - padding: 20px; + /*margin: 10px; + padding: 20px;*/ } diff --git a/examples/continuous-spreads.html b/examples/continuous-spreads.html index 9d77cd2..f261c94 100644 --- a/examples/continuous-spreads.html +++ b/examples/continuous-spreads.html @@ -27,7 +27,7 @@ height: 600 }); - var displayed = rendition.display(0); + var displayed = rendition.display(); displayed.then(function(renderer){ diff --git a/examples/embedded.html b/examples/embedded.html new file mode 100644 index 0000000..087650a --- /dev/null +++ b/examples/embedded.html @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/examples.css b/examples/examples.css index 2bbf1bb..233c922 100644 --- a/examples/examples.css +++ b/examples/examples.css @@ -29,7 +29,7 @@ body { height: 600px; box-shadow: 0 0 4px #ccc; border-radius: 5px; - padding: 20px 40px; + padding: 0; position: relative; margin: 10px auto; background: white url('ajax-loader.gif') center center no-repeat; diff --git a/examples/highlights.html b/examples/highlights.html index 34f9029..5635830 100644 --- a/examples/highlights.html +++ b/examples/highlights.html @@ -3,7 +3,7 @@ - EPUB.js Pagination Example + EPUB.js Highlights Example diff --git a/examples/hooks.html b/examples/hooks.html index 54b76b9..c5841b8 100644 --- a/examples/hooks.html +++ b/examples/hooks.html @@ -75,19 +75,19 @@ // Hooks // Add a single script - rendition.hooks.content.register(function(view){ - return view.addScript("https://code.jquery.com/jquery-2.1.4.min.js") + rendition.hooks.content.register(function(contents){ + return contents.addScript("https://code.jquery.com/jquery-2.1.4.min.js") .then(function(){ // init code }); }); // Add several scripts / css - rendition.hooks.content.register(function(view){ + rendition.hooks.content.register(function(contents){ var loaded = Promise.all([ - view.addScript("http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.min.js"), - view.addCss("http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css") + contents.addScript("https://code.jquery.com/jquery-2.1.4.min.js"), + contents.addStylesheet("http://code.jquery.com/mobile/1.4.5/jquery.mobile-1.4.5.css") ]); // return loaded promise diff --git a/examples/hypothesis-spreads.html b/examples/hypothesis-spreads.html new file mode 100644 index 0000000..3d57ab7 --- /dev/null +++ b/examples/hypothesis-spreads.html @@ -0,0 +1,408 @@ + + + + + + EPUB.js + Hypothes.is Example + + + + + + + + + + + + + + +
+ + menu + +
+ + +
+ + + + + + diff --git a/examples/index.html b/examples/index.html index c24a0c9..dbad668 100644 --- a/examples/index.html +++ b/examples/index.html @@ -66,7 +66,7 @@
  • Renderless
  • Hooks
  • Highlights
  • -
  • Annotator
  • +
  • Hypothes.is
  • diff --git a/examples/spreads.html b/examples/spreads.html index 616abdc..87d3d19 100644 --- a/examples/spreads.html +++ b/examples/spreads.html @@ -12,7 +12,8 @@ -
    + +
    @@ -72,7 +73,19 @@ var current = book.navigation && book.navigation.get(section.href); if (current) { - title.textContent = current.label; + var $select = document.getElementById("toc"); + var $selected = $select.querySelector("option[selected]"); + if ($selected) { + $selected.removeAttribute("selected"); + } + + var $options = $select.querySelectorAll("option"); + for (var i = 0; i < $options.length; ++i) { + let selected = $options[i].getAttribute("ref") === current.href; + if (selected) { + $options[i].setAttribute("selected", ""); + } + } } if(nextSection) { @@ -98,6 +111,29 @@ this.book.destroy(); }); + book.loaded.navigation.then(function(toc){ + var $select = document.getElementById("toc"), + docfrag = document.createDocumentFragment(); + + toc.forEach(function(chapter) { + var option = document.createElement("option"); + option.textContent = chapter.label; + option.setAttribute("ref", chapter.href); + + docfrag.appendChild(option); + }); + + $select.appendChild(docfrag); + + $select.onchange = function(){ + var index = $select.selectedIndex, + url = $select.options[index].getAttribute("ref"); + rendition.display(url); + return false; + }; + + }); + diff --git a/examples/themes.html b/examples/themes.html index 629c6f2..117f892 100644 --- a/examples/themes.html +++ b/examples/themes.html @@ -107,7 +107,7 @@ } }); - // rendition.themes.apply("tan"); + // rendition.themes.select("tan"); // rendition.themes.fontSize("140%"); diff --git a/package-lock.json b/package-lock.json index 9cc7ef9..4356936 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "epubjs", - "version": "0.3.40", + "version": "0.3.41", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -8530,8 +8530,7 @@ "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", - "dev": true + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" }, "lodash._baseassign": { "version": "3.2.0", @@ -8928,9 +8927,9 @@ "dev": true }, "marks-pane": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.1.tgz", - "integrity": "sha512-b93yiOd1dorO8fT4wH3AhoYenkosJgPHMEZeCl1MQOhhVXe8oJgBhrDKaYreguSiCjGmBP0CG+RMBOuvR60t/w==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/marks-pane/-/marks-pane-1.0.2.tgz", + "integrity": "sha512-S3OuXWgPlCR9nQEN52Ut/beuw7SwkmVrTd9Ce38uEoaTbaO3/5fzD5KPERlWILH1mfi/B91DYfwCeC0bgsliXQ==" }, "math-expression-evaluator": { "version": "1.2.17", diff --git a/package.json b/package.json index 425342e..62dfc46 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,8 @@ "dependencies": { "event-emitter": "^0.3.5", "jszip": "^3.1.3", - "marks-pane": "^1.0.1", + "lodash": "^4.17.4", + "marks-pane": "^1.0.2", "path-webpack": "0.0.3", "stream-browserify": "^2.0.1", "xmldom": "^0.1.27" diff --git a/src/contents.js b/src/contents.js index fda5c18..28774e2 100644 --- a/src/contents.js +++ b/src/contents.js @@ -302,11 +302,11 @@ class Contents { this.addSelectionListeners(); - this.transitionListeners(); + // this.transitionListeners(); this.resizeListeners(); - this.resizeObservers(); + // this.resizeObservers(); this.linksHandler(); } @@ -717,6 +717,7 @@ class Contents { if (width >= 0) { this.width(width); viewport.width = width; + this.css("padding", "0 "+(width/12)+"px", true); } if (height >= 0) { @@ -727,6 +728,7 @@ class Contents { this.css("margin", "0"); this.css("box-sizing", "border-box"); + this.viewport(viewport); } @@ -745,7 +747,9 @@ class Contents { this.css("display", "inline-block"); // Fixes Safari column cut offs this.css("overflow-y", "hidden"); this.css("margin", "0", true); - this.css("padding", "0", true); + + this.css("padding", "20px " + (gap / 2) + "px", true); + this.css("box-sizing", "border-box"); this.css("max-width", "inherit"); @@ -852,6 +856,7 @@ class Contents { return h; } + /* mark(cfiRange, data={}, cb) { let range = this.range(cfiRange); @@ -881,6 +886,50 @@ class Contents { return parent; } + */ + + mark(cfiRange, data={}, cb) { + + if (cfiRange in this.marks) { + item = this.marks[cfiRange]; + return item; + } + + let range = this.range(cfiRange); + + let container = range.commonAncestorContainer; + let parent = (container.nodeType === 1) ? container : container.parentNode; + let emitter = (e) => { + this.emit("markClicked", cfiRange, data); + }; + + let pos = parent.getBoundingClientRect(); + let mark = this.document.createElement('a'); + mark.setAttribute("ref", "epubjs-mk"); + mark.style.position = "absolute"; + mark.style.top = `${pos.top}px`; + mark.style.left = `${pos.right}px`; + + mark.dataset["epubcfi"] = cfiRange; + + if (data) { + Object.keys(data).forEach((key) => { + mark.dataset[key] = data[key]; + }); + } + + if (cb) { + mark.addEventListener("click", cb); + } + + mark.addEventListener("click", emitter); + + this.content.appendChild(mark); + + this.marks[cfiRange] = { "element": mark, "listeners": [emitter, cb] }; + + return parent; + } unhighlight(cfiRange) { let item; @@ -910,7 +959,7 @@ class Contents { let item; if (cfiRange in this.marks) { item = this.marks[cfiRange]; - item.element.removeAttribute("ref"); + this.content.removeChild(item.element); item.listeners.forEach((l) => { if (l) { item.element.removeEventListener("click", l) }; }); diff --git a/src/layout.js b/src/layout.js index 1d4230e..209a2ab 100644 --- a/src/layout.js +++ b/src/layout.js @@ -101,7 +101,7 @@ class Layout { // var fullWidth = Math.floor(_width); var width = _width; - var section = Math.floor(width / 8); + var section = Math.floor(width / 12); var colWidth; var spreadWidth; @@ -123,7 +123,10 @@ class Layout { //-- Double Page if(divisor > 1) { - colWidth = (width - gap) / divisor; + // width = width - gap; + // colWidth = (width - gap) / divisor; + // gap = gap / divisor; + colWidth = (width / divisor) - gap; } else { colWidth = width; } @@ -134,7 +137,8 @@ class Layout { spreadWidth = colWidth * divisor; - delta = (colWidth + gap) * divisor; + delta = width; + // console.log(delta, width); this.width = width; this.height = _height; diff --git a/src/locations.js b/src/locations.js index ad6c30a..e59ce03 100644 --- a/src/locations.js +++ b/src/locations.js @@ -239,7 +239,11 @@ class Locations { } load(locations){ - this._locations = JSON.parse(locations); + if (typeof locations === "string") { + this._locations = JSON.parse(locations); + } else { + this._locations = locations; + } this.total = this._locations.length - 1; return this._locations; } @@ -296,7 +300,7 @@ class Locations { this.request = undefined; this.pause = undefined; - this.q.clear(); + this.q.stop(); this.q = undefined; this.epubcfi = undefined; diff --git a/src/managers/continuous/index.js b/src/managers/continuous/index.js index 19507a1..8dcbe33 100644 --- a/src/managers/continuous/index.js +++ b/src/managers/continuous/index.js @@ -1,5 +1,6 @@ import {extend, defer, requestAnimationFrame} from "../../utils/core"; import DefaultViewManager from "../default"; +import debounce from 'lodash/debounce' class ContinuousViewManager extends DefaultViewManager { constructor(options) { @@ -10,7 +11,7 @@ class ContinuousViewManager extends DefaultViewManager { this.settings = extend(this.settings || {}, { infinite: true, - overflow: "auto", + overflow: undefined, axis: "vertical", offset: 500, offsetDelta: 250, @@ -48,13 +49,15 @@ class ContinuousViewManager extends DefaultViewManager { fill(_full){ var full = _full || new defer(); - this.check().then(function(result) { + this.q.enqueue(() => { + return this.check(); + }).then((result) => { if (result) { this.fill(full); } else { full.resolve(); } - }.bind(this)); + }); return full.promise; } @@ -76,10 +79,13 @@ class ContinuousViewManager extends DefaultViewManager { offsetX = distX+this.settings.offset; } - return this.check(offsetX, offsetY) - .then(function(){ - this.scrollBy(distX, distY, true); - }.bind(this)); + this.check(offsetX, offsetY); + this.scrollBy(distX, distY, true); + + // return this.check(offsetX, offsetY) + // .then(function(){ + // this.scrollBy(distX, distY, true); + // }.bind(this)); } /* @@ -106,36 +112,36 @@ class ContinuousViewManager extends DefaultViewManager { } */ - resize(width, height){ - - // Clear the queue - this.q.clear(); - - this._stageSize = this.stage.size(width, height); - this._bounds = this.bounds(); - console.log("set bounds", this._bounds); - - // Update for new views - this.viewSettings.width = this._stageSize.width; - this.viewSettings.height = this._stageSize.height; - - // Update for existing views - this.views.each(function(view) { - view.size(this._stageSize.width, this._stageSize.height); - }.bind(this)); - - this.updateLayout(); - - // if(this.location) { - // this.rendition.display(this.location.start); - // } - - this.emit("resized", { - width: this.stage.width, - height: this.stage.height - }); - - } + // resize(width, height){ + // + // // Clear the queue + // this.q.clear(); + // + // this._stageSize = this.stage.size(width, height); + // console.log("resize says", this._stageSize, width, height); + // this._bounds = this.bounds(); + // + // // Update for new views + // this.viewSettings.width = this._stageSize.width; + // this.viewSettings.height = this._stageSize.height; + // + // // Update for existing views + // this.views.each(function(view) { + // view.size(this._stageSize.width, this._stageSize.height); + // }.bind(this)); + // + // this.updateLayout(); + // + // // if(this.location) { + // // this.rendition.display(this.location.start); + // // } + // + // this.emit("resized", { + // width: this._stageSize.width, + // height: this._stageSize.height + // }); + // + // } onResized(e) { @@ -179,8 +185,29 @@ class ContinuousViewManager extends DefaultViewManager { // // }; + add(section){ + var view = this.createView(section); + + this.views.append(view); + + view.on("resized", (bounds) => { + view.expanded = true; + }); + + // view.on("shown", this.afterDisplayed.bind(this)); + view.onDisplayed = this.afterDisplayed.bind(this); + view.onResize = this.afterResized.bind(this); + + return view.display(this.request); + } + append(section){ var view = this.createView(section); + + view.on("resized", (bounds) => { + view.expanded = true; + }); + this.views.append(view); view.onDisplayed = this.afterDisplayed.bind(this); @@ -191,7 +218,10 @@ class ContinuousViewManager extends DefaultViewManager { prepend(section){ var view = this.createView(section); - view.on("resized", this.counter.bind(this)); + view.on("resized", (bounds) => { + this.counter(bounds); + view.expanded = true; + }); this.views.prepend(view); @@ -201,7 +231,6 @@ class ContinuousViewManager extends DefaultViewManager { } counter(bounds){ - if(this.settings.axis === "vertical") { this.scrollBy(0, bounds.heightDelta, true); } else { @@ -228,14 +257,19 @@ class ContinuousViewManager extends DefaultViewManager { isVisible = this.isVisible(view, offset, offset, container); if(isVisible === true) { + // console.log("visible " + view.index); + if (!view.displayed) { promises.push(view.display(this.request).then(function (view) { view.show(); })); + } else { + view.show(); } visible.push(view); } else { - this.q.enqueue(view.destroy.bind(view)); + // this.q.enqueue(view.destroy.bind(view)); + // console.log("hidden " + view.index); clearTimeout(this.trimTimeout); this.trimTimeout = setTimeout(function(){ @@ -280,6 +314,7 @@ class ContinuousViewManager extends DefaultViewManager { if (offset + visibleLength + delta >= contentLength) { last = this.views.last(); next = last && last.section.next(); + if(next) { newViews.push(this.append(next)); } @@ -287,19 +322,26 @@ class ContinuousViewManager extends DefaultViewManager { if (offset - delta < 0 ) { first = this.views.first(); + prev = first && first.section.prev(); if(prev) { newViews.push(this.prepend(prev)); } } + let promises = newViews.map((view) => { + return view.displayed; + }); + if(newViews.length){ - // Promise.all(promises) - // .then(function() { + return Promise.all(promises) + .then(() => { + return this.update(delta); + }); // Check to see if anything new is on screen after rendering - return this.q.enqueue(function(){ - return this.update(delta); - }.bind(this)); + // return this.q.enqueue(function(){ + // this.update(delta); + // }.bind(this)); // }.bind(this)); @@ -351,6 +393,7 @@ class ContinuousViewManager extends DefaultViewManager { var bounds = view.bounds(); + view.destroy.bind(view) this.views.remove(view); if(above) { @@ -402,7 +445,7 @@ class ContinuousViewManager extends DefaultViewManager { } scroller.addEventListener("scroll", this.onScroll.bind(this)); - + this._scrolled = debounce(this.scrolled.bind(this), 300); // this.tick.call(window, this.onScroll.bind(this)); this.scrolled = false; @@ -440,31 +483,35 @@ class ContinuousViewManager extends DefaultViewManager { if(!this.ignore) { - if((this.scrollDeltaVert === 0 && - this.scrollDeltaHorz === 0) || - this.scrollDeltaVert > this.settings.offsetDelta || - this.scrollDeltaHorz > this.settings.offsetDelta) { - - this.q.enqueue(function() { - this.check(); - }.bind(this)); - // this.check(); - - this.scrollDeltaVert = 0; - this.scrollDeltaHorz = 0; - - this.emit("scroll", { - top: scrollTop, - left: scrollLeft - }); - - clearTimeout(this.afterScrolled); - this.afterScrolled = setTimeout(function () { - this.emit("scrolled", { - top: this.scrollTop, - left: this.scrollLeft - }); - }.bind(this)); + this._scrolled(); + // if((this.scrollDeltaVert === 0 && + // this.scrollDeltaHorz === 0) || + // this.scrollDeltaVert > this.settings.offsetDelta || + // this.scrollDeltaHorz > this.settings.offsetDelta) { + if(this.scrollDeltaVert > this.settings.offsetDelta || + this.scrollDeltaHorz > this.settings.offsetDelta) { + // console.log("scroll", this.scrollDeltaHorz); + // + // this.q.enqueue(function() { + // this.check(); + // }.bind(this)); + // // this.check(); + // + // this.scrollDeltaVert = 0; + // this.scrollDeltaHorz = 0; + // + // this.emit("scroll", { + // top: scrollTop, + // left: scrollLeft + // }); + // + // clearTimeout(this.afterScrolled); + // this.afterScrolled = setTimeout(function () { + // this.emit("scrolled", { + // top: this.scrollTop, + // left: this.scrollLeft + // }); + // }.bind(this)); } @@ -492,36 +539,55 @@ class ContinuousViewManager extends DefaultViewManager { } - updateLayout() { + scrolled() { + this.q.enqueue(function() { + this.check(); + }.bind(this)); - if (!this.stage) { - return; - } - - if(this.settings.axis === "vertical") { - this.layout.calculate(this._stageSize.width, this._stageSize.height); - } else { - this.layout.calculate( - this._stageSize.width, - this._stageSize.height, - this.settings.gap - ); - - // Set the look ahead offset for what is visible - this.settings.offset = this.layout.delta; - - this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]); - - } - - // Set the dimensions for views - this.viewSettings.width = this.layout.width; - this.viewSettings.height = this.layout.height; - - this.setLayout(this.layout); + this.emit("scroll", { + top: this.scrollTop, + left: this.scrollLeft + }); + clearTimeout(this.afterScrolled); + this.afterScrolled = setTimeout(function () { + this.emit("scrolled", { + top: this.scrollTop, + left: this.scrollLeft + }); + }.bind(this)); } + // updateLayout() { + // + // if (!this.stage) { + // return; + // } + // + // if(this.settings.axis === "vertical") { + // this.layout.calculate(this._stageSize.width, this._stageSize.height); + // } else { + // this.layout.calculate( + // this._stageSize.width, + // this._stageSize.height, + // this.settings.gap + // ); + // + // // Set the look ahead offset for what is visible + // this.settings.offset = this.layout.delta; + // + // // this.stage.addStyleRules("iframe", [{"padding" : "0 " + (this.layout.gap / 2) + "px"}]); + // + // } + // + // // Set the dimensions for views + // this.viewSettings.width = this.layout.width; + // this.viewSettings.height = this.layout.height; + // + // this.setLayout(this.layout); + // + // } + next(){ if(this.settings.axis === "horizontal") { @@ -562,9 +628,15 @@ class ContinuousViewManager extends DefaultViewManager { this.settings.axis = axis; + this.stage && this.stage.axis(axis); + this.viewSettings.axis = axis; - this.settings.overflow = (flow === "paginated") ? "hidden" : "auto"; + if (!this.settings.overflow) { + this.overflow = (flow === "paginated") ? "hidden" : "auto"; + } else { + this.overflow = this.settings.overflow; + } // this.views.each(function(view){ // view.setAxis(axis); @@ -576,6 +648,8 @@ class ContinuousViewManager extends DefaultViewManager { this.settings.infinite = false; } + this.updateLayout(); + } } diff --git a/src/managers/default/index.js b/src/managers/default/index.js index ef6bffb..1bc2369 100644 --- a/src/managers/default/index.js +++ b/src/managers/default/index.js @@ -38,14 +38,28 @@ class DefaultViewManager { } render(element, size){ + let tag = element.tagName; + + if (tag && (tag.toLowerCase() == "body" || + tag.toLowerCase() == "html")) { + this.fullsize = true; + } + + if (this.fullsize) { + this.settings.overflow = "visible"; + this.overflow = this.settings.overflow; + } + + this.settings.size = size; // Save the stage this.stage = new Stage({ width: size.width, height: size.height, - overflow: this.settings.overflow, + overflow: this.overflow, hidden: this.settings.hidden, - axis: this.settings.axis + axis: this.settings.axis, + fullsize: this.fullsize }); this.stage.attachTo(element); @@ -85,7 +99,7 @@ class DefaultViewManager { this.destroy(); }.bind(this)); - if(this.settings.height) { + if(!this.fullsize) { scroller = this.container; } else { scroller = window; @@ -97,7 +111,7 @@ class DefaultViewManager { removeEventListeners(){ var scroller; - if(this.settings.height) { + if(!this.fullsize) { scroller = this.container; } else { scroller = window; @@ -127,6 +141,25 @@ class DefaultViewManager { */ } + onOrientationChange(e) { + let {orientation} = window; + + this._stageSize = this.stage.size(); + this._bounds = this.bounds(); + // Update for new views + this.viewSettings.width = this._stageSize.width; + this.viewSettings.height = this._stageSize.height; + + this.updateLayout(); + + // Update for existing views + // this.views.each(function(view) { + // view.size(this._stageSize.width, this._stageSize.height); + // }.bind(this)); + + this.emit("orientationChange", orientation); + } + onResized(e) { clearTimeout(this.resizeTimeout); this.resizeTimeout = setTimeout(function(){ @@ -139,6 +172,7 @@ class DefaultViewManager { this.q.clear(); this._stageSize = this.stage.size(width, height); + this._bounds = this.bounds(); // Update for new views @@ -148,14 +182,18 @@ class DefaultViewManager { this.updateLayout(); // Update for existing views + // TODO: this is not updating correctly, just clear and rerender for now + /* this.views.each(function(view) { + view.reset(); view.size(this._stageSize.width, this._stageSize.height); }.bind(this)); - + */ + this.clear(); this.emit("resized", { - width: this.stage.width, - height: this.stage.height + width: this._stageSize.width, + height: this._stageSize.height }); } @@ -393,9 +431,11 @@ class DefaultViewManager { } clear () { - this.views.hide(); - this.scrollTo(0,0, true); - this.views.clear(); + if (this.views) { + this.views.hide(); + this.scrollTo(0,0, true); + this.views.clear(); + } } currentLocation(){ @@ -464,7 +504,7 @@ class DefaultViewManager { var offset = 0; - if(!this.settings.height) { + if(this.fullsize) { offset = window.scrollY; } @@ -504,16 +544,22 @@ class DefaultViewManager { let visible = this.visible(); var container = this.container.getBoundingClientRect(); + var left = 0; + + if(this.fullsize) { + left = window.scrollX; + } + 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 startPos = left + offset; let endPos = startPos + this.layout.spreadWidth + this.layout.gap; - if (endPos > this.container.scrollLeft + offset + width) { - endPos = this.container.scrollLeft + offset + width; + if (endPos > left + offset + width) { + endPos = left + offset + width; } let totalPages = this.layout.count(width).pages; @@ -525,8 +571,9 @@ class DefaultViewManager { pages.push(pg); } - let start = container.left - position; + let start = left + 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 { @@ -587,11 +634,9 @@ class DefaultViewManager { this.ignore = true; } - if(this.settings.height) { - + if(!this.fullsize) { if(x) this.container.scrollLeft += x; if(y) this.container.scrollTop += y; - } else { window.scrollBy(x,y); } @@ -603,27 +648,20 @@ class DefaultViewManager { this.ignore = true; } - if(this.settings.height) { + if(!this.fullsize) { this.container.scrollLeft = x; this.container.scrollTop = y; } else { window.scrollTo(x,y); } this.scrolled = true; - - // if(this.container.scrollLeft != x){ - // setTimeout(function() { - // this.scrollTo(x, y, silent); - // }.bind(this), 10); - // return; - // }; } onScroll(){ let scrollTop; let scrollLeft; - if(this.settings.height) { + if(!this.fullsize) { scrollTop = this.container.scrollTop; scrollLeft = this.container.scrollLeft; } else { @@ -670,6 +708,7 @@ class DefaultViewManager { this.updateLayout(); this.mapping = new Mapping(this.layout.props); + // this.manager.layout(this.layout.format); } @@ -692,7 +731,7 @@ class DefaultViewManager { // Set the look ahead offset for what is visible this.settings.offset = this.layout.delta; - this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]); + // this.stage.addStyleRules("iframe", [{"margin-right" : this.layout.gap + "px"}]); } @@ -701,7 +740,6 @@ class DefaultViewManager { this.viewSettings.height = this.layout.height; this.setLayout(this.layout); - } setLayout(layout){ @@ -723,13 +761,21 @@ class DefaultViewManager { this.settings.axis = axis; + this.stage && this.stage.axis(axis); + this.viewSettings.axis = axis; - this.settings.overflow = (flow === "paginated") ? "hidden" : "auto"; + if (!this.settings.overflow) { + this.overflow = (flow === "paginated") ? "hidden" : "auto"; + } else { + this.overflow = this.settings.overflow; + } // this.views.each(function(view){ // view.setAxis(axis); // }); + this.updateLayout(); + } getContents(){ diff --git a/src/managers/helpers/stage.js b/src/managers/helpers/stage.js index ebed632..74cb5aa 100644 --- a/src/managers/helpers/stage.js +++ b/src/managers/helpers/stage.js @@ -45,7 +45,10 @@ class Stage { container.style.position = "relative"; if(axis === "horizontal") { - container.style.whiteSpace = "nowrap"; + // container.style.whiteSpace = "nowrap"; + container.style.display = "flex"; + container.style.flexDirection = "row"; + container.style.flexWrap = "nowrap"; } if(width){ @@ -124,11 +127,17 @@ class Stage { // This applies if it is set to a percent or auto. if(!isNumber(this.settings.width) || !isNumber(this.settings.height) ) { - window.addEventListener("resize", func, false); + this.resizeFunc = func; + window.addEventListener("resize", this.resizeFunc, false); } } + onOrientationChange(func){ + this.orientationChangeFunc = func; + window.addEventListener("orientationChange", this.orientationChangeFunc, false); + } + size(width, height){ var bounds; // var width = _width || this.settings.width; @@ -176,6 +185,15 @@ class Stage { bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0 }; + // Bounds not set, get them from window + let _windowBounds = windowBounds(); + if (!width) { + width = _windowBounds.width; + } + if (this.settings.fullsize || !height) { + height = _windowBounds.height; + } + return { width: width - this.containerPadding.left - @@ -188,7 +206,11 @@ class Stage { } bounds(){ - let box = this.container && this.container.getBoundingClientRect(); + let box; + if (this.container.style.overflow !== "visible") { + box = this.container && this.container.getBoundingClientRect(); + } + if(!box || !box.width || !box.height) { return windowBounds(); } else { @@ -227,6 +249,26 @@ class Stage { this.sheet.insertRule(scope + selector + " {" + rules + "}", 0); } + axis(axis) { + if(axis === "horizontal") { + this.container.style.display = "flex"; + this.container.style.flexDirection = "row"; + this.container.style.flexWrap = "nowrap"; + } else { + this.container.style.display = "block"; + } + } + + // orientation(orientation) { + // if (orientation === "landscape") { + // + // } else { + // + // } + // + // this.orientation = orientation; + // } + destroy() { var base; @@ -241,6 +283,10 @@ class Stage { if(this.element.contains(this.container)) { this.element.removeChild(this.container); } + + window.removeEventListener("resize", this.resizeFunc); + window.removeEventListener("orientationChange", this.orientationChangeFunc); + } } } diff --git a/src/managers/views/iframe.js b/src/managers/views/iframe.js index ecd3dc6..4e99c69 100644 --- a/src/managers/views/iframe.js +++ b/src/managers/views/iframe.js @@ -49,7 +49,8 @@ class IframeView { element.style.overflow = "hidden"; if(axis && axis == "horizontal"){ - element.style.display = "inline-block"; + element.style.display = "block"; + element.style.flex = "none"; } else { element.style.display = "block"; } @@ -86,6 +87,8 @@ class IframeView { this._width = 0; this._height = 0; + this.element.setAttribute("ref", this.index); + this.element.appendChild(this.iframe); this.added = true; @@ -129,19 +132,6 @@ class IframeView { .then(function(contents){ return this.load(contents); }.bind(this)) - // .then(function(doc){ - // return this.hooks.content.trigger(view, this); - // }.bind(this)) - .then(function(){ - // this.settings.layout.format(view.contents); - // return this.hooks.layout.trigger(view, this); - }.bind(this)) - // .then(function(){ - // return this.display(); - // }.bind(this)) - // .then(function(){ - // return this.hooks.render.trigger(view, this); - // }.bind(this)) .then(function(){ // apply the layout function to the contents @@ -169,6 +159,20 @@ class IframeView { } + reset () { + if (this.iframe) { + this.iframe.style.width = "0"; + this.iframe.style.height = "0"; + this._width = 0; + this._height = 0; + this._textWidth = undefined; + this._contentWidth = undefined; + this._textHeight = undefined; + this._contentHeight = undefined; + } + this._needsReframe = true; + } + // Determine locks base on settings size(_width, _height) { var width = _width || this.settings.width; @@ -181,7 +185,6 @@ class IframeView { } else { this.lock("width", width, height); } - } // Lock an axis to element dimensions, taking borders into account @@ -197,12 +200,12 @@ class IframeView { if(what == "width" && isNumber(width)){ this.lockedWidth = width - elBorders.width - iframeBorders.width; - this.resize(this.lockedWidth, width); // width keeps ratio correct + // this.resize(this.lockedWidth, width); // width keeps ratio correct } if(what == "height" && isNumber(height)){ this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(width, this.lockedHeight); + // this.resize(width, this.lockedHeight); } if(what === "both" && @@ -211,7 +214,7 @@ class IframeView { this.lockedWidth = width - elBorders.width - iframeBorders.width; this.lockedHeight = height - elBorders.height - iframeBorders.height; - this.resize(this.lockedWidth, this.lockedHeight); + // this.resize(this.lockedWidth, this.lockedHeight); } if(this.displayed && this.iframe) { @@ -252,7 +255,8 @@ class IframeView { // width = this.contentWidth(textWidth); - columns = Math.ceil(width / (this.settings.layout.columnWidth + this.settings.layout.gap)); + /* + columns = Math.ceil(width / (this.settings.layout.columnWidth)); if ( this.settings.layout.divisor > 1 && this.settings.layout.name === "reflowable" && @@ -260,6 +264,12 @@ class IframeView { // add a blank page width += this.settings.layout.gap + this.settings.layout.columnWidth; } + */ + + // Add padding back + if (width % this.layout.width > 0) { + width += this.layout.gap / 2; + } // Save the textWdith this._textWidth = textWidth; @@ -357,15 +367,16 @@ class IframeView { this.element.style.height = height + "px"; } - this.prevBounds = this.elementBounds; - this.elementBounds = bounds(this.element); + let widthDelta = this.prevBounds ? this.elementBounds.width - this.prevBounds.width : this.elementBounds.width; + let heightDelta = this.prevBounds ? this.elementBounds.height - this.prevBounds.height : this.elementBounds.height; + size = { width: this.elementBounds.width, height: this.elementBounds.height, - widthDelta: this.elementBounds.width - this.prevBounds.width, - heightDelta: this.elementBounds.height - this.prevBounds.height, + widthDelta: widthDelta, + heightDelta: heightDelta, }; this.onResize(this, size); @@ -376,6 +387,8 @@ class IframeView { this.emit("resized", size); + this.prevBounds = this.elementBounds; + } @@ -448,29 +461,6 @@ class IframeView { promise.resolve(this.contents); } - - - // layout(layoutFunc) { - // - // this.iframe.style.display = "inline-block"; - // - // // Reset Body Styles - // // this.document.body.style.margin = "0"; - // //this.document.body.style.display = "inline-block"; - // //this.document.documentElement.style.width = "auto"; - // - // if(layoutFunc){ - // this.layoutFunc = layoutFunc; - // } - // - // this.contents.layout(this.layoutFunc); - // - // }; - // - // onLayout(view) { - // // stub - // }; - setLayout(layout) { this.layout = layout; } diff --git a/src/navigation.js b/src/navigation.js index efd6a5d..8a85c5a 100644 --- a/src/navigation.js +++ b/src/navigation.js @@ -84,7 +84,7 @@ class Navigation { var index = id ? id : 0; tocLinkArray.forEach((linkElm) => { - if (linkElm.nodeName === 'li') { + if (linkElm.nodeName.toLowerCase() === 'li') { var tocLink = qs(linkElm, 'a'), tocLinkData = { id: -1, diff --git a/src/rendition.js b/src/rendition.js index 3908ee0..5d420aa 100644 --- a/src/rendition.js +++ b/src/rendition.js @@ -182,6 +182,9 @@ class Rendition { // Listen for resizing this.manager.on("resized", this.onResized.bind(this)); + // Listen for rotation + this.manager.on("orientationChange", this.onOrientationChange.bind(this)); + // Listen for scroll changes this.manager.on("scrolled", this.reportLocation.bind(this)); @@ -342,7 +345,8 @@ class Rendition { */ onResized(size){ - if(this.location) { + if (this.location) { + // this.manager.clear(); this.display(this.location.start.cfi); } @@ -353,6 +357,19 @@ class Rendition { } + /** + * Report orientation events and display the last seen location + * @private + */ + onOrientationChange(orientation){ + if (this.location) { + this.manager.clear(); + this.display(this.location.start.cfi); + } + + this.emit("orientationChange", orientation); + } + /** * Move the Rendition to a specific offset * Usually you would be better off calling display() @@ -443,9 +460,18 @@ class Rendition { this._layout.flow(_flow); } + if (this.manager && this._layout) { + this.manager.applyLayout(this._layout); + } + if (this.manager) { this.manager.updateFlow(_flow); } + + if (this.location) { + this.manager.clear(); + this.display(this.location.start.cfi); + } } /** @@ -538,8 +564,11 @@ class Rendition { } located(location){ + if (!location.length) { + return {}; + } let start = location[0]; - let end = location[location.length-1] + let end = location[location.length-1]; let located = { start: { diff --git a/src/themes.js b/src/themes.js index eca3326..28faae7 100644 --- a/src/themes.js +++ b/src/themes.js @@ -76,7 +76,7 @@ class Themes { } } - apply (name) { + select (name) { var prev = this._current; var contents; diff --git a/src/utils/queue.js b/src/utils/queue.js index cbca23e..f04d2e5 100644 --- a/src/utils/queue.js +++ b/src/utils/queue.js @@ -177,8 +177,6 @@ class Queue { */ clear(){ this._q = []; - this.running = false; - this.paused = true; } /** @@ -195,6 +193,15 @@ class Queue { pause(){ this.paused = true; } + + /** + * End the queue + */ + stop(){ + this._q = []; + this.running = false; + this.paused = true; + } }