Compare commits
24 Commits
Author | SHA1 | Date |
---|---|---|
John Bintz | 7ff9dc5ff9 | |
John Bintz | 0ba8019c64 | |
John Bintz | 134f93be86 | |
John Bintz | 81bd5c176c | |
John Bintz | 1ab4d353fa | |
John Bintz | b7d0e181d8 | |
John Bintz | b0a8425617 | |
John Bintz | 6b31491da7 | |
John Bintz | 8aea97569e | |
John Bintz | 755ffdb6c0 | |
John Bintz | d7a77e672b | |
John Bintz | 429549027f | |
John Bintz | a37de3c20c | |
John Bintz | 3b1f15f9ab | |
John Bintz | 5c2e078c02 | |
John Bintz | ed9a824c37 | |
John Bintz | 97efc633de | |
John Bintz | 14a2f3f714 | |
John Bintz | 2919235390 | |
John Bintz | 8fbe5628ff | |
John Bintz | b9c2f64d95 | |
John Bintz | adf18ae119 | |
John Bintz | a22177ba54 | |
John Bintz | 1e9213f653 |
|
@ -2,4 +2,12 @@ Autotest.add_hook(:initialize) do |at|
|
||||||
at.add_mapping(%r{bin/(.*)}, true) do |filename, matches|
|
at.add_mapping(%r{bin/(.*)}, true) do |filename, matches|
|
||||||
at.files_matching(%r{spec/bin/#{matches[1]}_spec\.rb})
|
at.files_matching(%r{spec/bin/#{matches[1]}_spec\.rb})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
at.add_mapping(%r{spec/(.*)}, true) do |filename, matches|
|
||||||
|
at.files_matching(%r{#{filename}})
|
||||||
|
end
|
||||||
|
|
||||||
|
at.add_mapping(%r{templates/.*}, true) do |filename, matches|
|
||||||
|
at.files_matching(%r{spec/bin/.*_spec\.rb})
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,15 +7,36 @@ require 'thor/group'
|
||||||
class BackboneGenerator < Thor
|
class BackboneGenerator < Thor
|
||||||
include Thor::Actions
|
include Thor::Actions
|
||||||
|
|
||||||
|
class_option :coffee, :type => :boolean, :desc => 'Generate CoffeeScript instead of JavaScript'
|
||||||
def self.source_root
|
def self.source_root
|
||||||
File.expand_path('../../templates', __FILE__)
|
File.expand_path('../../templates', __FILE__)
|
||||||
end
|
end
|
||||||
|
|
||||||
no_tasks do
|
no_tasks do
|
||||||
|
def extension
|
||||||
|
options[:coffee] ? 'coffee' : 'js'
|
||||||
|
end
|
||||||
|
|
||||||
|
def script_target
|
||||||
|
options[:coffee] ? 'app/assets/javascripts' : 'public/javascripts'
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_target
|
||||||
|
'app/views'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_target
|
||||||
|
'spec/javascripts'
|
||||||
|
end
|
||||||
|
|
||||||
def underscore_name
|
def underscore_name
|
||||||
singularize(Thor::Util.snake_case(@name.gsub("::", "/")))
|
singularize(Thor::Util.snake_case(@name.gsub("::", "/")))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def css_class_name
|
||||||
|
underscore_name.gsub(%r{[^a-z0-9_]}, '-')
|
||||||
|
end
|
||||||
|
|
||||||
def plural_underscore_name
|
def plural_underscore_name
|
||||||
pluralize(underscore_name)
|
pluralize(underscore_name)
|
||||||
end
|
end
|
||||||
|
@ -29,25 +50,25 @@ class BackboneGenerator < Thor
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_model
|
def generate_model
|
||||||
template('model.js.erb', "public/javascripts/models/#{underscore_name}.js")
|
template("model.#{extension}.erb", File.join(script_target, "models", "#{underscore_name}.#{extension}"))
|
||||||
template('model_spec.js.erb', "spec/javascripts/models/#{underscore_name}_spec.js")
|
template("model_spec.#{extension}.erb", File.join(test_target, "models", "#{underscore_name}_spec.#{extension}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_view
|
def generate_view
|
||||||
template('view.js.erb', "public/javascripts/views/#{underscore_name}_view.js")
|
template("view.#{extension}.erb", File.join(script_target, "views", "#{underscore_name}_view.#{extension}"))
|
||||||
template('view.jst.erb', "app/views/#{underscore_name}s/view.jst")
|
template("view.jst.erb", File.join(view_target, "#{underscore_name}s/view.jst"))
|
||||||
template('view_spec.js.erb', "spec/javascripts/views/#{underscore_name}_view_spec.js")
|
template("view_spec.#{extension}.erb", File.join(test_target, "views", "#{underscore_name}_view_spec.#{extension}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_collection
|
def generate_collection
|
||||||
template('collection.js.erb', "public/javascripts/collections/#{plural_underscore_name}.js")
|
template("collection.#{extension}.erb", File.join(script_target, "collections", "#{plural_underscore_name}.#{extension}"))
|
||||||
template('collection_spec.js.erb', "spec/javascripts/collections/#{plural_underscore_name}_spec.js")
|
template("collection_spec.#{extension}.erb", File.join(test_target, "collections", "#{plural_underscore_name}_spec.#{extension}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_collection_view
|
def generate_collection_view
|
||||||
template('collection_view.js.erb', "public/javascripts/views/#{plural_underscore_name}_view.js")
|
template("collection_view.#{extension}.erb", File.join(script_target, 'views', "#{plural_underscore_name}_view.#{extension}"))
|
||||||
template('collection_view.jst.erb', "app/views/#{plural_underscore_name}/list.jst")
|
template("collection_view.jst.erb", File.join(view_target, "#{plural_underscore_name}/list.jst"))
|
||||||
template('collection_view_spec.js.erb', "spec/javascripts/views/#{plural_underscore_name}_view_spec.js")
|
template("collection_view_spec.#{extension}.erb", File.join(test_target, "views", "#{plural_underscore_name}_view_spec.#{extension}"))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -83,7 +104,20 @@ class BackboneGenerator < Thor
|
||||||
|
|
||||||
desc 'spec-helper', "Generate a spec helper for Backbone things"
|
desc 'spec-helper', "Generate a spec helper for Backbone things"
|
||||||
def spec_helper
|
def spec_helper
|
||||||
template('spec_helper.js.erb', 'spec/javascripts/helpers/backbone_spec_helper.js')
|
template("spec_helper.#{extension}.erb", File.join(test_target, "helpers", "backbone_spec_helper.#{extension}"))
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "app-helper", "Generate an application helper for useful Backbone things"
|
||||||
|
def app_helper
|
||||||
|
template("app_helper.#{extension}.erb", File.join(script_target, "application", "backbone_helper.#{extension}"))
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "app-scaffold", "Generate an application scaffold"
|
||||||
|
def app_scaffold
|
||||||
|
template("app_view.#{extension}.erb", File.join(script_target, "application", "app_view.#{extension}"))
|
||||||
|
template("app_view.jst.erb", File.join(view_target, "application", "app_view.jst"))
|
||||||
|
template("controller.#{extension}.erb", File.join(script_target, "application", "controller.#{extension}"))
|
||||||
|
template("app_view_spec.#{extension}.erb", File.join(test_target, "application", "app_view_spec.#{extension}"))
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -8,9 +8,128 @@ describe 'backbone-generator' do
|
||||||
FileUtils.rm_rf 'app'
|
FileUtils.rm_rf 'app'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def run(*opts)
|
||||||
|
system %{bin/backbone-generator #{opts.join(' ')}}
|
||||||
|
end
|
||||||
|
|
||||||
before { clean! }
|
before { clean! }
|
||||||
after { clean! }
|
after { clean! }
|
||||||
|
|
||||||
|
describe 'coffeescript' do
|
||||||
|
def should_generate_model
|
||||||
|
File.file?(model = 'app/assets/javascripts/models/section/model.coffee').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/models/section/model_spec.coffee').should be_true
|
||||||
|
|
||||||
|
File.read(model).should match(/SectionModel/)
|
||||||
|
File.read(spec).should match(/SectionModel/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_generate_view
|
||||||
|
File.file?(view = 'app/assets/javascripts/views/section/model_view.coffee').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/views/section/model_view_spec.coffee').should be_true
|
||||||
|
File.file?(template = 'app/views/section/models/view.jst').should be_true
|
||||||
|
|
||||||
|
File.read(view).should match(/SectionModel/)
|
||||||
|
File.read(view).should match(%r{template: JST\['section/models/view'\]})
|
||||||
|
File.read(spec).should match(/SectionModel/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_generate_collection
|
||||||
|
File.file?(collection = 'app/assets/javascripts/collections/section/models.coffee').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/collections/section/models_spec.coffee').should be_true
|
||||||
|
|
||||||
|
File.read(collection).should match(/SectionModels/)
|
||||||
|
File.read(collection).should_not match(/SectionModelss/)
|
||||||
|
File.read(collection).should match(%r{section/model})
|
||||||
|
File.read(spec).should match(/SectionModels/)
|
||||||
|
File.read(spec).should_not match(/SectionModelss/)
|
||||||
|
end
|
||||||
|
|
||||||
|
def should_generate_collection_view
|
||||||
|
File.file?(view = 'app/assets/javascripts/views/section/models_view.coffee').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/views/section/models_view_spec.coffee').should be_true
|
||||||
|
File.file?(template = 'app/views/section/models/list.jst').should be_true
|
||||||
|
|
||||||
|
File.read(view).should match(/SectionModelsView/)
|
||||||
|
File.read(view).should_not match(/SectionModelssView/)
|
||||||
|
File.read(view).should match(/SectionModelView/)
|
||||||
|
File.read(view).should match(%r{template: JST\['section/models/list'\]})
|
||||||
|
File.read(spec).should match(/SectionModelsView/)
|
||||||
|
File.read(spec).should_not match(/SectionModelssView/)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'model' do
|
||||||
|
it "should generate the model files" do
|
||||||
|
run "model", "Section::Model", '--coffee'
|
||||||
|
|
||||||
|
should_generate_model
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'view' do
|
||||||
|
it "should generate the model files" do
|
||||||
|
run "view", "Section::Model", '--coffee'
|
||||||
|
|
||||||
|
should_generate_view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'collection view' do
|
||||||
|
it "should generate the collection view files" do
|
||||||
|
run "collection-view", "Section::Model", '--coffee'
|
||||||
|
|
||||||
|
should_generate_collection_view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'collection' do
|
||||||
|
it "should generate the collection files" do
|
||||||
|
run "collection", "Section::Model", '--coffee'
|
||||||
|
|
||||||
|
should_generate_collection
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'scaffold' do
|
||||||
|
it "should generate everything!" do
|
||||||
|
run "scaffold", "Section::Model", '--coffee'
|
||||||
|
|
||||||
|
should_generate_model
|
||||||
|
should_generate_view
|
||||||
|
should_generate_collection
|
||||||
|
should_generate_collection_view
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'spec helper' do
|
||||||
|
it "should generate a spec helper" do
|
||||||
|
run "spec-helper", '--coffee'
|
||||||
|
|
||||||
|
File.file?(collection = 'spec/javascripts/helpers/backbone_spec_helper.coffee').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'app helper' do
|
||||||
|
it "should generate an app helper" do
|
||||||
|
run "app-helper", '--coffee'
|
||||||
|
|
||||||
|
File.file?(collection = 'app/assets/javascripts/application/backbone_helper.coffee').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'application scaffold' do
|
||||||
|
it "should generate an application scaffold" do
|
||||||
|
run "app-scaffold", '--coffee'
|
||||||
|
|
||||||
|
File.file?(app = 'app/assets/javascripts/application/app_view.coffee').should be_true
|
||||||
|
File.file?(app_view = 'app/views/application/app_view.jst').should be_true
|
||||||
|
File.file?(controller = 'app/assets/javascripts/application/controller.coffee').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/application/app_view_spec.coffee').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'javascript' do
|
||||||
def should_generate_model
|
def should_generate_model
|
||||||
File.file?(model = 'public/javascripts/models/section/model.js').should be_true
|
File.file?(model = 'public/javascripts/models/section/model.js').should be_true
|
||||||
File.file?(spec = 'spec/javascripts/models/section/model_spec.js').should be_true
|
File.file?(spec = 'spec/javascripts/models/section/model_spec.js').should be_true
|
||||||
|
@ -57,7 +176,7 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
describe 'model' do
|
describe 'model' do
|
||||||
it "should generate the model files" do
|
it "should generate the model files" do
|
||||||
system %{bin/backbone-generator model Section::Model}
|
run "model", "Section::Model"
|
||||||
|
|
||||||
should_generate_model
|
should_generate_model
|
||||||
end
|
end
|
||||||
|
@ -65,7 +184,7 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
describe 'view' do
|
describe 'view' do
|
||||||
it "should generate the view files" do
|
it "should generate the view files" do
|
||||||
system %{bin/backbone-generator view Section::Model}
|
run "view", "Section::Model"
|
||||||
|
|
||||||
should_generate_view
|
should_generate_view
|
||||||
end
|
end
|
||||||
|
@ -74,7 +193,7 @@ describe 'backbone-generator' do
|
||||||
describe 'collection view' do
|
describe 'collection view' do
|
||||||
context 'without trailing s' do
|
context 'without trailing s' do
|
||||||
it "should generate the collection view files" do
|
it "should generate the collection view files" do
|
||||||
system %{bin/backbone-generator collection-view Section::Model}
|
run "collection-view", "Section::Model"
|
||||||
|
|
||||||
should_generate_collection_view
|
should_generate_collection_view
|
||||||
end
|
end
|
||||||
|
@ -82,7 +201,7 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
context 'with trailing s' do
|
context 'with trailing s' do
|
||||||
it "should generate the collection view files" do
|
it "should generate the collection view files" do
|
||||||
system %{bin/backbone-generator collection-view Section::Models}
|
run "collection-view", "Section::Models"
|
||||||
|
|
||||||
should_generate_collection_view
|
should_generate_collection_view
|
||||||
end
|
end
|
||||||
|
@ -92,7 +211,7 @@ describe 'backbone-generator' do
|
||||||
describe 'collection' do
|
describe 'collection' do
|
||||||
context 'without trailing s' do
|
context 'without trailing s' do
|
||||||
it "should generate the collection files" do
|
it "should generate the collection files" do
|
||||||
system %{bin/backbone-generator collection Section::Model}
|
run "collection", "Section::Model"
|
||||||
|
|
||||||
should_generate_collection
|
should_generate_collection
|
||||||
end
|
end
|
||||||
|
@ -100,7 +219,7 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
context 'with trailing s' do
|
context 'with trailing s' do
|
||||||
it "should generate the collection files" do
|
it "should generate the collection files" do
|
||||||
system %{bin/backbone-generator collection Section::Models}
|
run "collection", "Section::Models"
|
||||||
|
|
||||||
should_generate_collection
|
should_generate_collection
|
||||||
end
|
end
|
||||||
|
@ -109,7 +228,7 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
describe 'scaffold' do
|
describe 'scaffold' do
|
||||||
it "should generate everything!" do
|
it "should generate everything!" do
|
||||||
system %{bin/backbone-generator scaffold Section::Model}
|
run "scaffold", "Section::Model"
|
||||||
|
|
||||||
should_generate_model
|
should_generate_model
|
||||||
should_generate_view
|
should_generate_view
|
||||||
|
@ -120,9 +239,29 @@ describe 'backbone-generator' do
|
||||||
|
|
||||||
describe 'spec helper' do
|
describe 'spec helper' do
|
||||||
it "should generate a spec helper" do
|
it "should generate a spec helper" do
|
||||||
system %{bin/backbone-generator spec-helper}
|
run "spec-helper"
|
||||||
|
|
||||||
File.file?(collection = 'spec/javascripts/helpers/backbone_spec_helper.js').should be_true
|
File.file?(collection = 'spec/javascripts/helpers/backbone_spec_helper.js').should be_true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'app helper' do
|
||||||
|
it "should generate an app helper" do
|
||||||
|
run "app-helper"
|
||||||
|
|
||||||
|
File.file?(collection = 'public/javascripts/application/backbone_helper.js').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'application scaffold' do
|
||||||
|
it "should generate an application scaffold" do
|
||||||
|
run "app-scaffold"
|
||||||
|
|
||||||
|
File.file?(app = 'public/javascripts/application/app_view.js').should be_true
|
||||||
|
File.file?(app_view = 'app/views/application/app_view.jst').should be_true
|
||||||
|
File.file?(controller = 'public/javascripts/application/controller.js').should be_true
|
||||||
|
File.file?(spec = 'spec/javascripts/application/app_view_spec.js').should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
Backbone.Collection.prototype.ensureFetched = (callback) ->
|
||||||
|
if !@_alreadyEnsureFetched
|
||||||
|
_refresher = null
|
||||||
|
_refresher =>
|
||||||
|
this.unbind('refresh', _refresher)
|
||||||
|
callback.apply(this)
|
||||||
|
@_alreadyEnsureFetched = true
|
||||||
|
this.bind('refresh', _refresher)
|
||||||
|
this.fetch()
|
||||||
|
else
|
||||||
|
callback.apply(this)
|
||||||
|
|
||||||
|
Backbone.View.prototype.attributes = ->
|
||||||
|
attrs = {}
|
||||||
|
for field in @attributeFields
|
||||||
|
do (field) =>
|
||||||
|
attrs[field] = this.$("input[name='#{field}']").val()
|
||||||
|
attrs
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* Ensure a Collection is fetched and has entries before running a block of code. */
|
||||||
|
|
||||||
|
_.extend(Backbone.Collection.prototype, {
|
||||||
|
ensureFetched: function(callback) {
|
||||||
|
if (this._alreadyEnsureFetched) {
|
||||||
|
var _this = this;
|
||||||
|
var _refresher = function() {
|
||||||
|
_this.unbind('refresh', _refresher);
|
||||||
|
callback.apply(_this);
|
||||||
|
_this._alreadyEnsureFetched = true;
|
||||||
|
};
|
||||||
|
this.bind('refresh', _refresher);
|
||||||
|
this.fetch();
|
||||||
|
} else {
|
||||||
|
callback.apply(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
_.extend(Backbone.View.prototype, {
|
||||||
|
attributes: function() {
|
||||||
|
var attrs = {};
|
||||||
|
var _this = this;
|
||||||
|
_.each(this.attributeFields, function(field) {
|
||||||
|
attrs[field] = _this.$('input[name="' + field + '"]').val();
|
||||||
|
});
|
||||||
|
return attrs;
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
class window.AppView extends Backbone.View
|
||||||
|
el: '#application'
|
||||||
|
template: JST['application/app_view']
|
||||||
|
initialize: ->
|
||||||
|
controller = new Controller({app: this})
|
||||||
|
Backbone.history.start()
|
||||||
|
render: =>
|
||||||
|
$(@el).html(@template())
|
||||||
|
this
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
var AppView = Backbone.View.extend({
|
||||||
|
el: '#application',
|
||||||
|
template: JST['application/app_view'],
|
||||||
|
initialize: function() {
|
||||||
|
_.bindAll(this, 'render');
|
||||||
|
|
||||||
|
var controller = new Controller({app: this});
|
||||||
|
|
||||||
|
Backbone.history.start();
|
||||||
|
},
|
||||||
|
render: function() {
|
||||||
|
$(this.el).html(this.template());
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<!-- application view goes here -->
|
|
@ -0,0 +1,9 @@
|
||||||
|
describe 'AppView', ->
|
||||||
|
appView = null
|
||||||
|
|
||||||
|
beforeEach, ->
|
||||||
|
appView = new AppView()
|
||||||
|
|
||||||
|
it 'should render', ->
|
||||||
|
expect($(appView.render().el)).toContain('.something')
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
describe('AppView', function() {
|
||||||
|
var app_view;
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
app_view = new AppView();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render', function() {
|
||||||
|
expect($(app_view.render().el)).toContain('.something');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class window.<%= plural_object_name %> extends Backbone.Collection
|
||||||
|
url: '/<%= plural_underscore_name %>'
|
||||||
|
model: <%= object_name %>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
describe '<%= plural_object_name %>', ->
|
||||||
|
collection = null
|
||||||
|
|
||||||
|
withServer()
|
||||||
|
|
||||||
|
it 'should fetch records from the API', ->
|
||||||
|
collection = new <%= plural_object_name %>()
|
||||||
|
|
||||||
|
@server.respondWith('GET', '/<%= plural_underscore_name %>', @validJSONResponse([{id: 1}]))
|
||||||
|
collection.fetch()
|
||||||
|
@server.respond()
|
||||||
|
|
||||||
|
expect(collection.length).toEqual(1)
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
class window.<%= plural_object_name %>View extends Backbone.View
|
||||||
|
events: {
|
||||||
|
'click button.new': 'addNew'
|
||||||
|
}
|
||||||
|
template: JST['<%= plural_underscore_name %>/list']
|
||||||
|
initialize: ->
|
||||||
|
@collection.bind('refresh', this.addAll)
|
||||||
|
render: =>
|
||||||
|
$(this.el).html(this.template())
|
||||||
|
this.addAll()
|
||||||
|
this
|
||||||
|
addOne: (model) =>
|
||||||
|
view = new <%= object_name %>View({model: model})
|
||||||
|
this.$('.list').append(view.render().el)
|
||||||
|
addAll: =>
|
||||||
|
@collection.each(this.addOne)
|
||||||
|
addNew: =>
|
||||||
|
object = new <%= object_name %>()
|
||||||
|
@collection.add(object)
|
||||||
|
this.addOne(object)
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
var <%= plural_object_name %>View = Backbone.View.extend({
|
var <%= plural_object_name %>View = Backbone.View.extend({
|
||||||
|
events: {
|
||||||
|
'click button.new': 'addNew'
|
||||||
|
},
|
||||||
template: JST['<%= plural_underscore_name %>/list'],
|
template: JST['<%= plural_underscore_name %>/list'],
|
||||||
initialize: function(collection) {
|
initialize: function() {
|
||||||
_.bindAll(this, 'render', 'addOne', 'addAll');
|
_.bindAll(this, 'render', 'addOne', 'addAll', 'addNew');
|
||||||
|
|
||||||
this.collection = collection;
|
|
||||||
this.collection.bind('refresh', this.addAll);
|
this.collection.bind('refresh', this.addAll);
|
||||||
|
|
||||||
this.render();
|
this.render();
|
||||||
|
@ -19,5 +21,11 @@ var <%= plural_object_name %>View = Backbone.View.extend({
|
||||||
},
|
},
|
||||||
addAll: function() {
|
addAll: function() {
|
||||||
this.collection.each(this.addOne);
|
this.collection.each(this.addOne);
|
||||||
|
},
|
||||||
|
addNew: function() {
|
||||||
|
var object = new <%= object_name %>();
|
||||||
|
this.collection.add(object);
|
||||||
|
|
||||||
|
this.addOne(object);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
<div class="list"></div>
|
<div class="list"></div>
|
||||||
|
<button class="new">Create</button>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
describe '<%= plural_object_name %>View', ->
|
||||||
|
view = collection = null
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
collection = new <%= plural_object_name %>()
|
||||||
|
view = new <%= plural_object_name %>View({collection: collection})
|
||||||
|
view.render()
|
||||||
|
|
||||||
|
it 'should render', ->
|
||||||
|
expect($(view.el)).toContain('.list')
|
||||||
|
expect($(view.el)).toContain('button.new')
|
||||||
|
|
||||||
|
it 'should add a new model when new is clicked', ->
|
||||||
|
view.$('button.new').trigger('click')
|
||||||
|
|
||||||
|
expect(view.$('.list')).toContain('.<%= css_class_name %>')
|
||||||
|
expect(collection.length).toEqual(1)
|
||||||
|
|
||||||
|
it 'should render the models when re-rendered', ->
|
||||||
|
expect(view.$('.list')).not.toContain('.<%= css_class_name %>')
|
||||||
|
|
||||||
|
model = new <%= object_name %>({id: 1})
|
||||||
|
collection.add(model)
|
||||||
|
view.render()
|
||||||
|
|
||||||
|
expect(view.$('.list')).toContain('.<%= css_class_name %>')
|
|
@ -6,9 +6,17 @@ describe('<%= plural_object_name %>View', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render', function() {
|
it('should render', function() {
|
||||||
view = new <%= plural_object_name %>View(collection);
|
view = new <%= plural_object_name %>View({collection: collection});
|
||||||
view.render();
|
view.render();
|
||||||
|
|
||||||
expect($(view.el)).toContain('.list');
|
expect($(view.el)).toContain('.list');
|
||||||
|
expect($(view.el)).toContain('button.new');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add a new model when new is clicked', function() {
|
||||||
|
view.$('button.new').trigger('click');
|
||||||
|
|
||||||
|
expect(view.$('.list')).toContain('.<%= underscore_name %>');
|
||||||
|
expect(collection.length).toEqual(1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
class window.Controller extends Backbone.Controller
|
||||||
|
routes: {
|
||||||
|
'index': 'index'
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
var Controller = Backbone.Controller.extend({
|
||||||
|
routes: {
|
||||||
|
'index': 'index'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
class window.<%= object_name %> extends Backbone.Model
|
|
@ -0,0 +1,8 @@
|
||||||
|
describe '<%= object_name %>', ->
|
||||||
|
model = null
|
||||||
|
|
||||||
|
it 'should have some tests', ->
|
||||||
|
model = new <%= object_name %>()
|
||||||
|
|
||||||
|
expect(true).toEqual(false)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
window.withServer ->
|
||||||
|
jasmine.getEnv().withServer()
|
||||||
|
|
||||||
|
jasmine.Env.prototype.withServer ->
|
||||||
|
@currentSuite.beforeEach ->
|
||||||
|
@server = sinon.fakeServer.create()
|
||||||
|
|
||||||
|
@currentSuite.afterEach ->
|
||||||
|
@server.restore()
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
@validJSONResponse = (data) ->
|
||||||
|
[ 200, { 'Content-type': 'application/json' }, JSON.stringify(data) ]
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
class window.<%= object_name %>View extends Backbone.View
|
||||||
|
events: {
|
||||||
|
'click button.save': 'save',
|
||||||
|
'click button.delete': 'destroy'
|
||||||
|
}
|
||||||
|
attributeFields: []
|
||||||
|
template: JST['<%= underscore_name %>s/view']
|
||||||
|
className: '<%= css_class_name %>'
|
||||||
|
initialize: ->
|
||||||
|
_.bindAll(this, 'remove')
|
||||||
|
|
||||||
|
@model.bind('change', this.render)
|
||||||
|
@model.bind('remove', this.remove)
|
||||||
|
@model.view = this
|
||||||
|
render: =>
|
||||||
|
$(@el).html(this.template(@model.toJSON()))
|
||||||
|
this.$('button.save').text(if @model.isNew() then 'Create' else 'Update')
|
||||||
|
this.$('button.delete')[if @model.isNew() then 'hide' else 'show']();
|
||||||
|
this
|
||||||
|
save: =>
|
||||||
|
@model.save(this.attributes())
|
||||||
|
destroy: =>
|
||||||
|
if confirm("Are you sure?")
|
||||||
|
@model.destroy()
|
||||||
|
|
|
@ -1,11 +1,31 @@
|
||||||
var <%= object_name %>View = Backbone.View.extend({
|
var <%= object_name %>View = Backbone.View.extend({
|
||||||
|
events: {
|
||||||
|
'click button.save': 'save',
|
||||||
|
'click button.delete': 'destroy'
|
||||||
|
},
|
||||||
|
attributeFields: [],
|
||||||
template: JST['<%= underscore_name %>s/view'],
|
template: JST['<%= underscore_name %>s/view'],
|
||||||
|
className: '<%= underscore_name %>',
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
_.bindAll(this, 'render');
|
_.bindAll(this, 'render', 'save', 'destroy', 'remove');
|
||||||
|
|
||||||
|
this.model.bind('change', this.render);
|
||||||
|
this.model.bind('remove', this.remove);
|
||||||
|
this.model.view = this;
|
||||||
},
|
},
|
||||||
render: function() {
|
render: function() {
|
||||||
$(this.el).html(this.template());
|
$(this.el).html(this.template(this.model.toJSON()));
|
||||||
|
this.$('button.save').text(this.model.isNew() ? 'Create' : 'Update');
|
||||||
|
this.$('button.delete')[this.model.isNew() ? 'hide' : 'show']();
|
||||||
return this;
|
return this;
|
||||||
|
},
|
||||||
|
save: function() {
|
||||||
|
this.model.save(this.attributes(), { success: function(model) { model.view.render(); } });
|
||||||
|
},
|
||||||
|
destroy: function() {
|
||||||
|
if (confirm("Are you sure?")) {
|
||||||
|
this.model.destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
<!-- your <%= object_name %>View template goes here -->
|
<!-- your <%= object_name %>View template fields go here -->
|
||||||
|
<button class="save" /><button class="delete">Delete</button>
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
describe '<%= object_name %>View', ->
|
||||||
|
view = model = null
|
||||||
|
|
||||||
|
describe 'new record', ->
|
||||||
|
beforeEach ->
|
||||||
|
model = new <%= object_name %>
|
||||||
|
|
||||||
|
it 'should render with a create button', ->
|
||||||
|
view = new <%= object_name %>View({model: model})
|
||||||
|
view.render()
|
||||||
|
|
||||||
|
expect(view.$('button.save')).toHaveText('Create')
|
||||||
|
|
||||||
|
describe 'existing record', ->
|
||||||
|
beforeEach ->
|
||||||
|
model = new <%= object_name %>({id: 1})
|
||||||
|
setFixtures('<div id="container" />')
|
||||||
|
|
||||||
|
view = new <%= object_name %>View({model: model})
|
||||||
|
view.render()
|
||||||
|
|
||||||
|
it 'should render with an update button', ->
|
||||||
|
expect(view.$('button.save')).toHaveText('Update')
|
||||||
|
|
||||||
|
it 'should destroy the model', ->
|
||||||
|
spyOn(window, 'confirm').andReturn(true)
|
||||||
|
spyOn(model, 'destroy')
|
||||||
|
|
||||||
|
$('#container').append(view.el)
|
||||||
|
view.$('button.delete').trigger('click')
|
||||||
|
|
||||||
|
expect(model.destroy).toHaveBeenCalled()
|
||||||
|
expect(window.confirm).toHaveBeenCalled()
|
||||||
|
|
||||||
|
it 'should remove the view when the model is destroyed', ->
|
||||||
|
$('#container').append(view.render().el)
|
||||||
|
|
||||||
|
expect($('button.save')).toExist()
|
||||||
|
model.trigger('remove')
|
||||||
|
expect($('button.save')).not.toExist()
|
||||||
|
|
|
@ -1,10 +1,50 @@
|
||||||
describe('<%= object_name %>View', function() {
|
describe('<%= object_name %>View', function() {
|
||||||
var view;
|
var view, model;
|
||||||
|
|
||||||
it('should render', function() {
|
describe('new record', function() {
|
||||||
view = new <%= object_name %>View();
|
beforeEach(function() {
|
||||||
|
model = new <%= object_name %>();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with a create button', function() {
|
||||||
|
view = new <%= object_name %>View({model: model});
|
||||||
view.render();
|
view.render();
|
||||||
|
|
||||||
expect($(view.el)).toContain('.something');
|
expect(view.$('button.save')).toHaveText('Create');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('existing record', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
model = new <%= object_name %>({id: 1});
|
||||||
|
setFixtures('<div id="container" />');
|
||||||
|
|
||||||
|
view = new <%= object_name %>View({model: model});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should render with an update button', function() {
|
||||||
|
view.render();
|
||||||
|
|
||||||
|
expect(view.$('button.save')).toHaveText('Update');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should destroy the model', function() {
|
||||||
|
spyOn(window, 'confirm').andReturn(true);
|
||||||
|
spyOn(model, 'destroy');
|
||||||
|
|
||||||
|
$('#container').append(view.el);
|
||||||
|
view.$('button.delete').trigger('click');
|
||||||
|
|
||||||
|
expect(model.destroy).toHaveBeenCalled();
|
||||||
|
expect(window.confirm).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should remove the view when the model is destroyed', function() {
|
||||||
|
$('#container').append(view.render().el);
|
||||||
|
|
||||||
|
expect($('button.save')).toExist();
|
||||||
|
model.trigger('remove');
|
||||||
|
expect($('button.save')).not.toExist();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue