ngx-toastr.js 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. import { __decorate, __metadata, __param } from 'tslib';
  2. import { Directive, ElementRef, NgModule, InjectionToken, defineInjectable, inject, Injectable, Inject, ComponentFactoryResolver, ApplicationRef, SecurityContext, INJECTOR, NgZone, Injector, HostBinding, HostListener, Component } from '@angular/core';
  3. import { trigger, state, style, transition, animate } from '@angular/animations';
  4. import { Subject } from 'rxjs';
  5. import { DomSanitizer } from '@angular/platform-browser';
  6. import { DOCUMENT, CommonModule } from '@angular/common';
  7. let ToastContainerDirective = class ToastContainerDirective {
  8. constructor(el) {
  9. this.el = el;
  10. }
  11. getContainerElement() {
  12. return this.el.nativeElement;
  13. }
  14. };
  15. ToastContainerDirective = __decorate([
  16. Directive({
  17. selector: '[toastContainer]',
  18. exportAs: 'toastContainer',
  19. }),
  20. __metadata("design:paramtypes", [ElementRef])
  21. ], ToastContainerDirective);
  22. let ToastContainerModule = class ToastContainerModule {
  23. };
  24. ToastContainerModule = __decorate([
  25. NgModule({
  26. declarations: [ToastContainerDirective],
  27. exports: [ToastContainerDirective],
  28. })
  29. ], ToastContainerModule);
  30. /**
  31. * Everything a toast needs to launch
  32. */
  33. class ToastPackage {
  34. constructor(toastId, config, message, title, toastType, toastRef) {
  35. this.toastId = toastId;
  36. this.config = config;
  37. this.message = message;
  38. this.title = title;
  39. this.toastType = toastType;
  40. this.toastRef = toastRef;
  41. this._onTap = new Subject();
  42. this._onAction = new Subject();
  43. this.toastRef.afterClosed().subscribe(() => {
  44. this._onAction.complete();
  45. this._onTap.complete();
  46. });
  47. }
  48. /** Fired on click */
  49. triggerTap() {
  50. this._onTap.next();
  51. if (this.config.tapToDismiss) {
  52. this._onTap.complete();
  53. }
  54. }
  55. onTap() {
  56. return this._onTap.asObservable();
  57. }
  58. /** available for use in custom toast */
  59. triggerAction(action) {
  60. this._onAction.next(action);
  61. }
  62. onAction() {
  63. return this._onAction.asObservable();
  64. }
  65. }
  66. const DefaultNoComponentGlobalConfig = {
  67. maxOpened: 0,
  68. autoDismiss: false,
  69. newestOnTop: true,
  70. preventDuplicates: false,
  71. countDuplicates: false,
  72. resetTimeoutOnDuplicate: false,
  73. iconClasses: {
  74. error: 'toast-error',
  75. info: 'toast-info',
  76. success: 'toast-success',
  77. warning: 'toast-warning',
  78. },
  79. // Individual
  80. closeButton: false,
  81. disableTimeOut: false,
  82. timeOut: 5000,
  83. extendedTimeOut: 1000,
  84. enableHtml: false,
  85. progressBar: false,
  86. toastClass: 'ngx-toastr',
  87. positionClass: 'toast-top-right',
  88. titleClass: 'toast-title',
  89. messageClass: 'toast-message',
  90. easing: 'ease-in',
  91. easeTime: 300,
  92. tapToDismiss: true,
  93. onActivateTick: false,
  94. progressAnimation: 'decreasing',
  95. };
  96. const TOAST_CONFIG = new InjectionToken('ToastConfig');
  97. /**
  98. * A `ComponentPortal` is a portal that instantiates some Component upon attachment.
  99. */
  100. class ComponentPortal {
  101. constructor(component, injector) {
  102. this.component = component;
  103. this.injector = injector;
  104. }
  105. /** Attach this portal to a host. */
  106. attach(host, newestOnTop) {
  107. this._attachedHost = host;
  108. return host.attach(this, newestOnTop);
  109. }
  110. /** Detach this portal from its host */
  111. detach() {
  112. const host = this._attachedHost;
  113. if (host) {
  114. this._attachedHost = undefined;
  115. return host.detach();
  116. }
  117. }
  118. /** Whether this portal is attached to a host. */
  119. get isAttached() {
  120. return this._attachedHost != null;
  121. }
  122. /**
  123. * Sets the PortalHost reference without performing `attach()`. This is used directly by
  124. * the PortalHost when it is performing an `attach()` or `detach()`.
  125. */
  126. setAttachedHost(host) {
  127. this._attachedHost = host;
  128. }
  129. }
  130. /**
  131. * Partial implementation of PortalHost that only deals with attaching a
  132. * ComponentPortal
  133. */
  134. class BasePortalHost {
  135. attach(portal, newestOnTop) {
  136. this._attachedPortal = portal;
  137. return this.attachComponentPortal(portal, newestOnTop);
  138. }
  139. detach() {
  140. if (this._attachedPortal) {
  141. this._attachedPortal.setAttachedHost();
  142. }
  143. this._attachedPortal = undefined;
  144. if (this._disposeFn) {
  145. this._disposeFn();
  146. this._disposeFn = undefined;
  147. }
  148. }
  149. setDisposeFn(fn) {
  150. this._disposeFn = fn;
  151. }
  152. }
  153. /**
  154. * A PortalHost for attaching portals to an arbitrary DOM element outside of the Angular
  155. * application context.
  156. *
  157. * This is the only part of the portal core that directly touches the DOM.
  158. */
  159. class DomPortalHost extends BasePortalHost {
  160. constructor(_hostDomElement, _componentFactoryResolver, _appRef) {
  161. super();
  162. this._hostDomElement = _hostDomElement;
  163. this._componentFactoryResolver = _componentFactoryResolver;
  164. this._appRef = _appRef;
  165. }
  166. /**
  167. * Attach the given ComponentPortal to DOM element using the ComponentFactoryResolver.
  168. * @param portal Portal to be attached
  169. */
  170. attachComponentPortal(portal, newestOnTop) {
  171. const componentFactory = this._componentFactoryResolver.resolveComponentFactory(portal.component);
  172. let componentRef;
  173. // If the portal specifies a ViewContainerRef, we will use that as the attachment point
  174. // for the component (in terms of Angular's component tree, not rendering).
  175. // When the ViewContainerRef is missing, we use the factory to create the component directly
  176. // and then manually attach the ChangeDetector for that component to the application (which
  177. // happens automatically when using a ViewContainer).
  178. componentRef = componentFactory.create(portal.injector);
  179. // When creating a component outside of a ViewContainer, we need to manually register
  180. // its ChangeDetector with the application. This API is unfortunately not yet published
  181. // in Angular core. The change detector must also be deregistered when the component
  182. // is destroyed to prevent memory leaks.
  183. this._appRef.attachView(componentRef.hostView);
  184. this.setDisposeFn(() => {
  185. this._appRef.detachView(componentRef.hostView);
  186. componentRef.destroy();
  187. });
  188. // At this point the component has been instantiated, so we move it to the location in the DOM
  189. // where we want it to be rendered.
  190. if (newestOnTop) {
  191. this._hostDomElement.insertBefore(this._getComponentRootNode(componentRef), this._hostDomElement.firstChild);
  192. }
  193. else {
  194. this._hostDomElement.appendChild(this._getComponentRootNode(componentRef));
  195. }
  196. return componentRef;
  197. }
  198. /** Gets the root HTMLElement for an instantiated component. */
  199. _getComponentRootNode(componentRef) {
  200. return componentRef.hostView.rootNodes[0];
  201. }
  202. }
  203. /** Container inside which all toasts will render. */
  204. let OverlayContainer = class OverlayContainer {
  205. constructor(_document) {
  206. this._document = _document;
  207. }
  208. ngOnDestroy() {
  209. if (this._containerElement && this._containerElement.parentNode) {
  210. this._containerElement.parentNode.removeChild(this._containerElement);
  211. }
  212. }
  213. /**
  214. * This method returns the overlay container element. It will lazily
  215. * create the element the first time it is called to facilitate using
  216. * the container in non-browser environments.
  217. * @returns the container element
  218. */
  219. getContainerElement() {
  220. if (!this._containerElement) {
  221. this._createContainer();
  222. }
  223. return this._containerElement;
  224. }
  225. /**
  226. * Create the overlay container element, which is simply a div
  227. * with the 'cdk-overlay-container' class on the document body.
  228. */
  229. _createContainer() {
  230. const container = this._document.createElement('div');
  231. container.classList.add('overlay-container');
  232. this._document.body.appendChild(container);
  233. this._containerElement = container;
  234. }
  235. };
  236. OverlayContainer.ngInjectableDef = defineInjectable({ factory: function OverlayContainer_Factory() { return new OverlayContainer(inject(DOCUMENT)); }, token: OverlayContainer, providedIn: "root" });
  237. OverlayContainer = __decorate([
  238. Injectable({ providedIn: 'root' }),
  239. __param(0, Inject(DOCUMENT)),
  240. __metadata("design:paramtypes", [Object])
  241. ], OverlayContainer);
  242. /**
  243. * Reference to an overlay that has been created with the Overlay service.
  244. * Used to manipulate or dispose of said overlay.
  245. */
  246. class OverlayRef {
  247. constructor(_portalHost) {
  248. this._portalHost = _portalHost;
  249. }
  250. attach(portal, newestOnTop = true) {
  251. return this._portalHost.attach(portal, newestOnTop);
  252. }
  253. /**
  254. * Detaches an overlay from a portal.
  255. * @returns Resolves when the overlay has been detached.
  256. */
  257. detach() {
  258. return this._portalHost.detach();
  259. }
  260. }
  261. /**
  262. * Service to create Overlays. Overlays are dynamically added pieces of floating UI, meant to be
  263. * used as a low-level building building block for other components. Dialogs, tooltips, menus,
  264. * selects, etc. can all be built using overlays. The service should primarily be used by authors
  265. * of re-usable components rather than developers building end-user applications.
  266. *
  267. * An overlay *is* a PortalHost, so any kind of Portal can be loaded into one.
  268. */
  269. let Overlay = class Overlay {
  270. constructor(_overlayContainer, _componentFactoryResolver, _appRef, _document) {
  271. this._overlayContainer = _overlayContainer;
  272. this._componentFactoryResolver = _componentFactoryResolver;
  273. this._appRef = _appRef;
  274. this._document = _document;
  275. // Namespace panes by overlay container
  276. this._paneElements = new Map();
  277. }
  278. /**
  279. * Creates an overlay.
  280. * @returns A reference to the created overlay.
  281. */
  282. create(positionClass, overlayContainer) {
  283. // get existing pane if possible
  284. return this._createOverlayRef(this.getPaneElement(positionClass, overlayContainer));
  285. }
  286. getPaneElement(positionClass = '', overlayContainer) {
  287. if (!this._paneElements.get(overlayContainer)) {
  288. this._paneElements.set(overlayContainer, {});
  289. }
  290. if (!this._paneElements.get(overlayContainer)[positionClass]) {
  291. this._paneElements.get(overlayContainer)[positionClass] = this._createPaneElement(positionClass, overlayContainer);
  292. }
  293. return this._paneElements.get(overlayContainer)[positionClass];
  294. }
  295. /**
  296. * Creates the DOM element for an overlay and appends it to the overlay container.
  297. * @returns Newly-created pane element
  298. */
  299. _createPaneElement(positionClass, overlayContainer) {
  300. const pane = this._document.createElement('div');
  301. pane.id = 'toast-container';
  302. pane.classList.add(positionClass);
  303. pane.classList.add('toast-container');
  304. if (!overlayContainer) {
  305. this._overlayContainer.getContainerElement().appendChild(pane);
  306. }
  307. else {
  308. overlayContainer.getContainerElement().appendChild(pane);
  309. }
  310. return pane;
  311. }
  312. /**
  313. * Create a DomPortalHost into which the overlay content can be loaded.
  314. * @param pane The DOM element to turn into a portal host.
  315. * @returns A portal host for the given DOM element.
  316. */
  317. _createPortalHost(pane) {
  318. return new DomPortalHost(pane, this._componentFactoryResolver, this._appRef);
  319. }
  320. /**
  321. * Creates an OverlayRef for an overlay in the given DOM element.
  322. * @param pane DOM element for the overlay
  323. */
  324. _createOverlayRef(pane) {
  325. return new OverlayRef(this._createPortalHost(pane));
  326. }
  327. };
  328. Overlay.ngInjectableDef = defineInjectable({ factory: function Overlay_Factory() { return new Overlay(inject(OverlayContainer), inject(ComponentFactoryResolver), inject(ApplicationRef), inject(DOCUMENT)); }, token: Overlay, providedIn: "root" });
  329. Overlay = __decorate([
  330. Injectable({ providedIn: 'root' }),
  331. __param(3, Inject(DOCUMENT)),
  332. __metadata("design:paramtypes", [OverlayContainer,
  333. ComponentFactoryResolver,
  334. ApplicationRef, Object])
  335. ], Overlay);
  336. /**
  337. * Reference to a toast opened via the Toastr service.
  338. */
  339. class ToastRef {
  340. constructor(_overlayRef) {
  341. this._overlayRef = _overlayRef;
  342. /** Count of duplicates of this toast */
  343. this.duplicatesCount = 0;
  344. /** Subject for notifying the user that the toast has finished closing. */
  345. this._afterClosed = new Subject();
  346. /** triggered when toast is activated */
  347. this._activate = new Subject();
  348. /** notifies the toast that it should close before the timeout */
  349. this._manualClose = new Subject();
  350. /** notifies the toast that it should reset the timeouts */
  351. this._resetTimeout = new Subject();
  352. /** notifies the toast that it should count a duplicate toast */
  353. this._countDuplicate = new Subject();
  354. }
  355. manualClose() {
  356. this._manualClose.next();
  357. this._manualClose.complete();
  358. }
  359. manualClosed() {
  360. return this._manualClose.asObservable();
  361. }
  362. timeoutReset() {
  363. return this._resetTimeout.asObservable();
  364. }
  365. countDuplicate() {
  366. return this._countDuplicate.asObservable();
  367. }
  368. /**
  369. * Close the toast.
  370. */
  371. close() {
  372. this._overlayRef.detach();
  373. this._afterClosed.next();
  374. this._manualClose.next();
  375. this._afterClosed.complete();
  376. this._manualClose.complete();
  377. this._activate.complete();
  378. this._resetTimeout.complete();
  379. this._countDuplicate.complete();
  380. }
  381. /** Gets an observable that is notified when the toast is finished closing. */
  382. afterClosed() {
  383. return this._afterClosed.asObservable();
  384. }
  385. isInactive() {
  386. return this._activate.isStopped;
  387. }
  388. activate() {
  389. this._activate.next();
  390. this._activate.complete();
  391. }
  392. /** Gets an observable that is notified when the toast has started opening. */
  393. afterActivate() {
  394. return this._activate.asObservable();
  395. }
  396. /** Reset the toast timouts and count duplicates */
  397. onDuplicate(resetTimeout, countDuplicate) {
  398. if (resetTimeout) {
  399. this._resetTimeout.next();
  400. }
  401. if (countDuplicate) {
  402. this._countDuplicate.next(++this.duplicatesCount);
  403. }
  404. }
  405. }
  406. /** Custom injector type specifically for instantiating components with a toast. */
  407. class ToastInjector {
  408. constructor(_toastPackage, _parentInjector) {
  409. this._toastPackage = _toastPackage;
  410. this._parentInjector = _parentInjector;
  411. }
  412. get(token, notFoundValue, flags) {
  413. if (token === ToastPackage) {
  414. return this._toastPackage;
  415. }
  416. return this._parentInjector.get(token, notFoundValue, flags);
  417. }
  418. }
  419. let ToastrService = class ToastrService {
  420. constructor(token, overlay, _injector, sanitizer, ngZone) {
  421. this.overlay = overlay;
  422. this._injector = _injector;
  423. this.sanitizer = sanitizer;
  424. this.ngZone = ngZone;
  425. this.currentlyActive = 0;
  426. this.toasts = [];
  427. this.index = 0;
  428. this.toastrConfig = Object.assign({}, token.default, token.config);
  429. if (token.config.iconClasses) {
  430. this.toastrConfig.iconClasses = Object.assign({}, token.default.iconClasses, token.config.iconClasses);
  431. }
  432. }
  433. /** show toast */
  434. show(message, title, override = {}, type = '') {
  435. return this._preBuildNotification(type, message, title, this.applyConfig(override));
  436. }
  437. /** show successful toast */
  438. success(message, title, override = {}) {
  439. const type = this.toastrConfig.iconClasses.success || '';
  440. return this._preBuildNotification(type, message, title, this.applyConfig(override));
  441. }
  442. /** show error toast */
  443. error(message, title, override = {}) {
  444. const type = this.toastrConfig.iconClasses.error || '';
  445. return this._preBuildNotification(type, message, title, this.applyConfig(override));
  446. }
  447. /** show info toast */
  448. info(message, title, override = {}) {
  449. const type = this.toastrConfig.iconClasses.info || '';
  450. return this._preBuildNotification(type, message, title, this.applyConfig(override));
  451. }
  452. /** show warning toast */
  453. warning(message, title, override = {}) {
  454. const type = this.toastrConfig.iconClasses.warning || '';
  455. return this._preBuildNotification(type, message, title, this.applyConfig(override));
  456. }
  457. /**
  458. * Remove all or a single toast by id
  459. */
  460. clear(toastId) {
  461. // Call every toastRef manualClose function
  462. for (const toast of this.toasts) {
  463. if (toastId !== undefined) {
  464. if (toast.toastId === toastId) {
  465. toast.toastRef.manualClose();
  466. return;
  467. }
  468. }
  469. else {
  470. toast.toastRef.manualClose();
  471. }
  472. }
  473. }
  474. /**
  475. * Remove and destroy a single toast by id
  476. */
  477. remove(toastId) {
  478. const found = this._findToast(toastId);
  479. if (!found) {
  480. return false;
  481. }
  482. found.activeToast.toastRef.close();
  483. this.toasts.splice(found.index, 1);
  484. this.currentlyActive = this.currentlyActive - 1;
  485. if (!this.toastrConfig.maxOpened || !this.toasts.length) {
  486. return false;
  487. }
  488. if (this.currentlyActive < this.toastrConfig.maxOpened &&
  489. this.toasts[this.currentlyActive]) {
  490. const p = this.toasts[this.currentlyActive].toastRef;
  491. if (!p.isInactive()) {
  492. this.currentlyActive = this.currentlyActive + 1;
  493. p.activate();
  494. }
  495. }
  496. return true;
  497. }
  498. /**
  499. * Determines if toast message is already shown
  500. */
  501. findDuplicate(message, resetOnDuplicate, countDuplicates) {
  502. for (let i = 0; i < this.toasts.length; i++) {
  503. const toast = this.toasts[i];
  504. if (toast.message === message) {
  505. toast.toastRef.onDuplicate(resetOnDuplicate, countDuplicates);
  506. return toast;
  507. }
  508. }
  509. return null;
  510. }
  511. /** create a clone of global config and apply individual settings */
  512. applyConfig(override = {}) {
  513. return Object.assign({}, this.toastrConfig, override);
  514. }
  515. /**
  516. * Find toast object by id
  517. */
  518. _findToast(toastId) {
  519. for (let i = 0; i < this.toasts.length; i++) {
  520. if (this.toasts[i].toastId === toastId) {
  521. return { index: i, activeToast: this.toasts[i] };
  522. }
  523. }
  524. return null;
  525. }
  526. /**
  527. * Determines the need to run inside angular's zone then builds the toast
  528. */
  529. _preBuildNotification(toastType, message, title, config) {
  530. if (config.onActivateTick) {
  531. return this.ngZone.run(() => this._buildNotification(toastType, message, title, config));
  532. }
  533. return this._buildNotification(toastType, message, title, config);
  534. }
  535. /**
  536. * Creates and attaches toast data to component
  537. * returns the active toast, or in case preventDuplicates is enabled the original/non-duplicate active toast.
  538. */
  539. _buildNotification(toastType, message, title, config) {
  540. if (!config.toastComponent) {
  541. throw new Error('toastComponent required');
  542. }
  543. // max opened and auto dismiss = true
  544. // if timeout = 0 resetting it would result in setting this.hideTime = Date.now(). Hence, we only want to reset timeout if there is
  545. // a timeout at all
  546. const duplicate = this.findDuplicate(message, this.toastrConfig.resetTimeoutOnDuplicate && config.timeOut > 0, this.toastrConfig.countDuplicates);
  547. if (message && this.toastrConfig.preventDuplicates && duplicate !== null) {
  548. return duplicate;
  549. }
  550. this.previousToastMessage = message;
  551. let keepInactive = false;
  552. if (this.toastrConfig.maxOpened &&
  553. this.currentlyActive >= this.toastrConfig.maxOpened) {
  554. keepInactive = true;
  555. if (this.toastrConfig.autoDismiss) {
  556. this.clear(this.toasts[0].toastId);
  557. }
  558. }
  559. const overlayRef = this.overlay.create(config.positionClass, this.overlayContainer);
  560. this.index = this.index + 1;
  561. let sanitizedMessage = message;
  562. if (message && config.enableHtml) {
  563. sanitizedMessage = this.sanitizer.sanitize(SecurityContext.HTML, message);
  564. }
  565. const toastRef = new ToastRef(overlayRef);
  566. const toastPackage = new ToastPackage(this.index, config, sanitizedMessage, title, toastType, toastRef);
  567. const toastInjector = new ToastInjector(toastPackage, this._injector);
  568. const component = new ComponentPortal(config.toastComponent, toastInjector);
  569. const portal = overlayRef.attach(component, this.toastrConfig.newestOnTop);
  570. toastRef.componentInstance = portal._component;
  571. const ins = {
  572. toastId: this.index,
  573. message: message || '',
  574. toastRef,
  575. onShown: toastRef.afterActivate(),
  576. onHidden: toastRef.afterClosed(),
  577. onTap: toastPackage.onTap(),
  578. onAction: toastPackage.onAction(),
  579. portal
  580. };
  581. if (!keepInactive) {
  582. setTimeout(() => {
  583. ins.toastRef.activate();
  584. this.currentlyActive = this.currentlyActive + 1;
  585. });
  586. }
  587. this.toasts.push(ins);
  588. return ins;
  589. }
  590. };
  591. ToastrService.ngInjectableDef = defineInjectable({ factory: function ToastrService_Factory() { return new ToastrService(inject(TOAST_CONFIG), inject(Overlay), inject(INJECTOR), inject(DomSanitizer), inject(NgZone)); }, token: ToastrService, providedIn: "root" });
  592. ToastrService = __decorate([
  593. Injectable({ providedIn: 'root' }),
  594. __param(0, Inject(TOAST_CONFIG)),
  595. __metadata("design:paramtypes", [Object, Overlay,
  596. Injector,
  597. DomSanitizer,
  598. NgZone])
  599. ], ToastrService);
  600. let Toast = class Toast {
  601. constructor(toastrService, toastPackage, ngZone) {
  602. this.toastrService = toastrService;
  603. this.toastPackage = toastPackage;
  604. this.ngZone = ngZone;
  605. /** width of progress bar */
  606. this.width = -1;
  607. /** a combination of toast type and options.toastClass */
  608. this.toastClasses = '';
  609. /** controls animation */
  610. this.state = {
  611. value: 'inactive',
  612. params: {
  613. easeTime: this.toastPackage.config.easeTime,
  614. easing: 'ease-in'
  615. }
  616. };
  617. this.message = toastPackage.message;
  618. this.title = toastPackage.title;
  619. this.options = toastPackage.config;
  620. this.originalTimeout = toastPackage.config.timeOut;
  621. this.toastClasses = `${toastPackage.toastType} ${toastPackage.config.toastClass}`;
  622. this.sub = toastPackage.toastRef.afterActivate().subscribe(() => {
  623. this.activateToast();
  624. });
  625. this.sub1 = toastPackage.toastRef.manualClosed().subscribe(() => {
  626. this.remove();
  627. });
  628. this.sub2 = toastPackage.toastRef.timeoutReset().subscribe(() => {
  629. this.resetTimeout();
  630. });
  631. this.sub3 = toastPackage.toastRef.countDuplicate().subscribe(count => {
  632. this.duplicatesCount = count;
  633. });
  634. }
  635. /** hides component when waiting to be displayed */
  636. get displayStyle() {
  637. if (this.state.value === 'inactive') {
  638. return 'none';
  639. }
  640. }
  641. ngOnDestroy() {
  642. this.sub.unsubscribe();
  643. this.sub1.unsubscribe();
  644. this.sub2.unsubscribe();
  645. this.sub3.unsubscribe();
  646. clearInterval(this.intervalId);
  647. clearTimeout(this.timeout);
  648. }
  649. /**
  650. * activates toast and sets timeout
  651. */
  652. activateToast() {
  653. this.state = Object.assign({}, this.state, { value: 'active' });
  654. if (!this.options.disableTimeOut && this.options.timeOut) {
  655. this.outsideTimeout(() => this.remove(), this.options.timeOut);
  656. this.hideTime = new Date().getTime() + this.options.timeOut;
  657. if (this.options.progressBar) {
  658. this.outsideInterval(() => this.updateProgress(), 10);
  659. }
  660. }
  661. }
  662. /**
  663. * updates progress bar width
  664. */
  665. updateProgress() {
  666. if (this.width === 0 || this.width === 100 || !this.options.timeOut) {
  667. return;
  668. }
  669. const now = new Date().getTime();
  670. const remaining = this.hideTime - now;
  671. this.width = (remaining / this.options.timeOut) * 100;
  672. if (this.options.progressAnimation === 'increasing') {
  673. this.width = 100 - this.width;
  674. }
  675. if (this.width <= 0) {
  676. this.width = 0;
  677. }
  678. if (this.width >= 100) {
  679. this.width = 100;
  680. }
  681. }
  682. resetTimeout() {
  683. clearTimeout(this.timeout);
  684. clearInterval(this.intervalId);
  685. this.state = Object.assign({}, this.state, { value: 'active' });
  686. this.outsideTimeout(() => this.remove(), this.originalTimeout);
  687. this.options.timeOut = this.originalTimeout;
  688. this.hideTime = new Date().getTime() + (this.options.timeOut || 0);
  689. this.width = -1;
  690. if (this.options.progressBar) {
  691. this.outsideInterval(() => this.updateProgress(), 10);
  692. }
  693. }
  694. /**
  695. * tells toastrService to remove this toast after animation time
  696. */
  697. remove() {
  698. if (this.state.value === 'removed') {
  699. return;
  700. }
  701. clearTimeout(this.timeout);
  702. this.state = Object.assign({}, this.state, { value: 'removed' });
  703. this.outsideTimeout(() => this.toastrService.remove(this.toastPackage.toastId), +this.toastPackage.config.easeTime);
  704. }
  705. tapToast() {
  706. if (this.state.value === 'removed') {
  707. return;
  708. }
  709. this.toastPackage.triggerTap();
  710. if (this.options.tapToDismiss) {
  711. this.remove();
  712. }
  713. }
  714. stickAround() {
  715. if (this.state.value === 'removed') {
  716. return;
  717. }
  718. clearTimeout(this.timeout);
  719. this.options.timeOut = 0;
  720. this.hideTime = 0;
  721. // disable progressBar
  722. clearInterval(this.intervalId);
  723. this.width = 0;
  724. }
  725. delayedHideToast() {
  726. if (this.options.disableTimeOut ||
  727. this.options.extendedTimeOut === 0 ||
  728. this.state.value === 'removed') {
  729. return;
  730. }
  731. this.outsideTimeout(() => this.remove(), this.options.extendedTimeOut);
  732. this.options.timeOut = this.options.extendedTimeOut;
  733. this.hideTime = new Date().getTime() + (this.options.timeOut || 0);
  734. this.width = -1;
  735. if (this.options.progressBar) {
  736. this.outsideInterval(() => this.updateProgress(), 10);
  737. }
  738. }
  739. outsideTimeout(func, timeout) {
  740. if (this.ngZone) {
  741. this.ngZone.runOutsideAngular(() => (this.timeout = setTimeout(() => this.runInsideAngular(func), timeout)));
  742. }
  743. else {
  744. this.timeout = setTimeout(() => func(), timeout);
  745. }
  746. }
  747. outsideInterval(func, timeout) {
  748. if (this.ngZone) {
  749. this.ngZone.runOutsideAngular(() => (this.intervalId = setInterval(() => this.runInsideAngular(func), timeout)));
  750. }
  751. else {
  752. this.intervalId = setInterval(() => func(), timeout);
  753. }
  754. }
  755. runInsideAngular(func) {
  756. if (this.ngZone) {
  757. this.ngZone.run(() => func());
  758. }
  759. else {
  760. func();
  761. }
  762. }
  763. };
  764. __decorate([
  765. HostBinding('class'),
  766. __metadata("design:type", Object)
  767. ], Toast.prototype, "toastClasses", void 0);
  768. __decorate([
  769. HostBinding('@flyInOut'),
  770. __metadata("design:type", Object)
  771. ], Toast.prototype, "state", void 0);
  772. __decorate([
  773. HostBinding('style.display'),
  774. __metadata("design:type", Object),
  775. __metadata("design:paramtypes", [])
  776. ], Toast.prototype, "displayStyle", null);
  777. __decorate([
  778. HostListener('click'),
  779. __metadata("design:type", Function),
  780. __metadata("design:paramtypes", []),
  781. __metadata("design:returntype", void 0)
  782. ], Toast.prototype, "tapToast", null);
  783. __decorate([
  784. HostListener('mouseenter'),
  785. __metadata("design:type", Function),
  786. __metadata("design:paramtypes", []),
  787. __metadata("design:returntype", void 0)
  788. ], Toast.prototype, "stickAround", null);
  789. __decorate([
  790. HostListener('mouseleave'),
  791. __metadata("design:type", Function),
  792. __metadata("design:paramtypes", []),
  793. __metadata("design:returntype", void 0)
  794. ], Toast.prototype, "delayedHideToast", null);
  795. Toast = __decorate([
  796. Component({
  797. selector: '[toast-component]',
  798. template: `
  799. <button *ngIf="options.closeButton" (click)="remove()" class="toast-close-button" aria-label="Close">
  800. <span aria-hidden="true">&times;</span>
  801. </button>
  802. <div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
  803. {{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
  804. </div>
  805. <div *ngIf="message && options.enableHtml" role="alertdialog" aria-live="polite"
  806. [class]="options.messageClass" [innerHTML]="message">
  807. </div>
  808. <div *ngIf="message && !options.enableHtml" role="alertdialog" aria-live="polite"
  809. [class]="options.messageClass" [attr.aria-label]="message">
  810. {{ message }}
  811. </div>
  812. <div *ngIf="options.progressBar">
  813. <div class="toast-progress" [style.width]="width + '%'"></div>
  814. </div>
  815. `,
  816. animations: [
  817. trigger('flyInOut', [
  818. state('inactive', style({ opacity: 0 })),
  819. state('active', style({ opacity: 1 })),
  820. state('removed', style({ opacity: 0 })),
  821. transition('inactive => active', animate('{{ easeTime }}ms {{ easing }}')),
  822. transition('active => removed', animate('{{ easeTime }}ms {{ easing }}'))
  823. ])
  824. ],
  825. preserveWhitespaces: false
  826. }),
  827. __metadata("design:paramtypes", [ToastrService,
  828. ToastPackage,
  829. NgZone])
  830. ], Toast);
  831. var ToastrModule_1;
  832. const DefaultGlobalConfig = Object.assign({}, DefaultNoComponentGlobalConfig, { toastComponent: Toast });
  833. let ToastrModule = ToastrModule_1 = class ToastrModule {
  834. static forRoot(config = {}) {
  835. return {
  836. ngModule: ToastrModule_1,
  837. providers: [
  838. {
  839. provide: TOAST_CONFIG,
  840. useValue: {
  841. default: DefaultGlobalConfig,
  842. config,
  843. },
  844. },
  845. ],
  846. };
  847. }
  848. };
  849. ToastrModule = ToastrModule_1 = __decorate([
  850. NgModule({
  851. imports: [CommonModule],
  852. declarations: [Toast],
  853. exports: [Toast],
  854. entryComponents: [Toast],
  855. })
  856. ], ToastrModule);
  857. let ToastrComponentlessModule = class ToastrComponentlessModule {
  858. static forRoot(config = {}) {
  859. return {
  860. ngModule: ToastrModule,
  861. providers: [
  862. {
  863. provide: TOAST_CONFIG,
  864. useValue: {
  865. default: DefaultNoComponentGlobalConfig,
  866. config,
  867. },
  868. },
  869. ],
  870. };
  871. }
  872. };
  873. ToastrComponentlessModule = __decorate([
  874. NgModule({
  875. imports: [CommonModule],
  876. })
  877. ], ToastrComponentlessModule);
  878. var ToastNoAnimationModule_1;
  879. let ToastNoAnimation = class ToastNoAnimation {
  880. constructor(toastrService, toastPackage, appRef) {
  881. this.toastrService = toastrService;
  882. this.toastPackage = toastPackage;
  883. this.appRef = appRef;
  884. /** width of progress bar */
  885. this.width = -1;
  886. /** a combination of toast type and options.toastClass */
  887. this.toastClasses = '';
  888. /** controls animation */
  889. this.state = 'inactive';
  890. this.message = toastPackage.message;
  891. this.title = toastPackage.title;
  892. this.options = toastPackage.config;
  893. this.originalTimeout = toastPackage.config.timeOut;
  894. this.toastClasses = `${toastPackage.toastType} ${toastPackage.config.toastClass}`;
  895. this.sub = toastPackage.toastRef.afterActivate().subscribe(() => {
  896. this.activateToast();
  897. });
  898. this.sub1 = toastPackage.toastRef.manualClosed().subscribe(() => {
  899. this.remove();
  900. });
  901. this.sub2 = toastPackage.toastRef.timeoutReset().subscribe(() => {
  902. this.resetTimeout();
  903. });
  904. this.sub3 = toastPackage.toastRef.countDuplicate().subscribe(count => {
  905. this.duplicatesCount = count;
  906. });
  907. }
  908. /** hides component when waiting to be displayed */
  909. get displayStyle() {
  910. if (this.state === 'inactive') {
  911. return 'none';
  912. }
  913. }
  914. ngOnDestroy() {
  915. this.sub.unsubscribe();
  916. this.sub1.unsubscribe();
  917. this.sub2.unsubscribe();
  918. this.sub3.unsubscribe();
  919. clearInterval(this.intervalId);
  920. clearTimeout(this.timeout);
  921. }
  922. /**
  923. * activates toast and sets timeout
  924. */
  925. activateToast() {
  926. this.state = 'active';
  927. if (!this.options.disableTimeOut && this.options.timeOut) {
  928. this.timeout = setTimeout(() => {
  929. this.remove();
  930. }, this.options.timeOut);
  931. this.hideTime = new Date().getTime() + this.options.timeOut;
  932. if (this.options.progressBar) {
  933. this.intervalId = setInterval(() => this.updateProgress(), 10);
  934. }
  935. }
  936. if (this.options.onActivateTick) {
  937. this.appRef.tick();
  938. }
  939. }
  940. /**
  941. * updates progress bar width
  942. */
  943. updateProgress() {
  944. if (this.width === 0 || this.width === 100 || !this.options.timeOut) {
  945. return;
  946. }
  947. const now = new Date().getTime();
  948. const remaining = this.hideTime - now;
  949. this.width = (remaining / this.options.timeOut) * 100;
  950. if (this.options.progressAnimation === 'increasing') {
  951. this.width = 100 - this.width;
  952. }
  953. if (this.width <= 0) {
  954. this.width = 0;
  955. }
  956. if (this.width >= 100) {
  957. this.width = 100;
  958. }
  959. }
  960. resetTimeout() {
  961. clearTimeout(this.timeout);
  962. clearInterval(this.intervalId);
  963. this.state = 'active';
  964. this.options.timeOut = this.originalTimeout;
  965. this.timeout = setTimeout(() => this.remove(), this.originalTimeout);
  966. this.hideTime = new Date().getTime() + (this.originalTimeout || 0);
  967. this.width = -1;
  968. if (this.options.progressBar) {
  969. this.intervalId = setInterval(() => this.updateProgress(), 10);
  970. }
  971. }
  972. /**
  973. * tells toastrService to remove this toast after animation time
  974. */
  975. remove() {
  976. if (this.state === 'removed') {
  977. return;
  978. }
  979. clearTimeout(this.timeout);
  980. this.state = 'removed';
  981. this.timeout = setTimeout(() => this.toastrService.remove(this.toastPackage.toastId));
  982. }
  983. tapToast() {
  984. if (this.state === 'removed') {
  985. return;
  986. }
  987. this.toastPackage.triggerTap();
  988. if (this.options.tapToDismiss) {
  989. this.remove();
  990. }
  991. }
  992. stickAround() {
  993. if (this.state === 'removed') {
  994. return;
  995. }
  996. clearTimeout(this.timeout);
  997. this.options.timeOut = 0;
  998. this.hideTime = 0;
  999. // disable progressBar
  1000. clearInterval(this.intervalId);
  1001. this.width = 0;
  1002. }
  1003. delayedHideToast() {
  1004. if (this.options.disableTimeOut ||
  1005. this.options.extendedTimeOut === 0 ||
  1006. this.state === 'removed') {
  1007. return;
  1008. }
  1009. this.timeout = setTimeout(() => this.remove(), this.options.extendedTimeOut);
  1010. this.options.timeOut = this.options.extendedTimeOut;
  1011. this.hideTime = new Date().getTime() + (this.options.timeOut || 0);
  1012. this.width = -1;
  1013. if (this.options.progressBar) {
  1014. this.intervalId = setInterval(() => this.updateProgress(), 10);
  1015. }
  1016. }
  1017. };
  1018. __decorate([
  1019. HostBinding('class'),
  1020. __metadata("design:type", Object)
  1021. ], ToastNoAnimation.prototype, "toastClasses", void 0);
  1022. __decorate([
  1023. HostBinding('style.display'),
  1024. __metadata("design:type", Object),
  1025. __metadata("design:paramtypes", [])
  1026. ], ToastNoAnimation.prototype, "displayStyle", null);
  1027. __decorate([
  1028. HostListener('click'),
  1029. __metadata("design:type", Function),
  1030. __metadata("design:paramtypes", []),
  1031. __metadata("design:returntype", void 0)
  1032. ], ToastNoAnimation.prototype, "tapToast", null);
  1033. __decorate([
  1034. HostListener('mouseenter'),
  1035. __metadata("design:type", Function),
  1036. __metadata("design:paramtypes", []),
  1037. __metadata("design:returntype", void 0)
  1038. ], ToastNoAnimation.prototype, "stickAround", null);
  1039. __decorate([
  1040. HostListener('mouseleave'),
  1041. __metadata("design:type", Function),
  1042. __metadata("design:paramtypes", []),
  1043. __metadata("design:returntype", void 0)
  1044. ], ToastNoAnimation.prototype, "delayedHideToast", null);
  1045. ToastNoAnimation = __decorate([
  1046. Component({
  1047. selector: '[toast-component]',
  1048. template: `
  1049. <button *ngIf="options.closeButton" (click)="remove()" class="toast-close-button" aria-label="Close">
  1050. <span aria-hidden="true">&times;</span>
  1051. </button>
  1052. <div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
  1053. {{ title }} <ng-container *ngIf="duplicatesCount">[{{ duplicatesCount + 1 }}]</ng-container>
  1054. </div>
  1055. <div *ngIf="message && options.enableHtml" role="alert" aria-live="polite"
  1056. [class]="options.messageClass" [innerHTML]="message">
  1057. </div>
  1058. <div *ngIf="message && !options.enableHtml" role="alert" aria-live="polite"
  1059. [class]="options.messageClass" [attr.aria-label]="message">
  1060. {{ message }}
  1061. </div>
  1062. <div *ngIf="options.progressBar">
  1063. <div class="toast-progress" [style.width]="width + '%'"></div>
  1064. </div>
  1065. `
  1066. }),
  1067. __metadata("design:paramtypes", [ToastrService,
  1068. ToastPackage,
  1069. ApplicationRef])
  1070. ], ToastNoAnimation);
  1071. const DefaultNoAnimationsGlobalConfig = Object.assign({}, DefaultNoComponentGlobalConfig, { toastComponent: ToastNoAnimation });
  1072. let ToastNoAnimationModule = ToastNoAnimationModule_1 = class ToastNoAnimationModule {
  1073. static forRoot(config = {}) {
  1074. return {
  1075. ngModule: ToastNoAnimationModule_1,
  1076. providers: [
  1077. {
  1078. provide: TOAST_CONFIG,
  1079. useValue: {
  1080. default: DefaultNoAnimationsGlobalConfig,
  1081. config,
  1082. },
  1083. },
  1084. ],
  1085. };
  1086. }
  1087. };
  1088. ToastNoAnimationModule = ToastNoAnimationModule_1 = __decorate([
  1089. NgModule({
  1090. imports: [CommonModule],
  1091. declarations: [ToastNoAnimation],
  1092. exports: [ToastNoAnimation],
  1093. entryComponents: [ToastNoAnimation],
  1094. })
  1095. ], ToastNoAnimationModule);
  1096. /**
  1097. * Generated bundle index. Do not edit.
  1098. */
  1099. export { BasePortalHost, ComponentPortal, DefaultGlobalConfig, DefaultNoAnimationsGlobalConfig, DefaultNoComponentGlobalConfig, Overlay, OverlayContainer, OverlayRef, TOAST_CONFIG, Toast, ToastContainerDirective, ToastContainerModule, ToastInjector, ToastNoAnimation, ToastNoAnimationModule, ToastPackage, ToastRef, ToastrComponentlessModule, ToastrModule, ToastrService };
  1100. //# sourceMappingURL=ngx-toastr.js.map