summaryrefslogtreecommitdiff
path: root/lib/epub.js/src/managers/views/inline.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/epub.js/src/managers/views/inline.js')
-rw-r--r--lib/epub.js/src/managers/views/inline.js432
1 files changed, 432 insertions, 0 deletions
diff --git a/lib/epub.js/src/managers/views/inline.js b/lib/epub.js/src/managers/views/inline.js
new file mode 100644
index 0000000..072b586
--- /dev/null
+++ b/lib/epub.js/src/managers/views/inline.js
@@ -0,0 +1,432 @@
+import EventEmitter from "event-emitter";
+import {extend, borders, uuid, isNumber, bounds, defer, qs, parse} from "../../utils/core";
+import EpubCFI from "../../epubcfi";
+import Contents from "../../contents";
+import { EVENTS } from "../../utils/constants";
+
+class InlineView {
+ constructor(section, options) {
+ this.settings = extend({
+ ignoreClass : "",
+ axis: "vertical",
+ width: 0,
+ height: 0,
+ layout: undefined,
+ globalLayoutProperties: {},
+ }, options || {});
+
+ this.id = "epubjs-view:" + uuid();
+ this.section = section;
+ this.index = section.index;
+
+ this.element = this.container(this.settings.axis);
+
+ this.added = false;
+ this.displayed = false;
+ this.rendered = false;
+
+ this.width = this.settings.width;
+ this.height = this.settings.height;
+
+ this.fixedWidth = 0;
+ this.fixedHeight = 0;
+
+ // Blank Cfi for Parsing
+ this.epubcfi = new EpubCFI();
+
+ this.layout = this.settings.layout;
+ // Dom events to listen for
+ // this.listenedEvents = ["keydown", "keyup", "keypressed", "mouseup", "mousedown", "click", "touchend", "touchstart"];
+
+ }
+
+ container(axis) {
+ var element = document.createElement("div");
+
+ element.classList.add("epub-view");
+
+ // if(this.settings.axis === "horizontal") {
+ // element.style.width = "auto";
+ // element.style.height = "0";
+ // } else {
+ // element.style.width = "0";
+ // element.style.height = "auto";
+ // }
+
+ element.style.overflow = "hidden";
+
+ if(axis && axis == "horizontal"){
+ element.style.display = "inline-block";
+ } else {
+ element.style.display = "block";
+ }
+
+ return element;
+ }
+
+ create() {
+
+ if(this.frame) {
+ return this.frame;
+ }
+
+ if(!this.element) {
+ this.element = this.createContainer();
+ }
+
+ this.frame = document.createElement("div");
+ this.frame.id = this.id;
+ this.frame.style.overflow = "hidden";
+ this.frame.style.wordSpacing = "initial";
+ this.frame.style.lineHeight = "initial";
+
+ this.resizing = true;
+
+ // this.frame.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.frame.style.visibility = "hidden";
+
+ if(this.settings.axis === "horizontal") {
+ this.frame.style.width = "auto";
+ this.frame.style.height = "0";
+ } else {
+ this.frame.style.width = "0";
+ this.frame.style.height = "auto";
+ }
+
+ this._width = 0;
+ this._height = 0;
+
+ this.element.appendChild(this.frame);
+ this.added = true;
+
+ this.elementBounds = bounds(this.element);
+
+ return this.frame;
+ }
+
+ render(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.emit(EVENTS.VIEWS.RENDERED, this.section);
+
+ }.bind(this))
+ .catch(function(e){
+ this.emit(EVENTS.VIEWS.LOAD_ERROR, e);
+ }.bind(this));
+
+ }
+
+ // Determine locks base on settings
+ size(_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
+ lock(what, width, height) {
+ var elBorders = borders(this.element);
+ var iframeBorders;
+
+ if(this.frame) {
+ iframeBorders = borders(this.frame);
+ } else {
+ iframeBorders = {width: 0, height: 0};
+ }
+
+ if(what == "width" && isNumber(width)){
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.resize(this.lockedWidth, false); // width keeps ratio correct
+ }
+
+ if(what == "height" && isNumber(height)){
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+ this.resize(false, this.lockedHeight);
+ }
+
+ if(what === "both" &&
+ isNumber(width) &&
+ isNumber(height)){
+
+ this.lockedWidth = width - elBorders.width - iframeBorders.width;
+ this.lockedHeight = height - elBorders.height - iframeBorders.height;
+
+ this.resize(this.lockedWidth, this.lockedHeight);
+ }
+
+ }
+
+ // Resize a single axis based on content dimensions
+ expand(force) {
+ var width = this.lockedWidth;
+ var height = this.lockedHeight;
+
+ var textWidth, textHeight;
+
+ if(!this.frame || this._expanding) return;
+
+ this._expanding = true;
+
+ // Expand Horizontally
+ if(this.settings.axis === "horizontal") {
+ width = this.contentWidth(textWidth);
+ } // Expand Vertically
+ else if(this.settings.axis === "vertical") {
+ height = this.contentHeight(textHeight);
+ }
+
+ // 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;
+ }
+
+ contentWidth(min) {
+ return this.frame.scrollWidth;
+ }
+
+ contentHeight(min) {
+ return this.frame.scrollHeight;
+ }
+
+
+ resize(width, height) {
+
+ if(!this.frame) return;
+
+ if(isNumber(width)){
+ this.frame.style.width = width + "px";
+ this._width = width;
+ }
+
+ if(isNumber(height)){
+ this.frame.style.height = height + "px";
+ this._height = height;
+ }
+
+ this.prevBounds = this.elementBounds;
+
+ this.elementBounds = bounds(this.element);
+
+ let size = {
+ width: this.elementBounds.width,
+ height: this.elementBounds.height,
+ widthDelta: this.elementBounds.width - this.prevBounds.width,
+ heightDelta: this.elementBounds.height - this.prevBounds.height,
+ };
+
+ this.onResize(this, size);
+
+ this.emit(EVENTS.VIEWS.RESIZED, size);
+
+ }
+
+
+ load(contents) {
+ var loading = new defer();
+ var loaded = loading.promise;
+ var doc = parse(contents, "text/html");
+ var body = qs(doc, "body");
+
+ /*
+ var srcs = doc.querySelectorAll("[src]");
+
+ Array.prototype.slice.call(srcs)
+ .forEach(function(item) {
+ var src = item.getAttribute("src");
+ var assetUri = URI(src);
+ var origin = assetUri.origin();
+ var absoluteUri;
+
+ if (!origin) {
+ absoluteUri = assetUri.absoluteTo(this.section.url);
+ item.src = absoluteUri;
+ }
+ }.bind(this));
+ */
+ this.frame.innerHTML = body.innerHTML;
+
+ this.document = this.frame.ownerDocument;
+ this.window = this.document.defaultView;
+
+ this.contents = new Contents(this.document, this.frame);
+
+ this.rendering = false;
+
+ loading.resolve(this.contents);
+
+
+ return loaded;
+ }
+
+ setLayout(layout) {
+ this.layout = layout;
+ }
+
+
+ resizeListenters() {
+ // Test size again
+ // clearTimeout(this.expanding);
+ // this.expanding = setTimeout(this.expand.bind(this), 350);
+ }
+
+ addListeners() {
+ //TODO: Add content listeners for expanding
+ }
+
+ removeListeners(layoutFunc) {
+ //TODO: remove content listeners for expanding
+ }
+
+ display(request) {
+ var displayed = new defer();
+
+ if (!this.displayed) {
+
+ this.render(request).then(function () {
+
+ this.emit(EVENTS.VIEWS.DISPLAYED, this);
+ this.onDisplayed(this);
+
+ this.displayed = true;
+
+ displayed.resolve(this);
+
+ }.bind(this));
+
+ } else {
+ displayed.resolve(this);
+ }
+
+
+ return displayed.promise;
+ }
+
+ show() {
+
+ this.element.style.visibility = "visible";
+
+ if(this.frame){
+ this.frame.style.visibility = "visible";
+ }
+
+ this.emit(EVENTS.VIEWS.SHOWN, this);
+ }
+
+ hide() {
+ // this.frame.style.display = "none";
+ this.element.style.visibility = "hidden";
+ this.frame.style.visibility = "hidden";
+
+ this.stopExpanding = true;
+ this.emit(EVENTS.VIEWS.HIDDEN, this);
+ }
+
+ position() {
+ return this.element.getBoundingClientRect();
+ }
+
+ locationOf(target) {
+ var parentPos = this.frame.getBoundingClientRect();
+ var targetPos = this.contents.locationOf(target, this.settings.ignoreClass);
+
+ return {
+ "left": window.scrollX + parentPos.left + targetPos.left,
+ "top": window.scrollY + parentPos.top + targetPos.top
+ };
+ }
+
+ onDisplayed(view) {
+ // Stub, override with a custom functions
+ }
+
+ onResize(view, e) {
+ // Stub, override with a custom functions
+ }
+
+ bounds() {
+ if(!this.elementBounds) {
+ this.elementBounds = bounds(this.element);
+ }
+ return this.elementBounds;
+ }
+
+ destroy() {
+
+ if(this.displayed){
+ this.displayed = false;
+
+ this.removeListeners();
+
+ this.stopExpanding = true;
+ this.element.removeChild(this.frame);
+ this.displayed = false;
+ this.frame = null;
+
+ this._textWidth = null;
+ this._textHeight = null;
+ this._width = null;
+ this._height = null;
+ }
+ // this.element.style.height = "0px";
+ // this.element.style.width = "0px";
+ }
+}
+
+EventEmitter(InlineView.prototype);
+
+export default InlineView;