From a5b7b97a1f0c8d08781a88b69ce47541c701dabc Mon Sep 17 00:00:00 2001 From: gleb Date: Wed, 31 Aug 2016 13:45:24 +0300 Subject: [PATCH] FIX: cancel $timeout promises when calling clearAll (related to #78) Benefits: * Protractor doesn't wait untill timeouts will finish after calling clearAll --- demo/clear_all.html | 51 +++++++++++++++++++++++++++++ dist/angular-ui-notification.js | 13 +++++++- dist/angular-ui-notification.min.js | 2 +- src/angular-ui-notification.js | 13 +++++++- test/e2e/main.spec.js | 18 ++++++++++ 5 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 demo/clear_all.html diff --git a/demo/clear_all.html b/demo/clear_all.html new file mode 100644 index 0000000..bceedd8 --- /dev/null +++ b/demo/clear_all.html @@ -0,0 +1,51 @@ + + + Notification demo (kill message) + + + + + +
+

Angular ui-notification demo (clear all messages)

+
+ +
+ +
+

Clear All messages

+
+ +
+
+ +
+ + + + + + \ No newline at end of file diff --git a/dist/angular-ui-notification.js b/dist/angular-ui-notification.js index 08410b8..d85138a 100644 --- a/dist/angular-ui-notification.js +++ b/dist/angular-ui-notification.js @@ -9,6 +9,8 @@ angular.module('ui-notification',[]); angular.module('ui-notification').provider('Notification', function() { + var $timeoutPromises = []; + this.options = { delay: 5000, startTop: 10, @@ -136,9 +138,14 @@ angular.module('ui-notification').provider('Notification', function() { templateElement.bind('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd', closeEvent); if (angular.isNumber(args.delay)) { - $timeout(function() { + var $timeoutPromise = $timeout(function() { templateElement.addClass('killed'); + var promiseIndex = $timeoutPromises.indexOf($timeoutPromise); + if(promiseIndex !== -1) { + $timeoutPromises.splice(promiseIndex, 1); + } }, args.delay); + $timeoutPromises.push($timeoutPromise); } setCssTransitions('none'); @@ -218,6 +225,10 @@ angular.module('ui-notification').provider('Notification', function() { angular.forEach(messageElements, function(element) { element.addClass('killed'); }); + angular.forEach($timeoutPromises, function($timeoutPromise) { + $timeout.cancel($timeoutPromise); + }); + $timeoutPromises = []; }; return notify; diff --git a/dist/angular-ui-notification.min.js b/dist/angular-ui-notification.min.js index 317c18c..42b1130 100644 --- a/dist/angular-ui-notification.min.js +++ b/dist/angular-ui-notification.min.js @@ -5,4 +5,4 @@ * @link https://github.com/alexcrack/angular-ui-notification * @license MIT */ -angular.module("ui-notification",[]),angular.module("ui-notification").provider("Notification",function(){this.options={delay:5e3,startTop:10,startRight:10,verticalSpacing:10,horizontalSpacing:10,positionX:"right",positionY:"top",replaceMessage:!1,templateUrl:"angular-ui-notification.html",onClose:void 0,closeOnClick:!0,maxCount:0},this.setOptions=function(e){if(!angular.isObject(e))throw new Error("Options should be an object!");this.options=angular.extend({},this.options,e)},this.$get=["$timeout","$http","$compile","$templateCache","$rootScope","$injector","$sce","$q","$window",function(e,t,n,i,o,s,a,l,r){var c=this.options,p=c.startTop,d=c.startRight,u=c.verticalSpacing,m=c.horizontalSpacing,f=c.delay,g=[],h=!1,C=function(s,C){var y=l.defer();return"object"!=typeof s&&(s={message:s}),s.scope=s.scope?s.scope:o,s.template=s.templateUrl?s.templateUrl:c.templateUrl,s.delay=angular.isUndefined(s.delay)?f:s.delay,s.type=C||c.type||"",s.positionY=s.positionY?s.positionY:c.positionY,s.positionX=s.positionX?s.positionX:c.positionX,s.replaceMessage=s.replaceMessage?s.replaceMessage:c.replaceMessage,s.onClose=s.onClose?s.onClose:c.onClose,s.closeOnClick=null!==s.closeOnClick&&void 0!==s.closeOnClick?s.closeOnClick:c.closeOnClick,t.get(s.template,{cache:i}).success(function(t){function i(e){["-webkit-transition","-o-transition","transition"].forEach(function(t){f.css(t,e)})}var o=s.scope.$new();o.message=a.trustAsHtml(s.message),o.title=a.trustAsHtml(s.title),o.t=s.type.substr(0,1),o.delay=s.delay,o.onClose=s.onClose;var l=function(){for(var e=0,t=0,n=p,i=d,o=[],a=g.length-1;a>=0;a--){var l=g[a];if(s.replaceMessage&&awindow.innerHeight&&(h=p,t++,e=0);var C=n=h?0===e?h:h+u:p,y=i+t*(m+f);l.css(l._positionY,C+"px"),"center"==l._positionX?l.css("left",parseInt(window.innerWidth/2-f/2)+"px"):l.css(l._positionX,y+"px"),o[l._positionY+l._positionX]=C+r,c.maxCount>0&&g.length>c.maxCount&&0===a&&l.scope().kill(!0),e++}}},f=n(t)(o);f._positionY=s.positionY,f._positionX=s.positionX,f.addClass(s.type);var C=function(e){e=e.originalEvent||e,("click"===e.type||"opacity"===e.propertyName&&e.elapsedTime>=1)&&(o.onClose&&o.$apply(o.onClose(f)),f.remove(),g.splice(g.indexOf(f),1),o.$destroy(),l())};s.closeOnClick&&(f.addClass("clickable"),f.bind("click",C)),f.bind("webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",C),angular.isNumber(s.delay)&&e(function(){f.addClass("killed")},s.delay),i("none"),angular.element(document.getElementsByTagName("body")).append(f);var v=-(parseInt(f[0].offsetHeight)+50);if(f.css(f._positionY,v+"px"),g.push(f),"center"==s.positionX){var k=parseInt(f[0].offsetWidth);f.css("left",parseInt(window.innerWidth/2-k/2)+"px")}e(function(){i("")}),o._templateElement=f,o.kill=function(t){t?(o.onClose&&o.$apply(o.onClose(o._templateElement)),g.splice(g.indexOf(o._templateElement),1),o._templateElement.remove(),o.$destroy(),e(l)):o._templateElement.addClass("killed")},e(l),h||(angular.element(r).bind("resize",function(){e(l)}),h=!0),y.resolve(o)}).error(function(e){throw new Error("Template ("+s.template+") could not be loaded. "+e)}),y.promise};return C.primary=function(e){return this(e,"primary")},C.error=function(e){return this(e,"error")},C.success=function(e){return this(e,"success")},C.info=function(e){return this(e,"info")},C.warning=function(e){return this(e,"warning")},C.clearAll=function(){angular.forEach(g,function(e){e.addClass("killed")})},C}]}),angular.module("ui-notification").run(["$templateCache",function(e){e.put("angular-ui-notification.html",'

')}]); \ No newline at end of file +angular.module("ui-notification",[]),angular.module("ui-notification").provider("Notification",function(){var e=[];this.options={delay:5e3,startTop:10,startRight:10,verticalSpacing:10,horizontalSpacing:10,positionX:"right",positionY:"top",replaceMessage:!1,templateUrl:"angular-ui-notification.html",onClose:void 0,closeOnClick:!0,maxCount:0},this.setOptions=function(e){if(!angular.isObject(e))throw new Error("Options should be an object!");this.options=angular.extend({},this.options,e)},this.$get=["$timeout","$http","$compile","$templateCache","$rootScope","$injector","$sce","$q","$window",function(t,n,i,o,s,a,l,r,c){var p=this.options,u=p.startTop,d=p.startRight,f=p.verticalSpacing,m=p.horizontalSpacing,g=p.delay,h=[],C=!1,v=function(a,v){var y=r.defer();return"object"!=typeof a&&(a={message:a}),a.scope=a.scope?a.scope:s,a.template=a.templateUrl?a.templateUrl:p.templateUrl,a.delay=angular.isUndefined(a.delay)?g:a.delay,a.type=v||p.type||"",a.positionY=a.positionY?a.positionY:p.positionY,a.positionX=a.positionX?a.positionX:p.positionX,a.replaceMessage=a.replaceMessage?a.replaceMessage:p.replaceMessage,a.onClose=a.onClose?a.onClose:p.onClose,a.closeOnClick=null!==a.closeOnClick&&void 0!==a.closeOnClick?a.closeOnClick:p.closeOnClick,n.get(a.template,{cache:o}).success(function(n){function o(e){["-webkit-transition","-o-transition","transition"].forEach(function(t){g.css(t,e)})}var s=a.scope.$new();s.message=l.trustAsHtml(a.message),s.title=l.trustAsHtml(a.title),s.t=a.type.substr(0,1),s.delay=a.delay,s.onClose=a.onClose;var r=function(){for(var e=0,t=0,n=u,i=d,o=[],s=h.length-1;s>=0;s--){var l=h[s];if(a.replaceMessage&&swindow.innerHeight&&(g=u,t++,e=0);var C=n=g?0===e?g:g+f:u,v=i+t*(m+c);l.css(l._positionY,C+"px"),"center"==l._positionX?l.css("left",parseInt(window.innerWidth/2-c/2)+"px"):l.css(l._positionX,v+"px"),o[l._positionY+l._positionX]=C+r,p.maxCount>0&&h.length>p.maxCount&&0===s&&l.scope().kill(!0),e++}}},g=i(n)(s);g._positionY=a.positionY,g._positionX=a.positionX,g.addClass(a.type);var v=function(e){e=e.originalEvent||e,("click"===e.type||"opacity"===e.propertyName&&e.elapsedTime>=1)&&(s.onClose&&s.$apply(s.onClose(g)),g.remove(),h.splice(h.indexOf(g),1),s.$destroy(),r())};if(a.closeOnClick&&(g.addClass("clickable"),g.bind("click",v)),g.bind("webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",v),angular.isNumber(a.delay)){var k=t(function(){g.addClass("killed");var t=e.indexOf(k);t!==-1&&e.splice(t,1)},a.delay);e.push(k)}o("none"),angular.element(document.getElementsByTagName("body")).append(g);var w=-(parseInt(g[0].offsetHeight)+50);if(g.css(g._positionY,w+"px"),h.push(g),"center"==a.positionX){var b=parseInt(g[0].offsetWidth);g.css("left",parseInt(window.innerWidth/2-b/2)+"px")}t(function(){o("")}),s._templateElement=g,s.kill=function(e){e?(s.onClose&&s.$apply(s.onClose(s._templateElement)),h.splice(h.indexOf(s._templateElement),1),s._templateElement.remove(),s.$destroy(),t(r)):s._templateElement.addClass("killed")},t(r),C||(angular.element(c).bind("resize",function(e){t(r)}),C=!0),y.resolve(s)}).error(function(e){throw new Error("Template ("+a.template+") could not be loaded. "+e)}),y.promise};return v.primary=function(e){return this(e,"primary")},v.error=function(e){return this(e,"error")},v.success=function(e){return this(e,"success")},v.info=function(e){return this(e,"info")},v.warning=function(e){return this(e,"warning")},v.clearAll=function(){angular.forEach(h,function(e){e.addClass("killed")}),angular.forEach(e,function(e){t.cancel(e)}),e=[]},v}]}),angular.module("ui-notification").run(["$templateCache",function(e){e.put("angular-ui-notification.html",'

')}]); \ No newline at end of file diff --git a/src/angular-ui-notification.js b/src/angular-ui-notification.js index f7a1c4d..3f8dd8b 100644 --- a/src/angular-ui-notification.js +++ b/src/angular-ui-notification.js @@ -2,6 +2,8 @@ angular.module('ui-notification',[]); angular.module('ui-notification').provider('Notification', function() { + var $timeoutPromises = []; + this.options = { delay: 5000, startTop: 10, @@ -129,9 +131,14 @@ angular.module('ui-notification').provider('Notification', function() { templateElement.bind('webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd', closeEvent); if (angular.isNumber(args.delay)) { - $timeout(function() { + var $timeoutPromise = $timeout(function() { templateElement.addClass('killed'); + var promiseIndex = $timeoutPromises.indexOf($timeoutPromise); + if(promiseIndex !== -1) { + $timeoutPromises.splice(promiseIndex, 1); + } }, args.delay); + $timeoutPromises.push($timeoutPromise); } setCssTransitions('none'); @@ -211,6 +218,10 @@ angular.module('ui-notification').provider('Notification', function() { angular.forEach(messageElements, function(element) { element.addClass('killed'); }); + angular.forEach($timeoutPromises, function($timeoutPromise) { + $timeout.cancel($timeoutPromise); + }); + $timeoutPromises = []; }; return notify; diff --git a/test/e2e/main.spec.js b/test/e2e/main.spec.js index 2d5b146..c858ca3 100644 --- a/test/e2e/main.spec.js +++ b/test/e2e/main.spec.js @@ -202,4 +202,22 @@ describe("E2E: Max count", function() { }); }); +}); + +describe("E2E: check if protractor don't wait $timeout after calling clearAll", function() { + beforeEach(function() { + browser.ignoreSynchronization = true; + browser.driver.get('http://localhost:8080/clear_all.html'); + }); + + describe('Click on button should generate several notifications and kill them al after 1 sec', function() { + + it("should click on button and check if all message disappears", function() { + element(by.css('button.btn-success.clear-all')).click(); + expect(element.all(by.css('.ui-notification')).count()).toBe(3); + browser.sleep(1200); + browser.ignoreSynchronization = false; // protractor shouldn't wait 10 secs + }); + + }) }); \ No newline at end of file