angular-gem 1.1.5 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/lib/angular-gem/version.rb +1 -1
  2. data/lib/tasks/copy.rake +22 -11
  3. data/lib/tasks/tag.rake +2 -11
  4. data/vendor/assets/javascripts/1.2.0/angular-animate.js +1226 -0
  5. data/vendor/assets/javascripts/1.2.0/angular-animate.min.js +21 -0
  6. data/vendor/assets/javascripts/1.2.0/angular-animate.min.js.map +8 -0
  7. data/vendor/assets/javascripts/{angular-cookies-unstable.js → 1.2.0/angular-cookies.js} +21 -4
  8. data/vendor/assets/javascripts/1.2.0/angular-cookies.min.js +8 -0
  9. data/vendor/assets/javascripts/1.2.0/angular-cookies.min.js.map +8 -0
  10. data/vendor/assets/javascripts/1.2.0/angular-csp.css +24 -0
  11. data/vendor/assets/javascripts/{angular-loader-unstable.js → 1.2.0/angular-loader.js} +48 -29
  12. data/vendor/assets/javascripts/1.2.0/angular-loader.min.js +8 -0
  13. data/vendor/assets/javascripts/1.2.0/angular-loader.min.js.map +8 -0
  14. data/vendor/assets/javascripts/{angular-mocks-unstable.js → 1.2.0/angular-mocks.js} +460 -216
  15. data/vendor/assets/javascripts/{angular-resource-unstable.js → 1.2.0/angular-resource.js} +189 -148
  16. data/vendor/assets/javascripts/1.2.0/angular-resource.min.js +12 -0
  17. data/vendor/assets/javascripts/1.2.0/angular-resource.min.js.map +8 -0
  18. data/vendor/assets/javascripts/1.2.0/angular-route.js +880 -0
  19. data/vendor/assets/javascripts/1.2.0/angular-route.min.js +14 -0
  20. data/vendor/assets/javascripts/1.2.0/angular-route.min.js.map +8 -0
  21. data/vendor/assets/javascripts/{angular-sanitize-unstable.js → 1.2.0/angular-sanitize.js} +142 -123
  22. data/vendor/assets/javascripts/1.2.0/angular-sanitize.min.js +14 -0
  23. data/vendor/assets/javascripts/1.2.0/angular-sanitize.min.js.map +8 -0
  24. data/vendor/assets/javascripts/{angular-scenario-unstable.js → 1.2.0/angular-scenario.js} +15978 -12405
  25. data/vendor/assets/javascripts/{angular-mobile-unstable.js → 1.2.0/angular-touch.js} +214 -111
  26. data/vendor/assets/javascripts/1.2.0/angular-touch.min.js +13 -0
  27. data/vendor/assets/javascripts/1.2.0/angular-touch.min.js.map +8 -0
  28. data/vendor/assets/javascripts/{angular-unstable.js → 1.2.0/angular.js} +10167 -7012
  29. data/vendor/assets/javascripts/1.2.0/angular.min.js +200 -0
  30. data/vendor/assets/javascripts/1.2.0/angular.min.js.map +8 -0
  31. data/vendor/assets/javascripts/1.2.0/errors.json +1 -0
  32. data/vendor/assets/javascripts/1.2.0/version.json +1 -0
  33. data/vendor/assets/javascripts/1.2.0/version.txt +1 -0
  34. data/vendor/assets/javascripts/angular-animate.js +1226 -0
  35. data/vendor/assets/javascripts/angular-animate.min.js +21 -0
  36. data/vendor/assets/javascripts/angular-cookies.js +21 -4
  37. data/vendor/assets/javascripts/angular-cookies.min.js +8 -0
  38. data/vendor/assets/javascripts/angular-loader.js +63 -17
  39. data/vendor/assets/javascripts/angular-loader.min.js +8 -0
  40. data/vendor/assets/javascripts/angular-mocks.js +553 -211
  41. data/vendor/assets/javascripts/angular-resource.js +268 -147
  42. data/vendor/assets/javascripts/angular-resource.min.js +12 -0
  43. data/vendor/assets/javascripts/angular-route.js +880 -0
  44. data/vendor/assets/javascripts/angular-route.min.js +14 -0
  45. data/vendor/assets/javascripts/angular-sanitize.js +165 -125
  46. data/vendor/assets/javascripts/angular-sanitize.min.js +14 -0
  47. data/vendor/assets/javascripts/angular-scenario.js +16615 -10889
  48. data/vendor/assets/javascripts/angular-touch.js +563 -0
  49. data/vendor/assets/javascripts/angular-touch.min.js +13 -0
  50. data/vendor/assets/javascripts/angular.js +9717 -4533
  51. data/vendor/assets/javascripts/angular.min.js +200 -0
  52. metadata +44 -21
  53. data/test/dummy/log/test.log +0 -2
  54. data/test/dummy/tmp/cache/assets/D65/250/sprockets%2F54a960d46bb0b354e8bd46fa03f5e0e4 +0 -0
  55. data/test/dummy/tmp/cache/assets/D6A/FB0/sprockets%2F92721e9941b77adcfdfba3d060622de2 +0 -0
  56. data/test/dummy/tmp/cache/assets/E07/040/sprockets%2Ff55b8ce9d0f28ce36b768a1c7aeb2ef3 +0 -0
  57. data/test/tmp/app/assets/javascripts/application.js +0 -5
