alpha-simprini-engine 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +38 -0
- data/app/assets/javascripts/alpha_simprini.coffee +15 -0
- data/app/assets/javascripts/alpha_simprini/application.coffee +22 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/binding.coffee +119 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/helpers.coffee +17 -0
- data/app/assets/javascripts/alpha_simprini/coffee_kup/tags.coffee +7 -0
- data/app/assets/javascripts/alpha_simprini/collection.coffee +62 -0
- data/app/assets/javascripts/alpha_simprini/delegate.coffee +21 -0
- data/app/assets/javascripts/alpha_simprini/event.coffee +75 -0
- data/app/assets/javascripts/alpha_simprini/html.coffee +56 -0
- data/app/assets/javascripts/alpha_simprini/mixin.coffee +10 -0
- data/app/assets/javascripts/alpha_simprini/model.coffee +137 -0
- data/app/assets/javascripts/alpha_simprini/models/radio_selection_model.coffee +9 -0
- data/app/assets/javascripts/alpha_simprini/packer.coffee +93 -0
- data/app/assets/javascripts/alpha_simprini/template_helpers.coffee +8 -0
- data/app/assets/javascripts/alpha_simprini/view.coffee +182 -0
- data/app/assets/javascripts/alpha_simprini/views/canvas.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/horizontal_split.coffee +9 -0
- data/app/assets/javascripts/alpha_simprini/views/panel.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/splitter.coffee +2 -0
- data/app/assets/javascripts/alpha_simprini/views/stage.coffee +7 -0
- data/app/assets/javascripts/alpha_simprini/views/vertical_split.coffee +8 -0
- data/app/assets/javascripts/alpha_simprini/views/viewport.coffee +0 -0
- data/app/assets/javascripts/bundle.js +16416 -0
- data/app/assets/javascripts/lib/backbone.coffee +11 -0
- data/app/assets/javascripts/lib/koffeecup_backbone_databind.coffee +25 -0
- data/app/assets/javascripts/lib/module.coffee +15 -0
- data/app/assets/javascripts/lib/state_machine.coffee +33 -0
- data/app/assets/javascripts/lib/string.coffee +13 -0
- data/app/assets/javascripts/qunit.js +1513 -0
- data/app/assets/javascripts/test.coffee +4 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/binding.coffee +118 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/helpers.coffee +10 -0
- data/app/assets/javascripts/test/alpha_simprini/coffee_kup/tags.coffee +18 -0
- data/app/assets/javascripts/test/alpha_simprini/collection.coffee +7 -0
- data/app/assets/javascripts/test/alpha_simprini/event.coffee +43 -0
- data/app/assets/javascripts/test/alpha_simprini/model.coffee +63 -0
- data/app/assets/javascripts/test/alpha_simprini/view.coffee +72 -0
- data/app/assets/javascripts/test/alpha_simprini/views/canvas.coffee +8 -0
- data/app/assets/javascripts/test/alpha_simprini/views/horizontal_split.coffee +13 -0
- data/app/assets/javascripts/test/alpha_simprini/views/vertical_split.coffee +13 -0
- data/app/assets/javascripts/test/backbone/collection.js +345 -0
- data/app/assets/javascripts/test/backbone/events.js +86 -0
- data/app/assets/javascripts/test/backbone/model.js +426 -0
- data/app/assets/javascripts/test/backbone/view.js +137 -0
- data/app/assets/stylesheets/bootstrap.sass +6 -0
- data/app/assets/stylesheets/paneling.sass +2 -0
- data/app/assets/stylesheets/qunit.scss +228 -0
- data/app/assets/stylesheets/table.sass +10 -0
- data/app/assets/stylesheets/typography.sass +19 -0
- data/app/controllers/alpha_simprini/test_controller.rb +3 -0
- data/app/controllers/resources_controller.rb +7 -0
- data/app/views/alpha_simprini/test/root.rb +13 -0
- data/app/views/resources/base.rb +2 -0
- data/app/views/resources/edit.rb +9 -0
- data/app/views/resources/form.rb +26 -0
- data/app/views/resources/index.rb +41 -0
- data/app/views/resources/new.rb +9 -0
- data/app/views/resources/show.rb +42 -0
- data/app/views/resources/show_has_many.rb +28 -0
- data/config/locales/en.yml +4 -0
- data/config/routes.rb +3 -0
- data/lib/alpha-simprini-engine.rb +33 -0
- data/lib/alpha-simprini-engine/version.rb +3 -0
- data/lib/alpha_simprini/directive_processor.rb +77 -0
- data/lib/alpha_simprini/packer.rb +161 -0
- data/lib/alpha_simprini/page.rb +37 -0
- data/lib/tasks/alpha-simprini-engine_tasks.rake +4 -0
- data/test/alpha-simprini-engine_test.rb +7 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +9 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +42 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +51 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +4 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/log/development.log +800 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C24/D70/sprockets%2F388a550030239f3784f207fa32954f64 +0 -0
- data/test/dummy/tmp/cache/assets/C34/620/sprockets%2F097ee8532856d48d70420c006f475889 +0 -0
- data/test/dummy/tmp/cache/assets/C6F/710/sprockets%2F908d18b0f21c18dad508851126164a41 +0 -0
- data/test/dummy/tmp/cache/assets/CA7/120/sprockets%2F35278a6c0150c40394fe02629c8b0eb9 +0 -0
- data/test/dummy/tmp/cache/assets/CDB/A80/sprockets%2F443b1c6e71b482fdd83b1833b7e27712 +0 -0
- data/test/dummy/tmp/cache/assets/CE3/FB0/sprockets%2F6d3f87a4232e0368bb86760780c5f1bd +0 -0
- data/test/dummy/tmp/cache/assets/D1C/160/sprockets%2F87876f7e55ebc78ae11c6c08a27f0605 +0 -0
- data/test/dummy/tmp/cache/assets/D26/6C0/sprockets%2F65bce2254bb3140a50326ea1654ea5df +0 -0
- data/test/dummy/tmp/cache/assets/D26/FA0/sprockets%2F1f50f59148df5f3e2ab889df381d9744 +0 -0
- data/test/dummy/tmp/cache/assets/D36/220/sprockets%2F841654b01d89eada195d7d1fe10b57b0 +0 -0
- data/test/dummy/tmp/cache/assets/D47/410/sprockets%2Ff1fe319eb4064bd5b861ac28f7d76555 +18122 -0
- data/test/dummy/tmp/cache/assets/D57/1E0/sprockets%2Fe267e3e1059799c429e4f5cfb95ec53c +0 -0
- data/test/dummy/tmp/cache/assets/D64/3E0/sprockets%2Fb49b7f8034b81ec601bc32fb127fbe08 +0 -0
- data/test/dummy/tmp/cache/assets/D65/850/sprockets%2F7a9b6a0e2d51adb43a1d3f859213e6b8 +15469 -0
- data/test/dummy/tmp/cache/assets/D6C/E30/sprockets%2Fcc7322b05ac2bef75e9f4f145d38117f +0 -0
- data/test/dummy/tmp/cache/assets/D7D/E00/sprockets%2Fce33b82451c73df1cfec69928b4f77b6 +0 -0
- data/test/dummy/tmp/cache/assets/D85/5D0/sprockets%2Fcf743946c378c148b19ce78eeaa9cc75 +0 -0
- data/test/dummy/tmp/cache/assets/DBB/560/sprockets%2F5a1d70cf7dd81a5ab5ce7a40a3a38d06 +0 -0
- data/test/dummy/tmp/cache/assets/DC1/670/sprockets%2Fefdfad0542298a1db90d24dc27ecc250 +0 -0
- data/test/dummy/tmp/cache/assets/DC5/1E0/sprockets%2F7517f22ad0f9dc13b8f0f6e0cc0e5de2 +0 -0
- data/test/dummy/tmp/cache/assets/DCC/220/sprockets%2F28d953c6ab9cc9a7db15600aabc6d77d +208 -0
- data/test/dummy/tmp/cache/assets/DCF/DF0/sprockets%2Ff0d3068f05825e1dfd9f5aaba946d3dc +0 -0
- data/test/dummy/tmp/cache/assets/DD3/0E0/sprockets%2F3e9e08a334bae7deadb5335f5e4f195f +0 -0
- data/test/dummy/tmp/cache/assets/DDB/980/sprockets%2Fbd2abc80a17c901e2f497f88f9be58cf +0 -0
- data/test/dummy/tmp/cache/assets/E00/ED0/sprockets%2Ffecf3bffeb200a47e96bd04cbc878076 +1535 -0
- data/test/dummy/tmp/cache/assets/EFB/560/sprockets%2Fbca0daf751c020cdeddabbefa51cb6ea +0 -0
- data/test/dummy/tmp/restart.txt +0 -0
- data/test/test_helper.rb +10 -0
- metadata +326 -0
@@ -0,0 +1,118 @@
|
|
1
|
+
@module "AS.CK.Binding"
|
2
|
+
render = (locals, template) ->
|
3
|
+
locals.hardcode = AS.TemplateHelpers
|
4
|
+
jQuery CoffeeKup.render template, locals
|
5
|
+
|
6
|
+
add_remove_do = (elements..., fn) ->
|
7
|
+
element.appendTo(document.body) for element in elements
|
8
|
+
fn.call()
|
9
|
+
element.remove() for element in elements
|
10
|
+
|
11
|
+
test "bind", ->
|
12
|
+
model = new AS.Model
|
13
|
+
model.set property:"value"
|
14
|
+
|
15
|
+
bound = render model:model, ->
|
16
|
+
div -> bind @model, "property"
|
17
|
+
|
18
|
+
bound_get = render model:model, ->
|
19
|
+
div -> bind @model, "property", -> "#{this}-GOT"
|
20
|
+
|
21
|
+
add_remove_do bound, bound_get, =>
|
22
|
+
equal bound.find("span").text(), "value", "binds initial value to a span"
|
23
|
+
equal bound_get.find("span").text(), "value-GOT", "processes value through getter"
|
24
|
+
model.set property:"new"
|
25
|
+
equal bound.find("span").text(), "new", "updates value in place when bound property changes"
|
26
|
+
equal bound_get.find("span").text(), "new-GOT", "processes updated value in place through getter"
|
27
|
+
model.destroy()
|
28
|
+
ok bound.find("span").get(0) is undefined, "remove binding from dom when model is destroyed"
|
29
|
+
ok bound_get.find("span").get(0) is undefined, "removes binding from dom when model is destroyed"
|
30
|
+
|
31
|
+
test "bound_input", ->
|
32
|
+
model = new AS.Model
|
33
|
+
model.set property:"value"
|
34
|
+
|
35
|
+
bound = render model:model, ->
|
36
|
+
div -> bound_input @model, "property"
|
37
|
+
|
38
|
+
add_remove_do bound, =>
|
39
|
+
input = bound.find("input")
|
40
|
+
equal input.val(), "value", "binds initial value to input"
|
41
|
+
|
42
|
+
model.set property:"new"
|
43
|
+
equal input.val(), "new", "updates input when model changes"
|
44
|
+
|
45
|
+
input.val("keyup")
|
46
|
+
input.trigger("keyup")
|
47
|
+
equal model.get("property"), "keyup", "updates model on keyup of input"
|
48
|
+
|
49
|
+
input.val("change")
|
50
|
+
input.trigger("change")
|
51
|
+
equal model.get("property"), "change", "updates model on change of input"
|
52
|
+
|
53
|
+
test "bound_select", ->
|
54
|
+
model = new AS.Model
|
55
|
+
options = new AS.Collection
|
56
|
+
option = new AS.Model value:"option1"
|
57
|
+
added_option = new AS.Model value:"option2"
|
58
|
+
options.add option
|
59
|
+
|
60
|
+
bound = render model:model, options:options, ->
|
61
|
+
div -> bound_select @model, "property", @options, "value"
|
62
|
+
|
63
|
+
add_remove_do bound, =>
|
64
|
+
select = bound.find("select")
|
65
|
+
equal select.find("[value=#{option.cid}]option").text(), "option1", "renders given options from collection"
|
66
|
+
|
67
|
+
options.add added_option
|
68
|
+
added_option_node = select.find("[value=#{added_option.cid}]option")
|
69
|
+
equal added_option_node.text(), "option2", "adds option to select when item added to collection"
|
70
|
+
|
71
|
+
select.val(added_option.cid)
|
72
|
+
select.trigger("change")
|
73
|
+
equal model.get("property"), added_option, "sets value on model when property chosen"
|
74
|
+
|
75
|
+
model.set property:option
|
76
|
+
equal select.val(), option.cid, "changes value of select when property set on model"
|
77
|
+
|
78
|
+
option.set value:"changed option"
|
79
|
+
equal select.find("[value=#{option.cid}]option").text(), "changed option", "changes select text when option model value changes"
|
80
|
+
|
81
|
+
options.remove option
|
82
|
+
equal select.find("[value=#{option.cid}]option").get(0), undefined, "removes option from select when item added to collection"
|
83
|
+
equal model.get("property"), added_option, "reselects another option when option removed"
|
84
|
+
|
85
|
+
test "bound_select with blank", ->
|
86
|
+
model = new AS.Model
|
87
|
+
options = new AS.Collection
|
88
|
+
option = new AS.Model value:"option1"
|
89
|
+
options.add option
|
90
|
+
|
91
|
+
with_blank = render model:model, options:options, ->
|
92
|
+
div -> bound_select @model, "property", @options, "value", blank:"blank"
|
93
|
+
|
94
|
+
add_remove_do with_blank, =>
|
95
|
+
select = with_blank.find("select")
|
96
|
+
equal select.find("option:first").text(), "blank", "includes blank option"
|
97
|
+
equal select.val(), "blank", "starts out without selection selected"
|
98
|
+
equal model.get("property"), undefined, "leaves model property clear"
|
99
|
+
|
100
|
+
test "bound_select with preselect", ->
|
101
|
+
model = new AS.Model
|
102
|
+
options = new AS.Collection
|
103
|
+
option = new AS.Model value:"option1"
|
104
|
+
options.add option
|
105
|
+
model.set property:option
|
106
|
+
|
107
|
+
with_preselect = render model:model, options:options, ->
|
108
|
+
div -> bound_select @model, "property", @options, "value", blank:"blank"
|
109
|
+
|
110
|
+
add_remove_do with_preselect, =>
|
111
|
+
select = with_preselect.find("select")
|
112
|
+
equal select.find("option:first").text(), "blank", "includes blank option"
|
113
|
+
equal select.val(), option.cid, "starts out with selection selected"
|
114
|
+
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module "AS.CK.Helpers"
|
2
|
+
test "autoId", ->
|
3
|
+
id = AS.CK.Helpers.autoId()
|
4
|
+
ok id.string != "", "selector is not blank"
|
5
|
+
ok id.string != undefined, "selector is defined"
|
6
|
+
equal id.query().selector, "##{id.string}", "gives id as a string and a selector"
|
7
|
+
|
8
|
+
test "shy", ->
|
9
|
+
shy = AS.CK.Helpers.shy("ThisShallShy")
|
10
|
+
equal shy, "This­Shall­Shy", "adds shy markers to titlecase text"
|
@@ -0,0 +1,18 @@
|
|
1
|
+
@module "AS.CK.Tags"
|
2
|
+
render = (locals, template) ->
|
3
|
+
locals.hardcode = AS.TemplateHelpers
|
4
|
+
jQuery CoffeeKup.render template, locals
|
5
|
+
|
6
|
+
test "model tag", ->
|
7
|
+
model = new AS.Model
|
8
|
+
defaults = render model:model, -> model_tag @model
|
9
|
+
tagnamed = render model:model, -> model_tag @model, tagname: "ul"
|
10
|
+
content = render model:model, ->
|
11
|
+
model_tag @model, -> p "content"
|
12
|
+
optioned = render model:model, ->
|
13
|
+
model_tag @model, key:"value"
|
14
|
+
|
15
|
+
ok defaults.is("div##{model.cid}"), "renders div with model cid by default"
|
16
|
+
ok tagnamed.is("ul##{model.cid}"), "renders tagname when given as an option"
|
17
|
+
equal content.find("p").text(), "content", "renders nested content when given as a function"
|
18
|
+
ok optioned.is("[key=value]"), "renders other options passed"
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module "AS.Collection"
|
2
|
+
test "adding a model to a collection with @inverse and @source property specified", ->
|
3
|
+
collection = new (AS.Collection.extend(inverse: "inverse", source: "source"))
|
4
|
+
model = new AS.Model
|
5
|
+
|
6
|
+
collection.add model
|
7
|
+
equal model.get('inverse'), "source", "sets collection to property on model"
|
@@ -0,0 +1,43 @@
|
|
1
|
+
for klass in [AS.Model, AS.Collection, AS.View]
|
2
|
+
module "#{klass.name} Event Extensions"
|
3
|
+
class of_prototype
|
4
|
+
of_prototype.prototype = klass.prototype
|
5
|
+
|
6
|
+
test "events bound are triggered by event with and without namespace", ->
|
7
|
+
proof = false
|
8
|
+
object = new of_prototype
|
9
|
+
object.bind "event.namespace", -> proof = true
|
10
|
+
object.trigger "event"
|
11
|
+
ok proof, "triggers without namespace"
|
12
|
+
|
13
|
+
proof = false
|
14
|
+
object.trigger "event.namespace"
|
15
|
+
ok proof, "triggers with namespace"
|
16
|
+
|
17
|
+
test "events bound without namespace are not triggered by namespace", ->
|
18
|
+
proof = false
|
19
|
+
all_proof = false
|
20
|
+
object = new of_prototype
|
21
|
+
object.bind "all", -> all_proof = true
|
22
|
+
object.bind "event", -> proof = true
|
23
|
+
object.trigger "event.namespace"
|
24
|
+
ok !proof, "doesn't trigger with namespace"
|
25
|
+
ok all_proof, "triggers all event"
|
26
|
+
|
27
|
+
test "unbind with namespace", ->
|
28
|
+
proof = false
|
29
|
+
other_proof = false
|
30
|
+
none_proof = false
|
31
|
+
object = new of_prototype
|
32
|
+
object.bind "event.namespace", -> proof = true
|
33
|
+
object.bind "event.other_namespace", -> other_proof = true
|
34
|
+
object.bind "event", -> none_proof = true
|
35
|
+
|
36
|
+
object.unbind "event.namespace"
|
37
|
+
|
38
|
+
object.trigger "event"
|
39
|
+
|
40
|
+
ok !proof, "clears binding for namespace"
|
41
|
+
ok other_proof, "doesn't clear binding for other namespace"
|
42
|
+
ok none_proof, "doesn't clear binding for no namespace"
|
43
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module "AS.Model"
|
2
|
+
test "All", ->
|
3
|
+
model = new AS.Model
|
4
|
+
equal AS.All.getByCid(model.cid), model, "All models are automatically addded to the All collection"
|
5
|
+
|
6
|
+
test "has_many", ->
|
7
|
+
class AS.HasManyModel extends AS.Model
|
8
|
+
@has_many 'things', model: -> "AS.HadModel"
|
9
|
+
class AS.HadModel extends AS.Model
|
10
|
+
|
11
|
+
deepEqual AS.HasManyModel.associations, ["things"], "stores the association in the association list"
|
12
|
+
ok AS.HasManyModel.has_manys.things, "stores a configuration for the association"
|
13
|
+
|
14
|
+
equal AS.HasManyModel.has_manys.things.model, undefined, "association collection configuration is lazy to allow associated class to load"
|
15
|
+
model = new AS.HasManyModel
|
16
|
+
equal AS.HasManyModel.has_manys.things.model, AS.HadModel, "configures the collection class properly when needed"
|
17
|
+
|
18
|
+
equal model.get("things").model, AS.HadModel, "association collection is auto-created"
|
19
|
+
|
20
|
+
model.get("things").add {}
|
21
|
+
|
22
|
+
equal model.get("things").at(0).constructor, AS.HadModel, "items added to the association are properly instantiated"
|
23
|
+
|
24
|
+
model2 = new AS.HasManyModel
|
25
|
+
things: [{}]
|
26
|
+
|
27
|
+
equal model2.get("things").at(0).constructor, AS.HadModel, "items passed to constructor for the association are properly instantiated"
|
28
|
+
|
29
|
+
test "belongs to", ->
|
30
|
+
class AS.Belonging extends AS.Model
|
31
|
+
@belongs_to "parent"
|
32
|
+
class AS.Owner extends AS.Model
|
33
|
+
|
34
|
+
deepEqual AS.Belonging.associations, ["parent"], "stores the association on the class"
|
35
|
+
|
36
|
+
ok AS.Belonging.belongs_to.parent, "stores a configuration object for the association on the class"
|
37
|
+
|
38
|
+
owner = new AS.Owner id:"OWNERID"
|
39
|
+
model = new AS.Belonging
|
40
|
+
|
41
|
+
model.set parent:owner
|
42
|
+
|
43
|
+
equal model.get("parent"), owner, "correctly sets the owner"
|
44
|
+
|
45
|
+
model = new AS.Belonging
|
46
|
+
|
47
|
+
model.set parent:owner.get("id")
|
48
|
+
equal model.get("parent"), owner, "correctly sets the from a string id"
|
49
|
+
|
50
|
+
proof = false
|
51
|
+
model.bind "change:parent", -> proof = true
|
52
|
+
owner.set some:"value"
|
53
|
+
|
54
|
+
ok proof, "association changes trigger on the child"
|
55
|
+
|
56
|
+
proof = false
|
57
|
+
new_owner = new AS.Owner
|
58
|
+
model.set parent: new_owner
|
59
|
+
new_owner.set some:"other value"
|
60
|
+
|
61
|
+
ok proof, "changes trigger when associated model is changed"
|
62
|
+
|
63
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module "AS.View"
|
2
|
+
test "::klass_string()", ->
|
3
|
+
equal new AS.View().klass_string(), "ASView", "basic klass_string is ASView"
|
4
|
+
|
5
|
+
class SomeView extends AS.View
|
6
|
+
|
7
|
+
equal new SomeView().klass_string(), "ASView.SomeView", "subclasses include parent class string"
|
8
|
+
|
9
|
+
test "::element_string()", ->
|
10
|
+
equal new AS.View().element_string(), "div.ASView", "defaults to a div + klass_string"
|
11
|
+
equal new AS.View(tagName:"tagname").element_string(), "tagname.ASView", "allows setting of a tag"
|
12
|
+
|
13
|
+
model = {cid: "cid"}
|
14
|
+
|
15
|
+
equal new AS.View(model:model).element_string(), "div.ASView#cid.Object", "uses the cid/class of an associated model as the dom id/class"
|
16
|
+
|
17
|
+
test "::build_element()", ->
|
18
|
+
ok new AS.View().build_element().is(new AS.View().element_string()), "uses jQuery.satisfy to build the element"
|
19
|
+
model = {cid: "cid"}
|
20
|
+
ok new AS.View(model:model).build_element().is(new AS.View(model:model).element_string()), "with more complex element"
|
21
|
+
|
22
|
+
test "element is jquery wrapped", ->
|
23
|
+
equal new AS.View().el.constructor, jQuery
|
24
|
+
|
25
|
+
test "configuration", ->
|
26
|
+
view = new AS.View option:"OPTION"
|
27
|
+
equal view.option, "OPTION", "allow setting of arbitrary options from constructor"
|
28
|
+
|
29
|
+
test "event delegation", ->
|
30
|
+
click_proof = false
|
31
|
+
member_proof = false
|
32
|
+
button_proof = false
|
33
|
+
guard_pass_proof = false
|
34
|
+
guard_fail_proof = false
|
35
|
+
|
36
|
+
class BoundView extends AS.View
|
37
|
+
constructor: ->
|
38
|
+
@member = new AS.Model
|
39
|
+
super
|
40
|
+
@el.append @button = jQuery.satisfy("button")
|
41
|
+
@render()
|
42
|
+
|
43
|
+
events:
|
44
|
+
"click": "click_handler"
|
45
|
+
"click button": "button_handler"
|
46
|
+
"event @member": "member_handler"
|
47
|
+
"pass{pass:true} @member": "guard_pass_handler"
|
48
|
+
"fail{pass:false} @member": "guard_fail_handler"
|
49
|
+
|
50
|
+
click_handler: -> click_proof = true
|
51
|
+
member_handler: -> member_proof = true
|
52
|
+
button_handler: -> button_proof = true
|
53
|
+
guard_fail_handler: -> guard_fail_proof = true
|
54
|
+
guard_pass_handler: -> guard_pass_proof = true
|
55
|
+
|
56
|
+
render: -> @el.appendTo(document.body)
|
57
|
+
|
58
|
+
view = new BoundView
|
59
|
+
|
60
|
+
view.el.click()
|
61
|
+
view.member.trigger("event")
|
62
|
+
view.button.click()
|
63
|
+
view.member.trigger("pass", pass: true)
|
64
|
+
view.member.trigger("fail", pass: true)
|
65
|
+
|
66
|
+
ok click_proof, "binds simple dom events to view element"
|
67
|
+
ok member_proof, "binds to events of member objects"
|
68
|
+
ok button_proof, "binds to events of elements inside view"
|
69
|
+
ok guard_pass_proof, "correct values get past the guard"
|
70
|
+
ok !guard_fail_proof, "incorrect values blocked by the guard"
|
71
|
+
|
72
|
+
view.el.remove()
|
@@ -0,0 +1,8 @@
|
|
1
|
+
module "AS.Views.Stage"
|
2
|
+
test "is a Panel", ->
|
3
|
+
ok (new AS.Views.Stage).el.is(".Panel")
|
4
|
+
test "Comes with a canvas inside it", ->
|
5
|
+
view = new AS.Views.Stage
|
6
|
+
ok view.el.find(".Canvas").is(".ASView")
|
7
|
+
test "allows setting any canvas", ->
|
8
|
+
equal (new AS.Views.Stage canvas:"canvas").canvas, "canvas"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module "AS.Views.HorizontalSplit"
|
2
|
+
test "contains left, right and splitter elemens", ->
|
3
|
+
view = new AS.Views.HorizontalSplit()
|
4
|
+
|
5
|
+
equal view.el.find(".Panel").length, 2, "contains two panels"
|
6
|
+
ok view.el.find(":nth-child(2)").is(".Splitter"), "with a splitter in the middle"
|
7
|
+
|
8
|
+
test "allows configurable left, right and splitter elements", ->
|
9
|
+
view = new AS.Views.HorizontalSplit
|
10
|
+
left: 'left', right: 'right', splitter: 'splitter'
|
11
|
+
|
12
|
+
deepEqual [view.left, view.right, view.splitter], 'left right splitter'.split(" "), "lets you set them"
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module "AS.Views.VerticalSplit"
|
2
|
+
test "contains top, bottom and splitter elemens", ->
|
3
|
+
view = new AS.Views.VerticalSplit()
|
4
|
+
|
5
|
+
equal view.el.find(".Panel").length, 2, "contains two panels"
|
6
|
+
ok view.el.find(":nth-child(2)").is(".Splitter"), "with a splitter in the middle"
|
7
|
+
|
8
|
+
test "allows configurable top, bottom and splitter elements", ->
|
9
|
+
view = new AS.Views.VerticalSplit
|
10
|
+
top: 'top', bottom: 'bottom', splitter: 'splitter'
|
11
|
+
|
12
|
+
deepEqual [view.top, view.bottom, view.splitter], 'top bottom splitter'.split(" "), "lets you set them"
|
13
|
+
|
@@ -0,0 +1,345 @@
|
|
1
|
+
$(document).ready(function() {
|
2
|
+
|
3
|
+
module("Backbone.Collection");
|
4
|
+
|
5
|
+
window.lastRequest = null;
|
6
|
+
|
7
|
+
Backbone.sync = function() {
|
8
|
+
lastRequest = _.toArray(arguments);
|
9
|
+
};
|
10
|
+
|
11
|
+
var a = new Backbone.Model({id: 3, label: 'a'});
|
12
|
+
var b = new Backbone.Model({id: 2, label: 'b'});
|
13
|
+
var c = new Backbone.Model({id: 1, label: 'c'});
|
14
|
+
var d = new Backbone.Model({id: 0, label: 'd'});
|
15
|
+
var e = null;
|
16
|
+
var col = new Backbone.Collection([a,b,c,d]);
|
17
|
+
var otherCol = new Backbone.Collection();
|
18
|
+
|
19
|
+
test("Collection: new and sort", function() {
|
20
|
+
equals(col.first(), a, "a should be first");
|
21
|
+
equals(col.last(), d, "d should be last");
|
22
|
+
col.comparator = function(model) { return model.id; };
|
23
|
+
col.sort();
|
24
|
+
equals(col.first(), d, "d should be first");
|
25
|
+
equals(col.last(), a, "a should be last");
|
26
|
+
equals(col.length, 4);
|
27
|
+
});
|
28
|
+
|
29
|
+
test("Collection: get, getByCid", function() {
|
30
|
+
equals(col.get(0), d);
|
31
|
+
equals(col.get(2), b);
|
32
|
+
equals(col.getByCid(col.first().cid), col.first());
|
33
|
+
});
|
34
|
+
|
35
|
+
test("Collection: get with non-default ids", function() {
|
36
|
+
var col = new Backbone.Collection();
|
37
|
+
var MongoModel = Backbone.Model.extend({
|
38
|
+
idAttribute: '_id'
|
39
|
+
});
|
40
|
+
var model = new MongoModel({_id: 100});
|
41
|
+
col.add(model);
|
42
|
+
equals(col.get(100), model);
|
43
|
+
model.set({_id: 101});
|
44
|
+
equals(col.get(101), model);
|
45
|
+
});
|
46
|
+
|
47
|
+
test("Collection: update index when id changes", function() {
|
48
|
+
var col = new Backbone.Collection();
|
49
|
+
col.add([
|
50
|
+
{id : 0, name : 'one'},
|
51
|
+
{id : 1, name : 'two'}
|
52
|
+
]);
|
53
|
+
var one = col.get(0);
|
54
|
+
equals(one.get('name'), 'one');
|
55
|
+
one.set({id : 101});
|
56
|
+
equals(col.get(0), null);
|
57
|
+
equals(col.get(101).get('name'), 'one');
|
58
|
+
});
|
59
|
+
|
60
|
+
test("Collection: at", function() {
|
61
|
+
equals(col.at(2), b);
|
62
|
+
});
|
63
|
+
|
64
|
+
test("Collection: pluck", function() {
|
65
|
+
equals(col.pluck('label').join(' '), 'd c b a');
|
66
|
+
});
|
67
|
+
|
68
|
+
test("Collection: add", function() {
|
69
|
+
var added = opts = secondAdded = null;
|
70
|
+
e = new Backbone.Model({id: 10, label : 'e'});
|
71
|
+
otherCol.add(e);
|
72
|
+
otherCol.bind('add', function() {
|
73
|
+
secondAdded = true;
|
74
|
+
});
|
75
|
+
col.bind('add', function(model, collection, options){
|
76
|
+
added = model.get('label');
|
77
|
+
opts = options;
|
78
|
+
});
|
79
|
+
col.add(e, {amazing: true});
|
80
|
+
equals(added, 'e');
|
81
|
+
equals(col.length, 5);
|
82
|
+
equals(col.last(), e);
|
83
|
+
equals(otherCol.length, 1);
|
84
|
+
equals(secondAdded, null);
|
85
|
+
ok(opts.amazing);
|
86
|
+
|
87
|
+
var f = new Backbone.Model({id: 20, label : 'f'});
|
88
|
+
var g = new Backbone.Model({id: 21, label : 'g'});
|
89
|
+
var h = new Backbone.Model({id: 22, label : 'h'});
|
90
|
+
var atCol = new Backbone.Collection([f, g, h]);
|
91
|
+
equals(atCol.length, 3);
|
92
|
+
atCol.add(e, {at: 1});
|
93
|
+
equals(atCol.length, 4);
|
94
|
+
equals(atCol.at(1), e);
|
95
|
+
equals(atCol.last(), h);
|
96
|
+
});
|
97
|
+
|
98
|
+
test("Collection: add model to collection twice", function() {
|
99
|
+
try {
|
100
|
+
// no id, same cid
|
101
|
+
var a2 = new Backbone.Model({label: a.label});
|
102
|
+
a2.cid = a.cid;
|
103
|
+
col.add(a2);
|
104
|
+
ok(false, "duplicate; expected add to fail");
|
105
|
+
} catch (e) {
|
106
|
+
equals(e.message, "Can't add the same model to a set twice,3");
|
107
|
+
}
|
108
|
+
});
|
109
|
+
|
110
|
+
test("Collection: add model to multiple collections", function() {
|
111
|
+
var counter = 0;
|
112
|
+
var e = new Backbone.Model({id: 10, label : 'e'});
|
113
|
+
e.bind('add', function(model, collection) {
|
114
|
+
counter++;
|
115
|
+
equals(e, model);
|
116
|
+
if (counter > 1) {
|
117
|
+
equals(collection, colF);
|
118
|
+
} else {
|
119
|
+
equals(collection, colE);
|
120
|
+
}
|
121
|
+
});
|
122
|
+
var colE = new Backbone.Collection([]);
|
123
|
+
colE.bind('add', function(model, collection) {
|
124
|
+
equals(e, model);
|
125
|
+
equals(colE, collection);
|
126
|
+
});
|
127
|
+
var colF = new Backbone.Collection([]);
|
128
|
+
colF.bind('add', function(model, collection) {
|
129
|
+
equals(e, model);
|
130
|
+
equals(colF, collection);
|
131
|
+
});
|
132
|
+
colE.add(e);
|
133
|
+
equals(e.collection, colE);
|
134
|
+
colF.add(e);
|
135
|
+
equals(e.collection, colE);
|
136
|
+
});
|
137
|
+
|
138
|
+
test("Collection: remove", function() {
|
139
|
+
var removed = otherRemoved = null;
|
140
|
+
col.bind('remove', function(model){ removed = model.get('label'); });
|
141
|
+
otherCol.bind('remove', function(){ otherRemoved = true; });
|
142
|
+
col.remove(e);
|
143
|
+
equals(removed, 'e');
|
144
|
+
equals(col.length, 4);
|
145
|
+
equals(col.first(), d);
|
146
|
+
equals(otherRemoved, null);
|
147
|
+
});
|
148
|
+
|
149
|
+
test("Collection: events are unbound on remove", function() {
|
150
|
+
var counter = 0;
|
151
|
+
var dj = new Backbone.Model();
|
152
|
+
var emcees = new Backbone.Collection([dj]);
|
153
|
+
emcees.bind('change', function(){ counter++; });
|
154
|
+
dj.set({name : 'Kool'});
|
155
|
+
equals(counter, 1);
|
156
|
+
emcees.reset([]);
|
157
|
+
equals(dj.collection, undefined);
|
158
|
+
dj.set({name : 'Shadow'});
|
159
|
+
equals(counter, 1);
|
160
|
+
});
|
161
|
+
|
162
|
+
test("Collection: remove in multiple collections", function() {
|
163
|
+
var modelData = {
|
164
|
+
id : 5,
|
165
|
+
title : 'Othello'
|
166
|
+
};
|
167
|
+
var passed = false;
|
168
|
+
var e = new Backbone.Model(modelData);
|
169
|
+
var f = new Backbone.Model(modelData);
|
170
|
+
f.bind('remove', function() {
|
171
|
+
passed = true;
|
172
|
+
});
|
173
|
+
var colE = new Backbone.Collection([e]);
|
174
|
+
var colF = new Backbone.Collection([f]);
|
175
|
+
ok(e != f);
|
176
|
+
ok(colE.length == 1);
|
177
|
+
ok(colF.length == 1);
|
178
|
+
colE.remove(e);
|
179
|
+
equals(passed, false);
|
180
|
+
ok(colE.length == 0);
|
181
|
+
colF.remove(e);
|
182
|
+
ok(colF.length == 0);
|
183
|
+
equals(passed, true);
|
184
|
+
});
|
185
|
+
|
186
|
+
test("Collection: remove same model in multiple collection", function() {
|
187
|
+
var counter = 0;
|
188
|
+
var e = new Backbone.Model({id: 5, title: 'Othello'});
|
189
|
+
e.bind('remove', function(model, collection) {
|
190
|
+
counter++;
|
191
|
+
equals(e, model);
|
192
|
+
if (counter > 1) {
|
193
|
+
equals(collection, colE);
|
194
|
+
} else {
|
195
|
+
equals(collection, colF);
|
196
|
+
}
|
197
|
+
});
|
198
|
+
var colE = new Backbone.Collection([e]);
|
199
|
+
colE.bind('remove', function(model, collection) {
|
200
|
+
equals(e, model);
|
201
|
+
equals(colE, collection);
|
202
|
+
});
|
203
|
+
var colF = new Backbone.Collection([e]);
|
204
|
+
colF.bind('remove', function(model, collection) {
|
205
|
+
equals(e, model);
|
206
|
+
equals(colF, collection);
|
207
|
+
});
|
208
|
+
equals(colE, e.collection);
|
209
|
+
colF.remove(e);
|
210
|
+
ok(colF.length == 0);
|
211
|
+
ok(colE.length == 1);
|
212
|
+
equals(counter, 1);
|
213
|
+
equals(colE, e.collection);
|
214
|
+
colE.remove(e);
|
215
|
+
equals(null, e.collection);
|
216
|
+
ok(colE.length == 0);
|
217
|
+
equals(counter, 2);
|
218
|
+
});
|
219
|
+
|
220
|
+
test("Collection: model destroy removes from all collections", function() {
|
221
|
+
var e = new Backbone.Model({id: 5, title: 'Othello'});
|
222
|
+
e.sync = function(method, model, options) { options.success({}); };
|
223
|
+
var colE = new Backbone.Collection([e]);
|
224
|
+
var colF = new Backbone.Collection([e]);
|
225
|
+
e.destroy();
|
226
|
+
ok(colE.length == 0);
|
227
|
+
ok(colF.length == 0);
|
228
|
+
equals(null, e.collection);
|
229
|
+
});
|
230
|
+
|
231
|
+
test("Colllection: non-persisted model destroy removes from all collections", function() {
|
232
|
+
var e = new Backbone.Model({title: 'Othello'});
|
233
|
+
e.sync = function(method, model, options) { throw "should not be called"; };
|
234
|
+
var colE = new Backbone.Collection([e]);
|
235
|
+
var colF = new Backbone.Collection([e]);
|
236
|
+
e.destroy();
|
237
|
+
ok(colE.length == 0);
|
238
|
+
ok(colF.length == 0);
|
239
|
+
equals(null, e.collection);
|
240
|
+
});
|
241
|
+
|
242
|
+
test("Collection: fetch", function() {
|
243
|
+
col.fetch();
|
244
|
+
equals(lastRequest[0], 'read');
|
245
|
+
equals(lastRequest[1], col);
|
246
|
+
});
|
247
|
+
|
248
|
+
test("Collection: create", function() {
|
249
|
+
var model = col.create({label: 'f'});
|
250
|
+
equals(lastRequest[0], 'create');
|
251
|
+
equals(lastRequest[1], model);
|
252
|
+
equals(model.get('label'), 'f');
|
253
|
+
equals(model.collection, col);
|
254
|
+
});
|
255
|
+
|
256
|
+
test("Collection: create enforces validation", function() {
|
257
|
+
var ValidatingModel = Backbone.Model.extend({
|
258
|
+
validate: function(attrs) {
|
259
|
+
return "fail";
|
260
|
+
}
|
261
|
+
});
|
262
|
+
var ValidatingCollection = Backbone.Collection.extend({
|
263
|
+
model: ValidatingModel
|
264
|
+
});
|
265
|
+
var col = new ValidatingCollection();
|
266
|
+
equals(col.create({"foo":"bar"}),false);
|
267
|
+
});
|
268
|
+
|
269
|
+
test("Collection: a failing create runs the error callback", function() {
|
270
|
+
var ValidatingModel = Backbone.Model.extend({
|
271
|
+
validate: function(attrs) {
|
272
|
+
return "fail";
|
273
|
+
}
|
274
|
+
});
|
275
|
+
var ValidatingCollection = Backbone.Collection.extend({
|
276
|
+
model: ValidatingModel
|
277
|
+
});
|
278
|
+
var flag = false;
|
279
|
+
var callback = function(model, error) { flag = true; };
|
280
|
+
var col = new ValidatingCollection();
|
281
|
+
col.create({"foo":"bar"}, { error: callback });
|
282
|
+
equals(flag, true);
|
283
|
+
});
|
284
|
+
|
285
|
+
test("collection: initialize", function() {
|
286
|
+
var Collection = Backbone.Collection.extend({
|
287
|
+
initialize: function() {
|
288
|
+
this.one = 1;
|
289
|
+
}
|
290
|
+
});
|
291
|
+
var coll = new Collection;
|
292
|
+
equals(coll.one, 1);
|
293
|
+
});
|
294
|
+
|
295
|
+
test("Collection: toJSON", function() {
|
296
|
+
equals(JSON.stringify(col), '[{"id":0,"label":"d"},{"id":1,"label":"c"},{"id":2,"label":"b"},{"id":3,"label":"a"}]');
|
297
|
+
});
|
298
|
+
|
299
|
+
test("Collection: Underscore methods", function() {
|
300
|
+
equals(col.map(function(model){ return model.get('label'); }).join(' '), 'd c b a');
|
301
|
+
equals(col.any(function(model){ return model.id === 100; }), false);
|
302
|
+
equals(col.any(function(model){ return model.id === 0; }), true);
|
303
|
+
equals(col.indexOf(b), 2);
|
304
|
+
equals(col.size(), 4);
|
305
|
+
equals(col.rest().length, 3);
|
306
|
+
ok(!_.include(col.rest()), a);
|
307
|
+
ok(!_.include(col.rest()), d);
|
308
|
+
ok(!col.isEmpty());
|
309
|
+
ok(!_.include(col.without(d)), d);
|
310
|
+
equals(col.max(function(model){ return model.id; }).id, 3);
|
311
|
+
equals(col.min(function(model){ return model.id; }).id, 0);
|
312
|
+
same(col.chain()
|
313
|
+
.filter(function(o){ return o.id % 2 === 0; })
|
314
|
+
.map(function(o){ return o.id * 2; })
|
315
|
+
.value(),
|
316
|
+
[0, 4]);
|
317
|
+
});
|
318
|
+
|
319
|
+
test("Collection: reset", function() {
|
320
|
+
var resetCount = 0;
|
321
|
+
var models = col.models;
|
322
|
+
col.bind('reset', function() { resetCount += 1; });
|
323
|
+
col.reset([]);
|
324
|
+
equals(resetCount, 1);
|
325
|
+
equals(col.length, 0);
|
326
|
+
equals(col.last(), null);
|
327
|
+
col.reset(models);
|
328
|
+
equals(resetCount, 2);
|
329
|
+
equals(col.length, 4);
|
330
|
+
equals(col.last(), a);
|
331
|
+
col.reset(_.map(models, function(m){ return m.attributes; }));
|
332
|
+
equals(resetCount, 3);
|
333
|
+
equals(col.length, 4);
|
334
|
+
ok(col.last() !== a);
|
335
|
+
ok(_.isEqual(col.last().attributes, a.attributes));
|
336
|
+
});
|
337
|
+
|
338
|
+
test("Collection: trigger custom events on models", function() {
|
339
|
+
var fired = null;
|
340
|
+
a.bind("custom", function() { fired = true; });
|
341
|
+
a.trigger("custom");
|
342
|
+
equals(fired, true);
|
343
|
+
});
|
344
|
+
|
345
|
+
});
|