luca 0.9.4 → 0.9.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/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
|