@@ -1,15 +1,27 @@
1
1
  /**
2
- * @license AngularJS v1.0.7
2
+ * @license AngularJS v1.2.0
3
3
  * (c) 2010-2012 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
- (function(window, angular, undefined) {
7
- 'use strict';
6
+ (function(window, angular, undefined) {'use strict';
7
+
8
+ var $resourceMinErr = angular.$$minErr('$resource');
8
9
 
9
10
  /**
10
11
  * @ngdoc overview
11
12
  * @name ngResource
12
13
  * @description
14
+ *
15
+ * # ngResource
16
+ *
17
+ * The `ngResource` module provides interaction support with RESTful services
18
+ * via the $resource service.
19
+ *
20
+ * {@installModule resource}
21
+ *
22
+ * <div doc-module-components="ngResource"></div>
23
+ *
24
+ * See {@link ngResource.$resource `$resource`} for usage.
13
25
  */
14
26
 
15
27
  /**
@@ -24,24 +36,22 @@
24
36
  * The returned resource object has action methods which provide high-level behaviors without
25
37
  * the need to interact with the low level {@link ng.$http $http} service.
26
38
  *
27
- * # Installation
28
- * To use $resource make sure you have included the `angular-resource.js` that comes in Angular
29
- * package. You can also find this file on Google CDN, bower as well as at
30
- * {@link http://code.angularjs.org/ code.angularjs.org}.
31
- *
32
- * Finally load the module in your application:
39
+ * Requires the {@link ngResource `ngResource`} module to be installed.
33
40
  *
34
- * angular.module('app', ['ngResource']);
41
+ * @param {string} url A parametrized URL template with parameters prefixed by `:` as in
42
+ * `/user/:username`. If you are using a URL with a port number (e.g.
43
+ * `http://example.com:8080/api`), it will be respected.
35
44
  *
36
- * and you are ready to get started!
37
- *
38
- * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
39
- * `/user/:username`. If you are using a URL with a port number (e.g.
40
- * `http://example.com:8080/api`), you'll need to escape the colon character before the port
41
- * number, like this: `$resource('http://example.com\\:8080/api')`.
45
+ * If you are using a url with a suffix, just add the suffix, like this:
46
+ * `$resource('http://example.com/resource.json')` or `$resource('http://example.com/:id.json')`
47
+ * or even `$resource('http://example.com/resource/:resource_id.:format')`
48
+ * If the parameter before the suffix is empty, :resource_id in this case, then the `/.` will be
49
+ * collapsed down to a single `.`. If you need this sequence to appear and not collapse then you
50
+ * can escape it with `/\.`.
42
51
  *
43
52
  * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
44
- * `actions` methods.
53
+ * `actions` methods. If any of the parameter value is a function, it will be executed every time
54
+ * when a param value needs to be obtained for a request (unless the param was overridden).
45
55
  *
46
56
  * Each key value in the parameter object is first bound to url template if present and then any
47
57
  * excess keys are appended to the url search query after the `?`.
@@ -53,21 +63,48 @@
53
63
  * the data object (useful for non-GET operations).
54
64
  *
55
65
  * @param {Object.<Object>=} actions Hash with declaration of custom action that should extend the
56
- * default set of resource actions. The declaration should be created in the following format:
66
+ * default set of resource actions. The declaration should be created in the format of {@link
67
+ * ng.$http#usage_parameters $http.config}:
57
68
  *
58
- * {action1: {method:?, params:?, isArray:?},
59
- * action2: {method:?, params:?, isArray:?},
69
+ * {action1: {method:?, params:?, isArray:?, headers:?, ...},
70
+ * action2: {method:?, params:?, isArray:?, headers:?, ...},
60
71
  * ...}
61
72
  *
62
73
  * Where:
63
74
  *
64
- * - `action` – {string} – The name of action. This name becomes the name of the method on your
65
- * resource object.
66
- * - `method` – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, `DELETE`,
67
- * and `JSONP`
68
- * - `params` – {object=} – Optional set of pre-bound parameters for this action.
69
- * - isArray {boolean=} If true then the returned object for this action is an array, see
70
- * `returns` section.
75
+ * - **`action`** – {string} – The name of action. This name becomes the name of the method on
76
+ * your resource object.
77
+ * - **`method`** – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`,
78
+ * `DELETE`, and `JSONP`.
79
+ * - **`params`** – {Object=} – Optional set of pre-bound parameters for this action. If any of
80
+ * the parameter value is a function, it will be executed every time when a param value needs to
81
+ * be obtained for a request (unless the param was overridden).
82
+ * - **`url`** – {string} – action specific `url` override. The url templating is supported just
83
+ * like for the resource-level urls.
84
+ * - **`isArray`** – {boolean=} – If true then the returned object for this action is an array,
85
+ * see `returns` section.
86
+ * - **`transformRequest`** –
87
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
88
+ * transform function or an array of such functions. The transform function takes the http
89
+ * request body and headers and returns its transformed (typically serialized) version.
90
+ * - **`transformResponse`** –
91
+ * `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
92
+ * transform function or an array of such functions. The transform function takes the http
93
+ * response body and headers and returns its transformed (typically deserialized) version.
94
+ * - **`cache`** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
95
+ * GET request, otherwise if a cache instance built with
96
+ * {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
97
+ * caching.
98
+ * - **`timeout`** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise} that
99
+ * should abort the request when resolved.
100
+ * - **`withCredentials`** - `{boolean}` - whether to set the `withCredentials` flag on the
101
+ * XHR object. See {@link https://developer.mozilla.org/en/http_access_control#section_5
102
+ * requests with credentials} for more information.
103
+ * - **`responseType`** - `{string}` - see {@link
104
+ * https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest#responseType requestType}.
105
+ * - **`interceptor`** - `{Object=}` - The interceptor object has two optional methods -
106
+ * `response` and `responseError`. Both `response` and `responseError` interceptors get called
107
+ * with `http response` object. See {@link ng.$http $http interceptors}.
71
108
  *
72
109
  * @returns {Object} A resource "class" object with methods for the default set of resource actions
73
110
  * optionally extended with custom `actions`. The default set contains these actions:
@@ -106,6 +143,28 @@
106
143
  * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
107
144
  * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
108
145
  *
146
+ * Success callback is called with (value, responseHeaders) arguments. Error callback is called
147
+ * with (httpResponse) argument.
148
+ *
149
+ * Class actions return empty instance (with additional properties below).
150
+ * Instance actions return promise of the action.
151
+ *
152
+ * The Resource instances and collection have these additional properties:
153
+ *
154
+ * - `$promise`: the {@link ng.$q promise} of the original server interaction that created this
155
+ * instance or collection.
156
+ *
157
+ * On success, the promise is resolved with the same resource instance or collection object,
158
+ * updated with data from server. This makes it easy to use in
159
+ * {@link ngRoute.$routeProvider resolve section of $routeProvider.when()} to defer view
160
+ * rendering until the resource(s) are loaded.
161
+ *
162
+ * On failure, the promise is resolved with the {@link ng.$http http response} object, without
163
+ * the `resource` property.
164
+ *
165
+ * - `$resolved`: `true` after first server interaction is completed (either with success or
166
+ * rejection), `false` before that. Knowing if the Resource has been resolved is useful in
167
+ * data-binding.
109
168
  *
110
169
  * @example
111
170
  *
@@ -149,7 +208,8 @@
149
208
  * The object returned from this function execution is a resource "class" which has "static" method
150
209
  * for each action in the definition.
151
210
  *
152
- * Calling these methods invoke `$http` on the `url` template with the given `method` and `params`.
211
+ * Calling these methods invoke `$http` on the `url` template with the given `method`, `params` and
212
+ * `headers`.
153
213
  * When the data is returned from the server then the object is an instance of the resource type and
154
214
  * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
155
215
  * operations (create, read, update, delete) on server-side data.
@@ -162,7 +222,7 @@
162
222
  });
163
223
  </pre>
164
224
  *
165
- * It's worth noting that the success callback for `get`, `query` and other method gets passed
225
+ * It's worth noting that the success callback for `get`, `query` and other methods gets passed
166
226
  * in the response that came from the server as well as $http header getter function, so one
167
227
  * could rewrite the above example and get access to http headers as:
168
228
  *
@@ -181,52 +241,56 @@
181
241
 
182
242
  Let's look at what a buzz client created with the `$resource` service looks like:
183
243
  <doc:example>
184
- <doc:source jsfiddle="false">
185
- <script>
186
- function BuzzController($resource) {
187
- this.userId = 'googlebuzz';
188
- this.Activity = $resource(
189
- 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
190
- {alt:'json', callback:'JSON_CALLBACK'},
191
- {get:{method:'JSONP', params:{visibility:'@self'}}, replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}}}
192
- );
244
+ <doc:source jsfiddle="false">
245
+ <script>
246
+ function BuzzController($resource) {
247
+ this.userId = 'googlebuzz';
248
+ this.Activity = $resource(
249
+ 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
250
+ {alt:'json', callback:'JSON_CALLBACK'},
251
+ {
252
+ get:{method:'JSONP', params:{visibility:'@self'}},
253
+ replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}}
193
254
  }
194
-
195
- BuzzController.prototype = {
196
- fetch: function() {
197
- this.activities = this.Activity.get({userId:this.userId});
198
- },
199
- expandReplies: function(activity) {
200
- activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id});
201
- }
202
- };
203
- BuzzController.$inject = ['$resource'];
204
- </script>
205
-
206
- <div ng-controller="BuzzController">
207
- <input ng-model="userId"/>
208
- <button ng-click="fetch()">fetch</button>
209
- <hr/>
210
- <div ng-repeat="item in activities.data.items">
211
- <h1 style="font-size: 15px;">
212
- <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
213
- <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
214
- <a href ng-click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
215
- </h1>
216
- {{item.object.content | html}}
217
- <div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
218
- <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
219
- <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}}
220
- </div>
221
- </div>
255
+ );
256
+ }
257
+
258
+ BuzzController.prototype = {
259
+ fetch: function() {
260
+ this.activities = this.Activity.get({userId:this.userId});
261
+ },
262
+ expandReplies: function(activity) {
263
+ activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id});
264
+ }
265
+ };
266
+ BuzzController.$inject = ['$resource'];
267
+ </script>
268
+
269
+ <div ng-controller="BuzzController">
270
+ <input ng-model="userId"/>
271
+ <button ng-click="fetch()">fetch</button>
272
+ <hr/>
273
+ <div ng-repeat="item in activities.data.items">
274
+ <h1 style="font-size: 15px;">
275
+ <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
276
+ <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
277
+ <a href ng-click="expandReplies(item)" style="float: right;">Expand replies:
278
+ {{item.links.replies[0].count}}</a>
279
+ </h1>
280
+ {{item.object.content | html}}
281
+ <div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
282
+ <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
283
+ <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}}
222
284
  </div>
223
- </doc:source>
224
- <doc:scenario>
225
- </doc:scenario>
285
+ </div>
286
+ </div>
287
+ </doc:source>
288
+ <doc:scenario>
289
+ </doc:scenario>
226
290
  </doc:example>
227
291
  */
