import { NgModule, Component, ElementRef, AfterViewInit, OnDestroy, Input, Output, Renderer2, Inject, forwardRef, ViewChild, NgZone } from '@angular/core'; import { CommonModule } from '@angular/common'; import { DomHandler } from '../dom/domhandler'; import { MenuItem } from '../common/menuitem'; import { Location } from '@angular/common'; import { RouterModule } from '@angular/router'; @Component({ selector: 'p-contextMenuSub', template: ` `, providers: [DomHandler] }) export class ContextMenuSub { @Input() item: MenuItem; @Input() root: boolean; constructor(public domHandler: DomHandler, @Inject(forwardRef(() => ContextMenu)) public contextMenu: ContextMenu) { } activeItem: any; containerLeft: any; hideTimeout: any; onItemMouseEnter(event, item, menuitem) { if (menuitem.disabled) { return; } if (this.hideTimeout) { clearTimeout(this.hideTimeout); this.hideTimeout = null; } this.activeItem = item; let nextElement = item.children[0].nextElementSibling; if (nextElement) { let sublist = nextElement.children[0]; sublist.style.zIndex = ++DomHandler.zindex; this.position(sublist, item); } } onItemMouseLeave(event, link) { this.hideTimeout = setTimeout(() => { this.activeItem = null; }, 1000); } itemClick(event, item: MenuItem)  { if (item.disabled) { event.preventDefault(); return; } if (!item.url) { event.preventDefault(); } if (item.command) { item.command({ originalEvent: event, item: item }); } } listClick(event) { this.activeItem = null; } position(sublist, item) { this.containerLeft = this.domHandler.getOffset(item.parentElement) let viewport = this.domHandler.getViewport(); let sublistWidth = sublist.offsetParent ? sublist.offsetWidth : this.domHandler.getHiddenElementOuterWidth(sublist); let itemOuterWidth = this.domHandler.getOuterWidth(item.children[0]); sublist.style.top = '0px'; if ((parseInt(this.containerLeft.left) + itemOuterWidth + sublistWidth) > (viewport.width - this.calculateScrollbarWidth())) { sublist.style.left = -sublistWidth + 'px'; } else { sublist.style.left = itemOuterWidth + 'px'; } } calculateScrollbarWidth(): number { let scrollDiv = document.createElement("div"); scrollDiv.className = "ui-scrollbar-measure"; document.body.appendChild(scrollDiv); let scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; document.body.removeChild(scrollDiv); return scrollbarWidth; } } @Component({ selector: 'p-contextMenu', template: `
`, providers: [DomHandler] }) export class ContextMenu implements AfterViewInit, OnDestroy { @Input() model: MenuItem[]; @Input() global: boolean; @Input() target: any; @Input() style: any; @Input() styleClass: string; @Input() appendTo: any; @Input() autoZIndex: boolean = true; @Input() baseZIndex: number = 0; @ViewChild('container') containerViewChild: ElementRef; documentClickListener: any; windowResizeListener: any; rightClickListener: any; constructor(public el: ElementRef, public domHandler: DomHandler, public renderer: Renderer2, public zone: NgZone) { } ngAfterViewInit() { if (this.global) { this.rightClickListener = this.renderer.listen('document', 'contextmenu', (event) => { this.show(event); event.preventDefault(); }); } else if (this.target) { this.rightClickListener = this.renderer.listen(this.target, 'contextmenu', (event) => { this.show(event); event.preventDefault(); event.stopPropagation(); }); } if (this.appendTo) { if (this.appendTo === 'body') document.body.appendChild(this.containerViewChild.nativeElement); else this.domHandler.appendChild(this.containerViewChild.nativeElement, this.appendTo); } } show(event?: MouseEvent) { this.position(event); this.moveOnTop(); this.containerViewChild.nativeElement.style.display = 'block'; this.domHandler.fadeIn(this.containerViewChild.nativeElement, 250); this.bindGlobalListeners(); if (event) { event.preventDefault(); } } hide() { this.containerViewChild.nativeElement.style.display = 'none'; this.unbindGlobalListeners(); } moveOnTop() { if (this.autoZIndex) { this.containerViewChild.nativeElement.style.zIndex = String(this.baseZIndex + (++DomHandler.zindex)); } } toggle(event?: MouseEvent) { if (this.containerViewChild.nativeElement.offsetParent) this.hide(); else this.show(event); } position(event?: MouseEvent) { if (event) { let left = event.pageX + 1; let top = event.pageY + 1; let width = this.containerViewChild.nativeElement.offsetParent ? this.containerViewChild.nativeElement.offsetWidth : this.domHandler.getHiddenElementOuterWidth(this.containerViewChild.nativeElement); let height = this.containerViewChild.nativeElement.offsetParent ? this.containerViewChild.nativeElement.offsetHeight : this.domHandler.getHiddenElementOuterHeight(this.containerViewChild.nativeElement); let viewport = this.domHandler.getViewport(); //flip if (left + width - document.body.scrollLeft > viewport.width) { left -= width; } //flip if (top + height - document.body.scrollTop > viewport.height) { top -= height; } //fit if (left < document.body.scrollLeft) { left = document.body.scrollLeft; } //fit if (top < document.body.scrollTop) { top = document.body.scrollTop; } this.containerViewChild.nativeElement.style.left = left + 'px'; this.containerViewChild.nativeElement.style.top = top + 'px'; } } bindGlobalListeners() { if (!this.documentClickListener) { this.documentClickListener = this.renderer.listen('document', 'click', (event) => { if (this.containerViewChild.nativeElement.offsetParent && event.button !== 2) { this.hide(); } }); } this.zone.runOutsideAngular(() => { if (!this.windowResizeListener) { this.windowResizeListener = this.onWindowResize.bind(this); window.addEventListener('resize', this.windowResizeListener); } }); } unbindGlobalListeners() { if (this.documentClickListener) { this.documentClickListener(); this.documentClickListener = null; } if (this.windowResizeListener) { window.removeEventListener('resize', this.windowResizeListener); this.windowResizeListener = null; } } onWindowResize(event) { if (this.containerViewChild.nativeElement.offsetParent) { this.hide(); } } ngOnDestroy() { this.unbindGlobalListeners(); if (this.rightClickListener) { this.rightClickListener(); } if (this.appendTo) { this.el.nativeElement.appendChild(this.containerViewChild.nativeElement); } } } @NgModule({ imports: [CommonModule, RouterModule], exports: [ContextMenu, RouterModule], declarations: [ContextMenu, ContextMenuSub] }) export class ContextMenuModule { }