From dc9694c42cde3d61d13370ce49a03404727f3bd4 Mon Sep 17 00:00:00 2001 From: iseulde Date: Tue, 26 Mar 2019 10:51:06 +0100 Subject: [PATCH] Merge isEdge logic --- packages/dom/src/dom.js | 115 ++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 75 deletions(-) diff --git a/packages/dom/src/dom.js b/packages/dom/src/dom.js index fadf4d135b11d1..d0034205ba86a9 100644 --- a/packages/dom/src/dom.js +++ b/packages/dom/src/dom.js @@ -60,14 +60,17 @@ function isSelectionForward( selection ) { } /** - * Check whether the selection is horizontally at the edge of the container. + * Check whether the selection is at the edge of the container. Checks for + * horizontal position by default. Set `isVertical` to true to check only + * vertically. * - * @param {Element} container Focusable element. - * @param {boolean} isReverse Set to true to check left, false for right. + * @param {Element} container Focusable element. + * @param {boolean} isReverse Set to true to check left, false to check right. + * @param {boolean} isVertical Set to true to check only vertical position. * * @return {boolean} True if at the horizontal edge, false if not. */ -export function isHorizontalEdge( container, isReverse ) { +function isEdge( container, { isReverse, isVertical } ) { if ( includes( [ 'INPUT', 'TEXTAREA' ], container.tagName ) ) { if ( container.selectionStart !== container.selectionEnd ) { return false; @@ -86,36 +89,35 @@ export function isHorizontalEdge( container, isReverse ) { const selection = window.getSelection(); - // Only consider the selection at the edge if the direction is towards the - // edge. - if ( - ! selection.isCollapsed && - isSelectionForward( selection ) === isReverse - ) { - return false; + if ( ! selection.rangeCount ) { + return; } - const range = selection.rangeCount ? selection.getRangeAt( 0 ) : null; + const rangeRect = getRectangleFromRange( selection.getRangeAt( 0 ) ); - if ( ! range ) { + if ( ! rangeRect ) { return false; } - const rangeRect = getRectangleFromRange( range ); + const computedStyle = window.getComputedStyle( container ); + const lineHeight = parseInt( computedStyle.lineHeight, 10 ); - if ( ! rangeRect ) { + // Only consider the multiline selection at the edge if the direction is + // towards the edge. + if ( + ! selection.isCollapsed && + rangeRect.height > lineHeight && + isSelectionForward( selection ) === isReverse + ) { return false; } - const containerRect = container.getBoundingClientRect(); - // Calculate a buffer that is half the line height. In some browsers, the // selection rectangle may not fill the entire height of the line, so we add - // half the line height to the selection rectangle to ensure that it is well + // 3/4 the line height to the selection rectangle to ensure that it is well // over its line boundary. - const { lineHeight } = window.getComputedStyle( container ); const buffer = 3 * parseInt( lineHeight, 10 ) / 4; - + const containerRect = container.getBoundingClientRect(); const verticalEdge = isReverse ? containerRect.top > rangeRect.top - buffer : containerRect.bottom < rangeRect.bottom + buffer; @@ -124,10 +126,12 @@ export function isHorizontalEdge( container, isReverse ) { return false; } + if ( isVertical ) { + return true; + } + const x = isReverse ? containerRect.left + 1 : containerRect.right - 1; - const y = isReverse ? - containerRect.top + buffer : - containerRect.bottom - buffer; + const y = isReverse ? containerRect.top + buffer : containerRect.bottom - buffer; const testRange = hiddenCaretRangeFromPoint( document, x, y, container ); if ( ! testRange ) { @@ -140,6 +144,18 @@ export function isHorizontalEdge( container, isReverse ) { return Math.round( testRect[ side ] ) === Math.round( rangeRect[ side ] ); } +/** + * Check whether the selection is horizontally at the edge of the container. + * + * @param {Element} container Focusable element. + * @param {boolean} isReverse Set to true to check left, false for right. + * + * @return {boolean} True if at the horizontal edge, false if not. + */ +export function isHorizontalEdge( container, isReverse ) { + return isEdge( container, { isReverse } ); +} + /** * Check whether the selection is vertically at the edge of the container. * @@ -149,58 +165,7 @@ export function isHorizontalEdge( container, isReverse ) { * @return {boolean} True if at the edge, false if not. */ export function isVerticalEdge( container, isReverse ) { - if ( includes( [ 'INPUT', 'TEXTAREA' ], container.tagName ) ) { - return isHorizontalEdge( container, isReverse ); - } - - if ( ! container.isContentEditable ) { - return true; - } - - const selection = window.getSelection(); - const range = selection.rangeCount ? selection.getRangeAt( 0 ) : null; - - if ( ! range ) { - return false; - } - - const rangeRect = getRectangleFromRange( range ); - - if ( ! rangeRect ) { - return false; - } - - // Calculate a buffer that is half the line height. In some browsers, the - // selection rectangle may not fill the entire height of the line, so we add - // half the line height to the selection rectangle to ensure that it is well - // over its line boundary. - const computedStyle = window.getComputedStyle( container ); - const lineHeight = parseInt( computedStyle.lineHeight, 10 ); - - // Only consider the multiline selection at the edge if the direction is - // towards the edge. - if ( - ! selection.isCollapsed && - rangeRect.height > lineHeight && - isSelectionForward( selection ) === isReverse - ) { - return false; - } - - const editableRect = container.getBoundingClientRect(); - const buffer = lineHeight / 2; - - // Too low. - if ( isReverse && rangeRect.top - buffer > editableRect.top ) { - return false; - } - - // Too high. - if ( ! isReverse && rangeRect.bottom + buffer < editableRect.bottom ) { - return false; - } - - return true; + return isEdge( container, { isReverse, isVertical: true } ); } /**