1 import * as debug from 'debug'
2 import { pairwise } from 'rxjs'
3 import { ViewportScroller } from '@angular/common'
4 import { Injectable } from '@angular/core'
5 import { RouterSetting } from '../'
6 import { PeerTubeRouterService } from './peertube-router.service'
8 const logger = debug('peertube:main:ScrollService')
11 export class ScrollService {
13 private resetScroll = true
16 private viewportScroller: ViewportScroller,
17 private peertubeRouter: PeerTubeRouterService
20 enableScrollRestoration () {
21 // We'll manage scroll restoration ourselves
22 this.viewportScroller.setHistoryScrollRestoration('manual')
28 private produceScroll () {
29 // When we add the a-state parameter, we don't want to alter the scroll
30 this.peertubeRouter.getNavigationEndEvents().pipe(pairwise())
31 .subscribe(([ e1, e2 ]) => {
33 this.resetScroll = false
35 const previousUrl = new URL(window.location.origin + e1.urlAfterRedirects)
36 const nextUrl = new URL(window.location.origin + e2.urlAfterRedirects)
38 if (previousUrl.pathname !== nextUrl.pathname) {
39 this.resetScroll = true
43 if (this.peertubeRouter.hasRouteSetting(RouterSetting.DISABLE_SCROLL_RESTORE)) {
44 this.resetScroll = false
48 // Remove route settings from the comparison
49 const nextSearchParams = nextUrl.searchParams
50 nextSearchParams.delete(PeerTubeRouterService.ROUTE_SETTING_NAME)
52 const previousSearchParams = previousUrl.searchParams
54 nextSearchParams.sort()
55 previousSearchParams.sort()
57 if (nextSearchParams.toString() !== previousSearchParams.toString()) {
58 this.resetScroll = true
61 console.error('Cannot parse URL to check next scroll.', e)
62 this.resetScroll = true
67 private consumeScroll () {
68 // Handle anchors/restore position
69 this.peertubeRouter.getScrollEvents().subscribe(e => {
70 logger('Will schedule scroll after router event %o.', { e, resetScroll: this.resetScroll })
72 // scrollToAnchor first to preserve anchor position when using history navigation
74 setTimeout(() => this.viewportScroller.scrollToAnchor(e.anchor))
80 setTimeout(() => this.viewportScroller.scrollToPosition(e.position))
85 if (this.resetScroll) {
86 return this.viewportScroller.scrollToPosition([ 0, 0 ])