import { ComponentRef, Injectable } from '@angular/core' import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router' import { DisableForReuseHook } from './disable-for-reuse-hook' import { PeerTubeRouterService, RouterSetting } from './peertube-router.service' @Injectable() export class CustomReuseStrategy implements RouteReuseStrategy { storedRouteHandles = new Map() recentlyUsed: string private readonly MAX_SIZE = 2 // Decides if the route should be stored shouldDetach (route: ActivatedRouteSnapshot): boolean { return this.isReuseEnabled(route) } // Store the information for the route we're destructing store (route: ActivatedRouteSnapshot, handle: DetachedRouteHandle): void { if (!handle) return const key = this.generateKey(route) this.recentlyUsed = key console.log('Storing component %s to reuse later.', key) const componentRef = (handle as any).componentRef as ComponentRef componentRef.instance.disableForReuse() componentRef.changeDetectorRef.detectChanges() this.storedRouteHandles.set(key, handle) this.gb() } // Return true if we have a stored route object for the next route shouldAttach (route: ActivatedRouteSnapshot): boolean { const key = this.generateKey(route) return this.isReuseEnabled(route) && this.storedRouteHandles.has(key) } // If we returned true in shouldAttach(), now return the actual route data for restoration retrieve (route: ActivatedRouteSnapshot): DetachedRouteHandle { if (!this.isReuseEnabled(route)) return undefined const key = this.generateKey(route) this.recentlyUsed = key console.log('Reusing component %s.', key) const handle = this.storedRouteHandles.get(key) if (!handle) return handle; (handle as any).componentRef.instance.enabledForReuse() return handle } // Reuse the route if we're going to and from the same route shouldReuseRoute (future: ActivatedRouteSnapshot, curr: ActivatedRouteSnapshot): boolean { return future.routeConfig === curr.routeConfig && future.routeConfig?.data?.reloadOnSameNavigation !== true } private gb () { if (this.storedRouteHandles.size >= this.MAX_SIZE) { this.storedRouteHandles.forEach((r, key) => { if (key === this.recentlyUsed) return console.log('Removing stored component %s.', key); (r as any).componentRef.destroy() this.storedRouteHandles.delete(key) }) } } private generateKey (route: ActivatedRouteSnapshot) { const reuse = route.data.reuse if (!reuse) return undefined return reuse.key + JSON.stringify(route.queryParams) } private isReuseEnabled (route: ActivatedRouteSnapshot) { // Cannot use peertube router here because of cyclic router dependency return route.data.reuse?.enabled && !!(route.queryParams[PeerTubeRouterService.ROUTE_SETTING_NAME] & RouterSetting.REUSE_COMPONENT) } }