angularjs-rails 1.6.8 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.6.8
3
- * (c) 2010-2017 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';
@@ -1229,15 +1229,21 @@ function IDC_Y(cp) {
1229
1229
  * @ngdoc module
1230
1230
  * @name ngParseExt
1231
1231
  * @packageName angular-parse-ext
1232
+ *
1232
1233
  * @description
1233
1234
  *
1234
1235
  * The `ngParseExt` module provides functionality to allow Unicode characters in
1235
- * identifiers inside Angular expressions.
1236
+ * identifiers inside AngularJS expressions.
1236
1237
  *
1237
1238
  * This module allows the usage of any identifier that follows ES6 identifier naming convention
1238
- * 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
1239
1240
  * rules definition to Unicode, this module uses ES6 and Unicode 8.0 identifiers convention.
1240
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>
1241
1247
  */
1242
1248
 
1243
1249
  /* global angularParseExtModule: true,
@@ -1263,7 +1269,7 @@ angular.module('ngParseExt', [])
1263
1269
  .config(['$parseProvider', function($parseProvider) {
1264
1270
  $parseProvider.setIdentifierFns(isValidIdentifierStart, isValidIdentifierContinue);
1265
1271
  }])
1266
- .info({ angularVersion: '1.6.8' });
1272
+ .info({ angularVersion: '1.8.0' });
1267
1273
 
1268
1274
 
1269
1275
  })(window, window.angular);
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.6.8
3
- * (c) 2010-2017 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';
@@ -115,13 +115,13 @@ function shallowClearAndCopy(src, dst) {
115
115
  *
116
116
  * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
117
117
  * `actions` methods. If a parameter value is a function, it will be called every time
118
- * a param value needs to be obtained for a request (unless the param was overridden). The function
119
- * 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.
120
120
  *
121
121
  * Each key value in the parameter object is first bound to url template if present and then any
122
122
  * excess keys are appended to the url search query after the `?`.
123
123
  *
124
- * 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
125
125
  * URL `/path/greet?salutation=Hello`.
126
126
  *
127
127
  * If the parameter value is prefixed with `@`, then the value for that parameter will be
@@ -130,7 +130,7 @@ function shallowClearAndCopy(src, dst) {
130
130
  * For example, if the `defaultParam` object is `{someParam: '@someProp'}` then the value of
131
131
  * `someParam` will be `data.someProp`.
132
132
  * Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action
133
- * method that does not accept a request body)
133
+ * method that does not accept a request body).
134
134
  *
135
135
  * @param {Object.<Object>=} actions Hash with declaration of custom actions that will be available
136
136
  * in addition to the default set of resource actions (see below). If a custom action has the same
@@ -139,9 +139,11 @@ function shallowClearAndCopy(src, dst) {
139
139
  *
140
140
  * The declaration should be created in the format of {@link ng.$http#usage $http.config}:
141
141
  *
142
- * {action1: {method:?, params:?, isArray:?, headers:?, ...},
143
- * action2: {method:?, params:?, isArray:?, headers:?, ...},
144
- * ...}
142
+ * {
143
+ * action1: {method:?, params:?, isArray:?, headers:?, ...},
144
+ * action2: {method:?, params:?, isArray:?, headers:?, ...},
145
+ * ...
146
+ * }
145
147
  *
146
148
  * Where:
147
149
  *
@@ -153,54 +155,58 @@ function shallowClearAndCopy(src, dst) {
153
155
  * the parameter value is a function, it will be called every time when a param value needs to
154
156
  * be obtained for a request (unless the param was overridden). The function will be passed the
155
157
  * current data value as an argument.
156
- * - **`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
157
159
  * like for the resource-level urls.
158
160
  * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
159
161
  * see `returns` section.
160
162
  * - **`transformRequest`** –
161
163
  * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
162
- * 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
163
165
  * request body and headers and returns its transformed (typically serialized) version.
164
166
  * By default, transformRequest will contain one function that checks if the request data is
165
167
  * an object and serializes it using `angular.toJson`. To prevent this behavior, set
166
168
  * `transformRequest` to an empty array: `transformRequest: []`
167
169
  * - **`transformResponse`** –
168
170
  * `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
169
- * transform function or an array of such functions. The transform function takes the http
171
+ * Transform function or an array of such functions. The transform function takes the HTTP
170
172
  * response body, headers and status and returns its transformed (typically deserialized)
171
173
  * version.
172
174
  * By default, transformResponse will contain one function that checks if the response looks
173
175
  * like a JSON string and deserializes it using `angular.fromJson`. To prevent this behavior,
174
176
  * set `transformResponse` to an empty array: `transformResponse: []`
175
- * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
176
- * GET request, otherwise if a cache instance built with
177
- * {@link ng.$cacheFactory $cacheFactory} is supplied, this cache will be used for
178
- * caching.
179
- * - **`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 />
180
181
  * **Note:** In contrast to {@link ng.$http#usage $http.config}, {@link ng.$q promises} are
181
- * **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.
182
183
  * If you are looking for a way to cancel requests, you should use the `cancellable` option.
183
- * - **`cancellable`** – `{boolean}` – if set to true, the request made by a "non-instance" call
184
- * will be cancelled (if not already completed) by calling `$cancelRequest()` on the call's
185
- * return value. Calling `$cancelRequest()` for a non-cancellable or an already
186
- * completed/cancelled request will have no effect.<br />
187
- * - **`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
188
189
  * XHR object. See
189
- * [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)
190
191
  * for more information.
191
- * - **`responseType`** - `{string}` - see
192
- * [requestType](https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType).
193
- * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
194
- * `response` and `responseError`. Both `response` and `responseError` interceptors get called
195
- * with `http response` object. See {@link ng.$http $http interceptors}. In addition, the
196
- * resource instance or array object is accessible by the `resource` property of the
197
- * `http response` object.
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.
198
202
  * Keep in mind that the associated promise will be resolved with the value returned by the
199
- * response interceptor, if one is specified. The default response interceptor returns
200
- * `response.resource` (i.e. the resource instance or array).
201
- * - **`hasBody`** - `{boolean}` - allows to specify if a request body should be included or not.
202
- * If not specified only POST, PUT and PATCH requests will have a body.
203
- *
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. *
204
210
  * @param {Object} options Hash with custom settings that should extend the
205
211
  * default `$resourceProvider` behavior. The supported options are:
206
212
  *
@@ -213,27 +219,29 @@ function shallowClearAndCopy(src, dst) {
213
219
  * @returns {Object} A resource "class" object with methods for the default set of resource actions
214
220
  * optionally extended with custom `actions`. The default set contains these actions:
215
221
  * ```js
216
- * { 'get': {method:'GET'},
217
- * 'save': {method:'POST'},
218
- * 'query': {method:'GET', isArray:true},
219
- * 'remove': {method:'DELETE'},
220
- * '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
+ * }
221
229
  * ```
222
230
  *
223
- * Calling these methods invoke an {@link ng.$http} with the specified http method,
224
- * destination and parameters. When the data is returned from the server then the object is an
225
- * instance of the resource class. The actions `save`, `remove` and `delete` are available on it
226
- * as methods with the `$` prefix. This allows you to easily perform CRUD operations (create,
227
- * 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:
228
236
  * ```js
229
- * var User = $resource('/user/:userId', {userId:'@id'});
230
- * var user = User.get({userId:123}, function() {
237
+ * var User = $resource('/user/:userId', {userId: '@id'});
238
+ * User.get({userId: 123}).$promise.then(function(user) {
231
239
  * user.abc = true;
232
240
  * user.$save();
233
241
  * });
234
242
  * ```
235
243
  *
236
- * 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
237
245
  * empty reference (object or array depending on `isArray`). Once the data is returned from the
238
246
  * server the existing reference is populated with the actual data. This is a useful trick since
239
247
  * usually the resource is assigned to a model which is then rendered by the view. Having an empty
@@ -256,30 +264,31 @@ function shallowClearAndCopy(src, dst) {
256
264
  *
257
265
  *
258
266
  * Success callback is called with (value (Object|Array), responseHeaders (Function),
259
- * status (number), statusText (string)) arguments, where the value is the populated resource
267
+ * status (number), statusText (string)) arguments, where `value` is the populated resource
260
268
  * instance or collection object. The error callback is called with (httpResponse) argument.
261
269
  *
262
- * Class actions return empty instance (with additional properties below).
263
- * 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.
264
272
  *
265
273
  * The Resource instances and collections have these additional properties:
266
274
  *
267
- * - `$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
268
276
  * instance or collection.
269
277
  *
270
278
  * On success, the promise is resolved with the same resource instance or collection object,
271
- * updated with data from server. This makes it easy to use in
272
- * {@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
273
281
  * rendering until the resource(s) are loaded.
274
282
  *
275
283
  * On failure, the promise is rejected with the {@link ng.$http http response} object.
276
284
  *
277
285
  * If an interceptor object was provided, the promise will instead be resolved with the value
278
- * returned by the interceptor.
286
+ * returned by the response interceptor (on success) or responceError interceptor (on failure).
279
287
  *
280
288
  * - `$resolved`: `true` after first server interaction is completed (either with success or
281
289
  * rejection), `false` before that. Knowing if the Resource has been resolved is useful in
282
- * data-binding.
290
+ * data-binding. If there is a response/responseError interceptor and it returns a promise,
291
+ * `$resolved` will wait for that too.
283
292
  *
284
293
  * The Resource instances and collections have these additional methods:
285
294
  *
@@ -290,127 +299,134 @@ function shallowClearAndCopy(src, dst) {
290
299
  *
291
300
  * - `toJSON`: It returns a simple object without any of the extra properties added as part of
292
301
  * the Resource API. This object can be serialized through {@link angular.toJson} safely
293
- * without attaching Angular-specific fields. Notice that `JSON.stringify` (and
302
+ * without attaching AngularJS-specific fields. Notice that `JSON.stringify` (and
294
303
  * `angular.toJson`) automatically use this method when serializing a Resource instance
295
304
  * (see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON%28%29_behavior)).
296
305
  *
297
306
  * @example
298
307
  *
299
- * ### Credit card resource
308
+ * ### Basic usage
300
309
  *
301
- * ```js
302
- // Define CreditCard class
303
- var CreditCard = $resource('/user/:userId/card/:cardId',
304
- {userId:123, cardId:'@id'}, {
305
- charge: {method:'POST', params:{charge:true}}
306
- });
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
+ });
307
316
 
308
317
  // We can retrieve a collection from the server
309
- var cards = CreditCard.query(function() {
310
- // GET: /user/123/card
311
- // 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'}]
312
321
 
322
+ // Wait for the request to complete
323
+ cards.$promise.then(function() {
313
324
  var card = cards[0];
314
- // each item is an instance of CreditCard
325
+
326
+ // Each item is an instance of CreditCard
315
327
  expect(card instanceof CreditCard).toEqual(true);
316
- card.name = "J. Smith";
317
- // non GET methods are mapped onto the instances
328
+
329
+ // Non-GET methods are mapped onto the instances
330
+ card.name = 'J. Smith';
318
331
  card.$save();
319
- // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
320
- // 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'}
321
334
 
322
- // our custom method is mapped as well.
323
- card.$charge({amount:9.99});
324
- // 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'}
325
338
  });
326
339
 
327
- // we can create an instance as well
328
- var newCard = new CreditCard({number:'0123'});
329
- newCard.name = "Mike Smith";
330
- newCard.$save();
331
- // POST: /user/123/card {number:'0123', name:'Mike Smith'}
332
- // server returns: {id:789, number:'0123', name: 'Mike Smith'};
333
- expect(newCard.id).toEqual(789);
334
- * ```
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
+ ```
335
354
  *
336
- * The object returned from this function execution is a resource "class" which has "static" method
337
- * 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.
338
357
  *
339
- * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
340
- * `headers`.
358
+ * Calling these methods invokes `$http` on the `url` template with the given HTTP `method`,
359
+ * `params` and `headers`.
341
360
  *
342
361
  * @example
343
362
  *
344
- * ### User resource
363
+ * ### Accessing the response
345
364
  *
346
365
  * When the data is returned from the server then the object is an instance of the resource type and
347
366
  * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
348
367
  * operations (create, read, update, delete) on server-side data.
349
-
368
+ *
350
369
  ```js
351
- var User = $resource('/user/:userId', {userId:'@id'});
352
- User.get({userId:123}, function(user) {
370
+ var User = $resource('/users/:userId', {userId: '@id'});
371
+ User.get({userId: 123}).$promise.then(function(user) {
353
372
  user.abc = true;
354
373
  user.$save();
355
374
  });
356
375
  ```
357
376
  *
358
- * It's worth noting that the success callback for `get`, `query` and other methods gets passed
359
- * in the response that came from the server as well as $http header getter function, so one
360
- * 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:
361
381
  *
362
382
  ```js
363
- var User = $resource('/user/:userId', {userId:'@id'});
364
- User.get({userId:123}, function(user, getResponseHeaders){
383
+ var User = $resource('/users/:userId', {userId: '@id'});
384
+ User.get({userId: 123}, function(user, getResponseHeaders) {
365
385
  user.abc = true;
366
386
  user.$save(function(user, putResponseHeaders) {
367
- //user => saved user object
368
- //putResponseHeaders => $http header getter
387
+ // `user` => saved `User` object
388
+ // `putResponseHeaders` => `$http` header getter
369
389
  });
370
390
  });
371
391
  ```
372
392
  *
373
- * You can also access the raw `$http` promise via the `$promise` property on the object returned
374
- *
375
- ```
376
- var User = $resource('/user/:userId', {userId:'@id'});
377
- User.get({userId:123})
378
- .$promise.then(function(user) {
379
- $scope.user = user;
380
- });
381
- ```
382
- *
383
393
  * @example
384
394
  *
385
- * ### Creating a custom 'PUT' request
395
+ * ### Creating custom actions
386
396
  *
387
- * In this example we create a custom method on our resource to make a PUT request
388
- * ```js
389
- * var app = angular.module('app', ['ngResource', 'ngRoute']);
390
- *
391
- * // Some APIs expect a PUT request in the format URL/object/ID
392
- * // Here we are creating an 'update' method
393
- * app.factory('Notes', ['$resource', function($resource) {
394
- * return $resource('/notes/:id', null,
395
- * {
396
- * 'update': { method:'PUT' }
397
- * });
398
- * }]);
399
- *
400
- * // In our controller we get the ID from the URL using ngRoute and $routeParams
401
- * // We pass in $routeParams and our Notes factory along with $scope
402
- * app.controller('NotesCtrl', ['$scope', '$routeParams', 'Notes',
403
- function($scope, $routeParams, Notes) {
404
- * // First get a note object from the factory
405
- * var note = Notes.get({ id:$routeParams.id });
406
- * $id = note.id;
407
- *
408
- * // Now call update passing in the ID first then the object you are updating
409
- * Notes.update({ id:$id }, note);
410
- *
411
- * // This will PUT /notes/ID with the note object in the request payload
412
- * }]);
413
- * ```
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
+ ```
414
430
  *
415
431
  * @example
416
432
  *
@@ -421,7 +437,7 @@ function shallowClearAndCopy(src, dst) {
421
437
  *
422
438
  ```js
423
439
  // ...defining the `Hotel` resource...
424
- var Hotel = $resource('/api/hotel/:id', {id: '@id'}, {
440
+ var Hotel = $resource('/api/hotels/:id', {id: '@id'}, {
425
441
  // Let's make the `query()` method cancellable
426
442
  query: {method: 'get', isArray: true, cancellable: true}
427
443
  });
@@ -431,17 +447,57 @@ function shallowClearAndCopy(src, dst) {
431
447
  this.onDestinationChanged = function onDestinationChanged(destination) {
432
448
  // We don't care about any pending request for hotels
433
449
  // in a different destination any more
434
- this.availableHotels.$cancelRequest();
450
+ if (this.availableHotels) {
451
+ this.availableHotels.$cancelRequest();
452
+ }
435
453
 
436
- // Let's query for hotels in '<destination>'
437
- // (calls: /api/hotel?location=<destination>)
454
+ // Let's query for hotels in `destination`
455
+ // (calls: /api/hotels?location=<destination>)
438
456
  this.availableHotels = Hotel.query({location: destination});
439
457
  };
440
458
  ```
441
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
+ *
442
498
  */
443
499
  angular.module('ngResource', ['ng']).
444
- info({ angularVersion: '1.6.8' }).
500
+ info({ angularVersion: '1.8.0' }).
445
501
  provider('$resource', function ResourceProvider() {
446
502
  var PROTOCOL_AND_IPV6_REGEX = /^https?:\/\/\[[^\]]*][^/]*/;
447
503
 
@@ -671,34 +727,34 @@ angular.module('ngResource', ['ng']).
671
727
  }
672
728
 
673
729
  Resource[name] = function(a1, a2, a3, a4) {
674
- var params = {}, data, success, error;
730
+ var params = {}, data, onSuccess, onError;
675
731
 
676
732
  switch (arguments.length) {
677
733
  case 4:
678
- error = a4;
679
- success = a3;
734
+ onError = a4;
735
+ onSuccess = a3;
680
736
  // falls through
681
737
  case 3:
682
738
  case 2:
683
739
  if (isFunction(a2)) {
684
740
  if (isFunction(a1)) {
685
- success = a1;
686
- error = a2;
741
+ onSuccess = a1;
742
+ onError = a2;
687
743
  break;
688
744
  }
689
745
 
690
- success = a2;
691
- error = a3;
746
+ onSuccess = a2;
747
+ onError = a3;
692
748
  // falls through
693
749
  } else {
694
750
  params = a1;
695
751
  data = a2;
696
- success = a3;
752
+ onSuccess = a3;
697
753
  break;
698
754
  }
699
755
  // falls through
700
756
  case 1:
701
- if (isFunction(a1)) success = a1;
757
+ if (isFunction(a1)) onSuccess = a1;
702
758
  else if (hasBody) data = a1;
703
759
  else params = a1;
704
760
  break;
@@ -712,14 +768,20 @@ angular.module('ngResource', ['ng']).
712
768
  var isInstanceCall = this instanceof Resource;
713
769
  var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
714
770
  var httpConfig = {};
771
+ var requestInterceptor = action.interceptor && action.interceptor.request || undefined;
772
+ var requestErrorInterceptor = action.interceptor && action.interceptor.requestError ||
773
+ undefined;
715
774
  var responseInterceptor = action.interceptor && action.interceptor.response ||
716
775
  defaultResponseInterceptor;
717
776
  var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
718
- undefined;
719
- var hasError = !!error;
720
- var hasResponseErrorInterceptor = !!responseErrorInterceptor;
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;
721
782
  var timeoutDeferred;
722
783
  var numericTimeoutPromise;
784
+ var response;
723
785
 
724
786
  forEach(action, function(value, key) {
725
787
  switch (key) {
@@ -748,8 +810,15 @@ angular.module('ngResource', ['ng']).
748
810
  extend({}, extractParams(data, action.params || {}), params),
749
811
  action.url);
750
812
 
751
- var promise = $http(httpConfig).then(function(response) {
752
- 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;
753
822
 
754
823
  if (data) {
755
824
  // Need to convert action.isArray to boolean in case it is undefined
@@ -777,12 +846,14 @@ angular.module('ngResource', ['ng']).
777
846
  value.$promise = promise; // Restore the promise
778
847
  }
779
848
  }
780
- response.resource = value;
781
849
 
782
- return response;
783
- }, function(response) {
784
- response.resource = value;
785
- 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);
786
857
  });
787
858
 
788
859
  promise = promise['finally'](function() {
@@ -794,25 +865,8 @@ angular.module('ngResource', ['ng']).
794
865
  }
795
866
  });
796
867
 
797
- promise = promise.then(
798
- function(response) {
799
- var value = responseInterceptor(response);
800
- (success || noop)(value, response.headers, response.status, response.statusText);
801
- return value;
802
- },
803
- (hasError || hasResponseErrorInterceptor) ?
804
- function(response) {
805
- if (hasError && !hasResponseErrorInterceptor) {
806
- // Avoid `Possibly Unhandled Rejection` error,
807
- // but still fulfill the returned promise with a rejection
808
- promise.catch(noop);
809
- }
810
- if (hasError) error(response);
811
- return hasResponseErrorInterceptor ?
812
- responseErrorInterceptor(response) :
813
- $q.reject(response);
814
- } :
815
- undefined);
868
+ // Run the `success`/`error` callbacks, but do not let them affect the returned promise.
869
+ promise.then(successCallback, errorCallback);
816
870
 
817
871
  if (!isInstanceCall) {
818
872
  // we are creating instance / collection