diff options
| author | Alex Yatskov <alex@foosoft.net> | 2020-01-26 11:29:30 -0800 | 
|---|---|---|
| committer | Alex Yatskov <alex@foosoft.net> | 2020-01-26 11:29:30 -0800 | 
| commit | 0c5b9b1fa1599cbf769d96cdebc226310f9dd8bc (patch) | |
| tree | e734e2c3005078dbc248b541d357a934baa8a116 /ext/fg/js/popup.js | |
| parent | 2a12036ca305044291f1f4105d6a8d249848b210 (diff) | |
| parent | 0cf1cf3aa094585bd6db8db2c1f229ba0ea37b6e (diff) | |
Merge branch 'master' into testing
Diffstat (limited to 'ext/fg/js/popup.js')
| -rw-r--r-- | ext/fg/js/popup.js | 173 | 
1 files changed, 121 insertions, 52 deletions
| diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 7a0c6133..e7dae93e 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -28,10 +28,13 @@ class Popup {          this._childrenSupported = true;          this._injectPromise = null;          this._isInjected = false; +        this._isInjectedAndLoaded = false;          this._visible = false;          this._visibleOverride = null;          this._options = null;          this._stylesheetInjectedViaApi = false; +        this._contentScale = 1.0; +        this._containerSizeContentScale = null;          this._container = document.createElement('iframe');          this._container.className = 'yomichan-float'; @@ -103,7 +106,7 @@ class Popup {      }      async showContent(elementRect, writingMode, type=null, details=null) { -        if (!this._isInitialized()) { return; } +        if (this._options === null) { throw new Error('Options not assigned'); }          await this._show(elementRect, writingMode);          if (type === null) { return; }          this._invokeApi('setContent', {type, details}); @@ -114,11 +117,18 @@ class Popup {      }      clearAutoPlayTimer() { -        if (this._isInjected) { +        if (this._isInjectedAndLoaded) {              this._invokeApi('clearAutoPlayTimer');          }      } +    setContentScale(scale) { +        this._contentScale = scale; +        if (this._isInjectedAndLoaded) { +            this._invokeApi('setContentScale', {scale}); +        } +    } +      // Popup-only public functions      setParent(parent) { @@ -215,6 +225,7 @@ class Popup {          return new Promise((resolve) => {              const parentFrameId = (typeof this._frameId === 'number' ? this._frameId : null);              this._container.addEventListener('load', () => { +                this._isInjectedAndLoaded = true;                  this._invokeApi('initialize', {                      options: this._options,                      popupInfo: { @@ -223,7 +234,8 @@ class Popup {                          parentFrameId                      },                      url: this.url, -                    childrenSupported: this._childrenSupported +                    childrenSupported: this._childrenSupported, +                    scale: this._contentScale                  });                  resolve();              }); @@ -234,10 +246,6 @@ class Popup {          });      } -    _isInitialized() { -        return this._options !== null; -    } -      async _show(elementRect, writingMode) {          await this._inject(); @@ -250,18 +258,30 @@ class Popup {              Popup._getPositionForVerticalText          ); -        const [x, y, width, height, below] = getPosition( +        const viewport = Popup._getViewport(optionsGeneral.popupScaleRelativeToVisualViewport); +        const scale = this._contentScale; +        const scaleRatio = this._containerSizeContentScale === null ? 1.0 : scale / this._containerSizeContentScale; +        this._containerSizeContentScale = scale; +        let [x, y, width, height, below] = getPosition(              elementRect, -            Math.max(containerRect.width, optionsGeneral.popupWidth), -            Math.max(containerRect.height, optionsGeneral.popupHeight), -            document.body.clientWidth, -            window.innerHeight, +            Math.max(containerRect.width * scaleRatio, optionsGeneral.popupWidth * scale), +            Math.max(containerRect.height * scaleRatio, optionsGeneral.popupHeight * scale), +            viewport, +            scale,              optionsGeneral,              writingMode          ); -        container.classList.toggle('yomichan-float-full-width', optionsGeneral.popupDisplayMode === 'full-width'); +        const fullWidth = (optionsGeneral.popupDisplayMode === 'full-width'); +        container.classList.toggle('yomichan-float-full-width', fullWidth);          container.classList.toggle('yomichan-float-above', !below); + +        if (optionsGeneral.popupDisplayMode === 'full-width') { +            x = viewport.left; +            y = below ? viewport.bottom - height : viewport.top; +            width = viewport.right - viewport.left; +        } +          container.style.left = `${x}px`;          container.style.top = `${y}px`;          container.style.width = `${width}px`; @@ -307,6 +327,9 @@ class Popup {      }      _invokeApi(action, params={}) { +        if (!this._isInjectedAndLoaded) { +            throw new Error('Frame not loaded'); +        }          this._container.contentWindow.postMessage({action, params}, '*');      } @@ -338,49 +361,49 @@ class Popup {          }      } -    static _getPositionForHorizontalText(elementRect, width, height, maxWidth, maxHeight, optionsGeneral) { -        let x = elementRect.left + optionsGeneral.popupHorizontalOffset; -        const overflowX = Math.max(x + width - maxWidth, 0); -        if (overflowX > 0) { -            if (x >= overflowX) { -                x -= overflowX; -            } else { -                width = maxWidth; -                x = 0; -            } -        } - +    static _getPositionForHorizontalText(elementRect, width, height, viewport, offsetScale, optionsGeneral) {          const preferBelow = (optionsGeneral.popupHorizontalTextPosition === 'below'); +        const horizontalOffset = optionsGeneral.popupHorizontalOffset * offsetScale; +        const verticalOffset = optionsGeneral.popupVerticalOffset * offsetScale; -        const verticalOffset = optionsGeneral.popupVerticalOffset; -        const [y, h, below] = Popup._limitGeometry( +        const [x, w] = Popup._getConstrainedPosition( +            elementRect.right - horizontalOffset, +            elementRect.left + horizontalOffset, +            width, +            viewport.left, +            viewport.right, +            true +        ); +        const [y, h, below] = Popup._getConstrainedPositionBinary(              elementRect.top - verticalOffset,              elementRect.bottom + verticalOffset,              height, -            maxHeight, +            viewport.top, +            viewport.bottom,              preferBelow          ); - -        return [x, y, width, h, below]; +        return [x, y, w, h, below];      } -    static _getPositionForVerticalText(elementRect, width, height, maxWidth, maxHeight, optionsGeneral, writingMode) { +    static _getPositionForVerticalText(elementRect, width, height, viewport, offsetScale, optionsGeneral, writingMode) {          const preferRight = Popup._isVerticalTextPopupOnRight(optionsGeneral.popupVerticalTextPosition, writingMode); -        const horizontalOffset = optionsGeneral.popupHorizontalOffset2; -        const verticalOffset = optionsGeneral.popupVerticalOffset2; +        const horizontalOffset = optionsGeneral.popupHorizontalOffset2 * offsetScale; +        const verticalOffset = optionsGeneral.popupVerticalOffset2 * offsetScale; -        const [x, w] = Popup._limitGeometry( +        const [x, w] = Popup._getConstrainedPositionBinary(              elementRect.left - horizontalOffset,              elementRect.right + horizontalOffset,              width, -            maxWidth, +            viewport.left, +            viewport.right,              preferRight          ); -        const [y, h, below] = Popup._limitGeometry( +        const [y, h, below] = Popup._getConstrainedPosition(              elementRect.bottom - verticalOffset,              elementRect.top + verticalOffset,              height, -            maxHeight, +            viewport.top, +            viewport.bottom,              true          );          return [x, y, w, h, below]; @@ -409,23 +432,36 @@ class Popup {          }      } -    static _limitGeometry(positionBefore, positionAfter, size, limit, preferAfter) { -        let after = preferAfter; -        let position = 0; -        const overflowBefore = Math.max(0, size - positionBefore); -        const overflowAfter = Math.max(0, positionAfter + size - limit); +    static _getConstrainedPosition(positionBefore, positionAfter, size, minLimit, maxLimit, after) { +        size = Math.min(size, maxLimit - minLimit); + +        let position; +        if (after) { +            position = Math.max(minLimit, positionAfter); +            position = position - Math.max(0, (position + size) - maxLimit); +        } else { +            position = Math.min(maxLimit, positionBefore) - size; +            position = position + Math.max(0, minLimit - position); +        } + +        return [position, size, after]; +    } + +    static _getConstrainedPositionBinary(positionBefore, positionAfter, size, minLimit, maxLimit, after) { +        const overflowBefore = minLimit - (positionBefore - size); +        const overflowAfter = (positionAfter + size) - maxLimit; +          if (overflowAfter > 0 || overflowBefore > 0) { -            if (overflowAfter < overflowBefore) { -                size = Math.max(0, size - overflowAfter); -                position = positionAfter; -                after = true; -            } else { -                size = Math.max(0, size - overflowBefore); -                position = Math.max(0, positionBefore - size); -                after = false; -            } +            after = (overflowAfter < overflowBefore); +        } + +        let position; +        if (after) { +            size -= Math.max(0, overflowAfter); +            position = Math.max(minLimit, positionAfter);          } else { -            position = preferAfter ? positionAfter : positionBefore - size; +            size -= Math.max(0, overflowBefore); +            position = Math.min(maxLimit, positionBefore) - size;          }          return [position, size, after]; @@ -464,6 +500,39 @@ class Popup {              // NOP          }      } + +    static _getViewport(useVisualViewport) { +        const visualViewport = window.visualViewport; +        if (visualViewport !== null && typeof visualViewport === 'object') { +            const left = visualViewport.offsetLeft; +            const top = visualViewport.offsetTop; +            const width = visualViewport.width; +            const height = visualViewport.height; +            if (useVisualViewport) { +                return { +                    left, +                    top, +                    right: left + width, +                    bottom: top + height +                }; +            } else { +                const scale = visualViewport.scale; +                return { +                    left: 0, +                    top: 0, +                    right: Math.max(left + width, width * scale), +                    bottom: Math.max(top + height, height * scale) +                }; +            } +        } + +        return { +            left: 0, +            top: 0, +            right: document.body.clientWidth, +            bottom: window.innerHeight +        }; +    }  }  Popup.outerStylesheet = null; |