mirror of https://github.com/Chocobozzz/PeerTube
Allow to disable all hotkeys
Added angular2-hotkeys dependency inside PeerTube, to tweak some settings It will also allow us to support non latin keyboard in the future as we can choose the "mouse trap" dependencypull/6000/head
parent
e6b455b4ea
commit
50e415e12e
|
@ -195,7 +195,6 @@
|
|||
"path-browserify",
|
||||
"deep-merge",
|
||||
"escape-string-regexp",
|
||||
"mousetrap",
|
||||
"is-plain-object",
|
||||
"parse-srcset",
|
||||
"deepmerge",
|
||||
|
|
|
@ -84,7 +84,6 @@
|
|||
"@wdio/mocha-framework": "^8.10.4",
|
||||
"@wdio/shared-store-service": "^8.10.5",
|
||||
"@wdio/spec-reporter": "^8.10.5",
|
||||
"angular2-hotkeys": "^13.1.0",
|
||||
"angularx-qrcode": "16.0.0",
|
||||
"babel-loader": "^9.1.0",
|
||||
"bootstrap": "^5.1.3",
|
||||
|
@ -126,6 +125,7 @@
|
|||
"socket.io-client": "^4.5.4",
|
||||
"stylelint": "^15.1.0",
|
||||
"stylelint-config-sass-guidelines": "^10.0.0",
|
||||
"tinykeys": "^2.1.0",
|
||||
"ts-loader": "^9.3.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "^2.4.0",
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { catchError, distinctUntilChanged, map, switchMap } from 'rxjs/operators'
|
||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { AuthService, MarkdownService, Notifier, RestExtractor, ScreenService } from '@app/core'
|
||||
import { AuthService, MarkdownService, Notifier, RestExtractor, ScreenService, Hotkey, HotkeysService } from '@app/core'
|
||||
import { Account, ListOverflowItem, VideoChannel, VideoChannelService, VideoService } from '@app/shared/shared-main'
|
||||
import { BlocklistService } from '@app/shared/shared-moderation'
|
||||
import { SupportModalComponent } from '@app/shared/shared-support-modal'
|
||||
|
@ -77,12 +76,12 @@ export class VideoChannelsComponent implements OnInit, OnDestroy {
|
|||
})
|
||||
|
||||
this.hotkeys = [
|
||||
new Hotkey('S', (event: KeyboardEvent): boolean => {
|
||||
if (this.subscribeButton.subscribed) this.subscribeButton.unsubscribe()
|
||||
new Hotkey('Shift+s', () => {
|
||||
if (this.subscribeButton.isSubscribedToAll()) this.subscribeButton.unsubscribe()
|
||||
else this.subscribeButton.subscribe()
|
||||
|
||||
return false
|
||||
}, undefined, $localize`Subscribe to the account`)
|
||||
}, $localize`Subscribe to the account`)
|
||||
]
|
||||
if (this.isUserLoggedIn()) this.hotkeysService.add(this.hotkeys)
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { Observable } from 'rxjs'
|
||||
import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } from '@angular/core'
|
||||
import { Notifier, ScreenService } from '@app/core'
|
||||
import { Notifier, ScreenService, Hotkey, HotkeysService } from '@app/core'
|
||||
import { VideoDetails, VideoService } from '@app/shared/shared-main'
|
||||
import { UserVideoRateType } from '@peertube/peertube-models'
|
||||
|
||||
|
@ -41,15 +40,15 @@ export class VideoRateComponent implements OnInit, OnChanges, OnDestroy {
|
|||
|
||||
if (this.isUserLoggedIn) {
|
||||
this.hotkeys = [
|
||||
new Hotkey('shift+l', () => {
|
||||
new Hotkey('Shift+l', () => {
|
||||
this.setLike()
|
||||
return false
|
||||
}, undefined, $localize`Like the video`),
|
||||
}, $localize`Like the video`),
|
||||
|
||||
new Hotkey('shift+d', () => {
|
||||
new Hotkey('Shift+d', () => {
|
||||
this.setDislike()
|
||||
return false
|
||||
}, undefined, $localize`Dislike the video`)
|
||||
}, $localize`Dislike the video`)
|
||||
]
|
||||
|
||||
this.hotkeysService.add(this.hotkeys)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { forkJoin, map, Observable, of, Subscription, switchMap } from 'rxjs'
|
||||
import { PlatformLocation } from '@angular/common'
|
||||
import { Component, ElementRef, Inject, LOCALE_ID, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||
|
@ -13,6 +12,8 @@ import {
|
|||
RestExtractor,
|
||||
ScreenService,
|
||||
ServerService,
|
||||
Hotkey,
|
||||
HotkeysService,
|
||||
User,
|
||||
UserService
|
||||
} from '@app/core'
|
||||
|
@ -866,33 +867,33 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
|
||||
this.hotkeys = [
|
||||
// These hotkeys are managed by the player
|
||||
new Hotkey('f', e => e, undefined, $localize`Enter/exit fullscreen`),
|
||||
new Hotkey('space', e => e, undefined, $localize`Play/Pause the video`),
|
||||
new Hotkey('m', e => e, undefined, $localize`Mute/unmute the video`),
|
||||
new Hotkey('f', e => e, $localize`Enter/exit fullscreen`),
|
||||
new Hotkey('space', e => e, $localize`Play/Pause the video`),
|
||||
new Hotkey('m', e => e, $localize`Mute/unmute the video`),
|
||||
|
||||
new Hotkey('up', e => e, undefined, $localize`Increase the volume`),
|
||||
new Hotkey('down', e => e, undefined, $localize`Decrease the volume`),
|
||||
new Hotkey('up', e => e, $localize`Increase the volume`),
|
||||
new Hotkey('down', e => e, $localize`Decrease the volume`),
|
||||
|
||||
new Hotkey('t', e => {
|
||||
this.theaterEnabled = !this.theaterEnabled
|
||||
return false
|
||||
}, undefined, $localize`Toggle theater mode`)
|
||||
}, $localize`Toggle theater mode`)
|
||||
]
|
||||
|
||||
if (!video.isLive) {
|
||||
this.hotkeys = this.hotkeys.concat([
|
||||
// These hotkeys are also managed by the player but only for VOD
|
||||
|
||||
new Hotkey('0-9', e => e, undefined, $localize`Skip to a percentage of the video: 0 is 0% and 9 is 90%`),
|
||||
new Hotkey('0-9', e => e, $localize`Skip to a percentage of the video: 0 is 0% and 9 is 90%`),
|
||||
|
||||
new Hotkey('right', e => e, undefined, $localize`Seek the video forward`),
|
||||
new Hotkey('left', e => e, undefined, $localize`Seek the video backward`),
|
||||
new Hotkey('right', e => e, $localize`Seek the video forward`),
|
||||
new Hotkey('left', e => e, $localize`Seek the video backward`),
|
||||
|
||||
new Hotkey('>', e => e, undefined, $localize`Increase playback rate`),
|
||||
new Hotkey('<', e => e, undefined, $localize`Decrease playback rate`),
|
||||
new Hotkey('>', e => e, $localize`Increase playback rate`),
|
||||
new Hotkey('<', e => e, $localize`Decrease playback rate`),
|
||||
|
||||
new Hotkey(',', e => e, undefined, $localize`Navigate in the video to the previous frame`),
|
||||
new Hotkey('.', e => e, undefined, $localize`Navigate in the video to the next frame`)
|
||||
new Hotkey(',', e => e, $localize`Navigate in the video to the previous frame`),
|
||||
new Hotkey('.', e => e, $localize`Navigate in the video to the next frame`)
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -903,7 +904,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
|||
else this.subscribeButton.subscribe()
|
||||
|
||||
return false
|
||||
}, undefined, $localize`Subscribe to the account`)
|
||||
}, $localize`Subscribe to the account`)
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<a i18n class="visually-hidden-focusable skip-to-content" href="#content" (click)="$event.preventDefault(); mainContent.focus()">Skip to main content</a>
|
||||
|
||||
<my-hotkeys-cheatsheet (hotkeysModalStateChange)="onHotkeysModalStateChange($event)"></my-hotkeys-cheatsheet>
|
||||
<my-hotkeys-cheat-sheet (hotkeysModalStateChange)="onHotkeysModalStateChange($event)"></my-hotkeys-cheat-sheet>
|
||||
|
||||
<div
|
||||
class="peertube-container"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { delay, forkJoin } from 'rxjs'
|
||||
import { filter, first, map } from 'rxjs/operators'
|
||||
import { DOCUMENT, getLocaleDirection, PlatformLocation } from '@angular/common'
|
||||
|
@ -15,7 +14,9 @@ import {
|
|||
ServerService,
|
||||
ThemeService,
|
||||
User,
|
||||
UserLocalStorageService
|
||||
UserLocalStorageService,
|
||||
Hotkey,
|
||||
HotkeysService
|
||||
} from '@app/core'
|
||||
import { HooksService } from '@app/core/plugins/hooks.service'
|
||||
import { PluginService } from '@app/core/plugins/plugin.service'
|
||||
|
@ -313,40 +314,40 @@ export class AppComponent implements OnInit, AfterViewInit {
|
|||
|
||||
private initHotkeys () {
|
||||
this.hotkeysService.add([
|
||||
new Hotkey([ '/', 's' ], (event: KeyboardEvent): boolean => {
|
||||
new Hotkey([ '/', 's' ], () => {
|
||||
document.getElementById('search-video').focus()
|
||||
return false
|
||||
}, undefined, $localize`Focus the search bar`),
|
||||
}, $localize`Focus the search bar`),
|
||||
|
||||
new Hotkey('b', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('b', () => {
|
||||
this.menu.toggleMenu()
|
||||
return false
|
||||
}, undefined, $localize`Toggle the left menu`),
|
||||
}, $localize`Toggle the left menu`),
|
||||
|
||||
new Hotkey('g o', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('g o', () => {
|
||||
this.router.navigate([ '/videos/overview' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to the discover videos page`),
|
||||
}, $localize`Go to the discover videos page`),
|
||||
|
||||
new Hotkey('g t', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('g t', () => {
|
||||
this.router.navigate([ '/videos/trending' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to the trending videos page`),
|
||||
}, $localize`Go to the trending videos page`),
|
||||
|
||||
new Hotkey('g r', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('g r', () => {
|
||||
this.router.navigate([ '/videos/recently-added' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to the recently added videos page`),
|
||||
}, $localize`Go to the recently added videos page`),
|
||||
|
||||
new Hotkey('g l', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('g l', () => {
|
||||
this.router.navigate([ '/videos/local' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to the local videos page`),
|
||||
}, $localize`Go to the local videos page`),
|
||||
|
||||
new Hotkey('g u', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('g u', () => {
|
||||
this.router.navigate([ '/videos/upload' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to the videos upload page`)
|
||||
}, $localize`Go to the videos upload page`)
|
||||
])
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import { SharedGlobalIconModule } from './shared/shared-icons'
|
|||
import { SharedInstanceModule } from './shared/shared-instance'
|
||||
import { SharedMainModule } from './shared/shared-main'
|
||||
import { SharedUserInterfaceSettingsModule } from './shared/shared-user-settings'
|
||||
import { HotkeysCheatSheetComponent } from './hotkeys'
|
||||
|
||||
registerLocaleData(localeOc, 'oc')
|
||||
|
||||
|
@ -63,7 +64,9 @@ export function loadConfigFactory (server: ServerService, pluginService: PluginS
|
|||
CustomModalComponent,
|
||||
AdminWelcomeModalComponent,
|
||||
InstanceConfigWarningModalComponent,
|
||||
ConfirmComponent
|
||||
ConfirmComponent,
|
||||
|
||||
HotkeysCheatSheetComponent
|
||||
],
|
||||
|
||||
imports: [
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { Hotkey, HotkeysService } from '@app/core'
|
||||
import { Observable, ReplaySubject, Subject, throwError as observableThrowError } from 'rxjs'
|
||||
import { catchError, map, mergeMap, share, tap } from 'rxjs/operators'
|
||||
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http'
|
||||
|
@ -57,22 +57,22 @@ export class AuthService {
|
|||
|
||||
// Set HotKeys
|
||||
this.hotkeys = [
|
||||
new Hotkey('m s', (event: KeyboardEvent): boolean => {
|
||||
new Hotkey('m s', e => {
|
||||
this.router.navigate([ '/videos/subscriptions' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to my subscriptions`),
|
||||
new Hotkey('m v', (event: KeyboardEvent): boolean => {
|
||||
}, $localize`Go to my subscriptions`),
|
||||
new Hotkey('m v', e => {
|
||||
this.router.navigate([ '/my-library/videos' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to my videos`),
|
||||
new Hotkey('m i', (event: KeyboardEvent): boolean => {
|
||||
}, $localize`Go to my videos`),
|
||||
new Hotkey('m i', e => {
|
||||
this.router.navigate([ '/my-library/video-imports' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to my imports`),
|
||||
new Hotkey('m c', (event: KeyboardEvent): boolean => {
|
||||
}, $localize`Go to my imports`),
|
||||
new Hotkey('m c', e => {
|
||||
this.router.navigate([ '/my-library/video-channels' ])
|
||||
return false
|
||||
}, undefined, $localize`Go to my channels`)
|
||||
}, $localize`Go to my channels`)
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { HotkeyModule } from 'angular2-hotkeys'
|
||||
import { MessageService } from 'primeng/api'
|
||||
import { ToastModule } from 'primeng/toast'
|
||||
import { CommonModule } from '@angular/common'
|
||||
|
@ -8,7 +7,6 @@ import { PeerTubeSocket } from '@app/core/notification/peertube-socket.service'
|
|||
import { HooksService, PluginService } from '@app/core/plugins'
|
||||
import { AuthService } from './auth'
|
||||
import { ConfirmService } from './confirm'
|
||||
import { CheatSheetComponent } from './hotkeys'
|
||||
import { MenuService } from './menu'
|
||||
import { throwIfAlreadyLoaded } from './module-import-guard'
|
||||
import { Notifier } from './notification'
|
||||
|
@ -32,30 +30,23 @@ import { ServerService } from './server'
|
|||
import { ThemeService } from './theme'
|
||||
import { UserLocalStorageService, UserService } from './users'
|
||||
import { LocalStorageService, ScreenService, SessionStorageService } from './wrappers'
|
||||
import { HotkeysService } from './hotkeys'
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
BrowserAnimationsModule,
|
||||
|
||||
ToastModule,
|
||||
|
||||
HotkeyModule.forRoot({
|
||||
cheatSheetCloseEsc: true,
|
||||
cheatSheetDescription: $localize`Show/hide this help menu`,
|
||||
cheatSheetCloseEscDescription: $localize`Hide this help menu`
|
||||
})
|
||||
ToastModule
|
||||
],
|
||||
|
||||
declarations: [
|
||||
CheatSheetComponent,
|
||||
HomepageRedirectComponent
|
||||
],
|
||||
|
||||
exports: [
|
||||
ToastModule,
|
||||
|
||||
CheatSheetComponent,
|
||||
HomepageRedirectComponent
|
||||
],
|
||||
|
||||
|
@ -97,7 +88,9 @@ import { LocalStorageService, ScreenService, SessionStorageService } from './wra
|
|||
ScrollService,
|
||||
|
||||
MetaService,
|
||||
MetaGuard
|
||||
MetaGuard,
|
||||
|
||||
HotkeysService
|
||||
]
|
||||
})
|
||||
export class CoreModule {
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
// Thanks to https://github.com/brtnshrdr/angular2-hotkeys
|
||||
|
||||
import { arrayify } from '@peertube/peertube-core-utils'
|
||||
|
||||
export class Hotkey {
|
||||
private formattedHotkey: string[]
|
||||
|
||||
static symbolize (combo: string): string {
|
||||
const map: any = {
|
||||
command: '\u2318', // ⌘
|
||||
shift: '\u21E7', // ⇧
|
||||
left: '\u2190', // ←
|
||||
right: '\u2192', // →
|
||||
up: '\u2191', // ↑
|
||||
down: '\u2193', // ↓
|
||||
return: '\u23CE', // ⏎
|
||||
backspace: '\u232B' // ⌫
|
||||
}
|
||||
const comboSplit: string[] = combo.split('+')
|
||||
|
||||
for (let i = 0; i < comboSplit.length; i++) {
|
||||
// try to resolve command / ctrl based on OS:
|
||||
if (comboSplit[i] === 'mod') {
|
||||
if (window.navigator?.platform.includes('Mac')) {
|
||||
comboSplit[i] = 'command'
|
||||
} else {
|
||||
comboSplit[i] = 'ctrl'
|
||||
}
|
||||
}
|
||||
|
||||
comboSplit[i] = map[comboSplit[i]] || comboSplit[i]
|
||||
}
|
||||
|
||||
return comboSplit.join(' + ')
|
||||
}
|
||||
|
||||
constructor (
|
||||
public combo: string | string[],
|
||||
public callback: (event: KeyboardEvent, combo: string) => any | boolean,
|
||||
public description?: string | Function
|
||||
) {
|
||||
this.combo = arrayify(combo)
|
||||
this.description = description || ''
|
||||
}
|
||||
|
||||
get formatted (): string[] {
|
||||
if (!this.formattedHotkey) {
|
||||
const sequence: string[] = [ ...this.combo ]
|
||||
|
||||
for (let i = 0; i < sequence.length; i++) {
|
||||
sequence[i] = Hotkey.symbolize(sequence[i])
|
||||
}
|
||||
|
||||
this.formattedHotkey = sequence
|
||||
}
|
||||
|
||||
return this.formattedHotkey
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
import { Hotkey, HotkeysService } from 'angular2-hotkeys'
|
||||
import { Subscription } from 'rxjs'
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'my-hotkeys-cheatsheet',
|
||||
templateUrl: './hotkeys.component.html',
|
||||
styleUrls: [ './hotkeys.component.scss' ]
|
||||
})
|
||||
export class CheatSheetComponent implements OnInit, OnDestroy {
|
||||
@Input() title = $localize`Keyboard Shortcuts:`
|
||||
|
||||
@Output() hotkeysModalStateChange = new EventEmitter<boolean>()
|
||||
|
||||
helpVisible = false
|
||||
subscription: Subscription
|
||||
|
||||
hotkeys: Hotkey[]
|
||||
|
||||
constructor (
|
||||
private hotkeysService: HotkeysService
|
||||
) {}
|
||||
|
||||
public ngOnInit (): void {
|
||||
this.subscription = this.hotkeysService.cheatSheetToggle.subscribe((isOpen) => {
|
||||
if (isOpen !== false) {
|
||||
this.hotkeys = this.hotkeysService.hotkeys.filter(hotkey => hotkey.description)
|
||||
}
|
||||
|
||||
if (isOpen === false) {
|
||||
this.helpVisible = false
|
||||
} else {
|
||||
this.toggleHelpVisible()
|
||||
}
|
||||
|
||||
this.hotkeysModalStateChange.emit(this.helpVisible)
|
||||
})
|
||||
}
|
||||
|
||||
public ngOnDestroy (): void {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
public toggleCheatSheet (): void {
|
||||
this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
|
||||
}
|
||||
|
||||
public toggleHelpVisible (): void {
|
||||
this.helpVisible = !this.helpVisible
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
// Thanks to https://github.com/brtnshrdr/angular2-hotkeys
|
||||
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Hotkey } from './hotkey.model'
|
||||
import { Subject } from 'rxjs'
|
||||
import { tinykeys } from 'tinykeys'
|
||||
import debug from 'debug'
|
||||
|
||||
const debugLogger = debug('peertube:hotkeys')
|
||||
|
||||
@Injectable()
|
||||
export class HotkeysService {
|
||||
cheatSheetToggle = new Subject<boolean>()
|
||||
|
||||
private hotkeys: Hotkey[] = []
|
||||
private preventIn = [ 'INPUT', 'SELECT', 'TEXTAREA' ]
|
||||
|
||||
private disabled = false
|
||||
|
||||
private removeTinyKeysStore = new Map<Hotkey, (() => void)[]>()
|
||||
|
||||
constructor () {
|
||||
this.initCheatSheet()
|
||||
}
|
||||
|
||||
private initCheatSheet () {
|
||||
debugLogger('Init hotkeys')
|
||||
|
||||
this.add([
|
||||
new Hotkey(
|
||||
[ '?', 'Shift+?' ],
|
||||
() => this.cheatSheetToggle.next(undefined),
|
||||
$localize`Show / hide this help menu`
|
||||
),
|
||||
|
||||
new Hotkey(
|
||||
'escape',
|
||||
() => this.cheatSheetToggle.next(false),
|
||||
$localize`Hide this help menu`
|
||||
)
|
||||
])
|
||||
}
|
||||
|
||||
add (hotkey: Hotkey): Hotkey
|
||||
add (hotkey: Hotkey[]): Hotkey[]
|
||||
add (hotkey: Hotkey | Hotkey[]): Hotkey[] | Hotkey {
|
||||
if (Array.isArray(hotkey)) {
|
||||
return hotkey.map(h => this.add(h))
|
||||
}
|
||||
|
||||
this.remove(hotkey)
|
||||
this.hotkeys.push(hotkey)
|
||||
|
||||
for (const combo of hotkey.combo) {
|
||||
debugLogger('Adding hotkey ' + hotkey.formatted)
|
||||
|
||||
const removeTinyKey = tinykeys(window, {
|
||||
[combo]: event => {
|
||||
if (this.disabled) return
|
||||
|
||||
const target = event.target as Element
|
||||
const nodeName: string = target.nodeName.toUpperCase()
|
||||
|
||||
if (this.preventIn.includes(nodeName)) {
|
||||
return
|
||||
}
|
||||
|
||||
const result = hotkey.callback.apply(this, [ event, combo ])
|
||||
|
||||
if (result === false) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (!this.removeTinyKeysStore.has(hotkey)) {
|
||||
this.removeTinyKeysStore.set(hotkey, [])
|
||||
}
|
||||
|
||||
this.removeTinyKeysStore.get(hotkey).push(removeTinyKey)
|
||||
}
|
||||
|
||||
return hotkey
|
||||
}
|
||||
|
||||
remove (hotkey: Hotkey | Hotkey[]) {
|
||||
if (Array.isArray(hotkey)) {
|
||||
for (const h of hotkey) {
|
||||
this.remove(h)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.hotkeys = this.hotkeys.filter(h => h !== hotkey)
|
||||
const removeHandlers = this.removeTinyKeysStore.get(hotkey)
|
||||
|
||||
if (removeHandlers) {
|
||||
debugLogger('Removing hotkey ' + hotkey.formatted)
|
||||
|
||||
for (const removeHandler of removeHandlers) {
|
||||
removeHandler()
|
||||
}
|
||||
}
|
||||
|
||||
this.removeTinyKeysStore.delete(hotkey)
|
||||
}
|
||||
|
||||
getHotkeys () {
|
||||
return this.hotkeys
|
||||
}
|
||||
|
||||
disableHotkeys () {
|
||||
this.disabled = true
|
||||
}
|
||||
|
||||
enableHotkeys () {
|
||||
this.disabled = false
|
||||
}
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
export * from './hotkeys.component'
|
||||
export * from './hotkey.model'
|
||||
export * from './hotkeys.service'
|
||||
|
|
|
@ -2,6 +2,13 @@
|
|||
<div class="cfp-hotkeys">
|
||||
<h1 class="cfp-hotkeys-title">{{ title }}</h1>
|
||||
|
||||
<div class="d-flex justify-content-center m-3">
|
||||
<my-peertube-checkbox
|
||||
inputName="enable-hotkeys" [(ngModel)]="hotkeysEnabled" (ngModelChange)="onHotkeysEnabledChange()"
|
||||
i18n-labelText labelText="Enable hotkeys in this web browser"
|
||||
></my-peertube-checkbox>
|
||||
</div>
|
||||
|
||||
<ul role="presentation">
|
||||
<li *ngFor="let hotkey of hotkeys">
|
||||
<div class="cfp-hotkeys-keys">
|
|
@ -0,0 +1,74 @@
|
|||
import { Subscription } from 'rxjs'
|
||||
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'
|
||||
import { LocalStorageService, HotkeysService, Hotkey } from '@app/core'
|
||||
|
||||
@Component({
|
||||
selector: 'my-hotkeys-cheat-sheet',
|
||||
templateUrl: './hotkeys-cheat-sheet.component.html',
|
||||
styleUrls: [ './hotkeys-cheat-sheet.component.scss' ]
|
||||
})
|
||||
export class HotkeysCheatSheetComponent implements OnInit, OnDestroy {
|
||||
@Input() title = $localize`Keyboard Shortcuts`
|
||||
|
||||
@Output() hotkeysModalStateChange = new EventEmitter<boolean>()
|
||||
|
||||
hotkeysEnabled = true
|
||||
|
||||
helpVisible = false
|
||||
subscription: Subscription
|
||||
|
||||
hotkeys: Hotkey[]
|
||||
|
||||
private readonly localStorageHotkeysDisabledKey = 'peertube-hotkeys-disabled'
|
||||
|
||||
constructor (
|
||||
private hotkeysService: HotkeysService,
|
||||
private localStorage: LocalStorageService
|
||||
) {}
|
||||
|
||||
ngOnInit () {
|
||||
if (this.localStorage.getItem(this.localStorageHotkeysDisabledKey) === 'true') {
|
||||
this.hotkeysEnabled = false
|
||||
this.hotkeysService.disableHotkeys()
|
||||
}
|
||||
|
||||
this.subscription = this.hotkeysService.cheatSheetToggle.subscribe(isOpen => {
|
||||
if (isOpen !== false) {
|
||||
this.hotkeys = this.hotkeysService.getHotkeys().filter(hotkey => hotkey.description)
|
||||
}
|
||||
|
||||
if (isOpen === false) {
|
||||
this.helpVisible = false
|
||||
} else {
|
||||
this.toggleHelpVisible()
|
||||
}
|
||||
|
||||
this.hotkeysModalStateChange.emit(this.helpVisible)
|
||||
})
|
||||
}
|
||||
|
||||
ngOnDestroy () {
|
||||
if (this.subscription) {
|
||||
this.subscription.unsubscribe()
|
||||
}
|
||||
}
|
||||
|
||||
toggleCheatSheet () {
|
||||
this.hotkeysService.cheatSheetToggle.next(!this.helpVisible)
|
||||
}
|
||||
|
||||
toggleHelpVisible () {
|
||||
this.helpVisible = !this.helpVisible
|
||||
}
|
||||
|
||||
onHotkeysEnabledChange () {
|
||||
if (!this.hotkeysEnabled) {
|
||||
this.localStorage.setItem(this.localStorageHotkeysDisabledKey, 'true')
|
||||
this.hotkeysService.disableHotkeys()
|
||||
return
|
||||
}
|
||||
|
||||
this.hotkeysService.enableHotkeys()
|
||||
this.localStorage.removeItem(this.localStorageHotkeysDisabledKey)
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from './hotkeys-cheat-sheet.component'
|
|
@ -1,4 +1,3 @@
|
|||
import { HotkeysService } from 'angular2-hotkeys'
|
||||
import * as debug from 'debug'
|
||||
import { forkJoin, Subscription } from 'rxjs'
|
||||
import { first, switchMap } from 'rxjs/operators'
|
||||
|
@ -10,6 +9,7 @@ import {
|
|||
AuthStatus,
|
||||
AuthUser,
|
||||
HooksService,
|
||||
HotkeysService,
|
||||
MenuSection,
|
||||
MenuService,
|
||||
RedirectService,
|
||||
|
|
|
@ -2460,11 +2460,6 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
|
||||
integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==
|
||||
|
||||
"@types/mousetrap@^1.6.9":
|
||||
version "1.6.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/mousetrap/-/mousetrap-1.6.11.tgz#ef9620160fdcefcb85bccda8aaa3e84d7429376d"
|
||||
integrity sha512-F0oAily9Q9QQpv9JKxKn0zMKfOo36KHCW7myYsmUyf2t0g+sBTbG3UleTPoguHdE1z3GLFr3p7/wiOio52QFjQ==
|
||||
|
||||
"@types/ms@*":
|
||||
version "0.7.31"
|
||||
resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197"
|
||||
|
@ -3293,15 +3288,6 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5:
|
|||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
angular2-hotkeys@^13.1.0:
|
||||
version "13.4.0"
|
||||
resolved "https://registry.yarnpkg.com/angular2-hotkeys/-/angular2-hotkeys-13.4.0.tgz#a96676466936556655cd64f92e1f5cd3aeac8e10"
|
||||
integrity sha512-WvkouvdXtTYw3tpuaoEVF+ue41pvI2XSa8m4tVRPLzAblT/f7PG0uQO4npyjVw3oDIc7qnFkQR+oqGl1KM1eow==
|
||||
dependencies:
|
||||
"@types/mousetrap" "^1.6.9"
|
||||
mousetrap "^1.6.5"
|
||||
tslib "^2.3.1"
|
||||
|
||||
angularx-qrcode@16.0.0:
|
||||
version "16.0.0"
|
||||
resolved "https://registry.yarnpkg.com/angularx-qrcode/-/angularx-qrcode-16.0.0.tgz#c637924b8d8f9cc344216caa80adf3810ccd5e5b"
|
||||
|
@ -8186,11 +8172,6 @@ moment@^2.10.2:
|
|||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||
|
||||
mousetrap@^1.6.5:
|
||||
version "1.6.5"
|
||||
resolved "https://registry.yarnpkg.com/mousetrap/-/mousetrap-1.6.5.tgz#8a766d8c272b08393d5f56074e0b5ec183485bf9"
|
||||
integrity sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==
|
||||
|
||||
mpd-parser@0.22.1, mpd-parser@^0.22.1:
|
||||
version "0.22.1"
|
||||
resolved "https://registry.yarnpkg.com/mpd-parser/-/mpd-parser-0.22.1.tgz#bc2bf7d3e56368e4b0121035b055675401871521"
|
||||
|
@ -10789,6 +10770,11 @@ thunky@^1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
|
||||
integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
|
||||
|
||||
tinykeys@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tinykeys/-/tinykeys-2.1.0.tgz#1341563e92a7fac9ca90053fddaf2b7553500298"
|
||||
integrity sha512-/MESnqBD1xItZJn5oGQ4OsNORQgJfPP96XSGoyu4eLpwpL0ifO0SYR5OD76u0YMhMXsqkb0UqvI9+yXTh4xv8Q==
|
||||
|
||||
tmp@0.2.1, tmp@~0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14"
|
||||
|
|
Loading…
Reference in New Issue