rails-backbone 0.5.4 → 0.5.5
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/README.md +16 -4
- data/lib/generators/backbone/model/templates/model.coffee +2 -2
- data/lib/generators/backbone/resource_helpers.rb +2 -2
- data/lib/generators/backbone/router/templates/router.coffee +4 -4
- data/lib/generators/backbone/router/templates/view.coffee +2 -2
- data/lib/generators/backbone/scaffold/templates/model.coffee +2 -2
- data/lib/generators/backbone/scaffold/templates/router.coffee +2 -3
- data/lib/generators/backbone/scaffold/templates/views/edit_view.coffee +8 -8
- data/lib/generators/backbone/scaffold/templates/views/index_view.coffee +9 -11
- data/lib/generators/backbone/scaffold/templates/views/model_view.coffee +7 -7
- data/lib/generators/backbone/scaffold/templates/views/new_view.coffee +13 -13
- data/lib/generators/backbone/scaffold/templates/views/show_view.coffee +3 -3
- data/vendor/assets/javascripts/backbone_rails_sync.js +9 -0
- data/vendor/assets/javascripts/underscore.js +227 -95
- metadata +42 -48
data/README.md
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
-
# Backbone-Rails [](
|
1
|
+
# Backbone-Rails [](http://travis-ci.org/codebrew/backbone-rails)
|
2
2
|
|
3
|
-
Easily setup and use backbone.js (0.5.
|
3
|
+
Easily setup and use backbone.js (0.5.3) with rails 3.1
|
4
|
+
|
5
|
+
Follow [@TheRyanFitz on Twitter](http://twitter.com/#!/TheRyanFitz). Tweet any questions or suggestions you have about the project.
|
4
6
|
|
5
7
|
## Rails 3.1 setup
|
6
8
|
This gem requires the use of rails 3.1, coffeescript and the new rails asset pipeline provided by sprockets.
|
7
9
|
|
8
|
-
This gem vendors the latest version of underscore.js and
|
10
|
+
This gem vendors the latest version of underscore.js and backbone.js for Rails 3.1 and greater. The files will be added to the asset pipeline and available for you to use.
|
9
11
|
|
10
12
|
### Installation
|
11
13
|
|
@@ -30,7 +32,7 @@ Running `rails g backbone:install` will create the following directory structure
|
|
30
32
|
It will also create a toplevel app_name.coffee file to setup namespacing and setup initial requires.
|
31
33
|
|
32
34
|
## Generators
|
33
|
-
backbone-rails provides 3 simple generators to help get you started using
|
35
|
+
backbone-rails provides 3 simple generators to help get you started using backbone.js with rails 3.1.
|
34
36
|
The generators will only create client side code (javascript).
|
35
37
|
|
36
38
|
### Model Generator
|
@@ -85,5 +87,15 @@ Edit your posts index view `app/views/posts/index.html.erb` with the following c
|
|
85
87
|
});
|
86
88
|
</script>
|
87
89
|
|
90
|
+
If you prefer haml, this is equivalent to inserting the following code into `app/views/posts/index.html.haml`:
|
91
|
+
|
92
|
+
:javascript
|
93
|
+
$(function() {
|
94
|
+
// Blog is the app name
|
95
|
+
window.router = new Blog.Routers.PostsRouter({posts: #{@posts.to_json.html_safe}});
|
96
|
+
Backbone.history.start();
|
97
|
+
});
|
98
|
+
|
99
|
+
|
88
100
|
Now start your server `rails s` and browse to [localhost:3000/posts](http://localhost:3000/posts)
|
89
101
|
You should now have a fully functioning single page crud app for Post models.
|
@@ -5,7 +5,7 @@ class <%= model_namespace %> extends Backbone.Model
|
|
5
5
|
<% attributes.each do |attribute| -%>
|
6
6
|
<%= attribute.name %>: null
|
7
7
|
<% end -%>
|
8
|
-
|
8
|
+
|
9
9
|
class <%= collection_namespace %>Collection extends Backbone.Collection
|
10
10
|
model: <%= model_namespace %>
|
11
|
-
url: '<%= route_url %>'
|
11
|
+
url: '<%= route_url %>'
|
@@ -1,14 +1,14 @@
|
|
1
1
|
class <%= router_namespace %>Router extends Backbone.Router
|
2
2
|
initialize: (options) ->
|
3
|
-
|
3
|
+
|
4
4
|
routes:
|
5
5
|
<% actions.each do |action| -%>
|
6
6
|
"/<%= action %>": "<%= action %>"
|
7
7
|
<% end -%>
|
8
|
-
|
8
|
+
|
9
9
|
<% actions.each do |action| -%>
|
10
10
|
<%= action %>: ->
|
11
11
|
@view = new <%= "#{view_namespace}.#{action.camelize}View()" %>
|
12
12
|
$("#<%= plural_name %>").html(@view.render().el)
|
13
|
-
|
14
|
-
<% end -%>
|
13
|
+
|
14
|
+
<% end -%>
|
@@ -5,7 +5,7 @@ class <%= model_namespace %> extends Backbone.Model
|
|
5
5
|
<% attributes.each do |attribute| -%>
|
6
6
|
<%= attribute.name %>: null
|
7
7
|
<% end -%>
|
8
|
-
|
8
|
+
|
9
9
|
class <%= collection_namespace %>Collection extends Backbone.Collection
|
10
10
|
model: <%= model_namespace %>
|
11
|
-
url: '<%= route_url %>'
|
11
|
+
url: '<%= route_url %>'
|
@@ -20,13 +20,12 @@ class <%= router_namespace %>Router extends Backbone.Router
|
|
20
20
|
|
21
21
|
show: (id) ->
|
22
22
|
<%= singular_name %> = @<%= plural_name %>.get(id)
|
23
|
-
|
23
|
+
|
24
24
|
@view = new <%= "#{view_namespace}.ShowView(model: #{singular_name})" %>
|
25
25
|
$("#<%= plural_name %>").html(@view.render().el)
|
26
|
-
|
26
|
+
|
27
27
|
edit: (id) ->
|
28
28
|
<%= singular_name %> = @<%= plural_name %>.get(id)
|
29
29
|
|
30
30
|
@view = new <%= "#{view_namespace}.EditView(model: #{singular_name})" %>
|
31
31
|
$("#<%= plural_name %>").html(@view.render().el)
|
32
|
-
|
@@ -2,23 +2,23 @@
|
|
2
2
|
|
3
3
|
class <%= view_namespace %>.EditView extends Backbone.View
|
4
4
|
template : JST["<%= jst 'edit' %>"]
|
5
|
-
|
5
|
+
|
6
6
|
events :
|
7
7
|
"submit #edit-<%= singular_name %>" : "update"
|
8
|
-
|
8
|
+
|
9
9
|
update : (e) ->
|
10
10
|
e.preventDefault()
|
11
11
|
e.stopPropagation()
|
12
|
-
|
12
|
+
|
13
13
|
@model.save(null,
|
14
14
|
success : (<%= singular_name %>) =>
|
15
15
|
@model = <%= singular_name %>
|
16
16
|
window.location.hash = "/#{@model.id}"
|
17
17
|
)
|
18
|
-
|
18
|
+
|
19
19
|
render : ->
|
20
|
-
$(
|
21
|
-
|
20
|
+
$(@el).html(@template(@model.toJSON() ))
|
21
|
+
|
22
22
|
this.$("form").backboneLink(@model)
|
23
|
-
|
24
|
-
return this
|
23
|
+
|
24
|
+
return this
|
@@ -2,21 +2,19 @@
|
|
2
2
|
|
3
3
|
class <%= view_namespace %>.IndexView extends Backbone.View
|
4
4
|
template: JST["<%= jst 'index' %>"]
|
5
|
-
|
5
|
+
|
6
6
|
initialize: () ->
|
7
|
-
_.bindAll(this, 'addOne', 'addAll', 'render')
|
8
|
-
|
9
7
|
@options.<%= plural_model_name %>.bind('reset', @addAll)
|
10
|
-
|
11
|
-
addAll: ()
|
8
|
+
|
9
|
+
addAll: () =>
|
12
10
|
@options.<%= plural_model_name %>.each(@addOne)
|
13
|
-
|
14
|
-
addOne: (<%= singular_model_name %>)
|
11
|
+
|
12
|
+
addOne: (<%= singular_model_name %>) =>
|
15
13
|
view = new <%= view_namespace %>.<%= singular_name.camelize %>View({model : <%= singular_model_name %>})
|
16
14
|
@$("tbody").append(view.render().el)
|
17
|
-
|
18
|
-
render:
|
15
|
+
|
16
|
+
render: =>
|
19
17
|
$(@el).html(@template(<%= plural_model_name %>: @options.<%= plural_model_name %>.toJSON() ))
|
20
18
|
@addAll()
|
21
|
-
|
22
|
-
return this
|
19
|
+
|
20
|
+
return this
|
@@ -2,18 +2,18 @@
|
|
2
2
|
|
3
3
|
class <%= view_namespace %>.<%= singular_name.camelize %>View extends Backbone.View
|
4
4
|
template: JST["<%= jst singular_name %>"]
|
5
|
-
|
5
|
+
|
6
6
|
events:
|
7
7
|
"click .destroy" : "destroy"
|
8
|
-
|
8
|
+
|
9
9
|
tagName: "tr"
|
10
|
-
|
10
|
+
|
11
11
|
destroy: () ->
|
12
12
|
@model.destroy()
|
13
13
|
this.remove()
|
14
|
-
|
14
|
+
|
15
15
|
return false
|
16
|
-
|
16
|
+
|
17
17
|
render: ->
|
18
|
-
$(
|
19
|
-
return this
|
18
|
+
$(@el).html(@template(@model.toJSON() ))
|
19
|
+
return this
|
@@ -1,11 +1,11 @@
|
|
1
1
|
<%= view_namespace %> ||= {}
|
2
2
|
|
3
|
-
class <%= view_namespace %>.NewView extends Backbone.View
|
3
|
+
class <%= view_namespace %>.NewView extends Backbone.View
|
4
4
|
template: JST["<%= jst 'new' %>"]
|
5
|
-
|
5
|
+
|
6
6
|
events:
|
7
7
|
"submit #new-<%= singular_name %>": "save"
|
8
|
-
|
8
|
+
|
9
9
|
constructor: (options) ->
|
10
10
|
super(options)
|
11
11
|
@model = new @collection.model()
|
@@ -13,25 +13,25 @@ class <%= view_namespace %>.NewView extends Backbone.View
|
|
13
13
|
@model.bind("change:errors", () =>
|
14
14
|
this.render()
|
15
15
|
)
|
16
|
-
|
16
|
+
|
17
17
|
save: (e) ->
|
18
18
|
e.preventDefault()
|
19
19
|
e.stopPropagation()
|
20
|
-
|
20
|
+
|
21
21
|
@model.unset("errors")
|
22
|
-
|
23
|
-
@collection.create(@model.toJSON(),
|
22
|
+
|
23
|
+
@collection.create(@model.toJSON(),
|
24
24
|
success: (<%= singular_name %>) =>
|
25
25
|
@model = <%= singular_name %>
|
26
26
|
window.location.hash = "/#{@model.id}"
|
27
|
-
|
27
|
+
|
28
28
|
error: (<%= singular_name %>, jqXHR) =>
|
29
29
|
@model.set({errors: $.parseJSON(jqXHR.responseText)})
|
30
30
|
)
|
31
|
-
|
31
|
+
|
32
32
|
render: ->
|
33
|
-
$(
|
34
|
-
|
33
|
+
$(@el).html(@template(@model.toJSON() ))
|
34
|
+
|
35
35
|
this.$("form").backboneLink(@model)
|
36
|
-
|
37
|
-
return this
|
36
|
+
|
37
|
+
return this
|
@@ -25,6 +25,8 @@
|
|
25
25
|
beforeSend: function( xhr ) {
|
26
26
|
var token = $('meta[name="csrf-token"]').attr('content');
|
27
27
|
if (token) xhr.setRequestHeader('X-CSRF-Token', token);
|
28
|
+
|
29
|
+
model.trigger('sync:start');
|
28
30
|
}
|
29
31
|
}, options);
|
30
32
|
|
@@ -51,6 +53,13 @@
|
|
51
53
|
if (params.type !== 'GET') {
|
52
54
|
params.processData = false;
|
53
55
|
}
|
56
|
+
|
57
|
+
// Trigger the sync end event
|
58
|
+
var complete = options.complete;
|
59
|
+
options.complete = function(jqXHR, textStatus) {
|
60
|
+
model.trigger('sync:end');
|
61
|
+
if (complete) complete(jqXHR, textStatus);
|
62
|
+
};
|
54
63
|
|
55
64
|
// Make the request.
|
56
65
|
return $.ajax(params);
|
@@ -1,4 +1,4 @@
|
|
1
|
-
// Underscore.js 1.
|
1
|
+
// Underscore.js 1.2.2
|
2
2
|
// (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
|
3
3
|
// Underscore is freely distributable under the MIT license.
|
4
4
|
// Portions of Underscore are inspired or borrowed from Prototype,
|
@@ -48,19 +48,26 @@
|
|
48
48
|
// Create a safe reference to the Underscore object for use below.
|
49
49
|
var _ = function(obj) { return new wrapper(obj); };
|
50
50
|
|
51
|
-
// Export the Underscore object for **CommonJS**, with
|
52
|
-
// for the old `require()` API. If we're not in
|
53
|
-
// global object.
|
54
|
-
if (typeof
|
55
|
-
module.exports
|
56
|
-
|
51
|
+
// Export the Underscore object for **Node.js** and **"CommonJS"**, with
|
52
|
+
// backwards-compatibility for the old `require()` API. If we're not in
|
53
|
+
// CommonJS, add `_` to the global object.
|
54
|
+
if (typeof exports !== 'undefined') {
|
55
|
+
if (typeof module !== 'undefined' && module.exports) {
|
56
|
+
exports = module.exports = _;
|
57
|
+
}
|
58
|
+
exports._ = _;
|
59
|
+
} else if (typeof define === 'function' && define.amd) {
|
60
|
+
// Register as a named module with AMD.
|
61
|
+
define('underscore', function() {
|
62
|
+
return _;
|
63
|
+
});
|
57
64
|
} else {
|
58
65
|
// Exported as a string, for Closure Compiler "advanced" mode.
|
59
66
|
root['_'] = _;
|
60
67
|
}
|
61
68
|
|
62
69
|
// Current version.
|
63
|
-
_.VERSION = '1.
|
70
|
+
_.VERSION = '1.2.2';
|
64
71
|
|
65
72
|
// Collection Functions
|
66
73
|
// --------------------
|
@@ -187,7 +194,7 @@
|
|
187
194
|
if (obj == null) return result;
|
188
195
|
if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
|
189
196
|
each(obj, function(value, index, list) {
|
190
|
-
if (result
|
197
|
+
if (result || (result = iterator.call(context, value, index, list))) return breaker;
|
191
198
|
});
|
192
199
|
return !!result;
|
193
200
|
};
|
@@ -198,8 +205,8 @@
|
|
198
205
|
var found = false;
|
199
206
|
if (obj == null) return found;
|
200
207
|
if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
|
201
|
-
any(obj, function(value) {
|
202
|
-
|
208
|
+
found = any(obj, function(value) {
|
209
|
+
return value === target;
|
203
210
|
});
|
204
211
|
return found;
|
205
212
|
};
|
@@ -220,6 +227,7 @@
|
|
220
227
|
// Return the maximum element or (element-based computation).
|
221
228
|
_.max = function(obj, iterator, context) {
|
222
229
|
if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
|
230
|
+
if (!iterator && _.isEmpty(obj)) return -Infinity;
|
223
231
|
var result = {computed : -Infinity};
|
224
232
|
each(obj, function(value, index, list) {
|
225
233
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
@@ -231,6 +239,7 @@
|
|
231
239
|
// Return the minimum element (or element-based computation).
|
232
240
|
_.min = function(obj, iterator, context) {
|
233
241
|
if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
|
242
|
+
if (!iterator && _.isEmpty(obj)) return Infinity;
|
234
243
|
var result = {computed : Infinity};
|
235
244
|
each(obj, function(value, index, list) {
|
236
245
|
var computed = iterator ? iterator.call(context, value, index, list) : value;
|
@@ -239,6 +248,21 @@
|
|
239
248
|
return result.value;
|
240
249
|
};
|
241
250
|
|
251
|
+
// Shuffle an array.
|
252
|
+
_.shuffle = function(obj) {
|
253
|
+
var shuffled = [], rand;
|
254
|
+
each(obj, function(value, index, list) {
|
255
|
+
if (index == 0) {
|
256
|
+
shuffled[0] = value;
|
257
|
+
} else {
|
258
|
+
rand = Math.floor(Math.random() * (index + 1));
|
259
|
+
shuffled[index] = shuffled[rand];
|
260
|
+
shuffled[rand] = value;
|
261
|
+
}
|
262
|
+
});
|
263
|
+
return shuffled;
|
264
|
+
};
|
265
|
+
|
242
266
|
// Sort the object's values by a criterion produced by an iterator.
|
243
267
|
_.sortBy = function(obj, iterator, context) {
|
244
268
|
return _.pluck(_.map(obj, function(value, index, list) {
|
@@ -252,9 +276,11 @@
|
|
252
276
|
}), 'value');
|
253
277
|
};
|
254
278
|
|
255
|
-
// Groups the object's values by a criterion
|
256
|
-
|
279
|
+
// Groups the object's values by a criterion. Pass either a string attribute
|
280
|
+
// to group by, or a function that returns the criterion.
|
281
|
+
_.groupBy = function(obj, val) {
|
257
282
|
var result = {};
|
283
|
+
var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; };
|
258
284
|
each(obj, function(value, index) {
|
259
285
|
var key = iterator(value, index);
|
260
286
|
(result[key] || (result[key] = [])).push(value);
|
@@ -298,6 +324,24 @@
|
|
298
324
|
return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
|
299
325
|
};
|
300
326
|
|
327
|
+
// Returns everything but the last entry of the array. Especcialy useful on
|
328
|
+
// the arguments object. Passing **n** will return all the values in
|
329
|
+
// the array, excluding the last N. The **guard** check allows it to work with
|
330
|
+
// `_.map`.
|
331
|
+
_.initial = function(array, n, guard) {
|
332
|
+
return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
|
333
|
+
};
|
334
|
+
|
335
|
+
// Get the last element of an array. Passing **n** will return the last N
|
336
|
+
// values in the array. The **guard** check allows it to work with `_.map`.
|
337
|
+
_.last = function(array, n, guard) {
|
338
|
+
if ((n != null) && !guard) {
|
339
|
+
return slice.call(array, Math.max(array.length - n, 0));
|
340
|
+
} else {
|
341
|
+
return array[array.length - 1];
|
342
|
+
}
|
343
|
+
};
|
344
|
+
|
301
345
|
// Returns everything but the first entry of the array. Aliased as `tail`.
|
302
346
|
// Especially useful on the arguments object. Passing an **index** will return
|
303
347
|
// the rest of the values in the array from that index onward. The **guard**
|
@@ -306,20 +350,15 @@
|
|
306
350
|
return slice.call(array, (index == null) || guard ? 1 : index);
|
307
351
|
};
|
308
352
|
|
309
|
-
// Get the last element of an array.
|
310
|
-
_.last = function(array) {
|
311
|
-
return array[array.length - 1];
|
312
|
-
};
|
313
|
-
|
314
353
|
// Trim out all falsy values from an array.
|
315
354
|
_.compact = function(array) {
|
316
355
|
return _.filter(array, function(value){ return !!value; });
|
317
356
|
};
|
318
357
|
|
319
358
|
// Return a completely flattened version of an array.
|
320
|
-
_.flatten = function(array) {
|
359
|
+
_.flatten = function(array, shallow) {
|
321
360
|
return _.reduce(array, function(memo, value) {
|
322
|
-
if (_.isArray(value)) return memo.concat(_.flatten(value));
|
361
|
+
if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value));
|
323
362
|
memo[memo.length] = value;
|
324
363
|
return memo;
|
325
364
|
}, []);
|
@@ -349,7 +388,7 @@
|
|
349
388
|
// Produce an array that contains the union: each distinct element from all of
|
350
389
|
// the passed-in arrays.
|
351
390
|
_.union = function() {
|
352
|
-
return _.uniq(_.flatten(arguments));
|
391
|
+
return _.uniq(_.flatten(arguments, true));
|
353
392
|
};
|
354
393
|
|
355
394
|
// Produce an array that contains every item shared between all the
|
@@ -397,7 +436,6 @@
|
|
397
436
|
return -1;
|
398
437
|
};
|
399
438
|
|
400
|
-
|
401
439
|
// Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
|
402
440
|
_.lastIndexOf = function(array, item) {
|
403
441
|
if (array == null) return -1;
|
@@ -432,15 +470,25 @@
|
|
432
470
|
// Function (ahem) Functions
|
433
471
|
// ------------------
|
434
472
|
|
473
|
+
// Reusable constructor function for prototype setting.
|
474
|
+
var ctor = function(){};
|
475
|
+
|
435
476
|
// Create a function bound to a given object (assigning `this`, and arguments,
|
436
477
|
// optionally). Binding with arguments is also known as `curry`.
|
437
478
|
// Delegates to **ECMAScript 5**'s native `Function.bind` if available.
|
438
479
|
// We check for `func.bind` first, to fail fast when `func` is undefined.
|
439
|
-
_.bind = function(func,
|
480
|
+
_.bind = function bind(func, context) {
|
481
|
+
var bound, args;
|
440
482
|
if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
|
441
|
-
|
442
|
-
|
443
|
-
|
483
|
+
if (!_.isFunction(func)) throw new TypeError;
|
484
|
+
args = slice.call(arguments, 2);
|
485
|
+
return bound = function() {
|
486
|
+
if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
|
487
|
+
ctor.prototype = func.prototype;
|
488
|
+
var self = new ctor;
|
489
|
+
var result = func.apply(self, args.concat(slice.call(arguments)));
|
490
|
+
if (Object(result) === result) return result;
|
491
|
+
return self;
|
444
492
|
};
|
445
493
|
};
|
446
494
|
|
@@ -476,31 +524,43 @@
|
|
476
524
|
return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
|
477
525
|
};
|
478
526
|
|
479
|
-
//
|
480
|
-
|
481
|
-
|
527
|
+
// Returns a function, that, when invoked, will only be triggered at most once
|
528
|
+
// during a given window of time.
|
529
|
+
_.throttle = function(func, wait) {
|
530
|
+
var context, args, timeout, throttling, more;
|
531
|
+
var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
|
482
532
|
return function() {
|
483
|
-
|
484
|
-
var
|
533
|
+
context = this; args = arguments;
|
534
|
+
var later = function() {
|
485
535
|
timeout = null;
|
486
|
-
func.apply(context, args);
|
536
|
+
if (more) func.apply(context, args);
|
537
|
+
whenDone();
|
487
538
|
};
|
488
|
-
if (
|
489
|
-
if (
|
539
|
+
if (!timeout) timeout = setTimeout(later, wait);
|
540
|
+
if (throttling) {
|
541
|
+
more = true;
|
542
|
+
} else {
|
543
|
+
func.apply(context, args);
|
544
|
+
}
|
545
|
+
whenDone();
|
546
|
+
throttling = true;
|
490
547
|
};
|
491
548
|
};
|
492
549
|
|
493
|
-
// Returns a function, that, when invoked, will only be triggered at most once
|
494
|
-
// during a given window of time.
|
495
|
-
_.throttle = function(func, wait) {
|
496
|
-
return limit(func, wait, false);
|
497
|
-
};
|
498
|
-
|
499
550
|
// Returns a function, that, as long as it continues to be invoked, will not
|
500
551
|
// be triggered. The function will be called after it stops being called for
|
501
552
|
// N milliseconds.
|
502
553
|
_.debounce = function(func, wait) {
|
503
|
-
|
554
|
+
var timeout;
|
555
|
+
return function() {
|
556
|
+
var context = this, args = arguments;
|
557
|
+
var later = function() {
|
558
|
+
timeout = null;
|
559
|
+
func.apply(context, args);
|
560
|
+
};
|
561
|
+
clearTimeout(timeout);
|
562
|
+
timeout = setTimeout(later, wait);
|
563
|
+
};
|
504
564
|
};
|
505
565
|
|
506
566
|
// Returns a function that will be executed at most one time, no matter how
|
@@ -539,12 +599,12 @@
|
|
539
599
|
|
540
600
|
// Returns a function that will only be executed after being called N times.
|
541
601
|
_.after = function(times, func) {
|
602
|
+
if (times <= 0) return func();
|
542
603
|
return function() {
|
543
604
|
if (--times < 1) { return func.apply(this, arguments); }
|
544
605
|
};
|
545
606
|
};
|
546
607
|
|
547
|
-
|
548
608
|
// Object Functions
|
549
609
|
// ----------------
|
550
610
|
|
@@ -594,6 +654,7 @@
|
|
594
654
|
|
595
655
|
// Create a (shallow-cloned) duplicate of an object.
|
596
656
|
_.clone = function(obj) {
|
657
|
+
if (!_.isObject(obj)) return obj;
|
597
658
|
return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
|
598
659
|
};
|
599
660
|
|
@@ -605,47 +666,103 @@
|
|
605
666
|
return obj;
|
606
667
|
};
|
607
668
|
|
608
|
-
//
|
609
|
-
|
610
|
-
//
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
if (
|
615
|
-
// Basic equality test (watch out for coercions).
|
616
|
-
if (a == b) return true;
|
617
|
-
// One is falsy and the other truthy.
|
618
|
-
if ((!a && b) || (a && !b)) return false;
|
669
|
+
// Internal recursive comparison function.
|
670
|
+
function eq(a, b, stack) {
|
671
|
+
// Identical objects are equal. `0 === -0`, but they aren't identical.
|
672
|
+
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
|
673
|
+
if (a === b) return a !== 0 || 1 / a == 1 / b;
|
674
|
+
// A strict comparison is necessary because `null == undefined`.
|
675
|
+
if (a == null || b == null) return a === b;
|
619
676
|
// Unwrap any wrapped objects.
|
620
677
|
if (a._chain) a = a._wrapped;
|
621
678
|
if (b._chain) b = b._wrapped;
|
622
|
-
//
|
623
|
-
if (a.isEqual) return a.isEqual(b);
|
624
|
-
if (b.isEqual) return b.isEqual(a);
|
625
|
-
//
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
679
|
+
// Invoke a custom `isEqual` method if one is provided.
|
680
|
+
if (_.isFunction(a.isEqual)) return a.isEqual(b);
|
681
|
+
if (_.isFunction(b.isEqual)) return b.isEqual(a);
|
682
|
+
// Compare `[[Class]]` names.
|
683
|
+
var className = toString.call(a);
|
684
|
+
if (className != toString.call(b)) return false;
|
685
|
+
switch (className) {
|
686
|
+
// Strings, numbers, dates, and booleans are compared by value.
|
687
|
+
case '[object String]':
|
688
|
+
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
|
689
|
+
// equivalent to `new String("5")`.
|
690
|
+
return String(a) == String(b);
|
691
|
+
case '[object Number]':
|
692
|
+
a = +a;
|
693
|
+
b = +b;
|
694
|
+
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
|
695
|
+
// other numeric values.
|
696
|
+
return a != a ? b != b : (a == 0 ? 1 / a == 1 / b : a == b);
|
697
|
+
case '[object Date]':
|
698
|
+
case '[object Boolean]':
|
699
|
+
// Coerce dates and booleans to numeric primitive values. Dates are compared by their
|
700
|
+
// millisecond representations. Note that invalid dates with millisecond representations
|
701
|
+
// of `NaN` are not equivalent.
|
702
|
+
return +a == +b;
|
703
|
+
// RegExps are compared by their source patterns and flags.
|
704
|
+
case '[object RegExp]':
|
705
|
+
return a.source == b.source &&
|
706
|
+
a.global == b.global &&
|
707
|
+
a.multiline == b.multiline &&
|
708
|
+
a.ignoreCase == b.ignoreCase;
|
709
|
+
}
|
710
|
+
if (typeof a != 'object' || typeof b != 'object') return false;
|
711
|
+
// Assume equality for cyclic structures. The algorithm for detecting cyclic
|
712
|
+
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
713
|
+
var length = stack.length;
|
714
|
+
while (length--) {
|
715
|
+
// Linear search. Performance is inversely proportional to the number of
|
716
|
+
// unique nested structures.
|
717
|
+
if (stack[length] == a) return true;
|
718
|
+
}
|
719
|
+
// Add the first object to the stack of traversed objects.
|
720
|
+
stack.push(a);
|
721
|
+
var size = 0, result = true;
|
722
|
+
// Recursively compare objects and arrays.
|
723
|
+
if (className == '[object Array]') {
|
724
|
+
// Compare array lengths to determine if a deep comparison is necessary.
|
725
|
+
size = a.length;
|
726
|
+
result = size == b.length;
|
727
|
+
if (result) {
|
728
|
+
// Deep compare the contents, ignoring non-numeric properties.
|
729
|
+
while (size--) {
|
730
|
+
// Ensure commutative equality for sparse arrays.
|
731
|
+
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
|
732
|
+
}
|
733
|
+
}
|
734
|
+
} else {
|
735
|
+
// Objects with different constructors are not equivalent.
|
736
|
+
if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) return false;
|
737
|
+
// Deep compare objects.
|
738
|
+
for (var key in a) {
|
739
|
+
if (hasOwnProperty.call(a, key)) {
|
740
|
+
// Count the expected number of properties.
|
741
|
+
size++;
|
742
|
+
// Deep compare each member.
|
743
|
+
if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
|
744
|
+
}
|
745
|
+
}
|
746
|
+
// Ensure that both objects contain the same number of properties.
|
747
|
+
if (result) {
|
748
|
+
for (key in b) {
|
749
|
+
if (hasOwnProperty.call(b, key) && !(size--)) break;
|
750
|
+
}
|
751
|
+
result = !size;
|
752
|
+
}
|
753
|
+
}
|
754
|
+
// Remove the first object from the stack of traversed objects.
|
755
|
+
stack.pop();
|
756
|
+
return result;
|
757
|
+
}
|
758
|
+
|
759
|
+
// Perform a deep comparison to check if two objects are equal.
|
760
|
+
_.isEqual = function(a, b) {
|
761
|
+
return eq(a, b, []);
|
646
762
|
};
|
647
763
|
|
648
|
-
// Is a given array or object empty?
|
764
|
+
// Is a given array, string, or object empty?
|
765
|
+
// An "empty" object has no enumerable own-properties.
|
649
766
|
_.isEmpty = function(obj) {
|
650
767
|
if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
|
651
768
|
for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
|
@@ -660,7 +777,7 @@
|
|
660
777
|
// Is a given value an array?
|
661
778
|
// Delegates to ECMA5's native Array.isArray
|
662
779
|
_.isArray = nativeIsArray || function(obj) {
|
663
|
-
return toString.call(obj)
|
780
|
+
return toString.call(obj) == '[object Array]';
|
664
781
|
};
|
665
782
|
|
666
783
|
// Is a given variable an object?
|
@@ -669,44 +786,50 @@
|
|
669
786
|
};
|
670
787
|
|
671
788
|
// Is a given variable an arguments object?
|
672
|
-
|
673
|
-
|
674
|
-
|
789
|
+
if (toString.call(arguments) == '[object Arguments]') {
|
790
|
+
_.isArguments = function(obj) {
|
791
|
+
return toString.call(obj) == '[object Arguments]';
|
792
|
+
};
|
793
|
+
} else {
|
794
|
+
_.isArguments = function(obj) {
|
795
|
+
return !!(obj && hasOwnProperty.call(obj, 'callee'));
|
796
|
+
};
|
797
|
+
}
|
675
798
|
|
676
799
|
// Is a given value a function?
|
677
800
|
_.isFunction = function(obj) {
|
678
|
-
return
|
801
|
+
return toString.call(obj) == '[object Function]';
|
679
802
|
};
|
680
803
|
|
681
804
|
// Is a given value a string?
|
682
805
|
_.isString = function(obj) {
|
683
|
-
return
|
806
|
+
return toString.call(obj) == '[object String]';
|
684
807
|
};
|
685
808
|
|
686
809
|
// Is a given value a number?
|
687
810
|
_.isNumber = function(obj) {
|
688
|
-
return
|
811
|
+
return toString.call(obj) == '[object Number]';
|
689
812
|
};
|
690
813
|
|
691
|
-
// Is the given value `NaN`?
|
692
|
-
// that does not equal itself.
|
814
|
+
// Is the given value `NaN`?
|
693
815
|
_.isNaN = function(obj) {
|
816
|
+
// `NaN` is the only value for which `===` is not reflexive.
|
694
817
|
return obj !== obj;
|
695
818
|
};
|
696
819
|
|
697
820
|
// Is a given value a boolean?
|
698
821
|
_.isBoolean = function(obj) {
|
699
|
-
return obj === true || obj === false;
|
822
|
+
return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
|
700
823
|
};
|
701
824
|
|
702
825
|
// Is a given value a date?
|
703
826
|
_.isDate = function(obj) {
|
704
|
-
return
|
827
|
+
return toString.call(obj) == '[object Date]';
|
705
828
|
};
|
706
829
|
|
707
830
|
// Is the given value a regular expression?
|
708
831
|
_.isRegExp = function(obj) {
|
709
|
-
return
|
832
|
+
return toString.call(obj) == '[object RegExp]';
|
710
833
|
};
|
711
834
|
|
712
835
|
// Is a given value equal to null?
|
@@ -739,6 +862,11 @@
|
|
739
862
|
for (var i = 0; i < n; i++) iterator.call(context, i);
|
740
863
|
};
|
741
864
|
|
865
|
+
// Escape a string for HTML interpolation.
|
866
|
+
_.escape = function(string) {
|
867
|
+
return (''+string).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/');
|
868
|
+
};
|
869
|
+
|
742
870
|
// Add your own custom functions to the Underscore object, ensuring that
|
743
871
|
// they're correctly added to the OOP wrapper as well.
|
744
872
|
_.mixin = function(obj) {
|
@@ -759,7 +887,8 @@
|
|
759
887
|
// following template settings to use alternative delimiters.
|
760
888
|
_.templateSettings = {
|
761
889
|
evaluate : /<%([\s\S]+?)%>/g,
|
762
|
-
interpolate : /<%=([\s\S]+?)%>/g
|
890
|
+
interpolate : /<%=([\s\S]+?)%>/g,
|
891
|
+
escape : /<%-([\s\S]+?)%>/g
|
763
892
|
};
|
764
893
|
|
765
894
|
// JavaScript micro-templating, similar to John Resig's implementation.
|
@@ -771,19 +900,22 @@
|
|
771
900
|
'with(obj||{}){__p.push(\'' +
|
772
901
|
str.replace(/\\/g, '\\\\')
|
773
902
|
.replace(/'/g, "\\'")
|
903
|
+
.replace(c.escape, function(match, code) {
|
904
|
+
return "',_.escape(" + code.replace(/\\'/g, "'") + "),'";
|
905
|
+
})
|
774
906
|
.replace(c.interpolate, function(match, code) {
|
775
907
|
return "'," + code.replace(/\\'/g, "'") + ",'";
|
776
908
|
})
|
777
909
|
.replace(c.evaluate || null, function(match, code) {
|
778
910
|
return "');" + code.replace(/\\'/g, "'")
|
779
|
-
.replace(/[\r\n\t]/g, ' ') + "__p.push('";
|
911
|
+
.replace(/[\r\n\t]/g, ' ') + ";__p.push('";
|
780
912
|
})
|
781
913
|
.replace(/\r/g, '\\r')
|
782
914
|
.replace(/\n/g, '\\n')
|
783
915
|
.replace(/\t/g, '\\t')
|
784
916
|
+ "');}return __p.join('');";
|
785
|
-
var func = new Function('obj', tmpl);
|
786
|
-
return data ? func(data) : func;
|
917
|
+
var func = new Function('obj', '_', tmpl);
|
918
|
+
return data ? func(data, _) : function(data) { return func(data, _) };
|
787
919
|
};
|
788
920
|
|
789
921
|
// The OOP Wrapper
|
@@ -842,4 +974,4 @@
|
|
842
974
|
return this._wrapped;
|
843
975
|
};
|
844
976
|
|
845
|
-
})();
|
977
|
+
}).call(this);
|
metadata
CHANGED
@@ -1,62 +1,58 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-backbone
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.5
|
4
5
|
prerelease:
|
5
|
-
version: 0.5.4
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Ryan Fitzgerald
|
9
9
|
- Code Brew Studios
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
dependencies:
|
17
|
-
- !ruby/object:Gem::Dependency
|
13
|
+
date: 2011-11-27 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
18
16
|
name: rails
|
19
|
-
requirement: &
|
17
|
+
requirement: &70162401622700 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
19
|
+
requirements:
|
22
20
|
- - ~>
|
23
|
-
- !ruby/object:Gem::Version
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 3.1.0
|
25
23
|
type: :runtime
|
26
24
|
prerelease: false
|
27
|
-
version_requirements: *
|
28
|
-
- !ruby/object:Gem::Dependency
|
25
|
+
version_requirements: *70162401622700
|
26
|
+
- !ruby/object:Gem::Dependency
|
29
27
|
name: coffee-script
|
30
|
-
requirement: &
|
28
|
+
requirement: &70162401622140 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
30
|
+
requirements:
|
33
31
|
- - ~>
|
34
|
-
- !ruby/object:Gem::Version
|
32
|
+
- !ruby/object:Gem::Version
|
35
33
|
version: 2.2.0
|
36
34
|
type: :runtime
|
37
35
|
prerelease: false
|
38
|
-
version_requirements: *
|
39
|
-
- !ruby/object:Gem::Dependency
|
36
|
+
version_requirements: *70162401622140
|
37
|
+
- !ruby/object:Gem::Dependency
|
40
38
|
name: ejs
|
41
|
-
requirement: &
|
39
|
+
requirement: &70162401501620 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
41
|
+
requirements:
|
44
42
|
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
43
|
+
- !ruby/object:Gem::Version
|
46
44
|
version: 1.0.0
|
47
45
|
type: :runtime
|
48
46
|
prerelease: false
|
49
|
-
version_requirements: *
|
50
|
-
description: Quickly setup backbone.js for use with rails 3.1. Generators are provided
|
51
|
-
|
47
|
+
version_requirements: *70162401501620
|
48
|
+
description: Quickly setup backbone.js for use with rails 3.1. Generators are provided
|
49
|
+
to quickly get started.
|
50
|
+
email:
|
52
51
|
- ryan@codebrewstudios.com
|
53
52
|
executables: []
|
54
|
-
|
55
53
|
extensions: []
|
56
|
-
|
57
54
|
extra_rdoc_files: []
|
58
|
-
|
59
|
-
files:
|
55
|
+
files:
|
60
56
|
- lib/backbone-rails.rb
|
61
57
|
- lib/generators/backbone/install/install_generator.rb
|
62
58
|
- lib/generators/backbone/install/templates/app.coffee
|
@@ -89,36 +85,34 @@ files:
|
|
89
85
|
- MIT-LICENSE
|
90
86
|
- Rakefile
|
91
87
|
- README.md
|
92
|
-
has_rdoc: true
|
93
88
|
homepage: http://github.com/codebrew/backbone-rails
|
94
89
|
licenses: []
|
95
|
-
|
96
90
|
post_install_message:
|
97
91
|
rdoc_options: []
|
98
|
-
|
99
|
-
require_paths:
|
92
|
+
require_paths:
|
100
93
|
- lib
|
101
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
95
|
none: false
|
103
|
-
requirements:
|
104
|
-
- -
|
105
|
-
- !ruby/object:Gem::Version
|
106
|
-
|
107
|
-
segments:
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
segments:
|
108
101
|
- 0
|
109
|
-
|
110
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
hash: 1776603317908361039
|
103
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
104
|
none: false
|
112
|
-
requirements:
|
113
|
-
- -
|
114
|
-
- !ruby/object:Gem::Version
|
115
|
-
version:
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
segments:
|
110
|
+
- 0
|
111
|
+
hash: 1776603317908361039
|
116
112
|
requirements: []
|
117
|
-
|
118
113
|
rubyforge_project:
|
119
|
-
rubygems_version: 1.
|
114
|
+
rubygems_version: 1.8.11
|
120
115
|
signing_key:
|
121
116
|
specification_version: 3
|
122
117
|
summary: Use backbone.js with rails 3.1
|
123
118
|
test_files: []
|
124
|
-
|