diff options
Diffstat (limited to 'ext/fg/js')
| -rw-r--r-- | ext/fg/js/frontend.js | 8 | ||||
| -rw-r--r-- | ext/fg/js/popup.js | 147 | ||||
| -rw-r--r-- | ext/fg/js/source.js | 25 | 
3 files changed, 141 insertions, 39 deletions
| diff --git a/ext/fg/js/frontend.js b/ext/fg/js/frontend.js index 3c5f2ac8..72379062 100644 --- a/ext/fg/js/frontend.js +++ b/ext/fg/js/frontend.js @@ -301,7 +301,11 @@ class Frontend {          } catch (e) {              if (window.yomichan_orphaned) {                  if (textSource && this.options.scanning.modifier !== 'none') { -                    this.popup.showOrphaned(textSource.getRect(), this.options); +                    this.popup.showOrphaned( +                        textSource.getRect(), +                        textSource.getWritingMode(), +                        this.options +                    );                  }              } else {                  this.onError(e); @@ -332,6 +336,7 @@ class Frontend {          const url = window.location.href;          this.popup.termsShow(              textSource.getRect(), +            textSource.getWritingMode(),              definitions,              this.options,              {sentence, url, focus} @@ -357,6 +362,7 @@ class Frontend {          const url = window.location.href;          this.popup.kanjiShow(              textSource.getRect(), +            textSource.getWritingMode(),              definitions,              this.options,              {sentence, url, focus} diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 18dc0386..138dec41 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -48,59 +48,130 @@ class Popup {          return this.injected;      } -    async show(elementRect, options) { +    async show(elementRect, writingMode, options) {          await this.inject(options); -        const containerStyle = window.getComputedStyle(this.container); -        const containerHeight = parseInt(containerStyle.height); -        const containerWidth = parseInt(containerStyle.width); +        const optionsGeneral = options.general; +        const container = this.container; +        const containerRect = container.getBoundingClientRect(); +        const getPosition = ( +            writingMode === 'horizontal-tb' || optionsGeneral.popupVerticalTextPosition === 'default' ? +            Popup.getPositionForHorizontalText : +            Popup.getPositionForVerticalText +        ); -        const limitX = document.body.clientWidth; -        const limitY = window.innerHeight; +        const [x, y, width, height, below] = getPosition( +            elementRect, +            Math.max(containerRect.width, optionsGeneral.popupWidth), +            Math.max(containerRect.height, optionsGeneral.popupHeight), +            document.body.clientWidth, +            window.innerHeight, +            optionsGeneral, +            writingMode +        ); -        let x = elementRect.left + options.general.popupHorizontalOffset; -        let width = Math.max(containerWidth, options.general.popupWidth); -        const overflowX = Math.max(x + width - limitX, 0); +        container.classList.toggle('yomichan-float-full-width', optionsGeneral.popupDisplayMode === 'full-width'); +        container.classList.toggle('yomichan-float-above', !below); +        container.style.left = `${x}px`; +        container.style.top = `${y}px`; +        container.style.width = `${width}px`; +        container.style.height = `${height}px`; +        container.style.visibility = 'visible'; +    } + +    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 = limitX; +                width = maxWidth;                  x = 0;              }          } -        let above = false; -        let y = 0; -        let height = Math.max(containerHeight, options.general.popupHeight); -        const yBelow = elementRect.bottom + options.general.popupVerticalOffset; -        const yAbove = elementRect.top - options.general.popupVerticalOffset; -        const overflowBelow = Math.max(yBelow + height - limitY, 0); -        const overflowAbove = Math.max(height - yAbove, 0); -        if (overflowBelow > 0 || overflowAbove > 0) { -            if (overflowBelow < overflowAbove) { -                height = Math.max(height - overflowBelow, 0); -                y = yBelow; +        const verticalOffset = optionsGeneral.popupVerticalOffset; +        const [y, h, below] = Popup.limitGeometry( +            elementRect.top - verticalOffset, +            elementRect.bottom + verticalOffset, +            height, +            maxHeight, +            true +        ); + +        return [x, y, width, h, below]; +    } + +    static getPositionForVerticalText(elementRect, width, height, maxWidth, maxHeight, optionsGeneral, writingMode) { +        const preferRight = Popup.isVerticalTextPopupOnRight(optionsGeneral.popupVerticalTextPosition, writingMode); +        const horizontalOffset = optionsGeneral.popupHorizontalOffset2; +        const verticalOffset = optionsGeneral.popupVerticalOffset2; + +        const [x, w] = Popup.limitGeometry( +            elementRect.left - horizontalOffset, +            elementRect.right + horizontalOffset, +            width, +            maxWidth, +            preferRight +        ); +        const [y, h, below] = Popup.limitGeometry( +            elementRect.bottom - verticalOffset, +            elementRect.top + verticalOffset, +            height, +            maxHeight, +            true +        ); +        return [x, y, w, h, below]; +    } + +    static isVerticalTextPopupOnRight(positionPreference, writingMode) { +        switch (positionPreference) { +            case 'before': +                return !Popup.isWritingModeLeftToRight(writingMode); +            case 'after': +                return Popup.isWritingModeLeftToRight(writingMode); +            case 'left': +                return false; +            case 'right': +                return true; +        } +    } + +    static isWritingModeLeftToRight(writingMode) { +        switch (writingMode) { +            case 'vertical-lr': +            case 'sideways-lr': +                return true; +            default: +                return false; +        } +    } + +    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); +        if (overflowAfter > 0 || overflowBefore > 0) { +            if (overflowAfter < overflowBefore) { +                size = Math.max(0, size - overflowAfter); +                position = positionAfter; +                after = true;              } else { -                height = Math.max(height - overflowAbove, 0); -                y = Math.max(yAbove - height, 0); -                above = true; +                size = Math.max(0, size - overflowBefore); +                position = Math.max(0, positionBefore - size); +                after = false;              }          } else { -            y = yBelow; +            position = preferAfter ? positionAfter : positionBefore - size;          } -        this.container.classList.toggle('yomichan-float-full-width', options.general.popupDisplayMode === 'full-width'); -        this.container.classList.toggle('yomichan-float-above', above); -        this.container.style.left = `${x}px`; -        this.container.style.top = `${y}px`; -        this.container.style.width = `${width}px`; -        this.container.style.height = `${height}px`; -        this.container.style.visibility = 'visible'; +        return [position, size, after];      } -    async showOrphaned(elementRect, options) { -        await this.show(elementRect, options); +    async showOrphaned(elementRect, writingMode, options) { +        await this.show(elementRect, writingMode, options);          this.invokeApi('orphaned');      } @@ -136,13 +207,13 @@ class Popup {          return contained;      } -    async termsShow(elementRect, definitions, options, context) { -        await this.show(elementRect, options); +    async termsShow(elementRect, writingMode, definitions, options, context) { +        await this.show(elementRect, writingMode, options);          this.invokeApi('termsShow', {definitions, options, context});      } -    async kanjiShow(elementRect, definitions, options, context) { -        await this.show(elementRect, options); +    async kanjiShow(elementRect, writingMode, definitions, options, context) { +        await this.show(elementRect, writingMode, options);          this.invokeApi('kanjiShow', {definitions, options, context});      } diff --git a/ext/fg/js/source.js b/ext/fg/js/source.js index a360b331..a5421934 100644 --- a/ext/fg/js/source.js +++ b/ext/fg/js/source.js @@ -61,6 +61,10 @@ class TextSourceRange {          return this.range.getBoundingClientRect();      } +    getWritingMode() { +        return TextSourceRange.getElementWritingMode(TextSourceRange.getParentElement(this.range.startContainer)); +    } +      getPaddedRect() {          const range = this.range.cloneRange();          const startOffset = range.startOffset; @@ -204,6 +208,23 @@ class TextSourceRange {          return state.remainder > 0;      } + +    static getParentElement(node) { +        while (node !== null && node.nodeType !== Node.ELEMENT_NODE) { +            node = node.parentNode; +        } +        return node; +    } + +    static getElementWritingMode(element) { +        if (element === null) { +            return 'horizontal-tb'; +        } + +        const style = window.getComputedStyle(element); +        const writingMode = style.writingMode; +        return typeof writingMode === 'string' ? writingMode : 'horizontal-tb'; +    }  } @@ -267,6 +288,10 @@ class TextSourceElement {          return this.element.getBoundingClientRect();      } +    getWritingMode() { +        return 'horizontal-tb'; +    } +      select() {          // NOP      } |