angularjs-rails 1.2.26 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) hide show
  1. checksums.yaml +4 -4
  2. data/lib/angularjs-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/angular-animate.js +879 -456
  4. data/vendor/assets/javascripts/angular-aria.js +250 -0
  5. data/vendor/assets/javascripts/angular-cookies.js +1 -1
  6. data/vendor/assets/javascripts/angular-loader.js +17 -10
  7. data/vendor/assets/javascripts/angular-messages.js +400 -0
  8. data/vendor/assets/javascripts/angular-mocks.js +220 -110
  9. data/vendor/assets/javascripts/angular-resource.js +287 -247
  10. data/vendor/assets/javascripts/angular-route.js +111 -54
  11. data/vendor/assets/javascripts/angular-sanitize.js +1 -1
  12. data/vendor/assets/javascripts/angular-scenario.js +11579 -8665
  13. data/vendor/assets/javascripts/angular-touch.js +49 -11
  14. data/vendor/assets/javascripts/angular.js +6660 -3106
  15. data/vendor/assets/javascripts/unstable/angular-animate.js +240 -71
  16. data/vendor/assets/javascripts/unstable/angular-aria.js +12 -12
  17. data/vendor/assets/javascripts/unstable/angular-cookies.js +1 -1
  18. data/vendor/assets/javascripts/unstable/angular-loader.js +4 -4
  19. data/vendor/assets/javascripts/unstable/angular-messages.js +1 -1
  20. data/vendor/assets/javascripts/unstable/angular-mocks.js +21 -14
  21. data/vendor/assets/javascripts/unstable/angular-resource.js +2 -2
  22. data/vendor/assets/javascripts/unstable/angular-route.js +1 -1
  23. data/vendor/assets/javascripts/unstable/angular-sanitize.js +1 -1
  24. data/vendor/assets/javascripts/unstable/angular-scenario.js +562 -262
  25. data/vendor/assets/javascripts/unstable/angular-touch.js +1 -1
  26. data/vendor/assets/javascripts/unstable/angular.js +562 -262
  27. metadata +16 -14
