src/dialog/dialog.directive.ts
        
A generic directive that can be inherited from to create dialogs (for example, a tooltip or popover)
This class contains the relevant initialization code, specific templates, options, and additional inputs should be specified in the derived class.
NOTE: All child classes should add DialogService as a provider, otherwise they will lose context that
the service relies on.
                        OnInit
                        OnDestroy
                        OnChanges
            
| Providers | 
                            
                                DialogService
                            
                         | 
                    
| Selector | [cdsDialog], [ibmDialog] | 
                    
| exportAs | dialog | 
                    
                        Properties | 
                
                        
  | 
                
                        Methods | 
                
                        
  | 
                
                        Inputs | 
                
                        Outputs | 
                
                        HostBindings | 
                
                            Accessors | 
                    
constructor(elementRef: ElementRef, viewContainerRef: ViewContainerRef, dialogService: DialogService, eventService: EventService)
                     | 
                |||||||||||||||
| 
                                 Defined in src/dialog/dialog.directive.ts:129 
                             | 
                        |||||||||||||||
| 
                             Creates an instance of DialogDirective. 
                                    Parameters :
                                     
                    
  | 
                
| appendInline | |
                        Type :         boolean
                     | 
                |
                        Default value : false
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:86 
                             | 
                        |
| 
                         Set to   | 
                |
| cdsDialog | |
                        Type :     string | TemplateRef<any>
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:52 
                             | 
                        |
| closeTrigger | |
                        Type :     "mouseout" | "mouseleave"
                     | 
                |
                        Default value : "mouseleave"
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:66 
                             | 
                        |
| 
                         Defines how the Dialog close event is triggered. See here
for more on the difference between  Defaults to   | 
                |
| data | |
                        Type :     {}
                     | 
                |
                        Default value : {}
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:90 
                             | 
                        |
| 
                         Optional data for templates  | 
                |
| disabled | |
                        Type :         boolean
                     | 
                |
                        Default value : false
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:96 
                             | 
                        |
| 
                         This prevents the dialog from being toggled  | 
                |
| gap | |
                        Type :         number
                     | 
                |
                        Default value : 0
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:82 
                             | 
                        |
| 
                         Spacing between the dialog and it's triggering element  | 
                |
| ibmDialog | |
                        Type :     string | TemplateRef
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:48 
                             | 
                        |
| isOpen | |
                        Type :         boolean
                     | 
                |
                        Default value : false
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:92 
                             | 
                        |
| offset | |
                        Type :     literal type
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:74 
                             | 
                        |
| 
                         This specifies any vertical and horizontal offset for the position of the dialog  | 
                |
| placement | |
                        Type :         string
                     | 
                |
                        Default value : "left"
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:70 
                             | 
                        |
| 
                         Placement of the dialog, usually relative to the element the directive is on.  | 
                |
| shouldClose | |
                        Type :         function
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:100 
                             | 
                        |
| 
                         This input allows explicit control over how the dialog should close  | 
                |
| title | |
                        Type :         string
                     | 
                |
                        Default value : ""
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:43 
                             | 
                        |
| 
                         Title for the dialog  | 
                |
| trigger | |
                        Type :     "click" | "hover" | "mouseenter"
                     | 
                |
                        Default value : "click"
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:57 
                             | 
                        |
| 
                         Defines how the Dialog is triggered.(Hover and click behave the same on mobile - both respond to a single tap).
Do not add focusable elements if trigger is   | 
                |
| wrapperClass | |
                        Type :         string
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:78 
                             | 
                        |
| 
                         Classes to add to the dialog container  | 
                |
| isOpenChange | |
                        Type :     EventEmitter
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:116 
                             | 
                        |
| 
                         Emits an event when the state of   | 
                |
| onClose | |
                        Type :     EventEmitter<any>
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:108 
                             | 
                        |
| 
                         Emits an event when the dialog is closed  | 
                |
| onOpen | |
                        Type :     EventEmitter<any>
                     | 
                |
| 
                                     Defined in src/dialog/dialog.directive.ts:112 
                             | 
                        |
| 
                         Emits an event when the dialog is opened  | 
                |
| attr.aria-haspopup | 
                        Type :         boolean
                     | 
                
                        Default value : true
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:119 
                         | 
                    
| attr.aria-owns | 
                        Type :         string
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:120 
                         | 
                    
| attr.role | 
                        Type :         string
                     | 
                
                        Default value : "button"
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:118 
                         | 
                    
| close | ||||||||
close(meta: CloseMeta)
                 | 
            ||||||||
| 
                             Defined in src/dialog/dialog.directive.ts:305 
                         | 
                    ||||||||
