Skip to content

Commit

Permalink
feat: Get hotkeys working
Browse files Browse the repository at this point in the history
  • Loading branch information
isaacplmann committed Oct 23, 2017
1 parent ca61ad7 commit 498827e
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 182 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 0 additions & 29 deletions src/lib/contextMenu.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,6 @@ export class ContextMenuComponent implements OnDestroy {
this.useBootstrap4 = options.useBootstrap4;
}
this.subscription.add(_contextMenuService.show.subscribe(menuEvent => this.onMenuEvent(menuEvent)));
this.subscription.add(_contextMenuService.triggerClose.subscribe(contextMenuContent => {
// if (!contextMenuContent) {
// this.contextMenuInjector.destroyAll();
// } else {
// this.destroySubMenus(contextMenuContent);
// this.contextMenuInjector.destroy(contextMenuContent);
// }
}));
this.subscription.add(_contextMenuService.close.subscribe(event => this.close.emit(event)));
}

Expand All @@ -103,27 +95,6 @@ export class ContextMenuComponent implements OnDestroy {
this.open.next(menuEvent);
}

// public destroySubMenus(parent: ContextMenuContentComponent): void {
// const cmContents: ComponentRef<ContextMenuContentComponent>[] = this.contextMenuInjector.getByType(this.contextMenuInjector.type);
// cmContents.filter(content => content.instance.parentContextMenu === parent)
// .forEach(comp => {
// this.destroySubMenus(comp.instance);
// this.contextMenuInjector.destroy(comp);
// });
// }

@HostListener('window:keydown.Escape')
public destroyLeafMenu(): void {
this._contextMenuService.destroyLeafMenu();
}

@HostListener('document:click')
@HostListener('document:contextmenu')
// @HostListener('window:resize')
public closeMenu(): void {
this._contextMenuService.closeAllContextMenus();
}

public isMenuItemVisible(menuItem: ContextMenuItemDirective): boolean {
return this.evaluateIfFunction(menuItem.visible);
}
Expand Down
18 changes: 17 additions & 1 deletion src/lib/contextMenu.item.directive.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import { ContextMenuComponent } from './contextMenu.component';
import { Directive, Input, Output, EventEmitter, TemplateRef, ElementRef } from '@angular/core';
import { Highlightable } from '@angular/cdk/a11y';

