From 56cac512f7ccd873d82d2014113f348db8f6d1f9 Mon Sep 17 00:00:00 2001 From: Evgeny Lupanov Date: Wed, 26 Jun 2019 14:56:46 +0300 Subject: [PATCH] feat(toastr): add toasts limit (#1637) --- src/app/playground-components.ts | 6 +++ .../theme/components/toastr/toastr-config.ts | 4 ++ .../components/toastr/toastr.service.spec.ts | 46 ++++++++++++++++++- .../theme/components/toastr/toastr.service.ts | 20 +++++++- .../toastr/toastr-limit.component.ts | 31 +++++++++++++ .../toastr/toastr-routing.module.ts | 5 ++ .../with-layout/toastr/toastr.module.ts | 2 + 7 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 src/playground/with-layout/toastr/toastr-limit.component.ts diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts index a2037b1ab5..010fb54f18 100644 --- a/src/app/playground-components.ts +++ b/src/app/playground-components.ts @@ -1132,6 +1132,12 @@ export const PLAYGROUND_COMPONENTS: ComponentLink[] = [ component: 'ToastrStatusesComponent', name: 'Toastr Statuses', }, + { + path: 'toastr-limit.component', + link: '/toastr/toastr-limit.component', + component: 'ToastrLimitComponent', + name: 'Toastr Limit', + }, ], }, { diff --git a/src/framework/theme/components/toastr/toastr-config.ts b/src/framework/theme/components/toastr/toastr-config.ts index 0492e1667b..295c39a8ff 100644 --- a/src/framework/theme/components/toastr/toastr-config.ts +++ b/src/framework/theme/components/toastr/toastr-config.ts @@ -47,6 +47,10 @@ export class NbToastrConfig { * Determines the how to threat duplicates. * */ duplicatesBehaviour: NbDuplicateToastBehaviour = 'previous'; + /* + * The number of visible toasts. If the limit exceeded the oldest toast will be removed. + * */ + limit?: number = null; /** * Determines render icon or not. * */ diff --git a/src/framework/theme/components/toastr/toastr.service.spec.ts b/src/framework/theme/components/toastr/toastr.service.spec.ts index f21f1e98c2..3bd5d14adb 100644 --- a/src/framework/theme/components/toastr/toastr.service.spec.ts +++ b/src/framework/theme/components/toastr/toastr.service.spec.ts @@ -256,7 +256,7 @@ describe('toastr-container', () => { config: { status: 'dander', preventDuplicates: true, duplicatesBehaviour: 'previous' }, }; - const toast2 = Object.assign({title: 'toast2'}, toast1); + const toast2 = Object.assign({}, toast1, {title: 'toast2'}); toastrContainer.attach( toast1); toastrContainer.attach( toast2); @@ -272,7 +272,7 @@ describe('toastr-container', () => { config: { status: 'dander', preventDuplicates: true, duplicatesBehaviour: 'all' }, }; - const toast2 = Object.assign({title: 'toast2'}, toast1); + const toast2 = Object.assign({}, toast1, {title: 'toast2'}); toastrContainer.attach( toast1); toastrContainer.attach( toast2); @@ -280,4 +280,46 @@ describe('toastr-container', () => { expect(duplicateToast).toBeUndefined(); }); + + describe('if limit set', () => { + + const toast1 = { + title: 'toast1', + config: { limit: 3 }, + }; + + const toast2 = Object.assign({}, toast1, {title: 'toast2'}); + const toast3 = Object.assign({}, toast1, {title: 'toast3'}); + const toast4 = Object.assign({}, toast1, {title: 'toast4'}); + + function attachToasts() { + toastrContainer.attach( toast1); + toastrContainer.attach( toast2); + toastrContainer.attach( toast3); + toastrContainer.attach( toast4); + } + + it('should remove the first toast in container in top position', () => { + attachToasts(); + expect(containerRefStub.instance.content.length).toEqual(3); + expect(containerRefStub.instance.content[0]).toEqual(toast4); + expect(containerRefStub.instance.content[1]).toEqual(toast3); + expect(containerRefStub.instance.content[2]).toEqual(toast2); + }); + it('should remove the last toast in container in bottom position', () => { + positionHelperStub = { + isTopPosition() { + return false; + }, + }; + + toastrContainer = new NbToastContainer( {}, containerRefStub, positionHelperStub); + + attachToasts(); + expect(containerRefStub.instance.content.length).toEqual(3); + expect(containerRefStub.instance.content[0]).toEqual(toast2); + expect(containerRefStub.instance.content[1]).toEqual(toast3); + expect(containerRefStub.instance.content[2]).toEqual(toast4); + }); + }); }); diff --git a/src/framework/theme/components/toastr/toastr.service.ts b/src/framework/theme/components/toastr/toastr.service.ts index 7be25d0774..4b9602ddc2 100644 --- a/src/framework/theme/components/toastr/toastr.service.ts +++ b/src/framework/theme/components/toastr/toastr.service.ts @@ -44,6 +44,7 @@ export class NbToastContainer { return; } + this.removeToastIfLimitReached(toast); const toastComponent: NbToastComponent = this.attachToast(toast); if (toast.config.destroyByClick) { @@ -88,6 +89,17 @@ export class NbToastContainer { && t1.config.status === t2.config.status; }; + protected removeToastIfLimitReached(toast: NbToast) { + if (!toast.config.limit || this.toasts.length < toast.config.limit) { + return; + } + if (this.positionHelper.isTopPosition(toast.config.position)) { + this.toasts.pop(); + } else { + this.toasts.shift(); + } + } + protected attachToast(toast: NbToast): NbToastComponent { if (this.positionHelper.isTopPosition(toast.config.position)) { return this.attachToTop(toast); @@ -220,11 +232,15 @@ export class NbToastrContainerRegistry { * @stacked-example(Prevent duplicates, toastr/toastr-prevent-duplicates.component) * * `duplicatesBehaviour` - determines how to threat the toasts duplication. - * Compare with the previous message (`NbDuplicateToastBehaviour.PREVIOUS`) - * or with all visible messages (`NbDuplicateToastBehaviour.ALL`). + * Compare with the previous message `previous` + * or with all visible messages `all`. * * @stacked-example(Prevent duplicates behaviour , toastr/toastr-prevent-duplicates-behaviour.component) * + * `limit` - the number of visible toasts in the toast container. The number of toasts is unlimited by default. + * + * @stacked-example(Prevent duplicates behaviour , toastr/toastr-limit.component) + * * `hasIcon` - if true then render toast icon. * `icon` - you can pass icon class that will be applied into the toast. * diff --git a/src/playground/with-layout/toastr/toastr-limit.component.ts b/src/playground/with-layout/toastr/toastr-limit.component.ts new file mode 100644 index 0000000000..8904660882 --- /dev/null +++ b/src/playground/with-layout/toastr/toastr-limit.component.ts @@ -0,0 +1,31 @@ +import { NbGlobalLogicalPosition, NbToastrService } from '@nebular/theme'; +import { Component } from '@angular/core'; + +@Component({ + selector: 'nb-toastr-limit', + template: ` + + `, + styles: [ + ` + ::ng-deep nb-layout-column { + height: 80vw; + } + `, + ], +}) +export class ToastrLimitComponent { + + constructor(private toastrService: NbToastrService) { + } + + i: number = 1; + + showToast() { + this.toastrService.show( + `Toast number ${this.i}`, + `Toast with the limit`, + { limit: 3, position: NbGlobalLogicalPosition.TOP_END }); + this.i++; + } +} diff --git a/src/playground/with-layout/toastr/toastr-routing.module.ts b/src/playground/with-layout/toastr/toastr-routing.module.ts index 54f1d3dbf0..4f4211021a 100644 --- a/src/playground/with-layout/toastr/toastr-routing.module.ts +++ b/src/playground/with-layout/toastr/toastr-routing.module.ts @@ -14,6 +14,7 @@ import { ToastrPreventDuplicatesComponent } from './toastr-prevent-duplicates.co import { ToastrShowcaseComponent } from './toastr-showcase.component'; import { ToastrStatusesComponent } from './toastr-statuses.component'; import { ToastrPreventDuplicatesBehaviourComponent } from './toastr-prevent-duplicates-behaviour.component'; +import { ToastrLimitComponent } from './toastr-limit.component'; const routes: Route[] = [ { @@ -48,6 +49,10 @@ const routes: Route[] = [ path: 'toastr-statuses.component', component: ToastrStatusesComponent, }, + { + path: 'toastr-limit.component', + component: ToastrLimitComponent, + }, ]; @NgModule({ diff --git a/src/playground/with-layout/toastr/toastr.module.ts b/src/playground/with-layout/toastr/toastr.module.ts index 7568df69bd..748f562c3d 100644 --- a/src/playground/with-layout/toastr/toastr.module.ts +++ b/src/playground/with-layout/toastr/toastr.module.ts @@ -14,6 +14,7 @@ import { ToastrPositionsComponent } from './toastr-positions.component'; import { ToastrPreventDuplicatesComponent } from './toastr-prevent-duplicates.component'; import { ToastrShowcaseComponent } from './toastr-showcase.component'; import { ToastrStatusesComponent } from './toastr-statuses.component'; +import { ToastrLimitComponent } from './toastr-limit.component'; import { ToastrPreventDuplicatesBehaviourComponent } from './toastr-prevent-duplicates-behaviour.component'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; @@ -28,6 +29,7 @@ import { FormsModule } from '@angular/forms'; ToastrPreventDuplicatesBehaviourComponent, ToastrShowcaseComponent, ToastrStatusesComponent, + ToastrLimitComponent, ], imports: [ CommonModule,