@@ -0,0 +1,250 @@
1
+ /**
2
+ * @license AngularJS v1.3.0
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {'use strict';
7
+
8
+ /**
9
+ * @ngdoc module
10
+ * @name ngAria
11
+ * @description
12
+ *
13
+ * The `ngAria` module provides support for adding <abbr title="Accessible Rich Internet Applications">ARIA</abbr>
14
+ * attributes that convey state or semantic information about the application in order to allow assistive technologies
15
+ * to convey appropriate information to persons with disabilities.
16
+ *
17
+ * <div doc-module-components="ngAria"></div>
18
+ *
19
+ * # Usage
20
+ * To enable the addition of the ARIA tags, just require the module into your application and the tags will
21
+ * hook into your ng-show/ng-hide, input, textarea, button, select and ng-required directives and adds the
22
+ * appropriate ARIA attributes.
23
+ *
24
+ * Currently, the following ARIA attributes are implemented:
25
+ *
26
+ * + aria-hidden
27
+ * + aria-checked
28
+ * + aria-disabled
29
+ * + aria-required
30
+ * + aria-invalid
31
+ * + aria-multiline
32
+ * + aria-valuenow
33
+ * + aria-valuemin
34
+ * + aria-valuemax
35
+ * + tabindex
36
+ *
37
+ * You can disable individual ARIA attributes by using the {@link ngAria.$ariaProvider#config config} method.
38
+ */
39
+
40
+ /* global -ngAriaModule */
41
+ var ngAriaModule = angular.module('ngAria', ['ng']).
42
+ provider('$aria', $AriaProvider);
43
+
44
+ /**
45
+ * @ngdoc provider
46
+ * @name $ariaProvider
47
+ *
48
+ * @description
49
+ *
50
+ * Used for configuring ARIA attributes.
51
+ *
52
+ * ## Dependencies
53
+ * Requires the {@link ngAria} module to be installed.
54
+ */
55
+ function $AriaProvider() {
56
+ var config = {
57
+ ariaHidden : true,
58
+ ariaChecked: true,
59
+ ariaDisabled: true,
60
+ ariaRequired: true,
61
+ ariaInvalid: true,
62
+ ariaMultiline: true,
63
+ ariaValue: true,
64
+ tabindex: true
65
+ };
66
+
67
+ /**
68
+ * @ngdoc method
69
+ * @name $ariaProvider#config
70
+ *
71
+ * @param {object} config object to enable/disable specific ARIA attributes
72
+ *
73
+ * - **ariaHidden** – `{boolean}` – Enables/disables aria-hidden tags
74
+ * - **ariaChecked** – `{boolean}` – Enables/disables aria-checked tags
75
+ * - **ariaDisabled** – `{boolean}` – Enables/disables aria-disabled tags
76
+ * - **ariaRequired** – `{boolean}` – Enables/disables aria-required tags
77
+ * - **ariaInvalid** – `{boolean}` – Enables/disables aria-invalid tags
78
+ * - **ariaMultiline** – `{boolean}` – Enables/disables aria-multiline tags
79
+ * - **ariaValue** – `{boolean}` – Enables/disables aria-valuemin, aria-valuemax and aria-valuenow tags
80
+ * - **tabindex** – `{boolean}` – Enables/disables tabindex tags
81
+ *
82
+ * @description
83
+ * Enables/disables various ARIA attributes
84
+ */
85
+ this.config = function(newConfig) {
86
+ config = angular.extend(config, newConfig);
87
+ };
88
+
89
+ function camelCase(input) {
90
+ return input.replace(/-./g, function(letter, pos) {
91
+ return letter[1].toUpperCase();
92
+ });
93
+ }
94
+
95
+
96
+ function watchExpr(attrName, ariaAttr, negate) {
97
+ var ariaCamelName = camelCase(ariaAttr);
98
+ return function(scope, elem, attr) {
99
+ if (config[ariaCamelName] && !attr[ariaCamelName]) {
100
+ scope.$watch(attr[attrName], function(boolVal) {
101
+ if (negate) {
102
+ boolVal = !boolVal;
103
+ }
104
+ elem.attr(ariaAttr, boolVal);
105
+ });
106
+ }
107
+ };
108
+ }
109
+
110
+ /**
111
+ * @ngdoc service
112
+ * @name $aria
113
+ *
114
+ * @description
115
+ *
116
+ * Contains helper methods for applying ARIA attributes to HTML
117
+ *
118
+ * ## Dependencies
119
+ * Requires the {@link ngAria} module to be installed.
120
+ */
121
+ this.$get = function() {
122
+ return {
123
+ config: function (key) {
124
+ return config[camelCase(key)];
125
+ },
126
+ $$watchExpr: watchExpr
127
+ };
128
+ };
129
+ }
130
+
131
+ var ngAriaTabindex = ['$aria', function($aria) {
132
+ return function(scope, elem, attr) {
133
+ if ($aria.config('tabindex') && !elem.attr('tabindex')) {
134
+ elem.attr('tabindex', 0);
135
+ }
136
+ };
137
+ }];
138
+
139
+ ngAriaModule.directive('ngShow', ['$aria', function($aria) {
140
+ return $aria.$$watchExpr('ngShow', 'aria-hidden', true);
141
+ }])
142
+ .directive('ngHide', ['$aria', function($aria) {
143
+ return $aria.$$watchExpr('ngHide', 'aria-hidden', false);
144
+ }])
145
+ .directive('ngModel', ['$aria', function($aria) {
146
+
147
+ function shouldAttachAttr (attr, elem) {
148
+ return $aria.config(attr) && !elem.attr(attr);
149
+ }
150
+
151
+ function getShape (attr, elem) {
152
+ var type = attr.type,
153
+ role = attr.role;
154
+
155
+ return ((type || role) === 'checkbox' || role === 'menuitemcheckbox') ? 'checkbox' :
156
+ ((type || role) === 'radio' || role === 'menuitemradio') ? 'radio' :
157
+ (type === 'range' || role === 'progressbar' || role === 'slider') ? 'range' :
158
+ (type || role) === 'textbox' || elem[0].nodeName === 'TEXTAREA' ? 'multiline' : '';
159
+ }
160
+
161
+ return {
162
+ restrict: 'A',
163
+ require: '?ngModel',
164
+ link: function(scope, elem, attr, ngModel) {
165
+ var shape = getShape(attr, elem);
166
+ var needsTabIndex = shouldAttachAttr('tabindex', elem);
167
+
168
+ function ngAriaWatchModelValue() {
169
+ return ngModel.$modelValue;
170
+ }
171
+
172
+ function getRadioReaction() {
173
+ if (needsTabIndex) {
174
+ needsTabIndex = false;
175
+ return function ngAriaRadioReaction(newVal) {
176
+ var boolVal = newVal === attr.value;
177
+ elem.attr('aria-checked', boolVal);
178
+ elem.attr('tabindex', 0 - !boolVal);
179
+ };
180
+ } else {
181
+ return function ngAriaRadioReaction(newVal) {
182
+ elem.attr('aria-checked', newVal === attr.value);
183
+ };
184
+ }
185
+ }
186
+
187
+ function ngAriaCheckboxReaction(newVal) {
188
+ elem.attr('aria-checked', !!newVal);
189
+ }
190
+
191
+ switch (shape) {
192
+ case 'radio':
193
+ case 'checkbox':
194
+ if (shouldAttachAttr('aria-checked', elem)) {
195
+ scope.$watch(ngAriaWatchModelValue, shape === 'radio' ?
196
+ getRadioReaction() : ngAriaCheckboxReaction);
197
+ }
198
+ break;
199
+ case 'range':
200
+ if ($aria.config('ariaValue')) {
201
+ if (attr.min && !elem.attr('aria-valuemin')) {
202
+ elem.attr('aria-valuemin', attr.min);
203
+ }
204
+ if (attr.max && !elem.attr('aria-valuemax')) {
205
+ elem.attr('aria-valuemax', attr.max);
206
+ }
207
+ if (!elem.attr('aria-valuenow')) {
208
+ scope.$watch(ngAriaWatchModelValue, function ngAriaValueNowReaction(newVal) {
209
+ elem.attr('aria-valuenow', newVal);
210
+ });
211
+ }
212
+ }
213
+ break;
214
+ case 'multiline':
215
+ if (shouldAttachAttr('aria-multiline', elem)) {
216
+ elem.attr('aria-multiline', true);
217
+ }
218
+ break;
219
+ }
220
+
221
+ if (needsTabIndex) {
222
+ elem.attr('tabindex', 0);
223
+ }
224
+
225
+ if (ngModel.$validators.required && shouldAttachAttr('aria-required', elem)) {
226
+ scope.$watch(function ngAriaRequiredWatch() {
227
+ return ngModel.$error.required;
228
+ }, function ngAriaRequiredReaction(newVal) {
229
+ elem.attr('aria-required', !!newVal);
230
+ });
231
+ }
232
+
233
+ if (shouldAttachAttr('aria-invalid', elem)) {
234
+ scope.$watch(function ngAriaInvalidWatch() {
235
+ return ngModel.$invalid;
236
+ }, function ngAriaInvalidReaction(newVal) {
237
+ elem.attr('aria-invalid', !!newVal);
238
+ });
239
+ }
240
+ }
241
+ };
242
+ }])
243
+ .directive('ngDisabled', ['$aria', function($aria) {
244
+ return $aria.$$watchExpr('ngDisabled', 'aria-disabled');
245
+ }])
246
+ .directive('ngClick', ngAriaTabindex)
247
+ .directive('ngDblclick', ngAriaTabindex);
248
+
249
+
250
+ })(window, window.angular);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.26
2
+ * @license AngularJS v1.3.0
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license AngularJS v1.2.26
2
+ * @license AngularJS v1.3.0
3
3
  * (c) 2010-2014 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