@Directive({
/* tslint:disable:directive-selector-type */
selector: '[contextMenuItem]',
/* tslint:enable:directive-selector-type */
})
export class ContextMenuItemDirective {
export class ContextMenuItemDirective implements Highlightable {
@Input() public subMenu: ContextMenuComponent;
@Input() public divider = false;
@Input() public enabled: boolean | ((item: any) => boolean) = true;
@Input() public passive = false;
@Input() public visible: boolean | ((item: any) => boolean) = true;
@Output() public execute: EventEmitter<{ event: Event, item: any }> = new EventEmitter();

public currentItem: any;
public isActive = false;
public get disabled() {
return this.passive ||
this.divider ||
!this.evaluateIfFunction(this.enabled, this.currentItem);
}

constructor(public template: TemplateRef<{ item: any }>, public elementRef: ElementRef) { }

public evaluateIfFunction(value: any, item: any): any {
Expand All @@ -23,6 +32,13 @@ export class ContextMenuItemDirective {
return value;
}

public setActiveStyles(): void {
this.isActive = true;
}
public setInactiveStyles(): void {
this.isActive = false;
}

public triggerExecute(item: any, $event?: MouseEvent): void {
if (!this.evaluateIfFunction(this.enabled, item)) {
return;
Expand Down
11 changes: 0 additions & 11 deletions src/lib/contextMenu.options.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
<<<<<<< HEAD
export interface IContextMenuOptions {
useBootstrap4?: boolean;
autoFocus?: boolean;
}
=======
import { InjectionToken } from '@angular/core';

export const CONTEXT_MENU_OPTIONS = new InjectionToken<IContextMenuOptions>('CONTEXT_MENU_OPTIONS');

export interface IContextMenuOptions {
useBootstrap4?: boolean;
autoFocus?: boolean;
}
>>>>>>> master
89 changes: 53 additions & 36 deletions src/lib/contextMenu.service.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import { Overlay, ScrollStrategy, ScrollStrategyOptions, OverlayRef } from '@angular/cdk/overlay';
import { Overlay, OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import { ComponentRef, Injectable } from '@angular/core';
import { Subject } from 'rxjs/Subject';
import { takeUntil } from 'rxjs/operator/takeUntil';
import { Subscription } from 'rxjs/Subscription';

import { ContextMenuComponent } from './contextMenu.component';
import { ContextMenuItemDirective } from './contextMenu.item.directive';
import { ContextMenuContentComponent } from './contextMenuContent.component';

export interface IContextMenuClickEvent {
anchorElement?: Element;
contextMenu?: ContextMenuComponent;
event: MouseEvent;
event?: MouseEvent;
parentContextMenu?: ContextMenuContentComponent;
item: any;
activeMenuItemIndex?: number;
}
export interface IContextMenuContext extends IContextMenuClickEvent {
menuItems: ContextMenuItemDirective[];
}
export interface CloseLeafMenuEvent {
exceptRootMenu?: boolean;
}
export interface OverlayRefWithContextMenu extends OverlayRef {
contextMenu?: ContextMenuContentComponent;
}

@Injectable()
export class ContextMenuService {
Expand Down Expand Up @@ -46,7 +53,7 @@ export class ContextMenuService {
) { }

public openContextMenu(context: IContextMenuContext) {
const { event, parentContextMenu } = context;
const { anchorElement, event, parentContextMenu } = context;

if (!parentContextMenu) {
this.fakeElement.getBoundingClientRect = (): ClientRect => ({
Expand Down Expand Up @@ -82,7 +89,7 @@ export class ContextMenuService {
this.attachContextMenu(this.overlays[0], context);
} else {
const positionStrategy = this.overlay.position().connectedTo(
{ nativeElement: event.target },
{ nativeElement: event ? event.target : anchorElement },
{ originX: 'end', originY: 'top' },
{ overlayX: 'start', overlayY: 'top' })
.withFallbackPosition(
Expand All @@ -98,24 +105,40 @@ export class ContextMenuService {
this.overlays = this.overlays.concat(newOverlay);
this.attachContextMenu(newOverlay, context);
}

}

public attachContextMenu(overlay: OverlayRef, context: IContextMenuContext): void {
const { event, item, menuItems } = context;

const contextMenuContent = overlay.attach(new ComponentPortal(ContextMenuContentComponent));
const contextMenuContent: ComponentRef<ContextMenuContentComponent> = overlay.attach(new ComponentPortal(ContextMenuContentComponent));
contextMenuContent.instance.event = event;
contextMenuContent.instance.item = item;
contextMenuContent.instance.menuItems = menuItems;
contextMenuContent.instance.overlay = overlay;
const detachments = contextMenuContent.instance.overlay.detachments;
takeUntil.call(contextMenuContent.instance.execute.asObservable(), detachments)
.subscribe(() => this.closeAllContextMenus());
takeUntil.call(contextMenuContent.instance.closeSubMenus.asObservable(), detachments)
.subscribe(() => this.destroySubMenus(contextMenuContent.instance));
takeUntil.call(contextMenuContent.instance.openSubMenu.asObservable(), detachments)
.subscribe(subMenuEvent => this.show.next(subMenuEvent));
contextMenuContent.instance.isLeaf = true;
(<OverlayRefWithContextMenu>overlay).contextMenu = contextMenuContent.instance;

const subscriptions: Subscription = new Subscription();
subscriptions.add(contextMenuContent.instance.execute.asObservable()
.subscribe(() => this.closeAllContextMenus()));
subscriptions.add(contextMenuContent.instance.closeAllMenus.asObservable()
.subscribe(() => this.closeAllContextMenus()));
subscriptions.add(contextMenuContent.instance.closeLeafMenu.asObservable()
.subscribe(closeLeafMenuEvent => this.destroyLeafMenu(closeLeafMenuEvent)));
subscriptions.add(contextMenuContent.instance.openSubMenu.asObservable()
.subscribe((subMenuEvent: IContextMenuContext) => {
this.destroySubMenus(contextMenuContent.instance);
if (!subMenuEvent.contextMenu) {
contextMenuContent.instance.isLeaf = true;
return;
}
contextMenuContent.instance.isLeaf = false;
this.show.next(subMenuEvent);
}));
contextMenuContent.onDestroy(() => {
menuItems.forEach(menuItem => menuItem.isActive = false);
subscriptions.unsubscribe();
});
}

public closeAllContextMenus(): void {
Expand All @@ -126,18 +149,17 @@ export class ContextMenuService {
overlay.dispose();
}
});
// this.overlays = this.overlays.slice(0, 1);
}
}

public getLastAttachedOverlay(): OverlayRef {
public getLastAttachedOverlay(): OverlayRefWithContextMenu {
let overlay: OverlayRef = this.overlays[this.overlays.length - 1];
while (this.overlays.length > 1 && !overlay || !overlay.hasAttached()) {
console.log(this.overlays.length);
while (this.overlays.length > 1 && (!overlay || !overlay.hasAttached())) {
overlay.detach();
this.overlays = this.overlays.slice(0, -1);
overlay = this.overlays[this.overlays.length - 1];
}
console.log(this.overlays.length);
return overlay;
}

Expand All @@ -147,34 +169,29 @@ export class ContextMenuService {
}
this.isDestroyingLeafMenu = true;

const overlay = this.getLastAttachedOverlay();
if (this.overlays.length > (exceptRootMenu ? 1 : 0)) {
overlay.detach();
}
setTimeout(() => {
const overlay = this.getLastAttachedOverlay();
if (this.overlays.length > (exceptRootMenu ? 1 : 0)) {
overlay.detach();
}

this.getLastAttachedOverlay().contextMenu.isLeaf = true;

this.isDestroyingLeafMenu = false;
this.isDestroyingLeafMenu = false;
});
}

public destroySubMenus(contextMenu: ContextMenuContentComponent): void {
console.log(contextMenu);
const overlay = contextMenu.overlay;
const index = this.overlays.indexOf(overlay);
console.log(index);
this.overlays.slice(index + 1).forEach(subMenuOverlay => {
subMenuOverlay.detach();
subMenuOverlay.dispose();
});
}

// public getLeafMenu(): ContextMenuContentComponent {
// // const cmContents: ComponentRef<ContextMenuContentComponent>[] = this.contextMenuInjector.getByType(this.contextMenuInjector.type);
// // if (cmContents && cmContents.length > 0) {
// // return cmContents[cmContents.length - 1].instance;
// // }
// return undefined;
// }

// public isLeafMenu(cmContent: ContextMenuContentComponent): boolean {
// return this.getLeafMenu() === cmContent;
// }
public isLeafMenu(contextMenuContent: ContextMenuContentComponent): boolean {
const overlay = this.getLastAttachedOverlay();
return contextMenuContent.overlay === overlay;
}
}
Loading

0 comments on commit 498827e

Please sign in to comment.