angular-rails 0.0.11 → 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (26) hide show
  1. data/lib/angular-rails/version.rb +1 -1
  2. data/test/angular-rails_test.rb +2 -2
  3. data/test/dummy/log/test.log +21 -12
  4. data/test/dummy/tmp/cache/assets/{D21/570/sprockets%2Fc943c801ce0caac77ad24200450912ae → C89/210/sprockets%2F418a14e2c274ff430d7c7a0984674389} +0 -0
  5. data/test/dummy/tmp/cache/assets/{D9F/C50/sprockets%2Ff1c6daf537a49ce6c96ef829b3000ad3 → CE4/260/sprockets%2F1833b0fd8c294a4677c47df30b2928c5} +0 -0
  6. data/test/dummy/tmp/cache/assets/D43/6A0/sprockets%2Fb57422af8cc0d9bc269d96510e93f5d0 +0 -0
  7. data/test/dummy/tmp/cache/assets/{D39/900/sprockets%2Fb8870fba4613fc84863ba75d021a0fb8 → D9D/E10/sprockets%2Fd242e0caed4b59f17fcb7f32a3f85166} +0 -0
  8. data/test/dummy/tmp/cache/assets/DA0/0E0/sprockets%2Fecbfe6dc07211f12a7f6a243de68c598 +0 -0
  9. data/test/dummy/tmp/cache/assets/E12/EC0/sprockets%2F0b5bd14cd0c3e0be2cfd134fc0752dde +0 -0
  10. data/vendor/assets/javascripts/angular-ie-compat.js +35 -35
  11. data/vendor/assets/javascripts/angular-resource.js +428 -0
  12. data/vendor/assets/javascripts/angular-resource.min.js +10 -0
  13. data/vendor/assets/javascripts/angular-sanitize.js +535 -0
  14. data/vendor/assets/javascripts/angular-sanitize.min.js +13 -0
  15. data/vendor/assets/javascripts/angular.js +14401 -0
  16. data/vendor/assets/javascripts/angular.min.js +155 -134
  17. metadata +88 -82
  18. data/test/dummy/db/development.sqlite3 +0 -0
  19. data/test/dummy/db/test.sqlite3 +0 -0
  20. data/test/dummy/log/development.log +0 -38
  21. data/test/dummy/tmp/cache/assets/CB8/DA0/sprockets%2Fc3c2c990532795ef50ae856f345b7180 +0 -0
  22. data/test/dummy/tmp/cache/assets/CCF/8E0/sprockets%2F6bed2d97ed023774109a241f0a8450b0 +0 -0
  23. data/test/dummy/tmp/cache/assets/CE0/600/sprockets%2F7b3428bf74f80926f20a216683bf5b0f +0 -0
  24. data/test/dummy/tmp/cache/assets/D11/830/sprockets%2F376c8de111107498cc89fc305dac169a +0 -0
  25. data/test/dummy/tmp/cache/assets/D3C/4A0/sprockets%2F55361a479acf3690d592c04adddfa507 +0 -0
  26. data/test/dummy/tmp/cache/assets/D9F/120/sprockets%2Fe8a9852102a74db1afd5fe4dd860db93 +0 -0
@@ -1,3 +1,3 @@
1
1
  module AngularRails
2
- VERSION = "0.0.11"
2
+ VERSION = "0.0.12"
3
3
  end
@@ -8,8 +8,8 @@ class AngularRailsTest < ActiveSupport::TestCase
8
8
  test "angular.js is found as an asset" do
9
9
  assert_not_nil @app.assets["angular.min"]
10
10
  end
11
- test "angular-helpers.coffee is found as an asset" do
11
+ test "angle-up.js is found as an asset" do
12
12
  assert_not_nil @app.assets["angle-up"]
13
- puts @app.assets["angle-up"]
14
13
  end
14
+
15
15
  end
