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

Added render functions to rendition and views

This commit is contained in:
fchasen 2016-05-08 11:23:27 -04:00
parent 948c356597
commit ddb127cac5
17 changed files with 1402 additions and 679 deletions

1264
dist/epub.js vendored

File diff suppressed because it is too large Load diff

2
dist/epub.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -62,7 +62,7 @@
var currentSectionIndex = 8; var currentSectionIndex = 8;
// Load the opf // Load the opf
var book = ePub("../books/alice/OPS/package.opf"); var book = ePub("../books/alice/OPS/package.opf");
var rendition = book.renderTo("viewer"); var rendition = book.renderTo("viewer", { view: "inline" });
rendition.display("chapter_008.xhtml"); rendition.display("chapter_008.xhtml");

View file

@ -68,6 +68,7 @@ Book.prototype.open = function(_url){
var book = this; var book = this;
var containerPath = "META-INF/container.xml"; var containerPath = "META-INF/container.xml";
var location; var location;
var absoluteUri;
if(!_url) { if(!_url) {
this.opening.resolve(this); this.opening.resolve(this);
@ -81,7 +82,13 @@ Book.prototype.open = function(_url){
// uri = core.uri(_url); // uri = core.uri(_url);
// } // }
uri = URI(_url); uri = URI(_url);
this.url = _url;
if (window) {
absoluteUri = uri.absoluteTo(window.location.href);
this.url = absoluteUri.toString();
} else {
this.url = _url;
}
// Find path to the Container // Find path to the Container
if(uri.suffix() === "opf") { if(uri.suffix() === "opf") {
@ -91,8 +98,9 @@ Book.prototype.open = function(_url){
if(uri.origin()) { if(uri.origin()) {
this.baseUrl = uri.origin() + "/" + uri.directory() + "/"; this.baseUrl = uri.origin() + "/" + uri.directory() + "/";
} else if(window){ } else if(absoluteUri){
this.baseUrl = uri.absoluteTo(window.location.href).directory() + "/"; this.baseUrl = absoluteUri.origin();
this.baseUrl += absoluteUri.directory() + "/";
} else { } else {
this.baseUrl = uri.directory() + "/"; this.baseUrl = uri.directory() + "/";
} }
@ -130,14 +138,14 @@ Book.prototype.open = function(_url){
then(function(paths){ then(function(paths){
var packageUri = URI(paths.packagePath); var packageUri = URI(paths.packagePath);
var absPackageUri = packageUri.absoluteTo(book.url); var absPackageUri = packageUri.absoluteTo(book.url);
var absWindowUri;
book.packageUrl = absPackageUri.toString(); book.packageUrl = absPackageUri.toString();
book.encoding = paths.encoding; book.encoding = paths.encoding;
// Set Url relative to the content // Set Url relative to the content
if(packageUri.origin()) { if(absPackageUri.origin()) {
book.baseUrl = packageUri.origin() + "/" + packageUri.directory() + "/"; book.baseUrl = absPackageUri.origin() + absPackageUri.directory() + "/";
} else if(window && !book.isArchivedUrl(uri)){
book.baseUrl = absPackageUri.absoluteTo(window.location.href).directory() + "/";
} else { } else {
book.baseUrl = "/" + packageUri.directory() + "/"; book.baseUrl = "/" + packageUri.directory() + "/";
} }

View file

@ -69,16 +69,14 @@ Contents.prototype.textHeight = function() {
return height; return height;
}; };
Contents.prototype.scrollWidth = function(min) { Contents.prototype.scrollWidth = function() {
var prev; var width = this.documentElement.scrollWidth;
var width = this.document.body.scrollWidth;
return width; return width;
}; };
Contents.prototype.scrollHeight = function(min) { Contents.prototype.scrollHeight = function() {
var prev; var height = this.documentElement.scrollHeight;
var height = this.document.body.scrollHeight;
return height; return height;
}; };
@ -149,6 +147,10 @@ Contents.prototype.viewport = function() {
// // stub // // stub
// }; // };
Contents.prototype.expand = function() {
//TODO: this should just report resize
};
Contents.prototype.listeners = function() { Contents.prototype.listeners = function() {
this.imageLoadListeners(); this.imageLoadListeners();
@ -197,6 +199,28 @@ Contents.prototype.mediaQueryListeners = function() {
} }
}; };
Contents.prototype.observe = function(target) {
var renderer = this;
// create an observer instance
var observer = new MutationObserver(function(mutations) {
if(renderer._expanding) {
renderer.expand();
}
// mutations.forEach(function(mutation) {
// console.log(mutation);
// });
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true, subtree: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
return observer;
};
Contents.prototype.imageLoadListeners = function(target) { Contents.prototype.imageLoadListeners = function(target) {
var images = this.contentDocument.querySelectorAll("img"); var images = this.contentDocument.querySelectorAll("img");
var img; var img;
@ -403,6 +427,16 @@ Contents.prototype.map = function(layout){
return map.section(); return map.section();
}; };
Contents.prototype.destroy = function() {
// Stop observing
if(this.observer) {
this.observer.disconnect();
}
this.removeListeners();
};
RSVP.EventTarget.mixin(Contents.prototype); RSVP.EventTarget.mixin(Contents.prototype);
module.exports = Contents; module.exports = Contents;

View file

@ -28,6 +28,7 @@ ePub.register = {
// Default Views // Default Views
ePub.register.view("iframe", require('./views/iframe')); ePub.register.view("iframe", require('./views/iframe'));
ePub.register.view("inline", require('./views/inline'));
// Default View Managers // Default View Managers
ePub.register.manager("single", require('./managers/single')); ePub.register.manager("single", require('./managers/single'));

View file

@ -14,6 +14,8 @@ function Reflowable(){
this.column = 0; this.column = 0;
this.gap = 0; this.gap = 0;
this.divisor = 0; this.divisor = 0;
this.name = "reflowable";
}; };
Reflowable.prototype.calculate = function(_width, _height, _gap, _devisor){ Reflowable.prototype.calculate = function(_width, _height, _gap, _devisor){
@ -107,6 +109,9 @@ Reflowable.prototype.count = function(totalWidth) {
function Fixed(_width, _height){ function Fixed(_width, _height){
this.width = 0; this.width = 0;
this.height = 0; this.height = 0;
this.name = "pre-paginated";
}; };
Fixed.prototype.calculate = function(_width, _height){ Fixed.prototype.calculate = function(_width, _height){
@ -166,6 +171,7 @@ function Scroll(){
this.spread = 0; this.spread = 0;
this.column = 0; this.column = 0;
this.gap = 0; this.gap = 0;
this.name = "scrolled";
}; };
Scroll.prototype.calculate = function(_width, _height){ Scroll.prototype.calculate = function(_width, _height){
@ -180,7 +186,7 @@ Scroll.prototype.format = function(contents){
// $doc.style.width = "auto"; // $doc.style.width = "auto";
// $doc.style.height = "auto"; // $doc.style.height = "auto";
contents.width("auto"); // contents.width("auto");
contents.height("auto"); contents.height("auto");
}; };

View file

@ -39,7 +39,7 @@ ContinuousViewManager.prototype.moveTo = function(offset){
}.bind(this)); }.bind(this));
}; };
/*
ContinuousViewManager.prototype.afterDisplayed = function(currView){ ContinuousViewManager.prototype.afterDisplayed = function(currView){
var next = currView.section.next(); var next = currView.section.next();
var prev = currView.section.prev(); var prev = currView.section.prev();
@ -61,7 +61,10 @@ ContinuousViewManager.prototype.afterDisplayed = function(currView){
this.trigger("added", currView.section); this.trigger("added", currView.section);
}; };
*/
ContinuousViewManager.prototype.afterResized = function(view){
this.trigger("resize", view.section);
};
// Remove Previous Listeners if present // Remove Previous Listeners if present
ContinuousViewManager.prototype.removeShownListeners = function(view){ ContinuousViewManager.prototype.removeShownListeners = function(view){
@ -72,27 +75,31 @@ ContinuousViewManager.prototype.removeShownListeners = function(view){
}; };
ContinuousViewManager.prototype.append = function(view){ ContinuousViewManager.prototype.append = function(section){
var view = this.createView(section);
// view.on("shown", this.afterDisplayed.bind(this)); return this.q.enqueue(function() {
view.onDisplayed = this.afterDisplayed.bind(this);
this.views.append(view); this.views.append(view);
//this.q.enqueue(this.check); return this.update();
return this.check();
}.bind(this));
}; };
ContinuousViewManager.prototype.prepend = function(view){ ContinuousViewManager.prototype.prepend = function(section){
// view.on("shown", this.afterDisplayedAbove.bind(this)); var view = this.createView(section);
view.onDisplayed = this.afterDisplayed.bind(this);
view.on("resized", this.counter.bind(this)); view.on("resized", this.counter.bind(this));
this.views.prepend(view); return this.q.enqueue(function() {
this.views.prepend(view);
return this.update();
}.bind(this));
// this.q.enqueue(this.check);
return this.check();
}; };
ContinuousViewManager.prototype.counter = function(bounds){ ContinuousViewManager.prototype.counter = function(bounds){
@ -104,7 +111,7 @@ ContinuousViewManager.prototype.counter = function(bounds){
} }
}; };
/*
ContinuousViewManager.prototype.check = function(_offset){ ContinuousViewManager.prototype.check = function(_offset){
var checking = new RSVP.defer(); var checking = new RSVP.defer();
var container = this.stage.bounds(); var container = this.stage.bounds();
@ -154,6 +161,98 @@ ContinuousViewManager.prototype.check = function(_offset){
return checking.promise; return checking.promise;
} }
};
*/
ContinuousViewManager.prototype.update = function(_offset){
var container = this.stage.bounds();
var views = this.views;
var viewsLength = views.length;
var visible = [];
var isVisible;
var view;
var updating = new RSVP.defer();
var promises = [];
for (var i = 0; i < viewsLength; i++) {
view = views[i];
isVisible = this.isVisible(view, 0, 0, container);
if(isVisible === true) {
promises.push(view.display());
visible.push(view);
} else {
this.q.enqueue(view.destroy.bind(view));
clearTimeout(this.trimTimeout);
this.trimTimeout = setTimeout(function(){
this.q.enqueue(this.trim.bind(this));
}.bind(this), 250);
}
}
if(promises.length){
return RSVP.all(promises);
} else {
updating.resolve();
return updating.promise;
}
};
ContinuousViewManager.prototype.check = function(_offsetLeft, _offsetTop){
var next, prev;
var horizontal = (this.settings.axis === "horizontal");
var delta = this.settings.offset || 0;
if (_offsetLeft && horizontal) {
delta = _offsetLeft;
}
if (_offsetTop && !horizontal) {
delta = _offsetTop;
}
var bounds = this.stage.bounds(); // TODO: save this until resize
var offset = horizontal ? this.container.scrollLeft : this.container.scrollTop;
var visibleLength = horizontal ? bounds.width : bounds.height;
var contentLength = horizontal ? this.container.scrollWidth : this.container.scrollHeight;
var checking = new RSVP.defer();
var promises = [];
if (offset + visibleLength + delta >= contentLength) {
next = this.views.last().section.next();
if(next) {
promises.push(this.append(next));
}
}
if (offset - delta < 0 ) {
prev = this.views.first().section.prev();
if(prev) {
promises.push(this.prepend(prev));
}
}
if(promises.length){
return RSVP.all(promises)
.then(function(posts) {
// Check to see if anything new is on screen after rendering
this.q.enqueue(this.update.bind(this));
}.bind(this));
} else {
checking.resolve();
return checking.promise;
}
}; };
ContinuousViewManager.prototype.trim = function(){ ContinuousViewManager.prototype.trim = function(){
@ -309,15 +408,15 @@ ContinuousViewManager.prototype.onScroll = function(){
}; };
ContinuousViewManager.prototype.resizeView = function(view) { // ContinuousViewManager.prototype.resizeView = function(view) {
//
if(this.settings.axis === "horizontal") { // if(this.settings.axis === "horizontal") {
view.lock("height", this.stage.width, this.stage.height); // view.lock("height", this.stage.width, this.stage.height);
} else { // } else {
view.lock("width", this.stage.width, this.stage.height); // view.lock("width", this.stage.width, this.stage.height);
} // }
//
}; // };
ContinuousViewManager.prototype.currentLocation = function(){ ContinuousViewManager.prototype.currentLocation = function(){
var visible = this.visible(); var visible = this.visible();

View file

@ -2,7 +2,7 @@ var RSVP = require('rsvp');
var core = require('../core'); var core = require('../core');
var ContinuousViewManager = require('./continuous'); var ContinuousViewManager = require('./continuous');
var Map = require('../map'); var Map = require('../map');
// var Layout = require('./layout'); var Layout = require('../layout');
function PaginatedViewManager(book, options) { function PaginatedViewManager(book, options) {
@ -84,7 +84,7 @@ PaginatedViewManager.prototype.applyLayoutMethod = function() {
// Set the look ahead offset for what is visible // Set the look ahead offset for what is visible
this.map = new Map(this.layout); // this.map = new Map(this.layout);
// this.hooks.layout.register(this.layout.format.bind(this)); // this.hooks.layout.register(this.layout.format.bind(this));

View file

@ -1,7 +1,9 @@
var RSVP = require('rsvp'); var RSVP = require('rsvp');
var core = require('../core'); var core = require('../core');
var Stage = require('../stage');
var Views = require('../views'); var Views = require('../views');
var EpubCFI = require('../epubcfi'); var EpubCFI = require('../epubcfi');
var Layout = require('../layout');
function SingleViewManager(options) { function SingleViewManager(options) {
@ -15,23 +17,35 @@ function SingleViewManager(options) {
width: false, width: false,
height: null, height: null,
globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'}, globalLayoutProperties : { layout: 'reflowable', spread: 'auto', orientation: 'auto'},
layout: null, // layout: null,
axis: "vertical", axis: "vertical",
ignoreClass: '' ignoreClass: ''
}); });
core.extend(this.settings, options.settings); core.extend(this.settings, options.settings);
this.viewSettings = { this.viewSettings = {
ignoreClass: this.settings.ignoreClass ignoreClass: this.settings.ignoreClass,
globalLayoutProperties: this.settings.globalLayoutProperties,
axis: this.settings.axis,
layout: this.layout,
width: 0,
height: 0
}; };
} }
SingleViewManager.prototype.start = function(stage){ SingleViewManager.prototype.render = function(element, size){
// Save the stage // Save the stage
this.stage = stage; this.stage = new Stage({
width: size.width,
height: size.height,
hidden: this.settings.hidden
});
this.stage.attachTo(element);
// Get this stage container div // Get this stage container div
this.container = this.stage.getContainer(); this.container = this.stage.getContainer();
@ -42,6 +56,10 @@ SingleViewManager.prototype.start = function(stage){
// Calculate Stage Size // Calculate Stage Size
this.bounds = this.stage.bounds(); this.bounds = this.stage.bounds();
// Set the dimensions for views
this.viewSettings.width = this.bounds.width;
this.viewSettings.height = this.bounds.height;
// Function to handle a resize event. // Function to handle a resize event.
// Will only attach if width and height are both fixed. // Will only attach if width and height are both fixed.
this.stage.onResize(this.onResized.bind(this)); this.stage.onResize(this.onResized.bind(this));
@ -50,7 +68,7 @@ SingleViewManager.prototype.start = function(stage){
this.addEventListeners(); this.addEventListeners();
// Add Layout method // Add Layout method
// this.applyLayoutMethod(); this.applyLayoutMethod();
}; };
SingleViewManager.prototype.addEventListeners = function(){ SingleViewManager.prototype.addEventListeners = function(){
@ -65,7 +83,14 @@ SingleViewManager.prototype.resize = function(width, height){
this.bounds = this.stage.bounds(width, height); this.bounds = this.stage.bounds(width, height);
this.views.each(this.resizeView.bind(this)); // Update for new views
this.viewSettings.width = this.bounds.width;
this.viewSettings.height = this.bounds.height;
// Update for existing views
this.views.each(function(view) {
view.size(this.bounds.width, this.bounds.height);
}.bind(this));
this.trigger("resized", { this.trigger("resized", {
width: this.stage.width, width: this.stage.width,
@ -74,10 +99,12 @@ SingleViewManager.prototype.resize = function(width, height){
}; };
SingleViewManager.prototype.layout = function(layoutFunc){ SingleViewManager.prototype.setLayout = function(layout){
this.viewSettings.layout = layout;
this.views.each(function(view){ this.views.each(function(view){
layoutFunc(view); view.setLayout(layout);
}); });
}; };
@ -106,10 +133,12 @@ SingleViewManager.prototype.display = function(section, target){
// Hide all current views // Hide all current views
this.views.hide(); this.views.hide();
this.views.clear();
// Create a new view // Create a new view
view = this.createView(section); view = this.createView(section);
return this.fill(view) return this.add(view)
.then(function(){ .then(function(){
// Move to correct place within the section, if needed // Move to correct place within the section, if needed
@ -129,34 +158,38 @@ SingleViewManager.prototype.display = function(section, target){
}; };
SingleViewManager.prototype.afterDisplayed = function(view){ SingleViewManager.prototype.afterDisplayed = function(view){
this.trigger("added", view.section); this.trigger("added", view);
};
SingleViewManager.prototype.afterResized = function(view){
this.trigger("resize", view.section);
}; };
SingleViewManager.prototype.moveTo = function(offset){ SingleViewManager.prototype.moveTo = function(offset){
this.scrollTo(offset.left, offset.top); this.scrollTo(offset.left, offset.top);
}; };
SingleViewManager.prototype.fill = function(view){ SingleViewManager.prototype.add = function(view){
this.views.clear();
this.views.append(view); this.views.append(view);
// view.on("shown", this.afterDisplayed.bind(this)); // view.on("shown", this.afterDisplayed.bind(this));
view.onDisplayed = this.afterDisplayed.bind(this); view.onDisplayed = this.afterDisplayed.bind(this);
view.onResize = this.afterResized.bind(this);
return this.renderer(view, this.views.hidden); return view.display();
// return this.renderer(view, this.views.hidden);
}; };
SingleViewManager.prototype.resizeView = function(view) { // SingleViewManager.prototype.resizeView = function(view) {
//
if(this.settings.globalLayoutProperties.layout === "pre-paginated") { // if(this.settings.globalLayoutProperties.layout === "pre-paginated") {
view.lock("both", this.bounds.width, this.bounds.height); // view.lock("both", this.bounds.width, this.bounds.height);
} else { // } else {
view.lock("width", this.bounds.width, this.bounds.height); // view.lock("width", this.bounds.width, this.bounds.height);
} // }
//
}; // };
SingleViewManager.prototype.next = function(){ SingleViewManager.prototype.next = function(){
var next; var next;
@ -167,8 +200,10 @@ SingleViewManager.prototype.next = function(){
next = this.views.last().section.next(); next = this.views.last().section.next();
if(next) { if(next) {
this.views.clear();
view = this.createView(next); view = this.createView(next);
return this.fill(view) return this.add(view)
.then(function(){ .then(function(){
this.views.show(); this.views.show();
}.bind(this)); }.bind(this));
@ -183,8 +218,10 @@ SingleViewManager.prototype.prev = function(){
prev = this.views.first().section.prev(); prev = this.views.first().section.prev();
if(prev) { if(prev) {
this.views.clear();
view = this.createView(prev); view = this.createView(prev);
return this.fill(view) return this.add(view)
.then(function(){ .then(function(){
this.views.show(); this.views.show();
}.bind(this)); }.bind(this));
@ -236,14 +273,17 @@ SingleViewManager.prototype.isVisible = function(view, offsetPrev, offsetNext, _
}; };
SingleViewManager.prototype.visible = function(){ SingleViewManager.prototype.visible = function(){
return this.views.displayed();
/*
var container = this.stage.bounds(); var container = this.stage.bounds();
var displayedViews = this.views.displayed(); var views = this.views;
var viewsLength = views.length;
var visible = []; var visible = [];
var isVisible; var isVisible;
var view; var view;
for (var i = 0; i < displayedViews.length; i++) { for (var i = 0; i < viewsLength; i++) {
view = displayedViews[i]; view = views[i];
isVisible = this.isVisible(view, 0, 0, container); isVisible = this.isVisible(view, 0, 0, container);
if(isVisible === true) { if(isVisible === true) {
@ -252,7 +292,7 @@ SingleViewManager.prototype.visible = function(){
} }
return visible; return visible;
*/
}; };
SingleViewManager.prototype.scrollBy = function(x, y, silent){ SingleViewManager.prototype.scrollBy = function(x, y, silent){
@ -293,6 +333,40 @@ SingleViewManager.prototype.scrollTo = function(x, y, silent){
// }; // };
}; };
SingleViewManager.prototype.bounds = function() {
var bounds;
if(!this.settings.height || !this.container) {
bounds = core.windowBounds();
} else {
bounds = this.container.getBoundingClientRect();
}
return bounds;
};
SingleViewManager.prototype.applyLayoutMethod = function() {
this.layout = new Layout.Scroll();
this.calculateLayout();
this.setLayout(this.layout);
// this.map = new Map(this.layout);
// this.manager.layout(this.layout.format);
};
SingleViewManager.prototype.calculateLayout = function() {
var bounds = this.stage.bounds();
this.layout.calculate(bounds.width, bounds.height);
};
SingleViewManager.prototype.updateLayout = function() {
this.calculateLayout();
this.setLayout(this.layout);
};
//-- Enable binding events to Manager //-- Enable binding events to Manager
RSVP.EventTarget.mixin(SingleViewManager.prototype); RSVP.EventTarget.mixin(SingleViewManager.prototype);

View file

@ -154,9 +154,11 @@ Parser.prototype.metadata = function(xml){
metadata.rights = p.getElementText(xml, "rights"); metadata.rights = p.getElementText(xml, "rights");
metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified'); metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified');
metadata.layout = p.getPropertyText(xml, "rendition:layout"); metadata.layout = p.getPropertyText(xml, "rendition:layout");
metadata.orientation = p.getPropertyText(xml, 'rendition:orientation'); metadata.orientation = p.getPropertyText(xml, 'rendition:orientation');
metadata.spread = p.getPropertyText(xml, 'rendition:spread'); metadata.flow = p.getPropertyText(xml, 'rendition:flow');
metadata.viewport = p.getPropertyText(xml, 'rendition:viewport');
// metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction"); // metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
return metadata; return metadata;

View file

@ -9,16 +9,15 @@ var View = require('./view');
var Views = require('./views'); var Views = require('./views');
var Layout = require('./layout'); var Layout = require('./layout');
var Map = require('./map'); var Map = require('./map');
var Stage = require('./stage');
function Rendition(book, options) { function Rendition(book, options) {
this.settings = core.extend(this.settings || {}, { this.settings = core.extend(this.settings || {}, {
infinite: true, infinite: true,
hidden: false, hidden: false,
width: false, width: null,
height: null, height: null,
layoutOveride : null, // Default: { spread: 'reflowable', layout: 'auto', orientation: 'auto'}, layoutOveride : null, // Default: { spread: 'reflowable', layout: 'auto', orientation: 'auto', flow: 'auto', viewport: ''},
axis: "vertical", axis: "vertical",
ignoreClass: '', ignoreClass: '',
manager: "single", manager: "single",
@ -67,6 +66,15 @@ function Rendition(book, options) {
this.replacements(); this.replacements();
} }
this.ViewManager = this.requireManager(this.settings.manager);
this.View = this.requireView(this.settings.view);
this.manager = new this.ViewManager({
view: this.View,
queue: this.q,
settings: this.settings
});
}; };
Rendition.prototype.setManager = function(manager) { Rendition.prototype.setManager = function(manager) {
@ -104,30 +112,13 @@ Rendition.prototype.requireView = function(view) {
return View; return View;
}; };
Rendition.prototype.start = function(stage){ Rendition.prototype.start = function(){
var ViewManager, View;
// Add view manager
if (!this.manager) {
ViewManager = this.requireManager(this.settings.manager);
View = this.requireView(this.settings.view);
this.manager = new ViewManager({
view: View,
renderer: this.render.bind(this),
queue: this.q,
settings: this.settings
});
}
// Listen for displayed views // Listen for displayed views
this.manager.on("added", this.afterDisplayed.bind(this)) this.manager.on("added", this.afterDisplayed.bind(this))
// Start rendering
this.manager.start(stage);
// Add Layout method // Add Layout method
this.applyLayoutMethod(); // this.applyLayoutMethod();
this.on('displayed', this.reportLocation.bind(this)); this.on('displayed', this.reportLocation.bind(this));
@ -142,12 +133,13 @@ Rendition.prototype.start = function(stage){
// Container must be attached before rendering can begin // Container must be attached before rendering can begin
Rendition.prototype.attachTo = function(element){ Rendition.prototype.attachTo = function(element){
this.container = new Stage(element, { // Start rendering
this.manager.render(element, {
"width" : this.settings.width, "width" : this.settings.width,
"height" : this.settings.height "height" : this.settings.height
}); });
this.start(this.container); this.start();
// Trigger Attached // Trigger Attached
this.trigger("attached"); this.trigger("attached");
@ -197,6 +189,7 @@ Rendition.prototype._display = function(target){
}; };
/*
Rendition.prototype.render = function(view, show) { Rendition.prototype.render = function(view, show) {
// view.onLayout = this.layout.format.bind(this.layout); // view.onLayout = this.layout.format.bind(this.layout);
@ -239,36 +232,17 @@ Rendition.prototype.render = function(view, show) {
}.bind(this)); }.bind(this));
}; };
*/
Rendition.prototype.afterDisplayed = function(section){ Rendition.prototype.afterDisplayed = function(view){
this.trigger("added", section); this.hooks.content.trigger(view, this);
this.trigger("rendered", view.section);
this.reportLocation(); this.reportLocation();
}; };
Rendition.prototype.applyLayoutMethod = function() {
this.layout = new Layout.Scroll();
this.calculateLayout();
// this.map = new Map(this.layout);
// this.manager.layout(this.layout.format);
};
Rendition.prototype.calculateLayout = function() {
// TODO: should this be a function to get the live bounds? It is cached and updated on resize for now.
var bounds = this.manager.bounds;
this.layout.calculate(bounds.width, bounds.height);
};
Rendition.prototype.updateLayout = function() {
this.calculateLayout();
this.manager.layout(this.layout.format);
};
Rendition.prototype.onResized = function(size){ Rendition.prototype.onResized = function(size){
this.updateLayout(); this.manager.updateLayout();
if(this.location) { if(this.location) {
this.display(this.location.start); this.display(this.location.start);
@ -293,29 +267,21 @@ Rendition.prototype.prev = function(){
return this.q.enqueue(this.manager.prev.bind(this.manager)); return this.q.enqueue(this.manager.prev.bind(this.manager));
}; };
Rendition.prototype.bounds = function() {
var bounds;
if(!this.settings.height || !this.container) {
bounds = core.windowBounds();
} else {
bounds = this.container.getBoundingClientRect();
}
return bounds;
};
//-- http://www.idpf.org/epub/fxl/ //-- http://www.idpf.org/epub/fxl/
Rendition.prototype.parseLayoutProperties = function(_metadata){ Rendition.prototype.parseLayoutProperties = function(_metadata){
var metadata = _metadata || this.book.package.metadata; var metadata = _metadata || this.book.package.metadata;
var layout = (this.layoutOveride && this.layoutOveride.layout) || metadata.layout || "reflowable"; var layout = (this.layoutOveride && this.layoutOveride.layout) || metadata.layout || "reflowable";
var spread = (this.layoutOveride && this.layoutOveride.spread) || metadata.spread || "auto"; var spread = (this.layoutOveride && this.layoutOveride.spread) || metadata.spread || "auto";
var orientation = (this.layoutOveride && this.layoutOveride.orientation) || metadata.orientation || "auto"; var orientation = (this.layoutOveride && this.layoutOveride.orientation) || metadata.orientation || "auto";
var flow = (this.layoutOveride && this.layoutOveride.flow) || metadata.flow || "auto";
var viewport = (this.layoutOveride && this.layoutOveride.viewport) || metadata.viewport || "";
this.settings.globalLayoutProperties = { this.settings.globalLayoutProperties = {
layout : layout, layout : layout,
spread : spread, spread : spread,
orientation : orientation orientation : orientation,
flow : flow,
viewport : viewport
}; };
return this.settings.globalLayoutProperties; return this.settings.globalLayoutProperties;
@ -323,33 +289,23 @@ Rendition.prototype.parseLayoutProperties = function(_metadata){
/** /**
* Uses the settings to determine which Layout Method is needed * Uses the settings to determine which Layout Method is needed
* Triggers events based on the method choosen
* Takes: Layout settings object
* Returns: String of appropriate for EPUBJS.Layout function
*/ */
// Paginate.prototype.determineLayout = function(settings){ // Rendition.prototype.determineLayout = function(settings){
// // Default is layout: reflowable & spread: auto // // Default is layout: reflowable & spread: auto
// var spreads = this.determineSpreads(this.settings.minSpreadWidth); // var spreads = this.determineSpreads(this.settings.minSpreadWidth);
// console.log("spreads", spreads, this.settings.minSpreadWidth)
// var layoutMethod = spreads ? "ReflowableSpreads" : "Reflowable"; // var layoutMethod = spreads ? "ReflowableSpreads" : "Reflowable";
// var scroll = false; // var scroll = false;
// //
// if(settings.layout === "pre-paginated") { // if(settings.layout === "pre-paginated") {
// layoutMethod = "Fixed"; //
// scroll = true;
// spreads = false;
// } // }
// //
// if(settings.layout === "reflowable" && settings.spread === "none") { // if(settings.layout === "reflowable" && settings.spread === "none") {
// layoutMethod = "Reflowable"; //
// scroll = false;
// spreads = false;
// } // }
// //
// if(settings.layout === "reflowable" && settings.spread === "both") { // if(settings.layout === "reflowable" && settings.spread === "both") {
// layoutMethod = "ReflowableSpreads"; //
// scroll = false;
// spreads = true;
// } // }
// //
// this.spreads = spreads; // this.spreads = spreads;

View file

@ -16,11 +16,10 @@ function base(doc, section){
if(!base) { if(!base) {
base = doc.createElement("base"); base = doc.createElement("base");
head.insertBefore(base, head.firstChild);
} }
base.setAttribute("href", section.url); base.setAttribute("href", section.url);
head.insertBefore(base, head.firstChild);
} }
function links(view, renderer) { function links(view, renderer) {

View file

@ -60,8 +60,9 @@ Section.prototype.base = function(_document){
var task = new RSVP.defer(); var task = new RSVP.defer();
var base = _document.createElement("base"); // TODO: check if exists var base = _document.createElement("base"); // TODO: check if exists
var head; var head;
console.log(window.location.origin + "/" +this.url);
base.setAttribute("href", this.url); base.setAttribute("href", window.location.origin + "/" +this.url);
if(_document) { if(_document) {
head = _document.querySelector("head"); head = _document.querySelector("head");

View file

@ -1,16 +1,12 @@
var core = require('./core'); var core = require('./core');
function Stage(element, _options) { function Stage(_options) {
this.settings = _options || {}; this.settings = _options || {};
this.element = this.getElement(element);
this.container = this.create(this.settings); this.container = this.create(this.settings);
if(this.settings.hidden) { if(this.settings.hidden) {
this.wrapper = this.wrap(this.container); this.wrapper = this.wrap(this.container);
this.attachTo(this.wrapper, this.element);
} else {
this.attachTo(this.container, this.element);
} }
} }
@ -39,7 +35,7 @@ Stage.prototype.create = function(options){
container.classList.add("epub-container"); container.classList.add("epub-container");
// Style Element // Style Element
container.style.fontSize = "0"; // container.style.fontSize = "0";
container.style.wordSpacing = "0"; container.style.wordSpacing = "0";
container.style.lineHeight = "0"; container.style.lineHeight = "0";
container.style.verticalAlign = "top"; container.style.verticalAlign = "top";
@ -93,13 +89,24 @@ Stage.prototype.getElement = function(_element){
return element; return element;
}; };
Stage.prototype.attachTo = function(what, element){ Stage.prototype.attachTo = function(what){
var element = this.getElement(what);
var base;
if(!element){ if(!element){
return; return;
} }
element.appendChild(what); if(this.settings.hidden) {
base = this.wrapper;
} else {
base = this.container;
}
element.appendChild(base);
this.element = element;
return element; return element;
@ -125,7 +132,7 @@ Stage.prototype.bounds = function(_width, _height){
var height = _height || this.settings.height; var height = _height || this.settings.height;
// If width or height are set to false, inherit them from containing element // If width or height are set to false, inherit them from containing element
if(width === false) { if(width === null) {
bounds = this.element.getBoundingClientRect(); bounds = this.element.getBoundingClientRect();
if(bounds.width) { if(bounds.width) {
@ -134,7 +141,7 @@ Stage.prototype.bounds = function(_width, _height){
} }
} }
if(height === false) { if(height === null) {
bounds = bounds || this.element.getBoundingClientRect(); bounds = bounds || this.element.getBoundingClientRect();
if(bounds.height) { if(bounds.height) {

View file

@ -13,10 +13,6 @@ Views.prototype.last = function() {
return this._views[this._views.length-1]; return this._views[this._views.length-1];
}; };
Views.prototype.each = function() {
return this._views.forEach.apply(this._views, arguments);
};
Views.prototype.indexOf = function(view) { Views.prototype.indexOf = function(view) {
return this._views.indexOf(view); return this._views.indexOf(view);
}; };
@ -89,6 +85,10 @@ Views.prototype.destroy = function(view) {
// Iterators // Iterators
Views.prototype.each = function() {
return this._views.forEach.apply(this._views, arguments);
};
Views.prototype.clear = function(){ Views.prototype.clear = function(){
// Remove all views // Remove all views
var view; var view;

View file

@ -5,42 +5,50 @@ var Contents = require('../contents');
function IframeView(section, options) { function IframeView(section, options) {
this.settings = core.extend({ this.settings = core.extend({
ignoreClass : '' ignoreClass : '',
axis: 'vertical',
width: 0,
height: 0,
layout: undefined,
globalLayoutProperties: {},
}, options || {}); }, options || {});
this.id = "epubjs-view:" + core.uuid(); this.id = "epubjs-view:" + core.uuid();
this.section = section; this.section = section;
this.index = section.index; this.index = section.index;
this.element = this.createContainer(); this.element = this.container(this.settings.axis);
this.added = false; this.added = false;
this.displayed = false; this.displayed = false;
this.rendered = false; this.rendered = false;
//this.width = 0; this.width = this.settings.width;
//this.height = 0; this.height = this.settings.height;
this.fixedWidth = 0;
this.fixedHeight = 0;
// Blank Cfi for Parsing // Blank Cfi for Parsing
this.epubcfi = new EpubCFI(); this.epubcfi = new EpubCFI();
this.layout = this.settings.layout;
// Dom events to listen for // Dom events to listen for
// this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"]; // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
}; };
IframeView.prototype.createContainer = function() { IframeView.prototype.container = function(axis) {
var element = document.createElement('div'); var element = document.createElement('div');
element.classList.add("epub-view"); element.classList.add("epub-view");
// this.element.style.minHeight = "100px"; // this.element.style.minHeight = "100px";
element.style.height = "0px"; element.style.height = "0px";
element.style.width = "0px"; element.style.width = "0px";
element.style.overflow = "hidden"; element.style.overflow = "hidden";
if(this.settings.axis && this.settings.axis == "horizontal"){ if(axis && axis == "horizontal"){
element.style.display = "inline-block"; element.style.display = "inline-block";
} else { } else {
element.style.display = "block"; element.style.display = "block";
@ -92,20 +100,87 @@ IframeView.prototype.create = function() {
// } // }
// Firefox has trouble with baseURI and srcdoc // Firefox has trouble with baseURI and srcdoc
// Disabled for now // TODO: Disable for now in firefox
/*
if(!!("srcdoc" in this.iframe)) { if(!!("srcdoc" in this.iframe)) {
this.supportsSrcdoc = true; this.supportsSrcdoc = true;
} else { } else {
this.supportsSrcdoc = false; this.supportsSrcdoc = false;
} }
*/
this.supportsSrcdoc = false;
return this.iframe; return this.iframe;
}; };
IframeView.prototype.render = function(request, show) {
// view.onLayout = this.layout.format.bind(this.layout);
this.create();
// Fit to size of the container, apply padding
this.size();
// Render Chain
return this.section.render(request)
.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
this.settings.layout.format(this.contents);
// Expand the iframe to the full size of the content
this.expand();
// Listen for events that require an expansion of the iframe
this.addListeners();
if(show !== false) {
//this.q.enqueue(function(view){
this.show();
//}, view);
}
// this.map = new Map(view, this.layout);
//this.hooks.show.trigger(view, this);
this.trigger("rendered", this.section);
}.bind(this))
.catch(function(e){
this.trigger("loaderror", e);
}.bind(this));
};
// Determine locks base on settings
IframeView.prototype.size = function(_width, _height) {
var width = _width || this.settings.width;
var height = _height || this.settings.height;
if(this.layout.name === "pre-paginated") {
// TODO: check if these are different than the size set in chapter
this.lock("both", width, height);
} else if(this.settings.axis === "horizontal") {
this.lock("height", width, height);
} else {
this.lock("width", width, height);
}
};
// Lock an axis to element dimensions, taking borders into account
IframeView.prototype.lock = function(what, width, height) { IframeView.prototype.lock = function(what, width, height) {
var elBorders = core.borders(this.element); var elBorders = core.borders(this.element);
var iframeBorders; var iframeBorders;
@ -147,18 +222,20 @@ IframeView.prototype.lock = function(what, width, height) {
}; };
// Resize a single axis based on content dimensions
IframeView.prototype.expand = function(force) { IframeView.prototype.expand = function(force) {
var width = this.lockedWidth; var width = this.lockedWidth;
var height = this.lockedHeight; var height = this.lockedHeight;
var textWidth, textHeight; var textWidth, textHeight;
// console.log("expanding a")
if(!this.iframe || this._expanding) return; if(!this.iframe || this._expanding) return;
this._expanding = true; this._expanding = true;
// Expand Horizontally // Expand Horizontally
if(height && !width) { // if(height && !width) {
if(this.settings.axis === "horizontal") {
// Get the width of the text // Get the width of the text
textWidth = this.contents.textWidth(); textWidth = this.contents.textWidth();
// Check if the textWidth has changed // Check if the textWidth has changed
@ -174,10 +251,8 @@ IframeView.prototype.expand = function(force) {
// Otherwise assume content height hasn't changed // Otherwise assume content height hasn't changed
width = this._contentWidth; width = this._contentWidth;
} }
} } // Expand Vertically
else if(this.settings.axis === "vertical") {
// Expand Vertically
if(width && !height) {
textHeight = this.contents.textHeight(); textHeight = this.contents.textHeight();
if(textHeight != this._textHeight){ if(textHeight != this._textHeight){
height = this.contentHeight(textHeight); height = this.contentHeight(textHeight);
@ -248,12 +323,12 @@ IframeView.prototype.resize = function(width, height) {
}; };
IframeView.prototype.reframe = function(width, height) { IframeView.prototype.reframe = function(width, height) {
//var prevBounds; var size;
if(!this.displayed) { // if(!this.displayed) {
this._needsReframe = true; // this._needsReframe = true;
return; // return;
} // }
if(core.isNumber(width)){ if(core.isNumber(width)){
this.element.style.width = width + "px"; this.element.style.width = width + "px";
@ -267,43 +342,19 @@ IframeView.prototype.reframe = function(width, height) {
this.elementBounds = core.bounds(this.element); this.elementBounds = core.bounds(this.element);
this.trigger("resized", { size = {
width: this.elementBounds.width, width: this.elementBounds.width,
height: this.elementBounds.height, height: this.elementBounds.height,
widthDelta: this.elementBounds.width - this.prevBounds.width, widthDelta: this.elementBounds.width - this.prevBounds.width,
heightDelta: this.elementBounds.height - this.prevBounds.height, heightDelta: this.elementBounds.height - this.prevBounds.height,
}); };
this.onResize(this, size);
this.trigger("resized", size);
}; };
// View.prototype.resized = function(e) {
// /*
// if (!this.resizing) {
// if(this.iframe) {
// // this.expand();
// }
// } else {
// this.resizing = false;
// }*/
//
// };
/*
View.prototype.render = function(_request) {
// if(this.rendering){
// return this.displayed;
// }
this.rendering = true;
// this.displayingDefer = new RSVP.defer();
// this.displayedPromise = this.displaying.promise;
return this.section.render(_request)
.then(function(contents){
return this.load(contents);
}.bind(this));
};
*/
IframeView.prototype.load = function(contents) { IframeView.prototype.load = function(contents) {
var loading = new RSVP.defer(); var loading = new RSVP.defer();
@ -375,50 +426,10 @@ IframeView.prototype.onLoad = function(event, promise) {
// // stub // // stub
// }; // };
IframeView.prototype.setLayout = function(layoutFunc) { IframeView.prototype.setLayout = function(layout) {
this.layoutFunc = layoutFunc; this.layout = layout;
}; };
IframeView.prototype.listeners = function() {
/*
setTimeout(function(){
this.window.addEventListener("resize", this.resized.bind(this), false);
}.bind(this), 10); // Wait to listen for resize events
*/
// Wait for fonts to load to finish
// http://dev.w3.org/csswg/css-font-loading/
// Not implemented fully except in chrome
if(this.document.fonts && this.document.fonts.status === "loading") {
// console.log("fonts unloaded");
this.document.fonts.onloadingdone = function(){
// console.log("loaded fonts");
this.expand();
}.bind(this);
}
if(this.section.properties.indexOf("scripted") > -1){
this.observer = this.observe(this.document.body);
}
this.imageLoadListeners();
this.mediaQueryListeners();
// this.resizeListenters();
// this.addEventListeners();
// this.addSelectionListeners();
};
IframeView.prototype.removeListeners = function() {
// this.removeEventListeners();
// this.removeSelectionListeners();
};
IframeView.prototype.resizeListenters = function() { IframeView.prototype.resizeListenters = function() {
// Test size again // Test size again
@ -426,93 +437,34 @@ IframeView.prototype.resizeListenters = function() {
this.expanding = setTimeout(this.expand.bind(this), 350); this.expanding = setTimeout(this.expand.bind(this), 350);
}; };
//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js IframeView.prototype.addListeners = function() {
IframeView.prototype.mediaQueryListeners = function() { //TODO: Add content listeners for expanding
var sheets = this.document.styleSheets;
var mediaChangeHandler = function(m){
if(m.matches && !this._expanding) {
setTimeout(this.expand.bind(this), 1);
// this.expand();
}
}.bind(this);
for (var i = 0; i < sheets.length; i += 1) {
var rules = sheets[i].cssRules;
if(!rules) return; // Stylesheets changed
for (var j = 0; j < rules.length; j += 1) {
//if (rules[j].constructor === CSSMediaRule) {
if(rules[j].media){
var mql = this.window.matchMedia(rules[j].media.mediaText);
mql.addListener(mediaChangeHandler);
//mql.onchange = mediaChangeHandler;
}
}
}
}; };
IframeView.prototype.observe = function(target) { IframeView.prototype.removeListeners = function(layoutFunc) {
var renderer = this; //TODO: remove content listeners for expanding
// create an observer instance
var observer = new MutationObserver(function(mutations) {
if(renderer._expanding) {
renderer.expand();
}
// mutations.forEach(function(mutation) {
// console.log(mutation);
// });
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true, subtree: true };
// pass in the target node, as well as the observer options
observer.observe(target, config);
return observer;
}; };
// View.prototype.appendTo = function(element) { IframeView.prototype.display = function(request) {
// this.element = element;
// this.element.appendChild(this.iframe);
// };
//
// View.prototype.prependTo = function(element) {
// this.element = element;
// element.insertBefore(this.iframe, element.firstChild);
// };
IframeView.prototype.imageLoadListeners = function(target) {
var images = this.document.body.querySelectorAll("img");
var img;
for (var i = 0; i < images.length; i++) {
img = images[i];
if (typeof img.naturalWidth !== "undefined" &&
img.naturalWidth === 0) {
img.onload = this.expand.bind(this);
}
}
};
IframeView.prototype.display = function() {
var displayed = new RSVP.defer(); var displayed = new RSVP.defer();
this.displayed = true; if (!this.displayed) {
// apply the layout function to the contents this.render(request).then(function () {
// this.layout(layoutFunc);
// Expand the iframe to the full size of the content this.trigger("displayed", this);
this.expand(); this.onDisplayed(this);
// Listen for event that require an expansion of the iframe this.displayed = true;
this.listeners();
this.trigger("displayed", this); displayed.resolve(this);
this.onDisplayed(this);
}.bind(this));
} else {
displayed.resolve(this);
}
displayed.resolve(this);
return displayed.promise; return displayed.promise;
}; };
@ -555,6 +507,10 @@ IframeView.prototype.onDisplayed = function(view) {
// Stub, override with a custom functions // Stub, override with a custom functions
}; };
IframeView.prototype.onResize = function(view, e) {
// Stub, override with a custom functions
};
IframeView.prototype.bounds = function() { IframeView.prototype.bounds = function() {
if(!this.elementBounds) { if(!this.elementBounds) {
this.elementBounds = core.bounds(this.element); this.elementBounds = core.bounds(this.element);
@ -563,12 +519,10 @@ IframeView.prototype.bounds = function() {
}; };
IframeView.prototype.destroy = function() { IframeView.prototype.destroy = function() {
// Stop observing
if(this.observer) {
this.observer.disconnect();
}
if(this.displayed){ if(this.displayed){
this.displayed = false;
this.removeListeners(); this.removeListeners();
this.stopExpanding = true; this.stopExpanding = true;