| 
                         Helper method to close the dialogRef. 
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            void
                         | 
            
| ngOnChanges | ||||||
ngOnChanges(changes: SimpleChanges)
                 | 
            ||||||
| 
                             Defined in src/dialog/dialog.directive.ts:148 
                         | 
                    ||||||
| 
                             
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            void
                         | 
            
| ngOnDestroy | 
ngOnDestroy()
                 | 
            
| 
                             Defined in src/dialog/dialog.directive.ts:252 
                         | 
                    
| 
                         When the host dies, kill the popover. 
 
                            Returns :          
                void
                         | 
            
| ngOnInit | 
ngOnInit()
                 | 
            
| 
                             Defined in src/dialog/dialog.directive.ts:185 
                         | 
                    
| 
                         Sets the config object and binds events for hovering or clicking before running code from child class. 
                            Returns :          
                void
                         | 
            
| Protected onDialogChanges | ||||||
                        
                    onDialogChanges(_changes: SimpleChanges)
                 | 
            ||||||
| 
                             Defined in src/dialog/dialog.directive.ts:321 
                         | 
                    ||||||
| 
                         Empty method for child to override and specify additional on changes steps. run after DialogDirective completes it's ngOnChanges. 
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            void
                         | 
            
| Protected onDialogInit | 
                        
                    onDialogInit()
                 | 
            
| 
                             Defined in src/dialog/dialog.directive.ts:315 
                         | 
                    
| 
                         Empty method for child classes to override and specify additional init steps. Run after DialogDirective completes it's ngOnInit. 
                            Returns :          
                void
                         | 
            
| open | ||||
open(component?)
                 | 
            ||||
| 
                             Defined in src/dialog/dialog.directive.ts:263 
                         | 
                    ||||
| 
                         Helper method to call dialogService 'open'. 
 
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            ComponentRef<Dialog>
                         | 
            
| toggle | ||||||||
toggle(meta: CloseMeta)
                 | 
            ||||||||
| 
                             Defined in src/dialog/dialog.directive.ts:294 
                         | 
                    ||||||||
| 
                         Helper method to toggle the open state of the dialog 
                                Parameters :
                                
                                 
                        
 
                            Returns :          
                            void
                         | 
            
| Protected updateConfig | 
                        
                    updateConfig()
                 | 
            
| 
                             Defined in src/dialog/dialog.directive.ts:323 
                         | 
                    
| 
                         
                            Returns :          
                void
                         | 
            
| dialogConfig | 
                        Type :         DialogConfig
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:104 
                         | 
                    
| 
                     Config object passed to the rendered component  | 
            
| Static dialogCounter | 
                        Type :         number
                     | 
                
                        Default value : 0
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:39 
                         | 
                    
| Protected dialogRef | 
                        Type :         ComponentRef<Dialog>
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:127 
                         | 
                    
| 
                     Keeps a reference to the currently opened dialog  | 
            
| hasPopup | 
                        Default value : true
                     | 
                
                        Decorators : 
                        
                            @HostBinding('attr.aria-haspopup')
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:119 
                         | 
                    
| role | 
                        Type :         string
                     | 
                
                        Default value : "button"
                     | 
                
                        Decorators : 
                        
                            @HostBinding('attr.role')
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:118 
                         | 
                    
| Private subscriptions | 
                        Type :     Subscription[]
                     | 
                
                        Default value : []
                     | 
                
| 
                                 Defined in src/dialog/dialog.directive.ts:129 
                         | 
                    
