import {
AfterContentInit,
ChangeDetectorRef,
Component,
ContentChildren,
EventEmitter,
HostListener,
Inject,
Input,
Optional,
Output,
QueryList,
} from '@angular/core';
import { ContextMenuService, IContextMenuClickEvent } from './context-menu.service';
import { ContextMenuItemDirective } from './context-menu.item.directive';
export interface ILinkConfig {
click: (item: any, $event?: MouseEvent) => void;
enabled?: (item: any) => boolean;
html: (item: any) => string;
}
@Component({
selector: 'context-menu',
styles: [ ] ,
template:
`
`,
})
export class ContextMenuComponent implements AfterContentInit {
@Output() public close: EventEmitter = new EventEmitter();
@ContentChildren(ContextMenuItemDirective) public menuItems: QueryList;
public visibleMenuItems: ContextMenuItemDirective[] = [];
public links: ILinkConfig[] = [];
public isShown: boolean = false;
public isOpening: boolean = false;
public item: any;
private mouseLocation: { left: number, top: number } = { left: 0, top: 0 };
constructor(
private _contextMenuService: ContextMenuService,
private changeDetector: ChangeDetectorRef,
) {
_contextMenuService.show.subscribe(menuEvent => this.onMenuEvent(menuEvent));
}
get locationCss(): any {
return {
'position': 'fixed',
'display': this.isShown ? 'block' : 'none',
left: this.mouseLocation.left + 'px',
top: this.mouseLocation.top + 'px',
};
}
@HostListener('document:click')
@HostListener('document:contextmenu')
public clickedOutside(): void {
if (!this.isOpening) {
this.hideMenu();
}
}
public ngAfterContentInit(): void {
this.menuItems.forEach(menuItem => {
menuItem.execute.subscribe(() => this.hideMenu());
});
}
public isMenuItemEnabled(menuItem: ContextMenuItemDirective): boolean {
return this.evaluateIfFunction(menuItem.enabled);
}
public isMenuItemVisible(menuItem: ContextMenuItemDirective): boolean {
return this.evaluateIfFunction(menuItem.visible);
}
public evaluateIfFunction(value: any): any {
if (value instanceof Function) {
return value(this.item);
}
return value;
}
public isDisabled(link: ILinkConfig): boolean {
return link.enabled && !link.enabled(this.item);
}
public execute(link: ILinkConfig, $event?: MouseEvent): void {
if (this.isDisabled(link)) {
return;
}
this.hideMenu();
link.click(this.item, $event);
}
public onMenuEvent(menuEvent: IContextMenuClickEvent): void {
let { actions, contextMenu, event, item } = menuEvent;
if (contextMenu && contextMenu !== this) {
this.hideMenu();
return;
}
this.isOpening = true;
setTimeout(() => this.isOpening = false, 400);
if (actions) {
if (console && console.warn) {
console.warn(`actions configuration object is deprecated and will be removed in version 1.x.
See https://github.com/isaacplmann/angular2-contextmenu for the new declarative syntax.`);
}
}
if (actions && actions.length > 0) {
// Imperative context menu
this.setVisibleMenuItems();
this.showMenu();
} else if (this.menuItems) {
// Declarative context menu
setTimeout(() => {
this.setVisibleMenuItems();
if (this.visibleMenuItems.length > 0) {
this.showMenu();
} else {
this.hideMenu();
}
});
} else {
this.hideMenu();
}
this.links = actions;
this.item = item;
this.mouseLocation = {
left: event.clientX,
top: event.clientY,
};
}
public setVisibleMenuItems(): void {
this.visibleMenuItems = this.menuItems.filter(menuItem => this.isMenuItemVisible(menuItem));
}
public showMenu(): void {
this.isShown = true;
this.changeDetector.markForCheck();
}
public hideMenu(): void {
if (this.isShown === true) {
this.close.emit({});
}
this.isShown = false;
this.changeDetector.markForCheck();
}
}