diff --git a/apps/block_scout_web/assets/js/pages/block.js b/apps/block_scout_web/assets/js/pages/block.js index 4a9a9d9a3a..17cf0eec5a 100644 --- a/apps/block_scout_web/assets/js/pages/block.js +++ b/apps/block_scout_web/assets/js/pages/block.js @@ -3,7 +3,7 @@ import URI from 'urijs' import humps from 'humps' import socket from '../socket' import { updateAllAges } from '../lib/from_now' -import { initRedux } from '../utils' +import { initRedux, prependWithClingBottom } from '../utils' export const initialState = { beyondPageOne: null, @@ -58,25 +58,7 @@ if ($blockListPage.length) { if (state.channelDisconnected) $channelDisconnected.show() if (oldState.newBlock !== state.newBlock) { - const fromBottom = document.body.scrollHeight - window.scrollY - let clingBottomAnimationFrame - let expectedScrollPosition = window.scrollY - function clingBottom () { - if (expectedScrollPosition !== window.scrollY) return stopCling() - - expectedScrollPosition = document.body.scrollHeight - fromBottom - $(window).scrollTop(expectedScrollPosition) - clingBottomAnimationFrame = requestAnimationFrame(clingBottom) - } - function stopCling () { - cancelAnimationFrame(clingBottomAnimationFrame) - $blocksList.off('animationend animationcancel', stopCling) - } - if (window.scrollY > $blocksList.offset().top) { - clingBottomAnimationFrame = requestAnimationFrame(clingBottom) - $blocksList.on('animationend animationcancel', stopCling) - } - $blocksList.prepend(state.newBlock) + prependWithClingBottom($blocksList, state.newBlock) updateAllAges() } } diff --git a/apps/block_scout_web/assets/js/utils.js b/apps/block_scout_web/assets/js/utils.js index 152718aa37..d1212b2e22 100644 --- a/apps/block_scout_web/assets/js/utils.js +++ b/apps/block_scout_web/assets/js/utils.js @@ -1,3 +1,4 @@ +import $ from 'jquery' import _ from 'lodash' import { createStore } from 'redux' @@ -32,3 +33,40 @@ export function initRedux (reducer, { main, render, debug } = {}) { } if (main) main(store) } + +export function prependWithClingBottom ($el, content) { + function userAtTop () { + return window.scrollY < $el.offset().top + } + if (userAtTop()) return $el.prepend(content) + + let isAnimating + function setIsAnimating () { + isAnimating = true + } + $el.on('animationstart', setIsAnimating) + + let expectedScrollPosition = window.scrollY + function userIsScrolling () { + return expectedScrollPosition !== window.scrollY + } + + const clingDistanceFromBottom = document.body.scrollHeight - window.scrollY + let clingBottomLoop = window.requestAnimationFrame(function clingBottom () { + if (userIsScrolling()) return stopClinging() + + expectedScrollPosition = document.body.scrollHeight - clingDistanceFromBottom + $(window).scrollTop(expectedScrollPosition) + clingBottomLoop = window.requestAnimationFrame(clingBottom) + }) + + function stopClinging () { + window.cancelAnimationFrame(clingBottomLoop) + $el.off('animationstart', setIsAnimating) + $el.off('animationend animationcancel', stopClinging) + } + $el.on('animationend animationcancel', stopClinging) + setTimeout(() => !isAnimating && stopClinging(), 100) + + return $el.prepend(content) +}