luca 0.9.65 → 0.9.76
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 +30 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +27 -0
- data/lib/luca/rails/version.rb +1 -1
- data/spec/components/controller_spec.coffee +58 -0
- data/spec/components/form_view_spec.coffee +4 -0
- data/spec/concerns/dom_helpers_spec.coffee +16 -0
- data/spec/{modules → concerns}/filterable_spec.coffee +0 -0
- data/spec/concerns/model_presenter_spec.coffee +31 -0
- data/spec/{modules → concerns}/paginatable_spec.coffee +0 -0
- data/spec/{modules → concerns}/state_model_spec.coffee +0 -0
- data/spec/concerns_spec.coffee +88 -0
- data/spec/core/container_spec.coffee +103 -6
- data/spec/core/field_spec.coffee +4 -0
- data/spec/core/model_spec.coffee +6 -1
- data/spec/define_spec.coffee +104 -7
- data/spec/framework_spec.coffee +30 -1
- data/spec/util_spec.coffee +24 -0
- data/src/components/application.coffee +62 -25
- data/src/components/base_toolbar.coffee +6 -4
- data/src/components/collection_loader_view.coffee +3 -1
- data/src/components/collection_view.coffee +36 -73
- data/src/components/controller.coffee +73 -35
- data/src/components/fields/button_field.coffee +20 -12
- data/src/components/fields/checkbox_array.coffee +8 -2
- data/src/components/fields/checkbox_field.coffee +18 -9
- data/src/components/fields/file_upload_field.coffee +5 -1
- data/src/components/fields/hidden_field.coffee +3 -1
- data/src/components/fields/label_field.coffee +4 -3
- data/src/components/fields/select_field.coffee +7 -8
- data/src/components/fields/text_area_field.coffee +3 -2
- data/src/components/fields/text_field.coffee +5 -4
- data/src/components/fields/type_ahead_field.coffee +4 -2
- data/src/components/form_button_toolbar.coffee +4 -1
- data/src/components/form_view.coffee +26 -24
- data/src/components/grid_view.coffee +3 -3
- data/src/components/multi_collection_view.coffee +6 -35
- data/src/components/pagination_control.coffee +1 -3
- data/src/components/router.coffee +2 -0
- data/src/components/table_view.coffee +7 -0
- data/src/concerns.coffee +70 -0
- data/src/{modules → concerns}/application_event_bindings.coffee +1 -1
- data/src/{modules → concerns}/collection_event_bindings.coffee +1 -1
- data/src/{modules → concerns}/deferrable.coffee +1 -1
- data/src/{modules → concerns}/dom_helpers.coffee +11 -2
- data/src/{modules → concerns}/enhanced_properties.coffee +1 -1
- data/src/{modules → concerns}/filterable.coffee +11 -11
- data/src/{modules → concerns}/grid_layout.coffee +1 -1
- data/src/{modules → concerns}/loadmaskable.coffee +1 -1
- data/src/{modules → concerns}/local_storage.coffee +0 -0
- data/src/{modules → concerns}/modal_view.coffee +1 -1
- data/src/concerns/model_presenter.coffee +23 -0
- data/src/{modules → concerns}/paginatable.coffee +9 -3
- data/src/concerns/query_collection_bindings.coffee +44 -0
- data/src/{modules → concerns}/state_model.coffee +1 -1
- data/src/{modules → concerns}/templating.coffee +1 -1
- data/src/containers/card_view.coffee +16 -9
- data/src/containers/tab_view.coffee +8 -11
- data/src/containers/viewport.coffee +3 -3
- data/src/core/collection.coffee +39 -28
- data/src/core/container.coffee +37 -15
- data/src/core/field.coffee +40 -39
- data/src/core/meta_data.coffee +93 -0
- data/src/core/model.coffee +18 -1
- data/src/core/registry.coffee +4 -3
- data/src/core/view.coffee +24 -30
- data/src/define.coffee +165 -79
- data/src/framework.coffee +97 -21
- data/src/index.coffee +4 -2
- data/src/managers/collection_manager.coffee +7 -3
- data/src/stylesheets/components/checkbox_array.scss +1 -1
- data/src/stylesheets/components/form_view.scss +5 -5
- data/src/stylesheets/components/viewport.scss +2 -1
- data/src/stylesheets/containers/container.scss +0 -5
- data/src/stylesheets/containers/tab_view.scss +5 -5
- data/src/templates/fields/text_area_field.jst.ejs +1 -1
- data/src/templates/fields/text_field.jst.ejs +1 -1
- data/src/util.coffee +47 -0
- data/vendor/assets/javascripts/luca-ui-full.js +1279 -494
- data/vendor/assets/javascripts/luca-ui-full.min.js +5 -5
- data/vendor/assets/javascripts/luca-ui-templates.js +2 -2
- data/vendor/assets/javascripts/luca-ui.js +1279 -494
- data/vendor/assets/javascripts/luca-ui.min.js +5 -4
- data/vendor/assets/stylesheets/luca-ui.css +15 -15
- metadata +27 -20
- data/spec/mixin_spec.coffee +0 -49
data/spec/core/field_spec.coffee
CHANGED
data/spec/core/model_spec.coffee
CHANGED
@@ -50,13 +50,14 @@ describe "Luca.Model with computed attribute", ->
|
|
50
50
|
expect(model.get("fullName")).toEqual('Nickolay Schwarz')
|
51
51
|
|
52
52
|
|
53
|
-
describe 'The Read Method', ->
|
54
53
|
|
54
|
+
describe 'The Read Method', ->
|
55
55
|
ModelClass = Luca.Model.extend
|
56
56
|
defaults:
|
57
57
|
attribute: "attribute"
|
58
58
|
reader: ()->
|
59
59
|
"reader"
|
60
|
+
property: true
|
60
61
|
|
61
62
|
it "should read an attribute", ->
|
62
63
|
model = new ModelClass()
|
@@ -66,3 +67,7 @@ describe 'The Read Method', ->
|
|
66
67
|
model = new ModelClass()
|
67
68
|
expect( model.read('attribute') ).toEqual "attribute"
|
68
69
|
expect( model.read('reader') ).toEqual 'reader'
|
70
|
+
|
71
|
+
it "should read model object attributes as a fallback", ->
|
72
|
+
model = new ModelClass()
|
73
|
+
expect( model.read('property') ).toEqual true
|
data/spec/define_spec.coffee
CHANGED
@@ -1,19 +1,116 @@
|
|
1
1
|
describe 'The Component Definition System', ->
|
2
2
|
beforeEach ->
|
3
|
-
Luca.components.
|
3
|
+
unfinished = Luca.register 'Luca.components.UnfinishedDefinition'
|
4
|
+
|
5
|
+
sample = Luca.register 'Luca.components.SampleComponentDefinition'
|
6
|
+
|
7
|
+
sample.classMethods
|
8
|
+
classMethod: ()-> "classMethod"
|
9
|
+
|
10
|
+
sample.contains
|
11
|
+
name: "component_one"
|
12
|
+
,
|
13
|
+
name: "component_two"
|
14
|
+
|
15
|
+
sample.classConfiguration
|
16
|
+
classAttribute: "classAttribute"
|
17
|
+
|
18
|
+
sample.afterDefinition( sinon.spy() )
|
19
|
+
|
20
|
+
sample.publicInterface
|
21
|
+
publicAttribute: "publicAttribute"
|
22
|
+
publicMethod: ()-> "publicMethod"
|
23
|
+
|
24
|
+
sample.privateInterface
|
25
|
+
privateAttribute: "privateAttribute"
|
26
|
+
privateMethod: ()-> "privateMethod"
|
27
|
+
|
28
|
+
sample.publicConfiguration
|
29
|
+
publicProperty: "publicProperty"
|
30
|
+
|
31
|
+
sample.privateConfiguration
|
32
|
+
privateProperty: "privateProperty"
|
33
|
+
|
34
|
+
sample.register()
|
35
|
+
|
36
|
+
it "should find a definition ", ->
|
37
|
+
definition = Luca.define.findDefinition('Luca.components.UnfinishedDefinition')
|
38
|
+
expect( Luca.components.UnfinishedDefinition ).not.toBeDefined()
|
39
|
+
expect( definition ).toBeDefined()
|
40
|
+
|
41
|
+
it "should find a component definition through the Luca() helper", ->
|
42
|
+
definition = Luca("Luca.components.SampleComponentDefinition")
|
43
|
+
expect( definition.extend ).toBeDefined()
|
44
|
+
expect( definition.register ).not.toBeDefined()
|
45
|
+
|
46
|
+
it "should find an incomplete definition through the Luca() helper", ->
|
47
|
+
definition = Luca("Luca.components.UnfinishedDefinition")
|
48
|
+
expect( definition ).toBeDefined()
|
49
|
+
expect( definition.register ).toBeDefined()
|
50
|
+
|
51
|
+
# I did this to make the definition not require a single method
|
52
|
+
# to be called at the end every time, if it is more readable to leave it off.
|
53
|
+
it "should know if a definition is 'open'", ->
|
54
|
+
definition = Luca("Luca.components.UnfinishedDefinition")
|
55
|
+
expect( definition.isOpen() ).toBeTruthy()
|
56
|
+
|
57
|
+
it "should close any open definitions", ->
|
58
|
+
Luca.define.close()
|
59
|
+
expect( Luca.components.UnfinishedDefinition ).toBeDefined()
|
60
|
+
expect( Luca.define.incomplete().length ).toEqual 0
|
4
61
|
|
5
62
|
it "should define a component", ->
|
6
|
-
Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
|
7
63
|
expect( Luca.isComponentPrototype(Luca.components.SampleComponentDefinition) ).toEqual true
|
8
64
|
|
65
|
+
it "should add everything defined for the prototype", ->
|
66
|
+
for attribute in ["publicMethod","publicProperty","publicAttribute","privateAttribute","privateMethod","privateProperty"]
|
67
|
+
expect( Luca.components.SampleComponentDefinition.prototype[attribute] ).toBeDefined()
|
68
|
+
|
9
69
|
it "should default to Luca.View for the extends portion", ->
|
10
|
-
Luca.register("Luca.components.SampleComponentDefinition").defines(version: 1)
|
11
70
|
expect( Luca.parentClasses(Luca.components.SampleComponentDefinition) ).toContain 'Luca.View'
|
71
|
+
|
72
|
+
it "should define class methods ", ->
|
73
|
+
test = Luca.components.SampleComponentDefinition.classMethod()
|
74
|
+
expect( test ).toEqual 'classMethod'
|
75
|
+
|
76
|
+
it "should inherit class methods when extending", ->
|
77
|
+
Luca.register("Luca.components.ExtendedSampleComponent").extends("Luca.components.SampleComponentDefinition").register()
|
78
|
+
test = Luca.components.ExtendedSampleComponent.classMethod()
|
79
|
+
expect( test ).toEqual('classMethod')
|
80
|
+
|
81
|
+
it "should define class configuration ", ->
|
82
|
+
test = Luca.components.SampleComponentDefinition.classAttribute
|
83
|
+
expect( test ).toEqual 'classAttribute'
|
84
|
+
|
85
|
+
describe 'The Component MetaData', ->
|
86
|
+
beforeEach ->
|
87
|
+
@metaData = Luca.registry.getMetaDataFor('Luca.components.SampleComponentDefinition')
|
88
|
+
|
89
|
+
it "should provide access to component meta data", ->
|
90
|
+
meta = Luca.components.SampleComponentDefinition::componentMetaData()
|
91
|
+
expect( meta ).toEqual( @metaData )
|
92
|
+
|
93
|
+
it "should know the public interface", ->
|
94
|
+
expect( @metaData.publicAttributes() ).toContain('publicProperty','publicMethod','publicAttribute')
|
95
|
+
|
96
|
+
it "should know the public methods", ->
|
97
|
+
expect( @metaData.publicMethods() ).toContain('publicMethod')
|
98
|
+
expect( @metaData.publicMethods() ).not.toContain('publicAttribute')
|
99
|
+
|
100
|
+
it "should know the private interface", ->
|
101
|
+
expect( @metaData.privateAttributes() ).toContain('privateProperty','privateMethod','privateAttribute')
|
12
102
|
|
13
|
-
|
14
|
-
|
15
|
-
|
103
|
+
it "should know the private methods", ->
|
104
|
+
expect( @metaData.privateMethods() ).toContain('privateMethod')
|
105
|
+
expect( @metaData.privateMethods() ).not.toContain('privateAttribute')
|
16
106
|
|
17
|
-
|
107
|
+
it "should know the class methods", ->
|
108
|
+
expect( @metaData.classMethods() ).toContain("classMethod")
|
18
109
|
|
110
|
+
it "should fire the afterDefinition hook on the component class", ->
|
111
|
+
expect( Luca.components.SampleComponentDefinition.afterDefinition ).toHaveBeenCalled()
|
19
112
|
|
113
|
+
describe 'Component Configuration Validations', ->
|
114
|
+
xit "should support specifying which values are required"
|
115
|
+
xit "should validate required values are present"
|
116
|
+
xit "should validate required values match certain expectations around data type"
|
data/spec/framework_spec.coffee
CHANGED
@@ -8,7 +8,7 @@ describe "The Luca Framework", ->
|
|
8
8
|
expect(Luca).toBeDefined()
|
9
9
|
|
10
10
|
it "should enable bootstrap by default", ->
|
11
|
-
expect(Luca.
|
11
|
+
expect(Luca.config.enableBoostrap).toBeTruthy()
|
12
12
|
|
13
13
|
it "should have classes in the registry", ->
|
14
14
|
expect( Luca.registry.classes ).toBeDefined()
|
@@ -113,3 +113,32 @@ describe "Luca Component Definition", ->
|
|
113
113
|
it "should allow me to set the namespace before the definition", ->
|
114
114
|
Luca.util.namespace("Luca.View")
|
115
115
|
expect( Luca.util.namespace() ).toEqual Luca.View
|
116
|
+
|
117
|
+
describe 'Application Space Initialization', ->
|
118
|
+
window.SampleLucaApplication = undefined
|
119
|
+
|
120
|
+
Luca.initialize("SampleLucaApplication", configOption: true)
|
121
|
+
|
122
|
+
it "should create the namespace", ->
|
123
|
+
expect( SampleLucaApplication ).toBeDefined()
|
124
|
+
|
125
|
+
it "should override luca config settings", ->
|
126
|
+
expect( Luca.config.configOption ).toEqual true
|
127
|
+
|
128
|
+
it "should create a helper function", ->
|
129
|
+
expect( SampleLucaApplication("Luca.View") ).toEqual( Luca.View )
|
130
|
+
|
131
|
+
it "should create the container for views", ->
|
132
|
+
expect( SampleLucaApplication.views ).toBeDefined()
|
133
|
+
|
134
|
+
it "should create the container for models", ->
|
135
|
+
expect( SampleLucaApplication.models ).toBeDefined()
|
136
|
+
|
137
|
+
it "should create the container for collections", ->
|
138
|
+
expect( SampleLucaApplication.collections ).toBeDefined()
|
139
|
+
|
140
|
+
it "should set the collection namespace", ->
|
141
|
+
namespace = Luca.util.read( Luca.Collection.namespace )
|
142
|
+
expect( namespace ).toEqual SampleLucaApplication.collections
|
143
|
+
|
144
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
describe 'The Luca Utilities', ->
|
2
|
+
describe "Converting from component class to css class", ->
|
3
|
+
it "should produce a css class from the component class name", ->
|
4
|
+
component = "Luca.core.Container"
|
5
|
+
cssClass = Luca.util.toCssClass(component)
|
6
|
+
expect( cssClass ).toEqual 'luca-core-container'
|
7
|
+
|
8
|
+
it "should produce a css class from the component class name", ->
|
9
|
+
component = "Luca.components.MultiCollectionView"
|
10
|
+
cssClass = Luca.util.toCssClass(component)
|
11
|
+
expect( cssClass ).toEqual 'luca-components-multi-collection-view'
|
12
|
+
|
13
|
+
it "should produce a css class from the component class name", ->
|
14
|
+
component = "Luca.View"
|
15
|
+
cssClass = Luca.util.toCssClass(component)
|
16
|
+
expect( cssClass ).toEqual 'luca-view'
|
17
|
+
|
18
|
+
it "should exclude parts", ->
|
19
|
+
component = "Luca.components.MultiCollectionView"
|
20
|
+
cssClass = Luca.util.toCssClass(component, 'components')
|
21
|
+
expect( cssClass ).toEqual "luca-multi-collection-view"
|
22
|
+
|
23
|
+
|
24
|
+
|
@@ -2,22 +2,13 @@
|
|
2
2
|
#
|
3
3
|
# The Application class is the global state tracking mechanism
|
4
4
|
# for your single page application, as well as the entry point.
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
# In a typical Luca application, the router will use the applications @navigate_to() method to switch
|
9
|
-
# from page to page on the main controller, or any other controllers nested inside of it.
|
10
|
-
#
|
11
|
-
# You would control flow when the controller fires activation events on the nested view components inside of it.
|
12
|
-
#
|
13
|
-
# Decoupling application control flow from the URL Fragment from Backbone.History and preventing
|
14
|
-
# your components from directly caring about the URL Fragment, allows you to build applications as
|
15
|
-
# isolated components which can run separately or nested inside of other applications.
|
5
|
+
application = Luca.register "Luca.Application"
|
6
|
+
application.extends "Luca.containers.Viewport"
|
16
7
|
|
17
|
-
|
18
|
-
|
8
|
+
application.triggers "controller:change",
|
9
|
+
"action:change"
|
19
10
|
|
20
|
-
|
11
|
+
application.publicInterface
|
21
12
|
name: "MyApp"
|
22
13
|
|
23
14
|
# The Application uses a Backbone.Model as a state machine, which
|
@@ -91,7 +82,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
91
82
|
# will get wrapped by the main controller unless you
|
92
83
|
# set useController = false
|
93
84
|
components:[
|
94
|
-
|
85
|
+
type: 'template'
|
95
86
|
name: 'welcome'
|
96
87
|
template: 'sample/welcome'
|
97
88
|
templateContainer: "Luca.templates"
|
@@ -102,8 +93,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
102
93
|
appName = @name
|
103
94
|
alreadyRunning = Luca.getApplication?()
|
104
95
|
|
105
|
-
Luca.Application.
|
106
|
-
Luca.Application.instances[ appName ] = app
|
96
|
+
Luca.Application.registerInstance(@)
|
107
97
|
|
108
98
|
Luca.containers.Viewport::initialize.apply @, arguments
|
109
99
|
|
@@ -213,11 +203,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
213
203
|
navigate_to: (component_name, callback)->
|
214
204
|
@getMainController().navigate_to(component_name, callback)
|
215
205
|
|
216
|
-
|
217
|
-
return @components[0] if @useController is true
|
218
|
-
Luca.cache('main_controller')
|
219
|
-
|
220
|
-
#
|
206
|
+
application.privateInterface
|
221
207
|
keyHandler: (e)->
|
222
208
|
return unless e and @keyEvents
|
223
209
|
|
@@ -249,7 +235,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
249
235
|
# the active card on the global state chart
|
250
236
|
@getMainController()?.bind "after:card:switch", (previous,current)=>
|
251
237
|
@state.set(active_section:current.name)
|
252
|
-
app.trigger "
|
238
|
+
app.trigger "controller:change"
|
253
239
|
|
254
240
|
# any time the card switches on one of the sub controllers
|
255
241
|
# then we should track the active sub section on the global state chart
|
@@ -258,7 +244,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
258
244
|
if type.match(/controller$/)
|
259
245
|
component.bind "after:card:switch", (previous,current)=>
|
260
246
|
@state.set(active_sub_section:current.name)
|
261
|
-
app.trigger "
|
247
|
+
app.trigger "action:change"
|
262
248
|
|
263
249
|
setupMainController: ()->
|
264
250
|
if @useController is true
|
@@ -267,8 +253,11 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
267
253
|
@components = [
|
268
254
|
type: 'controller'
|
269
255
|
name: "main_controller"
|
256
|
+
role: "main_controller"
|
270
257
|
components: definedComponents
|
271
258
|
]
|
259
|
+
|
260
|
+
@getMainController = ()=> @findComponentByRole('main_controller')
|
272
261
|
|
273
262
|
@defer( @setupControllerBindings, false ).until("after:components")
|
274
263
|
|
@@ -316,7 +305,7 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
316
305
|
# you can control which by setting the @startHistoryOn property
|
317
306
|
if @router and @autoStartHistory
|
318
307
|
@autoStartHistory = "before:render" if @autoStartHistory is true
|
319
|
-
@defer( Luca.
|
308
|
+
@defer( Luca.Application.startHistory, false).until(@, @autoStartHistory)
|
320
309
|
|
321
310
|
setupKeyHandler: ()->
|
322
311
|
return unless @keyEvents
|
@@ -330,3 +319,51 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
|
|
330
319
|
|
331
320
|
for keyEvent in (@keypressEvents || ["keydown"])
|
332
321
|
$( document ).on( keyEvent, handler )
|
322
|
+
|
323
|
+
application.classInterface
|
324
|
+
instances: {}
|
325
|
+
registerInstance: (app)->
|
326
|
+
Luca.Application.instances[ app.name ] = app
|
327
|
+
routeTo: (pages...)->
|
328
|
+
last = _( pages ).last()
|
329
|
+
first = _( pages ).first()
|
330
|
+
|
331
|
+
callback = undefined
|
332
|
+
specifiedAction = undefined
|
333
|
+
|
334
|
+
routeHelper = (args...)->
|
335
|
+
path = @app || Luca()
|
336
|
+
index = 0
|
337
|
+
|
338
|
+
if pages.length is 1 and target = Luca(first)
|
339
|
+
pages = target.controllerPath()
|
340
|
+
|
341
|
+
for page in pages when _.isString(page)
|
342
|
+
nextItem = pages[++index]
|
343
|
+
action = undefined
|
344
|
+
|
345
|
+
if _.isFunction(nextItem)
|
346
|
+
action = nextItem
|
347
|
+
else if _.isObject(nextItem) and nextItem.action?
|
348
|
+
action = nextItem.action
|
349
|
+
else if page is last and routeHandler = Luca(last)?.routeHandler
|
350
|
+
action = Luca.util.read(routeHandler)
|
351
|
+
|
352
|
+
if _.isString( action )
|
353
|
+
callback = ()->
|
354
|
+
@[ action ].apply(@, args)
|
355
|
+
|
356
|
+
if _.isFunction( action )
|
357
|
+
callback = nextItem
|
358
|
+
|
359
|
+
path = path.navigate_to(page, callback)
|
360
|
+
|
361
|
+
routeHelper.action = (action)->
|
362
|
+
pages.push(action: action)
|
363
|
+
|
364
|
+
return routeHelper
|
365
|
+
|
366
|
+
startHistory: ()->
|
367
|
+
Backbone.history.start()
|
368
|
+
|
369
|
+
application.register()
|
@@ -1,15 +1,17 @@
|
|
1
1
|
_.def('Luca.components.Toolbar').extends('Luca.core.Container').with
|
2
2
|
|
3
|
+
toolbar = Luca.register "Luca.components.Toolbar"
|
4
|
+
toolbar.extends "Luca.core.Container"
|
5
|
+
|
6
|
+
toolbar.defines
|
3
7
|
className: 'luca-ui-toolbar toolbar'
|
4
8
|
|
5
9
|
position: 'bottom'
|
6
10
|
|
7
|
-
initialize: (@options={})->
|
8
|
-
Luca.core.Container::initialize.apply @, arguments
|
9
|
-
|
10
11
|
prepareComponents: ()->
|
11
12
|
_( @components ).each (component)=>
|
12
13
|
component.container = @$el
|
13
14
|
|
14
15
|
render: ()->
|
15
|
-
$(@container).append(@el)
|
16
|
+
$(@container).append(@el)
|
17
|
+
@
|
@@ -3,8 +3,10 @@
|
|
3
3
|
# if you want to. Default implementation uses twitter bootstrap modal and
|
4
4
|
# progress bar (http://twitter.github.com/bootstrap/). You template
|
5
5
|
# should contain `progress`, `bar` and `message` classes
|
6
|
-
|
6
|
+
loaderView = Luca.register "Luca.components.CollectionLoaderView"
|
7
|
+
loaderView.extends "Luca.View"
|
7
8
|
|
9
|
+
loaderView.defines
|
8
10
|
className: 'luca-ui-collection-loader-view'
|
9
11
|
|
10
12
|
template: "components/collection_loader_view"
|
@@ -1,4 +1,4 @@
|
|
1
|
-
collectionView = Luca.
|
1
|
+
collectionView = Luca.register "Luca.components.CollectionView"
|
2
2
|
# The CollectionView facilitates the rendering of a Collection
|
3
3
|
# of models into a group of many rendered templates
|
4
4
|
#
|
@@ -16,7 +16,8 @@ collectionView = Luca.define "Luca.components.CollectionView"
|
|
16
16
|
#
|
17
17
|
collectionView.extends "Luca.components.Panel"
|
18
18
|
|
19
|
-
collectionView.
|
19
|
+
collectionView.mixesIn "QueryCollectionBindings",
|
20
|
+
"LoadMaskable",
|
20
21
|
"Filterable",
|
21
22
|
"Paginatable"
|
22
23
|
|
@@ -25,31 +26,36 @@ collectionView.triggers "before:refresh",
|
|
25
26
|
"refresh",
|
26
27
|
"empty:results"
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
# IDEA:
|
30
|
+
#
|
31
|
+
# For validation of component configuration,
|
32
|
+
# we could define a convention like:
|
33
|
+
#
|
34
|
+
# collectionView.validatesConfigurationWith
|
35
|
+
# requiresValidCollectionAt: "collection"
|
36
|
+
# requiresPresenceOf:
|
37
|
+
# either: ["itemTemplate", "itemRenderer", "itemProperty"]
|
38
|
+
#
|
39
|
+
#
|
40
|
+
collectionView.publicConfiguration
|
30
41
|
tagName: "ol"
|
31
|
-
|
32
|
-
className: "luca-ui-collection-view"
|
33
|
-
|
34
42
|
bodyClassName: "collection-ui-panel"
|
35
|
-
|
36
|
-
# A collection view can pass a model through to a template
|
37
|
-
itemTemplate: undefined
|
38
|
-
|
39
|
-
# A collection view can pass a model through a function which should return a string
|
40
|
-
itemRenderer: undefined
|
41
|
-
|
42
43
|
itemTagName: 'li'
|
43
|
-
|
44
44
|
itemClassName: 'collection-item'
|
45
|
+
itemTemplate: undefined
|
46
|
+
itemRenderer: undefined
|
47
|
+
itemProperty: undefined
|
45
48
|
|
46
|
-
|
49
|
+
collectionView.defines
|
47
50
|
initialize: (@options={})->
|
48
51
|
_.extend(@, @options)
|
49
|
-
|
50
52
|
_.bindAll @, "refresh"
|
51
53
|
|
52
|
-
|
54
|
+
# IDEA:
|
55
|
+
#
|
56
|
+
# This type of code could be moved into a re-usable concern
|
57
|
+
# which higher order components can mixin to make it easier
|
58
|
+
# to extend them, instantiate them, etc.
|
53
59
|
unless @collection? or @options.collection
|
54
60
|
console.log "Error on initialize of collection view", @
|
55
61
|
throw "Collection Views must specify a collection"
|
@@ -67,29 +73,24 @@ collectionView.defaults
|
|
67
73
|
console.log "Missing Collection on #{ @name || @cid }", @, @collection
|
68
74
|
throw "Collection Views must have a valid backbone collection"
|
69
75
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
+
@collection.on "before:fetch", ()=>
|
77
|
+
@trigger "enable:loadmask"
|
78
|
+
|
79
|
+
@collection.bind "reset", ()=>
|
80
|
+
@refresh()
|
81
|
+
@trigger "disable:loadmask"
|
76
82
|
|
77
|
-
|
78
|
-
|
83
|
+
@collection.bind "remove", ()=>
|
84
|
+
@refresh()
|
79
85
|
|
80
|
-
|
81
|
-
|
86
|
+
@collection.bind "add", ()=>
|
87
|
+
@refresh()
|
82
88
|
|
83
|
-
|
84
|
-
|
89
|
+
if @observeChanges is true
|
90
|
+
@collection.on "change", @refreshModel, @
|
85
91
|
|
86
92
|
Luca.components.Panel::initialize.apply(@, arguments)
|
87
93
|
|
88
|
-
unless @autoRefreshOnModelsPresent is false
|
89
|
-
@defer ()=>
|
90
|
-
@refresh() if @collection.length > 0
|
91
|
-
.until("after:render")
|
92
|
-
|
93
94
|
@on "refresh", @refresh, @
|
94
95
|
|
95
96
|
attributesForItem: (item, model)->
|
@@ -119,44 +120,6 @@ collectionView.defaults
|
|
119
120
|
console.log "Error generating DOM element for CollectionView", @, model, index
|
120
121
|
#no op
|
121
122
|
|
122
|
-
getCollection: ()->
|
123
|
-
@collection
|
124
|
-
|
125
|
-
applyQuery: (query={},queryOptions={})->
|
126
|
-
@query = query
|
127
|
-
@queryOptions = queryOptions
|
128
|
-
@refresh()
|
129
|
-
@
|
130
|
-
|
131
|
-
# Private: returns the query that is applied to the underlying collection.
|
132
|
-
# accepts the same options as Luca.Collection.query's initial query option.
|
133
|
-
getQuery: ()->
|
134
|
-
query = @query ||= {}
|
135
|
-
for querySource in _( @querySources || [] ).compact()
|
136
|
-
query = _.extend(query, (querySource()||{}) )
|
137
|
-
query
|
138
|
-
|
139
|
-
# Private: returns the query that is applied to the underlying collection.
|
140
|
-
# accepts the same options as Luca.Collection.query's initial query option.
|
141
|
-
getQueryOptions: ()->
|
142
|
-
options = @queryOptions ||= {}
|
143
|
-
|
144
|
-
for optionSource in _( @optionsSources || [] ).compact()
|
145
|
-
options = _.extend(options, (optionSource()||{}) )
|
146
|
-
|
147
|
-
options
|
148
|
-
|
149
|
-
# Private: returns the models to be rendered. If the underlying collection
|
150
|
-
# responds to @query() then it will use that interface.
|
151
|
-
getModels: (query,options)->
|
152
|
-
if @collection?.query
|
153
|
-
query ||= @getQuery()
|
154
|
-
options ||= @getQueryOptions()
|
155
|
-
|
156
|
-
@collection.query(query, options)
|
157
|
-
else
|
158
|
-
@collection.models
|
159
|
-
|
160
123
|
locateItemElement: (id)->
|
161
124
|
@$(".#{ @itemClassName }[data-model-id='#{ id }']")
|
162
125
|
|