diff options
Diffstat (limited to 'lib/epub.js/src/managers/views/inline.js')
-rw-r--r-- | lib/epub.js/src/managers/views/inline.js | 432 |
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; |