angularjs-rails 1.5.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.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