Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular 17 support #176 #177

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@
"tslib": "^2.3.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.2.0",
"@angular-devkit/core": "^16.2.0",
"@angular/animations": "^16.2.0",
"@angular/cli": "^16.2.0",
"@angular/common": "^16.2.0",
"@angular/compiler": "^16.2.0",
"@angular/compiler-cli": "^16.2.0",
"@angular/core": "^16.2.0",
"@angular/forms": "^16.2.0",
"@angular/language-service": "^16.2.0",
"@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0",
"@angular-devkit/build-angular": "^17.0.9",
"@angular-devkit/core": "^17.0.9",
"@angular/animations": "^17.0.9",
"@angular/cli": "^17.0.9",
"@angular/common": "^17.0.9",
"@angular/compiler": "^17.0.9",
"@angular/compiler-cli": "^17.0.9",
"@angular/core": "^17.0.9",
"@angular/forms": "^17.0.9",
"@angular/language-service": "^17.0.9",
"@angular/platform-browser": "^17.0.9",
"@angular/platform-browser-dynamic": "^17.0.9",
"@angular/router": "^17.0.9",
"@types/jasmine": "~3.10.3",
"@types/jasminewd2": "~2.0.10",
"@types/node": "^18.11.9 ",
Expand All @@ -61,12 +61,12 @@
"karma-coverage-istanbul-reporter": "~3.0.3",
"karma-jasmine": "~4.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"ng-packagr": "^16.2.0",
"ng-packagr": "^17.0.3",
"protractor": "~7.0.0",
"rxjs": "~7.5.2",
"ts-node": "~10.4.0",
"tslint": "~6.1.0",
"typescript": "~5.1.6",
"zone.js": "~0.13.1"
"typescript": "~5.2.2",
"zone.js": "~0.14.3"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { InjectionToken } from '@angular/core';

export const HotkeyOptions = new InjectionToken<IHotkeyOptions>('HotkeyOptions');

export interface IHotkeyOptions {
/**
* Disable the cheat sheet popover dialog? Default: false
Expand All @@ -24,4 +26,8 @@ export interface IHotkeyOptions {
cheatSheetDescription?: string;
}

export const HotkeyOptions = new InjectionToken<IHotkeyOptions>('HotkeyOptions');
export interface ExtendedKeyboardEvent extends KeyboardEvent {
returnValue: boolean; // IE returnValue
}

export type HotkeyMap = { [combo: string]: (event: KeyboardEvent, combo: string) => ExtendedKeyboardEvent }[];
11 changes: 5 additions & 6 deletions src/lib/hotkey.model.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
export interface ExtendedKeyboardEvent extends KeyboardEvent {
returnValue: boolean; // IE returnValue
}
import { ExtendedKeyboardEvent } from "./hotkey.interfaces-types";


export class Hotkey {
private formattedHotkey: string[];
private formattedHotkey: string[] = [];

static symbolize(combo: string): string {
const map: any = {
Expand Down Expand Up @@ -46,8 +45,8 @@ export class Hotkey {
* @param persistent if true, the binding is preserved upon route changes
*/
constructor(public combo: string | string[], public callback: (event: KeyboardEvent, combo: string) => ExtendedKeyboardEvent | boolean,
public allowIn?: string[], public description?: string | Function, public action?: string,
public persistent?: boolean) {
public allowIn?: string[], public description?: string | Function, public action?: string,
public persistent?: boolean) {
this.combo = (Array.isArray(combo) ? combo : [combo as string]);
this.allowIn = allowIn || [];
this.description = description || '';
Expand Down
11 changes: 5 additions & 6 deletions src/lib/hotkey.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ import { ModuleWithProviders, NgModule } from '@angular/core';
import { HotkeysDirective } from './hotkeys.directive';
import { HotkeysCheatsheetComponent } from './hotkeys-cheatsheet/hotkeys-cheatsheet.component';
import { CommonModule } from '@angular/common';
import { HotkeyOptions, IHotkeyOptions } from './hotkey.options';
import { HotkeyOptions, IHotkeyOptions } from './hotkey.interfaces-types';
import { HotkeysService } from './hotkeys.service';

@NgModule({
declarations: [HotkeysDirective, HotkeysCheatsheetComponent],
imports: [CommonModule],
imports: [CommonModule, HotkeysDirective, HotkeysCheatsheetComponent],
exports: [HotkeysDirective, HotkeysCheatsheetComponent]
})
export class HotkeyModule {
// noinspection JSUnusedGlobalSymbols
static forRoot(options: IHotkeyOptions = {}): ModuleWithProviders<HotkeyModule> {
return {
ngModule : HotkeyModule,
providers : [
ngModule: HotkeyModule,
providers: [
HotkeysService,
{provide : HotkeyOptions, useValue : options}
{ provide: HotkeyOptions, useValue: options }
]
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ describe('HotkeysCheatsheetComponent', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HotkeysCheatsheetComponent]
})
imports: [HotkeysCheatsheetComponent]
})
.compileComponents();
}));

