1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-02 14:49:16 +02:00

Updates for rendering in embedded Webviews (#643)

* Initial embedding support

* Updates for rendering in embedded webviews

* toLowerCase nodeName check
This commit is contained in:
Fred Chasen 2017-08-01 17:25:19 -04:00 committed by GitHub
parent 5cc8b191d0
commit bb1ab21a33
23 changed files with 987 additions and 213 deletions

View file

@ -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;*/
}
</style>

View file

@ -27,7 +27,7 @@
height: 600
});
var displayed = rendition.display(0);
var displayed = rendition.display();
displayed.then(function(renderer){

80
examples/embedded.html Normal file
View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title></title>
<script src="../dist/epub.js"></script>
<style>
body {
margin: 0;
-webkit-scroll-snap-type: mandatory;
-webkit-scroll-snap-points-x: repeat(100%);
/*This scroll snap functionality is part of a polyfill
that enables the functionality in Chrome.*/
scroll-snap-type: mandatory;
scroll-snap-points-x: repeat(100%);
width: 100vw;
overflow: auto;
}
.epub-container {
margin: 0;
/*-webkit-scroll-snap-type: mandatory;
-webkit-scroll-snap-points-x: repeat(100%);*/
/* -webkit-overflow-scrolling: touch; */
}
</style>
</head>
<body>
<script>
var params = URLSearchParams && new URLSearchParams(document.location.search.substring(1));
var url = params && params.get("url") && decodeURIComponent(params.get("url"));
var currentCfi = (params && params.get("cfi")) ? params.get("cfi") : undefined;
var currentSectionIndex = (params && params.get("loc")) ? parseInt(params.get("loc")) : 6;
// Load the opf
var book = ePub(url || "https://s3.amazonaws.com/moby-dick/");
var rendition = book.renderTo(document.body, {
// width: "100vw",
// height: "100vh",
overflow: "visible",
manager: "continuous",
flow: "paginated"
});
rendition.display(currentCfi || currentSectionIndex);
rendition.on("rendered", function(section){
var nextSection = section.next();
var prevSection = section.prev();
var current = book.navigation && book.navigation.get(section.href);
if (current) {
document.title = current.label;
}
});
rendition.on("relocated", function(location){
console.log("locationChanged", location)
console.log("locationChanged start", location.start.cfi)
console.log("locationChanged end", location.end.cfi)
});
window.addEventListener("unload", function () {
console.log("unloading");
this.book.destroy();
});
</script>
<!-- <script src="../node_modules/scrollsnap-polyfill/vendor/philipwalton/polyfill.js"></script>
<script src="../node_modules/scrollsnap-polyfill/src/scrollsnap-polyfill.js"></script> -->
</body>
</html>

View file

@ -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;

View file

@ -3,7 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EPUB.js Pagination Example</title>
<title>EPUB.js Highlights Example</title>
<script src="../dist/epub.js"></script>

View file

@ -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

View file

@ -0,0 +1,408 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>EPUB.js + Hypothes.is Example</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.1.1/jszip.min.js"></script>
<script src="../dist/epub.js"></script>
<!-- <script>
window.hypothesisConfig = function () {
return {
// constructor: this.Annotator.Sidebar,
app: 'https://hypothes.is/app.html',
};
};
</script> -->
<script type="text/javascript">
window.hypothesisConfig = function () {
return {
// Open the sidebar when the page loads
openSidebar: true,
// Needed for multi frame support
enableMultiFrameSupport: true,
embedScriptUrl: "https://cdn.hypothes.is/hypothesis"
};
};
</script>
<script src="https://cdn.hypothes.is/hypothesis"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="examples.css">
<style type="text/css">
body {
margin: 0;
background: #fafafa;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #333;
}
#navigation {
width: 400px;
position: fixed;
overflow: auto;
top: 0;
left: -425px;
background: #ECECEC;
min-height: 100%;
height: 100%;
height: 100vh;
overflow: scroll;
-webkit-overflow-scrolling: touch;
padding: 9px;
padding-top: 10px;
transition: left .2s ease-out;
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
}
#navigation.open {
left: 0;
}
#navigation.fixed {
position: fixed;
}
#navigation h1 {
width: 200px;
font-size: 16px;
font-weight: normal;
color: #777;
margin-bottom: 10px;
}
#navigation h2 {
font-size: 14px;
font-weight: normal;
color: #B0B0B0;
margin-bottom: 20px;
}
#navigation ul {
padding-left: 28px;
margin-left: 0;
}
#navigation ul li {
list-style: decimal;
margin-bottom: 10px;
color: #585858;
font-size: 12px;
padding-left: 0;
margin-left: 0;
}
#navigation ul li a {
color: #585858;
text-decoration: none;
}
#navigation ul li a:hover {
color: #585858;
text-decoration: underline;
}
#navigation ul li a.active {
color: #000;
font-weight: 400;
}
#navigation #author {
text-align: center;
}
#cover {
display: inline;
}
#main {
margin-top: 60px;
}
#pagination {
text-align: center;
margin: 20px;
/*padding: 0 50px;*/
}
.arrow:hover {
color: #777;
}
.arrow:active {
color: #000;
}
.arrow .material-icons {
font-size: 64px;
}
#prev {
float: left;
}
#next {
float: right;
}
#toc {
display: block;
margin: 10px auto;
}
#hypothesis-custom {
overflow: hidden;
/*position: absolute;*/
right: 0;
/*top: 0;*/
height: 100%;
width: 200px;
/*z-index: -2;*/
}
#hypothesis-custom iframe {
position: absolute;
width: 100%;
height: 100%;
}
#closer {
position: absolute;
left: 0;
top: 0;
color: #333;
cursor: pointer;
}
#closer .material-icons {
color: #333;
}
#opener {
position: absolute;
left: 0;
top: 0;
cursor: pointer;
}
</style>
</head>
<body>
<div id="main">
<a id="opener">
<i class="material-icons">menu</i>
</a>
<div id="viewer" class="spreads"></div>
<a id="prev" href="#prev" class="arrow">
<i class="material-icons">chevron_left</i>
</a>
<a id="next" href="#next" class="arrow">
<i class="material-icons">chevron_right</i>
</a>
</div>
<div id="navigation">
<a id="closer">
<i class="material-icons">close</i>
</a>
<h1 id="title">...</h1>
<image id="cover" width="150px"/>
<h2 id="author">...</h2>
<ul id="toc"></ul>
</div>
<script>
// Load the opf
var book = ePub(window.location.protocol + "//s3.amazonaws.com/epubjs/books/alice/OPS/package.opf");
var rendition = book.renderTo("viewer", {
ignoreClass: "annotator-hl",
width: "100%",
height: 600
});
// var hash = window.location.hash.slice(2);
var loc = window.location.href.indexOf("?loc=");
if (loc > -1) {
var href = window.location.href.slice(loc + 5);
var hash = decodeURIComponent(href);
}
rendition.display(hash || undefined);
var next = document.getElementById("next");
next.addEventListener("click", function(e){
rendition.next();
e.preventDefault();
}, false);
var prev = document.getElementById("prev");
prev.addEventListener("click", function(e){
rendition.prev();
e.preventDefault();
}, false);
var nav = document.getElementById("navigation");
var opener = document.getElementById("opener");
opener.addEventListener("click", function(e){
nav.classList.add("open");
}, false);
var closer = document.getElementById("closer");
closer.addEventListener("click", function(e){
nav.classList.remove("open");
}, false);
rendition.on("rendered", function(section){
var old = document.querySelectorAll('.active');
Array.prototype.slice.call(old, 0).forEach(function (link) {
link.classList.remove("active");
})
var active = document.querySelector('a[href="'+section.href+'"]');
if (active) {
active.classList.add("active");
}
// Add CFI fragment to the history
history.pushState({}, '', "?loc=" + encodeURIComponent(section.href));
// window.location.hash = "#/"+section.href
});
book.loaded.navigation.then(function(toc){
var $nav = document.getElementById("toc"),
docfrag = document.createDocumentFragment();
toc.forEach(function(chapter, index) {
var item = document.createElement("li");
var link = document.createElement("a");
link.id = "chap-" + chapter.id;
link.textContent = chapter.label;
link.href = chapter.href;
item.appendChild(link);
docfrag.appendChild(item);
link.onclick = function(){
var url = link.getAttribute("href");
console.log(url)
rendition.display(url);
return false;
};
});
$nav.appendChild(docfrag);
});
book.loaded.metadata.then(function(meta){
var $title = document.getElementById("title");
var $author = document.getElementById("author");
var $cover = document.getElementById("cover");
var $nav = document.getElementById('navigation');
$title.textContent = meta.title;
$author.textContent = meta.creator;
if (book.archive) {
book.archive.createUrl(book.cover)
.then(function (url) {
$cover.src = url;
})
} else {
$cover.src = book.cover;
}
// if ($nav.offsetHeight + 60 < window.innerHeight) {
// $nav.classList.add("fixed");
// }
});
function checkForAnnotator(cb, w) {
if (!w) {
w = window;
}
setTimeout(function () {
if (w && w.annotator) {
cb();
} else {
checkForAnnotator(cb, w);
}
}, 100);
}
book.rendition.hooks.content.register(function(contents, view) {
checkForAnnotator(function () {
var annotator = contents.window.annotator;
contents.window.addEventListener('scrolltorange', function (e) {
var range = e.detail;
var cfi = new ePub.CFI(range, contents.cfiBase).toString();
if (cfi) {
book.rendition.display(cfi);
}
e.preventDefault();
});
annotator.on("highlightClick", function (annotation) {
console.log(annotation);
window.annotator.show();
})
annotator.on("beforeAnnotationCreated", function (annotation) {
console.log(annotation);
window.annotator.show();
})
}, contents.window);
});
checkForAnnotator(function () {
var main = document.querySelector('#main');
var target = document.querySelector('.annotator-frame');
if(window.innerWidth < 1400) {
/*
window.annotator.on("show", function () {
main.classList.add("open");
});
window.annotator.on("hide", function () {
main.classList.remove("open");
});
*/
// create an observer instance
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === "class") {
if (target.classList.contains("annotator-collapsed")) {
main.classList.remove("open");
} else {
main.classList.add("open");
}
}
});
});
observer.observe(target, { attributes: true });
}
});
</script>
</body>
</html>

