import {Component, EventEmitter, OnInit, OnDestroy, ViewEncapsulation, Input, Output} from '@angular/core'; import {Notification} from './notification.type'; import {NotificationsService} from './notifications.service'; import {Options} from './options.type'; import {Subscription} from 'rxjs/Subscription'; @Component({ selector: 'simple-notifications', encapsulation: ViewEncapsulation.None, template: `
`, styles: [` .simple-notification-wrapper { position: fixed; width: 300px; z-index: 1000; } .simple-notification-wrapper.left { left: 20px; } .simple-notification-wrapper.top { top: 20px; } .simple-notification-wrapper.right { right: 20px; } .simple-notification-wrapper.bottom { bottom: 20px; } @media (max-width: 340px) { .simple-notification-wrapper { width: auto; left: 20px; right: 20px; } } `] }) export class SimpleNotificationsComponent implements OnInit, OnDestroy { @Input() set options(opt: Options) { this.attachChanges(opt); } @Output() onCreate = new EventEmitter(); @Output() onDestroy = new EventEmitter(); public notifications: Notification[] = []; public position: ['top' | 'bottom', 'right' | 'left'] = ['bottom', 'right']; private lastNotificationCreated: Notification; private listener: Subscription; // Received values private lastOnBottom: boolean = true; private maxStack: number = 8; private preventLastDuplicates: any = false; private preventDuplicates: boolean = false; // Sent values public timeOut: number = 0; public maxLength: number = 0; public clickToClose: boolean = true; public showProgressBar: boolean = true; public pauseOnHover: boolean = true; public theClass: string = ''; public rtl: boolean = false; public animate: 'fromRight' | 'fromLeft' | 'rotate' | 'scale' = 'fromRight'; constructor(private _service: NotificationsService) {} ngOnInit(): void { // Listen for changes in the service this.listener = this._service.getChangeEmitter() .subscribe(item => { switch (item.command) { case 'cleanAll': this.notifications = []; break; case 'clean': this.cleanSingle(item.id!); break; case 'set': if (item.add) this.add(item.notification!); else this.defaultBehavior(item); break; default: this.defaultBehavior(item); break; } }); } // Default behavior on event defaultBehavior(value: any): void { this.notifications.splice(this.notifications.indexOf(value.notification), 1); this.onDestroy.emit(this.buildEmit(value.notification, false)); } // Add the new notification to the notification array add(item: Notification): void { item.createdOn = new Date(); let toBlock: boolean = this.preventLastDuplicates || this.preventDuplicates ? this.block(item) : false; // Save this as the last created notification this.lastNotificationCreated = item; if (!toBlock) { // Check if the notification should be added at the start or the end of the array if (this.lastOnBottom) { if (this.notifications.length >= this.maxStack) this.notifications.splice(0, 1); this.notifications.push(item); } else { if (this.notifications.length >= this.maxStack) this.notifications.splice(this.notifications.length - 1, 1); this.notifications.splice(0, 0, item); } this.onCreate.emit(this.buildEmit(item, true)); } } // Check if notifications should be prevented block(item: Notification): boolean { let toCheck = item.html ? this.checkHtml : this.checkStandard; if (this.preventDuplicates && this.notifications.length > 0) { for (let i = 0; i < this.notifications.length; i++) { if (toCheck(this.notifications[i], item)) { return true; } } } if (this.preventLastDuplicates) { let comp: Notification; if (this.preventLastDuplicates === 'visible' && this.notifications.length > 0) { if (this.lastOnBottom) { comp = this.notifications[this.notifications.length - 1]; } else { comp = this.notifications[0]; } } else if (this.preventLastDuplicates === 'all' && this.lastNotificationCreated) { comp = this.lastNotificationCreated; } else { return false; } return toCheck(comp, item); } return false; } checkStandard(checker: Notification, item: Notification): boolean { return checker.type === item.type && checker.title === item.title && checker.content === item.content; } checkHtml(checker: Notification, item: Notification): boolean { return checker.html ? checker.type === item.type && checker.title === item.title && checker.content === item.content && checker.html === item.html : false; } // Attach all the changes received in the options object attachChanges(options: any): void { Object.keys(options).forEach(a => { if (this.hasOwnProperty(a)) { (this)[a] = options[a]; } }); } buildEmit(notification: Notification, to: boolean) { let toEmit: Notification = { createdOn: notification.createdOn, type: notification.type, icon: notification.icon, id: notification.id }; if (notification.html) { toEmit.html = notification.html; } else { toEmit.title = notification.title; toEmit.content = notification.content; } if (!to) { toEmit.destroyedOn = new Date(); } return toEmit; } cleanSingle(id: string): void { let indexOfDelete: number = 0; let doDelete: boolean = false; this.notifications.forEach((notification, idx) => { if (notification.id === id) { indexOfDelete = idx; doDelete = true; } }); if (doDelete) { this.notifications.splice(indexOfDelete, 1); } } ngOnDestroy(): void { if (this.listener) { this.listener.unsubscribe(); } } }