@@ -31,10 +31,13 @@
31
31
  * should all be static strings, not variables or general expressions.
32
32
  *
33
33
  * @param {string} module The namespace to use for the new minErr instance.
34
+ * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
35
+ * error from returned function, for cases when a particular type of error is useful.
34
36
  * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
35
37
  */
36
38
 
37
- function minErr(module) {
39
+ function minErr(module, ErrorConstructor) {
40
+ ErrorConstructor = ErrorConstructor || Error;
38
41
  return function () {
39
42
  var code = arguments[0],
40
43
  prefix = '[' + (module ? module + ':' : '') + code + '] ',
@@ -69,14 +72,13 @@ function minErr(module) {
69
72
  return match;
70
73
  });
71
74
 
72
- message = message + '\nhttp://errors.angularjs.org/1.2.26/' +
75
+ message = message + '\nhttp://errors.angularjs.org/1.3.0/' +
73
76
  (module ? module + '/' : '') + code;
74
77
  for (i = 2; i < arguments.length; i++) {
75
78
  message = message + (i == 2 ? '?' : '&') + 'p' + (i-2) + '=' +
76
79
  encodeURIComponent(stringify(arguments[i]));
77
80
  }
78
-
79
- return new Error(message);
81
+ return new ErrorConstructor(message);
80
82
  };
81
83
  }
