angularjs-rails-resource 1.0.0.pre.2 → 1.0.0.pre.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +57 -1
- data/Gruntfile.js +51 -36
- data/README.md +203 -68
- data/bower.json +2 -2
- data/changelog.js +206 -0
- data/karma.conf.js +2 -1
- data/lib/angularjs-rails-resource/version.rb +1 -1
- data/package.json +9 -3
- data/test/unit/angularjs/rails/extensions/snapshotsSpec.js +428 -0
- data/test/unit/angularjs/rails/resourceProviderSpec.js +20 -0
- data/test/unit/angularjs/rails/resourceSpec.js +173 -50
- data/vendor/assets/javascripts/angularjs/rails/resource/extensions/snapshots.js +117 -0
- data/vendor/assets/javascripts/angularjs/rails/resource/resource.js +239 -52
- data/vendor/assets/javascripts/angularjs/rails/resource/serialization.js +4 -4
- data/vendor/assets/javascripts/angularjs/rails/resource/utils/inflector.js +1 -1
- data/vendor/assets/javascripts/angularjs/rails/resource/utils/injector.js +21 -4
- data/vendor/assets/javascripts/angularjs/rails/resource/utils/url_builder.js +1 -2
- metadata +7 -6
- data/angularjs-rails-resource.js +0 -1117
- data/angularjs-rails-resource.min.js +0 -7
- data/angularjs-rails-resource.zip +0 -0
@@ -303,9 +303,9 @@
|
|
303
303
|
Serializer.prototype.getDeserializedAttributeName = function (attributeName) {
|
304
304
|
var camelizedName = this.camelize(attributeName);
|
305
305
|
|
306
|
-
camelizedName = this.deserializeMappings[attributeName]
|
307
|
-
|
308
|
-
|
306
|
+
camelizedName = this.deserializeMappings[attributeName] ||
|
307
|
+
this.deserializeMappings[camelizedName] ||
|
308
|
+
camelizedName;
|
309
309
|
|
310
310
|
if (this.isExcludedFromDeserialization(attributeName) || this.isExcludedFromDeserialization(camelizedName)) {
|
311
311
|
return undefined;
|
@@ -527,7 +527,7 @@
|
|
527
527
|
return this.options.camelize(value);
|
528
528
|
}
|
529
529
|
return value;
|
530
|
-
}
|
530
|
+
};
|
531
531
|
|
532
532
|
return Serializer;
|
533
533
|
}
|
@@ -9,7 +9,7 @@
|
|
9
9
|
*/
|
10
10
|
function getDependency(dependency) {
|
11
11
|
if (dependency) {
|
12
|
-
return angular.isString(dependency) ? $injector.get(dependency) : dependency
|
12
|
+
return angular.isString(dependency) ? $injector.get(dependency) : dependency;
|
13
13
|
}
|
14
14
|
|
15
15
|
return undefined;
|
@@ -17,9 +17,9 @@
|
|
17
17
|
|
18
18
|
/**
|
19
19
|
* Looks up and instantiates an instance of the requested service. If the service is not a string then it is
|
20
|
-
* assumed to be a
|
20
|
+
* assumed to be a constructor function.
|
21
21
|
*
|
22
|
-
* @param
|
22
|
+
* @param {String|function|Object} service The service to instantiate
|
23
23
|
* @returns {*} A new instance of the requested service
|
24
24
|
*/
|
25
25
|
function createService(service) {
|
@@ -30,9 +30,26 @@
|
|
30
30
|
return undefined;
|
31
31
|
}
|
32
32
|
|
33
|
+
/**
|
34
|
+
* Looks up and instantiates an instance of the requested service if .
|
35
|
+
* @param {String|function|Object} service The service to instantiate
|
36
|
+
* @returns {*}
|
37
|
+
*/
|
38
|
+
function getService(service) {
|
39
|
+
// strings and functions are not considered objects by angular.isObject()
|
40
|
+
if (angular.isObject(service)) {
|
41
|
+
return service;
|
42
|
+
} else if (service) {
|
43
|
+
return createService(service);
|
44
|
+
}
|
45
|
+
|
46
|
+
return undefined;
|
47
|
+
}
|
48
|
+
|
33
49
|
return {
|
34
50
|
createService: createService,
|
51
|
+
getService: getService,
|
35
52
|
getDependency: getDependency
|
36
|
-
}
|
53
|
+
};
|
37
54
|
}]);
|
38
55
|
}());
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angularjs-rails-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.
|
4
|
+
version: 1.0.0.pre.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tommy Odom
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-12-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A small AngularJS add-on for integrating with Rails via JSON more easily.
|
15
15
|
email:
|
@@ -29,10 +29,8 @@ files:
|
|
29
29
|
- README.md
|
30
30
|
- Rakefile
|
31
31
|
- angularjs-rails-resource.gemspec
|
32
|
-
- angularjs-rails-resource.js
|
33
|
-
- angularjs-rails-resource.min.js
|
34
|
-
- angularjs-rails-resource.zip
|
35
32
|
- bower.json
|
33
|
+
- changelog.js
|
36
34
|
- karma.conf.js
|
37
35
|
- lib/angularjs-rails-resource.rb
|
38
36
|
- lib/angularjs-rails-resource/version.rb
|
@@ -48,6 +46,7 @@ files:
|
|
48
46
|
- test/lib/angular/angular-sanitize.js
|
49
47
|
- test/lib/angular/angular-scenario.js
|
50
48
|
- test/lib/angular/angular.js
|
49
|
+
- test/unit/angularjs/rails/extensions/snapshotsSpec.js
|
51
50
|
- test/unit/angularjs/rails/httpSettingsSpec.js
|
52
51
|
- test/unit/angularjs/rails/interceptorsSpec.js
|
53
52
|
- test/unit/angularjs/rails/nestedUrlsSpec.js
|
@@ -59,6 +58,7 @@ files:
|
|
59
58
|
- test/unit/angularjs/rails/transformersSpec.js
|
60
59
|
- test/unit/angularjs/rails/utils/urlBuilderSpec.js
|
61
60
|
- test/unit/helpers/spec_helper.js
|
61
|
+
- vendor/assets/javascripts/angularjs/rails/resource/extensions/snapshots.js
|
62
62
|
- vendor/assets/javascripts/angularjs/rails/resource/index.js
|
63
63
|
- vendor/assets/javascripts/angularjs/rails/resource/resource.js
|
64
64
|
- vendor/assets/javascripts/angularjs/rails/resource/serialization.js
|
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
85
|
version: 1.3.1
|
86
86
|
requirements: []
|
87
87
|
rubyforge_project:
|
88
|
-
rubygems_version: 2.
|
88
|
+
rubygems_version: 2.1.9
|
89
89
|
signing_key:
|
90
90
|
specification_version: 4
|
91
91
|
summary: AngularJS add-on resource add-on for integrating with Rails
|
@@ -101,6 +101,7 @@ test_files:
|
|
101
101
|
- test/lib/angular/angular-sanitize.js
|
102
102
|
- test/lib/angular/angular-scenario.js
|
103
103
|
- test/lib/angular/angular.js
|
104
|
+
- test/unit/angularjs/rails/extensions/snapshotsSpec.js
|
104
105
|
- test/unit/angularjs/rails/httpSettingsSpec.js
|
105
106
|
- test/unit/angularjs/rails/interceptorsSpec.js
|
106
107
|
- test/unit/angularjs/rails/nestedUrlsSpec.js
|
data/angularjs-rails-resource.js
DELETED
@@ -1,1117 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* A resource factory inspired by $resource from AngularJS
|
3
|
-
* @version v1.0.0-pre.2 - 2013-11-24
|
4
|
-
* @link https://github.com/FineLinePrototyping/angularjs-rails-resource.git
|
5
|
-
* @author
|
6
|
-
*/
|
7
|
-
|
8
|
-
(function (undefined) {
|
9
|
-
angular.module('rails', ['ng']);
|
10
|
-
}());
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
(function (undefined) {
|
15
|
-
angular.module('rails').factory('RailsInflector', function() {
|
16
|
-
function camelize(key) {
|
17
|
-
if (!angular.isString(key)) {
|
18
|
-
return key;
|
19
|
-
}
|
20
|
-
|
21
|
-
// should this match more than word and digit characters?
|
22
|
-
return key.replace(/_[\w\d]/g, function (match, index, string) {
|
23
|
-
return index === 0 ? match : string.charAt(index + 1).toUpperCase();
|
24
|
-
});
|
25
|
-
}
|
26
|
-
|
27
|
-
function underscore(key) {
|
28
|
-
if (!angular.isString(key)) {
|
29
|
-
return key;
|
30
|
-
}
|
31
|
-
|
32
|
-
// TODO match the latest logic from Active Support
|
33
|
-
return key.replace(/[A-Z]/g, function (match, index) {
|
34
|
-
return index === 0 ? match : '_' + match.toLowerCase();
|
35
|
-
});
|
36
|
-
}
|
37
|
-
|
38
|
-
function pluralize(value) {
|
39
|
-
// TODO match Active Support
|
40
|
-
return value + 's';
|
41
|
-
}
|
42
|
-
|
43
|
-
return {
|
44
|
-
camelize: camelize,
|
45
|
-
underscore: underscore,
|
46
|
-
pluralize: pluralize
|
47
|
-
}
|
48
|
-
});
|
49
|
-
}());
|
50
|
-
(function (undefined) {
|
51
|
-
angular.module('rails').factory('RailsResourceInjector', ['$injector', function($injector) {
|
52
|
-
/**
|
53
|
-
* Allow dependencies to be referenced by name or instance. If referenced by name AngularJS $injector
|
54
|
-
* is used to retrieve the dependency.
|
55
|
-
*
|
56
|
-
* @param dependency (string | function) The dependency to retrieve
|
57
|
-
* @returns {*} The dependency
|
58
|
-
*/
|
59
|
-
function getDependency(dependency) {
|
60
|
-
if (dependency) {
|
61
|
-
return angular.isString(dependency) ? $injector.get(dependency) : dependency
|
62
|
-
}
|
63
|
-
|
64
|
-
return undefined;
|
65
|
-
}
|
66
|
-
|
67
|
-
/**
|
68
|
-
* Looks up and instantiates an instance of the requested service. If the service is not a string then it is
|
69
|
-
* assumed to be a constuctor function.
|
70
|
-
*
|
71
|
-
* @param service (string | function) The service to instantiate
|
72
|
-
* @returns {*} A new instance of the requested service
|
73
|
-
*/
|
74
|
-
function createService(service) {
|
75
|
-
if (service) {
|
76
|
-
return $injector.instantiate(getDependency(service));
|
77
|
-
}
|
78
|
-
|
79
|
-
return undefined;
|
80
|
-
}
|
81
|
-
|
82
|
-
return {
|
83
|
-
createService: createService,
|
84
|
-
getDependency: getDependency
|
85
|
-
}
|
86
|
-
}]);
|
87
|
-
}());
|
88
|
-
/**
|
89
|
-
* @ngdoc function
|
90
|
-
* @name rails.railsUrlBuilder
|
91
|
-
* @function
|
92
|
-
* @requires $interpolate
|
93
|
-
*
|
94
|
-
* @description
|
95
|
-
*
|
96
|
-
* Compiles a URL template string into an interpolation function using $interpolate. If no interpolation bindings
|
97
|
-
* found then {{id}} is appended to the url string.
|
98
|
-
*
|
99
|
-
<pre>
|
100
|
-
expect(railsUrlBuilder('/books')()).toEqual('/books')
|
101
|
-
expect(railsUrlBuilder('/books')({id: 1})).toEqual('/books/1')
|
102
|
-
expect(railsUrlBuilder('/authors/{{authorId}}/books/{{id}}')({id: 1, authorId: 2})).toEqual('/authors/2/books/1')
|
103
|
-
</pre>
|
104
|
-
*
|
105
|
-
* If the $interpolate startSymbol and endSymbol have been customized those values should be used instead of {{ and }}
|
106
|
-
*
|
107
|
-
* @param {string|function} url If the url is a function then that function is returned. Otherwise the url string
|
108
|
-
* is passed to $interpolate as an expression.
|
109
|
-
*
|
110
|
-
* @returns {function(context)} As stated by $interpolate documentation:
|
111
|
-
* An interpolation function which is used to compute the interpolated
|
112
|
-
* string. The function has these parameters:
|
113
|
-
*
|
114
|
-
* * `context`: an object against which any expressions embedded in the strings are evaluated
|
115
|
-
* against.
|
116
|
-
*
|
117
|
-
*/
|
118
|
-
(function (undefined) {
|
119
|
-
angular.module('rails').factory('railsUrlBuilder', ['$interpolate', function($interpolate) {
|
120
|
-
return function (url) {
|
121
|
-
var expression;
|
122
|
-
|
123
|
-
if (angular.isFunction(url) || angular.isUndefined(url)) {
|
124
|
-
return url;
|
125
|
-
}
|
126
|
-
|
127
|
-
if (url.indexOf($interpolate.startSymbol()) === -1) {
|
128
|
-
url = url + '/' + $interpolate.startSymbol() + 'id' + $interpolate.endSymbol();
|
129
|
-
}
|
130
|
-
|
131
|
-
expression = $interpolate(url);
|
132
|
-
|
133
|
-
return function (params) {
|
134
|
-
url = expression(params);
|
135
|
-
|
136
|
-
if (url.charAt(url.length - 1) === '/') {
|
137
|
-
url = url.substr(0, url.length - 1);
|
138
|
-
}
|
139
|
-
|
140
|
-
return url;
|
141
|
-
};
|
142
|
-
};
|
143
|
-
|
144
|
-
}])
|
145
|
-
}());
|
146
|
-
(function (undefined) {
|
147
|
-
angular.module('rails').provider('railsSerializer', function() {
|
148
|
-
var defaultOptions = {
|
149
|
-
underscore: undefined,
|
150
|
-
camelize: undefined,
|
151
|
-
pluralize: undefined,
|
152
|
-
exclusionMatchers: []
|
153
|
-
};
|
154
|
-
|
155
|
-
/**
|
156
|
-
* Configures the underscore method used by the serializer. If not defined then <code>RailsInflector.underscore</code>
|
157
|
-
* will be used.
|
158
|
-
*
|
159
|
-
* @param {function(string):string} fn The function to use for underscore conversion
|
160
|
-
* @returns {railsSerializerProvider} The provider for chaining
|
161
|
-
*/
|
162
|
-
this.underscore = function(fn) {
|
163
|
-
defaultOptions.underscore = fn;
|
164
|
-
return this;
|
165
|
-
};
|
166
|
-
|
167
|
-
/**
|
168
|
-
* Configures the camelize method used by the serializer. If not defined then <code>RailsInflector.camelize</code>
|
169
|
-
* will be used.
|
170
|
-
*
|
171
|
-
* @param {function(string):string} fn The function to use for camelize conversion
|
172
|
-
* @returns {railsSerializerProvider} The provider for chaining
|
173
|
-
*/
|
174
|
-
this.camelize = function(fn) {
|
175
|
-
defaultOptions.camelize = fn;
|
176
|
-
return this;
|
177
|
-
};
|
178
|
-
|
179
|
-
/**
|
180
|
-
* Configures the pluralize method used by the serializer. If not defined then <code>RailsInflector.pluralize</code>
|
181
|
-
* will be used.
|
182
|
-
*
|
183
|
-
* @param {function(string):string} fn The function to use for pluralizing strings.
|
184
|
-
* @returns {railsSerializerProvider} The provider for chaining
|
185
|
-
*/
|
186
|
-
this.pluralize = function(fn) {
|
187
|
-
defaultOptions.pluralize = fn;
|
188
|
-
return this;
|
189
|
-
};
|
190
|
-
|
191
|
-
/**
|
192
|
-
* Configures the array exclusion matchers by the serializer. Exclusion matchers can be one of the following:
|
193
|
-
* * string - Defines a prefix that is used to test for exclusion
|
194
|
-
* * RegExp - A custom regular expression that is tested against the attribute name
|
195
|
-
* * function - A custom function that accepts a string argument and returns a boolean with true indicating exclusion.
|
196
|
-
*
|
197
|
-
* @param {Array.<string|function(string):boolean|RegExp} exclusions An array of exclusion matchers
|
198
|
-
* @returns {railsSerializerProvider} The provider for chaining
|
199
|
-
*/
|
200
|
-
this.exclusionMatchers = function(exclusions) {
|
201
|
-
defaultOptions.exclusionMatchers = exclusions;
|
202
|
-
return this;
|
203
|
-
};
|
204
|
-
|
205
|
-
this.$get = ['$injector', 'RailsInflector', 'RailsResourceInjector', function ($injector, RailsInflector, RailsResourceInjector) {
|
206
|
-
defaultOptions.underscore = defaultOptions.underscore || RailsInflector.underscore;
|
207
|
-
defaultOptions.camelize = defaultOptions.camelize || RailsInflector.camelize;
|
208
|
-
defaultOptions.pluralize = defaultOptions.pluralize || RailsInflector.pluralize;
|
209
|
-
|
210
|
-
function railsSerializer(options, customizer) {
|
211
|
-
|
212
|
-
function Serializer() {
|
213
|
-
if (angular.isFunction(options)) {
|
214
|
-
customizer = options;
|
215
|
-
options = {};
|
216
|
-
}
|
217
|
-
|
218
|
-
this.exclusions = {};
|
219
|
-
this.inclusions = {};
|
220
|
-
this.serializeMappings = {};
|
221
|
-
this.deserializeMappings = {};
|
222
|
-
this.customSerializedAttributes = {};
|
223
|
-
this.preservedAttributes = {};
|
224
|
-
this.customSerializers = {};
|
225
|
-
this.nestedResources = {};
|
226
|
-
this.options = angular.extend({excludeByDefault: false}, defaultOptions, options || {});
|
227
|
-
|
228
|
-
if (customizer) {
|
229
|
-
customizer.call(this, this);
|
230
|
-
}
|
231
|
-
}
|
232
|
-
|
233
|
-
/**
|
234
|
-
* Accepts a variable list of attribute names to exclude from JSON serialization.
|
235
|
-
*
|
236
|
-
* @param attributeNames... {string} Variable number of attribute name parameters
|
237
|
-
* @returns {Serializer} this for chaining support
|
238
|
-
*/
|
239
|
-
Serializer.prototype.exclude = function () {
|
240
|
-
var exclusions = this.exclusions;
|
241
|
-
|
242
|
-
angular.forEach(arguments, function (attributeName) {
|
243
|
-
exclusions[attributeName] = false;
|
244
|
-
});
|
245
|
-
|
246
|
-
return this;
|
247
|
-
};
|
248
|
-
|
249
|
-
/**
|
250
|
-
* Accepts a variable list of attribute names that should be included in JSON serialization.
|
251
|
-
* Using this method will by default exclude all other attributes and only the ones explicitly included using <code>only</code> will be serialized.
|
252
|
-
* @param attributeNames... {string} Variable number of attribute name parameters
|
253
|
-
* @returns {Serializer} this for chaining support
|
254
|
-
*/
|
255
|
-
Serializer.prototype.only = function () {
|
256
|
-
var inclusions = this.inclusions;
|
257
|
-
this.options.excludeByDefault = true;
|
258
|
-
|
259
|
-
angular.forEach(arguments, function (attributeName) {
|
260
|
-
inclusions[attributeName] = true;
|
261
|
-
});
|
262
|
-
|
263
|
-
return this;
|
264
|
-
};
|
265
|
-
|
266
|
-
/**
|
267
|
-
* This is a shortcut for rename that allows you to specify a variable number of attributes that should all be renamed to
|
268
|
-
* <code>{attributeName}_attributes</code> to work with the Rails nested_attributes feature.
|
269
|
-
* @param attributeNames... {string} Variable number of attribute name parameters
|
270
|
-
* @returns {Serializer} this for chaining support
|
271
|
-
*/
|
272
|
-
Serializer.prototype.nestedAttribute = function () {
|
273
|
-
var self = this;
|
274
|
-
|
275
|
-
angular.forEach(arguments, function (attributeName) {
|
276
|
-
self.rename(attributeName, attributeName + '_attributes');
|
277
|
-
});
|
278
|
-
|
279
|
-
return this;
|
280
|
-
};
|
281
|
-
|
282
|
-
/**
|
283
|
-
* Specifies an attribute that is a nested resource within the parent object.
|
284
|
-
* Nested resources do not imply nested attributes, if you want both you still have to specify call <code>nestedAttribute</code> as well.
|
285
|
-
*
|
286
|
-
* A nested resource serves two purposes. First, it defines the resource that should be used when constructing resources from the server.
|
287
|
-
* Second, it specifies how the nested object should be serialized.
|
288
|
-
*
|
289
|
-
* An optional third parameter <code>serializer</code> is available to override the serialization logic
|
290
|
-
* of the resource in case you need to serialize it differently in multiple contexts.
|
291
|
-
*
|
292
|
-
* @param attributeName {string} The name of the attribute that is a nested resource
|
293
|
-
* @param resource {string | Resource} A reference to the resource that the attribute is a type of.
|
294
|
-
* @param serializer {string | Serializer} (optional) An optional serializer reference to override the nested resource's default serializer
|
295
|
-
* @returns {Serializer} this for chaining support
|
296
|
-
*/
|
297
|
-
Serializer.prototype.resource = function (attributeName, resource, serializer) {
|
298
|
-
this.nestedResources[attributeName] = resource;
|
299
|
-
|
300
|
-
if (serializer) {
|
301
|
-
this.serializeWith(attributeName, serializer);
|
302
|
-
}
|
303
|
-
|
304
|
-
return this;
|
305
|
-
};
|
306
|
-
|
307
|
-
/**
|
308
|
-
* Specifies a custom name mapping for an attribute.
|
309
|
-
* On serializing to JSON the jsonName will be used.
|
310
|
-
* On deserialization, if jsonName is seen then it will be renamed as javascriptName in the resulting resource.
|
311
|
-
*
|
312
|
-
* @param javascriptName {string} The attribute name as it appears in the JavaScript object
|
313
|
-
* @param jsonName {string} The attribute name as it should appear in JSON
|
314
|
-
* @param bidirectional {boolean} (optional) Allows turning off the bidirectional renaming, defaults to true.
|
315
|
-
* @returns {Serializer} this for chaining support
|
316
|
-
*/
|
317
|
-
Serializer.prototype.rename = function (javascriptName, jsonName, bidirectional) {
|
318
|
-
this.serializeMappings[javascriptName] = jsonName;
|
319
|
-
|
320
|
-
if (bidirectional || bidirectional === undefined) {
|
321
|
-
this.deserializeMappings[jsonName] = javascriptName;
|
322
|
-
}
|
323
|
-
return this;
|
324
|
-
};
|
325
|
-
|
326
|
-
/**
|
327
|
-
* Allows custom attribute creation as part of the serialization to JSON.
|
328
|
-
*
|
329
|
-
* @param attributeName {string} The name of the attribute to add
|
330
|
-
* @param value {*} The value to add, if specified as a function then the function will be called during serialization
|
331
|
-
* and should return the value to add.
|
332
|
-
* @returns {Serializer} this for chaining support
|
333
|
-
*/
|
334
|
-
Serializer.prototype.add = function (attributeName, value) {
|
335
|
-
this.customSerializedAttributes[attributeName] = value;
|
336
|
-
return this;
|
337
|
-
};
|
338
|
-
|
339
|
-
|
340
|
-
/**
|
341
|
-
* Allows the attribute to be preserved unmodified in the resulting object.
|
342
|
-
*
|
343
|
-
* @param attributeName {string} The name of the attribute to add
|
344
|
-
* @returns {Serializer} this for chaining support
|
345
|
-
*/
|
346
|
-
Serializer.prototype.preserve = function(attributeName) {
|
347
|
-
this.preservedAttributes[attributeName] = true;
|
348
|
-
return this;
|
349
|
-
};
|
350
|
-
|
351
|
-
/**
|
352
|
-
* Specify a custom serializer to use for an attribute.
|
353
|
-
*
|
354
|
-
* @param attributeName {string} The name of the attribute
|
355
|
-
* @param serializer {string | function} A reference to the custom serializer to use for the attribute.
|
356
|
-
* @returns {Serializer} this for chaining support
|
357
|
-
*/
|
358
|
-
Serializer.prototype.serializeWith = function (attributeName, serializer) {
|
359
|
-
this.customSerializers[attributeName] = serializer;
|
360
|
-
return this;
|
361
|
-
};
|
362
|
-
|
363
|
-
/**
|
364
|
-
* Determines whether or not an attribute should be excluded.
|
365
|
-
*
|
366
|
-
* If the option excludeByDefault has been set then attributes will default to excluded and will only
|
367
|
-
* be included if they have been included using the "only" customization function.
|
368
|
-
*
|
369
|
-
* If the option excludeByDefault has not been set then attributes must be explicitly excluded using the "exclude"
|
370
|
-
* customization function or must be matched by one of the exclusionMatchers.
|
371
|
-
*
|
372
|
-
* @param attributeName The name of the attribute to check for exclusion
|
373
|
-
* @returns {boolean} true if excluded, false otherwise
|
374
|
-
*/
|
375
|
-
Serializer.prototype.isExcludedFromSerialization = function (attributeName) {
|
376
|
-
if ((this.options.excludeByDefault && !this.inclusions.hasOwnProperty(attributeName)) || this.exclusions.hasOwnProperty(attributeName)) {
|
377
|
-
return true;
|
378
|
-
}
|
379
|
-
|
380
|
-
if (this.options.exclusionMatchers) {
|
381
|
-
var excluded = false;
|
382
|
-
|
383
|
-
angular.forEach(this.options.exclusionMatchers, function (matcher) {
|
384
|
-
if (angular.isString(matcher)) {
|
385
|
-
excluded = excluded || attributeName.indexOf(matcher) === 0;
|
386
|
-
} else if (angular.isFunction(matcher)) {
|
387
|
-
excluded = excluded || matcher.call(undefined, attributeName);
|
388
|
-
} else if (matcher instanceof RegExp) {
|
389
|
-
excluded = excluded || matcher.test(attributeName);
|
390
|
-
}
|
391
|
-
});
|
392
|
-
|
393
|
-
return excluded;
|
394
|
-
}
|
395
|
-
|
396
|
-
return false;
|
397
|
-
};
|
398
|
-
|
399
|
-
/**
|
400
|
-
* Remaps the attribute name to the serialized form which includes:
|
401
|
-
* - checking for exclusion
|
402
|
-
* - remapping to a custom value specified by the rename customization function
|
403
|
-
* - underscoring the name
|
404
|
-
*
|
405
|
-
* @param attributeName The current attribute name
|
406
|
-
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
407
|
-
*/
|
408
|
-
Serializer.prototype.getSerializedAttributeName = function (attributeName) {
|
409
|
-
var mappedName = this.serializeMappings[attributeName] || attributeName;
|
410
|
-
|
411
|
-
var mappedNameExcluded = this.isExcludedFromSerialization(mappedName),
|
412
|
-
attributeNameExcluded = this.isExcludedFromSerialization(attributeName);
|
413
|
-
|
414
|
-
if(this.options.excludeByDefault) {
|
415
|
-
if(mappedNameExcluded && attributeNameExcluded) {
|
416
|
-
return undefined;
|
417
|
-
}
|
418
|
-
} else {
|
419
|
-
if (mappedNameExcluded || attributeNameExcluded) {
|
420
|
-
return undefined;
|
421
|
-
}
|
422
|
-
}
|
423
|
-
|
424
|
-
return this.underscore(mappedName);
|
425
|
-
};
|
426
|
-
|
427
|
-
/**
|
428
|
-
* Determines whether or not an attribute should be excluded from deserialization.
|
429
|
-
*
|
430
|
-
* By default, we do not exclude any attributes from deserialization.
|
431
|
-
*
|
432
|
-
* @param attributeName The name of the attribute to check for exclusion
|
433
|
-
* @returns {boolean} true if excluded, false otherwise
|
434
|
-
*/
|
435
|
-
Serializer.prototype.isExcludedFromDeserialization = function (attributeName) {
|
436
|
-
return false;
|
437
|
-
};
|
438
|
-
|
439
|
-
/**
|
440
|
-
* Remaps the attribute name to the deserialized form which includes:
|
441
|
-
* - camelizing the name
|
442
|
-
* - checking for exclusion
|
443
|
-
* - remapping to a custom value specified by the rename customization function
|
444
|
-
*
|
445
|
-
* @param attributeName The current attribute name
|
446
|
-
* @returns {*} undefined if the attribute should be excluded or the mapped attribute name
|
447
|
-
*/
|
448
|
-
Serializer.prototype.getDeserializedAttributeName = function (attributeName) {
|
449
|
-
var camelizedName = this.camelize(attributeName);
|
450
|
-
|
451
|
-
camelizedName = this.deserializeMappings[attributeName]
|
452
|
-
|| this.deserializeMappings[camelizedName]
|
453
|
-
|| camelizedName;
|
454
|
-
|
455
|
-
if (this.isExcludedFromDeserialization(attributeName) || this.isExcludedFromDeserialization(camelizedName)) {
|
456
|
-
return undefined;
|
457
|
-
}
|
458
|
-
|
459
|
-
return camelizedName;
|
460
|
-
};
|
461
|
-
|
462
|
-
/**
|
463
|
-
* Returns a reference to the nested resource that has been specified for the attribute.
|
464
|
-
* @param attributeName The attribute name
|
465
|
-
* @returns {*} undefined if no nested resource has been specified or a reference to the nested resource class
|
466
|
-
*/
|
467
|
-
Serializer.prototype.getNestedResource = function (attributeName) {
|
468
|
-
return RailsResourceInjector.getDependency(this.nestedResources[attributeName]);
|
469
|
-
};
|
470
|
-
|
471
|
-
/**
|
472
|
-
* Returns a custom serializer for the attribute if one has been specified. Custom serializers can be specified
|
473
|
-
* in one of two ways. The serializeWith customization method allows specifying a custom serializer for any attribute.
|
474
|
-
* Or an attribute could have been specified as a nested resource in which case the nested resource's serializer
|
475
|
-
* is used. Custom serializers specified using serializeWith take precedence over the nested resource serializer.
|
476
|
-
*
|
477
|
-
* @param attributeName The attribute name
|
478
|
-
* @returns {*} undefined if no custom serializer has been specified or an instance of the Serializer
|
479
|
-
*/
|
480
|
-
Serializer.prototype.getAttributeSerializer = function (attributeName) {
|
481
|
-
var resource = this.getNestedResource(attributeName),
|
482
|
-
serializer = this.customSerializers[attributeName];
|
483
|
-
|
484
|
-
// custom serializer takes precedence over resource serializer
|
485
|
-
if (serializer) {
|
486
|
-
return RailsResourceInjector.createService(serializer);
|
487
|
-
} else if (resource) {
|
488
|
-
return resource.config.serializer;
|
489
|
-
}
|
490
|
-
|
491
|
-
return undefined;
|
492
|
-
};
|
493
|
-
|
494
|
-
|
495
|
-
/**
|
496
|
-
* Prepares the data for serialization to JSON.
|
497
|
-
*
|
498
|
-
* @param data The data to prepare
|
499
|
-
* @returns {*} A new object or array that is ready for JSON serialization
|
500
|
-
*/
|
501
|
-
Serializer.prototype.serializeValue = function (data) {
|
502
|
-
var result = data,
|
503
|
-
self = this;
|
504
|
-
|
505
|
-
if (angular.isArray(data)) {
|
506
|
-
result = [];
|
507
|
-
|
508
|
-
angular.forEach(data, function (value) {
|
509
|
-
result.push(self.serializeValue(value));
|
510
|
-
});
|
511
|
-
} else if (angular.isObject(data)) {
|
512
|
-
if (angular.isDate(data)) {
|
513
|
-
return data;
|
514
|
-
}
|
515
|
-
result = {};
|
516
|
-
|
517
|
-
angular.forEach(data, function (value, key) {
|
518
|
-
// if the value is a function then it can't be serialized to JSON so we'll just skip it
|
519
|
-
if (!angular.isFunction(value)) {
|
520
|
-
self.serializeAttribute(result, key, value);
|
521
|
-
}
|
522
|
-
});
|
523
|
-
}
|
524
|
-
|
525
|
-
return result;
|
526
|
-
};
|
527
|
-
|
528
|
-
/**
|
529
|
-
* Transforms an attribute and its value and stores it on the parent data object. The attribute will be
|
530
|
-
* renamed as needed and the value itself will be serialized as well.
|
531
|
-
*
|
532
|
-
* @param data The object that the attribute will be added to
|
533
|
-
* @param attribute The attribute to transform
|
534
|
-
* @param value The current value of the attribute
|
535
|
-
*/
|
536
|
-
Serializer.prototype.serializeAttribute = function (data, attribute, value) {
|
537
|
-
var serializer = this.getAttributeSerializer(attribute),
|
538
|
-
serializedAttributeName = this.getSerializedAttributeName(attribute);
|
539
|
-
|
540
|
-
// undefined means the attribute should be excluded from serialization
|
541
|
-
if (serializedAttributeName === undefined) {
|
542
|
-
return;
|
543
|
-
}
|
544
|
-
|
545
|
-
data[serializedAttributeName] = serializer ? serializer.serialize(value) : this.serializeValue(value);
|
546
|
-
};
|
547
|
-
|
548
|
-
/**
|
549
|
-
* Serializes the data by applying various transformations such as:
|
550
|
-
* - Underscoring attribute names
|
551
|
-
* - attribute renaming
|
552
|
-
* - attribute exclusion
|
553
|
-
* - custom attribute addition
|
554
|
-
*
|
555
|
-
* @param data The data to prepare
|
556
|
-
* @returns {*} A new object or array that is ready for JSON serialization
|
557
|
-
*/
|
558
|
-
Serializer.prototype.serialize = function (data) {
|
559
|
-
var result = this.serializeValue(data),
|
560
|
-
self = this;
|
561
|
-
|
562
|
-
if (angular.isObject(result)) {
|
563
|
-
angular.forEach(this.customSerializedAttributes, function (value, key) {
|
564
|
-
if (angular.isFunction(value)) {
|
565
|
-
value = value.call(data, data);
|
566
|
-
}
|
567
|
-
|
568
|
-
self.serializeAttribute(result, key, value);
|
569
|
-
});
|
570
|
-
}
|
571
|
-
|
572
|
-
return result;
|
573
|
-
};
|
574
|
-
|
575
|
-
/**
|
576
|
-
* Iterates over the data deserializing each entry on arrays and each key/value on objects.
|
577
|
-
*
|
578
|
-
* @param data The object to deserialize
|
579
|
-
* @param Resource (optional) The resource type to deserialize the result into
|
580
|
-
* @returns {*} A new object or an instance of Resource populated with deserialized data.
|
581
|
-
*/
|
582
|
-
Serializer.prototype.deserializeValue = function (data, Resource) {
|
583
|
-
var result = data,
|
584
|
-
self = this;
|
585
|
-
|
586
|
-
if (angular.isArray(data)) {
|
587
|
-
result = [];
|
588
|
-
|
589
|
-
angular.forEach(data, function (value) {
|
590
|
-
result.push(self.deserializeValue(value, Resource));
|
591
|
-
});
|
592
|
-
} else if (angular.isObject(data)) {
|
593
|
-
if (angular.isDate(data)) {
|
594
|
-
return data;
|
595
|
-
}
|
596
|
-
|
597
|
-
result = {};
|
598
|
-
|
599
|
-
if (Resource) {
|
600
|
-
result = new Resource.config.resourceConstructor();
|
601
|
-
}
|
602
|
-
|
603
|
-
angular.forEach(data, function (value, key) {
|
604
|
-
self.deserializeAttribute(result, key, value);
|
605
|
-
});
|
606
|
-
}
|
607
|
-
|
608
|
-
return result;
|
609
|
-
};
|
610
|
-
|
611
|
-
/**
|
612
|
-
* Transforms an attribute and its value and stores it on the parent data object. The attribute will be
|
613
|
-
* renamed as needed and the value itself will be deserialized as well.
|
614
|
-
*
|
615
|
-
* @param data The object that the attribute will be added to
|
616
|
-
* @param attribute The attribute to transform
|
617
|
-
* @param value The current value of the attribute
|
618
|
-
*/
|
619
|
-
Serializer.prototype.deserializeAttribute = function (data, attribute, value) {
|
620
|
-
var serializer,
|
621
|
-
NestedResource,
|
622
|
-
attributeName = this.getDeserializedAttributeName(attribute);
|
623
|
-
|
624
|
-
// undefined means the attribute should be excluded from serialization
|
625
|
-
if (attributeName === undefined) {
|
626
|
-
return;
|
627
|
-
}
|
628
|
-
|
629
|
-
serializer = this.getAttributeSerializer(attributeName);
|
630
|
-
NestedResource = this.getNestedResource(attributeName);
|
631
|
-
|
632
|
-
// preserved attributes are assigned unmodified
|
633
|
-
if (this.preservedAttributes[attributeName]) {
|
634
|
-
data[attributeName] = value;
|
635
|
-
} else {
|
636
|
-
data[attributeName] = serializer ? serializer.deserialize(value, NestedResource) : this.deserializeValue(value, NestedResource);
|
637
|
-
}
|
638
|
-
};
|
639
|
-
|
640
|
-
/**
|
641
|
-
* Deserializes the data by applying various transformations such as:
|
642
|
-
* - Camelizing attribute names
|
643
|
-
* - attribute renaming
|
644
|
-
* - attribute exclusion
|
645
|
-
* - nested resource creation
|
646
|
-
*
|
647
|
-
* @param data The object to deserialize
|
648
|
-
* @param Resource (optional) The resource type to deserialize the result into
|
649
|
-
* @returns {*} A new object or an instance of Resource populated with deserialized data
|
650
|
-
*/
|
651
|
-
Serializer.prototype.deserialize = function (data, Resource) {
|
652
|
-
// just calls deserializeValue for now so we can more easily add on custom attribute logic for deserialize too
|
653
|
-
return this.deserializeValue(data, Resource);
|
654
|
-
};
|
655
|
-
|
656
|
-
Serializer.prototype.pluralize = function (value) {
|
657
|
-
if (this.options.pluralize) {
|
658
|
-
return this.options.pluralize(value);
|
659
|
-
}
|
660
|
-
return value;
|
661
|
-
};
|
662
|
-
|
663
|
-
Serializer.prototype.underscore = function (value) {
|
664
|
-
if (this.options.underscore) {
|
665
|
-
return this.options.underscore(value);
|
666
|
-
}
|
667
|
-
return value;
|
668
|
-
};
|
669
|
-
|
670
|
-
Serializer.prototype.camelize = function (value) {
|
671
|
-
if (this.options.camelize) {
|
672
|
-
return this.options.camelize(value);
|
673
|
-
}
|
674
|
-
return value;
|
675
|
-
}
|
676
|
-
|
677
|
-
return Serializer;
|
678
|
-
}
|
679
|
-
|
680
|
-
railsSerializer.defaultOptions = defaultOptions;
|
681
|
-
return railsSerializer;
|
682
|
-
}];
|
683
|
-
});
|
684
|
-
}());
|
685
|
-
|
686
|
-
(function (undefined) {
|
687
|
-
angular.module('rails').factory('railsRootWrappingTransformer', function () {
|
688
|
-
return function (data, resource) {
|
689
|
-
var result = {};
|
690
|
-
result[angular.isArray(data) ? resource.config.pluralName : resource.config.name] = data;
|
691
|
-
return result;
|
692
|
-
};
|
693
|
-
});
|
694
|
-
|
695
|
-
angular.module('rails').factory('railsRootWrappingInterceptor', function () {
|
696
|
-
return function (promise) {
|
697
|
-
var resource = promise.resource;
|
698
|
-
|
699
|
-
if (!resource) {
|
700
|
-
return promise;
|
701
|
-
}
|
702
|
-
|
703
|
-
return promise.then(function (response) {
|
704
|
-
if (response.data && response.data.hasOwnProperty(resource.config.name)) {
|
705
|
-
response.data = response.data[resource.config.name];
|
706
|
-
} else if (response.data && response.data.hasOwnProperty(resource.config.pluralName)) {
|
707
|
-
response.data = response.data[resource.config.pluralName];
|
708
|
-
}
|
709
|
-
|
710
|
-
return response;
|
711
|
-
});
|
712
|
-
};
|
713
|
-
});
|
714
|
-
|
715
|
-
angular.module('rails').provider('RailsResource', function () {
|
716
|
-
var defaultOptions = {
|
717
|
-
rootWrapping: true,
|
718
|
-
updateMethod: 'put',
|
719
|
-
httpConfig: {},
|
720
|
-
defaultParams: undefined
|
721
|
-
};
|
722
|
-
|
723
|
-
this.rootWrapping = function (value) {
|
724
|
-
defaultOptions.rootWrapping = value;
|
725
|
-
return this;
|
726
|
-
};
|
727
|
-
|
728
|
-
this.updateMethod = function (value) {
|
729
|
-
defaultOptions.updateMethod = value;
|
730
|
-
return this;
|
731
|
-
};
|
732
|
-
|
733
|
-
this.httpConfig = function (value) {
|
734
|
-
defaultOptions.httpConfig = value;
|
735
|
-
return this;
|
736
|
-
};
|
737
|
-
|
738
|
-
this.defaultParams = function (value) {
|
739
|
-
defaultOptions.defaultParams = value;
|
740
|
-
return this;
|
741
|
-
};
|
742
|
-
|
743
|
-
this.$get = ['$http', '$q', 'railsUrlBuilder', 'railsSerializer', 'railsRootWrappingTransformer', 'railsRootWrappingInterceptor', 'RailsResourceInjector',
|
744
|
-
function ($http, $q, railsUrlBuilder, railsSerializer, railsRootWrappingTransformer, railsRootWrappingInterceptor, RailsResourceInjector) {
|
745
|
-
|
746
|
-
function appendPath(url, path) {
|
747
|
-
if (path) {
|
748
|
-
if (path[0] !== '/') {
|
749
|
-
url += '/';
|
750
|
-
}
|
751
|
-
|
752
|
-
url += path;
|
753
|
-
}
|
754
|
-
|
755
|
-
return url;
|
756
|
-
}
|
757
|
-
|
758
|
-
function forEachDependency(list, callback) {
|
759
|
-
var dependency;
|
760
|
-
|
761
|
-
for (var i = 0, len = list.length; i < len; i++) {
|
762
|
-
dependency = list[i];
|
763
|
-
|
764
|
-
if (angular.isString(dependency)) {
|
765
|
-
dependency = list[i] = RailsResourceInjector.getDependency(dependency);
|
766
|
-
}
|
767
|
-
|
768
|
-
callback(dependency);
|
769
|
-
}
|
770
|
-
}
|
771
|
-
|
772
|
-
function RailsResource(value) {
|
773
|
-
var instance = this;
|
774
|
-
if (value) {
|
775
|
-
var immediatePromise = function (data) {
|
776
|
-
return {
|
777
|
-
resource: RailsResource,
|
778
|
-
context: instance,
|
779
|
-
response: data,
|
780
|
-
then: function (callback) {
|
781
|
-
this.response = callback(this.response, this.resource, this.context);
|
782
|
-
return immediatePromise(this.response);
|
783
|
-
}
|
784
|
-
}
|
785
|
-
};
|
786
|
-
|
787
|
-
var data = this.constructor.callInterceptors(immediatePromise({data: value}), this).response.data;
|
788
|
-
angular.extend(this, data);
|
789
|
-
}
|
790
|
-
}
|
791
|
-
|
792
|
-
RailsResource.extend = function (child) {
|
793
|
-
// Extend logic copied from CoffeeScript generated code
|
794
|
-
var __hasProp = {}.hasOwnProperty, parent = this;
|
795
|
-
for (var key in parent) {
|
796
|
-
if (__hasProp.call(parent, key)) child[key] = parent[key];
|
797
|
-
}
|
798
|
-
|
799
|
-
function ctor() {
|
800
|
-
this.constructor = child;
|
801
|
-
}
|
802
|
-
|
803
|
-
ctor.prototype = parent.prototype;
|
804
|
-
child.prototype = new ctor();
|
805
|
-
child.__super__ = parent.prototype;
|
806
|
-
return child;
|
807
|
-
};
|
808
|
-
|
809
|
-
// allow calling configure multiple times to set configuration options and override values from inherited resources
|
810
|
-
RailsResource.configure = function (cfg) {
|
811
|
-
cfg = cfg || {};
|
812
|
-
|
813
|
-
if (this.config) {
|
814
|
-
cfg = angular.extend({}, this.config, cfg);
|
815
|
-
}
|
816
|
-
|
817
|
-
this.config = {};
|
818
|
-
this.config.url = cfg.url;
|
819
|
-
this.config.rootWrapping = cfg.rootWrapping === undefined ? defaultOptions.rootWrapping : cfg.rootWrapping; // using undefined check because config.rootWrapping || true would be true when config.rootWrapping === false
|
820
|
-
this.config.httpConfig = cfg.httpConfig || defaultOptions.httpConfig;
|
821
|
-
this.config.httpConfig.headers = angular.extend({'Accept': 'application/json', 'Content-Type': 'application/json'}, this.config.httpConfig.headers || {});
|
822
|
-
this.config.defaultParams = cfg.defaultParams || defaultOptions.defaultParams;
|
823
|
-
this.config.updateMethod = (cfg.updateMethod || defaultOptions.updateMethod).toLowerCase();
|
824
|
-
|
825
|
-
this.config.requestTransformers = cfg.requestTransformers ? cfg.requestTransformers.slice(0) : [];
|
826
|
-
this.config.responseInterceptors = cfg.responseInterceptors ? cfg.responseInterceptors.slice(0) : [];
|
827
|
-
this.config.afterResponseInterceptors = cfg.afterResponseInterceptors ? cfg.afterResponseInterceptors.slice(0) : [];
|
828
|
-
|
829
|
-
// strings and functions are not considered objects by angular.isObject()
|
830
|
-
if (angular.isObject(cfg.serializer)) {
|
831
|
-
this.config.serializer = cfg.serializer;
|
832
|
-
} else {
|
833
|
-
this.config.serializer = RailsResourceInjector.createService(cfg.serializer || railsSerializer());
|
834
|
-
}
|
835
|
-
|
836
|
-
this.config.name = this.config.serializer.underscore(cfg.name);
|
837
|
-
|
838
|
-
// we don't want to turn undefined name into "undefineds" then the plural name won't update when the name is set
|
839
|
-
if (this.config.name) {
|
840
|
-
this.config.pluralName = this.config.serializer.underscore(cfg.pluralName || this.config.serializer.pluralize(this.config.name));
|
841
|
-
}
|
842
|
-
|
843
|
-
this.config.urlBuilder = railsUrlBuilder(this.config.url);
|
844
|
-
this.config.resourceConstructor = this;
|
845
|
-
};
|
846
|
-
|
847
|
-
RailsResource.configure({});
|
848
|
-
|
849
|
-
RailsResource.setUrl = function (url) {
|
850
|
-
this.configure({url: url});
|
851
|
-
};
|
852
|
-
|
853
|
-
RailsResource.buildUrl = function (context) {
|
854
|
-
return this.config.urlBuilder(context);
|
855
|
-
};
|
856
|
-
|
857
|
-
/**
|
858
|
-
* Add a callback to run on response and construction.
|
859
|
-
* @param fn(response data, constructor, context) - response data is either the resource instance returned or an array of resource instances,
|
860
|
-
* constructor is the resource class calling the function,
|
861
|
-
* context is the resource instance of the calling method (create, update, delete) or undefined if the method was a class method (get, query)
|
862
|
-
*/
|
863
|
-
RailsResource.beforeResponse = function (fn) {
|
864
|
-
fn = RailsResourceInjector.getDependency(fn);
|
865
|
-
this.config.responseInterceptors.push(function (promise) {
|
866
|
-
return promise.then(function (response) {
|
867
|
-
fn(response.data, promise.resource.config.resourceConstructor, promise.context);
|
868
|
-
return response;
|
869
|
-
});
|
870
|
-
});
|
871
|
-
};
|
872
|
-
|
873
|
-
/**
|
874
|
-
* Add a callback to run after response has been processed. These callbacks are not called on object construction.
|
875
|
-
* @param fn(response data, constructor) - response data is either the resource instance returned or an array of resource instances and constructor is the resource class calling the function
|
876
|
-
*/
|
877
|
-
RailsResource.afterResponse = function (fn) {
|
878
|
-
fn = RailsResourceInjector.getDependency(fn);
|
879
|
-
this.config.afterResponseInterceptors.push(function (promise) {
|
880
|
-
return promise.then(function (response) {
|
881
|
-
fn(response, promise.resource.config.resourceConstructor);
|
882
|
-
return response;
|
883
|
-
});
|
884
|
-
});
|
885
|
-
};
|
886
|
-
|
887
|
-
/**
|
888
|
-
* Adds a function to run after serializing the data to send to the server, but before root-wrapping it.
|
889
|
-
* @param fn (data, constructor) - data object is the serialized resource instance, and constructor the resource class calling the function
|
890
|
-
*/
|
891
|
-
RailsResource.beforeRequest = function (fn) {
|
892
|
-
fn = RailsResourceInjector.getDependency(fn);
|
893
|
-
this.config.requestTransformers.push(function (data, resource) {
|
894
|
-
return fn(data, resource.config.resourceConstructor) || data;
|
895
|
-
});
|
896
|
-
};
|
897
|
-
|
898
|
-
// transform data for request:
|
899
|
-
RailsResource.transformData = function (data) {
|
900
|
-
var config = this.config;
|
901
|
-
data = config.serializer.serialize(data);
|
902
|
-
|
903
|
-
forEachDependency(this.config.requestTransformers, function (transformer) {
|
904
|
-
data = transformer(data, config.resourceConstructor);
|
905
|
-
});
|
906
|
-
|
907
|
-
if (config.rootWrapping) {
|
908
|
-
data = railsRootWrappingTransformer(data, config.resourceConstructor);
|
909
|
-
}
|
910
|
-
|
911
|
-
return data;
|
912
|
-
};
|
913
|
-
|
914
|
-
// transform data on response:
|
915
|
-
RailsResource.callInterceptors = function (promise, context) {
|
916
|
-
var config = this.config;
|
917
|
-
|
918
|
-
promise = promise.then(function (response) {
|
919
|
-
// store off the data in case something (like our root unwrapping) assigns data as a new object
|
920
|
-
response.originalData = response.data;
|
921
|
-
return response;
|
922
|
-
});
|
923
|
-
|
924
|
-
if (config.rootWrapping) {
|
925
|
-
promise.resource = config.resourceConstructor;
|
926
|
-
promise = railsRootWrappingInterceptor(promise);
|
927
|
-
}
|
928
|
-
|
929
|
-
promise.then(function (response) {
|
930
|
-
response.data = config.serializer.deserialize(response.data, config.resourceConstructor);
|
931
|
-
return response;
|
932
|
-
});
|
933
|
-
|
934
|
-
// data is now deserialized. call response interceptors including beforeResponse
|
935
|
-
forEachDependency(config.responseInterceptors, function (interceptor) {
|
936
|
-
promise.resource = config.resourceConstructor;
|
937
|
-
promise.context = context;
|
938
|
-
promise = interceptor(promise);
|
939
|
-
});
|
940
|
-
|
941
|
-
return promise;
|
942
|
-
};
|
943
|
-
|
944
|
-
// transform data after response has been converted to a resource instance:
|
945
|
-
RailsResource.callAfterInterceptors = function (promise) {
|
946
|
-
var config = this.config;
|
947
|
-
// data is now deserialized. call response interceptors including afterResponse
|
948
|
-
forEachDependency(config.afterResponseInterceptors, function (interceptor) {
|
949
|
-
promise.resource = config.resourceConstructor;
|
950
|
-
promise = interceptor(promise);
|
951
|
-
});
|
952
|
-
|
953
|
-
return promise;
|
954
|
-
};
|
955
|
-
|
956
|
-
RailsResource.processResponse = function (promise) {
|
957
|
-
promise = this.callInterceptors(promise).then(function (response) {
|
958
|
-
return response.data;
|
959
|
-
});
|
960
|
-
|
961
|
-
return this.callAfterInterceptors(promise);
|
962
|
-
};
|
963
|
-
|
964
|
-
RailsResource.getParameters = function (queryParams) {
|
965
|
-
var params;
|
966
|
-
|
967
|
-
if (this.config.defaultParams) {
|
968
|
-
params = this.config.defaultParams;
|
969
|
-
}
|
970
|
-
|
971
|
-
if (angular.isObject(queryParams)) {
|
972
|
-
params = angular.extend(params || {}, queryParams);
|
973
|
-
}
|
974
|
-
|
975
|
-
return params;
|
976
|
-
};
|
977
|
-
|
978
|
-
RailsResource.getHttpConfig = function (queryParams) {
|
979
|
-
var params = this.getParameters(queryParams);
|
980
|
-
|
981
|
-
if (params) {
|
982
|
-
return angular.extend({params: params}, this.config.httpConfig);
|
983
|
-
}
|
984
|
-
|
985
|
-
return angular.copy(this.config.httpConfig);
|
986
|
-
};
|
987
|
-
|
988
|
-
/**
|
989
|
-
* Returns a URL from the given parameters. You can override this method on your resource definitions to provide
|
990
|
-
* custom logic for building your URLs or you can utilize the parameterized url strings to substitute values in the
|
991
|
-
* URL string.
|
992
|
-
*
|
993
|
-
* The parameters in the URL string follow the normal Angular binding expression using {{ and }} for the start/end symbols.
|
994
|
-
*
|
995
|
-
* If the context is a number and the URL string does not contain an id parameter then the number is appended
|
996
|
-
* to the URL string.
|
997
|
-
*
|
998
|
-
* If the context is a number and the URL string does
|
999
|
-
* @param context
|
1000
|
-
* @param path {string} (optional) An additional path to append to the URL
|
1001
|
-
* @return {string}
|
1002
|
-
*/
|
1003
|
-
RailsResource.$url = RailsResource.resourceUrl = function (context, path) {
|
1004
|
-
if (!angular.isObject(context)) {
|
1005
|
-
context = {id: context};
|
1006
|
-
}
|
1007
|
-
|
1008
|
-
return appendPath(this.buildUrl(context || {}), path);
|
1009
|
-
};
|
1010
|
-
|
1011
|
-
RailsResource.$get = function (url, queryParams) {
|
1012
|
-
return this.processResponse($http.get(url, this.getHttpConfig(queryParams)));
|
1013
|
-
};
|
1014
|
-
|
1015
|
-
RailsResource.query = function (queryParams, context) {
|
1016
|
-
return this.$get(this.resourceUrl(context), queryParams);
|
1017
|
-
};
|
1018
|
-
|
1019
|
-
RailsResource.get = function (context, queryParams) {
|
1020
|
-
return this.$get(this.resourceUrl(context), queryParams);
|
1021
|
-
};
|
1022
|
-
|
1023
|
-
/**
|
1024
|
-
* Returns the URL for this resource.
|
1025
|
-
*
|
1026
|
-
* @param path {string} (optional) An additional path to append to the URL
|
1027
|
-
* @returns {string} The URL for the resource
|
1028
|
-
*/
|
1029
|
-
RailsResource.prototype.$url = function (path) {
|
1030
|
-
return appendPath(this.constructor.resourceUrl(this), path);
|
1031
|
-
};
|
1032
|
-
|
1033
|
-
RailsResource.prototype.processResponse = function (promise) {
|
1034
|
-
promise = this.constructor.callInterceptors(promise, this);
|
1035
|
-
|
1036
|
-
promise = promise.then(angular.bind(this, function (response) {
|
1037
|
-
// we may not have response data
|
1038
|
-
if (response.hasOwnProperty('data') && angular.isObject(response.data)) {
|
1039
|
-
angular.extend(this, response.data);
|
1040
|
-
}
|
1041
|
-
|
1042
|
-
return this;
|
1043
|
-
}));
|
1044
|
-
|
1045
|
-
return this.constructor.callAfterInterceptors(promise);
|
1046
|
-
};
|
1047
|
-
|
1048
|
-
angular.forEach(['post', 'put', 'patch'], function (method) {
|
1049
|
-
RailsResource['$' + method] = function (url, data) {
|
1050
|
-
var config;
|
1051
|
-
// clone so we can manipulate w/o modifying the actual instance
|
1052
|
-
data = this.transformData(angular.copy(data));
|
1053
|
-
config = angular.extend({method: method, url: url, data: data}, this.getHttpConfig());
|
1054
|
-
return this.processResponse($http(config));
|
1055
|
-
};
|
1056
|
-
|
1057
|
-
RailsResource.prototype['$' + method] = function (url) {
|
1058
|
-
var data, config;
|
1059
|
-
// clone so we can manipulate w/o modifying the actual instance
|
1060
|
-
data = this.constructor.transformData(angular.copy(this, {}));
|
1061
|
-
config = angular.extend({method: method, url: url, data: data}, this.constructor.getHttpConfig());
|
1062
|
-
return this.processResponse($http(config));
|
1063
|
-
|
1064
|
-
};
|
1065
|
-
});
|
1066
|
-
|
1067
|
-
RailsResource.prototype.create = function () {
|
1068
|
-
return this.$post(this.$url(), this);
|
1069
|
-
};
|
1070
|
-
|
1071
|
-
RailsResource.prototype.update = function () {
|
1072
|
-
return this['$' + this.constructor.config.updateMethod](this.$url(), this);
|
1073
|
-
};
|
1074
|
-
|
1075
|
-
RailsResource.prototype.isNew = function () {
|
1076
|
-
return this.id == null;
|
1077
|
-
};
|
1078
|
-
|
1079
|
-
RailsResource.prototype.save = function () {
|
1080
|
-
if (this.isNew()) {
|
1081
|
-
return this.create();
|
1082
|
-
} else {
|
1083
|
-
return this.update();
|
1084
|
-
}
|
1085
|
-
};
|
1086
|
-
|
1087
|
-
RailsResource['$delete'] = function (url) {
|
1088
|
-
return this.processResponse($http['delete'](url, this.getHttpConfig()));
|
1089
|
-
};
|
1090
|
-
|
1091
|
-
RailsResource.prototype['$delete'] = function (url) {
|
1092
|
-
return this.processResponse($http['delete'](url, this.constructor.getHttpConfig()));
|
1093
|
-
};
|
1094
|
-
|
1095
|
-
//using ['delete'] instead of .delete for IE7/8 compatibility
|
1096
|
-
RailsResource.prototype.remove = RailsResource.prototype['delete'] = function () {
|
1097
|
-
return this.$delete(this.$url());
|
1098
|
-
};
|
1099
|
-
|
1100
|
-
return RailsResource;
|
1101
|
-
}];
|
1102
|
-
});
|
1103
|
-
|
1104
|
-
angular.module('rails').factory('railsResourceFactory', ['RailsResource', function (RailsResource) {
|
1105
|
-
return function (config) {
|
1106
|
-
function Resource() {
|
1107
|
-
Resource.__super__.constructor.apply(this, arguments);
|
1108
|
-
}
|
1109
|
-
|
1110
|
-
RailsResource.extend(Resource);
|
1111
|
-
Resource.configure(config);
|
1112
|
-
|
1113
|
-
return Resource;
|
1114
|
-
}
|
1115
|
-
}]);
|
1116
|
-
|
1117
|
-
}());
|