luca 0.9.4 → 0.9.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +41 -1
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/README.md +5 -0
- data/Rakefile +4 -0
- data/assets/javascripts/dependencies/underscore-min.js +5 -31
- data/assets/javascripts/luca-templates.js +1 -0
- data/assets/javascripts/luca-ui-base.coffee +1 -1
- data/assets/javascripts/luca-ui-development-tools.coffee +1 -1
- data/assets/javascripts/luca-ui-full.js +1 -1
- data/assets/javascripts/luca-ui-spec.coffee +1 -1
- data/assets/javascripts/luca-ui.js +3 -0
- data/assets/javascripts/luca/index.coffee +1 -0
- data/lib/generators/luca/application/application_generator.rb +71 -0
- data/lib/generators/luca/application/templates/controller.rb +6 -0
- data/lib/generators/luca/application/templates/index.html.erb +7 -0
- data/lib/generators/luca/application/templates/index.html.haml +6 -0
- data/lib/generators/luca/application/templates/javascripts/application.js +28 -0
- data/lib/generators/luca/application/templates/javascripts/application.js.coffee +20 -0
- data/lib/generators/luca/application/templates/javascripts/config.js +15 -0
- data/lib/generators/luca/application/templates/javascripts/config.js.coffee +9 -0
- data/lib/generators/luca/application/templates/javascripts/dependencies.js +5 -0
- data/lib/generators/luca/application/templates/javascripts/dependencies.js.coffee +5 -0
- data/lib/generators/luca/application/templates/javascripts/index.js +9 -0
- data/lib/generators/luca/application/templates/javascripts/index.js.coffee +9 -0
- data/lib/generators/luca/application/templates/javascripts/main.js +8 -0
- data/lib/generators/luca/application/templates/javascripts/main.js.coffee +3 -0
- data/lib/generators/luca/application/templates/javascripts/main.jst.ejs +1 -0
- data/lib/generators/luca/application/templates/javascripts/router.js +12 -0
- data/lib/generators/luca/application/templates/javascripts/router.js.coffee +7 -0
- data/lib/luca/rails/version.rb +1 -1
- data/lib/luca/template.rb +1 -1
- data/spec/components/collection_view_spec.coffee +37 -0
- data/spec/components/multi_collection_view_spec.coffee +5 -0
- data/spec/components/table_view_spec.coffee +17 -0
- data/spec/core/container_spec.coffee +112 -5
- data/spec/core/model_spec.coffee +21 -3
- data/spec/define_spec.coffee +19 -0
- data/spec/mixin_spec.coffee +49 -0
- data/src/components/application.coffee +33 -19
- data/src/components/collection_view.coffee +109 -38
- data/src/components/fields/checkbox_field.coffee +2 -2
- data/src/components/fields/file_upload_field.coffee +0 -3
- data/src/components/fields/hidden_field.coffee +0 -3
- data/src/components/fields/label_field.coffee +1 -4
- data/src/components/fields/select_field.coffee +6 -6
- data/src/components/fields/text_area_field.coffee +1 -0
- data/src/components/fields/text_field.coffee +4 -0
- data/src/components/fields/type_ahead_field.coffee +5 -9
- data/src/components/form_view.coffee +2 -0
- data/src/components/index.coffee +1 -0
- data/src/components/multi_collection_view.coffee +94 -0
- data/src/components/pagination_control.coffee +100 -0
- data/src/components/table_view.coffee +62 -0
- data/src/containers/card_view.coffee +44 -11
- data/src/containers/panel_toolbar.coffee +88 -82
- data/src/containers/tab_view.coffee +3 -3
- data/src/containers/viewport.coffee +10 -4
- data/src/core/collection.coffee +11 -4
- data/src/core/container.coffee +189 -113
- data/src/core/field.coffee +13 -10
- data/src/core/model.coffee +23 -27
- data/src/core/registry.coffee +48 -35
- data/src/core/view.coffee +60 -140
- data/src/define.coffee +91 -19
- data/src/framework.coffee +10 -8
- data/src/index.coffee +23 -0
- data/src/managers/collection_manager.coffee +24 -8
- data/src/modules/application_event_bindings.coffee +19 -0
- data/src/modules/collection_event_bindings.coffee +26 -0
- data/src/modules/deferrable.coffee +3 -1
- data/src/modules/dom_helpers.coffee +49 -0
- data/src/modules/enhanced_properties.coffee +23 -0
- data/src/modules/filterable.coffee +60 -0
- data/src/modules/grid_layout.coffee +15 -0
- data/src/modules/{load_mask.coffee → loadmaskable.coffee} +10 -4
- data/src/modules/modal_view.coffee +38 -0
- data/src/modules/paginatable.coffee +79 -0
- data/src/modules/state_model.coffee +16 -0
- data/src/modules/templating.coffee +8 -0
- data/src/plugins/events.coffee +30 -2
- data/src/templates/components/bootstrap_form_controls.jst.ejs +10 -0
- data/src/templates/components/collection_loader_view.jst.ejs +6 -0
- data/src/templates/components/form_alert.jst.ejs +4 -0
- data/src/templates/components/grid_view.jst.ejs +11 -0
- data/src/templates/components/grid_view_empty_text.jst.ejs +3 -0
- data/src/templates/components/load_mask.jst.ejs +5 -0
- data/src/templates/components/nav_bar.jst.ejs +4 -0
- data/src/templates/components/pagination.jst.ejs +10 -0
- data/src/templates/containers/basic.jst.ejs +1 -0
- data/src/templates/containers/tab_selector_container.jst.ejs +12 -0
- data/src/templates/containers/tab_view.jst.ejs +2 -0
- data/src/templates/containers/toolbar_wrapper.jst.ejs +1 -0
- data/src/templates/fields/button_field.jst.ejs +2 -0
- data/src/templates/fields/button_field_link.jst.ejs +6 -0
- data/src/templates/fields/checkbox_array.jst.ejs +4 -0
- data/src/templates/fields/checkbox_array_item.jst.ejs +3 -0
- data/src/templates/fields/checkbox_field.jst.ejs +10 -0
- data/src/templates/fields/file_upload_field.jst.ejs +10 -0
- data/src/templates/fields/hidden_field.jst.ejs +1 -0
- data/src/templates/fields/select_field.jst.ejs +11 -0
- data/src/templates/fields/text_area_field.jst.ejs +11 -0
- data/src/templates/fields/text_field.jst.ejs +16 -0
- data/src/templates/table_view.jst.ejs +4 -0
- data/src/tools/console.coffee +51 -21
- data/src/util.coffee +17 -4
- data/vendor/assets/javascripts/luca-ui-base.js +3288 -613
- data/vendor/assets/javascripts/luca-ui-development-tools.js +49 -21
- data/vendor/assets/javascripts/luca-ui-development-tools.min.js +1 -1
- data/vendor/assets/javascripts/luca-ui-full.js +1704 -554
- data/vendor/assets/javascripts/luca-ui-full.min.js +7 -6
- data/vendor/assets/javascripts/luca-ui-spec.js +1783 -830
- data/vendor/assets/javascripts/luca-ui-templates.js +92 -0
- data/vendor/assets/javascripts/luca-ui.js +1694 -523
- data/vendor/assets/javascripts/luca-ui.min.js +4 -4
- metadata +69 -31
- data/assets/javascripts/luca-ui.coffee +0 -3
- data/src/luca.coffee +0 -22
- data/src/templates/components/bootstrap_form_controls.luca +0 -7
- data/src/templates/components/collection_loader_view.luca +0 -5
- data/src/templates/components/form_alert +0 -0
- data/src/templates/components/form_alert.luca +0 -3
- data/src/templates/components/grid_view.luca +0 -7
- data/src/templates/components/grid_view_empty_text.luca +0 -3
- data/src/templates/components/load_mask.luca +0 -3
- data/src/templates/components/nav_bar.luca +0 -2
- data/src/templates/containers/basic.luca +0 -1
- data/src/templates/containers/tab_selector_container.luca +0 -8
- data/src/templates/containers/tab_view.luca +0 -2
- data/src/templates/containers/toolbar_wrapper.luca +0 -1
- data/src/templates/fields/button_field.luca +0 -2
- data/src/templates/fields/button_field_link.luca +0 -5
- data/src/templates/fields/checkbox_array.luca +0 -4
- data/src/templates/fields/checkbox_array_item.luca +0 -4
- data/src/templates/fields/checkbox_field.luca +0 -9
- data/src/templates/fields/file_upload_field.luca +0 -8
- data/src/templates/fields/hidden_field.luca +0 -1
- data/src/templates/fields/select_field.luca +0 -8
- data/src/templates/fields/text_area_field.luca +0 -8
- data/src/templates/fields/text_field.luca +0 -17
- data/src/templates/sample/contents.luca +0 -1
- data/src/templates/sample/welcome.luca +0 -1
- data/vendor/assets/javascripts/luca-spec-dependencies.js +0 -6135
- data/vendor/assets/javascripts/luca-ui-development-dependencies.js +0 -12845
@@ -0,0 +1,37 @@
|
|
1
|
+
describe 'The Collection View', ->
|
2
|
+
beforeEach ->
|
3
|
+
@collection = new Luca.Collection([
|
4
|
+
id: 1, attr: "value_one"
|
5
|
+
,
|
6
|
+
id: 2, attr: "value_two"
|
7
|
+
],
|
8
|
+
model: Luca.Model)
|
9
|
+
|
10
|
+
@view = new Luca.components.CollectionView
|
11
|
+
itemTagName: "li"
|
12
|
+
itemClassName: "custom-class"
|
13
|
+
itemProperty: 'attr'
|
14
|
+
collection: @collection
|
15
|
+
|
16
|
+
@view.render()
|
17
|
+
|
18
|
+
it "should render the attributes in the specified list elements", ->
|
19
|
+
expect( @view.$html() ).toContain('value_one')
|
20
|
+
|
21
|
+
it "should render each of the attributes", ->
|
22
|
+
expect( @view.$('li.custom-class').length ).toEqual 2
|
23
|
+
|
24
|
+
it "should locate a dom element by luca model id", ->
|
25
|
+
expect( @view.locateItemElement(2).html() ).toContain('value_two')
|
26
|
+
|
27
|
+
it "should refresh the view when a model is added", ->
|
28
|
+
@view.collection.add(attr:"value_three",id:3)
|
29
|
+
expect( @view ).toHaveTriggered('after:refresh')
|
30
|
+
|
31
|
+
it "should refresh the view when a model is removed", ->
|
32
|
+
@view.collection.remove( @view.collection.at(0) )
|
33
|
+
expect( @view ).toHaveTriggered('after:refresh')
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,5 @@
|
|
1
|
+
describe 'The Collection Multi View component', ->
|
2
|
+
it "should share a single collection among multiple collection views", ->
|
3
|
+
it "should toggle visibility of one or more views", ->
|
4
|
+
it "should share pagination state across the multiple views", ->
|
5
|
+
it "should share filter state across the multiple views", ->
|
@@ -0,0 +1,17 @@
|
|
1
|
+
describe 'The Table View', ->
|
2
|
+
beforeEach ->
|
3
|
+
@tableView = new Luca.components.TableView
|
4
|
+
collection: new Luca.Collection
|
5
|
+
columns:[
|
6
|
+
"column_one"
|
7
|
+
"column_two"
|
8
|
+
]
|
9
|
+
|
10
|
+
$('body').append( @tableView.render() )
|
11
|
+
|
12
|
+
it 'should accept strings for column config', ->
|
13
|
+
expect( @tableView.columns[0].reader ).toEqual("column_one")
|
14
|
+
|
15
|
+
it 'should automatically determine a missing header config', ->
|
16
|
+
expect( @tableView.columns[0].header ).toBeDefined()
|
17
|
+
|
@@ -1,13 +1,18 @@
|
|
1
1
|
describe 'The Luca Container', ->
|
2
2
|
beforeEach ->
|
3
|
-
@container = new Luca.core.Container
|
3
|
+
c = @container = new Luca.core.Container
|
4
|
+
defaults:
|
5
|
+
defaultProperty: 'it_works'
|
4
6
|
components:[
|
5
7
|
name: "component_one"
|
6
8
|
ctype: "view"
|
9
|
+
defaultProperty: "oh_yeah"
|
7
10
|
bodyTemplate: ()-> "markup for component one"
|
8
11
|
id: "c1"
|
9
12
|
value: 1
|
13
|
+
getter: "getOne"
|
10
14
|
spy: sinon.spy()
|
15
|
+
role: "role_one"
|
11
16
|
,
|
12
17
|
name: "component_two"
|
13
18
|
ctype: "view"
|
@@ -15,6 +20,8 @@ describe 'The Luca Container', ->
|
|
15
20
|
id: "c2"
|
16
21
|
value: 0
|
17
22
|
spy: sinon.spy()
|
23
|
+
role: "role_two"
|
24
|
+
getter: "getComponentTwo"
|
18
25
|
,
|
19
26
|
name: "component_three"
|
20
27
|
ctype: "container"
|
@@ -29,6 +36,23 @@ describe 'The Luca Container', ->
|
|
29
36
|
]
|
30
37
|
]
|
31
38
|
|
39
|
+
@container.render()
|
40
|
+
|
41
|
+
it "should create getter methods on the for components with roles", ->
|
42
|
+
expect( @container.getRoleTwo ).toBeDefined()
|
43
|
+
|
44
|
+
it "should create getter methods on the for components with roles", ->
|
45
|
+
expect( @container.getRoleTwo().name ).toEqual 'component_two'
|
46
|
+
|
47
|
+
it "should create a getter function on the container", ->
|
48
|
+
expect( @container.getOne().name ).toEqual 'component_one'
|
49
|
+
|
50
|
+
it "should apply default properties to components", ->
|
51
|
+
defaults = @container.selectByAttribute('defaultProperty','it_works')
|
52
|
+
custom = @container.selectByAttribute('defaultProperty','oh_yeah')
|
53
|
+
expect( defaults.length ).toEqual(2)
|
54
|
+
expect( custom.length ).toEqual(1)
|
55
|
+
|
32
56
|
it "should trigger after initialize", ->
|
33
57
|
expect( @container ).toHaveTriggered "after:initialize"
|
34
58
|
|
@@ -47,7 +71,7 @@ describe 'The Luca Container', ->
|
|
47
71
|
expect( html ).toContain "markup for component four"
|
48
72
|
|
49
73
|
it "should select all components matching a key/value combo", ->
|
50
|
-
components = @container.
|
74
|
+
components = @container.selectByAttribute("value",1)
|
51
75
|
expect( components.length ).toEqual 2
|
52
76
|
|
53
77
|
it "should run a function on each component", ->
|
@@ -61,6 +85,89 @@ describe 'The Luca Container', ->
|
|
61
85
|
@container.eachComponent (c)-> c.spy()
|
62
86
|
expect( Luca.cache("component_four").spy ).toHaveBeenCalled()
|
63
87
|
|
64
|
-
|
65
|
-
|
66
|
-
|
88
|
+
|
89
|
+
describe 'Component Event Binding', ->
|
90
|
+
beforeEach ->
|
91
|
+
@container = new Luca.core.Container
|
92
|
+
componentEvents:
|
93
|
+
"component_alpha trigger:one" : "one"
|
94
|
+
"alpha trigger:two" : "two"
|
95
|
+
"getAlphaComponent trigger:three" : "three"
|
96
|
+
"* trigger:four" : "four"
|
97
|
+
"beta trigger:five" : "five"
|
98
|
+
|
99
|
+
one: ()->
|
100
|
+
@trigger "one"
|
101
|
+
|
102
|
+
two: ()->
|
103
|
+
@trigger "two"
|
104
|
+
|
105
|
+
three: ()->
|
106
|
+
@trigger "three"
|
107
|
+
|
108
|
+
four: ()->
|
109
|
+
@trigger "four"
|
110
|
+
|
111
|
+
five: ()->
|
112
|
+
@trigger "five"
|
113
|
+
|
114
|
+
registerComponentEvents: ()->
|
115
|
+
Luca.core.Container::registerComponentEvents.apply(@, arguments)
|
116
|
+
|
117
|
+
components:[
|
118
|
+
name: "component_alpha"
|
119
|
+
role: "alpha"
|
120
|
+
getter: "getAlphaComponent"
|
121
|
+
,
|
122
|
+
name: "container_tester"
|
123
|
+
type: "container"
|
124
|
+
components:[
|
125
|
+
name: "beta_view"
|
126
|
+
role: "beta"
|
127
|
+
]
|
128
|
+
]
|
129
|
+
|
130
|
+
@container.render()
|
131
|
+
|
132
|
+
it "should give me all of the components", ->
|
133
|
+
names = _( @container.allChildren() ).pluck('name')
|
134
|
+
expect( names ).toEqual ['component_alpha','container_tester','beta_view']
|
135
|
+
|
136
|
+
it "should drill down into nested components", ->
|
137
|
+
expect( @container.getBeta ).toBeDefined()
|
138
|
+
expect( @container.getBeta().name ).toEqual 'beta_view'
|
139
|
+
|
140
|
+
it "should pick up events on nested components", ->
|
141
|
+
@container.getBeta().trigger("trigger:five")
|
142
|
+
expect( @container ).toHaveTriggered("five")
|
143
|
+
|
144
|
+
it "should define a role based getter", ->
|
145
|
+
expect( @container.getAlpha ).toBeDefined()
|
146
|
+
|
147
|
+
it "should define a getter", ->
|
148
|
+
expect( @container.getAlphaComponent ).toBeDefined()
|
149
|
+
|
150
|
+
it "should find the component by its role", ->
|
151
|
+
expect( @container.findComponentByRole("alpha") ).toBeDefined()
|
152
|
+
|
153
|
+
it "should find the component by its name", ->
|
154
|
+
expect( @container.findComponentByName('component_alpha') ).toBeDefined()
|
155
|
+
|
156
|
+
it "should find the component by its getter", ->
|
157
|
+
expect( @container.findComponentByGetter('getAlphaComponent') ).toBeDefined()
|
158
|
+
|
159
|
+
it "should accept wildcard for component", ->
|
160
|
+
@container.getAlphaComponent().trigger "trigger:four"
|
161
|
+
expect( @container ).toHaveTriggered("four")
|
162
|
+
|
163
|
+
it "should accept component events with a component name", ->
|
164
|
+
@container.getAlphaComponent().trigger "trigger:one"
|
165
|
+
expect(@container).toHaveTriggered("one")
|
166
|
+
|
167
|
+
it "should accept component events with a component role", ->
|
168
|
+
@container.getAlphaComponent().trigger "trigger:two"
|
169
|
+
expect(@container).toHaveTriggered("two")
|
170
|
+
|
171
|
+
it "should accept component events with a component getter", ->
|
172
|
+
@container.getAlphaComponent().trigger "trigger:three"
|
173
|
+
expect(@container).toHaveTriggered("three")
|
data/spec/core/model_spec.coffee
CHANGED
@@ -14,15 +14,15 @@ describe "Luca.Model with computed attribute", ->
|
|
14
14
|
computed:
|
15
15
|
fullName: ['firstName', 'lastName']
|
16
16
|
|
17
|
-
it "should
|
17
|
+
it "should be undefined if dependences are not set", ->
|
18
18
|
model = new App.models.Sample
|
19
19
|
expect(model.get("fullName")).toEqual(undefined)
|
20
20
|
|
21
|
-
it "should
|
21
|
+
it "should be undefined if callback function is not present", ->
|
22
22
|
model = new App.models.SampleWithoutCallback
|
23
23
|
expect(model.get("fullName")).toEqual(undefined)
|
24
24
|
|
25
|
-
it "should not call
|
25
|
+
it "should not call the callback if dependences are not set", ->
|
26
26
|
model = new App.models.Sample
|
27
27
|
spy = sinon.spy(model, "fullName")
|
28
28
|
expect( spy.called ).toEqual(false)
|
@@ -48,3 +48,21 @@ describe "Luca.Model with computed attribute", ->
|
|
48
48
|
it "should have it set on constructor if dependencies are supplied", ->
|
49
49
|
model = new App.models.Sample({firstName:"Nickolay", lastName: "Schwarz"})
|
50
50
|
expect(model.get("fullName")).toEqual('Nickolay Schwarz')
|
51
|
+
|
52
|
+
|
53
|
+
describe 'The Read Method', ->
|
54
|
+
|
55
|
+
ModelClass = Luca.Model.extend
|
56
|
+
defaults:
|
57
|
+
attribute: "attribute"
|
58
|
+
reader: ()->
|
59
|
+
"reader"
|
60
|
+
|
61
|
+
it "should read an attribute", ->
|
62
|
+
model = new ModelClass()
|
63
|
+
expect( model.read('attribute') ).toEqual "attribute"
|
64
|
+
|
65
|
+
it "should read functions", ->
|
66
|
+
model = new ModelClass()
|
67
|
+
expect( model.read('attribute') ).toEqual "attribute"
|
68
|
+
expect( model.read('reader') ).toEqual 'reader'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe 'The Component Definition System', ->
|
2
|
+
beforeEach ->
|
3
|
+
Luca.components.SampleComponentDefinition = undefined
|
4
|
+
|
5
|
+
it "should define a component", ->
|
6
|
+
Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
|
7
|
+
expect( Luca.isComponentPrototype(Luca.components.SampleComponentDefinition) ).toEqual true
|
8
|
+
|
9
|
+
it "should default to Luca.View for the extends portion", ->
|
10
|
+
Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
|
11
|
+
expect( Luca.parentClasses(Luca.components.SampleComponentDefinition) ).toContain 'Luca.View'
|
12
|
+
|
13
|
+
it "should track the parent classes", ->
|
14
|
+
Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
|
15
|
+
expect( Luca.parentClasses(Luca.components.SampleComponentDefinition) ).toEqual ['Luca.View','Backbone.View']
|
16
|
+
|
17
|
+
xit "should defer component extension until dependencies are defined", ->
|
18
|
+
|
19
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
describe 'The Mixin System', ->
|
2
|
+
|
3
|
+
window.Luca ||= {}
|
4
|
+
|
5
|
+
Luca.mixin.namespace 'Luca.test_modules'
|
6
|
+
|
7
|
+
Luca.test_modules =
|
8
|
+
SecondMixin:
|
9
|
+
__included: ()->
|
10
|
+
window.secondMixinIncluded = true
|
11
|
+
__initializer: ()->
|
12
|
+
@trigger "second:mixin"
|
13
|
+
FirstMixin:
|
14
|
+
__initializer: ()->
|
15
|
+
@trigger "first:mixin"
|
16
|
+
__privateMethod: ()->
|
17
|
+
true
|
18
|
+
publicMethod: ()->
|
19
|
+
true
|
20
|
+
|
21
|
+
sampleView = Luca.register('Luca.components.FirstView')
|
22
|
+
|
23
|
+
sampleView.mixesIn 'FirstMixin'
|
24
|
+
|
25
|
+
sampleView.defines
|
26
|
+
sampleMethod: ()->
|
27
|
+
"sample"
|
28
|
+
|
29
|
+
secondView = Luca.register("Luca.components.SecondView")
|
30
|
+
secondView.extends 'Luca.components.FirstView'
|
31
|
+
secondView.mixesIn 'SecondMixin'
|
32
|
+
secondView.defines
|
33
|
+
version: 2
|
34
|
+
|
35
|
+
it "should omit the private methods defined on the mixin", ->
|
36
|
+
sampleView = new Luca.components.FirstView
|
37
|
+
expect( sampleView.__privateMethod ).not.toBeDefined()
|
38
|
+
|
39
|
+
it "should extend the prototype with the mixins normal methods", ->
|
40
|
+
sampleView = new Luca.components.FirstView
|
41
|
+
expect( sampleView.publicMethod ).toBeDefined()
|
42
|
+
|
43
|
+
it "should call the initializer for that module on the instance", ->
|
44
|
+
secondView = new Luca.components.SecondView
|
45
|
+
expect( secondView ).toHaveTriggered("second:mixin")
|
46
|
+
|
47
|
+
it "should call the initializers up the prototype chain", ->
|
48
|
+
secondView = new Luca.components.SecondView
|
49
|
+
expect( secondView ).toHaveTriggered("first:mixin")
|
@@ -113,7 +113,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
113
113
|
# method which delegates to the controller, and allows you to navigate
|
114
114
|
# to a given page, or component, by its name. The controller integrates
|
115
115
|
# with the state machine of the application
|
116
|
-
@setupMainController()
|
116
|
+
@setupMainController() if @useController is true
|
117
117
|
|
118
118
|
# The Collection Manager is responsible
|
119
119
|
@setupCollectionManager()
|
@@ -253,7 +253,8 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
253
253
|
# any time the card switches on one of the sub controllers
|
254
254
|
# then we should track the active sub section on the global state chart
|
255
255
|
@getMainController()?.each (component)=>
|
256
|
-
|
256
|
+
type = component.type || component.type
|
257
|
+
if type.match(/controller$/)
|
257
258
|
component.bind "after:card:switch", (previous,current)=>
|
258
259
|
@state.set(active_sub_section:current.name)
|
259
260
|
app.trigger "sub:page:change"
|
@@ -263,7 +264,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
263
264
|
definedComponents = @components || []
|
264
265
|
|
265
266
|
@components = [
|
266
|
-
|
267
|
+
type: 'controller'
|
267
268
|
name: "main_controller"
|
268
269
|
components: definedComponents
|
269
270
|
]
|
@@ -271,23 +272,36 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
271
272
|
@defer( @setupControllerBindings, false ).until("after:components")
|
272
273
|
|
273
274
|
setupCollectionManager: ()->
|
274
|
-
|
275
|
-
@collectionManagerClass = Luca.util.resolve( @collectionManagerClass ) if _.isString( @collectionManagerClass )
|
275
|
+
return unless @useCollectionManager is true
|
276
276
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
277
|
+
return if @collectionManager? and @collectionManager?.get?
|
278
|
+
|
279
|
+
if _.isString( @collectionManagerClass )
|
280
|
+
@collectionManagerClass = Luca.util.resolve( @collectionManagerClass )
|
281
|
+
|
282
|
+
collectionManagerOptions = @collectionManagerOptions || {}
|
283
|
+
|
284
|
+
# if the collectionManager property is present, and it
|
285
|
+
# isn't a reference to a collection manager instance, then
|
286
|
+
# it is being used as a configuration hash for when we do create
|
287
|
+
# the collection manager. so let's stash it.
|
288
|
+
if _.isObject(@collectionManager) and not _.isFunction( @collectionManager?.get )
|
289
|
+
collectionManagerOptions = @collectionManager
|
290
|
+
@collectionManager = undefined
|
291
|
+
|
292
|
+
# if the collection manager property is a string, then it is a
|
293
|
+
# reference to a name of a collection manager to use. so let's
|
294
|
+
# stash it
|
295
|
+
if _.isString(@collectionManager)
|
296
|
+
collectionManagerOptions =
|
297
|
+
name: @collectionManager
|
298
|
+
|
299
|
+
# let's try and get the collection manager by name if we can
|
300
|
+
@collectionManager = Luca.CollectionManager.get?( collectionManagerOptions.name )
|
301
|
+
|
302
|
+
# if we can't, then we will have to create one ourselves
|
303
|
+
unless _.isFunction(@collectionManager?.get)
|
304
|
+
@collectionManager = new @collectionManagerClass( collectionManagerOptions )
|
291
305
|
|
292
306
|
setupRouter: ()->
|
293
307
|
app = @
|
@@ -1,15 +1,33 @@
|
|
1
|
-
|
1
|
+
collectionView = Luca.define "Luca.components.CollectionView"
|
2
|
+
# The CollectionView facilitates the rendering of a Collection
|
3
|
+
# of models into a group of many rendered templates
|
2
4
|
#
|
3
|
-
#
|
5
|
+
# Example:
|
4
6
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# new Luca.components.CollectionView
|
8
|
+
# itemTemplate: "template_name"
|
9
|
+
# collection: "collection_class_name"
|
10
|
+
# pagination:
|
11
|
+
# page: 1
|
12
|
+
# limit: 15
|
13
|
+
# filterable:
|
14
|
+
# query:
|
15
|
+
# default: 'value'
|
9
16
|
#
|
17
|
+
collectionView.extends "Luca.components.Panel"
|
10
18
|
|
11
|
-
|
12
|
-
|
19
|
+
collectionView.behavesAs "LoadMaskable",
|
20
|
+
"Filterable",
|
21
|
+
"Paginatable"
|
22
|
+
|
23
|
+
collectionView.triggers "before:refresh",
|
24
|
+
"after:refresh",
|
25
|
+
"refresh",
|
26
|
+
"empty:results"
|
27
|
+
|
28
|
+
collectionView.defaults
|
29
|
+
|
30
|
+
tagName: "ol"
|
13
31
|
|
14
32
|
className: "luca-ui-collection-view"
|
15
33
|
|
@@ -25,16 +43,13 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
|
|
25
43
|
|
26
44
|
itemClassName: 'collection-item'
|
27
45
|
|
28
|
-
hooks:[
|
29
|
-
"empty:results"
|
30
|
-
]
|
31
|
-
|
32
46
|
initialize: (@options={})->
|
33
47
|
_.extend(@, @options)
|
34
48
|
|
35
49
|
_.bindAll @, "refresh"
|
36
50
|
|
37
51
|
unless @collection? or @options.collection
|
52
|
+
console.log "Error on initialize of collection view", @
|
38
53
|
throw "Collection Views must specify a collection"
|
39
54
|
|
40
55
|
unless @itemTemplate? || @itemRenderer? || @itemProperty?
|
@@ -45,56 +60,111 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
|
|
45
60
|
if _.isString(@collection) and Luca.CollectionManager.get()
|
46
61
|
@collection = Luca.CollectionManager.get().getOrCreate(@collection)
|
47
62
|
|
48
|
-
|
63
|
+
unless Luca.isBackboneCollection(@collection)
|
64
|
+
throw "Collection Views must have a valid backbone collection"
|
65
|
+
|
49
66
|
@collection.on "before:fetch", ()=>
|
50
|
-
@trigger "enable:loadmask"
|
67
|
+
@trigger "enable:loadmask"
|
51
68
|
|
52
69
|
@collection.bind "reset", ()=>
|
53
|
-
@trigger "disable:loadmask" if @loadMask is true
|
54
70
|
@refresh()
|
71
|
+
@trigger "disable:loadmask"
|
55
72
|
|
56
|
-
@collection.bind "
|
57
|
-
|
58
|
-
|
59
|
-
|
73
|
+
@collection.bind "remove", ()=>
|
74
|
+
@refresh()
|
75
|
+
|
76
|
+
@collection.bind "add", ()=>
|
77
|
+
@refresh()
|
78
|
+
|
79
|
+
if @observeChanges is true
|
80
|
+
@collection.on "change", @refreshModel, @
|
60
81
|
|
61
|
-
|
62
|
-
@
|
82
|
+
unless @autoRefreshOnModelsPresent is false
|
83
|
+
@defer ()=>
|
84
|
+
@refresh() if @collection.length > 0
|
85
|
+
.until("after:render")
|
63
86
|
|
64
|
-
|
65
|
-
|
87
|
+
@on "collection:change", @refresh, @
|
88
|
+
|
89
|
+
attributesForItem: (item, model)->
|
90
|
+
_.extend {}, class: @itemClassName, "data-index": item.index, "data-model-id": item.model.get('id')
|
66
91
|
|
67
92
|
contentForItem: (item={})->
|
68
93
|
if @itemTemplate? and templateFn = Luca.template(@itemTemplate)
|
69
|
-
content = templateFn.call(@, item)
|
94
|
+
return content = templateFn.call(@, item)
|
70
95
|
|
71
96
|
if @itemRenderer? and _.isFunction( @itemRenderer )
|
72
|
-
content = @itemRenderer.call(@, item, item.model, item.index)
|
97
|
+
return content = @itemRenderer.call(@, item, item.model, item.index)
|
73
98
|
|
74
|
-
if @itemProperty
|
75
|
-
content = item.model.
|
76
|
-
content = content() if _.isFunction(content)
|
99
|
+
if @itemProperty and item.model?
|
100
|
+
return content = item.model.read( @itemProperty )
|
77
101
|
|
78
|
-
|
102
|
+
""
|
79
103
|
|
80
104
|
makeItem: (model, index)->
|
81
105
|
item = if @prepareItem? then @prepareItem.call(@, model, index) else (model:model, index: index)
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
106
|
+
attributes = @attributesForItem(item, model)
|
107
|
+
content = @contentForItem(item)
|
108
|
+
# TEMP
|
109
|
+
# Figure out why calls to make are failing with an unexpected string error
|
110
|
+
try
|
111
|
+
make(@itemTagName, attributes, content)
|
112
|
+
catch e
|
113
|
+
console.log "Error generating DOM element for CollectionView", @, model, index
|
114
|
+
#no op
|
115
|
+
|
116
|
+
getCollection: ()->
|
117
|
+
@collection
|
118
|
+
|
119
|
+
# Private: returns the query that is applied to the underlying collection.
|
120
|
+
# accepts the same options as Luca.Collection.query's initial query option.
|
121
|
+
getQuery: ()->
|
122
|
+
@query ||= {}
|
123
|
+
|
124
|
+
# Private: returns the query that is applied to the underlying collection.
|
125
|
+
# accepts the same options as Luca.Collection.query's initial query option.
|
126
|
+
getQueryOptions: ()->
|
127
|
+
@queryOptions ||= {}
|
128
|
+
|
129
|
+
# Private: returns the models to be rendered. If the underlying collection
|
130
|
+
# responds to @query() then it will use that interface.
|
131
|
+
getModels: (query,options)->
|
132
|
+
if @collection?.query
|
133
|
+
query ||= @getQuery()
|
134
|
+
options ||= @getQueryOptions()
|
135
|
+
|
136
|
+
@collection.query(query, options)
|
87
137
|
else
|
88
138
|
@collection.models
|
89
139
|
|
90
|
-
|
140
|
+
locateItemElement: (id)->
|
141
|
+
@$(".#{ @itemClassName }[data-model-id='#{ id }']")
|
142
|
+
|
143
|
+
refreshModel: (model)->
|
144
|
+
index = @collection.indexOf( model )
|
145
|
+
@locateItemElement(model.get('id')).empty().append( @contentForItem({model,index}, model) )
|
146
|
+
@trigger("model:refreshed", index, model)
|
147
|
+
|
148
|
+
refresh: (query,options)->
|
149
|
+
query ||= @getQuery()
|
150
|
+
options ||= @getQueryOptions()
|
151
|
+
|
91
152
|
@$bodyEl().empty()
|
153
|
+
models = @getModels(query, options)
|
154
|
+
|
155
|
+
@trigger("before:refresh", models, query, options)
|
92
156
|
|
93
|
-
if
|
157
|
+
if models.length is 0
|
94
158
|
@trigger("empty:results")
|
95
159
|
|
96
|
-
|
97
|
-
|
160
|
+
index = 0
|
161
|
+
|
162
|
+
for model in models
|
163
|
+
@$append @makeItem(model, index++)
|
164
|
+
|
165
|
+
@trigger("after:refresh", models, query, options)
|
166
|
+
|
167
|
+
@
|
98
168
|
|
99
169
|
registerEvent: (domEvent, selector, handler)->
|
100
170
|
if !handler? and _.isFunction(selector)
|
@@ -111,4 +181,5 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
|
|
111
181
|
|
112
182
|
# Private Helpers
|
113
183
|
|
184
|
+
|
114
185
|
make = Luca.View::make
|