82
84
 
@@ -179,15 +181,19 @@ function setupModuleLoader(window) {
179
181
  /** @type {!Array.<Array.<*>>} */
180
182
  var invokeQueue = [];
181
183
 
184
+ /** @type {!Array.<Function>} */
185
+ var configBlocks = [];
186
+
182
187
  /** @type {!Array.<Function>} */
183
188
  var runBlocks = [];
184
189
 
185
- var config = invokeLater('$injector', 'invoke');
190
+ var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
186
191
 
187
192
  /** @type {angular.Module} */
188
193
  var moduleInstance = {
189
194
  // Private state
190
195
  _invokeQueue: invokeQueue,
196
+ _configBlocks: configBlocks,
191
197
  _runBlocks: runBlocks,
192
198
 
193
199
  /**
@@ -298,7 +304,7 @@ function setupModuleLoader(window) {
298
304
  * })
299
305
  * ```
300
306
  *
301
- * See {@link ngAnimate.$animateProvider#register $animateProvider.register()} and
307
+ * See {@link ng.$animateProvider#register $animateProvider.register()} and
302
308
  * {@link ngAnimate ngAnimate module} for more information.
303
309
  */
304
310
  animation: invokeLater('$animateProvider', 'register'),
@@ -348,7 +354,7 @@ function setupModuleLoader(window) {
348
354
  * @description
349
355
  * Use this method to register work which needs to be performed on module loading.
350
356
  * For more about how to configure services, see
351
- * {@link providers#providers_provider-recipe Provider Recipe}.
357
+ * {@link providers#provider-recipe Provider Recipe}.
352
358
  */
353
359
  config: config,
354
360
 
@@ -380,9 +386,10 @@ function setupModuleLoader(window) {
380
386
  * @param {String=} insertMethod
381
387
  * @returns {angular.Module}
382
388
  */
383
- function invokeLater(provider, method, insertMethod) {
389
+ function invokeLater(provider, method, insertMethod, queue) {
390
+ if (!queue) queue = invokeQueue;
384
391
  return function() {
385
- invokeQueue[insertMethod || 'push']([provider, method, arguments]);
392
+ queue[insertMethod || 'push']([provider, method, arguments]);
386
393
  return moduleInstance;
387
394
  };
388
395
  }
@@ -0,0 +1,400 @@
1
+ /**
2
+ * @license AngularJS v1.3.0
3
+ * (c) 2010-2014 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {'use strict';
7
+
8
+ /**
9
+ * @ngdoc module
10
+ * @name ngMessages
11
+ * @description
12
+ *
13
+ * The `ngMessages` module provides enhanced support for displaying messages within templates
14
+ * (typically within forms or when rendering message objects that return key/value data).
15
+ * Instead of relying on JavaScript code and/or complex ng-if statements within your form template to
16
+ * show and hide error messages specific to the state of an input field, the `ngMessages` and
17
+ * `ngMessage` directives are designed to handle the complexity, inheritance and priority
18
+ * sequencing based on the order of how the messages are defined in the template.
19
+ *
20
+ * Currently, the ngMessages module only contains the code for the `ngMessages`
21
+ * and `ngMessage` directives.
22
+ *
23
+ * # Usage
24
+ * The `ngMessages` directive listens on a key/value collection which is set on the ngMessages attribute.
25
+ * Since the {@link ngModel ngModel} directive exposes an `$error` object, this error object can be
26
+ * used with `ngMessages` to display control error messages in an easier way than with just regular angular
27
+ * template directives.
28
+ *
29
+ * ```html
30
+ * <form name="myForm">
31
+ * <input type="text" ng-model="field" name="myField" required minlength="5" />
32
+ * <div ng-messages="myForm.myField.$error">
33
+ * <div ng-message="required">You did not enter a field</div>
34
+ * <div ng-message="minlength">The value entered is too short</div>
35
+ * </div>
36
+ * </form>
37
+ * ```
38
+ *
39
+ * Now whatever key/value entries are present within the provided object (in this case `$error`) then
40
+ * the ngMessages directive will render the inner first ngMessage directive (depending if the key values
41
+ * match the attribute value present on each ngMessage directive). In other words, if your errors
42
+ * object contains the following data:
43
+ *
44
+ * ```javascript
45
+ * <!-- keep in mind that ngModel automatically sets these error flags -->
46
+ * myField.$error = { minlength : true, required : false };
47
+ * ```
48
+ *
49
+ * Then the `required` message will be displayed first. When required is false then the `minlength` message
50
+ * will be displayed right after (since these messages are ordered this way in the template HTML code).
51
+ * The prioritization of each message is determined by what order they're present in the DOM.
52
+ * Therefore, instead of having custom JavaScript code determine the priority of what errors are
53
+ * present before others, the presentation of the errors are handled within the template.
54
+ *
55
+ * By default, ngMessages will only display one error at a time. However, if you wish to display all
56
+ * messages then the `ng-messages-multiple` attribute flag can be used on the element containing the
57
+ * ngMessages directive to make this happen.
58
+ *
59
+ * ```html
60
+ * <div ng-messages="myForm.myField.$error" ng-messages-multiple>...</div>
61
+ * ```
62
+ *
63
+ * ## Reusing and Overriding Messages
64
+ * In addition to prioritization, ngMessages also allows for including messages from a remote or an inline
65
+ * template. This allows for generic collection of messages to be reused across multiple parts of an
66
+ * application.
67
+ *
68
+ * ```html
69
+ * <script type="text/ng-template" id="error-messages">
70
+ * <div ng-message="required">This field is required</div>
71
+ * <div ng-message="minlength">This field is too short</div>
72
+ * </script>
73
+ * <div ng-messages="myForm.myField.$error" ng-messages-include="error-messages"></div>
74
+ * ```
75
+ *
76
+ * However, including generic messages may not be useful enough to match all input fields, therefore,
77
+ * `ngMessages` provides the ability to override messages defined in the remote template by redefining
78
+ * then within the directive container.
79
+ *
80
+ * ```html
81
+ * <!-- a generic template of error messages known as "my-custom-messages" -->
82
+ * <script type="text/ng-template" id="my-custom-messages">
83
+ * <div ng-message="required">This field is required</div>
84
+ * <div ng-message="minlength">This field is too short</div>
85
+ * </script>
86
+ *
87
+ * <form name="myForm">
88
+ * <input type="email"
89
+ * id="email"
90
+ * name="myEmail"
91
+ * ng-model="email"
92
+ * minlength="5"
93
+ * required />
94
+ *
95
+ * <div ng-messages="myForm.myEmail.$error" ng-messages-include="my-custom-messages">
96
+ * <!-- this required message has overridden the template message -->
97
+ * <div ng-message="required">You did not enter your email address</div>
98
+ *
99
+ * <!-- this is a brand new message and will appear last in the prioritization -->
100
+ * <div ng-message="email">Your email address is invalid</div>
101
+ * </div>
102
+ * </form>
103
+ * ```
104
+ *
105
+ * In the example HTML code above the message that is set on required will override the corresponding
106
+ * required message defined within the remote template. Therefore, with particular input fields (such
107
+ * email addresses, date fields, autocomplete inputs, etc...), specialized error messages can be applied
108
+ * while more generic messages can be used to handle other, more general input errors.
109
+ *
110
+ * ## Animations
111
+ * If the `ngAnimate` module is active within the application then both the `ngMessages` and
112
+ * `ngMessage` directives will trigger animations whenever any messages are added and removed
113
+ * from the DOM by the `ngMessages` directive.
114
+ *
115
+ * Whenever the `ngMessages` directive contains one or more visible messages then the `.ng-active` CSS
116
+ * class will be added to the element. The `.ng-inactive` CSS class will be applied when there are no
117
+ * animations present. Therefore, CSS transitions and keyframes as well as JavaScript animations can
118
+ * hook into the animations whenever these classes are added/removed.
119
+ *
120
+ * Let's say that our HTML code for our messages container looks like so:
121
+ *
122
+ * ```html
123
+ * <div ng-messages="myMessages" class="my-messages">
124
+ * <div ng-message="alert" class="some-message">...</div>
125
+ * <div ng-message="fail" class="some-message">...</div>
126
+ * </div>
127
+ * ```
128
+ *
129
+ * Then the CSS animation code for the message container looks like so:
130
+ *
131
+ * ```css
132
+ * .my-messages {
133
+ * transition:1s linear all;
134
+ * }
135
+ * .my-messages.ng-active {
136
+ * // messages are visible
137
+ * }
138
+ * .my-messages.ng-inactive {
139
+ * // messages are hidden
140
+ * }
141
+ * ```
142
+ *
143
+ * Whenever an inner message is attached (becomes visible) or removed (becomes hidden) then the enter
144
+ * and leave animation is triggered for each particular element bound to the `ngMessage` directive.
145
+ *
146
+ * Therefore, the CSS code for the inner messages looks like so:
147
+ *
148
+ * ```css
149
+ * .some-message {
150
+ * transition:1s linear all;
151
+ * }
152
+ *
153
+ * .some-message.ng-enter {}
154
+ * .some-message.ng-enter.ng-enter-active {}
155
+ *
156
+ * .some-message.ng-leave {}
157
+ * .some-message.ng-leave.ng-leave-active {}
158
+ * ```
159
+ *
160
+ * {@link ngAnimate Click here} to learn how to use JavaScript animations or to learn more about ngAnimate.
161
+ */
162
+ angular.module('ngMessages', [])
163
+
164
+ /**
165
+ * @ngdoc directive
166
+ * @module ngMessages
167
+ * @name ngMessages
168
+ * @restrict AE
169
+ *
170
+ * @description
171
+ * `ngMessages` is a directive that is designed to show and hide messages based on the state
172
+ * of a key/value object that it listens on. The directive itself compliments error message
173
+ * reporting with the `ngModel` $error object (which stores a key/value state of validation errors).
174
+ *
175
+ * `ngMessages` manages the state of internal messages within its container element. The internal
176
+ * messages use the `ngMessage` directive and will be inserted/removed from the page depending
177
+ * on if they're present within the key/value object. By default, only one message will be displayed
178
+ * at a time and this depends on the prioritization of the messages within the template. (This can
179
+ * be changed by using the ng-messages-multiple on the directive container.)
180
+ *
181
+ * A remote template can also be used to promote message reuseability and messages can also be
182
+ * overridden.
183
+ *
184
+ * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
185
+ *
186
+ * @usage
187
+ * ```html
188
+ * <!-- using attribute directives -->
189
+ * <ANY ng-messages="expression">
190
+ * <ANY ng-message="keyValue1">...</ANY>
191
+ * <ANY ng-message="keyValue2">...</ANY>
192
+ * <ANY ng-message="keyValue3">...</ANY>
193
+ * </ANY>
194
+ *
195
+ * <!-- or by using element directives -->
196
+ * <ng-messages for="expression">
197
+ * <ng-message when="keyValue1">...</ng-message>
198
+ * <ng-message when="keyValue2">...</ng-message>
199
+ * <ng-message when="keyValue3">...</ng-message>
200
+ * </ng-messages>
201
+ * ```
202
+ *
203
+ * @param {string} ngMessages an angular expression evaluating to a key/value object
204
+ * (this is typically the $error object on an ngModel instance).
205
+ * @param {string=} ngMessagesMultiple|multiple when set, all messages will be displayed with true
206
+ * @param {string=} ngMessagesInclude|include when set, the specified template will be included into the ng-messages container
207
+ *
208
+ * @example
209
+ * <example name="ngMessages-directive" module="ngMessagesExample"
210
+ * deps="angular-messages.js"
211
+ * animations="true" fixBase="true">
212
+ * <file name="index.html">
213
+ * <form name="myForm">
214
+ * <label>Enter your name:</label>
215
+ * <input type="text"
216
+ * name="myName"
217
+ * ng-model="name"
218
+ * ng-minlength="5"
219
+ * ng-maxlength="20"
220
+ * required />
221
+ *
222
+ * <pre>myForm.myName.$error = {{ myForm.myName.$error | json }}</pre>
223
+ *
224
+ * <div ng-messages="myForm.myName.$error" style="color:maroon">
225
+ * <div ng-message="required">You did not enter a field</div>
226
+ * <div ng-message="minlength">Your field is too short</div>
227
+ * <div ng-message="maxlength">Your field is too long</div>
228
+ * </div>
229
+ * </form>
230
+ * </file>
231
+ * <file name="script.js">
232
+ * angular.module('ngMessagesExample', ['ngMessages']);
233
+ * </file>
234
+ * </example>
235
+ */
236
+ .directive('ngMessages', ['$compile', '$animate', '$templateRequest',
237
+ function($compile, $animate, $templateRequest) {
238
+ var ACTIVE_CLASS = 'ng-active';
239
+ var INACTIVE_CLASS = 'ng-inactive';
240
+
241
+ return {
242
+ restrict: 'AE',
243
+ controller: function() {
244
+ this.$renderNgMessageClasses = angular.noop;
245
+
246
+ var messages = [];
247
+ this.registerMessage = function(index, message) {
248
+ for(var i = 0; i < messages.length; i++) {
249
+ if(messages[i].type == message.type) {
250
+ if(index != i) {
251
+ var temp = messages[index];
252
+ messages[index] = messages[i];
253
+ if(index < messages.length) {
254
+ messages[i] = temp;
255
+ } else {
256
+ messages.splice(0, i); //remove the old one (and shift left)
257
+ }
258
+ }
259
+ return;
260
+ }
261
+ }
262
+ messages.splice(index, 0, message); //add the new one (and shift right)
263
+ };
264
+
265
+ this.renderMessages = function(values, multiple) {
266
+ values = values || {};
267
+
268
+ var found;
269
+ angular.forEach(messages, function(message) {
270
+ if((!found || multiple) && truthyVal(values[message.type])) {
271
+ message.attach();
272
+ found = true;
273
+ } else {
274
+ message.detach();
275
+ }
276
+ });
277
+
278
+ this.renderElementClasses(found);
279
+
280
+ function truthyVal(value) {
281
+ return value !== null && value !== false && value;
282
+ }
283
+ };
284
+ },
285
+ require: 'ngMessages',
286
+ link: function($scope, element, $attrs, ctrl) {
287
+ ctrl.renderElementClasses = function(bool) {
288
+ bool ? $animate.setClass(element, ACTIVE_CLASS, INACTIVE_CLASS)
289
+ : $animate.setClass(element, INACTIVE_CLASS, ACTIVE_CLASS);
290
+ };
291
+
292
+ //JavaScript treats empty strings as false, but ng-message-multiple by itself is an empty string
293
+ var multiple = angular.isString($attrs.ngMessagesMultiple) ||
294
+ angular.isString($attrs.multiple);
295
+
296
+ var cachedValues, watchAttr = $attrs.ngMessages || $attrs['for']; //for is a reserved keyword
297
+ $scope.$watchCollection(watchAttr, function(values) {
298
+ cachedValues = values;
299
+ ctrl.renderMessages(values, multiple);
300
+ });
301
+
302
+ var tpl = $attrs.ngMessagesInclude || $attrs.include;
303
+ if(tpl) {
304
+ $templateRequest(tpl)
305
+ .then(function processTemplate(html) {
306
+ var after, container = angular.element('<div/>').html(html);
307
+ angular.forEach(container.children(), function(elm) {
308
+ elm = angular.element(elm);
309
+ after ? after.after(elm)
310
+ : element.prepend(elm); //start of the container
311
+ after = elm;
312
+ $compile(elm)($scope);
313
+ });
314
+ ctrl.renderMessages(cachedValues, multiple);
315
+ });
316
+ }
317
+ }
318
+ };
319
+ }])
320
+
321
+
322
+ /**
323
+ * @ngdoc directive
324
+ * @name ngMessage
325
+ * @restrict AE
326
+ * @scope
327
+ *
328
+ * @description
329
+ * `ngMessage` is a directive with the purpose to show and hide a particular message.
330
+ * For `ngMessage` to operate, a parent `ngMessages` directive on a parent DOM element
331
+ * must be situated since it determines which messages are visible based on the state
332
+ * of the provided key/value map that `ngMessages` listens on.
333
+ *
334
+ * @usage
335
+ * ```html
336
+ * <!-- using attribute directives -->
337
+ * <ANY ng-messages="expression">
338
+ * <ANY ng-message="keyValue1">...</ANY>
339
+ * <ANY ng-message="keyValue2">...</ANY>
340
+ * <ANY ng-message="keyValue3">...</ANY>
341
+ * </ANY>
342
+ *
343
+ * <!-- or by using element directives -->
344
+ * <ng-messages for="expression">
345
+ * <ng-message when="keyValue1">...</ng-message>
346
+ * <ng-message when="keyValue2">...</ng-message>
347
+ * <ng-message when="keyValue3">...</ng-message>
348
+ * </ng-messages>
349
+ * ```
350
+ *
351
+ * {@link module:ngMessages Click here} to learn more about `ngMessages` and `ngMessage`.
352
+ *
353
+ * @param {string} ngMessage a string value corresponding to the message key.
354
+ */
355
+ .directive('ngMessage', ['$animate', function($animate) {
356
+ var COMMENT_NODE = 8;
357
+ return {
358
+ require: '^ngMessages',
359
+ transclude: 'element',
360
+ terminal: true,
361
+ restrict: 'AE',
362
+ link: function($scope, $element, $attrs, ngMessages, $transclude) {
363
+ var index, element;
364
+
365
+ var commentNode = $element[0];
366
+ var parentNode = commentNode.parentNode;
367
+ for(var i = 0, j = 0; i < parentNode.childNodes.length; i++) {
368
+ var node = parentNode.childNodes[i];
369
+ if(node.nodeType == COMMENT_NODE && node.nodeValue.indexOf('ngMessage') >= 0) {
370
+ if(node === commentNode) {
371
+ index = j;
372
+ break;
373
+ }
374
+ j++;
375
+ }
376
+ }
377
+
378
+ ngMessages.registerMessage(index, {
379
+ type : $attrs.ngMessage || $attrs.when,
380
+ attach : function() {
381
+ if(!element) {
382
+ $transclude($scope, function(clone) {
383
+ $animate.enter(clone, null, $element);
384
+ element = clone;
385
+ });
386
+ }
387
+ },
388
+ detach : function(now) {
389
+ if(element) {
390
+ $animate.leave(element);
391
+ element = null;
392
+ }
393
+ }
394
+ });
395
+ }
396
+ };
397
+ }]);
398
+
399
+
400
+ })(window, window.angular);