From cf728fc22356aeb8d501031a05a9692a6ebd7053 Mon Sep 17 00:00:00 2001 From: Massimiliano Vinciprova Date: Thu, 29 Dec 2022 12:38:53 +0100 Subject: [PATCH] fix scroll bug --- src/managers/helpers/stage.js | 721 +++++++++++++++++----------------- 1 file changed, 363 insertions(+), 358 deletions(-) diff --git a/src/managers/helpers/stage.js b/src/managers/helpers/stage.js index d0f67e6..8f4e89c 100644 --- a/src/managers/helpers/stage.js +++ b/src/managers/helpers/stage.js @@ -1,363 +1,368 @@ -import {uuid, isNumber, isElement, windowBounds, extend} from "../../utils/core"; -import throttle from 'lodash/throttle' +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); - - } - } + 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'; + container.style.overflowAnchor = 'none'; + + 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;