laces 0.1.0
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/CONTRIBUTING.md +38 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +122 -0
- data/LICENSE +21 -0
- data/README.md +5 -0
- data/Rakefile +8 -0
- data/bin/laces +16 -0
- data/features/creating_a_heroku_app.feature +9 -0
- data/features/rake_clean.feature +21 -0
- data/features/skipping_clearance.feature +13 -0
- data/features/step_definitions/gem_steps.rb +5 -0
- data/features/step_definitions/heroku_steps.rb +3 -0
- data/features/step_definitions/shell_steps.rb +55 -0
- data/features/support/bin/heroku +5 -0
- data/features/support/env.rb +15 -0
- data/features/support/fake_heroku.rb +21 -0
- data/laces-0.0.1.gem +0 -0
- data/laces.gemspec +35 -0
- data/lib/laces/actions.rb +35 -0
- data/lib/laces/app_builder.rb +237 -0
- data/lib/laces/generators/app_generator.rb +111 -0
- data/lib/laces/version.rb +3 -0
- data/templates/.DS_Store +0 -0
- data/templates/Gemfile_template +76 -0
- data/templates/HEROKU_README.md +66 -0
- data/templates/Procfile +1 -0
- data/templates/README.md +81 -0
- data/templates/app/assets/imgs/glyphicons-halflings-white.png +0 -0
- data/templates/app/assets/imgs/glyphicons-halflings.png +0 -0
- data/templates/app/assets/javascripts/admin.coffee +20 -0
- data/templates/app/assets/javascripts/application.coffee +21 -0
- data/templates/app/assets/javascripts/lib/actinology.coffee +47 -0
- data/templates/app/assets/javascripts/lib/analytics.js +11 -0
- data/templates/app/assets/javascripts/lib/auth_token_sync.js +17 -0
- data/templates/app/assets/javascripts/lib/backbone-ui.js +2455 -0
- data/templates/app/assets/javascripts/lib/backbone.coffee +27 -0
- data/templates/app/assets/javascripts/lib/backbone/collection.js +249 -0
- data/templates/app/assets/javascripts/lib/backbone/events.js +64 -0
- data/templates/app/assets/javascripts/lib/backbone/helpers.js +68 -0
- data/templates/app/assets/javascripts/lib/backbone/history.js +144 -0
- data/templates/app/assets/javascripts/lib/backbone/model.js +291 -0
- data/templates/app/assets/javascripts/lib/backbone/router.coffee +45 -0
- data/templates/app/assets/javascripts/lib/backbone/sync.coffee +38 -0
- data/templates/app/assets/javascripts/lib/backbone/view.js +150 -0
- data/templates/app/assets/javascripts/lib/backbone_extended.coffee +276 -0
- data/templates/app/assets/javascripts/lib/bootstrap.js +1836 -0
- data/templates/app/assets/javascripts/lib/inflection.js +658 -0
- data/templates/app/assets/javascripts/lib/jquery-ui.js +343 -0
- data/templates/app/assets/javascripts/lib/jquery.hotkeys.js +102 -0
- data/templates/app/assets/javascripts/lib/jquery.js +4 -0
- data/templates/app/assets/javascripts/lib/milk.js.coffee +265 -0
- data/templates/app/assets/javascripts/lib/raw.js +143 -0
- data/templates/app/assets/javascripts/lib/strftime.js +732 -0
- data/templates/app/assets/javascripts/lib/throttle-debounce.js +251 -0
- data/templates/app/assets/javascripts/lib/timeago.js +148 -0
- data/templates/app/assets/javascripts/lib/underscore.js +28 -0
- data/templates/app/assets/styles/application.sass +21 -0
- data/templates/app/assets/styles/layouts/default.sass +15 -0
- data/templates/app/assets/styles/layouts/footer.sass +0 -0
- data/templates/app/assets/styles/layouts/forms.sass +34 -0
- data/templates/app/assets/styles/layouts/header.sass +0 -0
- data/templates/app/assets/styles/layouts/navigation.sass +0 -0
- data/templates/app/assets/styles/lib/backbone-ui.css +580 -0
- data/templates/app/assets/styles/lib/bootstrap.sass +4248 -0
- data/templates/app/assets/styles/pages/home.sass +0 -0
- data/templates/app/assets/styles/sessions/new.sass +0 -0
- data/templates/app/assets/styles/users/activate.sass +0 -0
- data/templates/app/assets/styles/users/new.sass +0 -0
- data/templates/app/assets/styles/users/suspended.sass +0 -0
- data/templates/app/controllers/app_controller.rb +14 -0
- data/templates/app/controllers/pages_controller.rb +2 -0
- data/templates/app/controllers/sessions_controller.rb +2 -0
- data/templates/app/controllers/templating_controller.rb +31 -0
- data/templates/app/controllers/users_controller.rb +2 -0
- data/templates/app/helpers/app_helper.rb +94 -0
- data/templates/app/helpers/users_helper.rb +53 -0
- data/templates/app/models/user.rb +9 -0
- data/templates/app/views/devise/confirmations/new.haml +9 -0
- data/templates/app/views/devise/passwords/edit.haml +11 -0
- data/templates/app/views/devise/passwords/new.haml +9 -0
- data/templates/app/views/devise/registrations/edit.haml +13 -0
- data/templates/app/views/devise/registrations/new.haml +8 -0
- data/templates/app/views/devise/sessions/_form.haml +7 -0
- data/templates/app/views/devise/sessions/new.haml +5 -0
- data/templates/app/views/devise/unlocks/new.haml +7 -0
- data/templates/app/views/layouts/_ascii.haml +0 -0
- data/templates/app/views/layouts/_column.haml +0 -0
- data/templates/app/views/layouts/_content.haml +1 -0
- data/templates/app/views/layouts/_extra.haml +0 -0
- data/templates/app/views/layouts/_footer.haml +9 -0
- data/templates/app/views/layouts/_head.haml +13 -0
- data/templates/app/views/layouts/_header.haml +6 -0
- data/templates/app/views/layouts/application.html.haml +16 -0
- data/templates/app/views/pages/home.haml +1 -0
- data/templates/config/app.yml +29 -0
- data/templates/config/application.erb +28 -0
- data/templates/config/database.yml +32 -0
- data/templates/config/initializers/devise.rb +232 -0
- data/templates/config/initializers/rabl_init.rb +4 -0
- data/templates/config/initializers/setup_mail.rb +13 -0
- data/templates/config/initializers/wrap_parameters.rb +12 -0
- data/templates/db/migrate/user_migration.rb +36 -0
- data/templates/laces_gitignore +9 -0
- data/templates/lib/development_mail_interceptor.rb +7 -0
- data/templates/lib/templating.rb +40 -0
- metadata +225 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// Backbone.Model
|
|
2
|
+
// --------------
|
|
3
|
+
|
|
4
|
+
// Create a new model, with defined attributes. A client id (`cid`)
|
|
5
|
+
// is automatically generated and assigned for you.
|
|
6
|
+
Backbone.Model = function(attributes, options) {
|
|
7
|
+
var defaults;
|
|
8
|
+
attributes || (attributes = {});
|
|
9
|
+
if (defaults = this.defaults) {
|
|
10
|
+
if (_.isFunction(defaults)) defaults = defaults.call(this);
|
|
11
|
+
attributes = _.extend({}, defaults, attributes);
|
|
12
|
+
}
|
|
13
|
+
this.attributes = {};
|
|
14
|
+
this._escapedAttributes = {};
|
|
15
|
+
this.cid = _.uniqueId('c');
|
|
16
|
+
this.set(attributes, {silent : true});
|
|
17
|
+
this._changed = false;
|
|
18
|
+
this._previousAttributes = _.clone(this.attributes);
|
|
19
|
+
if (options && options.collection) this.collection = options.collection;
|
|
20
|
+
this.initialize(attributes, options);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// Attach all inheritable methods to the Model prototype.
|
|
24
|
+
_.extend(Backbone.Model.prototype, Backbone.Events, {
|
|
25
|
+
|
|
26
|
+
// Has the item been changed since the last `"change"` event?
|
|
27
|
+
_changed : false,
|
|
28
|
+
|
|
29
|
+
// The default name for the JSON `id` attribute is `"id"`. MongoDB and
|
|
30
|
+
// CouchDB users may want to set this to `"_id"`.
|
|
31
|
+
idAttribute : 'id',
|
|
32
|
+
|
|
33
|
+
// Initialize is an empty function by default. Override it with your own
|
|
34
|
+
// initialization logic.
|
|
35
|
+
initialize : function(){},
|
|
36
|
+
|
|
37
|
+
// Return a copy of the model's `attributes` object.
|
|
38
|
+
toJSON : function() {
|
|
39
|
+
return _.clone(this.attributes);
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
// Get the value of an attribute.
|
|
43
|
+
get : function(attr) {
|
|
44
|
+
return this.attributes[attr];
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Get the HTML-escaped value of an attribute.
|
|
48
|
+
escape : function(attr) {
|
|
49
|
+
var html;
|
|
50
|
+
if (html = this._escapedAttributes[attr]) return html;
|
|
51
|
+
var val = this.attributes[attr];
|
|
52
|
+
return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val);
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
// Returns `true` if the attribute contains a value that is not null
|
|
56
|
+
// or undefined.
|
|
57
|
+
has : function(attr) {
|
|
58
|
+
return this.attributes[attr] != null;
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// Set a hash of model attributes on the object, firing `"change"` unless you
|
|
62
|
+
// choose to silence it.
|
|
63
|
+
set : function(attrs, options) {
|
|
64
|
+
|
|
65
|
+
// Extract attributes and options.
|
|
66
|
+
options || (options = {});
|
|
67
|
+
if (!attrs) return this;
|
|
68
|
+
if (attrs.attributes) attrs = attrs.attributes;
|
|
69
|
+
var now = this.attributes, escaped = this._escapedAttributes;
|
|
70
|
+
|
|
71
|
+
// Run validation.
|
|
72
|
+
if (!options.silent && this.validate && !this._performValidation(attrs, options)) return false;
|
|
73
|
+
|
|
74
|
+
// Check for changes of `id`.
|
|
75
|
+
if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
|
|
76
|
+
|
|
77
|
+
// We're about to start triggering change events.
|
|
78
|
+
var alreadyChanging = this._changing;
|
|
79
|
+
this._changing = true;
|
|
80
|
+
|
|
81
|
+
// Update attributes.
|
|
82
|
+
for (var attr in attrs) {
|
|
83
|
+
var val = attrs[attr];
|
|
84
|
+
if (!_.isEqual(now[attr], val)) {
|
|
85
|
+
now[attr] = val;
|
|
86
|
+
delete escaped[attr];
|
|
87
|
+
this._changed = true;
|
|
88
|
+
if (!options.silent) this.trigger('change:' + attr, this, val, options);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Fire the `"change"` event, if the model has been changed.
|
|
93
|
+
if (!alreadyChanging && !options.silent && this._changed) this.change(options);
|
|
94
|
+
this._changing = false;
|
|
95
|
+
return this;
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
// Remove an attribute from the model, firing `"change"` unless you choose
|
|
99
|
+
// to silence it. `unset` is a noop if the attribute doesn't exist.
|
|
100
|
+
unset : function(attr, options) {
|
|
101
|
+
if (!(attr in this.attributes)) return this;
|
|
102
|
+
options || (options = {});
|
|
103
|
+
var value = this.attributes[attr];
|
|
104
|
+
|
|
105
|
+
// Run validation.
|
|
106
|
+
var validObj = {};
|
|
107
|
+
validObj[attr] = void 0;
|
|
108
|
+
if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
|
|
109
|
+
|
|
110
|
+
// changedAttributes needs to know if an attribute has been unset.
|
|
111
|
+
(this._unsetAttributes || (this._unsetAttributes = [])).push(attr);
|
|
112
|
+
|
|
113
|
+
// Remove the attribute.
|
|
114
|
+
delete this.attributes[attr];
|
|
115
|
+
delete this._escapedAttributes[attr];
|
|
116
|
+
if (attr == this.idAttribute) delete this.id;
|
|
117
|
+
this._changed = true;
|
|
118
|
+
if (!options.silent) {
|
|
119
|
+
this.trigger('change:' + attr, this, void 0, options);
|
|
120
|
+
this.change(options);
|
|
121
|
+
}
|
|
122
|
+
return this;
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
// Clear all attributes on the model, firing `"change"` unless you choose
|
|
126
|
+
// to silence it.
|
|
127
|
+
clear : function(options) {
|
|
128
|
+
options || (options = {});
|
|
129
|
+
var attr;
|
|
130
|
+
var old = this.attributes;
|
|
131
|
+
|
|
132
|
+
// Run validation.
|
|
133
|
+
var validObj = {};
|
|
134
|
+
for (attr in old) validObj[attr] = void 0;
|
|
135
|
+
if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
|
|
136
|
+
|
|
137
|
+
this.attributes = {};
|
|
138
|
+
this._escapedAttributes = {};
|
|
139
|
+
this._changed = true;
|
|
140
|
+
if (!options.silent) {
|
|
141
|
+
for (attr in old) {
|
|
142
|
+
this.trigger('change:' + attr, this, void 0, options);
|
|
143
|
+
}
|
|
144
|
+
this.change(options);
|
|
145
|
+
}
|
|
146
|
+
return this;
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
// Fetch the model from the server. If the server's representation of the
|
|
150
|
+
// model differs from its current attributes, they will be overriden,
|
|
151
|
+
// triggering a `"change"` event.
|
|
152
|
+
fetch : function(options) {
|
|
153
|
+
options || (options = {});
|
|
154
|
+
var model = this;
|
|
155
|
+
var success = options.success;
|
|
156
|
+
options.success = function(resp, status, xhr) {
|
|
157
|
+
if (!model.set(model.parse(resp, xhr), options)) return false;
|
|
158
|
+
if (success) success(model, resp);
|
|
159
|
+
};
|
|
160
|
+
options.error = wrapError(options.error, model, options);
|
|
161
|
+
return (this.sync || Backbone.sync).call(this, 'read', this, options);
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// Set a hash of model attributes, and sync the model to the server.
|
|
165
|
+
// If the server returns an attributes hash that differs, the model's
|
|
166
|
+
// state will be `set` again.
|
|
167
|
+
save : function(attrs, options) {
|
|
168
|
+
options || (options = {});
|
|
169
|
+
if (attrs && !this.set(attrs, options)) return false;
|
|
170
|
+
var model = this;
|
|
171
|
+
var success = options.success;
|
|
172
|
+
options.success = function(resp, status, xhr) {
|
|
173
|
+
if (!model.set(model.parse(resp, xhr), options)) return false;
|
|
174
|
+
if (success) success(model, resp, xhr);
|
|
175
|
+
};
|
|
176
|
+
options.error = wrapError(options.error, model, options);
|
|
177
|
+
var method = this.isNew() ? 'create' : 'update';
|
|
178
|
+
return (this.sync || Backbone.sync).call(this, method, this, options);
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
// Destroy this model on the server if it was already persisted. Upon success, the model is removed
|
|
182
|
+
// from its collection, if it has one.
|
|
183
|
+
destroy : function(options) {
|
|
184
|
+
options || (options = {});
|
|
185
|
+
if (this.isNew()) return this.trigger('destroy', this, this.collection, options);
|
|
186
|
+
var model = this;
|
|
187
|
+
var success = options.success;
|
|
188
|
+
options.success = function(resp) {
|
|
189
|
+
model.trigger('destroy', model, model.collection, options);
|
|
190
|
+
if (success) success(model, resp);
|
|
191
|
+
};
|
|
192
|
+
options.error = wrapError(options.error, model, options);
|
|
193
|
+
return (this.sync || Backbone.sync).call(this, 'delete', this, options);
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
// Default URL for the model's representation on the server -- if you're
|
|
197
|
+
// using Backbone's restful methods, override this to change the endpoint
|
|
198
|
+
// that will be called.
|
|
199
|
+
url : function() {
|
|
200
|
+
var base = getUrl(this.collection) || this.urlRoot || urlError();
|
|
201
|
+
if (this.isNew()) return base;
|
|
202
|
+
return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
// **parse** converts a response into the hash of attributes to be `set` on
|
|
206
|
+
// the model. The default implementation is just to pass the response along.
|
|
207
|
+
parse : function(resp, xhr) {
|
|
208
|
+
return resp;
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
// Create a new model with identical attributes to this one.
|
|
212
|
+
clone : function() {
|
|
213
|
+
return new this.constructor(this);
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
// A model is new if it has never been saved to the server, and lacks an id.
|
|
217
|
+
isNew : function() {
|
|
218
|
+
return this.id == null;
|
|
219
|
+
},
|
|
220
|
+
|
|
221
|
+
// Call this method to manually fire a `change` event for this model.
|
|
222
|
+
// Calling this will cause all objects observing the model to update.
|
|
223
|
+
change : function(options) {
|
|
224
|
+
this.trigger('change', this, options);
|
|
225
|
+
this._previousAttributes = _.clone(this.attributes);
|
|
226
|
+
this._unsetAttributes = null;
|
|
227
|
+
this._changed = false;
|
|
228
|
+
},
|
|
229
|
+
|
|
230
|
+
// Determine if the model has changed since the last `"change"` event.
|
|
231
|
+
// If you specify an attribute name, determine if that attribute has changed.
|
|
232
|
+
hasChanged : function(attr) {
|
|
233
|
+
if (attr) return this._previousAttributes[attr] != this.attributes[attr];
|
|
234
|
+
return this._changed;
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// Return an object containing all the attributes that have changed, or false
|
|
238
|
+
// if there are no changed attributes. Useful for determining what parts of a
|
|
239
|
+
// view need to be updated and/or what attributes need to be persisted to
|
|
240
|
+
// the server. Unset attributes will be set to undefined.
|
|
241
|
+
changedAttributes : function(now) {
|
|
242
|
+
now || (now = this.attributes);
|
|
243
|
+
var old = this._previousAttributes, unset = this._unsetAttributes;
|
|
244
|
+
|
|
245
|
+
var changed = false;
|
|
246
|
+
for (var attr in now) {
|
|
247
|
+
if (!_.isEqual(old[attr], now[attr])) {
|
|
248
|
+
changed || (changed = {});
|
|
249
|
+
changed[attr] = now[attr];
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (unset) {
|
|
254
|
+
changed || (changed = {});
|
|
255
|
+
var len = unset.length;
|
|
256
|
+
while (len--) changed[unset[len]] = void 0;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return changed;
|
|
260
|
+
},
|
|
261
|
+
|
|
262
|
+
// Get the previous value of an attribute, recorded at the time the last
|
|
263
|
+
// `"change"` event was fired.
|
|
264
|
+
previous : function(attr) {
|
|
265
|
+
if (!attr || !this._previousAttributes) return null;
|
|
266
|
+
return this._previousAttributes[attr];
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
// Get all of the attributes of the model at the time of the previous
|
|
270
|
+
// `"change"` event.
|
|
271
|
+
previousAttributes : function() {
|
|
272
|
+
return _.clone(this._previousAttributes);
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// Run validation against a set of incoming attributes, returning `true`
|
|
276
|
+
// if all is well. If a specific `error` callback has been passed,
|
|
277
|
+
// call that instead of firing the general `"error"` event.
|
|
278
|
+
_performValidation : function(attrs, options) {
|
|
279
|
+
var error = this.validate(attrs);
|
|
280
|
+
if (error) {
|
|
281
|
+
if (options.error) {
|
|
282
|
+
options.error(this, error, options);
|
|
283
|
+
} else {
|
|
284
|
+
this.trigger('error', this, error, options);
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
Backbone.Router = (options) ->
|
|
2
|
+
options or (options = {})
|
|
3
|
+
@routes = options.routes if options.routes
|
|
4
|
+
@_bindRoutes()
|
|
5
|
+
@initialize.apply this, arguments
|
|
6
|
+
|
|
7
|
+
namedParam = /:([\w\d]+)/g
|
|
8
|
+
splatParam = /\*([\w\d]+)/g
|
|
9
|
+
escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g
|
|
10
|
+
_.extend Backbone.Router::, Backbone.Events,
|
|
11
|
+
initialize: ->
|
|
12
|
+
route: (route, name, callback) ->
|
|
13
|
+
Backbone.history or (Backbone.history = new Backbone.History)
|
|
14
|
+
route = @_routeToRegExp route unless _.isRegExp(route)
|
|
15
|
+
Backbone.history.route route, _.bind((fragment) ->
|
|
16
|
+
args = @_extractParameters(route, fragment)
|
|
17
|
+
callback and callback.apply(this, args)
|
|
18
|
+
@trigger.apply this, [ "route:" + name ].concat(args)
|
|
19
|
+
, this)
|
|
20
|
+
|
|
21
|
+
navigate: (fragment, triggerRoute) ->
|
|
22
|
+
Backbone.history.navigate fragment, triggerRoute
|
|
23
|
+
|
|
24
|
+
_bindRoutes: ->
|
|
25
|
+
return unless @routes
|
|
26
|
+
routes = []
|
|
27
|
+
for route of @routes
|
|
28
|
+
routes.unshift [ route, @routes[route] ]
|
|
29
|
+
i = 0
|
|
30
|
+
l = routes.length
|
|
31
|
+
|
|
32
|
+
while i < l
|
|
33
|
+
@route routes[i][0],
|
|
34
|
+
routes[i][1],
|
|
35
|
+
this[routes[i][1]]
|
|
36
|
+
i++
|
|
37
|
+
|
|
38
|
+
_routeToRegExp: (route) ->
|
|
39
|
+
route = route.replace escapeRegExp, "\\$&"
|
|
40
|
+
route = route.replace namedParam , "([^/]*)"
|
|
41
|
+
route = route.replace splatParam , "(.*?)"
|
|
42
|
+
new RegExp("^" + route + "$")
|
|
43
|
+
|
|
44
|
+
_extractParameters: (route, fragment) ->
|
|
45
|
+
route.exec(fragment).slice 1
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Backbone.sync = (method, model, options) ->
|
|
2
|
+
type = methodMap[method]
|
|
3
|
+
params =
|
|
4
|
+
type: type
|
|
5
|
+
dataType: "json"
|
|
6
|
+
|
|
7
|
+
params.url = getUrl(model) or urlError() unless options.url
|
|
8
|
+
|
|
9
|
+
if not options.data and model and (method is 'create' or method is 'update')
|
|
10
|
+
extra = options.extra
|
|
11
|
+
data = model.toJSON()
|
|
12
|
+
data = _.extend data, extra unless extra is undefined
|
|
13
|
+
params.contentType = "application/json"
|
|
14
|
+
params.data = JSON.stringify data
|
|
15
|
+
|
|
16
|
+
if method is 'delete'
|
|
17
|
+
param = $("meta[name= 'csrf-param']").attr 'content'
|
|
18
|
+
token = $("meta[name= 'csrf-token']").attr 'content'
|
|
19
|
+
data = authenticity_token: token
|
|
20
|
+
params.contentType = 'application/json'
|
|
21
|
+
params.data = JSON.stringify data
|
|
22
|
+
|
|
23
|
+
emulate_json = Backbone.emulateJSON
|
|
24
|
+
if emulate_json
|
|
25
|
+
params.contentType = 'application/x-www-form-urlencoded'
|
|
26
|
+
params.data = if params.data then model: params.data else {}
|
|
27
|
+
|
|
28
|
+
if Backbone.emulateHTTP
|
|
29
|
+
if type is 'PUT' or type is 'DELETE'
|
|
30
|
+
params.data._method = type if emulate_json
|
|
31
|
+
params.type = 'POST'
|
|
32
|
+
params.beforeSend = (xhr) -> xhr.setRequestHeader "X-HTTP-Method-Override", type
|
|
33
|
+
|
|
34
|
+
if params.type isnt 'GET' and not emulate_json
|
|
35
|
+
params.processData = false
|
|
36
|
+
|
|
37
|
+
params = _.extend params, options
|
|
38
|
+
$.ajax params
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Backbone.View
|
|
2
|
+
// -------------
|
|
3
|
+
|
|
4
|
+
// Creating a Backbone.View creates its initial element outside of the DOM,
|
|
5
|
+
// if an existing element is not provided...
|
|
6
|
+
Backbone.View = function(options) {
|
|
7
|
+
this.cid = _.uniqueId('view');
|
|
8
|
+
this._configure(options || {});
|
|
9
|
+
this._ensureElement();
|
|
10
|
+
this.delegateEvents();
|
|
11
|
+
this.initialize.apply(this, arguments);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// Element lookup, scoped to DOM elements within the current view.
|
|
15
|
+
// This should be prefered to global lookups, if you're dealing with
|
|
16
|
+
// a specific view.
|
|
17
|
+
var selectorDelegate = function(selector) {
|
|
18
|
+
return $(selector, this.el);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Cached regex to split keys for `delegate`.
|
|
22
|
+
var eventSplitter = /^(\S+)\s*(.*)$/;
|
|
23
|
+
|
|
24
|
+
// List of view options to be merged as properties.
|
|
25
|
+
var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
|
|
26
|
+
|
|
27
|
+
// Set up all inheritable **Backbone.View** properties and methods.
|
|
28
|
+
_.extend(Backbone.View.prototype, Backbone.Events, {
|
|
29
|
+
|
|
30
|
+
// The default `tagName` of a View's element is `"div"`.
|
|
31
|
+
tagName : 'div',
|
|
32
|
+
|
|
33
|
+
// Attach the `selectorDelegate` function as the `$` property.
|
|
34
|
+
$ : selectorDelegate,
|
|
35
|
+
|
|
36
|
+
// Initialize is an empty function by default. Override it with your own
|
|
37
|
+
// initialization logic.
|
|
38
|
+
initialize : function(){},
|
|
39
|
+
|
|
40
|
+
// **render** is the core function that your view should override, in order
|
|
41
|
+
// to populate its element (`this.el`), with the appropriate HTML. The
|
|
42
|
+
// convention is for **render** to always return `this`.
|
|
43
|
+
render : function() {
|
|
44
|
+
return this;
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
// Remove this view from the DOM. Note that the view isn't present in the
|
|
48
|
+
// DOM by default, so calling this method may be a no-op.
|
|
49
|
+
remove : function() {
|
|
50
|
+
$(this.el).remove();
|
|
51
|
+
return this;
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
// For small amounts of DOM Elements, where a full-blown template isn't
|
|
55
|
+
// needed, use **make** to manufacture elements, one at a time.
|
|
56
|
+
//
|
|
57
|
+
// var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
|
|
58
|
+
//
|
|
59
|
+
make : function(tagName, attributes, content) {
|
|
60
|
+
var el = document.createElement(tagName);
|
|
61
|
+
if (attributes) $(el).attr(attributes);
|
|
62
|
+
if (content) $(el).html(content);
|
|
63
|
+
return el;
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
// Set callbacks, where `this.events` is a hash of
|
|
67
|
+
//
|
|
68
|
+
// *{"event selector": "callback"}*
|
|
69
|
+
//
|
|
70
|
+
// {
|
|
71
|
+
// 'mousedown .title': 'edit',
|
|
72
|
+
// 'click .button': 'save'
|
|
73
|
+
// }
|
|
74
|
+
//
|
|
75
|
+
// pairs. Callbacks will be bound to the view, with `this` set properly.
|
|
76
|
+
// Uses event delegation for efficiency.
|
|
77
|
+
// Omitting the selector binds the event to `this.el`.
|
|
78
|
+
// This only works for delegate-able events: not `focus`, `blur`, and
|
|
79
|
+
// not `change`, `submit`, and `reset` in Internet Explorer.
|
|
80
|
+
delegateEvents : function(events) {
|
|
81
|
+
if (!(events || (events = this.events))) return;
|
|
82
|
+
if (_.isFunction(events)) events = events.call(this);
|
|
83
|
+
this.undelegateEvents();
|
|
84
|
+
for (var key in events) {
|
|
85
|
+
var method = this[events[key]];
|
|
86
|
+
if (!method) throw new Error('Event "' + events[key] + '" does not exist');
|
|
87
|
+
var match = key.match(eventSplitter);
|
|
88
|
+
var eventName = match[1], selector = match[2];
|
|
89
|
+
method = _.bind(method, this);
|
|
90
|
+
eventName += '.delegateEvents' + this.cid;
|
|
91
|
+
if (selector === '') {
|
|
92
|
+
$(this.el).bind(eventName, method);
|
|
93
|
+
} else {
|
|
94
|
+
$(this.el).delegate(selector, eventName, method);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Clears all callbacks previously bound to the view with `delegateEvents`.
|
|
100
|
+
undelegateEvents: function() {
|
|
101
|
+
$(this.el).unbind('.delegateEvents' + this.cid);
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// Performs the initial configuration of a View with a set of options.
|
|
105
|
+
// Keys with special meaning *(model, collection, id, className)*, are
|
|
106
|
+
// attached directly to the view.
|
|
107
|
+
_configure : function(options) {
|
|
108
|
+
if (this.options) options = _.extend({}, this.options, options);
|
|
109
|
+
for (var i = 0, l = viewOptions.length; i < l; i++) {
|
|
110
|
+
var attr = viewOptions[i];
|
|
111
|
+
if (options[attr]) this[attr] = options[attr];
|
|
112
|
+
}
|
|
113
|
+
this.options = options;
|
|
114
|
+
},
|
|
115
|
+
|
|
116
|
+
// Ensure that the View has a DOM element to render into.
|
|
117
|
+
// If `this.el` is a string, pass it through `$()`, take the first
|
|
118
|
+
// matching element, and re-assign it to `el`. Otherwise, create
|
|
119
|
+
// an element from the `id`, `className` and `tagName` properties.
|
|
120
|
+
_ensureElement : function() {
|
|
121
|
+
if (!this.el) {
|
|
122
|
+
var attrs = this.attributes || {};
|
|
123
|
+
if (this.id) attrs.id = this.id;
|
|
124
|
+
if (this.className) attrs['class'] = this.className;
|
|
125
|
+
this.el = this.make(this.tagName, attrs);
|
|
126
|
+
} else if (_.isString(this.el)) {
|
|
127
|
+
this.el = $(this.el).get(0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// The self-propagating extend function that Backbone classes use.
|
|
134
|
+
var extend = function (protoProps, classProps) {
|
|
135
|
+
var child = inherits(this, protoProps, classProps);
|
|
136
|
+
child.extend = this.extend;
|
|
137
|
+
return child;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// Set up inheritance for the model, collection, and view.
|
|
141
|
+
Backbone.Model.extend = Backbone.Collection.extend =
|
|
142
|
+
Backbone.Router.extend = Backbone.View.extend = extend;
|
|
143
|
+
|
|
144
|
+
// Map from CRUD to HTTP for our default `Backbone.sync` implementation.
|
|
145
|
+
var methodMap = {
|
|
146
|
+
'create': 'POST',
|
|
147
|
+
'update': 'PUT',
|
|
148
|
+
'delete': 'DELETE',
|
|
149
|
+
'read' : 'GET'
|
|
150
|
+
};
|