]>
Commit | Line | Data |
---|---|---|
1 | import { ComponentRef, Injectable } from '@angular/core' | |
2 | import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router' | |
3 | import { logger } from '@root-helpers/logger' | |
4 | import { DisableForReuseHook } from './disable-for-reuse-hook' | |
5 | import { PeerTubeRouterService, RouterSetting } from './peertube-router.service' | |
6 | ||
7 | @Injectable() | |
8 | export class CustomReuseStrategy implements RouteReuseStrategy { | |
9 | storedRouteHandles = new Map<string, DetachedRouteHandle>() | |
10 | recentlyUsed: string | |
11 | ||
12 | private readonly MAX_SIZE = 2 | |
13 | ||
14 | // Decides if the route should be stored | |
15 | shouldDetach (route: ActivatedRouteSnapshot): boolean { | |
16 | return this.isReuseEnabled(route) | |
17 | } | |
18 | ||
19 | // Store the information for the route we're destructing | |
20 | store (route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { | |
21 | if (!handle) return | |
22 | ||
23 | const key = this.generateKey(route) | |
24 | this.recentlyUsed = key | |
25 | ||
26 | logger.info(`Storing component ${key} to reuse later.`) | |
27 | ||
28 | const componentRef = (handle as any).componentRef as ComponentRef<DisableForReuseHook> | |
29 | componentRef.instance.disableForReuse() | |
30 | componentRef.changeDetectorRef.detectChanges() | |
31 | ||
32 | this.storedRouteHandles.set(key, handle) | |
33 | ||
34 | this.gb() | |
35 | } | |
36 | ||
37 | // Return true if we have a stored route object for the next route | |
38 | shouldAttach (route: ActivatedRouteSnapshot): boolean { | |
39 | const key = this.generateKey(route) | |
40 | return this.isReuseEnabled(route) && this.storedRouteHandles.has(key) | |
41 | } | |
42 | ||
43 | // If we returned true in shouldAttach(), now return the actual route data for restoration | |
44 | retrieve (route: ActivatedRouteSnapshot): DetachedRouteHandle { | |
45 | if (!this.isReuseEnabled(route)) return undefined | |
46 | ||
47 | const key = this.generateKey(route) | |
48 | this.recentlyUsed = key | |
49 | ||
50 | logger.info(`Reusing component ${key}.`) | |
51 | ||
52 | const handle = this.storedRouteHandles.get(key) | |
53 | if (!handle) return handle; | |
54 | ||
55 | (handle as any).componentRef.instance.enabledForReuse() | |
56 | ||
57 | return handle | |
58 | } | |
59 | ||
60 | // Reuse the route if we're going to and from the same route | |
61 | shouldReuseRoute (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { | |
62 | return future.routeConfig === curr.routeConfig && future.routeConfig?.data?.reloadOnSameNavigation !== true | |
63 | } | |
64 | ||
65 | private gb () { | |
66 | if (this.storedRouteHandles.size >= this.MAX_SIZE) { | |
67 | this.storedRouteHandles.forEach((r, key) => { | |
68 | if (key === this.recentlyUsed) return | |
69 | ||
70 | logger.info(`Removing stored component ${key}`); | |
71 | ||
72 | (r as any).componentRef.destroy() | |
73 | this.storedRouteHandles.delete(key) | |
74 | }) | |
75 | } | |
76 | } | |
77 | ||
78 | private generateKey (route: ActivatedRouteSnapshot) { | |
79 | const reuse = route.data.reuse | |
80 | if (!reuse) return undefined | |
81 | ||
82 | return reuse.key + JSON.stringify(route.queryParams) | |
83 | } | |
84 | ||
85 | private isReuseEnabled (route: ActivatedRouteSnapshot) { | |
86 | // Cannot use peertube router here because of cyclic router dependency | |
87 | return route.data.reuse?.enabled && | |
88 | !!(route.queryParams[PeerTubeRouterService.ROUTE_SETTING_NAME] & RouterSetting.REUSE_COMPONENT) | |
89 | } | |
90 | } |