From dd24f1bb0a4b252e5342b251ba36853364da7b8e Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 19 Aug 2021 09:24:29 +0200 Subject: Add video filters to common video pages --- client/src/app/core/core.module.ts | 14 +++- .../src/app/core/routing/custom-reuse-strategy.ts | 6 +- client/src/app/core/routing/index.ts | 2 + .../app/core/routing/peertube-router.service.ts | 78 +++++++++++++++++++ client/src/app/core/routing/scroll.service.ts | 91 ++++++++++++++++++++++ 5 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 client/src/app/core/routing/peertube-router.service.ts create mode 100644 client/src/app/core/routing/scroll.service.ts (limited to 'client/src/app/core') diff --git a/client/src/app/core/core.module.ts b/client/src/app/core/core.module.ts index 3e2056481..04be0671c 100644 --- a/client/src/app/core/core.module.ts +++ b/client/src/app/core/core.module.ts @@ -14,7 +14,17 @@ import { throwIfAlreadyLoaded } from './module-import-guard' import { Notifier } from './notification' import { HtmlRendererService, LinkifierService, MarkdownService } from './renderer' import { RestExtractor, RestService } from './rest' -import { HomepageRedirectComponent, LoginGuard, MetaGuard, MetaService, RedirectService, UnloggedGuard, UserRightGuard } from './routing' +import { + HomepageRedirectComponent, + LoginGuard, + MetaGuard, + MetaService, + PeerTubeRouterService, + RedirectService, + ScrollService, + UnloggedGuard, + UserRightGuard +} from './routing' import { CanDeactivateGuard } from './routing/can-deactivate-guard.service' import { ServerConfigResolver } from './routing/server-config-resolver.service' import { ScopedTokensService } from './scoped-tokens' @@ -80,6 +90,8 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra PeerTubeSocket, ServerConfigResolver, CanDeactivateGuard, + PeerTubeRouterService, + ScrollService, MetaService, MetaGuard diff --git a/client/src/app/core/routing/custom-reuse-strategy.ts b/client/src/app/core/routing/custom-reuse-strategy.ts index c2510f1df..3000093a8 100644 --- a/client/src/app/core/routing/custom-reuse-strategy.ts +++ b/client/src/app/core/routing/custom-reuse-strategy.ts @@ -1,5 +1,7 @@ import { Injectable } from '@angular/core' import { ActivatedRouteSnapshot, DetachedRouteHandle, RouteReuseStrategy } from '@angular/router' +import { RouterSetting } from './' +import { PeerTubeRouterService } from './peertube-router.service' @Injectable() export class CustomReuseStrategy implements RouteReuseStrategy { @@ -78,6 +80,8 @@ export class CustomReuseStrategy implements RouteReuseStrategy { } private isReuseEnabled (route: ActivatedRouteSnapshot) { - return route.data.reuse?.enabled && route.queryParams['a-state'] + // Cannot use peertube router here because of cyclic router dependency + return route.data.reuse?.enabled && + !!(route.queryParams[PeerTubeRouterService.ROUTE_SETTING_NAME] & RouterSetting.REUSE_COMPONENT) } } diff --git a/client/src/app/core/routing/index.ts b/client/src/app/core/routing/index.ts index d0c688a2f..3b1690ecc 100644 --- a/client/src/app/core/routing/index.ts +++ b/client/src/app/core/routing/index.ts @@ -5,9 +5,11 @@ export * from './homepage-redirect.component' export * from './login-guard.service' export * from './menu-guard.service' export * from './meta-guard.service' +export * from './peertube-router.service' export * from './meta.service' export * from './preload-selected-modules-list' export * from './redirect.service' +export * from './scroll.service' export * from './server-config-resolver.service' export * from './unlogged-guard.service' export * from './user-right-guard.service' diff --git a/client/src/app/core/routing/peertube-router.service.ts b/client/src/app/core/routing/peertube-router.service.ts new file mode 100644 index 000000000..35716cc79 --- /dev/null +++ b/client/src/app/core/routing/peertube-router.service.ts @@ -0,0 +1,78 @@ +import { filter } from 'rxjs/operators' +import { Injectable } from '@angular/core' +import { ActivatedRoute, ActivatedRouteSnapshot, Event, NavigationEnd, Router, Scroll } from '@angular/router' +import { ServerService } from '../server' + +export const enum RouterSetting { + NONE = 0, + REUSE_COMPONENT = 1 << 0, + DISABLE_SCROLL_RESTORE = 1 << 1 +} + +@Injectable() +export class PeerTubeRouterService { + static readonly ROUTE_SETTING_NAME = 's' + + constructor ( + private route: ActivatedRoute, + private router: Router, + private server: ServerService + ) { } + + addRouteSetting (toAdd: RouterSetting) { + if (this.hasRouteSetting(toAdd)) return + + const current = this.getRouteSetting() + + this.setRouteSetting(current | toAdd) + } + + deleteRouteSetting (toDelete: RouterSetting) { + const current = this.getRouteSetting() + + this.setRouteSetting(current & ~toDelete) + } + + getRouteSetting (snapshot?: ActivatedRouteSnapshot) { + return (snapshot || this.route.snapshot).queryParams[PeerTubeRouterService.ROUTE_SETTING_NAME] + } + + setRouteSetting (value: number) { + let path = window.location.pathname + if (!path || path === '/') path = this.server.getHTMLConfig().instance.defaultClientRoute + + const queryParams = { [PeerTubeRouterService.ROUTE_SETTING_NAME]: value } + + this.router.navigate([ path ], { queryParams, replaceUrl: true, queryParamsHandling: 'merge' }) + } + + hasRouteSetting (setting: RouterSetting, snapshot?: ActivatedRouteSnapshot) { + return !!(this.getRouteSetting(snapshot) & setting) + } + + getNavigationEndEvents () { + return this.router.events.pipe( + filter((e: Event): e is NavigationEnd => e instanceof NavigationEnd) + ) + } + + getScrollEvents () { + return this.router.events.pipe( + filter((e: Event): e is Scroll => e instanceof Scroll) + ) + } + + silentNavigate (baseRoute: string[], queryParams: { [id: string]: string }) { + let routeSetting = this.getRouteSetting() ?? RouterSetting.NONE + routeSetting |= RouterSetting.DISABLE_SCROLL_RESTORE + + queryParams = { + ...queryParams, + + [PeerTubeRouterService.ROUTE_SETTING_NAME]: routeSetting + } + + return this.router.navigate(baseRoute, { queryParams }) + } + +} 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 @@ +import * as debug from 'debug' +import { pairwise } from 'rxjs' +import { ViewportScroller } from '@angular/common' +import { Injectable } from '@angular/core' +import { RouterSetting } from '../' +import { PeerTubeRouterService } from './peertube-router.service' + +const logger = debug('peertube:main:ScrollService') + +@Injectable() +export class ScrollService { + + private resetScroll = true + + constructor ( + private viewportScroller: ViewportScroller, + private peertubeRouter: PeerTubeRouterService + ) { } + + enableScrollRestoration () { + // We'll manage scroll restoration ourselves + this.viewportScroller.setHistoryScrollRestoration('manual') + + this.consumeScroll() + this.produceScroll() + } + + private produceScroll () { + // When we add the a-state parameter, we don't want to alter the scroll + this.peertubeRouter.getNavigationEndEvents().pipe(pairwise()) + .subscribe(([ e1, e2 ]) => { + try { + this.resetScroll = false + + const previousUrl = new URL(window.location.origin + e1.urlAfterRedirects) + const nextUrl = new URL(window.location.origin + e2.urlAfterRedirects) + + if (previousUrl.pathname !== nextUrl.pathname) { + this.resetScroll = true + return + } + + if (this.peertubeRouter.hasRouteSetting(RouterSetting.DISABLE_SCROLL_RESTORE)) { + this.resetScroll = false + return + } + + // Remove route settings from the comparison + const nextSearchParams = nextUrl.searchParams + nextSearchParams.delete(PeerTubeRouterService.ROUTE_SETTING_NAME) + + const previousSearchParams = previousUrl.searchParams + + nextSearchParams.sort() + previousSearchParams.sort() + + if (nextSearchParams.toString() !== previousSearchParams.toString()) { + this.resetScroll = true + } + } catch (e) { + console.error('Cannot parse URL to check next scroll.', e) + this.resetScroll = true + } + }) + } + + private consumeScroll () { + // Handle anchors/restore position + this.peertubeRouter.getScrollEvents().subscribe(e => { + logger('Will schedule scroll after router event %o.', e) + + // scrollToAnchor first to preserve anchor position when using history navigation + if (e.anchor) { + setTimeout(() => this.viewportScroller.scrollToAnchor(e.anchor)) + + return + } + + if (e.position) { + setTimeout(() => this.viewportScroller.scrollToPosition(e.position)) + + return + } + + if (this.resetScroll) { + return this.viewportScroller.scrollToPosition([ 0, 0 ]) + } + }) + } + +} -- cgit v1.2.3