@@ -1,12 +1,21 @@
1
- Compiled angular (1ms) (pid 26934)
2
- Compiled angular (1ms) (pid 28741)
3
- Compiled angular-helpers (198ms) (pid 42163)
4
- Compiled angular-helpers (229ms) (pid 42498)
5
- Compiled angular-helpers (371ms) (pid 42957)
6
- Compiled angular-helpers (174ms) (pid 46674)
7
- Compiled angular.min (2ms) (pid 46699)
8
- Compiled angular-helpers (589ms) (pid 50164)
9
- Compiled angular.min (7ms) (pid 50164)
10
- Compiled angular-helpers (184ms) (pid 56225)
11
- Compiled angular-helpers (522ms) (pid 4909)
12
- Compiled angle-up (22ms) (pid 17054)
1
+ Connecting to database specified by database.yml
2
+  (1.1ms) begin transaction
3
+ Compiled angle-up.js (2ms) (pid 2760)
4
+  (0.7ms) rollback transaction
5
+  (0.3ms) begin transaction
6
+ Compiled angular.min.js (5ms) (pid 2760)
7
+  (0.2ms) rollback transaction
8
+  (0.3ms) begin transaction
9
+  (0.3ms) rollback transaction
10
+  (0.2ms) begin transaction
11
+  (0.4ms) rollback transaction
12
+  (0.4ms) begin transaction
13
+  (0.3ms) rollback transaction
14
+  (0.1ms) begin transaction
15
+  (1.4ms) rollback transaction
16
+  (0.4ms) begin transaction
17
+  (0.4ms) rollback transaction
18
+  (0.4ms) begin transaction
19
+  (0.5ms) rollback transaction
20
+  (0.2ms) begin transaction
21
+  (0.4ms) rollback transaction
@@ -1,35 +1,35 @@
1
- /*
2
- Content-Type: multipart/related; boundary="_"
3
-
4
- --_
5
- Content-Location:img0
6
- Content-Transfer-Encoding:base64
7
-
8
- R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrSLoc/AG8FeUUIN+sGebWAnbKSJodqqlsOxJtqYooU9vvk+vcJIcTkg+QAAA7
9
- --_
10
- Content-Location:img1
11
- Content-Transfer-Encoding:base64
12
-
13
- R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrCLTcoM29yN6k9socs91e5X3EyJloipYrO4ohTMqA0Fn2XVNswJe+H+SXAAA7
14
- --_
15
- Content-Location:img2
16
- Content-Transfer-Encoding:base64
17
-
18
- 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
19
- --_--
20
- */
21
- (function(){
22
- var jsUri = document.location.href.replace(/\/[^\/]+(#.*)?$/, '/') +
23
- document.getElementById('ng-ie-compat').src,
24
- css = '#ng-callout .ng-arrow-left{*background-image:url("mhtml:' + jsUri + '!img0")}#ng-callout .ng-arrow-right{*background-image:url("mhtml:' + jsUri + '!img1")}.ng-input-indicator-wait {*background-image:url("mhtml:' + jsUri + '!img2")}',
25
- s = document.createElement('style');
26
-
27
- s.setAttribute('type', 'text/css');
28
-
29
- if (s.styleSheet) {
30
- s.styleSheet.cssText = css;
31
- } else {
32
- s.appendChild(document.createTextNode(css));
33
- }
34
- document.getElementsByTagName('head')[0].appendChild(s);
35
- })();
1
+ /*
2
+ Content-Type: multipart/related; boundary="_"
3
+
4
+ --_
5
+ Content-Location:img0
6
+ Content-Transfer-Encoding:base64
7
+
8
+ R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrSLoc/AG8FeUUIN+sGebWAnbKSJodqqlsOxJtqYooU9vvk+vcJIcTkg+QAAA7
9
+ --_
10
+ Content-Location:img1
11
+ Content-Transfer-Encoding:base64
12
+
13
+ R0lGODlhCwAXAKIAAMzMzO/v7/f39////////wAAAAAAAAAAACH5BAUUAAQALAAAAAALABcAAAMrCLTcoM29yN6k9socs91e5X3EyJloipYrO4ohTMqA0Fn2XVNswJe+H+SXAAA7
14
+ --_
15
+ Content-Location:img2
16
+ Content-Transfer-Encoding:base64
17
+
18
+ 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
19
+ --_--
20
+ */
21
+ (function(){
22
+ var jsUri = document.location.href.replace(/\/[^\/]+(#.*)?$/, '/') +
23
+ document.getElementById('ng-ie-compat').src,
24
+ css = '#ng-callout .ng-arrow-left{*background-image:url("mhtml:' + jsUri + '!img0")}#ng-callout .ng-arrow-right{*background-image:url("mhtml:' + jsUri + '!img1")}.ng-input-indicator-wait {*background-image:url("mhtml:' + jsUri + '!img2")}',
25
+ s = document.createElement('style');
26
+
27
+ s.setAttribute('type', 'text/css');
28
+
29
+ if (s.styleSheet) {
30
+ s.styleSheet.cssText = css;
31
+ } else {
32
+ s.appendChild(document.createTextNode(css));
33
+ }
34
+ document.getElementsByTagName('head')[0].appendChild(s);
35
+ })();
@@ -0,0 +1,428 @@
1
+ /**
2
+ * @license AngularJS v1.0.2
3
+ * (c) 2010-2012 Google, Inc. http://angularjs.org
4
+ * License: MIT
5
+ */
6
+ (function(window, angular, undefined) {
7
+ 'use strict';
8
+
9
+ /**
10
+ * @ngdoc overview
11
+ * @name ngResource
12
+ * @description
13
+ */
14
+
15
+ /**
16
+ * @ngdoc object
17
+ * @name ngResource.$resource
18
+ * @requires $http
19
+ *
20
+ * @description
21
+ * A factory which creates a resource object that lets you interact with
22
+ * [RESTful](http://en.wikipedia.org/wiki/Representational_State_Transfer) server-side data sources.
23
+ *
24
+ * The returned resource object has action methods which provide high-level behaviors without
25
+ * the need to interact with the low level {@link ng.$http $http} service.
26
+ *
27
+ * @param {string} url A parameterized URL template with parameters prefixed by `:` as in
28
+ * `/user/:username`.
29
+ *
30
+ * @param {Object=} paramDefaults Default values for `url` parameters. These can be overridden in
31
+ * `actions` methods.
32
+ *
33
+ * Each key value in the parameter object is first bound to url template if present and then any
34
+ * excess keys are appended to the url search query after the `?`.
35
+ *
36
+ * Given a template `/path/:verb` and parameter `{verb:'greet', salutation:'Hello'}` results in
37
+ * URL `/path/greet?salutation=Hello`.
38
+ *
39
+ * If the parameter value is prefixed with `@` then the value of that parameter is extracted from
40
+ * the data object (useful for non-GET operations).
41
+ *
42
+ * @param {Object.<Object>=} actions Hash with declaration of custom action that should extend the
43
+ * default set of resource actions. The declaration should be created in the following format:
44
+ *
45
+ * {action1: {method:?, params:?, isArray:?},
46
+ * action2: {method:?, params:?, isArray:?},
47
+ * ...}
48
+ *
49
+ * Where:
50
+ *
51
+ * - `action` – {string} – The name of action. This name becomes the name of the method on your
52
+ * resource object.
53
+ * - `method` – {string} – HTTP request method. Valid methods are: `GET`, `POST`, `PUT`, `DELETE`,
54
+ * and `JSONP`
55
+ * - `params` – {object=} – Optional set of pre-bound parameters for this action.
56
+ * - isArray – {boolean=} – If true then the returned object for this action is an array, see
57
+ * `returns` section.
58
+ *
59
+ * @returns {Object} A resource "class" object with methods for the default set of resource actions
60
+ * optionally extended with custom `actions`. The default set contains these actions:
61
+ *
62
+ * { 'get': {method:'GET'},
63
+ * 'save': {method:'POST'},
64
+ * 'query': {method:'GET', isArray:true},
65
+ * 'remove': {method:'DELETE'},
66
+ * 'delete': {method:'DELETE'} };
67
+ *
68
+ * Calling these methods invoke an {@link ng.$http} with the specified http method,
69
+ * destination and parameters. When the data is returned from the server then the object is an
70
+ * instance of the resource class `save`, `remove` and `delete` actions are available on it as
71
+ * methods with the `$` prefix. This allows you to easily perform CRUD operations (create, read,
72
+ * update, delete) on server-side data like this:
73
+ * <pre>
74
+ var User = $resource('/user/:userId', {userId:'@id'});
75
+ var user = User.get({userId:123}, function() {
76
+ user.abc = true;
77
+ user.$save();
78
+ });
79
+ </pre>
80
+ *
81
+ * It is important to realize that invoking a $resource object method immediately returns an
82
+ * empty reference (object or array depending on `isArray`). Once the data is returned from the
83
+ * server the existing reference is populated with the actual data. This is a useful trick since
84
+ * usually the resource is assigned to a model which is then rendered by the view. Having an empty
85
+ * object results in no rendering, once the data arrives from the server then the object is
86
+ * populated with the data and the view automatically re-renders itself showing the new data. This
87
+ * means that in most case one never has to write a callback function for the action methods.
88
+ *
89
+ * The action methods on the class object or instance object can be invoked with the following
90
+ * parameters:
91
+ *
92
+ * - HTTP GET "class" actions: `Resource.action([parameters], [success], [error])`
93
+ * - non-GET "class" actions: `Resource.action([parameters], postData, [success], [error])`
94
+ * - non-GET instance actions: `instance.$action([parameters], [success], [error])`
95
+ *
96
+ *
97
+ * @example
98
+ *
99
+ * # Credit card resource
100
+ *
101
+ * <pre>
102
+ // Define CreditCard class
103
+ var CreditCard = $resource('/user/:userId/card/:cardId',
104
+ {userId:123, cardId:'@id'}, {
105
+ charge: {method:'POST', params:{charge:true}}
106
+ });
107
+
108
+ // We can retrieve a collection from the server
109
+ var cards = CreditCard.query(function() {
110
+ // GET: /user/123/card
111
+ // server returns: [ {id:456, number:'1234', name:'Smith'} ];
112
+
113
+ var card = cards[0];
114
+ // each item is an instance of CreditCard
115
+ expect(card instanceof CreditCard).toEqual(true);
116
+ card.name = "J. Smith";
117
+ // non GET methods are mapped onto the instances
118
+ card.$save();
119
+ // POST: /user/123/card/456 {id:456, number:'1234', name:'J. Smith'}
120
+ // server returns: {id:456, number:'1234', name: 'J. Smith'};
121
+
122
+ // our custom method is mapped as well.
123
+ card.$charge({amount:9.99});
124
+ // POST: /user/123/card/456?amount=9.99&charge=true {id:456, number:'1234', name:'J. Smith'}
125
+ });
126
+
127
+ // we can create an instance as well
128
+ var newCard = new CreditCard({number:'0123'});
129
+ newCard.name = "Mike Smith";
130
+ newCard.$save();
131
+ // POST: /user/123/card {number:'0123', name:'Mike Smith'}
132
+ // server returns: {id:789, number:'01234', name: 'Mike Smith'};
133
+ expect(newCard.id).toEqual(789);
134
+ * </pre>
135
+ *
136
+ * The object returned from this function execution is a resource "class" which has "static" method
137
+ * for each action in the definition.
138
+ *
139
+ * Calling these methods invoke `$http` on the `url` template with the given `method` and `params`.
140
+ * When the data is returned from the server then the object is an instance of the resource type and
141
+ * all of the non-GET methods are available with `$` prefix. This allows you to easily support CRUD
142
+ * operations (create, read, update, delete) on server-side data.
143
+
144
+ <pre>
145
+ var User = $resource('/user/:userId', {userId:'@id'});
146
+ var user = User.get({userId:123}, function() {
147
+ user.abc = true;
148
+ user.$save();
149
+ });
150
+ </pre>
151
+ *
152
+ * It's worth noting that the success callback for `get`, `query` and other method gets passed
153
+ * in the response that came from the server as well as $http header getter function, so one
154
+ * could rewrite the above example and get access to http headers as:
155
+ *
156
+ <pre>
157
+ var User = $resource('/user/:userId', {userId:'@id'});
158
+ User.get({userId:123}, function(u, getResponseHeaders){
159
+ u.abc = true;
160
+ u.$save(function(u, putResponseHeaders) {
161
+ //u => saved user object
162
+ //putResponseHeaders => $http header getter
163
+ });
164
+ });
165
+ </pre>
166
+
167
+ * # Buzz client
168
+
169
+ Let's look at what a buzz client created with the `$resource` service looks like:
170
+ <doc:example>
171
+ <doc:source jsfiddle="false">
172
+ <script>
173
+ function BuzzController($resource) {
174
+ this.userId = 'googlebuzz';
175
+ this.Activity = $resource(
176
+ 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments',
177
+ {alt:'json', callback:'JSON_CALLBACK'},
178
+ {get:{method:'JSONP', params:{visibility:'@self'}}, replies: {method:'JSONP', params:{visibility:'@self', comments:'@comments'}}}
179
+ );
180
+ }
181
+
182
+ BuzzController.prototype = {
183
+ fetch: function() {
184
+ this.activities = this.Activity.get({userId:this.userId});
185
+ },
186
+ expandReplies: function(activity) {
187
+ activity.replies = this.Activity.replies({userId:this.userId, activityId:activity.id});
188
+ }
189
+ };
190
+ BuzzController.$inject = ['$resource'];
191
+ </script>
192
+
193
+ <div ng-controller="BuzzController">
194
+ <input ng-model="userId"/>
195
+ <button ng-click="fetch()">fetch</button>
196
+ <hr/>
197
+ <div ng-repeat="item in activities.data.items">
198
+ <h1 style="font-size: 15px;">
199
+ <img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
200
+ <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
201
+ <a href ng-click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
202
+ </h1>
203
+ {{item.object.content | html}}
204
+ <div ng-repeat="reply in item.replies.data.items" style="margin-left: 20px;">
205
+ <img src="{{reply.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
206
+ <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a>: {{reply.content | html}}
207
+ </div>
208
+ </div>
209
+ </div>
210
+ </doc:source>
211
+ <doc:scenario>
212
+ </doc:scenario>
213
+ </doc:example>
214
+ */
215
+ angular.module('ngResource', ['ng']).
216
+ factory('$resource', ['$http', '$parse', function($http, $parse) {
217
+ var DEFAULT_ACTIONS = {
218
+ 'get': {method:'GET'},
219
+ 'save': {method:'POST'},
220
+ 'query': {method:'GET', isArray:true},
221
+ 'remove': {method:'DELETE'},
222
+ 'delete': {method:'DELETE'}
223
+ };
224
+ var noop = angular.noop,
225
+ forEach = angular.forEach,
226
+ extend = angular.extend,
227
+ copy = angular.copy,
228
+ isFunction = angular.isFunction,
229
+ getter = function(obj, path) {
230
+ return $parse(path)(obj);
231
+ };
232
+
233
+ /**
234
+ * We need our custom mehtod because encodeURIComponent is too agressive and doesn't follow
235
+ * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
236
+ * segments:
237
+ * segment = *pchar
238
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
239
+ * pct-encoded = "%" HEXDIG HEXDIG
240
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
241
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
242
+ * / "*" / "+" / "," / ";" / "="
243
+ */
244
+ function encodeUriSegment(val) {
245
+ return encodeUriQuery(val, true).
246
+ replace(/%26/gi, '&').
247
+ replace(/%3D/gi, '=').
248
+ replace(/%2B/gi, '+');
249
+ }
250
+
251
+
252
+ /**
253
+ * This method is intended for encoding *key* or *value* parts of query component. We need a custom
254
+ * method becuase encodeURIComponent is too agressive and encodes stuff that doesn't have to be
255
+ * encoded per http://tools.ietf.org/html/rfc3986:
256
+ * query = *( pchar / "/" / "?" )
257
+ * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
258
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
259
+ * pct-encoded = "%" HEXDIG HEXDIG
260
+ * sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
261
+ * / "*" / "+" / "," / ";" / "="
262
+ */
263
+ function encodeUriQuery(val, pctEncodeSpaces) {
264
+ return encodeURIComponent(val).
265
+ replace(/%40/gi, '@').
266
+ replace(/%3A/gi, ':').
267
+ replace(/%24/g, '$').
268
+ replace(/%2C/gi, ',').
269
+ replace((pctEncodeSpaces ? null : /%20/g), '+');
270
+ }
271
+
272
+ function Route(template, defaults) {
273
+ this.template = template = template + '#';
274
+ this.defaults = defaults || {};
275
+ var urlParams = this.urlParams = {};
276
+ forEach(template.split(/\W/), function(param){
277
+ if (param && template.match(new RegExp("[^\\\\]:" + param + "\\W"))) {
278
+ urlParams[param] = true;
279
+ }
280
+ });
281
+ this.template = template.replace(/\\:/g, ':');
282
+ }
283
+
284
+ Route.prototype = {
285
+ url: function(params) {
286
+ var self = this,
287
+ url = this.template,
288
+ encodedVal;
289
+
290
+ params = params || {};
291
+ forEach(this.urlParams, function(_, urlParam){
292
+ encodedVal = encodeUriSegment(params[urlParam] || self.defaults[urlParam] || "");
293
+ url = url.replace(new RegExp(":" + urlParam + "(\\W)"), encodedVal + "$1");
294
+ });
295
+ url = url.replace(/\/?#$/, '');
296
+ var query = [];
297
+ forEach(params, function(value, key){
298
+ if (!self.urlParams[key]) {
299
+ query.push(encodeUriQuery(key) + '=' + encodeUriQuery(value));
300
+ }
301
+ });
302
+ query.sort();
303
+ url = url.replace(/\/*$/, '');
304
+ return url + (query.length ? '?' + query.join('&') : '');
305
+ }
306
+ };
307
+
308
+
309
+ function ResourceFactory(url, paramDefaults, actions) {
310
+ var route = new Route(url);
311
+
312
+ actions = extend({}, DEFAULT_ACTIONS, actions);
313
+
314
+ function extractParams(data){
315
+ var ids = {};
316
+ forEach(paramDefaults || {}, function(value, key){
317
+ ids[key] = value.charAt && value.charAt(0) == '@' ? getter(data, value.substr(1)) : value;
318
+ });
319
+ return ids;
320
+ }
321
+
322
+ function Resource(value){
323
+ copy(value || {}, this);
324
+ }
325
+
326
+ forEach(actions, function(action, name) {
327
+ var hasBody = action.method == 'POST' || action.method == 'PUT' || action.method == 'PATCH';
328
+ Resource[name] = function(a1, a2, a3, a4) {
329
+ var params = {};
330
+ var data;
331
+ var success = noop;
332
+ var error = null;
333
+ switch(arguments.length) {
334
+ case 4:
335
+ error = a4;
336
+ success = a3;
337
+ //fallthrough
338
+ case 3:
339
+ case 2:
340
+ if (isFunction(a2)) {
341
+ if (isFunction(a1)) {
342
+ success = a1;
343
+ error = a2;
344
+ break;
345
+ }
346
+
347
+ success = a2;
348
+ error = a3;
349
+ //fallthrough
350
+ } else {
351
+ params = a1;
352
+ data = a2;
353
+ success = a3;
354
+ break;
355
+ }
356
+ case 1:
357
+ if (isFunction(a1)) success = a1;
358
+ else if (hasBody) data = a1;
359
+ else params = a1;
360
+ break;
361
+ case 0: break;
362
+ default:
363
+ throw "Expected between 0-4 arguments [params, data, success, error], got " +
364
+ arguments.length + " arguments.";
365
+ }
366
+
367
+ var value = this instanceof Resource ? this : (action.isArray ? [] : new Resource(data));
368
+ $http({
369
+ method: action.method,
370
+ url: route.url(extend({}, extractParams(data), action.params || {}, params)),
371
+ data: data
372
+ }).then(function(response) {
373
+ var data = response.data;
374
+
375
+ if (data) {
376
+ if (action.isArray) {
377
+ value.length = 0;
378
+ forEach(data, function(item) {
379
+ value.push(new Resource(item));
380
+ });
381
+ } else {
382
+ copy(data, value);
383
+ }
384
+ }
385
+ (success||noop)(value, response.headers);
386
+ }, error);
387
+
388
+ return value;
389
+ };
390
+
391
+
392
+ Resource.bind = function(additionalParamDefaults){
393
+ return ResourceFactory(url, extend({}, paramDefaults, additionalParamDefaults), actions);
394
+ };
395
+
396
+
397
+ Resource.prototype['$' + name] = function(a1, a2, a3) {
398
+ var params = extractParams(this),
399
+ success = noop,
400
+ error;
401
+
402
+ switch(arguments.length) {
403
+ case 3: params = a1; success = a2; error = a3; break;
404
+ case 2:
405
+ case 1:
406
+ if (isFunction(a1)) {
407
+ success = a1;
408
+ error = a2;
409
+ } else {
410
+ params = a1;
411
+ success = a2 || noop;
412
+ }
413
+ case 0: break;
414
+ default:
415
+ throw "Expected between 1-3 arguments [params, success, error], got " +
416
+ arguments.length + " arguments.";
417
+ }
418
+ var data = hasBody ? this : undefined;
419
+ Resource[name].call(this, params, data, success, error);
420
+ };
421
+ });
422
+ return Resource;
423
+ }
424
+
425
+ return ResourceFactory;
426
+ }]);
427
+
428
+ })(window, window.angular);