View file

@ -66,7 +66,7 @@
<li><a href="renderless.html">Renderless</a></li>
<li><a href="hooks.html">Hooks</a></li>
<li><a href="highlights.html">Highlights</a></li>
<li><a href="annotator.html">Annotator</a></li>
<li><a href="hypothesis.html">Hypothes.is</a></li>
<!-- <li><a href="hypothesis.html">Annotations with Hypothes.is</a></li> -->
</ol>

View file

@ -12,7 +12,8 @@
</head>
<body>
<div id="title"></div>
<!-- <div id="title"></div> -->
<select id="toc"></select>
<div id="viewer" class="spreads"></div>
<a id="prev" href="#prev" class="arrow"></a>
<a id="next" href="#next" class="arrow"></a>
@ -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;
};
});
</script>
</body>

View file

@ -107,7 +107,7 @@
}
});
// rendition.themes.apply("tan");
// rendition.themes.select("tan");
// rendition.themes.fontSize("140%");
</script>

11
package-lock.json generated
View file

@ -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",

View file

@ -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"

View file

@ -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) };
});

View file

@ -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;

View file

@ -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;

View file

@ -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();
}
}

View file

@ -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(){

View file

@ -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);
}
}
}

View file

@ -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;
}

View file

@ -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,

View file

@ -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: {

View file

@ -76,7 +76,7 @@ class Themes {
}
}
apply (name) {
select (name) {
var prev = this._current;
var contents;

View file

@ -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;
}
}