luca 0.6.6
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/.gitignore +5 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +77 -0
- data/Guardfile +22 -0
- data/README.md +291 -0
- data/Rakefile +28 -0
- data/app.rb +46 -0
- data/assets/images/glyphicons-halflings-white.png +0 -0
- data/assets/images/glyphicons-halflings.png +0 -0
- data/assets/javascripts/dependencies/backbone-min.js +37 -0
- data/assets/javascripts/dependencies/backbone-query.min.js +1 -0
- data/assets/javascripts/dependencies/bootstrap.min.js +1 -0
- data/assets/javascripts/dependencies/jasmine-html.js +190 -0
- data/assets/javascripts/dependencies/jasmine.js +2476 -0
- data/assets/javascripts/dependencies/jquery.js +4 -0
- data/assets/javascripts/dependencies/modal.js +698 -0
- data/assets/javascripts/dependencies/modernizr.min.js +30 -0
- data/assets/javascripts/dependencies/prettify.js +28 -0
- data/assets/javascripts/dependencies/sinon.js +3469 -0
- data/assets/javascripts/dependencies/spin-min.js +2 -0
- data/assets/javascripts/dependencies/underscore-min.js +31 -0
- data/assets/javascripts/dependencies/underscore-string.min.js +14 -0
- data/assets/javascripts/dependencies.coffee +7 -0
- data/assets/javascripts/luca-ui-base.coffee +12 -0
- data/assets/javascripts/luca-ui-spec.coffee +2 -0
- data/assets/javascripts/luca-ui.coffee +3 -0
- data/assets/javascripts/sandbox/collections/sample.coffee +0 -0
- data/assets/javascripts/sandbox/config.coffee +7 -0
- data/assets/javascripts/sandbox/sandbox.coffee +16 -0
- data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +33 -0
- data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +48 -0
- data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +24 -0
- data/assets/javascripts/sandbox/templates/features/introduction.luca +11 -0
- data/assets/javascripts/sandbox/templates/features/view_helpers.luca +43 -0
- data/assets/javascripts/sandbox/templates/navigation.luca +8 -0
- data/assets/javascripts/sandbox/views/form_demo.coffee +47 -0
- data/assets/javascripts/sandbox/views/grid_demo.coffee +23 -0
- data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +1 -0
- data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +28 -0
- data/assets/javascripts/sandbox.coffee +4 -0
- data/assets/javascripts/spec-dependencies.coffee +4 -0
- data/assets/stylesheets/bootstrap-responsive.min.css +3 -0
- data/assets/stylesheets/bootstrap.min.css +610 -0
- data/assets/stylesheets/jasmine.css +166 -0
- data/assets/stylesheets/luca-ui-bootstrap.css +5 -0
- data/assets/stylesheets/luca-ui-spec.css +3 -0
- data/assets/stylesheets/luca-ui.css +3 -0
- data/assets/stylesheets/prettify.css +40 -0
- data/assets/stylesheets/sandbox/sandbox.scss +4 -0
- data/assets/stylesheets/sandbox.css +3 -0
- data/config.ru +11 -0
- data/lib/luca/command_line.rb +69 -0
- data/lib/luca/rails/engine.rb +12 -0
- data/lib/luca/rails/version.rb +6 -0
- data/lib/luca/rails.rb +9 -0
- data/lib/luca/template.rb +51 -0
- data/lib/luca/test_harness.rb +106 -0
- data/lib/luca.rb +1 -0
- data/lib/sprockets/luca_template.rb +49 -0
- data/lib/templates/spec_manifest_javascripts.erb +7 -0
- data/lib/templates/spec_manifest_stylesheets.erb +11 -0
- data/luca.gemspec +26 -0
- data/public/jasmine/index.html +26 -0
- data/public/sandbox/api.js +1 -0
- data/spec/components/application_spec.coffee +0 -0
- data/spec/components/collection_loader_view_spec.coffee +0 -0
- data/spec/components/controller_spec.coffee +0 -0
- data/spec/components/form_view_spec.coffee +13 -0
- data/spec/components/grid_view_spec.coffee +0 -0
- data/spec/components/record_manager_spec.coffee +0 -0
- data/spec/components/template_spec.coffee +0 -0
- data/spec/containers/card_view_spec.coffee +1 -0
- data/spec/containers/column_view_spec.coffee +0 -0
- data/spec/containers/modal_view_spec.coffee +0 -0
- data/spec/containers/panel_view_spec.coffee +0 -0
- data/spec/containers/split_view_spec.coffee +0 -0
- data/spec/containers/tab_view_spec.coffee +0 -0
- data/spec/containers/viewport_spec.coffee +0 -0
- data/spec/core/collection_spec.coffee +215 -0
- data/spec/core/container_spec.coffee +0 -0
- data/spec/core/field_spec.coffee +0 -0
- data/spec/core/observer_spec.coffee +0 -0
- data/spec/core/view_spec.coffee +87 -0
- data/spec/framework_spec.coffee +48 -0
- data/spec/helper.coffee +120 -0
- data/spec/managers/collection_manager_spec.coffee +95 -0
- data/spec/managers/socket_manager_spec.coffee +0 -0
- data/src/components/application.coffee +83 -0
- data/src/components/base_toolbar.coffee +16 -0
- data/src/components/collection_loader_view.coffee +37 -0
- data/src/components/controller.coffee +41 -0
- data/src/components/fields/button_field.coffee +40 -0
- data/src/components/fields/checkbox_field.coffee +41 -0
- data/src/components/fields/file_upload_field.coffee +15 -0
- data/src/components/fields/hidden_field.coffee +18 -0
- data/src/components/fields/select_field.coffee +100 -0
- data/src/components/fields/text_area_field.coffee +43 -0
- data/src/components/fields/text_field.coffee +42 -0
- data/src/components/fields/type_ahead_field.coffee +10 -0
- data/src/components/form_button_toolbar.coffee +26 -0
- data/src/components/form_view.coffee +205 -0
- data/src/components/grid_view.coffee +208 -0
- data/src/components/record_manager.coffee +215 -0
- data/src/components/router.coffee +34 -0
- data/src/components/template.coffee +19 -0
- data/src/containers/card_view.coffee +89 -0
- data/src/containers/column_view.coffee +48 -0
- data/src/containers/modal_view.coffee +85 -0
- data/src/containers/panel_view.coffee +24 -0
- data/src/containers/split_view.coffee +12 -0
- data/src/containers/tab_view.coffee +77 -0
- data/src/containers/viewport.coffee +16 -0
- data/src/core/collection.coffee +319 -0
- data/src/core/container.coffee +256 -0
- data/src/core/field.coffee +68 -0
- data/src/core/observer.coffee +17 -0
- data/src/core/view.coffee +190 -0
- data/src/framework.coffee +110 -0
- data/src/index.coffee +255 -0
- data/src/managers/collection_manager.coffee +168 -0
- data/src/managers/socket_manager.coffee +54 -0
- data/src/modules/deferrable.coffee +18 -0
- data/src/modules/local_storage.coffee +50 -0
- data/src/stylesheets/base.scss +78 -0
- data/src/stylesheets/components/form_view.scss +54 -0
- data/src/stylesheets/components/grid_view.scss +111 -0
- data/src/stylesheets/components/toolbar.scss +15 -0
- data/src/stylesheets/containers/container.scss +7 -0
- data/src/stylesheets/containers/modal_view.scss +0 -0
- data/src/stylesheets/containers/tab_view.scss +33 -0
- data/src/stylesheets/normalize.scss +430 -0
- data/src/templates/components/bootstrap_form_controls.luca +7 -0
- data/src/templates/components/collection_loader_view.luca +5 -0
- data/src/templates/components/form_view.luca +15 -0
- data/src/templates/components/grid_view.luca +9 -0
- data/src/templates/components/grid_view_empty_text.luca +3 -0
- data/src/templates/containers/basic.luca +1 -0
- data/src/templates/containers/tab_selector_container.luca +8 -0
- data/src/templates/containers/tab_view.luca +1 -0
- data/src/templates/containers/toolbar_wrapper.luca +1 -0
- data/src/templates/fields/button_field.luca +2 -0
- data/src/templates/fields/button_field_link.luca +5 -0
- data/src/templates/fields/checkbox_field.luca +9 -0
- data/src/templates/fields/file_upload_field.luca +8 -0
- data/src/templates/fields/hidden_field.luca +1 -0
- data/src/templates/fields/select_field.luca +7 -0
- data/src/templates/fields/text_area_field.luca +8 -0
- data/src/templates/fields/text_field.luca +13 -0
- data/src/templates/sample/contents.luca +1 -0
- data/src/templates/sample/welcome.luca +1 -0
- data/vendor/assets/images/glyphicons-halflings-white.png +0 -0
- data/vendor/assets/images/glyphicons-halflings.png +0 -0
- data/vendor/assets/javascripts/luca-spec-dependencies.js +6135 -0
- data/vendor/assets/javascripts/luca-ui-base.js +1527 -0
- data/vendor/assets/javascripts/luca-ui-spec.js +3654 -0
- data/vendor/assets/javascripts/luca-ui.js +2763 -0
- data/vendor/assets/luca-ui/base.css +85 -0
- data/vendor/assets/luca-ui/components/application.js +91 -0
- data/vendor/assets/luca-ui/components/base_toolbar.js +23 -0
- data/vendor/assets/luca-ui/components/controller.js +38 -0
- data/vendor/assets/luca-ui/components/fields/button_field.js +45 -0
- data/vendor/assets/luca-ui/components/fields/checkbox_field.js +43 -0
- data/vendor/assets/luca-ui/components/fields/file_upload_field.js +20 -0
- data/vendor/assets/luca-ui/components/fields/hidden_field.js +20 -0
- data/vendor/assets/luca-ui/components/fields/select_field.js +97 -0
- data/vendor/assets/luca-ui/components/fields/text_area_field.js +48 -0
- data/vendor/assets/luca-ui/components/fields/text_field.js +46 -0
- data/vendor/assets/luca-ui/components/fields/type_ahead_field.js +13 -0
- data/vendor/assets/luca-ui/components/form_button_toolbar.js +32 -0
- data/vendor/assets/luca-ui/components/form_view.css +32 -0
- data/vendor/assets/luca-ui/components/form_view.js +207 -0
- data/vendor/assets/luca-ui/components/grid_view.css +76 -0
- data/vendor/assets/luca-ui/components/grid_view.js +202 -0
- data/vendor/assets/luca-ui/components/record_manager.js +207 -0
- data/vendor/assets/luca-ui/components/router.js +36 -0
- data/vendor/assets/luca-ui/components/template.js +26 -0
- data/vendor/assets/luca-ui/components/toolbar.css +11 -0
- data/vendor/assets/luca-ui/containers/card_view.js +98 -0
- data/vendor/assets/luca-ui/containers/column_view.js +52 -0
- data/vendor/assets/luca-ui/containers/container.css +3 -0
- data/vendor/assets/luca-ui/containers/modal_view.css +0 -0
- data/vendor/assets/luca-ui/containers/modal_view.js +87 -0
- data/vendor/assets/luca-ui/containers/panel_view.js +34 -0
- data/vendor/assets/luca-ui/containers/split_view.js +13 -0
- data/vendor/assets/luca-ui/containers/tab_view.css +16 -0
- data/vendor/assets/luca-ui/containers/tab_view.js +80 -0
- data/vendor/assets/luca-ui/containers/viewport.js +18 -0
- data/vendor/assets/luca-ui/core/collection.js +221 -0
- data/vendor/assets/luca-ui/core/container.js +205 -0
- data/vendor/assets/luca-ui/core/field.js +59 -0
- data/vendor/assets/luca-ui/core/observer.js +42 -0
- data/vendor/assets/luca-ui/core/view.js +127 -0
- data/vendor/assets/luca-ui/framework.js +110 -0
- data/vendor/assets/luca-ui/index.js +5 -0
- data/vendor/assets/luca-ui/managers/collection_manager.js +98 -0
- data/vendor/assets/luca-ui/managers/socket_manager.js +52 -0
- data/vendor/assets/luca-ui/modules/deferrable.js +21 -0
- data/vendor/assets/luca-ui/modules/local_storage.js +81 -0
- data/vendor/assets/luca-ui/normalize.css +359 -0
- data/vendor/assets/luca-ui/stylesheets/base.css +85 -0
- data/vendor/assets/luca-ui/stylesheets/components/form_view.css +32 -0
- data/vendor/assets/luca-ui/stylesheets/components/grid_view.css +76 -0
- data/vendor/assets/luca-ui/stylesheets/components/toolbar.css +11 -0
- data/vendor/assets/luca-ui/stylesheets/containers/container.css +3 -0
- data/vendor/assets/luca-ui/stylesheets/containers/modal_view.css +0 -0
- data/vendor/assets/luca-ui/stylesheets/containers/tab_view.css +16 -0
- data/vendor/assets/luca-ui/stylesheets/normalize.css +359 -0
- data/vendor/assets/luca-ui/templates/components/bootstrap_form_controls.js +4 -0
- data/vendor/assets/luca-ui/templates/components/form_view.js +4 -0
- data/vendor/assets/luca-ui/templates/components/grid_view.js +4 -0
- data/vendor/assets/luca-ui/templates/components/grid_view_empty_text.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/basic.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/tab_selector_container.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/tab_view.js +4 -0
- data/vendor/assets/luca-ui/templates/containers/toolbar_wrapper.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/button_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/button_field_link.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/checkbox_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/file_upload_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/hidden_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/select_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/text_area_field.js +4 -0
- data/vendor/assets/luca-ui/templates/fields/text_field.js +4 -0
- data/vendor/assets/luca-ui/templates/sample/contents.js +4 -0
- data/vendor/assets/luca-ui/templates/sample/welcome.js +4 -0
- data/vendor/assets/stylesheets/luca-spec-dependencies.css +166 -0
- data/vendor/assets/stylesheets/luca-ui-bootstrap.css +1201 -0
- data/vendor/assets/stylesheets/luca-ui-spec.css +586 -0
- data/vendor/assets/stylesheets/luca-ui.css +586 -0
- data/views/index.erb +20 -0
- data/views/jasmine.erb +22 -0
- data/views/spec_harness.erb +29 -0
- metadata +361 -0
|
File without changes
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
describe 'The Form View', ->
|
|
2
|
+
describe 'Generating a form from a model', ->
|
|
3
|
+
beforeEach ->
|
|
4
|
+
Model = Backbone.Model.extend
|
|
5
|
+
schema:
|
|
6
|
+
field0: "hidden"
|
|
7
|
+
field1: "text"
|
|
8
|
+
field3: "boolean"
|
|
9
|
+
field4: "blob"
|
|
10
|
+
field5:
|
|
11
|
+
collection: "sample"
|
|
12
|
+
|
|
13
|
+
@model = new Model(field0:1,field1:"jonathan",field3:true,field4:"what up player?")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
describe "The Card View", ->
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
#### Luca.Collection
|
|
2
|
+
|
|
3
|
+
describe "Luca.Collection", ->
|
|
4
|
+
it "should accept a name and collection manager", ->
|
|
5
|
+
mgr = new Luca.CollectionManager()
|
|
6
|
+
collection = new Luca.Collection([], name:"booya",manager:mgr)
|
|
7
|
+
expect( collection.name ).toEqual("booya")
|
|
8
|
+
expect( collection.manager ).toEqual(mgr)
|
|
9
|
+
|
|
10
|
+
it "should allow me to specify my own fetch method on a per collection basis", ->
|
|
11
|
+
spy = sinon.spy()
|
|
12
|
+
collection = new Luca.Collection([],fetch:spy)
|
|
13
|
+
collection.fetch()
|
|
14
|
+
|
|
15
|
+
expect( spy.called ).toBeTruthy()
|
|
16
|
+
|
|
17
|
+
it "should trigger before:fetch", ->
|
|
18
|
+
collection = new Luca.Collection([], url:"/models")
|
|
19
|
+
spy = sinon.spy()
|
|
20
|
+
collection.bind "before:fetch", spy
|
|
21
|
+
collection.fetch()
|
|
22
|
+
expect( spy.called ).toBeTruthy()
|
|
23
|
+
|
|
24
|
+
it "should automatically parse a response with a root in it", ->
|
|
25
|
+
collection = new Luca.Collection([], root:"root",url:"/rooted/models")
|
|
26
|
+
collection.fetch()
|
|
27
|
+
@server.respond()
|
|
28
|
+
expect( collection.length ).toEqual(2)
|
|
29
|
+
|
|
30
|
+
it "should attempt to register with a collection manager", ->
|
|
31
|
+
registerSpy = sinon.spy()
|
|
32
|
+
|
|
33
|
+
collection = new Luca.Collection [],
|
|
34
|
+
name:"registered"
|
|
35
|
+
register: registerSpy
|
|
36
|
+
|
|
37
|
+
expect( registerSpy ).toHaveBeenCalled()
|
|
38
|
+
|
|
39
|
+
describe "The ifLoaded helper", ->
|
|
40
|
+
it "should fire the passed callback automatically if there are models", ->
|
|
41
|
+
spy = sinon.spy()
|
|
42
|
+
collection = new Luca.Collection([{attr:"value"}])
|
|
43
|
+
collection.ifLoaded(spy)
|
|
44
|
+
expect( spy.callCount ).toEqual(1)
|
|
45
|
+
|
|
46
|
+
it "should fire the passed callback any time the collection resets", ->
|
|
47
|
+
spy = sinon.spy()
|
|
48
|
+
|
|
49
|
+
collection = new Luca.Collection([{attr:"value"}], url:"/models")
|
|
50
|
+
|
|
51
|
+
collection.ifLoaded ()->
|
|
52
|
+
spy.call()
|
|
53
|
+
|
|
54
|
+
collection.fetch()
|
|
55
|
+
@server.respond()
|
|
56
|
+
|
|
57
|
+
expect( spy.callCount ).toEqual(2)
|
|
58
|
+
|
|
59
|
+
it "should not fire the callback if there are no models", ->
|
|
60
|
+
spy = sinon.spy()
|
|
61
|
+
collection = new Luca.Collection()
|
|
62
|
+
collection.ifLoaded(spy)
|
|
63
|
+
expect( spy.called ).toBeFalsy()
|
|
64
|
+
|
|
65
|
+
it "should automatically call fetch on the collection", ->
|
|
66
|
+
spy = sinon.spy()
|
|
67
|
+
collection = new Luca.Collection([],url:"/models",blah:true)
|
|
68
|
+
collection.ifLoaded(spy)
|
|
69
|
+
@server.respond()
|
|
70
|
+
expect( spy.called ).toBeTruthy()
|
|
71
|
+
|
|
72
|
+
it "should allow me to not automatically call fetch on the collection", ->
|
|
73
|
+
collection = new Luca.Collection([],url:"/models")
|
|
74
|
+
spy = sinon.spy( collection.fetch )
|
|
75
|
+
fn = ()-> true
|
|
76
|
+
collection.ifLoaded(fn, autoFetch:false)
|
|
77
|
+
expect( spy.called ).toBeFalsy()
|
|
78
|
+
|
|
79
|
+
describe "The onceLoaded helper", ->
|
|
80
|
+
it "should fire the passed callback once if there are models", ->
|
|
81
|
+
spy = sinon.spy()
|
|
82
|
+
collection = new Luca.Collection([{attr:"value"}])
|
|
83
|
+
collection.onceLoaded(spy)
|
|
84
|
+
expect( spy.callCount ).toEqual(1)
|
|
85
|
+
|
|
86
|
+
it "should fire the passed callback only once", ->
|
|
87
|
+
spy = sinon.spy()
|
|
88
|
+
collection = new Luca.Collection([{attr:"value"}],url:"/models")
|
|
89
|
+
collection.onceLoaded(spy)
|
|
90
|
+
expect( spy.callCount ).toEqual(1)
|
|
91
|
+
|
|
92
|
+
collection.fetch()
|
|
93
|
+
@server.respond()
|
|
94
|
+
expect( spy.callCount ).toEqual(1)
|
|
95
|
+
|
|
96
|
+
it "should not fire the callback if there are no models", ->
|
|
97
|
+
spy = sinon.spy()
|
|
98
|
+
collection = new Luca.Collection()
|
|
99
|
+
collection.onceLoaded(spy)
|
|
100
|
+
expect( spy.called ).toBeFalsy()
|
|
101
|
+
|
|
102
|
+
it "should automatically call fetch on the collection", ->
|
|
103
|
+
spy = sinon.spy()
|
|
104
|
+
collection = new Luca.Collection([],url:"/models")
|
|
105
|
+
collection.onceLoaded(spy)
|
|
106
|
+
@server.respond()
|
|
107
|
+
expect( spy.called ).toBeTruthy()
|
|
108
|
+
|
|
109
|
+
it "should allow me to not automatically call fetch on the collection", ->
|
|
110
|
+
collection = new Luca.Collection([],url:"/models")
|
|
111
|
+
spy = sinon.spy( collection.fetch )
|
|
112
|
+
fn = ()-> true
|
|
113
|
+
collection.onceLoaded(fn, autoFetch:false)
|
|
114
|
+
expect( spy.called ).toBeFalsy()
|
|
115
|
+
|
|
116
|
+
describe "Registering with the collection manager", ->
|
|
117
|
+
|
|
118
|
+
it "should be able to find a default collection manager", ->
|
|
119
|
+
mgr = new Luca.CollectionManager()
|
|
120
|
+
expect( Luca.CollectionManager.get() ).toEqual(mgr)
|
|
121
|
+
|
|
122
|
+
it "should automatically register with the manager if I specify a name", ->
|
|
123
|
+
mgr = new Luca.CollectionManager()
|
|
124
|
+
collection = new Luca.Collection([],name:"auto_register")
|
|
125
|
+
expect( mgr.get("auto_register") ).toEqual(collection)
|
|
126
|
+
|
|
127
|
+
it "should register with a specific manager", ->
|
|
128
|
+
window.other_manager = new Luca.CollectionManager()
|
|
129
|
+
|
|
130
|
+
collection = new Luca.Collection [],
|
|
131
|
+
name: "other_collection"
|
|
132
|
+
manager: window.other_manager
|
|
133
|
+
|
|
134
|
+
expect( window.other_manager.get("other_collection") ).toEqual(collection)
|
|
135
|
+
|
|
136
|
+
it "should find a collection manager by string", ->
|
|
137
|
+
window.find_mgr_by_string = new Luca.CollectionManager()
|
|
138
|
+
|
|
139
|
+
collection = new Luca.Collection [],
|
|
140
|
+
name: "biggie"
|
|
141
|
+
manager: "find_mgr_by_string"
|
|
142
|
+
|
|
143
|
+
expect( collection.manager ).toBeDefined()
|
|
144
|
+
|
|
145
|
+
it "should not register with a collection manager if it is marked as private", ->
|
|
146
|
+
manager = new Luca.CollectionManager()
|
|
147
|
+
|
|
148
|
+
registerSpy = sinon.spy()
|
|
149
|
+
|
|
150
|
+
private = new Luca.Collection [],
|
|
151
|
+
name: "private"
|
|
152
|
+
manager: manager
|
|
153
|
+
private: true
|
|
154
|
+
register: registerSpy
|
|
155
|
+
|
|
156
|
+
expect( registerSpy ).not.toHaveBeenCalled()
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
describe "The Model Bootstrap", ->
|
|
160
|
+
window.ModelBootstrap =
|
|
161
|
+
sample: []
|
|
162
|
+
|
|
163
|
+
_(5).times (n)->
|
|
164
|
+
window.ModelBootstrap.sample.push
|
|
165
|
+
id: n
|
|
166
|
+
key: "value"
|
|
167
|
+
|
|
168
|
+
it "should add an object into the models cache", ->
|
|
169
|
+
Luca.Collection.bootstrap( window.ModelBootstrap )
|
|
170
|
+
expect( Luca.Collection.cache("sample").length ).toEqual(5)
|
|
171
|
+
|
|
172
|
+
it "should fetch the cached models from the bootstrap", ->
|
|
173
|
+
collection = new Luca.Collection [],
|
|
174
|
+
cached: ()-> "sample"
|
|
175
|
+
|
|
176
|
+
collection.fetch()
|
|
177
|
+
|
|
178
|
+
expect( collection.length ).toEqual(5)
|
|
179
|
+
expect( collection.pluck('id') ).toEqual([0,1,2,3,4])
|
|
180
|
+
|
|
181
|
+
it "should reference the cached models", ->
|
|
182
|
+
collection = new Luca.Collection [],
|
|
183
|
+
cached: ()-> "sample"
|
|
184
|
+
|
|
185
|
+
expect( collection.cached_models().length ).toEqual(5)
|
|
186
|
+
|
|
187
|
+
it "should avoid making an API call", ->
|
|
188
|
+
spy = sinon.spy( Backbone.Collection.prototype.fetch )
|
|
189
|
+
collection = new Luca.Collection [],
|
|
190
|
+
cached: ()-> "sample"
|
|
191
|
+
|
|
192
|
+
collection.fetch()
|
|
193
|
+
expect( spy.called ).toBeFalsy()
|
|
194
|
+
|
|
195
|
+
it "should make an API call if specifically asked", ->
|
|
196
|
+
spy = sinon.spy()
|
|
197
|
+
|
|
198
|
+
collection = new Luca.Collection [],
|
|
199
|
+
cached: ()-> "sample"
|
|
200
|
+
url: ()-> "/models"
|
|
201
|
+
|
|
202
|
+
collection.bind "after:response", spy
|
|
203
|
+
collection.fetch(refresh:true)
|
|
204
|
+
@server.respond()
|
|
205
|
+
|
|
206
|
+
expect( spy.called ).toBeTruthy()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
describe "Luca.View", ->
|
|
2
|
+
Custom = Luca.View.extend
|
|
3
|
+
clickHandler: sinon.spy()
|
|
4
|
+
autoBindEventHandlers: true
|
|
5
|
+
|
|
6
|
+
it "should be defined", ->
|
|
7
|
+
expect(Luca.View).toBeDefined()
|
|
8
|
+
|
|
9
|
+
it "should extend itself with the passed options", ->
|
|
10
|
+
view = new Luca.View(name:"custom")
|
|
11
|
+
expect(view.name).toEqual("custom")
|
|
12
|
+
|
|
13
|
+
it "should create a unique id based on the name", ->
|
|
14
|
+
view = new Luca.View(name:"boom")
|
|
15
|
+
expect( view.cid ).toContain 'boom'
|
|
16
|
+
|
|
17
|
+
it "should register the view in the cache", ->
|
|
18
|
+
view = new Luca.View(name:"cached")
|
|
19
|
+
expect( Luca.cache("cached") ).toBeDefined()
|
|
20
|
+
|
|
21
|
+
it "should trigger after initialize", ->
|
|
22
|
+
view = new Luca.View()
|
|
23
|
+
expect( view ).toHaveTriggered("after:initialize")
|
|
24
|
+
|
|
25
|
+
it "should auto-bind event handlers", ->
|
|
26
|
+
# pending
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
describe "Hooks", ->
|
|
31
|
+
it "should have before and after render hooks", ->
|
|
32
|
+
Custom = Luca.View.extend
|
|
33
|
+
beforeRender: sinon.spy()
|
|
34
|
+
afterRender: sinon.spy()
|
|
35
|
+
|
|
36
|
+
view = new Custom()
|
|
37
|
+
|
|
38
|
+
view.render()
|
|
39
|
+
|
|
40
|
+
expect( view.beforeRender ).toHaveBeenCalled()
|
|
41
|
+
expect( view.afterRender ).toHaveBeenCalled()
|
|
42
|
+
|
|
43
|
+
it "should call custom hooks in addition to framework hooks", ->
|
|
44
|
+
Custom = Luca.View.extend
|
|
45
|
+
hooks:["custom:hook"]
|
|
46
|
+
afterRender: ()-> @trigger("custom:hook")
|
|
47
|
+
customHook: sinon.spy()
|
|
48
|
+
|
|
49
|
+
view = new Custom()
|
|
50
|
+
|
|
51
|
+
view.render()
|
|
52
|
+
|
|
53
|
+
expect( view.customHook ).toHaveBeenCalled()
|
|
54
|
+
|
|
55
|
+
describe "The Collection Events API", ->
|
|
56
|
+
App =
|
|
57
|
+
collections : {}
|
|
58
|
+
|
|
59
|
+
App.collections.Sample = Luca.Collection.extend
|
|
60
|
+
name: "sample"
|
|
61
|
+
|
|
62
|
+
SampleView = Luca.View.extend
|
|
63
|
+
resetHandler: sinon.spy()
|
|
64
|
+
collectionEvents:
|
|
65
|
+
"sample reset" : "resetHandler"
|
|
66
|
+
|
|
67
|
+
class SampleManager extends Luca.CollectionManager
|
|
68
|
+
collectionNamespace: App.collections
|
|
69
|
+
name: "collectionEvents"
|
|
70
|
+
|
|
71
|
+
beforeEach ()->
|
|
72
|
+
@manager ||= new SampleManager()
|
|
73
|
+
@collection = @manager.getOrCreate("sample")
|
|
74
|
+
|
|
75
|
+
it "should know which collection manager to use", ->
|
|
76
|
+
view = new SampleView()
|
|
77
|
+
expect( view.getCollectionManager().name ).toEqual( "collectionEvents" )
|
|
78
|
+
|
|
79
|
+
it "should create a reference to the collection", ->
|
|
80
|
+
view = new SampleView()
|
|
81
|
+
expect( view.sampleCollection ).toBeDefined()
|
|
82
|
+
|
|
83
|
+
it "should call the resetHandler callback on the view", ->
|
|
84
|
+
view = new SampleView()
|
|
85
|
+
collection = @manager.get("sample")
|
|
86
|
+
collection.reset([])
|
|
87
|
+
expect( view.resetHandler ).toHaveBeenCalled()
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#= require "./helper"
|
|
2
|
+
|
|
3
|
+
describe "The Luca Framework", ->
|
|
4
|
+
it "should specify a version", ->
|
|
5
|
+
expect(Luca.VERSION).toBeDefined()
|
|
6
|
+
|
|
7
|
+
it "should define Luca in the global space", ->
|
|
8
|
+
expect(Luca).toBeDefined()
|
|
9
|
+
|
|
10
|
+
it "should enable bootstrap by default", ->
|
|
11
|
+
expect(Luca.enableBootstrap).toBeTruthy()
|
|
12
|
+
|
|
13
|
+
it "should have classes in the registry", ->
|
|
14
|
+
expect( Luca.registry.classes ).toBeDefined()
|
|
15
|
+
|
|
16
|
+
it "should be able to lookup classes in the registry by ctype", ->
|
|
17
|
+
expect( Luca.registry.lookup("form_view") ).toBeTruthy()
|
|
18
|
+
|
|
19
|
+
it "should allow me to add view namespaces to the registry", ->
|
|
20
|
+
Luca.registry.addNamespace("Test.namespace")
|
|
21
|
+
expect( Luca.registry.namespaces ).toContain("Test.namespace")
|
|
22
|
+
|
|
23
|
+
it "should resolve a value.string to the object", ->
|
|
24
|
+
window.nested =
|
|
25
|
+
value:
|
|
26
|
+
string: "haha"
|
|
27
|
+
|
|
28
|
+
value = Luca.util.nestedValue("nested.value.string", window)
|
|
29
|
+
|
|
30
|
+
expect(value).toEqual("haha")
|
|
31
|
+
|
|
32
|
+
it "should create an instance of a class by ctype", ->
|
|
33
|
+
object =
|
|
34
|
+
ctype: "template"
|
|
35
|
+
template: "components/form_view"
|
|
36
|
+
|
|
37
|
+
component = Luca.util.lazyComponent(object)
|
|
38
|
+
expect( _.isFunction(component.render) ).toBeTruthy()
|
|
39
|
+
|
|
40
|
+
it "should find a created view in the cache", ->
|
|
41
|
+
template = new Luca.components.Template
|
|
42
|
+
template: "components/form_view"
|
|
43
|
+
name: 'test_template'
|
|
44
|
+
|
|
45
|
+
expect(Luca.cache("test_template")).toBeDefined()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
describe
|
data/spec/helper.coffee
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# thanks player
|
|
2
|
+
# https://github.com/thefrontside/jasmine.backbone.js
|
|
3
|
+
|
|
4
|
+
json = (object) ->
|
|
5
|
+
JSON.stringify object
|
|
6
|
+
|
|
7
|
+
msg = (list) ->
|
|
8
|
+
(if list.length isnt 0 then list.join(";") else "")
|
|
9
|
+
|
|
10
|
+
eventBucket = (model, eventName) ->
|
|
11
|
+
spiedEvents = model.spiedEvents
|
|
12
|
+
spiedEvents = model.spiedEvents = {} unless spiedEvents
|
|
13
|
+
bucket = spiedEvents[eventName]
|
|
14
|
+
bucket = spiedEvents[eventName] = [] unless bucket
|
|
15
|
+
bucket
|
|
16
|
+
|
|
17
|
+
triggerSpy = (constructor) ->
|
|
18
|
+
trigger = constructor::trigger
|
|
19
|
+
constructor::trigger = (eventName) ->
|
|
20
|
+
bucket = eventBucket(this, eventName)
|
|
21
|
+
bucket.push Array::slice.call(arguments, 1)
|
|
22
|
+
trigger.apply this, arguments
|
|
23
|
+
|
|
24
|
+
triggerSpy Backbone.Model
|
|
25
|
+
triggerSpy Backbone.Collection
|
|
26
|
+
triggerSpy Backbone.View
|
|
27
|
+
|
|
28
|
+
EventMatchers =
|
|
29
|
+
toHaveTriggered: (eventName) ->
|
|
30
|
+
bucket = eventBucket(@actual, eventName)
|
|
31
|
+
triggeredWith = Array::slice.call(arguments, 1)
|
|
32
|
+
@message = ->
|
|
33
|
+
[ "expected model or collection to have received '" + eventName + "' with " + json(triggeredWith), "expected model not to have received event '" + eventName + "', but it did" ]
|
|
34
|
+
|
|
35
|
+
_.detect bucket, (args) ->
|
|
36
|
+
if triggeredWith.length is 0
|
|
37
|
+
true
|
|
38
|
+
else
|
|
39
|
+
jasmine.getEnv().equals_ triggeredWith, args
|
|
40
|
+
|
|
41
|
+
ModelMatchers =
|
|
42
|
+
toHaveAttributes: (attributes) ->
|
|
43
|
+
keys = []
|
|
44
|
+
values = []
|
|
45
|
+
jasmine.getEnv().equals_ @actual.attributes, attributes, keys, values
|
|
46
|
+
missing = []
|
|
47
|
+
i = 0
|
|
48
|
+
|
|
49
|
+
while i < keys.length
|
|
50
|
+
message = keys[i]
|
|
51
|
+
missing.push keys[i] if message.match(/but missing from/)
|
|
52
|
+
i++
|
|
53
|
+
@message = ->
|
|
54
|
+
[ "model should have at least these attributes(" + json(attributes) + ") " + msg(missing) + " " + msg(values), "model should have none of the following attributes(" + json(attributes) + ") " + msg(keys) + " " + msg(values) ]
|
|
55
|
+
|
|
56
|
+
missing.length is 0 and values.length is 0
|
|
57
|
+
|
|
58
|
+
toHaveExactlyTheseAttributes: (attributes) ->
|
|
59
|
+
keys = []
|
|
60
|
+
values = []
|
|
61
|
+
equal = jasmine.getEnv().equals_(@actual.attributes, attributes, keys, values)
|
|
62
|
+
@message = ->
|
|
63
|
+
[ "model should match exact attributes, but does not. " + msg(keys) + " " + msg(values), "model has exactly these attributes, but shouldn't :" + json(attributes) ]
|
|
64
|
+
|
|
65
|
+
equal
|
|
66
|
+
|
|
67
|
+
createFakeServer = ->
|
|
68
|
+
server = sinon.fakeServer.create()
|
|
69
|
+
server.respondWith("GET", "/models", [
|
|
70
|
+
200,
|
|
71
|
+
{"Content-Type":"application/json"},
|
|
72
|
+
'[{"id":1,"attr1":"value1","attr2":"value2"},{"id":2,"attr1":"value1","attr2":"value2"}]'
|
|
73
|
+
])
|
|
74
|
+
server.respondWith("GET", "/rooted/models", [
|
|
75
|
+
200,
|
|
76
|
+
{"Content-Type":"application/json"},
|
|
77
|
+
'{"root":[{"id":1,"attr1":"value1","attr2":"value2"},{"id":2,"attr1":"value1","attr2":"value2"}]}'
|
|
78
|
+
])
|
|
79
|
+
server.respondWith("GET", "/empty", [
|
|
80
|
+
200,
|
|
81
|
+
{"Content-Type":"application/json"},
|
|
82
|
+
'[]'
|
|
83
|
+
])
|
|
84
|
+
server
|
|
85
|
+
|
|
86
|
+
spyMatchers = "called calledOnce calledTwice calledThrice calledBefore calledAfter calledOn alwaysCalledOn calledWith alwaysCalledWith calledWithExactly alwaysCalledWithExactly".split(" ")
|
|
87
|
+
i = spyMatchers.length
|
|
88
|
+
spyMatcherHash = {}
|
|
89
|
+
unusualMatchers =
|
|
90
|
+
returned: "toHaveReturned"
|
|
91
|
+
alwaysReturned: "toHaveAlwaysReturned"
|
|
92
|
+
threw: "toHaveThrown"
|
|
93
|
+
alwaysThrew: "toHaveAlwaysThrown"
|
|
94
|
+
|
|
95
|
+
getMatcherFunction = (sinonName) ->
|
|
96
|
+
->
|
|
97
|
+
sinonProperty = @actual[sinonName]
|
|
98
|
+
(if (typeof sinonProperty is "function") then sinonProperty.apply(@actual, arguments) else sinonProperty)
|
|
99
|
+
|
|
100
|
+
while i--
|
|
101
|
+
sinonName = spyMatchers[i]
|
|
102
|
+
matcherName = "toHaveBeen" + sinonName.charAt(0).toUpperCase() + sinonName.slice(1)
|
|
103
|
+
spyMatcherHash[matcherName] = getMatcherFunction(sinonName)
|
|
104
|
+
for j of unusualMatchers
|
|
105
|
+
spyMatcherHash[unusualMatchers[j]] = getMatcherFunction(j)
|
|
106
|
+
|
|
107
|
+
window.sinonJasmine =
|
|
108
|
+
getMatchers: ->
|
|
109
|
+
spyMatcherHash
|
|
110
|
+
|
|
111
|
+
#### Loadup Jasmine
|
|
112
|
+
beforeEach ->
|
|
113
|
+
@server = createFakeServer()
|
|
114
|
+
|
|
115
|
+
@addMatchers ModelMatchers
|
|
116
|
+
@addMatchers EventMatchers
|
|
117
|
+
@addMatchers sinonJasmine.getMatchers()
|
|
118
|
+
|
|
119
|
+
afterEach ->
|
|
120
|
+
@server.restore()
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
describe "The Collection Manager", ->
|
|
2
|
+
App = collections: {}
|
|
3
|
+
|
|
4
|
+
App.collections.SampleCollection = Luca.Collection.extend
|
|
5
|
+
url: "/models"
|
|
6
|
+
|
|
7
|
+
beforeEach ()->
|
|
8
|
+
@manager = new Luca.CollectionManager(name:"manager",collectionNamespace: App.collections)
|
|
9
|
+
|
|
10
|
+
it "should be defined", ->
|
|
11
|
+
expect( Luca.CollectionManager ).toBeDefined()
|
|
12
|
+
|
|
13
|
+
it "should make the latest instance accessible by class function", ->
|
|
14
|
+
expect( Luca.CollectionManager.get().name ).toEqual("manager")
|
|
15
|
+
|
|
16
|
+
it "should be able to guess a collection constructor class", ->
|
|
17
|
+
base = @manager.guessCollectionClass("sample_collection")
|
|
18
|
+
expect( base ).toEqual(App.collections.SampleCollection)
|
|
19
|
+
|
|
20
|
+
it "should create a collection on demand", ->
|
|
21
|
+
collection = @manager.getOrCreate("sample_collection")
|
|
22
|
+
expect( collection.url ).toEqual "/models"
|
|
23
|
+
|
|
24
|
+
describe "Adding Collections", ->
|
|
25
|
+
manager = new Luca.CollectionManager
|
|
26
|
+
first = new Luca.Collection([],name:"added",prop:"val2")
|
|
27
|
+
second = new Luca.Collection([],name:"added",prop:"val1")
|
|
28
|
+
|
|
29
|
+
manager.add("added", first)
|
|
30
|
+
manager.add("added", second)
|
|
31
|
+
|
|
32
|
+
expect( manager.get("added") ).toEqual( first )
|
|
33
|
+
|
|
34
|
+
describe "The Scope Functionality", ->
|
|
35
|
+
scope = "one"
|
|
36
|
+
|
|
37
|
+
manager = new Luca.CollectionManager
|
|
38
|
+
getScope: ()-> scope
|
|
39
|
+
|
|
40
|
+
babyone = new Luca.Collection([{id:1},{id:2}],name:"baby")
|
|
41
|
+
|
|
42
|
+
manager.add("baby", babyone)
|
|
43
|
+
|
|
44
|
+
expect( manager.get("baby").pluck('id') ).toEqual([1,2])
|
|
45
|
+
expect( manager.get("baby") ).toBeDefined()
|
|
46
|
+
expect( manager.get("baby") ).toEqual( babyone )
|
|
47
|
+
expect( manager.allCollections().length ).toEqual(1)
|
|
48
|
+
|
|
49
|
+
scope = "two"
|
|
50
|
+
|
|
51
|
+
babytwo = new Luca.Collection([{id:3},{id:4}],name:"baby")
|
|
52
|
+
|
|
53
|
+
expect( manager.get("baby").pluck('id') ).toEqual([3,4])
|
|
54
|
+
expect( manager.get("baby") ).toBeDefined()
|
|
55
|
+
expect( manager.get("baby") ).toEqual( babytwo )
|
|
56
|
+
expect( manager.allCollections().length ).toEqual(1)
|
|
57
|
+
|
|
58
|
+
scope = "one"
|
|
59
|
+
expect( manager.get("baby").pluck('id') ).toEqual([1,2])
|
|
60
|
+
|
|
61
|
+
describe "Loading collections", ->
|
|
62
|
+
App = collections: {}
|
|
63
|
+
|
|
64
|
+
exampleSpy = sinon.spy()
|
|
65
|
+
sampleSpy = sinon.spy()
|
|
66
|
+
|
|
67
|
+
App.collections.ExampleCollection = Luca.Collection.extend
|
|
68
|
+
name: "example"
|
|
69
|
+
url: "/example_models"
|
|
70
|
+
fetch: ()->
|
|
71
|
+
exampleSpy.call()
|
|
72
|
+
@reset([{id: 1}])
|
|
73
|
+
|
|
74
|
+
App.collections.SampleCollection = Luca.Collection.extend
|
|
75
|
+
name: "sample"
|
|
76
|
+
url: "/sample_models"
|
|
77
|
+
fetch: ()->
|
|
78
|
+
sampleSpy.call()
|
|
79
|
+
@reset([{id: 4}])
|
|
80
|
+
|
|
81
|
+
manager = new Luca.CollectionManager(name:"manager",collectionNamespace: App.collections, collectionNames: ["example", "sample"])
|
|
82
|
+
|
|
83
|
+
it "should have example collection created", ->
|
|
84
|
+
collection = manager.get("example")
|
|
85
|
+
expect(collection.url).toEqual ("/example_models")
|
|
86
|
+
|
|
87
|
+
it "should have example collection fetched", ->
|
|
88
|
+
expect(exampleSpy).toHaveBeenCalled()
|
|
89
|
+
|
|
90
|
+
it "should have sample collection created", ->
|
|
91
|
+
collection = manager.get("sample")
|
|
92
|
+
expect(collection.url).toEqual ("/sample_models")
|
|
93
|
+
|
|
94
|
+
it "should have sample collection loaded", ->
|
|
95
|
+
expect(sampleSpy).toHaveBeenCalled()
|
|
File without changes
|