Expand Down
11 changes: 7 additions & 4 deletions src/lib/hotkeys-cheatsheet/hotkeys-cheatsheet.component.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { Hotkey } from '../hotkey.model';
import { HotkeysService } from '../hotkeys.service';
import {BehaviorSubject, Subscription} from 'rxjs';
import { BehaviorSubject, Subscription } from 'rxjs';
import { NgClass, NgFor, AsyncPipe } from '@angular/common';

@Component({
selector: 'hotkeys-cheatsheet',
templateUrl: './hotkeys-cheatsheet.component.html',
styleUrls: ['./hotkeys-cheatsheet.component.css']
styleUrls: ['./hotkeys-cheatsheet.component.css'],
standalone: true,
imports: [NgClass, NgFor, AsyncPipe]
})
export class HotkeysCheatsheetComponent implements OnInit, OnDestroy {
helpVisible$ = new BehaviorSubject(false);
@Input() title = 'Keyboard Shortcuts:';
subscription: Subscription;
subscription: Subscription = new Subscription();

hotkeys: Hotkey[];
hotkeys: Hotkey[] = [];

constructor(private hotkeysService: HotkeysService) {
}
Expand Down
11 changes: 8 additions & 3 deletions src/lib/hotkeys.directive.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
import { Directive, ElementRef, Input, OnDestroy, OnInit } from '@angular/core';
import { ExtendedKeyboardEvent, Hotkey } from './hotkey.model';
import { Hotkey } from './hotkey.model';
import { HotkeysService } from './hotkeys.service';
import { MousetrapInstance } from 'mousetrap';
import * as Mousetrap from 'mousetrap';
import { ExtendedKeyboardEvent } from './hotkey.interfaces-types';

type HotkeyMap = { [combo: string]: (event: KeyboardEvent, combo: string) => ExtendedKeyboardEvent }[];

@Directive({
selector: '[hotkeys]',
providers: [HotkeysService]
providers: [HotkeysService],
standalone: true
})
export class HotkeysDirective implements OnInit, OnDestroy {
@Input() hotkeys: { [combo: string]: (event: KeyboardEvent, combo: string) => ExtendedKeyboardEvent }[];
@Input()
hotkeys: HotkeyMap = [];

private mousetrap: MousetrapInstance;
private hotkeysList: Hotkey[] = [];
Expand Down
71 changes: 39 additions & 32 deletions src/lib/hotkeys.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Inject, Injectable } from '@angular/core';
import { Hotkey } from './hotkey.model';
import { Subject } from 'rxjs';
import { HotkeyOptions, IHotkeyOptions } from './hotkey.options';
import { HotkeyOptions, IHotkeyOptions } from './hotkey.interfaces-types';
import { MousetrapInstance } from 'mousetrap';
import * as Mousetrap from 'mousetrap';

Expand Down Expand Up @@ -30,37 +30,44 @@ export class HotkeysService {
}

private initCheatSheet() {
// Cheat sheet hotkey
if (!this.options.disableCheatSheet) {
this.add(new Hotkey(
this.options.cheatSheetHotkey || '?',
function(_: KeyboardEvent) {
this.cheatSheetToggle.next();
}.bind(this),
[],
this.options.cheatSheetDescription || 'Show / hide this help menu',
));
let opt = {
combo: this.options.cheatSheetHotkey || '?',
callback: (_event: KeyboardEvent, _combo: string) => {
this.cheatSheetToggle.next(null);
return false;
},
description: this.options.cheatSheetDescription || 'Show / hide this help menu',
allowIn: []
};
let add: Hotkey | Hotkey[] = new Hotkey(opt.combo, opt.callback.bind(this), opt.allowIn, opt.description);
this.add(add);
}

// Cheat sheet close esc
if (this.options.cheatSheetCloseEsc) {
this.add(new Hotkey(
'esc',
function(_: KeyboardEvent) {
let opt = {
combo: 'esc',
callback: (_event: KeyboardEvent, _combo: string) => {
this.cheatSheetToggle.next(false);
}.bind(this),
['HOTKEYS-CHEATSHEET'],
this.options.cheatSheetCloseEscDescription || 'Hide this help menu',
));
return false;
},
description: this.options.cheatSheetCloseEscDescription || 'Hide this help menu',
allowIn: ['HOTKEYS-CHEATSHEET']
};
let add: Hotkey | Hotkey[] = new Hotkey(opt.combo, opt.callback.bind(this), opt.allowIn, opt.description);
this.add(add);
}

}

add(hotkey: Hotkey | Hotkey[], specificEvent?: string): Hotkey | Hotkey[] {
add<T extends Hotkey | Hotkey[]>(hotkey: T, specificEvent?: string): T {
if (Array.isArray(hotkey)) {
const temp: Hotkey[] = [];
for (const key of hotkey) {
temp.push(this.add(key, specificEvent) as Hotkey);
temp.push(this.add<Hotkey>(key, specificEvent));
}
return temp;
return temp as T;
}
this.remove(hotkey);
this.hotkeys.push(hotkey as Hotkey);
Expand All @@ -73,11 +80,12 @@ export class HotkeysService {
const target: HTMLElement = (event.target || event.srcElement) as HTMLElement; // srcElement is IE only
const nodeName: string = target.nodeName.toUpperCase();

const allowIn = (hotkey as Hotkey).allowIn || [];

// check if the input has a mousetrap class, and skip checking preventIn if so
if ((' ' + target.className + ' ').indexOf(' mousetrap ') > -1) {
shouldExecute = true;
} else if (this.preventIn.indexOf(nodeName) > -1 &&
(hotkey as Hotkey).allowIn.map(allow => allow.toUpperCase()).indexOf(nodeName) === -1) {
} else if (this.preventIn.indexOf(nodeName) > -1 && allowIn.map(allow => allow.toUpperCase()).indexOf(nodeName) === -1) {
// don't execute callback if the event was fired from inside an element listed in preventIn but not in allowIn
shouldExecute = false;
}
Expand All @@ -90,19 +98,19 @@ export class HotkeysService {
return hotkey;
}

remove(hotkey?: Hotkey | Hotkey[], specificEvent?: string): Hotkey | Hotkey[] {
remove<T extends Hotkey | Hotkey[]>(hotkey?: T, specificEvent?: string): T | null {
const temp: Hotkey[] = [];
if (!hotkey) {
for (const key of this.hotkeys) {
temp.push(this.remove(key, specificEvent) as Hotkey);
}
return temp;
return temp as T;
}
if (Array.isArray(hotkey)) {
for (const key of hotkey) {
temp.push(this.remove(key) as Hotkey);
}
return temp;
return temp as T;
}
const index = this.findHotkey(hotkey as Hotkey);
if (index > -1) {
Expand All @@ -113,7 +121,7 @@ export class HotkeysService {
return null;
}

get(combo?: string | string[]): Hotkey | Hotkey[] {
get<T extends string | string[]>(combo?: T): Hotkey | Hotkey[] | null {
if (!combo) {
return this.hotkeys;
}
Expand Down Expand Up @@ -150,21 +158,21 @@ export class HotkeysService {
}

// noinspection JSUnusedGlobalSymbols
unpause(hotkey?: Hotkey | Hotkey[]): Hotkey | Hotkey[] {
unpause<T extends Hotkey | Hotkey[]>(hotkey?: T): T | null {
if (!hotkey) {
return this.unpause(this.pausedHotkeys);
return this.unpause(this.pausedHotkeys) as T;
}
if (Array.isArray(hotkey)) {
const temp: Hotkey[] = [];
for (const key of hotkey.slice()) {
temp.push(this.unpause(key) as Hotkey);
}
return temp;
return temp as T;
}
const index: number = this.pausedHotkeys.indexOf(hotkey as Hotkey);
if (index > -1) {
this.add(hotkey);
return this.pausedHotkeys.splice(index, 1);
return this.pausedHotkeys.splice(index, 1) as T;
}
return null;
}
Expand All @@ -180,5 +188,4 @@ export class HotkeysService {
private findHotkey(hotkey: Hotkey): number {
return this.hotkeys.indexOf(hotkey);
}
}

}
2 changes: 1 addition & 1 deletion src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export * from './lib/hotkeys.service';
export * from './lib/hotkeys.directive';
export * from './lib/hotkeys-cheatsheet/hotkeys-cheatsheet.component';
export * from './lib/hotkey.model';
export * from './lib/hotkey.options';
export * from './lib/hotkey.interfaces-types';
export * from './lib/hotkey.module';
Loading