ng-toaster-rails 0.4.10.0 → 0.4.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 697ccecb4ea4a58a6b1831a6b004847a998fa4eb
4
- data.tar.gz: 7bc8efe62722bca0d03a3d4d930ed62a5012f1b4
3
+ metadata.gz: 401242d3f02d3e2b48f7fd684785ebe9e4c1fc42
4
+ data.tar.gz: a76c7190683446075a7bb399de98eabfb4ec1d9f
5
5
  SHA512:
6
- metadata.gz: 6c23cb27c01ca38cef99f3bf303120565d83b2a9bc2a1704a4dd4382babbbfb1df1615663f47cb096ece77da00ebafed953c0d1963212f71431fc25875f936e0
7
- data.tar.gz: 395425932fe7ed9b4d27bb01a385f8ff0c1eaba6e65a02fecf90b69b1505eab7146be5ee88751ec3122318560cddcb9df8ced640bd3d9f1b4eda7144cadadfc9
6
+ metadata.gz: 8d9ad77fa42a8867b4b3e6369ffb2f6b72b7b018b8ff70e5aca2d13fff0d4439f50a61b9e3fac2f74c27d46bbe3149bdf2feaaaa2bb51758baa13977c1a346ca
7
+ data.tar.gz: 2aafe6b0227879f872ac3bcbbe1383267c524b592eee2b532390dadaa5d5660fbb999c71810047b6d6a8735120997f42a9631ad94304ac0711ff3393b86298e9
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # ng-toaster-rails
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/ng-toaster-rails.svg)](http://badge.fury.io/rb/ng-toaster-rails)
4
+
3
5
  ng-toaster-rails wraps the [AngularJS-Toaster](https://github.com/jirikavi/AngularJS-Toaster) library in a rails engine for simple use with the asset pipeline provided by Rails 3.1 and higher. The gem includes the development (non-minified) source for ease of exploration. The asset pipeline will minify in production.
4
6
 
5
7
  For more info on customizing the library, please refer to the [doc](https://github.com/jirikavi/AngularJS-Toaster)
@@ -1,6 +1,6 @@
1
1
  module NgToaster
2
2
  module Rails
3
3
  TOASTER_VERSION = "0.4.10"
4
- VERSION = "#{TOASTER_VERSION}.0"
4
+ VERSION = "#{TOASTER_VERSION}.1"
5
5
  end
6
6
  end
@@ -3,11 +3,11 @@
3
3
 
4
4
  /*
5
5
  * AngularJS Toaster
6
- * Version: 0.4.10
6
+ * Version: 0.4.10+
7
7
  *
8
- * Copyright 2013 Jiri Kavulak.
9
- * All Rights Reserved.
10
- * Use, reproduction, distribution, and modification of this code is subject to the terms and
8
+ * Copyright 2013-2014 Jiri Kavulak.
9
+ * All Rights Reserved.
10
+ * Use, reproduction, distribution, and modification of this code is subject to the terms and
11
11
  * conditions of the MIT license, available at http://www.opensource.org/licenses/mit-license.php
12
12
  *
13
13
  * Author: Jiri Kavulak
@@ -16,15 +16,15 @@
16
16
 
17
17
  angular.module('toaster', ['ngAnimate'])
18
18
  .constant('toasterConfig', {
19
- 'limit': 0, // limits max number of toasts
19
+ 'limit': 0, // limits max number of toasts
20
20
  'tap-to-dismiss': true,
21
21
  'close-button': false,
22
22
  'newest-on-top': true,
23
23
  //'fade-in': 1000, // done in css
24
24
  //'on-fade-in': undefined, // not implemented
25
25
  //'fade-out': 1000, // done in css
26
- // 'on-fade-out': undefined, // not implemented
27
- //'extended-time-out': 1000, // not implemented
26
+ //'on-fade-out': undefined, // not implemented
27
+ //'extended-time-out': 1000, // not implemented
28
28
  'time-out': 5000, // Set timeOut and extendedTimeout to 0 to make it sticky
29
29
  'icon-classes': {
30
30
  error: 'toast-error',
@@ -33,18 +33,22 @@ angular.module('toaster', ['ngAnimate'])
33
33
  success: 'toast-success',
34
34
  warning: 'toast-warning'
35
35
  },
36
- 'body-output-type': '',// Options: '', 'trustedHtml', 'template', 'templateWithData'
36
+ 'body-output-type': '', // Options: '', 'trustedHtml', 'template', 'templateWithData'
37
37
  'body-template': 'toasterBodyTmpl.html',
38
38
  'icon-class': 'toast-info',
39
- 'position-class': 'toast-top-right',
39
+ 'position-class': 'toast-top-right', // Options (see CSS):
40
+ // 'toast-top-full-width', 'toast-bottom-full-width', 'toast-center',
41
+ // 'toast-top-left', 'toast-top-center', 'toast-top-rigt',
42
+ // 'toast-bottom-left', 'toast-bottom-center', 'toast-bottom-rigt',
40
43
  'title-class': 'toast-title',
41
44
  'message-class': 'toast-message',
45
+ 'prevent-duplicates': false,
42
46
  'mouseover-timer-stop': true // stop timeout on mouseover and restart timer on mouseout
43
47
  })
44
48
  .service('toaster', ['$rootScope', 'toasterConfig', function ($rootScope, toasterConfig) {
45
- this.pop = function (type, title, body, timeout, bodyOutputType, clickHandler) {
49
+ this.pop = function (type, title, body, timeout, bodyOutputType, clickHandler, toasterId) {
46
50
  if (angular.isObject(type)) {
47
- var params = type; // NOTE: anable parameters as pop argument
51
+ var params = type; // Enable named parameters as pop argument
48
52
  this.toast = {
49
53
  type: params.type,
50
54
  title: params.title,
@@ -53,8 +57,8 @@ angular.module('toaster', ['ngAnimate'])
53
57
  bodyOutputType: params.bodyOutputType,
54
58
  clickHandler: params.clickHandler
55
59
  };
56
- }
57
- else {
60
+ toasterId = params.toasterId;
61
+ } else {
58
62
  this.toast = {
59
63
  type: type,
60
64
  title: title,
@@ -64,93 +68,124 @@ angular.module('toaster', ['ngAnimate'])
64
68
  clickHandler: clickHandler
65
69
  };
66
70
  }
67
- $rootScope.$emit('toaster-newToast');
71
+ $rootScope.$emit('toaster-newToast', toasterId);
68
72
  };
69
73
 
70
74
  this.clear = function () {
71
75
  $rootScope.$emit('toaster-clearToasts');
72
76
  };
73
-
77
+
78
+ // Create one method per icon class, to allow to call toaster.info() and similar
74
79
  for (var type in toasterConfig['icon-classes']) {
75
- this[type] = (function (toasterType){
76
- return function(title, body, timeout, bodyOutputType, clickHandler) {
77
- if (angular.isString(title))
78
- this.pop(toasterType, title, body, timeout, bodyOutputType, clickHandler);
79
- else
80
- this.pop(angular.extend(title, {type: toasterType}));
81
- }
82
- })(type);
80
+ this[type] = (function (toasterType) {
81
+ return function(title, body, timeout, bodyOutputType, clickHandler, toasterId) {
82
+ if (angular.isString(title)) {
83
+ this.pop(toasterType, title, body, timeout, bodyOutputType, clickHandler, toasterId);
84
+ } else { // 'title' is actually an object with options
85
+ this.pop(angular.extend(title, { type: toasterType }));
86
+ }
87
+ };
88
+ })(type);
83
89
  }
84
90
  }])
85
- .factory('toasterRegisterEvents', function() {
86
-
87
- var toasterFactory = {
88
- _NewToastEvent: false,
89
- _ClearAllToastsEvent: false,
90
- registerNewToastEvent: function(){
91
- this._NewToastEvent = true;
92
- },
93
- registerClearAllToastsEvent: function(){
94
- this._ClearAllToastsEvent = true;
95
- },
96
- deregisterNewToastEvent: function(){
97
- this._NewToastEvent = false;
98
- },
99
- deregisterClearAllToastsEvent: function(){
100
- this._ClearAllToastsEvent = false;
101
- },
102
- isRegisteredNewToastEvent: function(){
103
- return this._NewToastEvent;
104
- },
105
- isRegisteredClearAllToastsEvent: function(){
106
- return this._ClearAllToastsEvent;
107
- }
108
- }
91
+ .factory('toasterEventRegistry',['$rootScope', function($rootScope) {
92
+ var deregisterNewToast = null,
93
+ deregisterClearToasts = null,
94
+ newToastEventSubscribers = [],
95
+ clearToastsEventSubscribers = [],
96
+ toasterFactory;
97
+
98
+ toasterFactory = {
99
+ setup: function () {
100
+ if (!deregisterNewToast) {
101
+ deregisterNewToast = $rootScope.$on('toaster-newToast', function (event, toasterId) {
102
+ for (var i = 0, len = newToastEventSubscribers.length; i < len; i++) {
103
+ newToastEventSubscribers[i](event, toasterId);
104
+ }
105
+ });
106
+ }
107
+
108
+ if (!deregisterClearToasts) {
109
+ deregisterClearToasts = $rootScope.$on('toaster-clearToasts', function (event) {
110
+ for (var i = 0, len = clearToastsEventSubscribers.length; i < len; i++) {
111
+ clearToastsEventSubscribers[i](event);
112
+ }
113
+ });
114
+ }
115
+ },
116
+
117
+ subscribeToNewToastEvent: function(onNewToast) {
118
+ newToastEventSubscribers.push(onNewToast);
119
+ },
120
+ subscribeToClearToastsEvent: function(onClearToasts) {
121
+ clearToastsEventSubscribers.push(onClearToasts);
122
+ },
123
+ unsubscribeToNewToastEvent: function(onNewToast) {
124
+ var index = newToastEventSubscribers.indexOf(onNewToast);
125
+ if (index >= 0)
126
+ newToastEventSubscribers.splice(index, 1);
127
+
128
+ if (newToastEventSubscribers.length === 0) {
129
+ deregisterNewToast();
130
+ deregisterNewToast = null;
131
+ }
132
+ },
133
+ unsubscribeToClearToastsEvent: function(onClearToasts) {
134
+ var index = clearToastsEventSubscribers.indexOf(onClearToasts);
135
+ if (index >= 0)
136
+ clearToastsEventSubscribers.splice(index, 1);
137
+
138
+ if (clearToastsEventSubscribers.length === 0) {
139
+ deregisterClearToasts();
140
+ deregisterClearToasts = null;
141
+ }
142
+ }
143
+ };
109
144
  return {
110
- registerNewToastEvent: toasterFactory.registerNewToastEvent,
111
- registerClearAllToastsEvent: toasterFactory.registerClearAllToastsEvent,
112
- deregisterNewToastEvent: toasterFactory.deregisterNewToastEvent,
113
- deregisterClearAllToastsEvent: toasterFactory.deregisterClearAllToastsEvent,
114
- isRegisteredNewToastEvent: toasterFactory.isRegisteredNewToastEvent,
115
- isRegisteredClearAllToastsEvent: toasterFactory.isRegisteredClearAllToastsEvent
116
- }
117
- })
118
- .directive('toasterContainer', ['$parse', '$rootScope', '$interval', '$sce', 'toasterConfig', 'toaster', 'toasterRegisterEvents',
119
- function ($parse, $rootScope, $interval, $sce, toasterConfig, toaster, toasterRegisterEvents) {
145
+ setup: toasterFactory.setup,
146
+ subscribeToNewToastEvent: toasterFactory.subscribeToNewToastEvent,
147
+ subscribeToClearToastsEvent: toasterFactory.subscribeToClearToastsEvent,
148
+ unsubscribeToNewToastEvent: toasterFactory.unsubscribeToNewToastEvent,
149
+ unsubscribeToClearToastsEvent: toasterFactory.unsubscribeToClearToastsEvent
150
+ };
151
+ }])
152
+ .directive('toasterContainer', ['$parse', '$rootScope', '$interval', '$sce', 'toasterConfig', 'toaster', 'toasterEventRegistry',
153
+ function ($parse, $rootScope, $interval, $sce, toasterConfig, toaster, toasterEventRegistry) {
120
154
  return {
121
155
  replace: true,
122
156
  restrict: 'EA',
123
- scope: true, // creates an internal scope for this directive
157
+ scope: true, // creates an internal scope for this directive (one per directive instance)
124
158
  link: function (scope, elm, attrs) {
125
159
  var id = 0,
126
160
  mergedConfig;
127
161
 
162
+ // Merges configuration set in directive with default one
128
163
  mergedConfig = angular.extend({}, toasterConfig, scope.$eval(attrs.toasterOptions));
129
164
 
130
165
  scope.config = {
166
+ toasterId: mergedConfig['toaster-id'],
131
167
  position: mergedConfig['position-class'],
132
168
  title: mergedConfig['title-class'],
133
169
  message: mergedConfig['message-class'],
134
170
  tap: mergedConfig['tap-to-dismiss'],
135
171
  closeButton: mergedConfig['close-button'],
136
172
  animation: mergedConfig['animation-class'],
137
- mouseoverTimer: mergedConfig['mouseover-timer-stop']
173
+ mouseoverTimer: mergedConfig['mouseover-timer-stop']
138
174
  };
139
175
 
140
- scope.deregClearToasts = null;
141
- scope.deregNewToast = null;
142
-
143
- scope.$on("$destroy",function () {
144
- if (scope.deregClearToasts) scope.deregClearToasts();
145
- if (scope.deregNewToast) scope.deregNewToast();
146
- scope.deregClearToasts=null;
147
- scope.deregNewToast=null;
148
- toasterRegisterEvents.deregisterNewToastEvent();
149
- toasterRegisterEvents.deregisterClearAllToastsEvent();
176
+ scope.$on("$destroy", function () {
177
+ toasterEventRegistry.unsubscribeToNewToastEvent(scope._onNewToast);
178
+ toasterEventRegistry.unsubscribeToClearToastsEvent(scope._onClearToasts);
150
179
  });
151
180
 
152
- scope.configureTimer = function configureTimer(toast) {
153
- var timeout = typeof (toast.timeout) == "number" ? toast.timeout : mergedConfig['time-out'];
181
+ function setTimeout(toast, time) {
182
+ toast.timeoutPromise = $interval(function () {
183
+ scope.removeToast(toast.id);
184
+ }, time, 1);
185
+ }
186
+
187
+ scope.configureTimer = function (toast) {
188
+ var timeout = angular.isNumber(toast.timeout) ? toast.timeout : mergedConfig['time-out'];
154
189
  if (timeout > 0)
155
190
  setTimeout(toast, timeout);
156
191
  };
@@ -160,8 +195,13 @@ function ($parse, $rootScope, $interval, $sce, toasterConfig, toaster, toasterRe
160
195
  if (!toast.type)
161
196
  toast.type = mergedConfig['icon-class'];
162
197
 
163
- id++;
164
- angular.extend(toast, { id: id });
198
+ // Prevent adding duplicate toasts if it's set
199
+ if (mergedConfig['prevent-duplicates'] === true &&
200
+ scope.toasters.length > 0 &&
201
+ scope.toasters[scope.toasters.length - 1].body === toast.body)
202
+ return;
203
+
204
+ toast.id = ++id;
165
205
 
166
206
  // Set the toast.bodyOutputType to the default if it isn't set
167
207
  toast.bodyOutputType = toast.bodyOutputType || mergedConfig['body-output-type'];
@@ -193,97 +233,104 @@ function ($parse, $rootScope, $interval, $sce, toasterConfig, toaster, toasterRe
193
233
  scope.toasters.shift();
194
234
  }
195
235
  }
196
-
197
- toast.mouseover = false;
198
236
  }
199
-
200
- function setTimeout(toast, time) {
201
- toast.timeout = $interval(function () {
202
- if (!toast.mouseover)
203
- scope.removeToast(toast.id);
204
- }, time);
237
+
238
+ scope.removeToast = function (id) {
239
+ var i, len, toast;
240
+ for (i = 0, len = scope.toasters.length; i < len; i++) {
241
+ if (scope.toasters[i].id === id) {
242
+ removeToast(i);
243
+ break;
244
+ }
245
+ }
246
+ };
247
+
248
+ function removeToast(toastIndex) {
249
+ var toast = scope.toasters[toastIndex];
250
+ if (toast) {
251
+ if (toast.timeoutPromise) {
252
+ $interval.cancel(toast.timeoutPromise);
253
+ }
254
+ scope.toasters.splice(toastIndex, 1);
255
+ }
256
+ }
257
+
258
+ function removeAllToasts() {
259
+ for (var i = scope.toasters.length; i >= 0; i--) {
260
+ removeToast(i);
261
+ }
205
262
  }
206
263
 
207
264
  scope.toasters = [];
208
-
209
- if(!toasterRegisterEvents.isRegisteredNewToastEvent()){
210
- toasterRegisterEvents.registerNewToastEvent();
211
- scope.deregNewToast = $rootScope.$on('toaster-newToast', function () {
265
+
266
+ scope._onNewToast = function (event, toasterId) {
267
+ // Compatibility: if toaster has no toasterId defined, and if call to display
268
+ // hasn't either, then the request is for us
269
+ if (scope.config.toasterId === undefined && toasterId === undefined ||
270
+ // Otherwise, we check if the event is for this toaster
271
+ toasterId !== undefined && toasterId === scope.config.toasterId)
212
272
  addToast(toaster.toast);
213
- });
214
- }
273
+ };
274
+ scope._onClearToasts = function (event) {
275
+ removeAllToasts();
276
+ };
215
277
 
216
- if(!toasterRegisterEvents.isRegisteredClearAllToastsEvent()){
217
- toasterRegisterEvents.registerClearAllToastsEvent();
218
- scope.deregClearToasts = $rootScope.$on('toaster-clearToasts', function () {
219
- scope.toasters.splice(0, scope.toasters.length);
220
- });
221
- }
278
+ toasterEventRegistry.setup();
279
+
280
+ toasterEventRegistry.subscribeToNewToastEvent(scope._onNewToast);
281
+ toasterEventRegistry.subscribeToClearToastsEvent(scope._onClearToasts);
222
282
  },
223
283
  controller: ['$scope', '$element', '$attrs', function ($scope, $element, $attrs) {
224
-
284
+ // Called on mouseover
225
285
  $scope.stopTimer = function (toast) {
226
- toast.mouseover = true;
227
286
  if ($scope.config.mouseoverTimer === true) {
228
- if (toast.timeout) {
229
- $interval.cancel(toast.timeout);
230
- toast.timeout = null;
287
+ if (toast.timeoutPromise) {
288
+ $interval.cancel(toast.timeoutPromise);
289
+ toast.timeoutPromise = null;
231
290
  }
232
291
  }
233
292
  };
234
293
 
294
+ // Called on mouseout
235
295
  $scope.restartTimer = function (toast) {
236
- toast.mouseover = false;
237
296
  if ($scope.config.mouseoverTimer === true) {
238
- if (!toast.timeout)
297
+ if (!toast.timeoutPromise)
239
298
  $scope.configureTimer(toast);
240
- }
241
- else if (toast.timeout === null) {
242
- $scope.removeToast(toaster.id);
243
- }
244
- };
245
-
246
- $scope.removeToast = function (id) {
247
- var i = 0;
248
- for (i; i < $scope.toasters.length; i++) {
249
- if ($scope.toasters[i].id === id)
250
- break;
299
+ } else if (toast.timeoutPromise === null) {
300
+ $scope.removeToast(toast.id);
251
301
  }
252
- $scope.toasters.splice(i, 1);
253
302
  };
254
303
 
255
- $scope.click = function (toaster, isCloseButton) {
256
- if ($scope.config.tap === true || isCloseButton == true) {
304
+ $scope.click = function (toast, isCloseButton) {
305
+ if ($scope.config.tap === true || isCloseButton === true) {
257
306
  var removeToast = true;
258
- if (toaster.clickHandler) {
259
- if (angular.isFunction(toaster.clickHandler)) {
260
- removeToast = toaster.clickHandler(toaster, isCloseButton);
261
- }
262
- else if (angular.isFunction($scope.$parent.$eval(toaster.clickHandler))) {
263
- removeToast = $scope.$parent.$eval(toaster.clickHandler)(toaster, isCloseButton);
264
- }
265
- else {
307
+ if (toast.clickHandler) {
308
+ if (angular.isFunction(toast.clickHandler)) {
309
+ removeToast = toast.clickHandler(toast, isCloseButton);
310
+ } else if (angular.isFunction($scope.$parent.$eval(toast.clickHandler))) {
311
+ removeToast = $scope.$parent.$eval(toast.clickHandler)(toast, isCloseButton);
312
+ } else {
266
313
  console.log("TOAST-NOTE: Your click handler is not inside a parent scope of toaster-container.");
267
314
  }
268
315
  }
269
316
  if (removeToast) {
270
- $scope.removeToast(toaster.id);
317
+ $scope.removeToast(toast.id);
271
318
  }
272
319
  }
273
320
  };
274
321
  }],
275
322
  template:
276
- '<div id="toast-container" ng-class="[config.position, config.animation]">' +
277
- '<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="click(toaster)" ng-mouseover="stopTimer(toaster)" ng-mouseout="restartTimer(toaster)">' +
278
- '<button class="toast-close-button" ng-show="config.closeButton" ng-click="click(toaster, true)">&times;</button>' +
279
- '<div ng-class="config.title">{{toaster.title}}</div>' +
280
- '<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
281
- '<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
282
- '<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
283
- '<div ng-switch-when="templateWithData"><div ng-include="toaster.bodyTemplate"></div></div>' +
284
- '<div ng-switch-default >{{toaster.body}}</div>' +
285
- '</div>' +
323
+ '<div id="toast-container" ng-class="[config.position, config.animation]">' +
324
+ '<div ng-repeat="toaster in toasters" class="toast" ng-class="toaster.type" ng-click="click(toaster)" ng-mouseover="stopTimer(toaster)" ng-mouseout="restartTimer(toaster)">' +
325
+ '<button class="toast-close-button" ng-show="config.closeButton" ng-click="click(toaster, true)">&times;</button>' +
326
+ '<div ng-class="config.title">{{toaster.title}}</div>' +
327
+ '<div ng-class="config.message" ng-switch on="toaster.bodyOutputType">' +
328
+ '<div ng-switch-when="trustedHtml" ng-bind-html="toaster.html"></div>' +
329
+ '<div ng-switch-when="template"><div ng-include="toaster.bodyTemplate"></div></div>' +
330
+ '<div ng-switch-when="templateWithData"><div ng-include="toaster.bodyTemplate"></div></div>' +
331
+ '<div ng-switch-default >{{toaster.body}}</div>' +
286
332
  '</div>' +
333
+ '</div>' +
287
334
  '</div>'
288
335
  };
289
336
  }]);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ng-toaster-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.10.0
4
+ version: 0.4.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - fdibartolo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-19 00:00:00.000000000 Z
11
+ date: 2015-03-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Rails engine for jirikavi/AngularJS-Toaster: "AngularJS Toaster is a
14
14
  customized version of "toastr" non-blocking notification javascript library"'