Skip to content
This repository has been archived by the owner on Aug 1, 2024. It is now read-only.

Commit

Permalink
Correct hit detection for cases when the scroll container is not the …
Browse files Browse the repository at this point in the history
…body but the document body is not scrolled to (0,0).

RELNOTES: Hit-detection fixes for DragScrollSupport class.

PiperOrigin-RevId: 549321784
Change-Id: Ic45cdc01ec177cce4332b5c223281637a401a991
  • Loading branch information
Closure Team authored and copybara-github committed Jul 19, 2023
1 parent 5918355 commit b91ebf6
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 4 deletions.
32 changes: 28 additions & 4 deletions closure/goog/fx/dragscrollsupport.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,24 @@ goog.fx.DragScrollSupport = function(
*/
this.scrollDelta_ = new goog.math.Coordinate();

/**
* Whether the container actually represents the scrollable content instead of
* the parent of the scrollable content. For the entire page (BODY/HTML),
* the behavior for hit detection is different because we care about events
* relative to the viewport, which serves as the actual container.
* @private
* @const
*/
this.containerIsActuallyContent_ =
containerNode.tagName === 'BODY' || containerNode.tagName === 'HTML';

/**
* The container bounds.
* @type {goog.math.Rect}
* @private
*/
this.containerBounds_ = goog.style.getBounds(containerNode);
if (containerNode.tagName === 'BODY' || containerNode.tagName === 'HTML') {
if (this.containerIsActuallyContent_) {
var size = goog.dom.getViewportSize();
this.containerBounds_.height = size.height;
this.containerBounds_.width = size.width;
Expand Down Expand Up @@ -137,6 +148,12 @@ goog.fx.DragScrollSupport.TIMER_STEP_ = 50;
*/
goog.fx.DragScrollSupport.SCROLL_STEP_ = 8;

/**
* @type {!goog.math.Coordinate}
* @private
* @const
*/
goog.fx.DragScrollSupport.ORIGIN_COORDINATE_ = new goog.math.Coordinate(0, 0);

/**
* The suggested scrolling margin.
Expand Down Expand Up @@ -237,22 +254,29 @@ goog.fx.DragScrollSupport.prototype.onTick_ = function(event) {
*/
goog.fx.DragScrollSupport.prototype.onMouseMove = function(event) {
'use strict';
let eventOffset = this.containerIsActuallyContent_ ?
goog.fx.DragScrollSupport.ORIGIN_COORDINATE_ :
goog.dom.getDomHelper(this.containerNode_).getDocumentScroll();

/** @suppress {strictMissingProperties} Added to tighten compiler checks */
var deltaX = this.horizontalScrolling_ ?
this.calculateScrollDelta(
event.clientX, this.scrollBounds_.left, this.scrollBounds_.width) :
event.clientX + eventOffset.x, this.scrollBounds_.left,
this.scrollBounds_.width) :
0;
/** @suppress {strictMissingProperties} Added to tighten compiler checks */
var deltaY = this.calculateScrollDelta(
event.clientY, this.scrollBounds_.top, this.scrollBounds_.height);
event.clientY + eventOffset.y, this.scrollBounds_.top,
this.scrollBounds_.height);
this.scrollDelta_.x = deltaX;
this.scrollDelta_.y = deltaY;

// If the scroll data is 0 or the event fired outside of the
// bounds of the container node.
if ((!deltaX && !deltaY) ||
(this.constrainScroll_ &&
!this.isInContainerBounds_(event.clientX, event.clientY))) {
!this.isInContainerBounds_(
event.clientX + eventOffset.x, event.clientY + eventOffset.y))) {
this.scrollTimer_.stop();
} else if (!this.scrollTimer_.enabled) {
this.scrollTimer_.start();
Expand Down
57 changes: 57 additions & 0 deletions closure/goog/fx/dragscrollsupport_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,63 @@ testSuite({
dsc.dispose();
},

/** @suppress {visibility} suppression added to enable type checking */
testBodyScrollDragZeroMarginDivVContainer() {
const dsc = new DragScrollSupport(vContainerDiv);

document.body.setAttribute('style', 'height: 1500px;');
if (document.scrollingElement) {
document.scrollingElement.scrollTop = 20;
} else {
// IE doesn't have scrollingElement API.
window.scrollTo(0, 20);
}

// Set initial scroll state.
let scrollTop = 50;
vContainerDiv.scrollTop = scrollTop;

// Mouse move events are relative to the viewport, so this is (mostly) the
// same as the testDragZeroMarginDivVContainer test width adjust coordinates
events.fireMouseMoveEvent(vContainerDiv, new Coordinate(50, 50));
clock.tick(DragScrollSupport.TIMER_STEP_ + 1);
assertEquals(
'Mousing inside the vContainer should not trigger scrolling.',
scrollTop, vContainerDiv.scrollTop);
assertEquals(
'Scroll timer should not tick yet', 0, clock.getTimeoutsMade());

scrollTop = vContainerDiv.scrollTop;
events.fireMouseMoveEvent(vContainerDiv, new Coordinate(50, 110));
clock.tick(DragScrollSupport.TIMER_STEP_ + 1);
assertTrue(
'Mousing below the vContainer should trigger scrolling down.',
scrollTop < vContainerDiv.scrollTop);
scrollTop = vContainerDiv.scrollTop;
clock.tick(DragScrollSupport.TIMER_STEP_ + 1);
assertTrue(
'Mousing below the vContainer should trigger scrolling down.',
scrollTop < vContainerDiv.scrollTop);

scrollTop = vContainerDiv.scrollTop;
events.fireMouseMoveEvent(vContainerDiv, new Coordinate(50, 50));
clock.tick(DragScrollSupport.TIMER_STEP_ + 1);
assertEquals(
'Mousing inside the vContainer should stop scrolling.', scrollTop,
vContainerDiv.scrollTop);

clock.tick(DragScrollSupport.TIMER_STEP_ + 1);

dsc.dispose();
if (document.scrollingElement) {
document.scrollingElement.scrollTop = 0;
} else {
// IE doesn't have scrollingElement API.
window.scrollTo(0, 0);
}
document.body.removeAttribute('style');
},

/** @suppress {visibility} suppression added to enable type checking */
testDragZeroMarginDivHContainer() {
const dsc = new DragScrollSupport(hContainerDiv);
Expand Down

0 comments on commit b91ebf6

Please sign in to comment.