import { pg } from "./Pages"; import { Control, type IControlOptions } from "./Control"; import Velocity from "velocity-animate"; const stringNotification = 'Notification'; export interface INotificationOptions extends IControlOptions { style?: "simple" | "bar" | "flip" | "circle"; message?: string, position?: "top" | "left" | "right" | "bottom" | "top-right" | "top-left" | "bottom-right" | "bottom-left", type?: "info" | "warning" | "danger" | "error", showClose?: boolean, timeout?: number, thumbnail?: string, title?: string, onShown?: (sender?: Notification) => void, onClosed?: (sender?: Notification) => void } const defaultProps: INotificationOptions = { style: "simple", message: null, position: "top-right", type: "info", showClose: true, timeout: 4000, onShown: () => {}, onClosed: () => {} }; export class Notification extends Control { wrapper: HTMLDivElement; notification: HTMLDivElement; alert: HTMLDivElement; constructor(element: HTMLElement | string, options: INotificationOptions) { super(element, options, defaultProps); this.notification = document.createElement('div') this.notification.className = "pgn push-on-sidebar-open" if (!this.element.querySelectorAll('.pgn-wrapper[data-position=' + this.options.position + ']').length) { this.wrapper = document.createElement('div'); this.wrapper.className = "pgn-wrapper"; this.wrapper.dataset.position=this.options.position; this.element.appendChild(this.wrapper); } else { this.wrapper = document.querySelector('.pgn-wrapper[data-position=' + this.options.position + ']'); } this.alert = document.createElement('div'); pg.addClass(this.alert, 'alert-' + this.options.type) pg.addClass(this.alert, 'alert') if (this.options.style == 'bar') { this.BarNotification(); } else if (this.options.style == 'flip') { this.FlipNotification(); } else if (this.options.style == 'circle') { this.CircleNotification(); } else if (this.options.style == 'simple') { this.SimpleNotification(); } else { // default = 'simple' this.SimpleNotification(); } this.bind(); } private bind = () => { const self = this; this.notification.appendChild(this.alert); if(pg.hasClass(document.body, 'horizontal-menu')){ this.alignWrapperToContainer() pg.on(window, 'resize', this.alignWrapperToContainer); } // bind to Bootstrap closed event for alerts pg.live('.close', 'click', function() { self.close(); // refresh layout after removal }); }; private alignWrapperToContainer = () => { const { element } = this; const parentNode: HTMLElement = element.parentNode as HTMLElement; const containerPosition = element.getBoundingClientRect(); const containerHeight = element.getBoundingClientRect().height; const containerWidth = element.getBoundingClientRect().width; const containerTop = containerPosition.top const containerBottom = parentNode.getBoundingClientRect().height - (containerTop + containerHeight) const containerLeft = containerPosition.left const containerRight = parentNode.getBoundingClientRect().width - (containerLeft + containerWidth) if(/top/.test(this.options.position)) { this.wrapper.style.top = containerTop + 'px'; } if(/bottom/.test(this.options.position)) { this.wrapper.style.bottom = containerBottom + 'px'; } if(/left/.test(this.options.position)) { this.wrapper.style.left = containerLeft + 'px'; } if(/right/.test(this.options.position)) { this.wrapper.style.right = containerRight + 'px'; } }; private SimpleNotification = () => { pg.addClass(this.notification, 'pgn-simple'); this.alert.insertAdjacentText("afterbegin", this.options.message); if (this.options.showClose) { const close = document.createElement('button') close.setAttribute('type', 'button') close.className = 'close' close.dataset.dismiss="alert" const icon1 = document.createElement('span') icon1.setAttribute('aria-hidde', 'true') icon1.innerHTML = '×' const icon2 = document.createElement('span') icon2.className = 'sr-only' icon2.innerHTML = 'Close' close.appendChild(icon1) close.appendChild(icon2); this.alert.insertAdjacentElement("afterbegin", close); } }; private BarNotification = () => { pg.addClass(this.notification, 'pgn-bar'); pg.addClass(this.alert, 'alert-' + this.options.type); const container = document.createElement('div') container.className = "container" container.innerHTML = '' + this.options.message + ''; if (this.options.showClose) { const close = document.createElement('button') close.setAttribute('type', 'button') close.className = 'close' close.dataset.dismiss="alert" close.innerHTML = 'Close' container.appendChild(close) } this.alert.appendChild(container); }; private CircleNotification = () => { pg.addClass(this.notification, 'pgn-circle'); let table = '
'; if (this.options.thumbnail) { table += '
' + this.options.thumbnail + '
'; } table += '
'; if (this.options.title) { table += '

' + this.options.title + '

'; } table += '

' + this.options.message + '

'; table += '
'; if (this.options.showClose) { table += ''; } this.alert.innerHTML = table; const clearfix = document.createElement('div') clearfix.className = 'clearfix' // self.alert.parentNode.insertBefore(clearfix, self.alert.nextSibling); }; private FlipNotification = () => { pg.addClass(this.notification, 'pgn-flip'); this.alert.innerHTML = "" + this.options.message + ""; if (this.options.showClose) { const close = document.createElement('button') close.setAttribute('type', 'button') close.className = 'close' close.dataset.dismiss="alert" close.innerHTML = 'Close' this.alert.insertAdjacentElement("afterbegin", close); } }; public show() { // TODO: add fadeOut animation on show as option this.wrapper.insertAdjacentElement("afterbegin", this.notification); this.options.onShown(); if (this.options.timeout != 0) { const self = this; // settimeout removes scope. use .bind(this) setTimeout(function() { Velocity(self.notification, { opacity: 0 }, { duration: 300, complete:function(){ self.close(); } }); }.bind(this), this.options.timeout); } } public close = () => { this.notification.remove(); this.options.onClosed(); }; } export const notify = (options: INotificationOptions) => { const note = new Notification(document.body, options); note.show(); return note; }; pg[stringNotification] = Notification;