angularjs-rails 1.5.8 → 1.8.0

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
3
- * (c) 2010-2016 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.8.0
3
+ * (c) 2010-2020 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular) {'use strict';
@@ -1223,24 +1223,27 @@ function IDC_Y(cp) {
1223
1223
  return false;
1224
1224
  }
1225
1225
 
1226
+ /* eslint-disable new-cap */
1227
+
1226
1228
  /**
1227
1229
  * @ngdoc module
1228
1230
  * @name ngParseExt
1229
1231
  * @packageName angular-parse-ext
1230
- * @description
1231
1232
  *
1232
- * # ngParseExt
1233
+ * @description
1233
1234
  *
1234
1235
  * The `ngParseExt` module provides functionality to allow Unicode characters in
1235
- * identifiers inside Angular expressions.
1236
- *
1237
- *
1238
- * <div doc-module-components="ngParseExt"></div>
1236
+ * identifiers inside AngularJS expressions.
1239
1237
  *
1240
1238
  * This module allows the usage of any identifier that follows ES6 identifier naming convention
1241
- * to be used as an identifier in an Angular expression. ES6 delegates some of the identifier
1239
+ * to be used as an identifier in an AngularJS expression. ES6 delegates some of the identifier
1242
1240
  * rules definition to Unicode, this module uses ES6 and Unicode 8.0 identifiers convention.
1243
1241
  *
1242
+ * <div class="alert alert-warning">
1243
+ * You cannot use Unicode characters for variable names in the {@link ngRepeat} or {@link ngOptions}
1244
+ * expressions (e.g. `ng-repeat="f in поля"`), because even with `ngParseExt` included, these
1245
+ * special expressions are not parsed by the {@link $parse} service.
1246
+ * </div>
1244
1247
  */
1245
1248
 
1246
1249
  /* global angularParseExtModule: true,
@@ -1265,7 +1268,8 @@ function isValidIdentifierContinue(ch, cp) {
1265
1268
  angular.module('ngParseExt', [])
1266
1269
  .config(['$parseProvider', function($parseProvider) {
1267
1270
  $parseProvider.setIdentifierFns(isValidIdentifierStart, isValidIdentifierContinue);
1268
- }]);
1271
+ }])
1272
+ .info({ angularVersion: '1.8.0' });
1269
1273
 
1270
1274
 
1271
1275
  })(window, window.angular);
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
3
- * (c) 2010-2016 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.8.0
3
+ * (c) 2010-2020 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular) {'use strict';
@@ -53,14 +53,9 @@ function shallowClearAndCopy(src, dst) {
53
53
  * @name ngResource
54
54
  * @description
55
55
  *
56
- * # ngResource
57
- *
58
56
  * The `ngResource` module provides interaction support with RESTful services
59
57
  * via the $resource service.
60
58
  *
61
- *
62
- * <div doc-module-components="ngResource"></div>
63
- *
64
59
  * See {@link ngResource.$resourceProvider} and {@link ngResource.$resource} for usage.
65
60
  */
66
61
 
@@ -120,30 +115,35 @@ function shallowClearAndCopy(src, dst) {
120
115
  *
121
116
  * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
122
117
  * `actions` methods. If a parameter value is a function, it will be called every time
123
- * a param value needs to be obtained for a request (unless the param was overridden). The function
124
- * will be passed the current data value as an argument.
118
+ * a param value needs to be obtained for a request (unless the param was overridden). The
119
+ * function will be passed the current data value as an argument.
125
120
  *
126
121
  * Each key value in the parameter object is first bound to url template if present and then any
127
122
  * excess keys are appended to the url search query after the `?`.
128
123
  *
129
- * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
124
+ * Given a template `/path/:verb` and parameter `{verb: 'greet', salutation: 'Hello'}` results in
130
125
  * URL `/path/greet?salutation=Hello`.
131
126
  *
132
127
  * If the parameter value is prefixed with `@`, then the value for that parameter will be
133
- * extracted from the corresponding property on the `data` object (provided when calling a
134
- * "non-GET" action method).
128
+ * extracted from the corresponding property on the `data` object (provided when calling actions
129
+ * with a request body).
135
130
  * For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
136
131
  * `someParam` will be `data.someProp`.
137
132
  * Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
138
- * method that does not accept a request body)
133
+ * method that does not accept a request body).
134
+ *
135
+ * @param {Object.<Object>=} actions Hash with declaration of custom actions that will be available
136
+ * in addition to the default set of resource actions (see below). If a custom action has the same
137
+ * key as a default action (e.g. `save`), then the default action will be *overwritten*, and not
138
+ * extended.
139
139
  *
