1 import {Injectable, EventEmitter, HostListener} from '@angular/core';
3 export interface AccessKeyAssignment {
4 key: string; // keyboard command
5 desc: string; // human-friendly description
6 ctx: string; // template context
7 action: Function; // handler function
8 shadowed?: boolean; // Has this assignemnt been shadowed by another.
12 export class AccessKeyService {
14 // Assignments stored as an array with most recently assigned
15 // items toward the front. Most recent items have precedence.
16 assignments: AccessKeyAssignment[] = [];
20 assign(assn: AccessKeyAssignment): void {
21 const list: AccessKeyAssignment[] = [];
23 // Avoid duplicate assignments for the same context.
24 // Most recent assignment always wins.
25 this.assignments.forEach(a => {
26 if (a.key === assn.key) {
27 if (a.ctx === assn.ctx) {
28 // If key and context match, keep only the most recent.
31 // An assignment within a different context shadows
32 // an existing assignment. Keep the assignment
33 // but mark it as shadowed.
41 this.assignments = list;
45 * Compress a set of single-fire keyboard events into single
46 * string. For example: Control and 't' becomes 'ctrl+t'.
48 compressKeys(evt: KeyboardEvent): string {
53 if (evt.ctrlKey || evt.metaKey) { s += 'ctrl+'; }
54 if (evt.altKey) { s += 'alt+'; }
55 if (evt.shiftKey) { s += 'shift+'; }
56 s += evt.key.toLowerCase();
62 * Checks for a key assignment and fires the assigned action.
64 fire(evt: KeyboardEvent): void {
65 const keySpec = this.compressKeys(evt);
66 for (const i in this.assignments) { // for-loop to exit early
67 if (keySpec === this.assignments[i].key) {
68 const assign = this.assignments[i];
69 console.debug(`AccessKey assignment found for ${assign.key}`);
70 // Allow the current digest cycle to complete before
71 // firing the access key action.
72 setTimeout(assign.action, 0);
80 * Returns a simplified key assignment list containing just
81 * the key spec and the description. Useful for inspecting
82 * without exposing the actions.
85 return this.assignments.map(a => {
86 return {key: a.key, desc: a.desc, ctx: a.ctx};