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.
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
- __hasProp = {}.hasOwnProperty;
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
- Utils = {
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 (!object) {
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 = _i = 0, _len = object.length; _i < _len; i = ++_i) {
43
+ for (i = j = 0, len = object.length; j < len; i = ++j) {
41
44
  element = object[i];
42
- s.push(this.serialize(element, prefix + "[]"));
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 (!__hasProp.call(object, key)) continue;
50
+ if (!hasProp.call(object, key)) continue;
48
51
  prop = object[key];
49
- if (!(prop != null)) {
50
- continue;
52
+ if ((prop == null) && (prefix != null)) {
53
+ prop = "";
51
54
  }
52
- if (prefix != null) {
53
- key = "" + prefix + "[" + key + "]";
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("" + (encodeURIComponent(prefix.toString())) + "=" + (encodeURIComponent(object.toString())));
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.look_like_serialized_model(last_el))) {
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
- look_like_serialized_model: function(object) {
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 (!__hasProp.call(obj, key)) continue;
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
- prepare_parameters: function(required_parameters, actual_parameters, options) {
163
- var i, result, val, _i, _len;
164
-
165
- result = this.clone(options) || {};
166
- for (i = _i = 0, _len = required_parameters.length; _i < _len; i = ++_i) {
167
- val = required_parameters[i];
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
- result[val] = actual_parameters[i];
185
+ url_parameters[value] = actual_parameters[i];
170
186
  }
171
187
  }
172
188
  return result;
173
189
  },
174
- build_path: function(required_parameters, optional_parts, route, args) {
175
- var anchor, opts, parameters, result, trailing_slash, url, url_params;
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
- opts = this.extract_options(required_parameters.length, args);
179
- if (args.length > required_parameters.length) {
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("" + result);
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 && !(left_part && right_part)) {
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 : "" + 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.build_path(required_parts, optional_parts, route_spec, arguments);
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 name, _i, _len, _ref;
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
- _ref = "Boolean Number String Function Array Date RegExp Object Error".split(" ");
316
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
317
- name = _ref[_i];
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
- serialize: (object, prefix = null) ->
15
- return "" unless object
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 @serialize(element, prefix + "[]")
35
+ s.push @default_serializer(element, prefix + "[]")
28
36
  when "object"
29
- for own key, prop of object when prop?
30
- key = "#{prefix}[#{key}]" if prefix?
31
- s.push @serialize(prop, key)
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 (last_el? and "object" is @get_object_type(last_el) and !@look_like_serialized_model(last_el))
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
- look_like_serialized_model: (object) ->
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
- prepare_parameters: (required_parameters, actual_parameters, options) ->
100
- result = @clone(options) or {}
101
- for val, i in required_parameters when i < actual_parameters.length
102
- result[val] = actual_parameters[i]
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
- build_path: (required_parameters, optional_parts, route, args) ->
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
- if args.length > required_parameters.length
110
- throw new Error("Too many parameters provided for path")
111
- parameters = @prepare_parameters(required_parameters, args, opts)
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("#{result}")
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
- return "" if optional and not (left_part and right_part)
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.build_path(required_parts, optional_parts, route_spec, arguments)
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()