js-routes 1.0.1 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +19 -4
- data/Appraisals +2 -2
- data/CHANGELOG.md +70 -0
- data/Rakefile +14 -1
- data/Readme.md +23 -11
- data/gemfiles/rails42.gemfile +1 -1
- data/gemfiles/rails42_sprockets3.gemfile +1 -1
- data/gemfiles/rails50.gemfile +8 -0
- data/gemfiles/rails50_sprockets3.gemfile +8 -0
- data/js-routes.gemspec +2 -2
- data/lib/js_routes/engine.rb +62 -14
- data/lib/js_routes/version.rb +1 -1
- data/lib/js_routes.rb +76 -60
- data/lib/routes.js +163 -100
- data/lib/routes.js.coffee +113 -54
- data/spec/js_routes/default_serializer_spec.rb +13 -0
- data/spec/js_routes/generated_javascript_spec.rb +12 -0
- data/spec/js_routes/options_spec.rb +90 -20
- data/spec/js_routes/rails_routes_compatibility_spec.rb +46 -49
- data/spec/js_routes/zzz_last_post_rails_init_spec.rb +3 -9
- data/spec/spec_helper.rb +31 -57
- data/spec/support/routes.rb +71 -0
- metadata +14 -12
- data/Guardfile +0 -3
- data/temp +0 -2
data/lib/routes.js
CHANGED
@@ -1,6 +1,12 @@
|
|
1
|
+
/*
|
2
|
+
File generated by js-routes GEM_VERSION
|
3
|
+
Based on Rails routes of APP_CLASS
|
4
|
+
*/
|
5
|
+
|
1
6
|
(function() {
|
2
|
-
var NodeTypes, ParameterMissing, Utils, createGlobalJsRoutesObject, defaults, root,
|
3
|
-
|
7
|
+
var NodeTypes, ParameterMissing, ReservedOptions, Utils, createGlobalJsRoutesObject, defaults, root,
|
8
|
+
hasProp = {}.hasOwnProperty,
|
9
|
+
slice = [].slice;
|
4
10
|
|
5
11
|
root = typeof exports !== "undefined" && exports !== null ? exports : this;
|
6
12
|
|
@@ -17,47 +23,46 @@
|
|
17
23
|
|
18
24
|
NodeTypes = NODE_TYPES;
|
19
25
|
|
20
|
-
|
21
|
-
serialize: function(object, prefix) {
|
22
|
-
var element, i, key, prop, result, s, _i, _len;
|
26
|
+
ReservedOptions = ['anchor', 'trailing_slash', 'host', 'port', 'protocol'];
|
23
27
|
|
28
|
+
Utils = {
|
29
|
+
default_serializer: function(object, prefix) {
|
30
|
+
var element, i, j, key, len, prop, s;
|
24
31
|
if (prefix == null) {
|
25
32
|
prefix = null;
|
26
33
|
}
|
27
|
-
if (
|
34
|
+
if (object == null) {
|
28
35
|
return "";
|
29
36
|
}
|
30
37
|
if (!prefix && !(this.get_object_type(object) === "object")) {
|
31
38
|
throw new Error("Url parameters should be a javascript hash");
|
32
39
|
}
|
33
|
-
if (root.jQuery) {
|
34
|
-
result = root.jQuery.param(object);
|
35
|
-
return (!result ? "" : result);
|
36
|
-
}
|
37
40
|
s = [];
|
38
41
|
switch (this.get_object_type(object)) {
|
39
42
|
case "array":
|
40
|
-
for (i =
|
43
|
+
for (i = j = 0, len = object.length; j < len; i = ++j) {
|
41
44
|
element = object[i];
|
42
|
-
s.push(this.
|
45
|
+
s.push(this.default_serializer(element, prefix + "[]"));
|
43
46
|
}
|
44
47
|
break;
|
45
48
|
case "object":
|
46
49
|
for (key in object) {
|
47
|
-
if (!
|
50
|
+
if (!hasProp.call(object, key)) continue;
|
48
51
|
prop = object[key];
|
49
|
-
if (
|
50
|
-
|
52
|
+
if ((prop == null) && (prefix != null)) {
|
53
|
+
prop = "";
|
51
54
|
}
|
52
|
-
if (
|
53
|
-
|
55
|
+
if (prop != null) {
|
56
|
+
if (prefix != null) {
|
57
|
+
key = prefix + "[" + key + "]";
|
58
|
+
}
|
59
|
+
s.push(this.default_serializer(prop, key));
|
54
60
|
}
|
55
|
-
s.push(this.serialize(prop, key));
|
56
61
|
}
|
57
62
|
break;
|
58
63
|
default:
|
59
|
-
if (object) {
|
60
|
-
s.push(
|
64
|
+
if (object != null) {
|
65
|
+
s.push((encodeURIComponent(prefix.toString())) + "=" + (encodeURIComponent(object.toString())));
|
61
66
|
}
|
62
67
|
}
|
63
68
|
if (!s.length) {
|
@@ -65,65 +70,35 @@
|
|
65
70
|
}
|
66
71
|
return s.join("&");
|
67
72
|
},
|
73
|
+
custom_serializer: SERIALIZER,
|
74
|
+
serialize: function(object) {
|
75
|
+
if ((this.custom_serializer != null) && this.get_object_type(this.custom_serializer) === "function") {
|
76
|
+
return this.custom_serializer(object);
|
77
|
+
} else {
|
78
|
+
return this.default_serializer(object);
|
79
|
+
}
|
80
|
+
},
|
68
81
|
clean_path: function(path) {
|
69
82
|
var last_index;
|
70
|
-
|
71
83
|
path = path.split("://");
|
72
84
|
last_index = path.length - 1;
|
73
85
|
path[last_index] = path[last_index].replace(/\/+/g, "/");
|
74
86
|
return path.join("://");
|
75
87
|
},
|
76
|
-
set_default_url_options: function(optional_parts, options) {
|
77
|
-
var i, part, _i, _len, _results;
|
78
|
-
|
79
|
-
_results = [];
|
80
|
-
for (i = _i = 0, _len = optional_parts.length; _i < _len; i = ++_i) {
|
81
|
-
part = optional_parts[i];
|
82
|
-
if (!options.hasOwnProperty(part) && defaults.default_url_options.hasOwnProperty(part)) {
|
83
|
-
_results.push(options[part] = defaults.default_url_options[part]);
|
84
|
-
}
|
85
|
-
}
|
86
|
-
return _results;
|
87
|
-
},
|
88
|
-
extract_anchor: function(options) {
|
89
|
-
var anchor;
|
90
|
-
|
91
|
-
anchor = "";
|
92
|
-
if (options.hasOwnProperty("anchor")) {
|
93
|
-
anchor = "#" + options.anchor;
|
94
|
-
delete options.anchor;
|
95
|
-
}
|
96
|
-
return anchor;
|
97
|
-
},
|
98
|
-
extract_trailing_slash: function(options) {
|
99
|
-
var trailing_slash;
|
100
|
-
|
101
|
-
trailing_slash = false;
|
102
|
-
if (defaults.default_url_options.hasOwnProperty("trailing_slash")) {
|
103
|
-
trailing_slash = defaults.default_url_options.trailing_slash;
|
104
|
-
}
|
105
|
-
if (options.hasOwnProperty("trailing_slash")) {
|
106
|
-
trailing_slash = options.trailing_slash;
|
107
|
-
delete options.trailing_slash;
|
108
|
-
}
|
109
|
-
return trailing_slash;
|
110
|
-
},
|
111
88
|
extract_options: function(number_of_params, args) {
|
112
89
|
var last_el;
|
113
|
-
|
114
90
|
last_el = args[args.length - 1];
|
115
|
-
if (args.length > number_of_params || ((last_el != null) && "object" === this.get_object_type(last_el) && !this.
|
116
|
-
return args.pop();
|
91
|
+
if ((args.length > number_of_params && last_el === void 0) || ((last_el != null) && "object" === this.get_object_type(last_el) && !this.looks_like_serialized_model(last_el))) {
|
92
|
+
return args.pop() || {};
|
117
93
|
} else {
|
118
94
|
return {};
|
119
95
|
}
|
120
96
|
},
|
121
|
-
|
97
|
+
looks_like_serialized_model: function(object) {
|
122
98
|
return "id" in object || "to_param" in object;
|
123
99
|
},
|
124
100
|
path_identifier: function(object) {
|
125
101
|
var property;
|
126
|
-
|
127
102
|
if (object === 0) {
|
128
103
|
return "0";
|
129
104
|
}
|
@@ -147,56 +122,92 @@
|
|
147
122
|
},
|
148
123
|
clone: function(obj) {
|
149
124
|
var attr, copy, key;
|
150
|
-
|
151
125
|
if ((obj == null) || "object" !== this.get_object_type(obj)) {
|
152
126
|
return obj;
|
153
127
|
}
|
154
128
|
copy = obj.constructor();
|
155
129
|
for (key in obj) {
|
156
|
-
if (!
|
130
|
+
if (!hasProp.call(obj, key)) continue;
|
157
131
|
attr = obj[key];
|
158
132
|
copy[key] = attr;
|
159
133
|
}
|
160
134
|
return copy;
|
161
135
|
},
|
162
|
-
|
163
|
-
var
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
136
|
+
merge: function() {
|
137
|
+
var tap, xs;
|
138
|
+
xs = 1 <= arguments.length ? slice.call(arguments, 0) : [];
|
139
|
+
tap = function(o, fn) {
|
140
|
+
fn(o);
|
141
|
+
return o;
|
142
|
+
};
|
143
|
+
if ((xs != null ? xs.length : void 0) > 0) {
|
144
|
+
return tap({}, function(m) {
|
145
|
+
var j, k, len, results, v, x;
|
146
|
+
results = [];
|
147
|
+
for (j = 0, len = xs.length; j < len; j++) {
|
148
|
+
x = xs[j];
|
149
|
+
results.push((function() {
|
150
|
+
var results1;
|
151
|
+
results1 = [];
|
152
|
+
for (k in x) {
|
153
|
+
v = x[k];
|
154
|
+
results1.push(m[k] = v);
|
155
|
+
}
|
156
|
+
return results1;
|
157
|
+
})());
|
158
|
+
}
|
159
|
+
return results;
|
160
|
+
});
|
161
|
+
}
|
162
|
+
},
|
163
|
+
normalize_options: function(default_parts, required_parameters, optional_parts, actual_parameters) {
|
164
|
+
var i, j, key, len, options, result, url_parameters, value;
|
165
|
+
options = this.extract_options(required_parameters.length, actual_parameters);
|
166
|
+
if (actual_parameters.length > required_parameters.length) {
|
167
|
+
throw new Error("Too many parameters provided for path");
|
168
|
+
}
|
169
|
+
options = this.merge(defaults.default_url_options, default_parts, options);
|
170
|
+
result = {};
|
171
|
+
url_parameters = {};
|
172
|
+
result['url_parameters'] = url_parameters;
|
173
|
+
for (key in options) {
|
174
|
+
if (!hasProp.call(options, key)) continue;
|
175
|
+
value = options[key];
|
176
|
+
if (this.indexOf(ReservedOptions, key) >= 0) {
|
177
|
+
result[key] = value;
|
178
|
+
} else {
|
179
|
+
url_parameters[key] = value;
|
180
|
+
}
|
181
|
+
}
|
182
|
+
for (i = j = 0, len = required_parameters.length; j < len; i = ++j) {
|
183
|
+
value = required_parameters[i];
|
168
184
|
if (i < actual_parameters.length) {
|
169
|
-
|
185
|
+
url_parameters[value] = actual_parameters[i];
|
170
186
|
}
|
171
187
|
}
|
172
188
|
return result;
|
173
189
|
},
|
174
|
-
|
175
|
-
var
|
176
|
-
|
190
|
+
build_route: function(required_parameters, optional_parts, route, default_parts, full_url, args) {
|
191
|
+
var options, parameters, result, url, url_params;
|
177
192
|
args = Array.prototype.slice.call(args);
|
178
|
-
|
179
|
-
|
180
|
-
throw new Error("Too many parameters provided for path");
|
181
|
-
}
|
182
|
-
parameters = this.prepare_parameters(required_parameters, args, opts);
|
183
|
-
this.set_default_url_options(optional_parts, parameters);
|
184
|
-
anchor = this.extract_anchor(parameters);
|
185
|
-
trailing_slash = this.extract_trailing_slash(parameters);
|
193
|
+
options = this.normalize_options(default_parts, required_parameters, optional_parts, args);
|
194
|
+
parameters = options['url_parameters'];
|
186
195
|
result = "" + (this.get_prefix()) + (this.visit(route, parameters));
|
187
|
-
url = Utils.clean_path(
|
188
|
-
if (trailing_slash === true) {
|
196
|
+
url = Utils.clean_path(result);
|
197
|
+
if (options['trailing_slash'] === true) {
|
189
198
|
url = url.replace(/(.*?)[\/]?$/, "$1/");
|
190
199
|
}
|
191
200
|
if ((url_params = this.serialize(parameters)).length) {
|
192
201
|
url += "?" + url_params;
|
193
202
|
}
|
194
|
-
url += anchor;
|
203
|
+
url += options.anchor ? "#" + options.anchor : "";
|
204
|
+
if (full_url) {
|
205
|
+
url = this.route_url(options) + url;
|
206
|
+
}
|
195
207
|
return url;
|
196
208
|
},
|
197
209
|
visit: function(route, parameters, optional) {
|
198
210
|
var left, left_part, right, right_part, type, value;
|
199
|
-
|
200
211
|
if (optional == null) {
|
201
212
|
optional = false;
|
202
213
|
}
|
@@ -213,7 +224,7 @@
|
|
213
224
|
case NodeTypes.CAT:
|
214
225
|
left_part = this.visit(left, parameters, optional);
|
215
226
|
right_part = this.visit(right, parameters, optional);
|
216
|
-
if (optional && !
|
227
|
+
if (optional && ((this.is_optional_node(left[0]) && !left_part) || ((this.is_optional_node(right[0])) && !right_part))) {
|
217
228
|
return "";
|
218
229
|
}
|
219
230
|
return "" + left_part + right_part;
|
@@ -233,9 +244,11 @@
|
|
233
244
|
throw new Error("Unknown Rails node type");
|
234
245
|
}
|
235
246
|
},
|
247
|
+
is_optional_node: function(node) {
|
248
|
+
return this.indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0;
|
249
|
+
},
|
236
250
|
build_path_spec: function(route, wildcard) {
|
237
251
|
var left, right, type;
|
238
|
-
|
239
252
|
if (wildcard == null) {
|
240
253
|
wildcard = false;
|
241
254
|
}
|
@@ -264,7 +277,6 @@
|
|
264
277
|
},
|
265
278
|
visit_globbing: function(route, parameters, optional) {
|
266
279
|
var left, right, type, value;
|
267
|
-
|
268
280
|
type = route[0], left = route[1], right = route[2];
|
269
281
|
if (left.replace(/^\*/i, "") !== left) {
|
270
282
|
route[1] = left = left.replace(/^\*/i, "");
|
@@ -285,18 +297,16 @@
|
|
285
297
|
},
|
286
298
|
get_prefix: function() {
|
287
299
|
var prefix;
|
288
|
-
|
289
300
|
prefix = defaults.prefix;
|
290
301
|
if (prefix !== "") {
|
291
|
-
prefix = (prefix.match("/$") ? prefix :
|
302
|
+
prefix = (prefix.match("/$") ? prefix : prefix + "/");
|
292
303
|
}
|
293
304
|
return prefix;
|
294
305
|
},
|
295
|
-
route: function(required_parts, optional_parts, route_spec) {
|
306
|
+
route: function(required_parts, optional_parts, route_spec, default_parts, full_url) {
|
296
307
|
var path_fn;
|
297
|
-
|
298
308
|
path_fn = function() {
|
299
|
-
return Utils.
|
309
|
+
return Utils.build_route(required_parts, optional_parts, route_spec, default_parts, full_url, arguments);
|
300
310
|
};
|
301
311
|
path_fn.required_params = required_parts;
|
302
312
|
path_fn.toString = function() {
|
@@ -304,17 +314,51 @@
|
|
304
314
|
};
|
305
315
|
return path_fn;
|
306
316
|
},
|
317
|
+
route_url: function(route_defaults) {
|
318
|
+
var hostname, port, protocol;
|
319
|
+
if (typeof route_defaults === 'string') {
|
320
|
+
return route_defaults;
|
321
|
+
}
|
322
|
+
protocol = route_defaults.protocol || Utils.current_protocol();
|
323
|
+
hostname = route_defaults.host || window.location.hostname;
|
324
|
+
port = route_defaults.port || (!route_defaults.host ? Utils.current_port() : void 0);
|
325
|
+
port = port ? ":" + port : '';
|
326
|
+
return protocol + "://" + hostname + port;
|
327
|
+
},
|
328
|
+
has_location: function() {
|
329
|
+
return typeof window !== 'undefined' && typeof window.location !== 'undefined';
|
330
|
+
},
|
331
|
+
current_host: function() {
|
332
|
+
if (this.has_location()) {
|
333
|
+
return window.location.hostname;
|
334
|
+
} else {
|
335
|
+
return null;
|
336
|
+
}
|
337
|
+
},
|
338
|
+
current_protocol: function() {
|
339
|
+
if (this.has_location() && window.location.protocol !== '') {
|
340
|
+
return window.location.protocol.replace(/:$/, '');
|
341
|
+
} else {
|
342
|
+
return 'http';
|
343
|
+
}
|
344
|
+
},
|
345
|
+
current_port: function() {
|
346
|
+
if (this.has_location() && window.location.port !== '') {
|
347
|
+
return window.location.port;
|
348
|
+
} else {
|
349
|
+
return '';
|
350
|
+
}
|
351
|
+
},
|
307
352
|
_classToTypeCache: null,
|
308
353
|
_classToType: function() {
|
309
|
-
var
|
310
|
-
|
354
|
+
var j, len, name, ref;
|
311
355
|
if (this._classToTypeCache != null) {
|
312
356
|
return this._classToTypeCache;
|
313
357
|
}
|
314
358
|
this._classToTypeCache = {};
|
315
|
-
|
316
|
-
for (
|
317
|
-
name =
|
359
|
+
ref = "Boolean Number String Function Array Date RegExp Object Error".split(" ");
|
360
|
+
for (j = 0, len = ref.length; j < len; j++) {
|
361
|
+
name = ref[j];
|
318
362
|
this._classToTypeCache["[object " + name + "]"] = name.toLowerCase();
|
319
363
|
}
|
320
364
|
return this._classToTypeCache;
|
@@ -331,15 +375,31 @@
|
|
331
375
|
} else {
|
332
376
|
return typeof obj;
|
333
377
|
}
|
378
|
+
},
|
379
|
+
indexOf: function(array, element) {
|
380
|
+
if (Array.prototype.indexOf) {
|
381
|
+
return array.indexOf(element);
|
382
|
+
} else {
|
383
|
+
return this.indexOfImplementation(array, element);
|
384
|
+
}
|
385
|
+
},
|
386
|
+
indexOfImplementation: function(array, element) {
|
387
|
+
var el, i, j, len, result;
|
388
|
+
result = -1;
|
389
|
+
for (i = j = 0, len = array.length; j < len; i = ++j) {
|
390
|
+
el = array[i];
|
391
|
+
if (el === element) {
|
392
|
+
result = i;
|
393
|
+
}
|
394
|
+
}
|
395
|
+
return result;
|
334
396
|
}
|
335
397
|
};
|
336
398
|
|
337
399
|
createGlobalJsRoutesObject = function() {
|
338
400
|
var namespace;
|
339
|
-
|
340
401
|
namespace = function(mainRoot, namespaceString) {
|
341
402
|
var current, parts;
|
342
|
-
|
343
403
|
parts = (namespaceString ? namespaceString.split(".") : []);
|
344
404
|
if (!parts.length) {
|
345
405
|
return;
|
@@ -351,6 +411,9 @@
|
|
351
411
|
namespace(root, "NAMESPACE");
|
352
412
|
root.NAMESPACE = ROUTES;
|
353
413
|
root.NAMESPACE.options = defaults;
|
414
|
+
root.NAMESPACE.default_serializer = function(object, prefix) {
|
415
|
+
return Utils.default_serializer(object, prefix);
|
416
|
+
};
|
354
417
|
return root.NAMESPACE;
|
355
418
|
};
|
356
419
|
|
data/lib/routes.js.coffee
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
###
|
2
|
+
File generated by js-routes GEM_VERSION
|
3
|
+
Based on Rails routes of APP_CLASS
|
4
|
+
###
|
1
5
|
# root is this
|
2
6
|
root = (exports ? this)
|
3
7
|
|
@@ -9,67 +13,62 @@ defaults =
|
|
9
13
|
|
10
14
|
NodeTypes = NODE_TYPES
|
11
15
|
|
16
|
+
ReservedOptions = [
|
17
|
+
'anchor'
|
18
|
+
'trailing_slash'
|
19
|
+
'host'
|
20
|
+
'port'
|
21
|
+
'protocol'
|
22
|
+
]
|
23
|
+
|
12
24
|
Utils =
|
13
25
|
|
14
|
-
|
15
|
-
return ""
|
26
|
+
default_serializer: (object, prefix = null) ->
|
27
|
+
return "" unless object?
|
16
28
|
if !prefix and !(@get_object_type(object) is "object")
|
17
29
|
throw new Error("Url parameters should be a javascript hash")
|
18
30
|
|
19
|
-
if root.jQuery
|
20
|
-
result = root.jQuery.param(object)
|
21
|
-
return (if not result then "" else result)
|
22
|
-
|
23
31
|
s = []
|
24
32
|
switch @get_object_type(object)
|
25
33
|
when "array"
|
26
34
|
for element, i in object
|
27
|
-
s.push @
|
35
|
+
s.push @default_serializer(element, prefix + "[]")
|
28
36
|
when "object"
|
29
|
-
for own key, prop of object
|
30
|
-
|
31
|
-
|
37
|
+
for own key, prop of object
|
38
|
+
if !prop? and prefix?
|
39
|
+
prop = ""
|
40
|
+
|
41
|
+
if prop?
|
42
|
+
key = "#{prefix}[#{key}]" if prefix?
|
43
|
+
s.push @default_serializer(prop, key)
|
32
44
|
else
|
33
|
-
if object
|
45
|
+
if object?
|
34
46
|
s.push "#{encodeURIComponent(prefix.toString())}=#{encodeURIComponent(object.toString())}"
|
35
47
|
|
36
48
|
return "" unless s.length
|
37
49
|
s.join("&")
|
38
50
|
|
51
|
+
custom_serializer: SERIALIZER
|
52
|
+
serialize: (object) ->
|
53
|
+
if @custom_serializer? and @get_object_type(@custom_serializer) is "function"
|
54
|
+
@custom_serializer(object)
|
55
|
+
else
|
56
|
+
@default_serializer(object)
|
57
|
+
|
39
58
|
clean_path: (path) ->
|
40
59
|
path = path.split("://")
|
41
60
|
last_index = path.length - 1
|
42
61
|
path[last_index] = path[last_index].replace(/\/+/g, "/")
|
43
62
|
path.join "://"
|
44
63
|
|
45
|
-
set_default_url_options: (optional_parts, options) ->
|
46
|
-
for part, i in optional_parts when (not options.hasOwnProperty(part) and defaults.default_url_options.hasOwnProperty(part))
|
47
|
-
options[part] = defaults.default_url_options[part]
|
48
|
-
|
49
|
-
extract_anchor: (options) ->
|
50
|
-
anchor = ""
|
51
|
-
if options.hasOwnProperty("anchor")
|
52
|
-
anchor = "##{options.anchor}"
|
53
|
-
delete options.anchor
|
54
|
-
anchor
|
55
|
-
|
56
|
-
extract_trailing_slash: (options) ->
|
57
|
-
trailing_slash = false
|
58
|
-
if defaults.default_url_options.hasOwnProperty("trailing_slash")
|
59
|
-
trailing_slash = defaults.default_url_options.trailing_slash
|
60
|
-
if options.hasOwnProperty("trailing_slash")
|
61
|
-
trailing_slash = options.trailing_slash
|
62
|
-
delete options.trailing_slash
|
63
|
-
trailing_slash
|
64
|
-
|
65
64
|
extract_options: (number_of_params, args) ->
|
66
65
|
last_el = args[args.length - 1]
|
67
|
-
if args.length > number_of_params or
|
68
|
-
args.pop()
|
66
|
+
if (args.length > number_of_params and last_el == undefined) or(last_el? and "object" is @get_object_type(last_el) and !@looks_like_serialized_model(last_el))
|
67
|
+
args.pop() || {}
|
69
68
|
else
|
70
69
|
{}
|
71
70
|
|
72
|
-
|
71
|
+
looks_like_serialized_model: (object) ->
|
73
72
|
# consider object a model if it have a path identifier properties like id and to_param
|
74
73
|
"id" of object or "to_param" of object
|
75
74
|
|
@@ -96,33 +95,47 @@ Utils =
|
|
96
95
|
copy[key] = attr for own key, attr of obj
|
97
96
|
copy
|
98
97
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
merge: (xs...) ->
|
99
|
+
tap = (o, fn) -> fn(o); o
|
100
|
+
if xs?.length > 0
|
101
|
+
tap {}, (m) -> m[k] = v for k, v of x for x in xs
|
102
|
+
|
103
|
+
normalize_options: (default_parts, required_parameters, optional_parts, actual_parameters) ->
|
104
|
+
options = @extract_options(required_parameters.length, actual_parameters)
|
105
|
+
if actual_parameters.length > required_parameters.length
|
106
|
+
throw new Error("Too many parameters provided for path")
|
107
|
+
options = @merge(defaults.default_url_options, default_parts, options)
|
108
|
+
result = {}
|
109
|
+
url_parameters = {}
|
110
|
+
result['url_parameters'] = url_parameters
|
111
|
+
for own key, value of options
|
112
|
+
if @indexOf(ReservedOptions, key) >= 0
|
113
|
+
result[key] = value
|
114
|
+
else
|
115
|
+
url_parameters[key] = value
|
116
|
+
|
117
|
+
for value, i in required_parameters when i < actual_parameters.length
|
118
|
+
url_parameters[value] = actual_parameters[i]
|
103
119
|
result
|
104
120
|
|
105
|
-
|
121
|
+
build_route: (required_parameters, optional_parts, route, default_parts, full_url, args) ->
|
106
122
|
args = Array::slice.call(args)
|
107
|
-
opts = @extract_options(required_parameters.length, args)
|
108
123
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
@set_default_url_options optional_parts, parameters
|
113
|
-
# options
|
114
|
-
anchor = @extract_anchor(parameters)
|
115
|
-
trailing_slash = @extract_trailing_slash(parameters)
|
124
|
+
options = @normalize_options(default_parts, required_parameters, optional_parts, args)
|
125
|
+
parameters = options['url_parameters']
|
126
|
+
|
116
127
|
# path
|
117
128
|
result = "#{@get_prefix()}#{@visit(route, parameters)}"
|
118
|
-
url = Utils.clean_path(
|
129
|
+
url = Utils.clean_path(result)
|
119
130
|
# set trailing_slash
|
120
|
-
url = url.replace(/(.*?)[\/]?$/, "$1/") if trailing_slash is true
|
131
|
+
url = url.replace(/(.*?)[\/]?$/, "$1/") if options['trailing_slash'] is true
|
121
132
|
# set additional url params
|
122
133
|
if (url_params = @serialize(parameters)).length
|
123
134
|
url += "?#{url_params}"
|
124
135
|
# set anchor
|
125
|
-
url += anchor
|
136
|
+
url += if options.anchor then "##{options.anchor}" else ""
|
137
|
+
if full_url
|
138
|
+
url = @route_url(options) + url
|
126
139
|
url
|
127
140
|
|
128
141
|
#
|
@@ -148,7 +161,9 @@ Utils =
|
|
148
161
|
when NodeTypes.CAT
|
149
162
|
left_part = @visit(left, parameters, optional)
|
150
163
|
right_part = @visit(right, parameters, optional)
|
151
|
-
|
164
|
+
if optional and ((@is_optional_node(left[0]) and not left_part) or
|
165
|
+
((@is_optional_node(right[0])) and not right_part))
|
166
|
+
return ""
|
152
167
|
"#{left_part}#{right_part}"
|
153
168
|
when NodeTypes.SYMBOL
|
154
169
|
value = parameters[left]
|
@@ -167,6 +182,9 @@ Utils =
|
|
167
182
|
else
|
168
183
|
throw new Error("Unknown Rails node type")
|
169
184
|
|
185
|
+
|
186
|
+
is_optional_node: (node) -> @indexOf([NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT], node) >= 0
|
187
|
+
|
170
188
|
#
|
171
189
|
# This method build spec for route
|
172
190
|
#
|
@@ -217,12 +235,44 @@ Utils =
|
|
217
235
|
#
|
218
236
|
# route function: create route path function and add spec to it
|
219
237
|
#
|
220
|
-
route: (required_parts, optional_parts, route_spec) ->
|
221
|
-
path_fn = -> Utils.
|
238
|
+
route: (required_parts, optional_parts, route_spec, default_parts, full_url) ->
|
239
|
+
path_fn = -> Utils.build_route(
|
240
|
+
required_parts, optional_parts, route_spec, default_parts, full_url, arguments
|
241
|
+
)
|
222
242
|
path_fn.required_params = required_parts
|
223
243
|
path_fn.toString = -> Utils.build_path_spec(route_spec)
|
224
244
|
path_fn
|
225
245
|
|
246
|
+
|
247
|
+
route_url: (route_defaults) ->
|
248
|
+
return route_defaults if typeof route_defaults == 'string'
|
249
|
+
protocol = route_defaults.protocol || Utils.current_protocol()
|
250
|
+
hostname = route_defaults.host || window.location.hostname
|
251
|
+
port = route_defaults.port || (Utils.current_port() unless route_defaults.host)
|
252
|
+
port = if port then ":#{port}" else ''
|
253
|
+
|
254
|
+
protocol + "://" + hostname + port
|
255
|
+
|
256
|
+
|
257
|
+
has_location: ->
|
258
|
+
typeof window != 'undefined' && typeof window.location != 'undefined'
|
259
|
+
|
260
|
+
current_host: ->
|
261
|
+
if @has_location() then window.location.hostname else null
|
262
|
+
|
263
|
+
current_protocol: () ->
|
264
|
+
if @has_location() && window.location.protocol != ''
|
265
|
+
# location.protocol includes the colon character
|
266
|
+
window.location.protocol.replace(/:$/, '')
|
267
|
+
else
|
268
|
+
'http'
|
269
|
+
|
270
|
+
current_port: () ->
|
271
|
+
if @has_location() && window.location.port != ''
|
272
|
+
window.location.port
|
273
|
+
else
|
274
|
+
''
|
275
|
+
|
226
276
|
#
|
227
277
|
# This is helper method to define object type.
|
228
278
|
# The typeof operator is probably the biggest design flaw of JavaScript, simply because it's basically completely broken.
|
@@ -260,6 +310,13 @@ Utils =
|
|
260
310
|
return "#{obj}" unless obj?
|
261
311
|
(if typeof obj is "object" or typeof obj is "function" then @_classToType()[Object::toString.call(obj)] or "object" else typeof obj)
|
262
312
|
|
313
|
+
# indexOf helper
|
314
|
+
indexOf: (array, element) -> if Array::indexOf then array.indexOf(element) else @indexOfImplementation(array, element)
|
315
|
+
indexOfImplementation: (array, element) ->
|
316
|
+
result = -1
|
317
|
+
(result = i for el, i in array when el is element)
|
318
|
+
result
|
319
|
+
|
263
320
|
# globalJsObject
|
264
321
|
createGlobalJsRoutesObject = ->
|
265
322
|
# namespace function, private
|
@@ -273,6 +330,8 @@ createGlobalJsRoutesObject = ->
|
|
273
330
|
namespace(root, "NAMESPACE")
|
274
331
|
root.NAMESPACE = ROUTES
|
275
332
|
root.NAMESPACE.options = defaults
|
333
|
+
root.NAMESPACE.default_serializer = (object, prefix) ->
|
334
|
+
Utils.default_serializer(object, prefix)
|
276
335
|
root.NAMESPACE
|
277
336
|
# Set up Routes appropriately for the environment.
|
278
337
|
if typeof define is "function" and define.amd
|
@@ -280,4 +339,4 @@ if typeof define is "function" and define.amd
|
|
280
339
|
define [], -> createGlobalJsRoutesObject()
|
281
340
|
else
|
282
341
|
# Browser globals
|
283
|
-
createGlobalJsRoutesObject()
|
342
|
+
createGlobalJsRoutesObject()
|