| ibmDialog | ||||||
                        setibmDialog(body: string | TemplateRef
                     | 
                ||||||
| 
                                     Defined in src/dialog/dialog.directive.ts:48 
                                 | 
                            ||||||
| 
                                 Dialog body content. 
                                        Parameters :
                                         
                                
 
                                    Returns :          
                        void
                                 | 
                    
| ariaOwns | 
                        getariaOwns()
                     | 
                
| 
                                     Defined in src/dialog/dialog.directive.ts:120 
                                 | 
                            
import {
	Directive,
	Input,
	Output,
	EventEmitter,
	OnInit,
	OnDestroy,
	ElementRef,
	TemplateRef,
	ViewContainerRef,
	OnChanges,
	HostBinding,
	SimpleChanges,
	ComponentRef
} from "@angular/core";
import { DialogService } from "./dialog.service";
import { CloseMeta, CloseReasons, DialogConfig } from "./dialog-config.interface";
import { EventService } from "carbon-components-angular/utils";
import { Dialog } from "./dialog.component";
import { fromEvent, Subscription } from "rxjs";
/**
 * A generic directive that can be inherited from to create dialogs (for example, a tooltip or popover)
 *
 * This class contains the relevant initialization code, specific templates, options, and additional inputs
 * should be specified in the derived class.
 *
 * NOTE: All child classes should add `DialogService` as a provider, otherwise they will lose context that
 * the service relies on.
 */
@Directive({
	selector: "[cdsDialog], [ibmDialog]",
	exportAs: "dialog",
	providers: [
		DialogService
	]
})
export class DialogDirective implements OnInit, OnDestroy, OnChanges {
	static dialogCounter = 0;
	/**
	 * Title for the dialog
	 */
	@Input() title = "";
	/**
	 * @deprecated as of v5, use `cdsDialog` instead
	 * Dialog body content.
	 */
	@Input() set ibmDialog(body: string | TemplateRef<any>) {
		this.cdsDialog = body;
	}
	@Input() cdsDialog: string | TemplateRef<any>;
	/**
	 * Defines how the Dialog is triggered.(Hover and click behave the same on mobile - both respond to a single tap).
	 * Do not add focusable elements if trigger is `hover` or `mouseenter`.
	 */
	@Input() trigger: "click" | "hover" | "mouseenter" = "click";
	/**
	 * Defines how the Dialog close event is triggered.
	 *
	 * [See here](https://developer.mozilla.org/en-US/docs/Web/API/Element/mouseleave_event)
	 * for more on the difference between `mouseleave` and `mouseout`.
	 *
	 * Defaults to `click` when `trigger` is set to `click`.
	 */
	@Input() closeTrigger: "mouseout" | "mouseleave" = "mouseleave";
	/**
	 * Placement of the dialog, usually relative to the element the directive is on.
	 */
	@Input() placement = "left";
	/**
	 * This specifies any vertical and horizontal offset for the position of the dialog
	 */
	@Input() offset: { x: number, y: number };
	/**
	 * Classes to add to the dialog container
	 */
	@Input() wrapperClass: string;
	/**
	 * Spacing between the dialog and it's triggering element
	 */
	@Input() gap = 0;
	/**
	 * Set to `true` to open the dialog next to the triggering component
	 */
	@Input() appendInline = false;
	/**
	 * Optional data for templates
	 */
	@Input() data = {};
	@Input() @HostBinding("attr.aria-expanded") isOpen = false;
	/**
	 * This prevents the dialog from being toggled
	 */
	@Input() disabled = false;
	/**
	 * This input allows explicit control over how the dialog should close
	 */
	@Input() shouldClose: (meta: CloseMeta) => boolean;
	/**
	 * Config object passed to the rendered component
	 */
	dialogConfig: DialogConfig;
	/**
	 * Emits an event when the dialog is closed
	 */
	@Output() onClose: EventEmitter<any> = new EventEmitter();
	/**
	 * Emits an event when the dialog is opened
	 */
	@Output() onOpen: EventEmitter<any> = new EventEmitter();
	/**
	 * Emits an event when the state of `isOpen` changes. Allows `isOpen` to be double bound
	 */
	@Output() isOpenChange = new EventEmitter<boolean>();
	@HostBinding("attr.role") role = "button";
	@HostBinding("attr.aria-haspopup") hasPopup = true;
	@HostBinding("attr.aria-owns") get ariaOwns(): string {
		return this.isOpen ? this.dialogConfig.compID : null;
	}
	/**
	 * Keeps a reference to the currently opened dialog
	 */
	protected dialogRef: ComponentRef<Dialog>;
	private subscriptions: Subscription[] = [];
	/**
	 * Creates an instance of DialogDirective.
	 * @param elementRef
	 * @param viewContainerRef
	 * @param dialogService
	 * @param eventService
	 */
	constructor(
		protected elementRef: ElementRef,
		protected viewContainerRef: ViewContainerRef,
		protected dialogService: DialogService,
		/**
		 * Deprecated as of v5
		 */
		protected eventService: EventService
	) {}
	ngOnChanges(changes: SimpleChanges) {
		// set the config object (this can [and should!] be added to in child classes depending on what they need)
		this.dialogConfig = {
			title: this.title,
			content: this.cdsDialog,
			placement: this.placement,
			parentRef: this.elementRef,
			gap: this.gap,
			trigger: this.trigger,
			closeTrigger: this.closeTrigger,
			shouldClose: this.shouldClose || (() => true),
			appendInline: this.appendInline,
			wrapperClass: this.wrapperClass,
			data: this.data,
			offset: this.offset,
			disabled: this.disabled
		};
		if (changes.isOpen) {
			if (changes.isOpen.currentValue) {
				this.open();
			} else if (!changes.isOpen.firstChange) {
				this.close({
					reason: CloseReasons.programmatic
				});
			}
		}
		// Run any code a child class may need.
		this.onDialogChanges(changes);
		this.updateConfig();
	}
	/**
	 * Sets the config object and binds events for hovering or clicking before
	 * running code from child class.
	 */
	ngOnInit() {
		// fix for safari hijacking clicks
		this.dialogService.singletonClickListen();
		const element: HTMLElement = this.elementRef.nativeElement;
		this.subscriptions.push(
			fromEvent(element, "keydown").subscribe((event: KeyboardEvent) => {
				if (event.target === this.dialogConfig.parentRef.nativeElement &&
					(event.key === "Tab" || event.key === "Tab" && event.shiftKey) ||
					event.key === "Escape") {
					this.close({
						reason: CloseReasons.interaction,
						target: event.target
					});
				}
			})
		);
		// bind events for hovering or clicking the host
		if (this.trigger === "hover" || this.trigger === "mouseenter") {
			this.subscriptions.push(
				fromEvent(element, "mouseenter").subscribe(() => this.open()),
				fromEvent(element, this.closeTrigger).subscribe((event) => {
					this.close({
						reason: CloseReasons.interaction,
						target: event.target
					});
				}),
				fromEvent(element, "focus").subscribe(() => this.open()),
				fromEvent(element, "blur").subscribe((event) => {
					this.close({
						reason: CloseReasons.interaction,
						target: event.target
					});
				})
			);
		} else {
			this.subscriptions.push(
				fromEvent(element, "click").subscribe((event) => {
					this.toggle({
						reason: CloseReasons.interaction,
						target: event.target
					});
				}),
				fromEvent(element, "keydown").subscribe((event: KeyboardEvent) => {
					if (event.key === "Enter" || event.key === " ") {
						setTimeout(() => {
							this.open();
						});
					}
				})
			);
		}
		DialogDirective.dialogCounter++;
		this.dialogConfig.compID = "dialog-" + DialogDirective.dialogCounter;
		// run any code a child class may need
		this.onDialogInit();
		this.updateConfig();
	}
	/**
	 * When the host dies, kill the popover.
	 * - Useful for use in a modal or similar.
	 */
	ngOnDestroy() {
		this.close({
			reason: CloseReasons.destroyed
		});
		this.subscriptions.forEach((subscription) => subscription.unsubscribe());
	}
	/**
	 * Helper method to call dialogService 'open'.
	 * - Enforce accessibility by updating an aria attr for nativeElement.
	 */
	open(component?) {
		// don't allow dialogs to be opened if they're already open
		if (this.dialogRef || this.disabled) { return; }
		// actually open the dialog, emit events, and set the open state
		this.dialogRef = this.dialogService.open(this.viewContainerRef, this.dialogConfig, component);
		this.isOpen = true;
		this.onOpen.emit();
		this.isOpenChange.emit(true);
		// Handles emitting all the close events to clean everything up
		// Also enforce accessibility on close by updating an aria attr on the nativeElement.
		const subscription = this.dialogRef.instance.close.subscribe((meta: CloseMeta) => {
			if (!this.dialogRef) { return; }
			if (this.dialogConfig.shouldClose && this.dialogConfig.shouldClose(meta)) {
				// close the dialog, emit events, and clear out the open states
				this.dialogService.close(this.dialogRef);
				this.dialogRef = null;
				this.isOpen = false;
				this.onClose.emit();
				this.isOpenChange.emit(false);
				subscription.unsubscribe();
			}
		});
		return this.dialogRef;
	}
	/**
	 * Helper method to toggle the open state of the dialog
	 */
	toggle(meta: CloseMeta = { reason: CloseReasons.interaction }) {
		if (!this.isOpen) {
			this.open();
		} else {
			this.close(meta);
		}
	}
	/**
	 * Helper method to close the dialogRef.
	 */
	close(meta: CloseMeta = { reason: CloseReasons.interaction }) {
		if (this.dialogRef) {
			this.dialogRef.instance.doClose(meta);
		}
	}
	/**
	 * Empty method for child classes to override and specify additional init steps.
	 * Run after DialogDirective completes it's ngOnInit.
	 */
	protected onDialogInit() {}
	/**
	 * Empty method for child to override and specify additional on changes steps.
	 * run after DialogDirective completes it's ngOnChanges.
	 */
	protected onDialogChanges(_changes: SimpleChanges) {}
	protected updateConfig() {}
}