Skip to content

Commit

Permalink
Merge pull request #14599 from ckeditor/ci/3442-document-outline-limi…
Browse files Browse the repository at this point in the history
…t-scrolling

Other (utils): Made the `scrollAncestorsToShowTarget()` helper take a limiter element as an argument in order to stop it from scrolling the entire viewport. Closes #14598.
  • Loading branch information
oleq authored Jul 18, 2023
2 parents cc7f05a + aa4667b commit a411cd7
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 4 deletions.
16 changes: 12 additions & 4 deletions packages/ckeditor5-utils/src/dom/scroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,14 +151,17 @@ export function scrollViewportToShowTarget<T extends boolean, U extends IfTrue<T
* @param target A target, which supposed to become visible to the user.
* @param ancestorOffset An offset between the target and the boundary of scrollable ancestors
* to be maintained while scrolling.
* @param limiterElement The outermost ancestor that should be scrolled. If specified, it can prevent
* scrolling the whole page.
*/
export function scrollAncestorsToShowTarget( target: HTMLElement | Range, ancestorOffset?: number ): void {
export function scrollAncestorsToShowTarget( target: HTMLElement | Range, ancestorOffset?: number, limiterElement?: HTMLElement ): void {
const targetParent = getParentElement( target );

scrollAncestorsToShowRect( {
parent: targetParent,
getRect: () => new Rect( target ),
ancestorOffset
ancestorOffset,
limiterElement
} );
}

Expand Down Expand Up @@ -291,27 +294,32 @@ function scrollWindowToShowRect<T extends boolean, U extends IfTrue<T>>(
* anyway.
* @param options.forceScroll When set `true`, the `rect` will be aligned to the top of scrollable ancestors
* whether it is already visible or not. This option will only work when `alignToTop` is `true`
* @param options.limiterElement The outermost ancestor that should be scrolled. Defaults to the `<body>` element.
*/
function scrollAncestorsToShowRect<T extends boolean, U extends IfTrue<T>>(
{
parent,
getRect,
alignToTop,
forceScroll,
ancestorOffset = 0
ancestorOffset = 0,
limiterElement
}: {
readonly parent: HTMLElement;
readonly getRect: () => Rect;
readonly alignToTop?: T;
readonly forceScroll?: U;
readonly ancestorOffset?: number;
readonly limiterElement?: HTMLElement;
}
): void {
const parentWindow = getWindow( parent );
const forceScrollToTop = alignToTop && forceScroll;
let parentRect: Rect, targetRect: Rect, targetFitsInTarget: boolean;

while ( parent != parentWindow.document.body ) {
const limiter = limiterElement || parentWindow.document.body;

while ( parent != limiter ) {
targetRect = getRect();
parentRect = new Rect( parent ).excludeScrollbarsAndBorders();
targetFitsInTarget = parentRect.contains( targetRect );
Expand Down
18 changes: 18 additions & 0 deletions packages/ckeditor5-utils/tests/dom/scroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ describe( 'scrollAncestorsToShowTarget()', () => {
assertScrollPosition( document.body, { scrollLeft: 1000, scrollTop: 1000 } );
} );

it( 'should not change the scroll of the ancestors of the given limiter', () => {
stubGeometry( testUtils, target, { top: 25, right: 75, bottom: 75, left: 25, width: 50, height: 50 } );

scrollAncestorsToShowTarget( target, 0, firstAncestor );

assertScrollPosition( firstAncestor, { scrollTop: 100, scrollLeft: 100 } );
assertScrollPosition( secondAncestor, { scrollTop: 100, scrollLeft: 100 } );
} );

it( 'should set #scrollTop and #scrollLeft of the ancestor to show the target (above)', () => {
stubGeometry( testUtils, target, { top: -100, right: 75, bottom: 0, left: 25, width: 50, height: 100 } );

Expand Down Expand Up @@ -171,6 +180,15 @@ describe( 'scrollAncestorsToShowTarget()', () => {
assertScrollPosition( document.body, { scrollLeft: 1000, scrollTop: 1000 } );
} );

it( 'should not change the scroll of the ancestors of the given limiter', () => {
stubGeometry( testUtils, target, { top: 25, right: 75, bottom: 75, left: 25, width: 50, height: 50 } );

scrollAncestorsToShowTarget( target, 20, firstAncestor );

assertScrollPosition( firstAncestor, { scrollTop: 100, scrollLeft: 100 } );
assertScrollPosition( secondAncestor, { scrollTop: 100, scrollLeft: 100 } );
} );

it( 'should set #scrollTop and #scrollLeft of the ancestor to show the target (above)', () => {
stubGeometry( testUtils, target, { top: -100, right: 75, bottom: 0, left: 25, width: 50, height: 100 } );

Expand Down

0 comments on commit a411cd7

Please sign in to comment.