import { extend } from '../../Helpers/Extend';
import { strToDOM } from '../../DOM/StrToDOM';
import { slice } from '../../Helpers/Slice';
import { aClass, rClass } from '../../DOM/Class';
import { append, remove } from '../../DOM/Manipulation';
import { wait } from '../../Helpers/Wait';
import onTransitionEnd from '../../Events/OnTransitionEnd';
import Notification from './Notification';
const DEFAULT_OPTIONS = {
"$wrapper": document.body,
"autoCloseDelay": "5", // s
"templates": {
"notifications": "
",
"notification": ""
},
"selectors": {
"notifications": ".notifications",
"list": ".list",
"notification": ".notification"
},
"cssClass": {
"open": "open",
"success": "success",
"danger": "danger",
"warning": "warning",
"info": "info"
},
"animations": {
"show": ( $notification, options ) => {
aClass( $notification, options.cssClass.open );
return Promise.resolve();
},
"hide": ( $notification, options ) => {
const prom = onTransitionEnd( $notification );
wait().then( () => rClass( $notification, options.cssClass.open ) );
return prom;
}
}
};
/**
* Manages a list of notifications
*
* @example let notifSys = new Notification();
* notifSys.add( 'Here is a simple notification' );
*/
export default class Notifications {
#options: FLib.Notifications.Options;
#$list: HTMLElement;
#$notifications: HTMLElement;
#notificationsList: Notification[];
constructor( userOptions: Partial ) {
this.#options = extend( {}, DEFAULT_OPTIONS, userOptions );
this.#notificationsList = [];
this.#$notifications = document.querySelector( this.#options.selectors.notifications ) as HTMLElement;
if ( !this.#$notifications ) {
this.#$notifications = strToDOM( this.#options.templates.notifications ) as HTMLElement;
append( this.#$notifications, this.#options.$wrapper );
}
this.#$list = this.#$notifications.querySelector( this.#options.selectors.list ) as HTMLElement;
this.#$list.querySelectorAll( this.#options.selectors.notification ).forEach( $notification => {
this.#insertNotification( $notification as HTMLElement );
} );
}
#insertNotification = ( htmlOrHTMLElement: string | HTMLElement, type: FLib.Notifications.Type = 'info', notificationOptions?: FLib.Notifications.NotificationOptions ): void => {
const notification = new Notification( htmlOrHTMLElement, type, this.#options, this.#close.bind( this ), notificationOptions );
notification.show( this.#$list );
if ( !this.#notificationsList.length ) {
aClass( this.#$notifications, 'open' );
}
this.#notificationsList.push( notification );
}
#close = ( notification: Notification ): void => {
notification.hide().then( () => {
this.#notificationsList = slice( this.#notificationsList, notification );
if ( !this.#notificationsList.length ) {
rClass( this.#$notifications, 'open' );
}
} );
}
/**
* Add a new notification.
*/
add( html: string, type?: FLib.Notifications.Type, notificationOptions?: FLib.Notifications.NotificationOptions ): this {
this.#insertNotification( html, type, notificationOptions );
return this;
}
/**
* Add a new information notification.
*/
addInfo( html: string, notificationOptions?: FLib.Notifications.NotificationOptions ): this {
this.#insertNotification( html, 'info', notificationOptions );
return this;
}
/**
* Add a new success notification.
*/
addSuccess( html: string, notificationOptions?: FLib.Notifications.NotificationOptions ): this {
this.#insertNotification( html, 'success', notificationOptions );
return this;
}
/**
* Add a new warning notification.
*/
addWarning( html: string, notificationOptions?: FLib.Notifications.NotificationOptions ): this {
this.#insertNotification( html, 'warning', notificationOptions );
return this;
}
/**
* Add a new error/danger notification.
*/
addDanger( html: string, notificationOptions?: FLib.Notifications.NotificationOptions ): this {
this.#insertNotification( html, 'danger', notificationOptions );
return this;
}
/**
* Close all notifications
*/
closeAll(): Promise {
return Promise.all( this.#notificationsList.map( notification => notification.hide() ) );
}
/**
* Close all notifications and remove all containers
*/
clean(): Promise {
return this.closeAll()
.then( () => remove( this.#$notifications ) );
}
}