import { Component , EventEmitter , Inject , Input , OnDestroy , OnInit , Output , Renderer2 , ViewChild } from '@angular/core' ; import { NodeMenuService } from './node-menu.service' ; import { NodeMenuAction , NodeMenuItemAction , NodeMenuItemSelectedEvent } from './menu.events' ; import { isEscapePressed , isLeftButtonClicked } from '../utils/event.utils' ; @ Component ( { selector : 'node-menu' , template : `
    <div class="node-menu">
      <ul class="node-menu-content" #menuContainer>
        <li class="node-menu-item" *ngFor="let menuItem of availableMenuItems"
          (click)="onMenuItemSelected($event, menuItem)">
          <div class="node-menu-item-icon {{menuItem.cssClass}}"></div>
          <span class="node-menu-item-value">{{menuItem.name}}</span>
        </li>
      </ul>
    </div>
  ` } ) export class NodeMenuComponent implements OnInit , OnDestroy { @ Output ( ) public menuItemSelected : EventEmitter < NodeMenuItemSelectedEvent > = new EventEmitter < NodeMenuItemSelectedEvent > ( ) ; @ Input ( ) public menuItems : NodeMenuItem [ ] ; @ ViewChild ( 'menuContainer' ) public menuContainer : any ; public availableMenuItems : NodeMenuItem [ ] = [ { name : 'New tag' , action : NodeMenuItemAction . NewTag , cssClass : 'new-tag' } , { name : 'New folder' , action : NodeMenuItemAction . NewFolder , cssClass : 'new-folder' } , { name : 'Rename' , action : NodeMenuItemAction . Rename , cssClass : 'rename' } , { name : 'Remove' , action : NodeMenuItemAction . Remove , cssClass : 'remove' } ] ; private disposersForGlobalListeners : Function [ ] = [ ] ; public constructor ( @ Inject ( Renderer2 ) private renderer , @ Inject ( NodeMenuService ) private nodeMenuService ) { } public ngOnInit ( ) { this . availableMenuItems = this . menuItems || this . availableMenuItems ; this . disposersForGlobalListeners . push ( this . renderer . listen ( 'document' , 'keyup' , this . closeMenu . bind ( this ) ) ) ; this . disposersForGlobalListeners . push ( this . renderer . listen ( 'document' , 'mousedown' , this . closeMenu . bind ( this ) ) ) ; } public ngOnDestroy ( ) { this . disposersForGlobalListeners . forEach ( ( dispose ) => dispose ( ) ) ; } public onMenuItemSelected ( e , selectedMenuItem ) { if ( isLeftButtonClicked ( e ) ) { this . menuItemSelected . emit ( { nodeMenuItemAction : selectedMenuItem . action , nodeMenuItemSelected : selectedMenuItem . name } ) ; this . nodeMenuService . fireMenuEvent ( e . target as HTMLElement , NodeMenuAction . Close ) ; } } private closeMenu ( e ) { const mouseClicked = e instanceof MouseEvent ; const containingTarget = this . menuContainer . nativeElement !== e . target && this . menuContainer . nativeElement . contains ( e . target ) ; if ( ( mouseClicked && ! containingTarget ) || isEscapePressed ( e as KeyboardEvent ) ) { this . nodeMenuService . fireMenuEvent ( e . target as HTMLElement , NodeMenuAction . Close ) ; } } } export interface NodeMenuItem { name : string ; action : NodeMenuItemAction ; cssClass ? : string ; }