diff --git a/platform/commonUI/notification/src/NotificationService.js b/platform/commonUI/notification/src/NotificationService.js index 8f5b71ec42..39104faca3 100644 --- a/platform/commonUI/notification/src/NotificationService.js +++ b/platform/commonUI/notification/src/NotificationService.js @@ -208,11 +208,11 @@ define( * @private */ NotificationService.prototype.dismissOrMinimize = function (notification) { - - //For now minimize everything, and have discussion around which - //kind of messages should or should not be in the minimized - //notifications list - notification.minimize(); + if (notification.minimizeInsteadOfDismiss) { + notification.minimize(); + } else { + notification.dismiss(); + } }; /** @@ -226,7 +226,9 @@ define( /** * A convenience method for info notifications. Notifications * created via this method will be auto-dismissed after a default - * wait period + * wait period unless explicitly forbidden by the caller through + * the {autoDismiss} property on the {NotificationModel}, in which + * case the notification will be minimized after the wait. * @param {NotificationModel | string} message either a string for * the title of the notification message, or a {@link NotificationModel} * defining the options notification to display @@ -235,7 +237,6 @@ define( */ NotificationService.prototype.info = function (message) { var notificationModel = typeof message === "string" ? {title: message} : message; - notificationModel.autoDismiss = notificationModel.autoDismiss || true; notificationModel.severity = "info"; return this.notify(notificationModel); }; @@ -306,27 +307,52 @@ define( activeNotification = self.active.notification, topic = this.topic(); + notificationModel.severity = notificationModel.severity || "info"; + notification = { model: notificationModel, + minimize: function () { self.minimize(self, notification); }, + dismiss: function () { self.dismiss(self, notification); topic.notify(); }, + dismissOrMinimize: function () { self.dismissOrMinimize(notification); }, + onDismiss: function (callback) { topic.listen(callback); - } - }; + }, - notificationModel.severity = notificationModel.severity || "info"; - if (notificationModel.autoDismiss === true) { - notificationModel.autoDismiss = this.AUTO_DISMISS_TIMEOUT; - } + autoDismiss: (function () { + if (notificationModel.severity === "info") { + return true; + } + return notificationModel.autoDismiss; + })(), + + autoDismissTimeout: (function () { + if (typeof notificationModel.autoDismiss === "number") { + return notificationModel.autoDismiss; + } + return self.AUTO_DISMISS_TIMEOUT; + })(), + + minimizeInsteadOfDismiss: (function () { + if (notificationModel.severity === "info") { + if (notificationModel.autoDismiss === false) { + return true; + } + return false; + } + return true; + })() + }; //Notifications support a 'dismissable' attribute. This is a // convenience to support adding a 'dismiss' option to the @@ -370,27 +396,23 @@ define( } return notification; - }; /** * Used internally by the NotificationService * @private */ - NotificationService.prototype.setActiveNotification = - function (notification) { + NotificationService.prototype.setActiveNotification = function (notification) { var timeout; - this.active.notification = notification; + /* If autoDismiss has been specified, OR there are other notifications queued for display, setup a timeout to dismiss the dialog. */ - if (notification && (notification.model.autoDismiss || - this.selectNextNotification())) { - - timeout = notification.model.autoDismiss || this.AUTO_DISMISS_TIMEOUT; + if (notification && (notification.autoDismiss || this.selectNextNotification())) { + timeout = notification.autoDismissTimeout || this.AUTO_DISMISS_TIMEOUT; this.active.timeout = this.$timeout(function () { notification.dismissOrMinimize(); }, timeout); diff --git a/platform/commonUI/notification/test/NotificationServiceSpec.js b/platform/commonUI/notification/test/NotificationServiceSpec.js index 715894a077..2c90dce621 100644 --- a/platform/commonUI/notification/test/NotificationServiceSpec.js +++ b/platform/commonUI/notification/test/NotificationServiceSpec.js @@ -33,8 +33,13 @@ define( mockTopicFunction, mockTopicObject, infoModel, + alertModel, errorModel; + function elapseTimeout() { + mockTimeout.mostRecentCall.args[0](); + } + beforeEach(function () { mockTimeout = jasmine.createSpy("$timeout"); mockTopicFunction = jasmine.createSpy("topic"); @@ -42,124 +47,180 @@ define( mockTopicFunction.andReturn(mockTopicObject); mockAutoDismiss = mockMinimizeTimeout = 1000; - notificationService = new NotificationService( - mockTimeout, mockTopicFunction, mockAutoDismiss, mockMinimizeTimeout); + notificationService = new NotificationService(mockTimeout, mockTopicFunction, mockAutoDismiss, mockMinimizeTimeout); infoModel = { title: "Mock Info Notification", severity: "info" }; + alertModel = { + title: "Mock Alert Notification", + severity: "alert" + }; + errorModel = { title: "Mock Error Notification", severity: "error" }; }); - it("activates info notifications", function () { - var activeNotification; - notificationService.notify(infoModel); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model).toBe(infoModel); - }); - it("notifies listeners on dismissal of notification", function () { - var notification, - dismissListener = jasmine.createSpy("ondismiss"); - notification = notificationService.notify(infoModel); + var dismissListener = jasmine.createSpy("ondismiss"); + var notification = notificationService.notify(infoModel); notification.onDismiss(dismissListener); expect(mockTopicObject.listen).toHaveBeenCalled(); notification.dismiss(); expect(mockTopicObject.notify).toHaveBeenCalled(); mockTopicObject.listen.mostRecentCall.args[0](); expect(dismissListener).toHaveBeenCalled(); - }); - it("activates an info notification built with just the title", function () { - var activeNotification, - notificationTitle = "Test info notification"; - notificationService.info(notificationTitle); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model.title).toBe(notificationTitle); - expect(activeNotification.model.severity).toBe("info"); + describe("when receiving info notifications", function () { + it("minimizes info notifications if the caller disables auto-dismiss", function () { + infoModel.autoDismiss = false; + var notification = notificationService.info(infoModel); + elapseTimeout(); + // 2nd elapse for the minimize animation timeout + elapseTimeout(); + expect(notificationService.getActiveNotification()).toBeUndefined(); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); + + it("dismisses info notifications if the caller ignores auto-dismiss", function () { + notificationService.info(infoModel); + elapseTimeout(); + expect(notificationService.getActiveNotification()).toBeUndefined(); + expect(notificationService.notifications.length).toEqual(0); + }); + + it("dismisses info notifications if the caller requests auto-dismissal", function () { + infoModel.autoDismiss = true; + notificationService.info(infoModel); + elapseTimeout(); + expect(notificationService.getActiveNotification()).toBeUndefined(); + expect(notificationService.notifications.length).toEqual(0); + }); + + it("uses a custom auto-dismiss timeout value if provided", function () { + var timeoutValueInModel = 1500; + var timeoutValueUsedByService = 0; + mockTimeout.andCallFake(function (callback, timeout) { + timeoutValueUsedByService = timeout; + }); + infoModel.autoDismiss = timeoutValueInModel; + notificationService.info(infoModel); + expect(timeoutValueUsedByService).toEqual(timeoutValueInModel); + }); }); - it("gets a new info notification with numerical auto-dismiss specified. ", function () { - var activeNotification; - infoModel.autoDismiss = 1000; - notificationService.notify(infoModel); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model).toBe(infoModel); - mockTimeout.mostRecentCall.args[0](); - expect(mockTimeout.calls.length).toBe(2); - mockTimeout.mostRecentCall.args[0](); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification).toBeUndefined(); + describe("when receiving alert notifications", function () { + it("minimizes alert notifications if the caller enables auto-dismiss", function () { + alertModel.autoDismiss = true; + var notification = notificationService.alert(alertModel); + elapseTimeout(); + elapseTimeout(); + expect(notificationService.getActiveNotification()).toBeUndefined(); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); + + it("keeps alert notifications active if the caller disables auto-dismiss", function () { + mockTimeout.andCallFake(function (callback, time) { + callback(); + }); + alertModel.autoDismiss = false; + var notification = notificationService.alert(alertModel); + expect(notificationService.getActiveNotification()).toEqual(notification); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); + + it("keeps alert notifications active if the caller ignores auto-dismiss", function () { + mockTimeout.andCallFake(function (callback, time) { + callback(); + }); + var notification = notificationService.alert(alertModel); + expect(notificationService.getActiveNotification()).toEqual(notification); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); + + it("uses a custom auto-dismiss timeout value if provided", function () { + var timeoutValueInModel = 1500; + var timeoutValueUsedByService = 0; + mockTimeout.andCallFake(function (callback, timeout) { + timeoutValueUsedByService = timeout; + }); + alertModel.autoDismiss = timeoutValueInModel; + notificationService.alert(alertModel); + expect(timeoutValueUsedByService).toEqual(timeoutValueInModel); + }); }); - it("gets a new notification with boolean auto-dismiss specified. ", function () { - var activeNotification; - infoModel.autoDismiss = true; - notificationService.notify(infoModel); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model).toBe(infoModel); - mockTimeout.mostRecentCall.args[0](); - expect(mockTimeout.calls.length).toBe(2); - mockTimeout.mostRecentCall.args[0](); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification).toBeUndefined(); - }); + describe("when receiving error notifications", function () { + it("minimizes error notifications if the caller enables auto-dismiss", function () { + errorModel.autoDismiss = true; + var notification = notificationService.error(errorModel); + elapseTimeout(); + elapseTimeout(); + expect(notificationService.getActiveNotification()).toBeUndefined(); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); - it("allows minimization of notifications", function () { - var notification, - activeNotification; + it("keeps error notifications active if the caller disables auto-dismiss", function () { + mockTimeout.andCallFake(function (callback, time) { + callback(); + }); + errorModel.autoDismiss = false; + var notification = notificationService.error(errorModel); + expect(notificationService.getActiveNotification()).toEqual(notification); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); - infoModel.autoDismiss = false; - notification = notificationService.notify(infoModel); + it("keeps error notifications active if the caller ignores auto-dismiss", function () { + mockTimeout.andCallFake(function (callback, time) { + callback(); + }); + var notification = notificationService.error(errorModel); + expect(notificationService.getActiveNotification()).toEqual(notification); + expect(notificationService.notifications.length).toEqual(1); + expect(notificationService.notifications[0]).toEqual(notification); + }); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model).toBe(infoModel); - notification.minimize(); - mockTimeout.mostRecentCall.args[0](); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification).toBeUndefined(); - expect(notificationService.notifications.length).toBe(1); - }); - - it("allows dismissal of notifications", function () { - var notification, - activeNotification; - - infoModel.autoDismiss = false; - notification = notificationService.notify(infoModel); - - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification.model).toBe(infoModel); - notification.dismiss(); - activeNotification = notificationService.getActiveNotification(); - expect(activeNotification).toBeUndefined(); - expect(notificationService.notifications.length).toBe(0); + it("uses a custom auto-dismiss timeout value if provided", function () { + var timeoutValueInModel = 1500; + var timeoutValueUsedByService = 0; + mockTimeout.andCallFake(function (callback, timeout) { + timeoutValueUsedByService = timeout; + }); + errorModel.autoDismiss = timeoutValueInModel; + notificationService.error(errorModel); + expect(timeoutValueUsedByService).toEqual(timeoutValueInModel); + }); }); describe("when called with multiple notifications", function () { it("auto-dismisses the previously active notification, making the new notification active", function () { var activeNotification; + infoModel.autoDismiss = false; //First pre-load with a info message notificationService.notify(infoModel); - activeNotification = - notificationService.getActiveNotification(); + activeNotification = notificationService.getActiveNotification(); //Initially expect the active notification to be info expect(activeNotification.model).toBe(infoModel); //Then notify of an error notificationService.notify(errorModel); //But it should be auto-dismissed and replaced with the // error notification - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Two timeouts, one is to force minimization after // displaying the message for a minimum period, the // second is to allow minimization animation to take place. - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); activeNotification = notificationService.getActiveNotification(); expect(activeNotification.model).toBe(errorModel); }); @@ -172,16 +233,15 @@ define( notificationService.notify(infoModel); expect(notificationService.notifications.length).toEqual(2); //Mock the auto-minimize - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Two timeouts, one is to force minimization after // displaying the message for a minimum period, the // second is to allow minimization animation to take place. - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Previous error message should be minimized, not // dismissed expect(notificationService.notifications.length).toEqual(2); - activeNotification = - notificationService.getActiveNotification(); + activeNotification = notificationService.getActiveNotification(); expect(activeNotification.model).toBe(infoModel); expect(errorModel.minimized).toEqual(true); }); @@ -204,27 +264,25 @@ define( notificationService.notify(error3); expect(notificationService.notifications.length).toEqual(3); //Mock the auto-minimize - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Two timeouts, one is to force minimization after // displaying the message for a minimum period, the // second is to allow minimization animation to take place. - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Previous error message should be minimized, not // dismissed expect(notificationService.notifications.length).toEqual(3); - activeNotification = - notificationService.getActiveNotification(); + activeNotification = notificationService.getActiveNotification(); expect(activeNotification.model).toBe(error2); expect(errorModel.minimized).toEqual(true); //Mock the second auto-minimize - mockTimeout.mostRecentCall.args[0](); + elapseTimeout(); //Two timeouts, one is to force minimization after // displaying the message for a minimum period, the // second is to allow minimization animation to take place. - mockTimeout.mostRecentCall.args[0](); - activeNotification = - notificationService.getActiveNotification(); + elapseTimeout(); + activeNotification = notificationService.getActiveNotification(); expect(activeNotification.model).toBe(error3); expect(error2.minimized).toEqual(true); });