]>
Commit | Line | Data |
---|---|---|
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' | |
7 | ||
8 | const logger = debug('peertube:main:ScrollService') | |
9 | ||
10 | @Injectable() | |
11 | export class ScrollService { | |
12 | ||
13 | private resetScroll = true | |
14 | ||
15 | constructor ( | |
16 | private viewportScroller: ViewportScroller, | |
17 | private peertubeRouter: PeerTubeRouterService | |
18 | ) { } | |
19 | ||
20 | enableScrollRestoration () { | |
21 | // We'll manage scroll restoration ourselves | |
22 | this.viewportScroller.setHistoryScrollRestoration('manual') | |
23 | ||
24 | this.consumeScroll() | |
25 | this.produceScroll() | |
26 | } | |
27 | ||
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 ]) => { | |
32 | try { | |
33 | this.resetScroll = false | |
34 | ||
35 | const previousUrl = new URL(window.location.origin + e1.urlAfterRedirects) | |
36 | const nextUrl = new URL(window.location.origin + e2.urlAfterRedirects) | |
37 | ||
38 | if (previousUrl.pathname !== nextUrl.pathname) { | |
39 | this.resetScroll = true | |
40 | return | |
41 | } | |
42 | ||
43 | if (this.peertubeRouter.hasRouteSetting(RouterSetting.DISABLE_SCROLL_RESTORE)) { | |
44 | this.resetScroll = false | |
45 | return | |
46 | } | |
47 | ||
48 | // Remove route settings from the comparison | |
49 | const nextSearchParams = nextUrl.searchParams | |
50 | nextSearchParams.delete(PeerTubeRouterService.ROUTE_SETTING_NAME) | |
51 | ||
52 | const previousSearchParams = previousUrl.searchParams | |
53 | ||
54 | nextSearchParams.sort() | |
55 | previousSearchParams.sort() | |
56 | ||
57 | if (nextSearchParams.toString() !== previousSearchParams.toString()) { | |
58 | this.resetScroll = true | |
59 | } | |
60 | } catch (e) { | |
61 | console.error('Cannot parse URL to check next scroll.', e) | |
62 | this.resetScroll = true | |
63 | } | |
64 | }) | |
65 | } | |
66 | ||
67 | private consumeScroll () { | |
68 | // Handle anchors/restore position | |
69 | this.peertubeRouter.getScrollEvents().subscribe(e => { | |
70 | logger('Will schedule scroll after router event %o.', e) | |
71 | ||
72 | // scrollToAnchor first to preserve anchor position when using history navigation | |
73 | if (e.anchor) { | |
74 | setTimeout(() => this.viewportScroller.scrollToAnchor(e.anchor)) | |
75 | ||
76 | return | |
77 | } | |
78 | ||
79 | if (e.position) { | |
80 | setTimeout(() => this.viewportScroller.scrollToPosition(e.position)) | |
81 | ||
82 | return | |
83 | } | |
84 | ||
85 | if (this.resetScroll) { | |
86 | return this.viewportScroller.scrollToPosition([ 0, 0 ]) | |
87 | } | |
88 | }) | |
89 | } | |
90 | ||
91 | } |