228
292
  angular.module('ngResource', ['ng']).
229
- factory('$resource', ['$http', '$parse', function($http, $parse) {
293
+ factory('$resource', ['$http', '$parse', '$q', function($http, $parse, $q) {
230
294
  var DEFAULT_ACTIONS = {
231
295
  'get': {method:'GET'},
232
296
  'save': {method:'POST'},
@@ -263,9 +327,9 @@ angular.module('ngResource', ['ng']).
263
327
 
264
328
 
265
329
  /**
266
- * This method is intended for encoding *key* or *value* parts of query component. We need a custom
267
- * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
268
- * encoded per http://tools.ietf.org/html/rfc3986:
330
+ * This method is intended for encoding *key* or *value* parts of query component. We need a
331
+ * custom method because encodeURIComponent is too aggressive and encodes stuff that doesn't
332
+ * have to be encoded per http://tools.ietf.org/html/rfc3986:
269
333
  * query = *( pchar / "/" / "?" )
270
334
  * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
271
335
  * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
@@ -283,32 +347,38 @@ angular.module('ngResource', ['ng']).
283
347
  }
284
348
 
285
349
  function Route(template, defaults) {
286
- this.template = template = template + '#';
350
+ this.template = template;
287
351
  this.defaults = defaults || {};
288
- var urlParams = this.urlParams = {};
289
- forEach(template.split(/\W/), function(param){
290
- if (param && (new RegExp("(^|[^\\\\]):" + param + "\\W").test(template))) {
291
- urlParams[param] = true;
292
- }
293
- });
294
- this.template = template.replace(/\\:/g, ':');
352
+ this.urlParams = {};
295
353
  }
296
354
 
297
355
  Route.prototype = {
298
- url: function(params) {
356
+ setUrlParams: function(config, params, actionUrl) {
299
357
  var self = this,
300
- url = this.template,
358
+ url = actionUrl || self.template,
301
359
  val,
302
360
  encodedVal;
303
361
 
362
+ var urlParams = self.urlParams = {};
363
+ forEach(url.split(/\W/), function(param){
364
+ if (param === 'hasOwnProperty') {
365
+ throw $resourceMinErr('badname', "hasOwnProperty is not a valid parameter name.");
366
+ }
367
+ if (!(new RegExp("^\\d+$").test(param)) && param &&
368
+ (new RegExp("(^|[^\\\\]):" + param + "(\\W|$)").test(url))) {
369
+ urlParams[param] = true;
370
+ }
371
+ });
372
+ url = url.replace(/\\:/g, ':');
373
+
304
374
  params = params || {};
305
- forEach(this.urlParams, function(_, urlParam){
375
+ forEach(self.urlParams, function(_, urlParam){
306
376
  val = params.hasOwnProperty(urlParam) ? params[urlParam] : self.defaults[urlParam];
307
377
  if (angular.isDefined(val) && val !== null) {
308
378
  encodedVal = encodeUriSegment(val);
309
- url = url.replace(new RegExp(":" + urlParam + "(\\W)", "g"), encodedVal + "$1");
379
+ url = url.replace(new RegExp(":" + urlParam + "(\\W|$)", "g"), encodedVal + "$1");
310
380
  } else {
311
- url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W)", "g"), function(match,
381
+ url = url.replace(new RegExp("(\/?):" + urlParam + "(\\W|$)", "g"), function(match,
312
382
  leadingSlashes, tail) {
313
383
  if (tail.charAt(0) == '/') {
314
384
  return tail;
@@ -318,21 +388,28 @@ angular.module('ngResource', ['ng']).
318
388
  });
319
389
  }
320
390
  });
321
- url = url.replace(/\/?#$/, '');
322
- var query = [];
391
+
392
+ // strip trailing slashes and set the url
393
+ url = url.replace(/\/+$/, '');
394
+ // then replace collapse `/.` if found in the last URL path segment before the query
395
+ // E.g. `http://url.com/id./format?q=x` becomes `http://url.com/id.format?q=x`
396
+ url = url.replace(/\/\.(?=\w+($|\?))/, '.');
397
+ // replace escaped `/\.` with `/.`
398
+ config.url = url.replace(/\/\\\./, '/.');
399
+
400
+
401
+ // set params - delegate param encoding to $http
323
402
  forEach(params, function(value, key){
324
403
  if (!self.urlParams[key]) {
325
- query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value));
404
+ config.params = config.params || {};
405
+ config.params[key] = value;
326
406
  }
327
407
  });
328
- query.sort();
329
- url = url.replace(/\/*$/, '');
330
- return url + (query.length ? '?' + query.join('&') : '');
331
408
  }
332
409
  };
333
410
 
334
411
 
335
- function ResourceFactory(url, paramDefaults, actions) {
412
+ function resourceFactory(url, paramDefaults, actions) {
336
413
  var route = new Route(url);
337
414
 
338
415
  actions = extend({}, DEFAULT_ACTIONS, actions);
@@ -341,23 +418,28 @@ angular.module('ngResource', ['ng']).
341
418
  var ids = {};
342
419
  actionParams = extend({}, paramDefaults, actionParams);
343
420
  forEach(actionParams, function(value, key){
344
- ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
421
+ if (isFunction(value)) { value = value(); }
422
+ ids[key] = value && value.charAt && value.charAt(0) == '@' ?
423
+ getter(data, value.substr(1)) : value;
345
424
  });
346
425
  return ids;
347
426
  }
348
427
 
428
+ function defaultResponseInterceptor(response) {
429
+ return response.resource;
430
+ }
431
+
349
432
  function Resource(value){
350
433
  copy(value || {}, this);
351
434
  }
352
435
 
353
436
  forEach(actions, function(action, name) {
354
- action.method = angular.uppercase(action.method);
355
- var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
437
+ var hasBody = /^(POST|PUT|PATCH)$/i.test(action.method);
438
+
356
439
  Resource[name] = function(a1, a2, a3, a4) {
357
- var params = {};
358
- var data;
359
- var success = noop;
360
- var error = null;
440
+ var params = {}, data, success, error;
441
+
442
+ /* jshint -W086 */ /* (purposefully fall through case statements) */
361
443
  switch(arguments.length) {
362
444
  case 4:
363
445
  error = a4;
@@ -388,69 +470,108 @@ angular.module('ngResource', ['ng']).
388
470
  break;
389
471
  case 0: break;
390
472
  default:
391
- throw "Expected between 0-4 arguments [params, data, success, error], got " +
392
- arguments.length + " arguments.";
473
+ throw $resourceMinErr('badargs',
474
+ "Expected up to 4 arguments [params, data, success, error], got {0} arguments",
475
+ arguments.length);
393
476
  }
394
-
395
- var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
396
- $http({
397
- method: action.method,
398
- url: route.url(extend({}, extractParams(data, action.params || {}), params)),
399
- data: data
400
- }).then(function(response) {
401
- var data = response.data;
402
-
403
- if (data) {
404
- if (action.isArray) {
405
- value.length = 0;
406
- forEach(data, function(item) {
407
- value.push(new Resource(item));
408
- });
409
- } else {
410
- copy(data, value);
411
- }
477
+ /* jshint +W086 */ /* (purposefully fall through case statements) */
478
+
479
+ var isInstanceCall = data instanceof Resource;
480
+ var value = isInstanceCall ? data : (action.isArray ? [] : new Resource(data));
481
+ var httpConfig = {};
482
+ var responseInterceptor = action.interceptor && action.interceptor.response ||
483
+ defaultResponseInterceptor;
484
+ var responseErrorInterceptor = action.interceptor && action.interceptor.responseError ||
485
+ undefined;
486
+
487
+ forEach(action, function(value, key) {
488
+ if (key != 'params' && key != 'isArray' && key != 'interceptor') {
489
+ httpConfig[key] = copy(value);
490
+ }
491
+ });
492
+
493
+ if (hasBody) httpConfig.data = data;
494
+ route.setUrlParams(httpConfig,
495
+ extend({}, extractParams(data, action.params || {}), params),
496
+ action.url);
497
+
498
+ var promise = $http(httpConfig).then(function(response) {
499
+ var data = response.data,
500
+ promise = value.$promise;
501
+
502
+ if (data) {
503
+ // Need to convert action.isArray to boolean in case it is undefined
504
+ // jshint -W018
505
+ if ( angular.isArray(data) !== (!!action.isArray) ) {
506
+ throw $resourceMinErr('badcfg', 'Error in resource configuration. Expected ' +
507
+ 'response to contain an {0} but got an {1}',
508
+ action.isArray?'array':'object', angular.isArray(data)?'array':'object');
412
509
  }
413
- (success||noop)(value, response.headers);
414
- }, error);
510
+ // jshint +W018
511
+ if (action.isArray) {
512
+ value.length = 0;
513
+ forEach(data, function(item) {
514
+ value.push(new Resource(item));
515
+ });
516
+ } else {
517
+ copy(data, value);
518
+ value.$promise = promise;
519
+ }
520
+ }
415
521
 
416
- return value;
417
- };
522
+ value.$resolved = true;
418
523
 
524
+ response.resource = value;
419
525
 
420
- Resource.prototype['$' + name] = function(a1, a2, a3) {
421
- var params = extractParams(this),
422
- success = noop,
423
- error;
526
+ return response;
527
+ }, function(response) {
528
+ value.$resolved = true;
424
529
 
425
- switch(arguments.length) {
426
- case 3: params = a1; success = a2; error = a3; break;
427
- case 2:
428
- case 1:
429
- if (isFunction(a1)) {
430
- success = a1;
431
- error = a2;
432
- } else {
433
- params = a1;
434
- success = a2 || noop;
435
- }
436
- case 0: break;
437
- default:
438
- throw "Expected between 1-3 arguments [params, success, error], got " +
439
- arguments.length + " arguments.";
530
+ (error||noop)(response);
531
+
532
+ return $q.reject(response);
533
+ });
534
+
535
+ promise = promise.then(
536
+ function(response) {
537
+ var value = responseInterceptor(response);
538
+ (success||noop)(value, response.headers);
539
+ return value;
540
+ },
541
+ responseErrorInterceptor);
542
+
543
+ if (!isInstanceCall) {
544
+ // we are creating instance / collection
545
+ // - set the initial promise
546
+ // - return the instance / collection
547
+ value.$promise = promise;
548
+ value.$resolved = false;
549
+
550
+ return value;
551
+ }
552
+
553
+ // instance call
554
+ return promise;
555
+ };
556
+
557
+
558
+ Resource.prototype['$' + name] = function(params, success, error) {
559
+ if (isFunction(params)) {
560
+ error = success; success = params; params = {};
440
561
  }
441
- var data = hasBody ? this : undefined;
442
- Resource[name].call(this, params, data, success, error);
562
+ var result = Resource[name](params, this, success, error);
563
+ return result.$promise || result;
443
564
  };
444
565
  });
445
566
 
446
567
  Resource.bind = function(additionalParamDefaults){
447
- return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
568
+ return resourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
448
569
  };
449
570
 
450
571
  return Resource;
451
572
  }
452
573
 
453
- return ResourceFactory;
574
+ return resourceFactory;
454
575
  }]);
455
576
 
456
577