Automattic / Automattic/jetpack
Infinite scroll: URL updated on scroll when paused
- Dominant language
- PHP
- Stars
- 1.8k
- Forks
- 898
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 774
Description
### Impacted plugin
Jetpack
### Steps to Reproduce
1. Visit a website with infinite scroll enabled.
2. Open the developer tools console.
3. Pause infinite-scroll with the provided method `infiniteScroll.scroller.pause();`.
4. Change the browser URL with `history.pushState({}, 'About', './about');` or method of choice.
5. Scroll (browser URL will be reset).
### A clear and concise description of what you expected to happen.
Most functionality is in fact paused when using the provided `scroller.pause() method`.
For example, [the refresh method](https://github.com/Automattic/jetpack/blob/trunk/projects/plugins/jetpack/modules/infinite-scroll/infinity.js#L303) is paused since it has a check for `this.disabled` which the `infiniteScroll.scroller.pause();` sets.
Since infinite scroll is paused, the browser URL update should not occur when custom `history.pushState()` is used while it is paused and the custom browser URL should stay until `infiniteScroll.scroller.resume();` is called.
### What actually happened
While paused and custom code triggers `history.pushState()`, the URL gets updated/reset once any scroll action occurs.
### Browser
Google Chrome/Chromium, Mozilla Firefox, Apple Safari
### Other information
The source of the issue is here:
https://github.com/Automattic/jetpack/blob/a5df28bc939057e720557f6ee79892cb0c5eb20e/projects/plugins/jetpack/modules/infinite-scroll/infinity.js#L78-L88
Specifically the call to `self.determineURL();`
A possible solution would be to check for `this.disabled` before doing most of the things inside the `determineURL()` method, similar to what is done in the [.refresh() method](https://github.com/Automattic/jetpack/blob/a5df28bc939057e720557f6ee79892cb0c5eb20e/projects/plugins/jetpack/modules/infinite-scroll/infinity.js#L310-L313).
Example:
```js
Scroller.prototype.determineURL = function () {
var self = this,
pageNum = -1,
currentFullScreenState = fullscreenState(),
wrapperEls,
maxFactor = 0;
if ( this.disabled ) {
return;
}
// xor - check if the state has changed
if ( previousFullScrenState ^ currentFullScreenState ) {
```
Edited the [infinity.js source file](https://github.com/Automattic/jetpack/blob/trunk/projects/plugins/jetpack/modules/infinite-scroll/infinity.js) with that edit and works as expected.
## Use case
Trying to implement an "expand single article" from the infinite scroll temporarily with a preview. User engagement is to scroll to read the rest of the article. Once the article is no longer on screen, the scroller `.resume()` method is triggered so everything goes back to normal.
### Platform (Simple, Atomic, or both?)
_No response_
### Reproducibility
Consistent
### Severity
_No response_
### Available workarounds?
Yes, difficult/complicated to implement.
### Workaround details
One override that isn't too obvious is to toggle the property/setting `infiniteScroll.scroller.throttle` between false/true but it needs to be done inside the scroll event but through a callback so that `.removeEventListener()` can be used.
Example:
```js
const toggleScrollerThrottle = function () {
infiniteScroll.scroller.throttle = !infiniteScroll.scroller.throttle;
};
window.addEventListener('scroll', toggleScrollerThrottle);
// ... Do rest of code like history.pushState({}, 'About', './about');
window.removeEventListener('scroll', toggleScrollerThrottle);
```
Contributor guide
Research direction
Start in projects/plugins/jetpack/modules/infinite-scroll/infinity.js, especially the scroll handler around the linked determineURL() call and the disabled check in refresh(). Reproduce the issue with scroller.pause(), history.pushState(), and a scroll event. Done means the custom URL remains while paused and normal URL behavior resumes after scroller.resume().
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100