diff options
Diffstat (limited to 'client/src/app/core/routing/scroll.service.ts')
-rw-r--r-- | client/src/app/core/routing/scroll.service.ts | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/client/src/app/core/routing/scroll.service.ts b/client/src/app/core/routing/scroll.service.ts new file mode 100644 index 000000000..bd5076502 --- /dev/null +++ b/client/src/app/core/routing/scroll.service.ts | |||
@@ -0,0 +1,91 @@ | |||
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 | } | ||