Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

placeCaretAtHorizontalEdge: allow scrolling on initial call #31506

Merged
merged 2 commits into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/dom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,6 @@ _Parameters_

- _container_ `HTMLElement`: Focusable element.
- _isReverse_ `boolean`: True for end, false for start.
- _mayUseScroll_ `[boolean]`: Whether to allow scrolling.

<a name="placeCaretAtVerticalEdge" href="#placeCaretAtVerticalEdge">#</a> **placeCaretAtVerticalEdge**

Expand Down
57 changes: 33 additions & 24 deletions packages/dom/src/dom/place-caret-at-horizontal-edge.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,33 @@ import hiddenCaretRangeFromPoint from './hidden-caret-range-from-point';
import isInputOrTextArea from './is-input-or-text-area';
import isRTL from './is-rtl';

/**
* Gets the range to place.
*
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
*
* @return {Range|null} The range to place.
*/
function getRange( container, isReverse ) {
const { ownerDocument } = container;
// In the case of RTL scripts, the horizontal edge is at the opposite side.
const isReverseDir = isRTL( container ) ? ! isReverse : isReverse;
const containerRect = container.getBoundingClientRect();
// When placing at the end (isReverse), find the closest range to the bottom
// right corner. When placing at the start, to the top left corner.
const x = isReverse ? containerRect.right - 1 : containerRect.left + 1;
const y = isReverseDir ? containerRect.bottom - 1 : containerRect.top + 1;
return hiddenCaretRangeFromPoint( ownerDocument, x, y, container );
}

/**
* Places the caret at start or end of a given element.
*
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
* @param {boolean} [mayUseScroll=false] Whether to allow scrolling.
* @param {HTMLElement} container Focusable element.
* @param {boolean} isReverse True for end, false for start.
*/
export default function placeCaretAtHorizontalEdge(
container,
isReverse,
mayUseScroll = false
) {
export default function placeCaretAtHorizontalEdge( container, isReverse ) {
if ( ! container ) {
return;
}
Expand Down Expand Up @@ -49,15 +64,7 @@ export default function placeCaretAtHorizontalEdge(
return;
}

const { ownerDocument } = container;
// In the case of RTL scripts, the horizontal edge is at the opposite side.
const isReverseDir = isRTL( container ) ? ! isReverse : isReverse;
const containerRect = container.getBoundingClientRect();
// When placing at the end (isReverse), find the closest range to the bottom
// right corner. When placing at the start, to the top left corner.
const x = isReverse ? containerRect.right - 1 : containerRect.left + 1;
const y = isReverseDir ? containerRect.bottom - 1 : containerRect.top + 1;
const range = hiddenCaretRangeFromPoint( ownerDocument, x, y, container );
let range = getRange( container, isReverse );

// If no range range can be created or it is outside the container, the
// element may be out of view.
Expand All @@ -66,17 +73,19 @@ export default function placeCaretAtHorizontalEdge(
! range.startContainer ||
! container.contains( range.startContainer )
) {
if ( ! mayUseScroll ) {
container.scrollIntoView( isReverse );
range = getRange( container, isReverse );

if (
! range ||
! range.startContainer ||
! container.contains( range.startContainer )
) {
return;
}

// Only try to scroll into view once to avoid an infinite loop.
mayUseScroll = false;
container.scrollIntoView( isReverse );
placeCaretAtHorizontalEdge( container, isReverse, mayUseScroll );
return;
}

const { ownerDocument } = container;
const { defaultView } = ownerDocument;
assertIsDefined( defaultView, 'defaultView' );
const selection = defaultView.getSelection();
Expand Down