mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-05 15:32:55 +02:00
Flattened src dir
This commit is contained in:
parent
da5006792f
commit
82fb23daab
22 changed files with 1487 additions and 2082 deletions
645
src/view.js
Normal file
645
src/view.js
Normal file
|
@ -0,0 +1,645 @@
|
|||
EPUBJS.View = function(section, options) {
|
||||
this.settings = options || {};
|
||||
|
||||
this.id = "epubjs-view:" + EPUBJS.core.uuid();
|
||||
this.section = section;
|
||||
this.index = section.index;
|
||||
|
||||
this.element = document.createElement('div');
|
||||
this.element.classList.add("epub-view");
|
||||
|
||||
|
||||
// this.element.style.minHeight = "100px";
|
||||
this.element.style.height = "0px";
|
||||
this.element.style.width = "0px";
|
||||
this.element.style.overflow = "hidden";
|
||||
|
||||
this.added = false;
|
||||
this.displayed = false;
|
||||
this.rendered = false;
|
||||
|
||||
//this.width = 0;
|
||||
//this.height = 0;
|
||||
|
||||
// Blank Cfi for Parsing
|
||||
this.epubcfi = new EPUBJS.EpubCFI();
|
||||
|
||||
if(this.settings.axis && this.settings.axis == "horizontal"){
|
||||
this.element.style.display = "inline-block";
|
||||
} else {
|
||||
this.element.style.display = "block";
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.create = function() {
|
||||
|
||||
if(this.iframe) {
|
||||
return this.iframe;
|
||||
}
|
||||
|
||||
this.iframe = document.createElement('iframe');
|
||||
this.iframe.id = this.id;
|
||||
this.iframe.scrolling = "no"; // Might need to be removed: breaks ios width calculations
|
||||
this.iframe.style.overflow = "hidden";
|
||||
this.iframe.seamless = "seamless";
|
||||
// Back up if seamless isn't supported
|
||||
this.iframe.style.border = "none";
|
||||
|
||||
this.resizing = true;
|
||||
|
||||
// this.iframe.style.display = "none";
|
||||
this.element.style.visibility = "hidden";
|
||||
this.iframe.style.visibility = "hidden";
|
||||
|
||||
this.iframe.style.width = "0";
|
||||
this.iframe.style.height = "0";
|
||||
this._width = 0;
|
||||
this._height = 0;
|
||||
|
||||
this.element.appendChild(this.iframe);
|
||||
this.added = true;
|
||||
|
||||
this.elementBounds = EPUBJS.core.bounds(this.element);
|
||||
|
||||
// if(width || height){
|
||||
// this.resize(width, height);
|
||||
// } else if(this.width && this.height){
|
||||
// this.resize(this.width, this.height);
|
||||
// } else {
|
||||
// this.iframeBounds = EPUBJS.core.bounds(this.iframe);
|
||||
// }
|
||||
|
||||
// Firefox has trouble with baseURI and srcdoc
|
||||
// Disabled for now
|
||||
/*
|
||||
if(!!("srcdoc" in this.iframe)) {
|
||||
this.supportsSrcdoc = true;
|
||||
} else {
|
||||
this.supportsSrcdoc = false;
|
||||
}
|
||||
*/
|
||||
this.supportsSrcdoc = false;
|
||||
|
||||
return this.iframe;
|
||||
};
|
||||
|
||||
|
||||
EPUBJS.View.prototype.lock = function(what, width, height) {
|
||||
|
||||
var elBorders = EPUBJS.core.borders(this.element);
|
||||
var iframeBorders;
|
||||
|
||||
if(this.iframe) {
|
||||
iframeBorders = EPUBJS.core.borders(this.iframe);
|
||||
} else {
|
||||
iframeBorders = {width: 0, height: 0};
|
||||
}
|
||||
|
||||
if(what == "width" && EPUBJS.core.isNumber(width)){
|
||||
this.lockedWidth = width - elBorders.width - iframeBorders.width;
|
||||
this.resize(this.lockedWidth, width); // width keeps ratio correct
|
||||
}
|
||||
|
||||
if(what == "height" && EPUBJS.core.isNumber(height)){
|
||||
this.lockedHeight = height - elBorders.height - iframeBorders.height;
|
||||
this.resize(width, this.lockedHeight);
|
||||
}
|
||||
|
||||
if(what === "both" &&
|
||||
EPUBJS.core.isNumber(width) &&
|
||||
EPUBJS.core.isNumber(height)){
|
||||
|
||||
this.lockedWidth = width - elBorders.width - iframeBorders.width;
|
||||
this.lockedHeight = height - elBorders.height - iframeBorders.height;
|
||||
|
||||
this.resize(this.lockedWidth, this.lockedHeight);
|
||||
}
|
||||
|
||||
if(this.displayed && this.iframe) {
|
||||
|
||||
this.layout();
|
||||
this.expand();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.expand = function(force) {
|
||||
var width = this.lockedWidth;
|
||||
var height = this.lockedHeight;
|
||||
|
||||
var textWidth, textHeight;
|
||||
|
||||
if(!this.iframe || this._expanding) return;
|
||||
|
||||
this._expanding = true;
|
||||
|
||||
// Expand Horizontally
|
||||
if(height && !width) {
|
||||
// Get the width of the text
|
||||
textWidth = this.textWidth();
|
||||
// Check if the textWidth has changed
|
||||
if(textWidth != this._textWidth){
|
||||
// Get the contentWidth by resizing the iframe
|
||||
// Check with a min reset of the textWidth
|
||||
width = this.contentWidth(textWidth);
|
||||
// Save the textWdith
|
||||
this._textWidth = textWidth;
|
||||
// Save the contentWidth
|
||||
this._contentWidth = width;
|
||||
} else {
|
||||
// Otherwise assume content height hasn't changed
|
||||
width = this._contentWidth;
|
||||
}
|
||||
};
|
||||
|
||||
// Expand Vertically
|
||||
if(width && !height) {
|
||||
textHeight = this.textHeight();
|
||||
if(textHeight != this._textHeight){
|
||||
height = this.contentHeight(textHeight);
|
||||
this._textHeight = textHeight;
|
||||
this._contentHeight = height;
|
||||
} else {
|
||||
height = this._contentHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// Only Resize if dimensions have changed or
|
||||
// if Frame is still hidden, so needs reframing
|
||||
if(this._needsReframe || width != this._width || height != this._height){
|
||||
this.resize(width, height);
|
||||
}
|
||||
|
||||
this._expanding = false;
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.contentWidth = function(min) {
|
||||
var prev;
|
||||
var width;
|
||||
|
||||
// Save previous width
|
||||
prev = this.iframe.style.width;
|
||||
// Set the iframe size to min, width will only ever be greater
|
||||
this.iframe.style.width = 0 + "px";
|
||||
// Get the scroll overflow width
|
||||
width = this.document.body.scrollWidth;
|
||||
// Reset iframe size back
|
||||
this.iframe.style.width = prev;
|
||||
return width;
|
||||
}
|
||||
|
||||
EPUBJS.View.prototype.contentHeight = function(min) {
|
||||
var prev;
|
||||
var height;
|
||||
|
||||
prev = this.iframe.style.height;
|
||||
this.iframe.style.height = (min || 0) + "px";
|
||||
height = this.document.body.scrollHeight;
|
||||
this.iframe.style.height = prev;
|
||||
return height;
|
||||
}
|
||||
|
||||
EPUBJS.View.prototype.textWidth = function() {
|
||||
var width;
|
||||
var range = this.document.createRange();
|
||||
|
||||
// Select the contents of frame
|
||||
range.selectNodeContents(this.document.body);
|
||||
|
||||
// get the width of the text content
|
||||
width = range.getBoundingClientRect().width;
|
||||
return width;
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.textHeight = function() {
|
||||
var height;
|
||||
var range = this.document.createRange();
|
||||
|
||||
range.selectNodeContents(this.document.body);
|
||||
|
||||
height = range.getBoundingClientRect().height;
|
||||
return height;
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.resize = function(width, height) {
|
||||
|
||||
if(!this.iframe) return;
|
||||
|
||||
if(EPUBJS.core.isNumber(width)){
|
||||
this.iframe.style.width = width + "px";
|
||||
this._width = width;
|
||||
}
|
||||
|
||||
if(EPUBJS.core.isNumber(height)){
|
||||
this.iframe.style.height = height + "px";
|
||||
this._height = height;
|
||||
}
|
||||
|
||||
this.iframeBounds = EPUBJS.core.bounds(this.iframe);
|
||||
|
||||
this.reframe(this.iframeBounds.width, this.iframeBounds.height);
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.reframe = function(width, height) {
|
||||
//var prevBounds;
|
||||
|
||||
if(!this.displayed) {
|
||||
this._needsReframe = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(EPUBJS.core.isNumber(width)){
|
||||
this.element.style.width = width + "px";
|
||||
}
|
||||
|
||||
if(EPUBJS.core.isNumber(height)){
|
||||
this.element.style.height = height + "px";
|
||||
}
|
||||
|
||||
this.prevBounds = this.elementBounds;
|
||||
|
||||
this.elementBounds = EPUBJS.core.bounds(this.element);
|
||||
|
||||
this.trigger("resized", {
|
||||
width: this.elementBounds.width,
|
||||
height: this.elementBounds.height,
|
||||
widthDelta: this.elementBounds.width - this.prevBounds.width,
|
||||
heightDelta: this.elementBounds.height - this.prevBounds.height,
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.resized = function(e) {
|
||||
/*
|
||||
if (!this.resizing) {
|
||||
if(this.iframe) {
|
||||
// this.expand();
|
||||
}
|
||||
} else {
|
||||
this.resizing = false;
|
||||
}*/
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.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));
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.load = function(contents) {
|
||||
var loading = new RSVP.defer();
|
||||
var loaded = loading.promise;
|
||||
|
||||
if(!this.iframe) {
|
||||
loading.reject(new Error("No Iframe Available"));
|
||||
return loaded;
|
||||
}
|
||||
|
||||
this.iframe.onload = function(event) {
|
||||
|
||||
this.window = this.iframe.contentWindow;
|
||||
this.document = this.iframe.contentDocument;
|
||||
this.rendering = false;
|
||||
loading.resolve(this);
|
||||
|
||||
}.bind(this);
|
||||
|
||||
if(this.supportsSrcdoc){
|
||||
this.iframe.srcdoc = contents;
|
||||
} else {
|
||||
|
||||
this.document = this.iframe.contentDocument;
|
||||
|
||||
if(!this.document) {
|
||||
loading.reject(new Error("No Document Available"));
|
||||
return loaded;
|
||||
}
|
||||
|
||||
this.document.open();
|
||||
this.document.write(contents);
|
||||
this.document.close();
|
||||
|
||||
}
|
||||
|
||||
return loaded;
|
||||
};
|
||||
|
||||
|
||||
EPUBJS.View.prototype.layout = function(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){
|
||||
layoutFunc(this);
|
||||
}
|
||||
|
||||
this.onLayout(this);
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.onLayout = function(view) {
|
||||
// stub
|
||||
};
|
||||
|
||||
EPUBJS.View.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();
|
||||
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.resizeListenters = function() {
|
||||
// Test size again
|
||||
clearTimeout(this.expanding);
|
||||
this.expanding = setTimeout(this.expand.bind(this), 350);
|
||||
};
|
||||
|
||||
//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js
|
||||
EPUBJS.View.prototype.mediaQueryListeners = function() {
|
||||
var sheets = this.document.styleSheets;
|
||||
var mediaChangeHandler = function(m){
|
||||
if(m.matches && !this._expanding) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EPUBJS.View.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;
|
||||
};
|
||||
|
||||
// EPUBJS.View.prototype.appendTo = function(element) {
|
||||
// this.element = element;
|
||||
// this.element.appendChild(this.iframe);
|
||||
// };
|
||||
//
|
||||
// EPUBJS.View.prototype.prependTo = function(element) {
|
||||
// this.element = element;
|
||||
// element.insertBefore(this.iframe, element.firstChild);
|
||||
// };
|
||||
|
||||
EPUBJS.View.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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.display = function() {
|
||||
var displayed = new RSVP.defer();
|
||||
|
||||
this.displayed = true;
|
||||
|
||||
this.layout();
|
||||
|
||||
this.listeners();
|
||||
|
||||
this.expand();
|
||||
|
||||
this.trigger("displayed", this);
|
||||
this.onDisplayed(this);
|
||||
|
||||
displayed.resolve(this);
|
||||
|
||||
return displayed.promise;
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.show = function() {
|
||||
|
||||
this.element.style.visibility = "visible";
|
||||
|
||||
if(this.iframe){
|
||||
this.iframe.style.visibility = "visible";
|
||||
}
|
||||
|
||||
this.trigger("shown", this);
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.hide = function() {
|
||||
// this.iframe.style.display = "none";
|
||||
this.element.style.visibility = "hidden";
|
||||
this.iframe.style.visibility = "hidden";
|
||||
|
||||
this.stopExpanding = true;
|
||||
this.trigger("hidden", this);
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.position = function() {
|
||||
return this.element.getBoundingClientRect();
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.onDisplayed = function(view) {
|
||||
// Stub, override with a custom functions
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.bounds = function() {
|
||||
if(!this.elementBounds) {
|
||||
this.elementBounds = EPUBJS.core.bounds(this.element);
|
||||
}
|
||||
return this.elementBounds;
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.destroy = function() {
|
||||
// Stop observing
|
||||
if(this.observer) {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
if(this.displayed){
|
||||
this.stopExpanding = true;
|
||||
this.element.removeChild(this.iframe);
|
||||
this.displayed = false;
|
||||
this.iframe = null;
|
||||
|
||||
this._textWidth = null;
|
||||
this._textHeight = null;
|
||||
this._width = null;
|
||||
this._height = null;
|
||||
}
|
||||
// this.element.style.height = "0px";
|
||||
// this.element.style.width = "0px";
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.root = function() {
|
||||
if(!this.document) return null;
|
||||
return this.document.documentElement;
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.locationOf = function(target) {
|
||||
|
||||
if(!this.document) return;
|
||||
|
||||
if(this.epubcfi.isCfiString(target)) {
|
||||
cfi = this.epubcfi.parse(target);
|
||||
|
||||
if(typeof document.evaluate === 'undefined') {
|
||||
marker = this.epubcfi.addMarker(cfi, this.document);
|
||||
if(marker) {
|
||||
// Must Clean up Marker before going to page
|
||||
this.epubcfi.removeMarker(marker, this.document);
|
||||
|
||||
return marker.getBoundingClientRect();
|
||||
}
|
||||
} else {
|
||||
range = this.epubcfi.generateRangeFromCfi(cfi, this.document);
|
||||
if(range) {
|
||||
return range.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
} else if(typeof target === "string" &&
|
||||
target.indexOf("#") > -1) {
|
||||
|
||||
id = target.substring(target.indexOf("#"));
|
||||
el = this.document.getElementById(id);
|
||||
|
||||
if(el) {
|
||||
return el.getBoundingClientRect();
|
||||
}
|
||||
}
|
||||
|
||||
return {"left": 0, "top": 0};
|
||||
};
|
||||
|
||||
EPUBJS.View.prototype.addCss = function(src) {
|
||||
var $stylesheet = document.createElement('link');
|
||||
var ready = false;
|
||||
|
||||
return new RSVP.Promise(function(resolve, reject){
|
||||
if(!this.document) {
|
||||
resolve(false);
|
||||
return;
|
||||
}
|
||||
|
||||
$stylesheet.type = 'text/css';
|
||||
$stylesheet.rel = "stylesheet";
|
||||
$stylesheet.href = src;
|
||||
$stylesheet.onload = $stylesheet.onreadystatechange = function() {
|
||||
if ( !ready && (!this.readyState || this.readyState == 'complete') ) {
|
||||
ready = true;
|
||||
// Let apply
|
||||
setTimeout(function(){
|
||||
resolve(true);
|
||||
}, 1);
|
||||
}
|
||||
};
|
||||
|
||||
this.document.head.appendChild($stylesheet);
|
||||
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
|
||||
EPUBJS.View.prototype.addStylesheetRules = function(rules) {
|
||||
var styleEl = document.createElement('style'),
|
||||
styleSheet;
|
||||
|
||||
if(!this.document) return;
|
||||
|
||||
// Append style element to head
|
||||
this.document.head.appendChild(styleEl);
|
||||
|
||||
// Grab style sheet
|
||||
styleSheet = styleEl.sheet;
|
||||
|
||||
for (var i = 0, rl = rules.length; i < rl; i++) {
|
||||
var j = 1, rule = rules[i], selector = rules[i][0], propStr = '';
|
||||
// If the second argument of a rule is an array of arrays, correct our variables.
|
||||
if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
|
||||
rule = rule[1];
|
||||
j = 0;
|
||||
}
|
||||
|
||||
for (var pl = rule.length; j < pl; j++) {
|
||||
var prop = rule[j];
|
||||
propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
|
||||
}
|
||||
|
||||
// Insert CSS Rule
|
||||
styleSheet.insertRule(selector + '{' + propStr + '}', styleSheet.cssRules.length);
|
||||
}
|
||||
};
|
||||
|
||||
RSVP.EventTarget.mixin(EPUBJS.View.prototype);
|
Loading…
Add table
Add a link
Reference in a new issue