1 import { HotkeysService } from 'angular2-hotkeys'
2 import * as debug from 'debug'
3 import { switchMap } from 'rxjs/operators'
4 import { ViewportScroller } from '@angular/common'
5 import { Component, OnInit, ViewChild } from '@angular/core'
6 import { Router } from '@angular/router'
18 import { scrollToTop } from '@app/helpers'
19 import { LanguageChooserComponent } from '@app/menu/language-chooser.component'
20 import { QuickSettingsModalComponent } from '@app/modal/quick-settings-modal.component'
21 import { PeertubeModalService } from '@app/shared/shared-main/peertube-modal/peertube-modal.service'
22 import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap'
23 import { ServerConfig, UserRight, VideoConstant } from '@shared/models'
25 const logger = debug('peertube:menu:MenuComponent')
29 templateUrl: './menu.component.html',
30 styleUrls: ['./menu.component.scss']
32 export class MenuComponent implements OnInit {
33 @ViewChild('languageChooserModal', { static: true }) languageChooserModal: LanguageChooserComponent
34 @ViewChild('quickSettingsModal', { static: true }) quickSettingsModal: QuickSettingsModalComponent
35 @ViewChild('dropdown') dropdown: NgbDropdown
40 userHasAdminAccess = false
43 videoLanguages: string[] = []
46 currentInterfaceLanguage: string
48 commonMenuLinks: MenuLink[] = []
50 private languages: VideoConstant<string>[] = []
51 private serverConfig: ServerConfig
52 private routesPerRight: { [role in UserRight]?: string } = {
53 [UserRight.MANAGE_USERS]: '/admin/users',
54 [UserRight.MANAGE_SERVER_FOLLOW]: '/admin/friends',
55 [UserRight.MANAGE_ABUSES]: '/admin/moderation/abuses',
56 [UserRight.MANAGE_VIDEO_BLACKLIST]: '/admin/moderation/video-blocks',
57 [UserRight.MANAGE_JOBS]: '/admin/jobs',
58 [UserRight.MANAGE_CONFIGURATION]: '/admin/config'
62 private viewportScroller: ViewportScroller,
63 private authService: AuthService,
64 private userService: UserService,
65 private serverService: ServerService,
66 private redirectService: RedirectService,
67 private hotkeysService: HotkeysService,
68 private screenService: ScreenService,
69 private menuService: MenuService,
70 private modalService: PeertubeModalService,
71 private router: Router
74 get isInMobileView () {
75 return this.screenService.isInMobileView()
78 get dropdownContainer () {
79 if (this.isInMobileView) return null
81 return 'body' as 'body'
85 return this.languageChooserModal.getCurrentLanguage()
89 return this.serverConfig.instance.name
93 this.serverConfig = this.serverService.getTmpConfig()
94 this.serverService.getConfig()
95 .subscribe(config => {
96 this.serverConfig = config
100 this.isLoggedIn = this.authService.isLoggedIn()
101 if (this.isLoggedIn === true) {
102 this.user = this.authService.getUser()
104 this.computeNSFWPolicy()
105 this.computeVideosLink()
108 this.computeAdminAccess()
110 this.currentInterfaceLanguage = this.languageChooserModal.getCurrentLanguage()
112 this.authService.loginChangedSource.subscribe(
114 if (status === AuthStatus.LoggedIn) {
115 this.isLoggedIn = true
116 this.user = this.authService.getUser()
118 this.computeAdminAccess()
119 this.computeVideosLink()
122 } else if (status === AuthStatus.LoggedOut) {
123 this.isLoggedIn = false
124 this.user = undefined
126 this.computeAdminAccess()
128 logger('Logged out.')
130 console.error('Unknown auth status: ' + status)
135 this.hotkeysService.cheatSheetToggle
136 .subscribe(isOpen => this.helpVisible = isOpen)
138 this.serverService.getVideoLanguages()
139 .subscribe(languages => {
140 this.languages = languages
142 this.authService.userInformationLoaded
143 .subscribe(() => this.buildUserLanguages())
146 this.modalService.openQuickSettingsSubject
147 .subscribe(() => this.openQuickSettings())
150 isRegistrationAllowed () {
151 return this.serverConfig.signup.allowed &&
152 this.serverConfig.signup.allowedForCurrentIP
155 getFirstAdminRightAvailable () {
156 const user = this.authService.getUser()
157 if (!user) return undefined
159 const adminRights = [
160 UserRight.MANAGE_USERS,
161 UserRight.MANAGE_SERVER_FOLLOW,
162 UserRight.MANAGE_ABUSES,
163 UserRight.MANAGE_VIDEO_BLACKLIST,
164 UserRight.MANAGE_JOBS,
165 UserRight.MANAGE_CONFIGURATION
168 for (const adminRight of adminRights) {
169 if (user.hasRight(adminRight)) {
177 getFirstAdminRouteAvailable () {
178 const right = this.getFirstAdminRightAvailable()
180 return this.routesPerRight[right]
183 logout (event: Event) {
184 event.preventDefault()
186 this.authService.logout()
187 // Redirect to home page
188 this.redirectService.redirectToHomepage()
191 openLanguageChooser () {
192 this.languageChooserModal.show()
195 openHotkeysCheatSheet () {
196 this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
199 openQuickSettings () {
200 this.quickSettingsModal.show()
204 if (!this.user) return
205 this.user.webTorrentEnabled = !this.user.webTorrentEnabled
207 this.userService.updateMyProfile({ webTorrentEnabled: this.user.webTorrentEnabled })
208 .subscribe(() => this.authService.refreshUserInformation())
211 langForLocale (localeId: string) {
212 if (localeId === '_unknown') return $localize`Unknown`
214 return this.languages.find(lang => lang.id === localeId).label
217 onActiveLinkScrollToAnchor (link: HTMLAnchorElement) {
218 const linkURL = link.getAttribute('href')
219 const linkHash = link.getAttribute('fragment')
221 // On same url without fragment restore top scroll position
222 if (!linkHash && this.router.url.includes(linkURL)) {
223 scrollToTop('smooth')
226 // On same url with fragment restore anchor scroll position
227 if (linkHash && this.router.url === linkURL) {
228 this.viewportScroller.scrollToAnchor(linkHash)
231 if (this.screenService.isInSmallView()) {
232 this.menuService.toggleMenu()
236 // Lock menu scroll when menu scroll to avoid fleeing / detached dropdown
237 onMenuScrollEvent () {
238 document.querySelector('menu').scrollTo(0, 0)
241 onDropdownOpenChange (opened: boolean) {
242 if (this.screenService.isInMobileView()) return
244 // Close dropdown when window scroll to avoid dropdown quick jump for re-position
245 const onWindowScroll = () => {
246 this.dropdown?.close()
247 window.removeEventListener('scroll', onWindowScroll)
251 window.addEventListener('scroll', onWindowScroll)
252 document.querySelector('menu').scrollTo(0, 0) // Reset menu scroll to easy lock
253 document.querySelector('menu').addEventListener('scroll', this.onMenuScrollEvent)
255 document.querySelector('menu').removeEventListener('scroll', this.onMenuScrollEvent)
259 private buildMenuLinks () {
260 this.commonMenuLinks = this.menuService.buildCommonLinks(this.serverConfig)
263 private buildUserLanguages () {
265 this.videoLanguages = []
269 if (!this.user.videoLanguages) {
270 this.videoLanguages = [$localize`any language`]
274 this.videoLanguages = this.user.videoLanguages
275 .map(locale => this.langForLocale(locale))
276 .map(value => value === undefined ? '?' : value)
279 private computeAdminAccess () {
280 const right = this.getFirstAdminRightAvailable()
282 this.userHasAdminAccess = right !== undefined
285 private computeVideosLink () {
286 this.authService.userInformationLoaded
288 switchMap(() => this.user.computeCanSeeVideosLink(this.userService.getMyVideoQuotaUsed()))
290 if (res === true) logger('User can see videos link.')
291 else logger('User cannot see videos link.')
295 private computeNSFWPolicy () {
297 this.nsfwPolicy = null
301 switch (this.user.nsfwPolicy) {
303 this.nsfwPolicy = $localize`hide`
307 this.nsfwPolicy = $localize`blur`
311 this.nsfwPolicy = $localize`display`