import {uuid, isNumber, isElement, windowBounds, extend} from "../../utils/core"; import throttle from 'lodash/throttle' class Stage { constructor(_options) { this.settings = _options || {}; this.id = "epubjs-container-" + uuid(); this.container = this.create(this.settings); if(this.settings.hidden) { this.wrapper = this.wrap(this.container); } } /* * Creates an element to render to. * Resizes to passed width and height or to the elements size */ create(options){ let height = options.height;// !== false ? options.height : "100%"; let width = options.width;// !== false ? options.width : "100%"; let overflow = options.overflow || false; let axis = options.axis || "vertical"; let direction = options.direction; extend(this.settings, options); if(options.height && isNumber(options.height)) { height = options.height + "px"; } if(options.width && isNumber(options.width)) { width = options.width + "px"; } // Create new container element let container = document.createElement("div"); container.id = this.id; container.classList.add("epub-container"); // Style Element // container.style.fontSize = "0"; container.style.wordSpacing = "0"; container.style.lineHeight = "0"; container.style.verticalAlign = "top"; container.style.position = "relative"; if(axis === "horizontal") { // container.style.whiteSpace = "nowrap"; container.style.display = "flex"; container.style.flexDirection = "row"; container.style.flexWrap = "nowrap"; } if(width){ container.style.width = width; } if(height){ container.style.height = height; } if (overflow) { if (overflow === "scroll" && axis === "vertical") { container.style["overflow-y"] = overflow; container.style["overflow-x"] = "hidden"; } else if (overflow === "scroll" && axis === "horizontal") { container.style["overflow-y"] = "hidden"; container.style["overflow-x"] = overflow; } else { container.style["overflow"] = overflow; } } if (direction) { container.dir = direction; container.style["direction"] = direction; } if (direction && this.settings.fullsize) { document.body.style["direction"] = direction; } return container; } wrap(container) { var wrapper = document.createElement("div"); wrapper.style.visibility = "hidden"; wrapper.style.overflow = "hidden"; wrapper.style.width = "0"; wrapper.style.height = "0"; wrapper.appendChild(container); return wrapper; } getElement(_element){ var element; if(isElement(_element)) { element = _element; } else if (typeof _element === "string") { element = document.getElementById(_element); } if(!element){ throw new Error("Not an Element"); } return element; } attachTo(what){ var element = this.getElement(what); var base; if(!element){ return; } if(this.settings.hidden) { base = this.wrapper; } else { base = this.container; } element.appendChild(base); this.element = element; return element; } getContainer() { return this.container; } onResize(func){ // Only listen to window for resize event if width and height are not fixed. // This applies if it is set to a percent or auto. if(!isNumber(this.settings.width) || !isNumber(this.settings.height) ) { this.resizeFunc = throttle(func, 50); window.addEventListener("resize", this.resizeFunc, false); } } onOrientationChange(func){ this.orientationChangeFunc = func; window.addEventListener("orientationchange", this.orientationChangeFunc, false); } size(width, height){ var bounds; let _width = width || this.settings.width; let _height = height || this.settings.height; // If width or height are set to false, inherit them from containing element if(width === null) { bounds = this.element.getBoundingClientRect(); if(bounds.width) { width = Math.floor(bounds.width); this.container.style.width = width + "px"; } } else { if (isNumber(width)) { this.container.style.width = width + "px"; } else { this.container.style.width = width; } } if(height === null) { bounds = bounds || this.element.getBoundingClientRect(); if(bounds.height) { height = bounds.height; this.container.style.height = height + "px"; } } else { if (isNumber(height)) { this.container.style.height = height + "px"; } else { this.container.style.height = height; } } if(!isNumber(width)) { width = this.container.clientWidth; } if(!isNumber(height)) { height = this.container.clientHeight; } this.containerStyles = window.getComputedStyle(this.container); this.containerPadding = { left: parseFloat(this.containerStyles["padding-left"]) || 0, right: parseFloat(this.containerStyles["padding-right"]) || 0, top: parseFloat(this.containerStyles["padding-top"]) || 0, bottom: parseFloat(this.containerStyles["padding-bottom"]) || 0 }; // Bounds not set, get them from window let _windowBounds = windowBounds(); let bodyStyles = window.getComputedStyle(document.body); let bodyPadding = { left: parseFloat(bodyStyles["padding-left"]) || 0, right: parseFloat(bodyStyles["padding-right"]) || 0, top: parseFloat(bodyStyles["padding-top"]) || 0, bottom: parseFloat(bodyStyles["padding-bottom"]) || 0 }; if (!_width) { width = _windowBounds.width - bodyPadding.left - bodyPadding.right; } if ((this.settings.fullsize && !_height) || !_height) { height = _windowBounds.height - bodyPadding.top - bodyPadding.bottom; } return { width: width - this.containerPadding.left - this.containerPadding.right, height: height - this.containerPadding.top - this.containerPadding.bottom }; } bounds(){ let box; if (this.container.style.overflow !== "visible") { box = this.container && this.container.getBoundingClientRect(); } if(!box || !box.width || !box.height) { return windowBounds(); } else { return box; } } getSheet(){ var style = document.createElement("style"); // WebKit hack --> https://davidwalsh.name/add-rules-stylesheets style.appendChild(document.createTextNode("")); document.head.appendChild(style); return style.sheet; } addStyleRules(selector, rulesArray){ var scope = "#" + this.id + " "; var rules = ""; if(!this.sheet){ this.sheet = this.getSheet(); } rulesArray.forEach(function(set) { for (var prop in set) { if(set.hasOwnProperty(prop)) { rules += prop + ":" + set[prop] + ";"; } } }); 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"; } this.settings.axis = axis; } // orientation(orientation) { // if (orientation === "landscape") { // // } else { // // } // // this.orientation = orientation; // } direction(dir) { if (this.container) { this.container.dir = dir; this.container.style["direction"] = dir; } if (this.settings.fullsize) { document.body.style["direction"] = dir; } this.settings.dir = dir; } overflow(overflow) { if (this.container) { if (overflow === "scroll" && this.settings.axis === "vertical") { this.container.style["overflow-y"] = overflow; this.container.style["overflow-x"] = "hidden"; } else if (overflow === "scroll" && this.settings.axis === "horizontal") { this.container.style["overflow-y"] = "hidden"; this.container.style["overflow-x"] = overflow; } else { this.container.style["overflow"] = overflow; } } this.settings.overflow = overflow; } destroy() { var base; if (this.element) { if(this.settings.hidden) { base = this.wrapper; } else { base = this.container; } if(this.element.contains(this.container)) { this.element.removeChild(this.container); } window.removeEventListener("resize", this.resizeFunc); window.removeEventListener("orientationChange", this.orientationChangeFunc); } } } export default Stage;