<h1 class="sr-only" i18n>Settings</h1>
<div class="form-row"> <!-- preview -->
- <div class="anchor" id="top"></div> <!-- top anchor -->
-
<div class="form-group col-12 col-lg-4 col-xl-3"></div>
<div class="form-group form-group-right col-12 col-lg-8 col-xl-9">
// scrollToAnchor first to preserve anchor position when using history navigation
if (e.anchor) {
setTimeout(() => {
- this.viewportScroller.scrollToAnchor(e.anchor)
+ document.getElementById(e.anchor).scrollIntoView({ behavior: 'smooth', inline: 'nearest' })
})
return
<a
i18n-title title="Update your notification preferences" class="glyphicon glyphicon-cog"
routerLink="/my-account/settings" fragment="notifications"
+ #settingsNotifications (click)="onNavigate(settingsNotifications)"
></a>
</div>
</div>
[markAllAsReadSubject]="markAllAsReadSubject" (notificationsLoaded)="onNotificationLoaded()"
></my-user-notifications>
- <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications">
+ <a *ngIf="loaded" class="all-notifications" routerLink="/my-account/notifications" #notifications (click)="onNavigate(notifications)">
<my-global-icon class="mr-1" iconName="inbox-full" aria-hidden="true"></my-global-icon>
<span i18n>See all your notifications</span>
</a>
import { Subject, Subscription } from 'rxjs'
import { filter } from 'rxjs/operators'
-import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'
+import { Component, EventEmitter, Input, Output, OnDestroy, OnInit, ViewChild } from '@angular/core'
import { NavigationEnd, Router } from '@angular/router'
import { Notifier, User, UserNotificationSocket } from '@app/core'
import { UserNotificationService } from '@app/shared/shared-main'
@ViewChild('popover', { static: true }) popover: NgbPopover
@Input() user: User
+ @Output() navigate = new EventEmitter<HTMLAnchorElement>()
unreadNotifications = 0
loaded = false
this.loaded = true
}
+ onNavigate (link: HTMLAnchorElement) {
+ this.navigate.emit(link)
+ }
+
markAllAsRead () {
this.markAllAsReadSubject.next(true)
}
<menu [ngClass]="{ 'logged-in': isLoggedIn }">
<div class="top-menu">
<div *ngIf="isLoggedIn" class="logged-in-block">
- <my-avatar-notification [user]="user"></my-avatar-notification>
+ <my-avatar-notification [user]="user" (navigate)="onSameUrlRestoreScrollPosition($event)"></my-avatar-notification>
<div class="logged-in-info">
<a *ngIf="user.account" [routerLink]="[ '/accounts', user.account.nameWithHost ]" class="logged-in-display-name">{{ user.account?.displayName }}</a>
<div class="dropdown-divider"></div>
- <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="top">
+ <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
+ #settingsLink (click)="onSameUrlRestoreScrollPosition(settingsLink)">
<my-global-icon iconName="user" aria-hidden="true"></my-global-icon> <ng-container i18n>Account settings</ng-container>
</a>
- <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/video-channels">
+ <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/video-channels"
+ #channelsLink (click)="onSameUrlRestoreScrollPosition(channelsLink)">
<my-global-icon iconName="channel" aria-hidden="true"></my-global-icon> <ng-container i18n>Channels settings</ng-container>
</a>
<span class="ml-auto text-muted">{{ language }}</span>
</a>
- <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles">
+ <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-languages-subtitles"
+ #settingsLanguagesSubtitles (click)="onSameUrlRestoreScrollPosition(settingsLanguagesSubtitles)">
<my-global-icon iconName="video-lang" aria-hidden="true"></my-global-icon>
<span i18n>Videos:</span>
<span class="ml-auto text-muted">{{ videoLanguages.join(', ') }}</span>
</a>
- <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="video-sensitive-content-policy">
+ <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
+ fragment="video-sensitive-content-policy" #settingsSensitiveContentPolicy
+ (click)="onSameUrlRestoreScrollPosition(settingsSensitiveContentPolicy)">
<my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy === 'display' }" iconName="sensitive" aria-hidden="true"></my-global-icon>
<my-global-icon class="hover-display-toggle" [ngClass]="{ 'not-displayed': user.nsfwPolicy !== 'display' }" iconName="unsensitive" aria-hidden="true"></my-global-icon>
<span i18n>Sensitive:</span>
<input type="checkbox" [checked]="user.webTorrentEnabled"/><label class="ml-auto" for="switch">Toggle p2p</label>
</a>
- <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings" fragment="top">
+ <a ngbDropdownItem ngbDropdownToggle class="dropdown-item" routerLink="/my-account/settings"
+ #settingsMoreLink (click)="onSameUrlRestoreScrollPosition(settingsMoreLink)">
<my-global-icon iconName="more-horizontal" aria-hidden="true"></my-global-icon> <ng-container i18n>More account settings</ng-container>
</a>
import * as debug from 'debug'
import { switchMap } from 'rxjs/operators'
import { Component, OnInit, ViewChild } from '@angular/core'
-import { AuthService, AuthStatus, AuthUser, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
+import { Router } from '@angular/router'
+import { AuthService, AuthStatus, AuthUser, MenuService, RedirectService, ScreenService, ServerService, UserService } from '@app/core'
import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
private serverService: ServerService,
private redirectService: RedirectService,
private hotkeysService: HotkeysService,
- private screenService: ScreenService
- ) { }
+ private screenService: ScreenService,
+ private menuService: MenuService,
+ private router: Router
+ ) { }
get isInMobileView () {
return this.screenService.isInMobileView()
return this.languages.find(lang => lang.id === localeId).label
}
+ onSameUrlRestoreScrollPosition (link: HTMLAnchorElement) {
+ const linkURL = link.getAttribute('href')
+ const linkHash = link.getAttribute('fragment')
+
+ // On same url without fragment restore top scroll position
+ if (!linkHash && this.router.url.includes(linkURL)) {
+ window.scrollTo({
+ left: 0,
+ top: 0,
+ behavior: 'smooth'
+ })
+ }
+
+ // On same url with fragment restore anchor scroll position
+ if (linkHash && this.router.url === linkURL) {
+ const anchor = document.getElementById(link.getAttribute('fragment'))
+ anchor.scrollIntoView({ behavior: 'smooth', inline: 'nearest' })
+ }
+
+ if (this.screenService.isInSmallView()) {
+ this.menuService.toggleMenu()
+ }
+ }
+
private buildUserLanguages () {
if (!this.user) {
this.videoLanguages = []
<div class="sub-menu" [ngClass]="{ 'sub-menu-fixed': !isBroadcastMessageDisplayed, 'no-scroll': isModalOpened }">
<ng-container *ngFor="let menuEntry of menuEntries; index as id">
- <a *ngIf="menuEntry.routerLink && isDisplayed(menuEntry)" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings">{{ menuEntry.label }}</a>
+ <a *ngIf="menuEntry.routerLink && isDisplayed(menuEntry)" [routerLink]="menuEntry.routerLink" routerLinkActive="active" class="title-page title-page-settings" #routerLink (click)="onActiveLinkScrollToTop(routerLink)">{{ menuEntry.label }}</a>
<div *ngIf="!menuEntry.routerLink && isDisplayed(menuEntry)" ngbDropdown class="parent-entry"
#dropdown="ngbDropdown" autoClose="true">
<ng-container *ngFor="let menuChild of menuEntry.children">
<a *ngIf="isDisplayed(menuChild)" class="dropdown-item"
[ngClass]="{ icon: hasIcons }"
- [routerLink]="menuChild.routerLink">
+ [routerLink]="menuChild.routerLink"
+ #routerLink (click)="onActiveLinkScrollToTop(routerLink)">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
{{ menuChild.label }}
<ng-container *ngFor="let menuChild of menuEntry.children">
<a *ngIf="isDisplayed(menuChild)"
[ngClass]="{ icon: hasIcons }"
- [routerLink]="menuChild.routerLink" routerLinkActive="active" (click)="dismissOtherModals()">
+ [routerLink]="menuChild.routerLink" routerLinkActive="active"
+ #routerLink (click)="dismissOtherModals(); onActiveLinkScrollToTop(routerLink)">
<my-global-icon *ngIf="menuChild.iconName" [iconName]="menuChild.iconName" aria-hidden="true"></my-global-icon>
{{ menuChild.label }}
this.isModalOpened = false
}
+ onActiveLinkScrollToTop (link: HTMLAnchorElement) {
+ if (!this.isBroadcastMessageDisplayed && this.router.url.includes(link.getAttribute('href'))) {
+ window.scrollTo({
+ left: 0,
+ top: 0,
+ behavior: 'smooth'
+ })
+ }
+ }
+
dismissOtherModals () {
this.modalService.dismissAll()
}