mirror of
https://gitlab.com/openlp/web-remote.git
synced 2024-12-22 11:32:47 +00:00
Merge branch 'use-configured-shortcuts' into 'master'
Make use of the configured shortcuts in OpenLP. See merge request openlp/web-remote!83
This commit is contained in:
commit
01724bb136
46
package.json
46
package.json
@ -24,44 +24,44 @@
|
|||||||
"supportedBrowsers": "(echo module.exports = && browserslist-useragent-regexp --allowHigherVersions) > src/assets/supportedBrowsers.js"
|
"supportedBrowsers": "(echo module.exports = && browserslist-useragent-regexp --allowHigherVersions) > src/assets/supportedBrowsers.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^17.3.1",
|
"@angular/animations": "^17.3.2",
|
||||||
"@angular/cdk": "^17.3.1",
|
"@angular/cdk": "^17.3.2",
|
||||||
"@angular/common": "^17.3.1",
|
"@angular/common": "^17.3.2",
|
||||||
"@angular/compiler": "^17.3.1",
|
"@angular/compiler": "^17.3.2",
|
||||||
"@angular/core": "^17.3.1",
|
"@angular/core": "^17.3.2",
|
||||||
"@angular/forms": "^17.3.1",
|
"@angular/forms": "^17.3.2",
|
||||||
"@angular/material": "^17.3.1",
|
"@angular/material": "^17.3.2",
|
||||||
"@angular/platform-browser": "^17.3.1",
|
"@angular/platform-browser": "^17.3.2",
|
||||||
"@angular/platform-browser-dynamic": "^17.3.1",
|
"@angular/platform-browser-dynamic": "^17.3.2",
|
||||||
"@angular/router": "^17.3.1",
|
"@angular/router": "^17.3.2",
|
||||||
"@fontsource/roboto": "^5.0.8",
|
"@fontsource/roboto": "^5.0.12",
|
||||||
"core-js": "^3.35.1",
|
"core-js": "^3.36.1",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
"material-icons": "^1.13.12",
|
"material-icons": "^1.13.12",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"zone.js": "^0.14.3"
|
"zone.js": "^0.14.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^17.3.1",
|
"@angular-devkit/build-angular": "^17.3.2",
|
||||||
"@angular-eslint/builder": "^17.3.0",
|
"@angular-eslint/builder": "^17.3.0",
|
||||||
"@angular-eslint/eslint-plugin": "^17.3.0",
|
"@angular-eslint/eslint-plugin": "^17.3.0",
|
||||||
"@angular-eslint/eslint-plugin-template": "^17.3.0",
|
"@angular-eslint/eslint-plugin-template": "^17.3.0",
|
||||||
"@angular-eslint/schematics": "^17.3.0",
|
"@angular-eslint/schematics": "^17.3.0",
|
||||||
"@angular-eslint/template-parser": "^17.3.0",
|
"@angular-eslint/template-parser": "^17.3.0",
|
||||||
"@angular/cli": "~17.3.1",
|
"@angular/cli": "~17.3.2",
|
||||||
"@angular/compiler-cli": "^17.3.1",
|
"@angular/compiler-cli": "^17.3.2",
|
||||||
"@angular/language-service": "^17.3.1",
|
"@angular/language-service": "^17.3.2",
|
||||||
"@chiragrupani/karma-chromium-edge-launcher": "^2.3.1",
|
"@chiragrupani/karma-chromium-edge-launcher": "^2.3.1",
|
||||||
"@types/jasmine": "~5.1.4",
|
"@types/jasmine": "~5.1.4",
|
||||||
"@types/jasminewd2": "~2.0.13",
|
"@types/jasminewd2": "~2.0.13",
|
||||||
"@types/node": "~20.11.17",
|
"@types/node": "~20.12.2",
|
||||||
"@typescript-eslint/eslint-plugin": "6.21.0",
|
"@typescript-eslint/eslint-plugin": "7.4.0",
|
||||||
"@typescript-eslint/parser": "6.21.0",
|
"@typescript-eslint/parser": "7.4.0",
|
||||||
"browserslist": "^4.23.0",
|
"browserslist": "^4.23.0",
|
||||||
"browserslist-useragent-regexp": "^4.1.1",
|
"browserslist-useragent-regexp": "^4.1.1",
|
||||||
"eslint": "^8.56.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-import": "~2.29.1",
|
"eslint-plugin-import": "~2.29.1",
|
||||||
"eslint-plugin-jsdoc": "~48.0.6",
|
"eslint-plugin-jsdoc": "~48.2.2",
|
||||||
"eslint-plugin-prefer-arrow": "~1.2.3",
|
"eslint-plugin-prefer-arrow": "~1.2.3",
|
||||||
"jasmine-core": "~5.1.2",
|
"jasmine-core": "~5.1.2",
|
||||||
"jasmine-spec-reporter": "~7.0.0",
|
"jasmine-spec-reporter": "~7.0.0",
|
||||||
@ -71,7 +71,7 @@
|
|||||||
"karma-jasmine": "~5.1.0",
|
"karma-jasmine": "~5.1.0",
|
||||||
"karma-jasmine-html-reporter": "^2.1.0",
|
"karma-jasmine-html-reporter": "^2.1.0",
|
||||||
"ts-node": "~10.9.2",
|
"ts-node": "~10.9.2",
|
||||||
"typescript": "~5.3.3"
|
"typescript": "~5.4.3"
|
||||||
},
|
},
|
||||||
"private": true
|
"private": true
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,8 @@ import { LoginComponent } from './components/login/login.component';
|
|||||||
import { fromEvent } from 'rxjs';
|
import { fromEvent } from 'rxjs';
|
||||||
import { debounceTime } from 'rxjs/operators';
|
import { debounceTime } from 'rxjs/operators';
|
||||||
import { DisplayModeSelectorComponent } from './components/display-mode-selector/display-mode-selector.component';
|
import { DisplayModeSelectorComponent } from './components/display-mode-selector/display-mode-selector.component';
|
||||||
import { HotKeysService } from './hotkeys.service';
|
import { Shortcuts, ShortcutsService } from './shortcuts.service';
|
||||||
|
import { ShortcutPipe } from './components/shortcuts/shortcut.pipe';
|
||||||
import { SettingsService } from './settings.service';
|
import { SettingsService } from './settings.service';
|
||||||
import * as supportedBrowsers from '../assets/supportedBrowsers';
|
import * as supportedBrowsers from '../assets/supportedBrowsers';
|
||||||
|
|
||||||
@ -29,14 +30,16 @@ export class AppComponent implements OnInit {
|
|||||||
appVersion = '0.0';
|
appVersion = '0.0';
|
||||||
webSocketOpen = false;
|
webSocketOpen = false;
|
||||||
fastSwitching = false;
|
fastSwitching = false;
|
||||||
|
useShortcutsFromOpenlp = false;
|
||||||
|
|
||||||
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,
|
constructor(private pageTitleService: PageTitleService, private openlpService: OpenLPService,
|
||||||
private dialog: MatDialog, private bottomSheet: MatBottomSheet, private windowRef: WindowRef,
|
private dialog: MatDialog, private bottomSheet: MatBottomSheet, private windowRef: WindowRef,
|
||||||
private hotKeysService: HotKeysService, private settingsService: SettingsService) {
|
private shortcutsService: ShortcutsService, private settingsService: SettingsService) {
|
||||||
pageTitleService.pageTitleChanged$.subscribe(pageTitle => this.pageTitle = pageTitle);
|
this.pageTitleService.pageTitleChanged$.subscribe(pageTitle => this.pageTitle = pageTitle);
|
||||||
openlpService.stateChanged$.subscribe(item => this.state = item);
|
this.openlpService.stateChanged$.subscribe(item => this.state = item);
|
||||||
openlpService.webSocketStateChanged$.subscribe(status => this.webSocketOpen = status === WebSocketStatus.Open);
|
this.openlpService.webSocketStateChanged$.subscribe(status => this.webSocketOpen = status === WebSocketStatus.Open);
|
||||||
this.appVersion = windowRef.nativeWindow.appVersion || '0.0';
|
this.shortcutsService.shortcutsChanged$.subscribe(shortcuts => this.addShortcuts(shortcuts));
|
||||||
|
this.appVersion = this.windowRef.nativeWindow.appVersion || '0.0';
|
||||||
this.webSocketOpen = openlpService.webSocketStatus === WebSocketStatus.Open;
|
this.webSocketOpen = openlpService.webSocketStatus === WebSocketStatus.Open;
|
||||||
// Try to force websocket reconnection as user is now focused on window and will try to interact soon
|
// Try to force websocket reconnection as user is now focused on window and will try to interact soon
|
||||||
// Adding a debounce to avoid event flooding
|
// Adding a debounce to avoid event flooding
|
||||||
@ -49,47 +52,60 @@ export class AppComponent implements OnInit {
|
|||||||
if (!(supportedBrowsers.test(navigator.userAgent))) {
|
if (!(supportedBrowsers.test(navigator.userAgent))) {
|
||||||
window.location.replace("/assets/notsupported.html");
|
window.location.replace("/assets/notsupported.html");
|
||||||
}
|
}
|
||||||
this.openlpService.retrieveSystemInformation().subscribe(res => this.showLogin = res.login_required);
|
this.openlpService.retrieveSystemInformation().subscribe(res => {
|
||||||
this.addHotKeys();
|
this.showLogin = res.login_required
|
||||||
|
this.useShortcutsFromOpenlp = this.openlpService.assertApiVersionMinimum(2, 5)
|
||||||
|
this.shortcutsService.getShortcuts(this.useShortcutsFromOpenlp);
|
||||||
|
}
|
||||||
|
);
|
||||||
this.fastSwitching = this.settingsService.get('fastSwitching');
|
this.fastSwitching = this.settingsService.get('fastSwitching');
|
||||||
this.settingsService.onPropertyChanged('fastSwitching').subscribe(value => this.fastSwitching = value);
|
this.settingsService.onPropertyChanged('fastSwitching').subscribe(value => this.fastSwitching = value);
|
||||||
}
|
}
|
||||||
|
|
||||||
addHotKeys(): void {
|
addShortcuts(shortcuts: Shortcuts): void {
|
||||||
this.hotKeysService.addShortcut({ keys: 'ArrowUp' }).subscribe(() =>
|
const shortcutPipe = new ShortcutPipe();
|
||||||
this.previousSlide()
|
shortcuts.previousSlide.forEach((key) => {
|
||||||
);
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
this.hotKeysService.addShortcut({ keys: 'ArrowDown' }).subscribe(() =>
|
this.previousSlide()
|
||||||
this.nextSlide()
|
)
|
||||||
);
|
});
|
||||||
this.hotKeysService.addShortcut({ keys: 'PageUp' }).subscribe(() =>
|
shortcuts.nextSlide.forEach((key) => {
|
||||||
this.previousSlide()
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
);
|
this.nextSlide()
|
||||||
this.hotKeysService.addShortcut({ keys: 'PageDown' }).subscribe(() =>
|
)
|
||||||
this.nextSlide()
|
});
|
||||||
);
|
shortcuts.previousItem.forEach((key) => {
|
||||||
this.hotKeysService.addShortcut({ keys: 'ArrowLeft' }).subscribe(() =>
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
this.previousItem()
|
this.previousItem()
|
||||||
);
|
)
|
||||||
this.hotKeysService.addShortcut({ keys: 'ArrowRight' }).subscribe(() =>
|
});
|
||||||
this.nextItem()
|
shortcuts.nextItem.forEach((key) => {
|
||||||
);
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
this.hotKeysService.addShortcut({ keys: 'Space' }).subscribe(() =>
|
this.nextItem()
|
||||||
{
|
)
|
||||||
|
});
|
||||||
|
shortcuts.showDisplay.forEach((key) => {
|
||||||
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() => {
|
||||||
if (this.state.displayMode !== DisplayMode.Presentation) {
|
if (this.state.displayMode !== DisplayMode.Presentation) {
|
||||||
this.showDisplay();
|
this.showDisplay();
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
);
|
});
|
||||||
this.hotKeysService.addShortcut({ keys: 't' }).subscribe(() =>
|
shortcuts.themeDisplay.forEach((key) => {
|
||||||
this.state.displayMode === DisplayMode.Theme ? this.showDisplay() : this.themeDisplay()
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
);
|
this.state.displayMode === DisplayMode.Theme ? this.showDisplay() : this.themeDisplay()
|
||||||
this.hotKeysService.addShortcut({ keys: 'code.Period' }).subscribe(() =>
|
)
|
||||||
this.state.displayMode === DisplayMode.Blank ? this.showDisplay() : this.blankDisplay()
|
});
|
||||||
);
|
shortcuts.blankDisplay.forEach((key) => {
|
||||||
this.hotKeysService.addShortcut({ keys: 'd' }).subscribe(() =>
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
this.state.displayMode === DisplayMode.Desktop ? this.showDisplay() : this.desktopDisplay()
|
this.state.displayMode === DisplayMode.Blank ? this.showDisplay() : this.blankDisplay()
|
||||||
);
|
)
|
||||||
|
});
|
||||||
|
shortcuts.desktopDisplay.forEach((key) => {
|
||||||
|
this.shortcutsService.addShortcut({ keys: shortcutPipe.transform(key) }).subscribe(() =>
|
||||||
|
this.state.displayMode === DisplayMode.Desktop ? this.showDisplay() : this.desktopDisplay()
|
||||||
|
)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openDisplayModeSelector(): void {
|
openDisplayModeSelector(): void {
|
||||||
|
23
src/app/components/shortcuts/shortcut.pipe.ts
Normal file
23
src/app/components/shortcuts/shortcut.pipe.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
@Pipe({name: 'shortcut'})
|
||||||
|
export class ShortcutPipe implements PipeTransform {
|
||||||
|
transform(value: string): string {
|
||||||
|
if (!value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
throw Error(`Invalid pipe argument: '${value}' for pipe 'ShortcutPipe'`);
|
||||||
|
}
|
||||||
|
value = value.replace('.', 'code.period');
|
||||||
|
value = value.replace('PgUp', 'pageup');
|
||||||
|
value = value.replace('PgDown', 'pagedown');
|
||||||
|
value = value.replace('Up', 'arrowup');
|
||||||
|
value = value.replace('Down', 'arrowdown');
|
||||||
|
value = value.replace('Left', 'arrowleft');
|
||||||
|
value = value.replace('Right', 'arrowright');
|
||||||
|
value = value.replace(/(Alt|Shift)\+/, '$1.');
|
||||||
|
value = value.replace(/Ctrl\+/, 'control.');
|
||||||
|
return value.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
@ -1,45 +0,0 @@
|
|||||||
import { DOCUMENT } from '@angular/common';
|
|
||||||
import { Inject, Injectable } from '@angular/core';
|
|
||||||
import { EventManager } from '@angular/platform-browser';
|
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
element: any;
|
|
||||||
keys: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
|
||||||
export class HotKeysService {
|
|
||||||
defaults: Partial<Options> = {
|
|
||||||
element: this.document
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(private eventManager: EventManager, @Inject(DOCUMENT) private document: Document) {
|
|
||||||
}
|
|
||||||
|
|
||||||
addShortcut(options: Partial<Options>) {
|
|
||||||
const merged = { ...this.defaults, ...options };
|
|
||||||
const event = `keydown.${merged.keys}`;
|
|
||||||
|
|
||||||
return new Observable(observer => {
|
|
||||||
const handler = (e: KeyboardEvent) => {
|
|
||||||
const activeElement = this.document.activeElement;
|
|
||||||
const notOnInput = activeElement?.tagName !== 'INPUT' && activeElement?.tagName !== 'TEXTAREA';
|
|
||||||
if (notOnInput) {
|
|
||||||
if (document.URL.endsWith('/slides')) {
|
|
||||||
e.preventDefault();
|
|
||||||
observer.next(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const dispose = this.eventManager.addEventListener(
|
|
||||||
merged.element, event, handler
|
|
||||||
);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
dispose();
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -10,6 +10,7 @@ import {
|
|||||||
ServiceItem,
|
ServiceItem,
|
||||||
Theme,
|
Theme,
|
||||||
MainView,
|
MainView,
|
||||||
|
Shortcut,
|
||||||
SystemInformation,
|
SystemInformation,
|
||||||
Credentials,
|
Credentials,
|
||||||
AuthToken,
|
AuthToken,
|
||||||
@ -96,6 +97,10 @@ export class OpenLPService {
|
|||||||
return this.doGet<MainView>(`${this.apiURL}/core/live-image`);
|
return this.doGet<MainView>(`${this.apiURL}/core/live-image`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getShortcuts(): Observable<Shortcut[]> {
|
||||||
|
return this.doGet(`${this.apiURL}/core/shortcuts`);
|
||||||
|
}
|
||||||
|
|
||||||
getSearchablePlugins(): Observable<PluginDescription[]> {
|
getSearchablePlugins(): Observable<PluginDescription[]> {
|
||||||
return this.doGet<PluginDescription[]>(`${this.apiURL}/core/plugins`);
|
return this.doGet<PluginDescription[]>(`${this.apiURL}/core/plugins`);
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,11 @@ export interface MainView {
|
|||||||
binary_image: string;
|
binary_image: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Shortcut {
|
||||||
|
action: string;
|
||||||
|
shortcut: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface SystemInformation {
|
export interface SystemInformation {
|
||||||
websocket_port: number;
|
websocket_port: number;
|
||||||
login_required: boolean;
|
login_required: boolean;
|
||||||
|
109
src/app/shortcuts.service.ts
Normal file
109
src/app/shortcuts.service.ts
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import { DOCUMENT } from '@angular/common';
|
||||||
|
import { EventEmitter, Inject, Injectable } from '@angular/core';
|
||||||
|
import { EventManager } from '@angular/platform-browser';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { OpenLPService } from './openlp.service';
|
||||||
|
|
||||||
|
export class Shortcuts {
|
||||||
|
previousSlide = ['Up', 'PgUp'];
|
||||||
|
nextSlide = ['Down', 'PgDown'];
|
||||||
|
previousItem = ['Left'];
|
||||||
|
nextItem = ['Right'];
|
||||||
|
showDisplay = ['Space'];
|
||||||
|
themeDisplay = ['t'];
|
||||||
|
blankDisplay = ['.'];
|
||||||
|
desktopDisplay = ['d'];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Options {
|
||||||
|
element: any;
|
||||||
|
keys: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class ShortcutsService {
|
||||||
|
defaults: Partial<Options> = {
|
||||||
|
element: this.document
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(DOCUMENT) private document: Document,
|
||||||
|
private eventManager: EventManager,
|
||||||
|
private openlpService: OpenLPService) {
|
||||||
|
this.shortcutsChanged$ = new EventEmitter<Shortcuts>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private shortcuts: Shortcuts
|
||||||
|
public shortcutsChanged$: EventEmitter<Shortcuts>;
|
||||||
|
|
||||||
|
getShortcuts(useShortcutsFromOpenlp: boolean) {
|
||||||
|
const shortcuts: Shortcuts = new Shortcuts()
|
||||||
|
if (useShortcutsFromOpenlp) {
|
||||||
|
this.openlpService.getShortcuts().subscribe(res => {
|
||||||
|
res.forEach((shortcut) => {
|
||||||
|
switch (shortcut.action) {
|
||||||
|
case 'blankScreen':
|
||||||
|
shortcuts.blankDisplay = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'desktopScreen':
|
||||||
|
shortcuts.desktopDisplay = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'nextItem_live':
|
||||||
|
shortcuts.nextSlide = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'nextService':
|
||||||
|
shortcuts.nextItem = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'previousItem_live':
|
||||||
|
shortcuts.previousSlide = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'previousService':
|
||||||
|
shortcuts.previousItem = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'showScreen':
|
||||||
|
shortcuts.showDisplay = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
case 'themeScreen':
|
||||||
|
shortcuts.themeDisplay = shortcut.shortcut;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this._handleShortcutsChanged(shortcuts);
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
this._handleShortcutsChanged(shortcuts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addShortcut(options: Partial<Options>) {
|
||||||
|
const merged = { ...this.defaults, ...options };
|
||||||
|
const event = `keydown.${merged.keys}`;
|
||||||
|
|
||||||
|
return new Observable(observer => {
|
||||||
|
const handler = (e: KeyboardEvent) => {
|
||||||
|
const activeElement = this.document.activeElement;
|
||||||
|
const notOnInput = activeElement?.tagName !== 'INPUT' && activeElement?.tagName !== 'TEXTAREA';
|
||||||
|
if (notOnInput) {
|
||||||
|
if (document.URL.endsWith('/slides')) {
|
||||||
|
e.preventDefault();
|
||||||
|
observer.next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const dispose = this.eventManager.addEventListener(
|
||||||
|
merged.element, event, handler
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispose();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected _handleShortcutsChanged(shortcuts: Shortcuts) {
|
||||||
|
this.shortcuts = shortcuts;
|
||||||
|
this.shortcutsChanged$.emit(this.shortcuts);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user