140
- * @param {Object.<Object>=} actions Hash with declaration of custom actions that should extend
141
- * the default set of resource actions. The declaration should be created in the format of {@link
142
- * ng.$http#usage $http.config}:
140
+ * The declaration should be created in the format of {@link ng.$http#usage $http.config}:
143
141
  *
144
- * {action1: {method:?, params:?, isArray:?, headers:?, ...},
145
- * action2: {method:?, params:?, isArray:?, headers:?, ...},
146
- * ...}
142
+ * {
143
+ * action1: {method:?, params:?, isArray:?, headers:?, ...},
144
+ * action2: {method:?, params:?, isArray:?, headers:?, ...},
145
+ * ...
146
+ * }
147
147
  *
148
148
  * Where:
149
149
  *
@@ -155,46 +155,58 @@ function shallowClearAndCopy(src, dst) {
155
155
  * the parameter value is a function, it will be called every time when a param value needs to
156
156
  * be obtained for a request (unless the param was overridden). The function will be passed the
157
157
  * current data value as an argument.
158
- * - **`url`** – {string} – action specific `url` override. The url templating is supported just
158
+ * - **`url`** – {string} – Action specific `url` override. The url templating is supported just
159
159
  * like for the resource-level urls.
160
160
  * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
161
161
  * see `returns` section.
162
162
  * - **`transformRequest`** –
163
163
  * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
164
- * transform function or an array of such functions. The transform function takes the http
164
+ * Transform function or an array of such functions. The transform function takes the http
165
165
  * request body and headers and returns its transformed (typically serialized) version.
166
166
  * By default, transformRequest will contain one function that checks if the request data is
167
- * an object and serializes to using `angular.toJson`. To prevent this behavior, set
167
+ * an object and serializes it using `angular.toJson`. To prevent this behavior, set
168
168
  * `transformRequest` to an empty array: `transformRequest: []`
169
169
  * - **`transformResponse`** –
170
- * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
171
- * transform function or an array of such functions. The transform function takes the http
172
- * response body and headers and returns its transformed (typically deserialized) version.
170
+ * `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
171
+ * Transform function or an array of such functions. The transform function takes the HTTP
172
+ * response body, headers and status and returns its transformed (typically deserialized)
173
+ * version.
173
174
  * By default, transformResponse will contain one function that checks if the response looks
174
175
  * like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
175
176
  * set `transformResponse` to an empty array: `transformResponse: []`
176
- * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
177
- * GET request, otherwise if a cache instance built with
178
- * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
179
- * caching.
180
- * - **`timeout`** – `{number}` – timeout in milliseconds.<br />
177
+ * - **`cache`** – `{boolean|Cache}` – A boolean value or object created with
178
+ * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
179
+ * See {@link $http#caching $http Caching} for more information.
180
+ * - **`timeout`** – `{number}` – Timeout in milliseconds.<br />
181
181
  * **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
182
- * **not** supported in $resource, because the same value would be used for multiple requests.
182
+ * **not** supported in `$resource`, because the same value would be used for multiple requests.
183
183
  * If you are looking for a way to cancel requests, you should use the `cancellable` option.
184
- * - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
185
- * will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
186
- * return value. Calling `$cancelRequest()` for a non-cancellable or an already
187
- * completed/cancelled request will have no effect.<br />
188
- * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
184
+ * - **`cancellable`** – `{boolean}` – If true, the request made by a "non-instance" call will be
185
+ * cancelled (if not already completed) by calling `$cancelRequest()` on the call's return
186
+ * value. Calling `$cancelRequest()` for a non-cancellable or an already completed/cancelled
187
+ * request will have no effect.
188
+ * - **`withCredentials`** `{boolean}` Whether to set the `withCredentials` flag on the
189
189
  * XHR object. See
190
- * [requests with credentials](https://developer.mozilla.org/en/http_access_control#section_5)
190
+ * [XMLHttpRequest.withCredentials](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials)
191
191
  * for more information.
192
- * - **`responseType`** - `{string}` - see
193
- * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
194
- * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
195
- * `response` and `responseError`. Both `response` and `responseError` interceptors get called
196
- * with `http response` object. See {@link ng.$http $http interceptors}.
197
- *
192
+ * - **`responseType`** `{string}` See
193
+ * [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseType).
194
+ * - **`interceptor`** `{Object=}` The interceptor object has four optional methods -
195
+ * `request`, `requestError`, `response`, and `responseError`. See
196
+ * {@link ng.$http#interceptors $http interceptors} for details. Note that
197
+ * `request`/`requestError` interceptors are applied before calling `$http`, thus before any
198
+ * global `$http` interceptors. Also, rejecting or throwing an error inside the `request`
199
+ * interceptor will result in calling the `responseError` interceptor.
200
+ * The resource instance or collection is available on the `resource` property of the
201
+ * `http response` object passed to `response`/`responseError` interceptors.
202
+ * Keep in mind that the associated promise will be resolved with the value returned by the
203
+ * response interceptors. Make sure you return an appropriate value and not the `response`
204
+ * object passed as input. For reference, the default `response` interceptor (which gets applied
205
+ * if you don't specify a custom one) returns `response.resource`.<br />
206
+ * See {@link ngResource.$resource#using-interceptors below} for an example of using
207
+ * interceptors in `$resource`.
208
+ * - **`hasBody`** – `{boolean}` – If true, then the request will have a body.
209
+ * If not specified, then only POST, PUT and PATCH requests will have a body. *
198
210
  * @param {Object} options Hash with custom settings that should extend the
199
211
  * default `$resourceProvider` behavior. The supported options are:
200
212
  *
@@ -207,27 +219,29 @@ function shallowClearAndCopy(src, dst) {
207
219
  * @returns {Object} A resource "class" object with methods for the default set of resource actions
208
220
  * optionally extended with custom `actions`. The default set contains these actions:
209
221
  * ```js
210
- * { 'get': {method:'GET'},
211
- * 'save': {method:'POST'},
212
- * 'query': {method:'GET', isArray:true},
213
- * 'remove': {method:'DELETE'},
214
- * 'delete': {method:'DELETE'} };
222
+ * {
223
+ * 'get': {method: 'GET'},
224
+ * 'save': {method: 'POST'},
225
+ * 'query': {method: 'GET', isArray: true},
226
+ * 'remove': {method: 'DELETE'},
227
+ * 'delete': {method: 'DELETE'}
228
+ * }
215
229
  * ```
216
230
  *
217
- * Calling these methods invoke an {@link ng.$http} with the specified http method,
218
- * destination and parameters. When the data is returned from the server then the object is an
219
- * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
220
- * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
221
- * read, update, delete) on server-side data like this:
231
+ * Calling these methods invoke {@link ng.$http} with the specified http method, destination and
232
+ * parameters. When the data is returned from the server then the object is an instance of the
233
+ * resource class. The actions `save`, `remove` and `delete` are available on it as methods with
234
+ * the `$` prefix. This allows you to easily perform CRUD operations (create, read, update,
235
+ * delete) on server-side data like this:
222
236
  * ```js
223
- * var User = $resource('/user/:userId', {userId:'@id'});
224
- * var user = User.get({userId:123}, function() {
237
+ * var User = $resource('/user/:userId', {userId: '@id'});
238
+ * User.get({userId: 123}).$promise.then(function(user) {
225
239
  * user.abc = true;
226
240
  * user.$save();
227
241
  * });
228
242
  * ```
229
243
  *
230
- * It is important to realize that invoking a $resource object method immediately returns an
244
+ * It is important to realize that invoking a `$resource` object method immediately returns an
231
245
  * empty reference (object or array depending on `isArray`). Once the data is returned from the
232
246
  * server the existing reference is populated with the actual data. This is a useful trick since
233
247
  * usually the resource is assigned to a model which is then rendered by the view. Having an empty
@@ -238,37 +252,43 @@ function shallowClearAndCopy(src, dst) {
238
252
  * The action methods on the class object or instance object can be invoked with the following
239
253
  * parameters:
240
254
  *
241
- * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
242
- * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
243
- * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
255
+ * - "class" actions without a body: `Resource.action([parameters], [success], [error])`
256
+ * - "class" actions with a body: `Resource.action([parameters], postData, [success], [error])`
257
+ * - instance actions: `instance.$action([parameters], [success], [error])`
258
+ *
259
+ *
260
+ * When calling instance methods, the instance itself is used as the request body (if the action
261
+ * should have a body). By default, only actions using `POST`, `PUT` or `PATCH` have request
262
+ * bodies, but you can use the `hasBody` configuration option to specify whether an action
263
+ * should have a body or not (regardless of its HTTP method).
244
264
  *
245
265
  *
246
- * Success callback is called with (value, responseHeaders) arguments, where the value is
247
- * the populated resource instance or collection object. The error callback is called
248
- * with (httpResponse) argument.
266
+ * Success callback is called with (value (Object|Array), responseHeaders (Function),
267
+ * status (number), statusText (string)) arguments, where `value` is the populated resource
268
+ * instance or collection object. The error callback is called with (httpResponse) argument.
249
269
  *
250
- * Class actions return empty instance (with additional properties below).
251
- * Instance actions return promise of the action.
270
+ * Class actions return an empty instance (with the additional properties listed below).
271
+ * Instance actions return a promise for the operation.
252
272
  *
253
273
  * The Resource instances and collections have these additional properties:
254
274
  *
255
- * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
275
+ * - `$promise`: The {@link ng.$q promise} of the original server interaction that created this
256
276
  * instance or collection.
257
277
  *
258
278
  * On success, the promise is resolved with the same resource instance or collection object,
259
- * updated with data from server. This makes it easy to use in
260
- * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
279
+ * updated with data from server. This makes it easy to use in the
280
+ * {@link ngRoute.$routeProvider `resolve` section of `$routeProvider.when()`} to defer view
261
281
  * rendering until the resource(s) are loaded.
262
282
  *
263
- * On failure, the promise is rejected with the {@link ng.$http http response} object, without
264
- * the `resource` property.
283
+ * On failure, the promise is rejected with the {@link ng.$http http response} object.
265
284
  *
266
285
  * If an interceptor object was provided, the promise will instead be resolved with the value
267
- * returned by the interceptor.
286
+ * returned by the response interceptor (on success) or responceError interceptor (on failure).
268
287
  *
269
288
  * - `$resolved`: `true` after first server interaction is completed (either with success or
270
289
  * rejection), `false` before that. Knowing if the Resource has been resolved is useful in
271
- * data-binding.
290
+ * data-binding. If there is a response/responseError interceptor and it returns a promise,
291
+ * `$resolved` will wait for that too.
272
292
  *
273
293
  * The Resource instances and collections have these additional methods:
274
294
  *
@@ -279,138 +299,145 @@ function shallowClearAndCopy(src, dst) {
279
299
  *
280
300
  * - `toJSON`: It returns a simple object without any of the extra properties added as part of
281
301
  * the Resource API. This object can be serialized through {@link angular.toJson} safely
282
- * without attaching Angular-specific fields. Notice that `JSON.stringify` (and
302
+ * without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and
283
303
  * `angular.toJson`) automatically use this method when serializing a Resource instance
284
- * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior)).
304
+ * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)).
285
305
  *
286
306
  * @example
287
307
  *
288
- * # Credit card resource
308
+ * ### Basic usage
289
309
  *
290
- * ```js
291
- // Define CreditCard class
292
- var CreditCard = $resource('/user/:userId/card/:cardId',
293
- {userId:123, cardId:'@id'}, {
294
- charge: {method:'POST', params:{charge:true}}
295
- });
310
+ ```js
311
+ // Define a CreditCard class
312
+ var CreditCard = $resource('/users/:userId/cards/:cardId',
313
+ {userId: 123, cardId: '@id'}, {
314
+ charge: {method: 'POST', params: {charge: true}}
315
+ });
296
316
 
297
317
  // We can retrieve a collection from the server
298
- var cards = CreditCard.query(function() {
299
- // GET: /user/123/card
300
- // server returns: [ {id:456, number:'1234', name:'Smith'} ];
318
+ var cards = CreditCard.query();
319
+ // GET: /users/123/cards
320
+ // server returns: [{id: 456, number: '1234', name: 'Smith'}]
301
321
 
322
+ // Wait for the request to complete
323
+ cards.$promise.then(function() {
302
324
  var card = cards[0];
303
- // each item is an instance of CreditCard
325
+
326
+ // Each item is an instance of CreditCard
304
327
  expect(card instanceof CreditCard).toEqual(true);
305
- card.name = "J. Smith";
306
- // non GET methods are mapped onto the instances
328
+
329
+ // Non-GET methods are mapped onto the instances
330
+ card.name = 'J. Smith';
307
331
  card.$save();
308
- // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
309
- // server returns: {id:456, number:'1234', name: 'J. Smith'};
332
+ // POST: /users/123/cards/456 {id: 456, number: '1234', name: 'J. Smith'}
333
+ // server returns: {id: 456, number: '1234', name: 'J. Smith'}
310
334
 
311
- // our custom method is mapped as well.
312
- card.$charge({amount:9.99});
313
- // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
335
+ // Our custom method is mapped as well (since it uses POST)
336
+ card.$charge({amount: 9.99});
337
+ // POST: /users/123/cards/456?amount=9.99&charge=true {id: 456, number: '1234', name: 'J. Smith'}
314
338
  });
315
339
 
316
- // we can create an instance as well
317
- var newCard = new CreditCard({number:'0123'});
318
- newCard.name = "Mike Smith";
319
- newCard.$save();
320
- // POST: /user/123/card {number:'0123', name:'Mike Smith'}
321
- // server returns: {id:789, number:'0123', name: 'Mike Smith'};
322
- expect(newCard.id).toEqual(789);
323
- * ```
340
+ // We can create an instance as well
341
+ var newCard = new CreditCard({number: '0123'});
342
+ newCard.name = 'Mike Smith';
343
+
344
+ var savePromise = newCard.$save();
345
+ // POST: /users/123/cards {number: '0123', name: 'Mike Smith'}
346
+ // server returns: {id: 789, number: '0123', name: 'Mike Smith'}
347
+
348
+ savePromise.then(function() {
349
+ // Once the promise is resolved, the created instance
350
+ // is populated with the data returned by the server
351
+ expect(newCard.id).toEqual(789);
352
+ });
353
+ ```
324
354
  *
325
- * The object returned from this function execution is a resource "class" which has "static" method
326
- * for each action in the definition.
355
+ * The object returned from a call to `$resource` is a resource "class" which has one "static"
356
+ * method for each action in the definition.
327
357
  *
328
- * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
329
- * `headers`.
358
+ * Calling these methods invokes `$http` on the `url` template with the given HTTP `method`,
359
+ * `params` and `headers`.
330
360
  *
331
361
  * @example
332
362
  *
333
- * # User resource
363
+ * ### Accessing the response
334
364
  *
335
365
  * When the data is returned from the server then the object is an instance of the resource type and
336
366
  * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
337
367
  * operations (create, read, update, delete) on server-side data.
338
-
368
+ *
339
369
  ```js
340
- var User = $resource('/user/:userId', {userId:'@id'});
341
- User.get({userId:123}, function(user) {
370
+ var User = $resource('/users/:userId', {userId: '@id'});
371
+ User.get({userId: 123}).$promise.then(function(user) {
342
372
  user.abc = true;
343
373
  user.$save();
344
374
  });
345
375
  ```
346
376
  *
347
- * It's worth noting that the success callback for `get`, `query` and other methods gets passed
348
- * in the response that came from the server as well as $http header getter function, so one
349
- * could rewrite the above example and get access to http headers as:
377
+ * It's worth noting that the success callback for `get`, `query` and other methods gets called with
378
+ * the resource instance (populated with the data that came from the server) as well as an `$http`
379
+ * header getter function, the HTTP status code and the response status text. So one could rewrite
380
+ * the above example and get access to HTTP headers as follows:
350
381
  *
351
382
  ```js
352
- var User = $resource('/user/:userId', {userId:'@id'});
353
- User.get({userId:123}, function(user, getResponseHeaders){
383
+ var User = $resource('/users/:userId', {userId: '@id'});
384
+ User.get({userId: 123}, function(user, getResponseHeaders) {
354
385
  user.abc = true;
355
386
  user.$save(function(user, putResponseHeaders) {
356
- //user => saved user object
357
- //putResponseHeaders => $http header getter
387
+ // `user` => saved `User` object
388
+ // `putResponseHeaders` => `$http` header getter
358
389
  });
359
390
  });
360
391
  ```
361
392
  *
362
- * You can also access the raw `$http` promise via the `$promise` property on the object returned
363
- *
364
- ```
365
- var User = $resource('/user/:userId', {userId:'@id'});
366
- User.get({userId:123})
367
- .$promise.then(function(user) {
368
- $scope.user = user;
369
- });
370
- ```
371
- *
372
393
  * @example
373
394
  *
374
- * # Creating a custom 'PUT' request
395
+ * ### Creating custom actions
375
396
  *
376
- * In this example we create a custom method on our resource to make a PUT request
377
- * ```js
378
- * var app = angular.module('app', ['ngResource', 'ngRoute']);
379
- *
380
- * // Some APIs expect a PUT request in the format URL/object/ID
381
- * // Here we are creating an 'update' method
382
- * app.factory('Notes', ['$resource', function($resource) {
383
- * return $resource('/notes/:id', null,
384
- * {
385
- * 'update': { method:'PUT' }
386
- * });
387
- * }]);
388
- *
389
- * // In our controller we get the ID from the URL using ngRoute and $routeParams
390
- * // We pass in $routeParams and our Notes factory along with $scope
391
- * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
392
- function($scope, $routeParams, Notes) {
393
- * // First get a note object from the factory
394
- * var note = Notes.get({ id:$routeParams.id });
395
- * $id = note.id;
396
- *
397
- * // Now call update passing in the ID first then the object you are updating
398
- * Notes.update({ id:$id }, note);
399
- *
400
- * // This will PUT /notes/ID with the note object in the request payload
401
- * }]);
402
- * ```
397
+ * In this example we create a custom method on our resource to make a PUT request:
398
+ *
399
+ ```js
400
+ var app = angular.module('app', ['ngResource']);
401
+
402
+ // Some APIs expect a PUT request in the format URL/object/ID
403
+ // Here we are creating an 'update' method
404
+ app.factory('Notes', ['$resource', function($resource) {
405
+ return $resource('/notes/:id', {id: '@id'}, {
406
+ update: {method: 'PUT'}
407
+ });
408
+ }]);
409
+
410
+ // In our controller we get the ID from the URL using `$location`
411
+ app.controller('NotesCtrl', ['$location', 'Notes', function($location, Notes) {
412
+ // First, retrieve the corresponding `Note` object from the server
413
+ // (Assuming a URL of the form `.../notes?id=XYZ`)
414
+ var noteId = $location.search().id;
415
+ var note = Notes.get({id: noteId});
416
+
417
+ note.$promise.then(function() {
418
+ note.content = 'Hello, world!';
419
+
420
+ // Now call `update` to save the changes on the server
421
+ Notes.update(note);
422
+ // This will PUT /notes/ID with the note object as the request payload
423
+
424
+ // Since `update` is a non-GET method, it will also be available on the instance
425
+ // (prefixed with `$`), so we could replace the `Note.update()` call with:
426
+ //note.$update();
427
+ });
428
+ }]);
429
+ ```
403
430
  *
404
431
  * @example
405
432
  *
406
- * # Cancelling requests
433
+ * ### Cancelling requests
407
434
  *
408
435
  * If an action's configuration specifies that it is cancellable, you can cancel the request related
409
436
  * to an instance or collection (as long as it is a result of a "non-instance" call):
410
437
  *
411
438
  ```js
412
439
  // ...defining the `Hotel` resource...
413
- var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
440
+ var Hotel = $resource('/api/hotels/:id', {id: '@id'}, {
414
441
  // Let's make the `query()` method cancellable
415
442
  query: {method: 'get', isArray: true, cancellable: true}
416
443
  });
@@ -420,18 +447,60 @@ function shallowClearAndCopy(src, dst) {
420
447
  this.onDestinationChanged = function onDestinationChanged(destination) {
421
448
  // We don't care about any pending request for hotels
422
449
  // in a different destination any more
423
- this.availableHotels.$cancelRequest();
450
+ if (this.availableHotels) {
451
+ this.availableHotels.$cancelRequest();
452
+ }
424
453
 
425
- // Let's query for hotels in '<destination>'
426
- // (calls: /api/hotel?location=<destination>)
454
+ // Let's query for hotels in `destination`
455
+ // (calls: /api/hotels?location=<destination>)
427
456
  this.availableHotels = Hotel.query({location: destination});
428
457
  };
429
458
  ```
430
459
  *
460
+ * @example
461
+ *
462
+ * ### Using interceptors
463
+ *
464
+ * You can use interceptors to transform the request or response, perform additional operations, and
465
+ * modify the returned instance/collection. The following example, uses `request` and `response`
466
+ * interceptors to augment the returned instance with additional info:
467
+ *
468
+ ```js
469
+ var Thing = $resource('/api/things/:id', {id: '@id'}, {
470
+ save: {
471
+ method: 'POST',
472
+ interceptor: {
473
+ request: function(config) {
474
+ // Before the request is sent out, store a timestamp on the request config
475
+ config.requestTimestamp = Date.now();
476
+ return config;
477
+ },
478
+ response: function(response) {
479
+ // Get the instance from the response object
480
+ var instance = response.resource;
481
+
482
+ // Augment the instance with a custom `saveLatency` property, computed as the time
483
+ // between sending the request and receiving the response.
484
+ instance.saveLatency = Date.now() - response.config.requestTimestamp;
485
+
486
+ // Return the instance
487
+ return instance;
488
+ }
489
+ }
490
+ }
491
+ });
492
+
493
+ Thing.save({foo: 'bar'}).$promise.then(function(thing) {
494
+ console.log('That thing was saved in ' + thing.saveLatency + 'ms.');
495
+ });
496
+ ```
497
+ *
431
498
  */
432
499
  angular.module('ngResource', ['ng']).
433
- provider('$resource', function() {
434
- var PROTOCOL_AND_DOMAIN_REGEX = /^https?:\/\/[^\/]*/;
500
+ info({ angularVersion: '1.8.0' }).
501
+ provider('$resource', function ResourceProvider() {
502
+ var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
503
+
435
504
  var provider = this;
436
505
 
437
506
  /**
@@ -475,11 +544,11 @@ angular.module('ngResource', ['ng']).
475
544
  * ```js
476
545
  * angular.
477
546
  * module('myApp').
478
- * config(['resourceProvider', function ($resourceProvider) {
547
+ * config(['$resourceProvider', function ($resourceProvider) {
479
548
  * $resourceProvider.defaults.actions.update = {
480
549
  * method: 'PUT'
481
550
  * };
482
- * });
551
+ * }]);
483
552
  * ```
484
553
  *
485
554
  * Or you can even overwrite the whole `actions` list and specify your own:
@@ -487,9 +556,9 @@ angular.module('ngResource', ['ng']).
487
556
  * ```js
488
557
  * angular.
489
558
  * module('myApp').
490
- * config(['resourceProvider', function ($resourceProvider) {
559
+ * config(['$resourceProvider', function ($resourceProvider) {
491
560
  * $resourceProvider.defaults.actions = {
492
- * create: {method: 'POST'}
561
+ * create: {method: 'POST'},
493
562
  * get: {method: 'GET'},
494
563
  * getAll: {method: 'GET', isArray:true},
495
564
  * update: {method: 'PUT'},
@@ -519,49 +588,15 @@ angular.module('ngResource', ['ng']).
519
588
  this.$get = ['$http', '$log', '$q', '$timeout', function($http, $log, $q, $timeout) {
520
589
 
521
590
  var noop = angular.noop,
522
- forEach = angular.forEach,
523
- extend = angular.extend,
524
- copy = angular.copy,
525
- isFunction = angular.isFunction;
526
-
527
- /**
528
- * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
529
- * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set
530
- * (pchar) allowed in path segments:
531
- * segment = *pchar
532
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
533
- * pct-encoded = "%" HEXDIG HEXDIG
534
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
535
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
536
- * / "*" / "+" / "," / ";" / "="
537
- */
538
- function encodeUriSegment(val) {
539
- return encodeUriQuery(val, true).
540
- replace(/%26/gi, '&').
541
- replace(/%3D/gi, '=').
542
- replace(/%2B/gi, '+');
543
- }
544
-
545
-
546
- /**
547
- * This method is intended for encoding *key* or *value* parts of query component. We need a
548
- * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
549
- * have to be encoded per http://tools.ietf.org/html/rfc3986:
550
- * query = *( pchar / "/" / "?" )
551
- * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
552
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
553
- * pct-encoded = "%" HEXDIG HEXDIG
554
- * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
555
- * / "*" / "+" / "," / ";" / "="
556
- */
557
- function encodeUriQuery(val, pctEncodeSpaces) {
558
- return encodeURIComponent(val).
559
- replace(/%40/gi, '@').
560
- replace(/%3A/gi, ':').
561
- replace(/%24/g, '$').
562
- replace(/%2C/gi, ',').
563
- replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
564
- }
591
+ forEach = angular.forEach,
592
+ extend = angular.extend,
593
+ copy = angular.copy,
594
+ isArray = angular.isArray,
595
+ isDefined = angular.isDefined,
596
+ isFunction = angular.isFunction,
597
+ isNumber = angular.isNumber,
598
+ encodeUriQuery = angular.$$encodeUriQuery,
599
+ encodeUriSegment = angular.$$encodeUriSegment;
565
600
 
566
601
  function Route(template, defaults) {
567
602
  this.template = template;
@@ -575,42 +610,42 @@ angular.module('ngResource', ['ng']).
575
610
  url = actionUrl || self.template,
576
611
  val,
577
612
  encodedVal,
578
- protocolAndDomain = '';
613
+ protocolAndIpv6 = '';
579
614
 
580
- var urlParams = self.urlParams = {};
615
+ var urlParams = self.urlParams = Object.create(null);
581
616
  forEach(url.split(/\W/), function(param) {
582
617
  if (param === 'hasOwnProperty') {
583
- throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
618
+ throw $resourceMinErr('badname', 'hasOwnProperty is not a valid parameter name.');
584
619
  }
585
- if (!(new RegExp("^\\d+$").test(param)) && param &&
586
- (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
620
+ if (!(new RegExp('^\\d+$').test(param)) && param &&
621
+ (new RegExp('(^|[^\\\\]):' + param + '(\\W|$)').test(url))) {
587
622
  urlParams[param] = {
588
- isQueryParamValue: (new RegExp("\\?.*=:" + param + "(?:\\W|$)")).test(url)
623
+ isQueryParamValue: (new RegExp('\\?.*=:' + param + '(?:\\W|$)')).test(url)
589
624
  };
590
625
  }
591
626
  });
592
627
  url = url.replace(/\\:/g, ':');
593
- url = url.replace(PROTOCOL_AND_DOMAIN_REGEX, function(match) {
594
- protocolAndDomain = match;
628
+ url = url.replace(PROTOCOL_AND_IPV6_REGEX, function(match) {
629
+ protocolAndIpv6 = match;
595
630
  return '';
596
631
  });
597
632
 
598
633
  params = params || {};
599
634
  forEach(self.urlParams, function(paramInfo, urlParam) {
600
635
  val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
601
- if (angular.isDefined(val) && val !== null) {
636
+ if (isDefined(val) && val !== null) {
602
637
  if (paramInfo.isQueryParamValue) {
603
638
  encodedVal = encodeUriQuery(val, true);
604
639
  } else {
605
640
  encodedVal = encodeUriSegment(val);
606
641
  }
607
- url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), function(match, p1) {
642
+ url = url.replace(new RegExp(':' + urlParam + '(\\W|$)', 'g'), function(match, p1) {
608
643
  return encodedVal + p1;
609
644
  });
610
645
  } else {
611
- url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
646
+ url = url.replace(new RegExp('(/?):' + urlParam + '(\\W|$)', 'g'), function(match,
612
647
  leadingSlashes, tail) {
613
- if (tail.charAt(0) == '/') {
648
+ if (tail.charAt(0) === '/') {
614
649
  return tail;
615
650
  } else {
616
651
  return leadingSlashes + tail;
@@ -624,11 +659,12 @@ angular.module('ngResource', ['ng']).
624
659
  url = url.replace(/\/+$/, '') || '/';
625
660
  }
626
661
 
627
- // then replace collapse `/.` if found in the last URL path segment before the query
628
- // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
662
+ // Collapse `/.` if found in the last URL path segment before the query.
663
+ // E.g. `http://url.com/id/.format?q=x` becomes `http://url.com/id.format?q=x`.
629
664
  url = url.replace(/\/\.(?=\w+($|\?))/, '.');
630
- // replace escaped `/\.` with `/.`
631
- config.url = protocolAndDomain + url.replace(/\/\\\./, '/.');
665
+ // Replace escaped `/\.` with `/.`.
666
+ // (If `\.` comes from a param value, it will be encoded as `%5C.`.)
667
+ config.url = protocolAndIpv6 + url.replace(/\/(\\|%5C)\./, '/.');
632
668
 
633
669
 
634
670
  // set params - delegate param encoding to $http
@@ -652,7 +688,7 @@ angular.module('ngResource', ['ng']).
652
688
  actionParams = extend({}, paramDefaults, actionParams);
653
689
  forEach(actionParams, function(value, key) {
654
690
  if (isFunction(value)) { value = value(data); }
655
- ids[key] = value && value.charAt && value.charAt(0) == '@' ?
691
+ ids[key] = value && value.charAt && value.charAt(0) === '@' ?
656
692
  lookupDottedPath(data, value.substr(1)) : value;
657
693
  });
658
694
  return ids;
@@ -670,17 +706,17 @@ angular.module('ngResource', ['ng']).
670
706
  var data = extend({}, this);
671
707
  delete data.$promise;
672
708
  delete data.$resolved;
709
+ delete data.$cancelRequest;
673
710
  return data;
674
711
  };
675
712
 
676
713
  forEach(actions, function(action, name) {
677
- var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
714
+ var hasBody = action.hasBody === true || (action.hasBody !== false && /^(POST|PUT|PATCH)$/i.test(action.method));
678
715
  var numericTimeout = action.timeout;
679
- var cancellable = angular.isDefined(action.cancellable) ? action.cancellable :
680
- (options && angular.isDefined(options.cancellable)) ? options.cancellable :
681
- provider.defaults.cancellable;
716
+ var cancellable = isDefined(action.cancellable) ?
717
+ action.cancellable : route.defaults.cancellable;
682
718
 
683
- if (numericTimeout && !angular.isNumber(numericTimeout)) {
719
+ if (numericTimeout && !isNumber(numericTimeout)) {
684
720
  $log.debug('ngResource:\n' +
685
721
  ' Only numeric values are allowed as `timeout`.\n' +
686
722
  ' Promises are not supported in $resource, because the same value would ' +
@@ -691,54 +727,61 @@ angular.module('ngResource', ['ng']).
691
727
  }
692
728
 
693
729
  Resource[name] = function(a1, a2, a3, a4) {
694
- var params = {}, data, success, error;
730
+ var params = {}, data, onSuccess, onError;
695
731
 
696
- /* jshint -W086 */ /* (purposefully fall through case statements) */
697
732
  switch (arguments.length) {
698
733
  case 4:
699
- error = a4;
700
- success = a3;
701
- //fallthrough
734
+ onError = a4;
735
+ onSuccess = a3;
736
+ // falls through
702
737
  case 3:
703
738
  case 2:
704
739
  if (isFunction(a2)) {
705
740
  if (isFunction(a1)) {
706
- success = a1;
707
- error = a2;
741
+ onSuccess = a1;
742
+ onError = a2;
708
743
  break;
709
744
  }
710
745
 
711
- success = a2;
712
- error = a3;
713
- //fallthrough
746
+ onSuccess = a2;
747
+ onError = a3;
748
+ // falls through
714
749
  } else {
715
750
  params = a1;
716
751
  data = a2;
717
- success = a3;
752
+ onSuccess = a3;
718
753
  break;
719
754
  }
755
+ // falls through
720
756
  case 1:
721
- if (isFunction(a1)) success = a1;
757
+ if (isFunction(a1)) onSuccess = a1;
722
758
  else if (hasBody) data = a1;
723
759
  else params = a1;
724
760
  break;
725
761
  case 0: break;
726
762
  default:
727
763
  throw $resourceMinErr('badargs',
728
- "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
764
+ 'Expected up to 4 arguments [params, data, success, error], got {0} arguments',
729
765
  arguments.length);
730
766
  }
731
- /* jshint +W086 */ /* (purposefully fall through case statements) */
732
767
 
733
768
  var isInstanceCall = this instanceof Resource;
734
769
  var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
735
770
  var httpConfig = {};
771
+ var requestInterceptor = action.interceptor && action.interceptor.request || undefined;
772
+ var requestErrorInterceptor = action.interceptor && action.interceptor.requestError ||
773
+ undefined;
736
774
  var responseInterceptor = action.interceptor && action.interceptor.response ||
737
775
  defaultResponseInterceptor;
738
776
  var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
739
- undefined;
777
+ $q.reject;
778
+ var successCallback = onSuccess ? function(val) {
779
+ onSuccess(val, response.headers, response.status, response.statusText);
780
+ } : undefined;
781
+ var errorCallback = onError || undefined;
740
782
  var timeoutDeferred;
741
783
  var numericTimeoutPromise;
784
+ var response;
742
785
 
743
786
  forEach(action, function(value, key) {
744
787
  switch (key) {
@@ -767,23 +810,28 @@ angular.module('ngResource', ['ng']).
767
810
  extend({}, extractParams(data, action.params || {}), params),
768
811
  action.url);
769
812
 
770
- var promise = $http(httpConfig).then(function(response) {
771
- var data = response.data;
813
+ // Start the promise chain
814
+ var promise = $q.
815
+ resolve(httpConfig).
816
+ then(requestInterceptor).
817
+ catch(requestErrorInterceptor).
818
+ then($http);
819
+
820
+ promise = promise.then(function(resp) {
821
+ var data = resp.data;
772
822
 
773
823
  if (data) {
774
824
  // Need to convert action.isArray to boolean in case it is undefined
775
- // jshint -W018
776
- if (angular.isArray(data) !== (!!action.isArray)) {
825
+ if (isArray(data) !== (!!action.isArray)) {
777
826
  throw $resourceMinErr('badcfg',
778
827
  'Error in resource configuration for action `{0}`. Expected response to ' +
779
828
  'contain an {1} but got an {2} (Request: {3} {4})', name, action.isArray ? 'array' : 'object',
780
- angular.isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
829
+ isArray(data) ? 'array' : 'object', httpConfig.method, httpConfig.url);
781
830
  }
782
- // jshint +W018
783
831
  if (action.isArray) {
784
832
  value.length = 0;
785
833
  forEach(data, function(item) {
786
- if (typeof item === "object") {
834
+ if (typeof item === 'object') {
787
835
  value.push(new Resource(item));
788
836
  } else {
789
837
  // Valid JSON values may be string literals, and these should not be converted
@@ -798,30 +846,27 @@ angular.module('ngResource', ['ng']).
798
846
  value.$promise = promise; // Restore the promise
799
847
  }
800
848
  }
801
- response.resource = value;
802
849
 
803
- return response;
804
- }, function(response) {
805
- (error || noop)(response);
806
- return $q.reject(response);
850
+ resp.resource = value;
851
+ response = resp;
852
+ return responseInterceptor(resp);
853
+ }, function(rejectionOrResponse) {
854
+ rejectionOrResponse.resource = value;
855
+ response = rejectionOrResponse;
856
+ return responseErrorInterceptor(rejectionOrResponse);
807
857
  });
808
858
 
809
- promise['finally'](function() {
859
+ promise = promise['finally'](function() {
810
860
  value.$resolved = true;
811
861
  if (!isInstanceCall && cancellable) {
812
- value.$cancelRequest = angular.noop;
862
+ value.$cancelRequest = noop;
813
863
  $timeout.cancel(numericTimeoutPromise);
814
864
  timeoutDeferred = numericTimeoutPromise = httpConfig.timeout = null;
815
865
  }
816
866
  });
817
867
 
818
- promise = promise.then(
819
- function(response) {
820
- var value = responseInterceptor(response);
821
- (success || noop)(value, response.headers);
822
- return value;
823
- },
824
- responseErrorInterceptor);
868
+ // Run the `success`/`error` callbacks, but do not let them affect the returned promise.
869
+ promise.then(successCallback, errorCallback);
825
870
 
826
871
  if (!isInstanceCall) {
827
872
  // we are creating instance / collection
@@ -829,13 +874,20 @@ angular.module('ngResource', ['ng']).
829
874
  // - return the instance / collection
830
875
  value.$promise = promise;
831
876
  value.$resolved = false;
832
- if (cancellable) value.$cancelRequest = timeoutDeferred.resolve;
877
+ if (cancellable) value.$cancelRequest = cancelRequest;
833
878
 
834
879
  return value;
835
880
  }
836
881
 
837
882
  // instance call
838
883
  return promise;
884
+
885
+ function cancelRequest(value) {
886
+ promise.catch(noop);
887
+ if (timeoutDeferred !== null) {
888
+ timeoutDeferred.resolve(value);
889
+ }
890
+ }
839
891
  };
840
892
 
841
893
 
@@ -848,10 +900,6 @@ angular.module('ngResource', ['ng']).
848
900
  };
849
901
  });
850
902
 
851
- Resource.bind = function(additionalParamDefaults) {
852
- return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
853
- };
854
-
855
903
  return Resource;
856
904
  }
857
905