luca 0.9.2 → 0.9.4

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.
Files changed (129) hide show
  1. data/.gitignore +1 -0
  2. data/.rvmrc +1 -1
  3. data/CHANGELOG +46 -2
  4. data/Gemfile +1 -1
  5. data/Gemfile.lock +2 -2
  6. data/Guardfile +1 -1
  7. data/README.md +64 -27
  8. data/ROADMAP +17 -2
  9. data/Rakefile +49 -1
  10. data/app.rb +38 -2
  11. data/assets/javascripts/luca-ui-base.coffee +1 -20
  12. data/assets/javascripts/luca-ui-full.js +3 -0
  13. data/assets/javascripts/luca-ui.coffee +0 -5
  14. data/assets/javascripts/sandbox/application.coffee +24 -18
  15. data/assets/javascripts/sandbox/router.coffee +16 -6
  16. data/assets/javascripts/sandbox/templates/builder/component_list.luca +1 -0
  17. data/assets/javascripts/sandbox/templates/builder.luca +2 -0
  18. data/assets/javascripts/sandbox/templates/main.luca +4 -3
  19. data/assets/javascripts/sandbox/templates/sandbox/docs_index.luca +1 -0
  20. data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +6 -1
  21. data/assets/javascripts/sandbox/templates/sandbox/readme.luca +30 -0
  22. data/assets/javascripts/sandbox/views/builder/builder_canvas.coffee +3 -0
  23. data/assets/javascripts/sandbox/views/builder/builder_editor.coffee +6 -0
  24. data/assets/javascripts/sandbox/views/builder/component_list.coffee +38 -0
  25. data/assets/javascripts/sandbox/views/builder/project_browser.coffee +14 -0
  26. data/assets/javascripts/sandbox/views/builder.coffee +133 -0
  27. data/assets/javascripts/sandbox/views/docs_controller.coffee +7 -0
  28. data/assets/javascripts/sandbox/views/inspector/instance_filter.coffee +18 -0
  29. data/assets/javascripts/sandbox/{collections/sample.coffee → views/inspector/instance_list.coffee} +0 -0
  30. data/assets/javascripts/sandbox/views/inspector.coffee +11 -0
  31. data/assets/javascripts/sandbox.coffee +2 -0
  32. data/assets/stylesheets/luca-ui-full.css +3 -0
  33. data/assets/stylesheets/sandbox/builder.scss +79 -0
  34. data/assets/stylesheets/sandbox/sandbox.scss +2 -1
  35. data/docs/application.md +41 -0
  36. data/docs/collection.md +79 -0
  37. data/docs/collection_manager.md +76 -0
  38. data/docs/container_philosophy.md +122 -0
  39. data/docs/event_binding_helpers.md +164 -0
  40. data/docs/method_caching_and_computed_properties.md +77 -0
  41. data/docs/view.md +119 -0
  42. data/lib/luca/rails/version.rb +1 -1
  43. data/lib/luca/template.rb +9 -9
  44. data/site/assets/bootstrap.min.js +7 -0
  45. data/site/assets/luca-ui-bootstrap.css +19 -1
  46. data/site/assets/luca-ui-development-tools.css +10 -0
  47. data/site/assets/luca-ui-development-tools.min.js +15 -0
  48. data/site/assets/luca-ui-full.min.js +8 -0
  49. data/site/assets/luca-ui.min.js +4 -0
  50. data/site/assets/sandbox.css +52 -4
  51. data/site/assets/sandbox.js +368 -30
  52. data/site/docs/application.html +41 -0
  53. data/site/docs/caching.html +43 -0
  54. data/site/docs/collection.html +75 -0
  55. data/site/docs/collection_manager.html +71 -0
  56. data/site/docs/containers.html +118 -0
  57. data/site/docs/events.html +153 -0
  58. data/site/docs/view.html +128 -0
  59. data/site/img/glyphicons-halflings-white.png +0 -0
  60. data/site/img/glyphicons-halflings.png +0 -0
  61. data/site/source-map.js +1 -0
  62. data/spec/core/view_spec.coffee +5 -17
  63. data/spec/managers/collection_manager_spec.coffee +4 -7
  64. data/src/components/application.coffee +202 -77
  65. data/src/components/base_toolbar.coffee +1 -1
  66. data/src/components/collection_view.coffee +38 -10
  67. data/src/components/controller.coffee +24 -1
  68. data/src/components/fields/checkbox_field.coffee +9 -12
  69. data/src/components/fields/label_field.coffee +14 -0
  70. data/src/components/fields/select_field.coffee +2 -2
  71. data/src/components/fields/text_field.coffee +12 -7
  72. data/src/components/fields/type_ahead_field.coffee +1 -0
  73. data/src/components/form_view.coffee +44 -25
  74. data/src/components/page_controller.coffee +2 -0
  75. data/src/containers/card_view.coffee +4 -1
  76. data/src/containers/column_view.coffee +2 -1
  77. data/src/containers/modal_view.coffee +6 -2
  78. data/src/containers/page_view.coffee +2 -0
  79. data/src/containers/panel_toolbar.coffee +0 -5
  80. data/src/containers/viewport.coffee +28 -10
  81. data/src/core/collection.coffee +7 -1
  82. data/src/core/container.coffee +57 -30
  83. data/src/core/core.coffee +0 -186
  84. data/src/core/field.coffee +11 -3
  85. data/src/core/model.coffee +31 -16
  86. data/src/core/panel.coffee +6 -46
  87. data/src/core/registry.coffee +19 -2
  88. data/src/core/script_loader.coffee +32 -0
  89. data/src/core/view.coffee +112 -139
  90. data/src/define.coffee +110 -0
  91. data/src/framework.coffee +8 -2
  92. data/src/luca.coffee +22 -0
  93. data/src/managers/collection_manager.coffee +65 -31
  94. data/src/modules/load_mask.coffee +47 -0
  95. data/src/plugins/development_tool_helpers.coffee +21 -0
  96. data/src/plugins/events.coffee +54 -0
  97. data/src/stylesheets/components/viewport.scss +15 -0
  98. data/src/stylesheets/containers/container.scss +1 -4
  99. data/src/stylesheets/tools/component_tester.scss +18 -0
  100. data/src/templates/fields/select_field.luca +6 -5
  101. data/src/templates/fields/text_field.luca +10 -9
  102. data/src/tools/application_inspector.coffee +2 -0
  103. data/src/tools/coffee_script_editor.coffee +28 -6
  104. data/src/tools/collections/components.coffee +59 -0
  105. data/src/tools/collections/instances.coffee +15 -0
  106. data/src/tools/component_tester.coffee +12 -22
  107. data/src/tools/console.coffee +22 -4
  108. data/src/tools/models/components.coffee +16 -54
  109. data/src/tools/models/instance.coffee +2 -0
  110. data/src/{core/util.coffee → util.coffee} +10 -1
  111. data/vendor/assets/javascripts/luca-ui-base.js +132 -137
  112. data/vendor/assets/javascripts/luca-ui-development-tools.js +191 -219
  113. data/vendor/assets/javascripts/luca-ui-development-tools.min.js +2 -2
  114. data/vendor/assets/javascripts/luca-ui-full.js +4680 -0
  115. data/vendor/assets/javascripts/luca-ui-full.min.js +8 -0
  116. data/vendor/assets/javascripts/luca-ui-spec.js +291 -225
  117. data/vendor/assets/javascripts/luca-ui.js +1001 -724
  118. data/vendor/assets/javascripts/luca-ui.min.js +4 -4
  119. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +19 -1
  120. data/vendor/assets/stylesheets/luca-ui-development-tools.css +10 -0
  121. data/vendor/assets/stylesheets/luca-ui-full.css +1334 -0
  122. data/vendor/assets/stylesheets/luca-ui-spec.css +19 -1
  123. data/vendor/assets/stylesheets/luca-ui.css +19 -1
  124. data/views/index.erb +2 -5
  125. metadata +58 -9
  126. data/lib/sprockets/luca_template.rb +0 -49
  127. data/src/tools/class_browser.coffee +0 -39
  128. data/src/tools/components/class_browser_detail.coffee +0 -10
  129. data/src/tools/components/class_browser_list.coffee +0 -74
@@ -1,14 +1,52 @@
1
+ # Luca.Application
2
+ #
3
+ # The Application class is the global state tracking mechanism
4
+ # for your single page application, as well as the entry point.
5
+ #
6
+ # By default it contains a main controller which is a Luca.components.Controller instance.
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.
16
+
17
+ startHistory = ()-> Backbone.history.start()
18
+
1
19
  _.def('Luca.Application').extends('Luca.containers.Viewport').with
20
+ name: "MyApp"
21
+
22
+ # The Application uses a Backbone.Model as a state machine, which
23
+ # allows you to get / set attributes, persist them somewhere, and
24
+ # most importantly to bind to change events of certain attributes.
25
+ #
26
+ # the @defaultState property will be the default attributes
27
+ defaultState: {}
2
28
 
3
- # automatically starts the @router
4
- # if it exists, once the components
5
- # for the application have been created
6
- autoStartHistory: true
29
+ # if autoBoot is set to true, the application will
30
+ # attempt to boot on document ready.
31
+ autoBoot: false
32
+
33
+ # automatically starts the @router if it exists,
34
+ # once the components for the application have
35
+ # been created. Pass the event name you want to
36
+ # listen for on this component before you start history
37
+ autoStartHistory: "before:render"
7
38
 
8
39
  # we will create a collection manager singleton
9
- # by default unless otherwise specified
40
+ # by default unless otherwise specified.
10
41
  useCollectionManager: true
11
42
 
43
+ # to pass options to the collection manager, set the @collectionManager
44
+ # hash which will get passed once the collection manager is created
45
+ collectionManager: {}
46
+
47
+ # by default we will use the standard collection manager which ships with
48
+ # Luca. If you would like to use your own extension of the collection manager
49
+ # just pass a reference to the class you would like to use.
12
50
  collectionManagerClass: "Luca.CollectionManager"
13
51
 
14
52
  # Luca plugin apps are apps which mount onto existing
@@ -22,7 +60,30 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
22
60
  # with several 'pages' so to speak
23
61
  useController: true
24
62
 
25
- #### Nested Components
63
+ # Key Handler
64
+ #
65
+ # One responsibility of the application, since it is a viewport which monopolizes the entire screen
66
+ # is to relay keypress events from the document, to whatever views are interested in responding to them.
67
+ #
68
+ # This functionality is disabled by default.
69
+ useKeyHandler: false
70
+
71
+ # You can configure key events by specifying them by their name, as it exists in Luca.keyMap. For example:
72
+ #
73
+ keyEvents: {}
74
+
75
+ # keyEvents
76
+ # keyup: keyUpHandler
77
+ # enter: enterHandler
78
+ # meta:
79
+ # up: metaUpHandler
80
+ # control:
81
+ # forwardslash: controlSlashHandler
82
+ # keyup: controlUpHandler
83
+ # control_meta:
84
+ # keydown: metaControlKeyDownHandler
85
+ #
86
+ #
26
87
 
27
88
  # applications have one component, the controller.
28
89
  # any components defined on the application class directly
@@ -36,31 +97,36 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
36
97
  ]
37
98
 
38
99
  initialize: (@options={})->
39
- Luca.containers.Viewport::initialize.apply @, arguments
40
-
41
- if @useController is true
42
- definedComponents = @components || []
100
+ app = @
101
+ appName = @name
102
+ alreadyRunning = Luca.getApplication?()
43
103
 
44
- @components = [
45
- ctype: 'controller'
46
- name: "main_controller"
47
- components: definedComponents
48
- ]
104
+ Luca.Application.instances ||= {}
105
+ Luca.Application.instances[ appName ] = app
106
+
107
+ Luca.containers.Viewport::initialize.apply @, arguments
49
108
 
50
- if @useCollectionManager is true
51
- @collectionManagerClass = Luca.util.resolve( @collectionManagerClass ) if _.isString( @collectionManagerClass )
109
+ @state = new Luca.Model( @defaultState )
52
110
 
53
- @collectionManager ||= Luca.CollectionManager.get?()
54
- @collectionManager ||= new @collectionManagerClass( @collectionManagerOptions||={} )
111
+ # The Controller is the piece of the application that handles showing
112
+ # and hiding 'pages' of the app. The Application has a navigate_to
113
+ # method which delegates to the controller, and allows you to navigate
114
+ # to a given page, or component, by its name. The controller integrates
115
+ # with the state machine of the application
116
+ @setupMainController()
55
117
 
56
- @state = new Luca.Model( @defaultState )
118
+ # The Collection Manager is responsible
119
+ @setupCollectionManager()
57
120
 
58
121
  # we will render when all of the various components
59
122
  # which handle our data dependencies determine that
60
123
  # we are ready
61
- @defer(()=>@render()).until("ready")
124
+ @defer(()-> app.render()).until(@, "ready")
125
+
126
+ # Set up the Backbone Router
127
+ @setupRouter()
62
128
 
63
- # the keyRouter allows us to specify
129
+ # the keyHandler allows us to specify
64
130
  # keyEvents on our application with an API very similar
65
131
  # to the DOM events API for Backbone.View
66
132
  #
@@ -69,52 +135,51 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
69
135
  # keyEvents:
70
136
  # meta:
71
137
  # forwardslash: "altSlashHandler"
72
- @setupKeyRouter() if @useKeyRouter is true and @keyEvents?
138
+ if @useKeyRouter is true
139
+ console.log "The useKeyRouter property is being deprecated. switch to useKeyHandler instead"
140
+
141
+ @setupKeyHandler() if (@useKeyHandler is true or @useKeyRouter is true) and @keyEvents?
73
142
 
74
143
  # if the application is a plugin designed to modify the behavior
75
144
  # of another app, then don't claim ownership. otherwise the most common
76
145
  # use-case is that there will be one application instance
77
- unless @plugin is true
78
- Luca.getApplication = ()=> @
146
+ unless @plugin is true or alreadyRunning
147
+ Luca.getApplication = (name)=>
148
+ return app unless name?
149
+ Luca.Application.instances[ name ]
150
+
151
+ if @autoBoot
152
+ if Luca.util.resolve(@name)
153
+ throw "Attempting to override window.#{ @name } when it already exists"
79
154
 
155
+ $ ->
156
+ window[ appName ] = app
157
+ app.boot()
158
+
159
+ # @activeView() returns a reference to the instance of the view
160
+ # which is currently monopolizing the viewport.
161
+ #
162
+ # this will be whicever component is active on the controllers
163
+ # nested within the main controller, if there are any, or the view
164
+ # itself which is active on the main controller.
80
165
  activeView: ()->
81
166
  if active = @activeSubSection()
82
167
  @view( active )
83
168
  else
84
169
  @view( @activeSection() )
85
170
 
86
- activeSubSection: ()->
87
- @get("active_sub_section")
88
-
171
+ # Returns the name of the active component on the main controller
89
172
  activeSection: ()->
90
173
  @get("active_section")
91
174
 
92
- beforeRender: ()->
93
- Luca.containers.Viewport::beforeRender?.apply(@, arguments)
94
-
95
- if @router? and @autoStartHistory is true
96
- routerStartEvent = @startRouterOn || "after:render"
97
-
98
- if routerStartEvent is "before:render"
99
- Backbone.history.start()
100
- else
101
- @bind routerStartEvent, ()-> Backbone.history.start()
102
-
103
- afterComponents: ()->
104
- Luca.containers.Viewport::afterComponents?.apply @, arguments
105
-
106
- # any time the main controller card switches we should track
107
- # the active card on the global state chart
108
- @getMainController()?.bind "after:card:switch", (previous,current)=>
109
- @state.set(active_section:current.name)
110
-
111
- # any time the card switches on one of the sub controllers
112
- # then we should track the active sub section on the global state chart
113
- @getMainController()?.each (component)=>
114
- if component.ctype.match(/controller$/)
115
- component.bind "after:card:switch", (previous,current)=>
116
- @state.set(active_sub_section:current.name)
175
+ # Returns the name of the active component on the nested controllers
176
+ # on the main controller, if there is one. These get set on the
177
+ # state machine in response to card switch events on the controller component
178
+ activeSubSection: ()->
179
+ @get("active_sub_section")
117
180
 
181
+ activePages: ()->
182
+ @$('.luca-ui-controller').map (index,element)=> $(element).data('active-section')
118
183
 
119
184
  # boot should trigger the ready event, which will call the initial call
120
185
  # to render() your application, which will have a cascading effect on every
@@ -135,12 +200,8 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
135
200
  get: (attribute)->
136
201
  @state.get(attribute)
137
202
 
138
- getMainController: ()->
139
- return @components[0] if @useController is true
140
- Luca.cache('main_controller')
141
-
142
- set: (attributes)->
143
- @state.set(attributes)
203
+ set: (attribute, value, options)->
204
+ @state.set.apply(@state, arguments)
144
205
 
145
206
  view: (name)->
146
207
  Luca.cache(name)
@@ -151,23 +212,12 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
151
212
  navigate_to: (component_name, callback)->
152
213
  @getMainController().navigate_to(component_name, callback)
153
214
 
154
- setupKeyRouter: ()->
155
- return unless @keyEvents
156
-
157
- @keyEvents.control_meta ||= {}
158
-
159
- # allow for both meta_control, control_meta for the combo
160
- _.extend(@keyEvents.control_meta, @keyEvents.meta_control) if @keyEvents.meta_control
161
-
162
- router = _.bind(@keyRouter, @)
163
-
164
- $( document ).keydown( router )
215
+ getMainController: ()->
216
+ return @components[0] if @useController is true
217
+ Luca.cache('main_controller')
165
218
 
166
- #### Key Router
167
- #
168
- # TODO: Define a syntax for mapping combinations of meta, control, and keycodes
169
- # to some sort of method delegation system that the application handles.
170
- keyRouter: (e)->
219
+ #
220
+ keyHandler: (e)->
171
221
  return unless e and @keyEvents
172
222
 
173
223
  isInputEvent = $(e.target).is('input') || $(e.target).is('textarea')
@@ -187,7 +237,82 @@ _.def('Luca.Application').extends('Luca.containers.Viewport').with
187
237
  source = if meta and control then @keyEvents.meta_control else source
188
238
 
189
239
  if keyEvent = source?[keyname]
190
- if @[keyEvent]?
240
+ if @[keyEvent]? and _.isFunction(@[keyEvent])
191
241
  @[keyEvent]?.call(@)
192
242
  else
193
- @trigger(keyEvent)
243
+ @trigger(keyEvent, e, keyname)
244
+
245
+ setupControllerBindings: ()->
246
+ app = @
247
+ # any time the main controller card switches we should track
248
+ # the active card on the global state chart
249
+ @getMainController()?.bind "after:card:switch", (previous,current)=>
250
+ @state.set(active_section:current.name)
251
+ app.trigger "page:change"
252
+
253
+ # any time the card switches on one of the sub controllers
254
+ # then we should track the active sub section on the global state chart
255
+ @getMainController()?.each (component)=>
256
+ if component.ctype.match(/controller$/)
257
+ component.bind "after:card:switch", (previous,current)=>
258
+ @state.set(active_sub_section:current.name)
259
+ app.trigger "sub:page:change"
260
+
261
+ setupMainController: ()->
262
+ if @useController is true
263
+ definedComponents = @components || []
264
+
265
+ @components = [
266
+ ctype: 'controller'
267
+ name: "main_controller"
268
+ components: definedComponents
269
+ ]
270
+
271
+ @defer( @setupControllerBindings, false ).until("after:components")
272
+
273
+ setupCollectionManager: ()->
274
+ if @useCollectionManager is true
275
+ @collectionManagerClass = Luca.util.resolve( @collectionManagerClass ) if _.isString( @collectionManagerClass )
276
+
277
+ collectionManagerOptions = @collectionManagerOptions
278
+
279
+ if _.isObject(@collectionManager) and not _.isFunction( @collectionManager?.get )
280
+ collectionManagerOptions = @collectionManager
281
+ @collectionManager = undefined
282
+
283
+ if _.isString(@collectionManager)
284
+ collectionManagerOptions =
285
+ name: @collectionManager
286
+
287
+ @collectionManager = Luca.CollectionManager.get?( collectionManagerOptions.name )
288
+
289
+ unless _.isFunction(@collectionManager?.get)
290
+ @collectionManager = new @collectionManagerClass( collectionManagerOptions )
291
+
292
+ setupRouter: ()->
293
+ app = @
294
+
295
+ if _.isString( @router )
296
+ routerClass = Luca.util.resolve(@router)
297
+ @router = new routerClass({app})
298
+
299
+ # if this application has a router associated with it
300
+ # then we need to start backbone history on a certain event.
301
+ # you can control which by setting the @startHistoryOn property
302
+ if @router and @autoStartHistory
303
+ @autoStartHistory = "before:render" if @autoStartHistory is true
304
+ @defer(startHistory, false).until(@, @autoStartHistory)
305
+
306
+ setupKeyHandler: ()->
307
+ return unless @keyEvents
308
+
309
+ @keyEvents.control_meta ||= {}
310
+
311
+ # allow for both meta_control, control_meta for the combo
312
+ _.extend(@keyEvents.control_meta, @keyEvents.meta_control) if @keyEvents.meta_control
313
+
314
+ handler = _.bind(@keyHandler, @)
315
+
316
+ for keyEvent in (@keypressEvents || ["keydown"])
317
+ $( document ).on( keyEvent, handler )
318
+
@@ -1,6 +1,6 @@
1
1
  _.def('Luca.components.Toolbar').extends('Luca.core.Container').with
2
2
 
3
- className: 'luca-ui-toolbar'
3
+ className: 'luca-ui-toolbar toolbar'
4
4
 
5
5
  position: 'bottom'
6
6
 
@@ -1,4 +1,12 @@
1
- make = Luca.View::make
1
+ # Public: The CollectionView renders a collection of models into a list of items.
2
+ #
3
+ # Examples
4
+ #
5
+ # _.def('App.ListView').extends('Luca.components.CollectionView').with
6
+ # collection: new App.SampleCollection()
7
+ # itemTemplate: "list_view_item"
8
+ # loadMask: true
9
+ #
2
10
 
3
11
  _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
4
12
  tagName: "div"
@@ -17,6 +25,10 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
17
25
 
18
26
  itemClassName: 'collection-item'
19
27
 
28
+ hooks:[
29
+ "empty:results"
30
+ ]
31
+
20
32
  initialize: (@options={})->
21
33
  _.extend(@, @options)
22
34
 
@@ -31,12 +43,23 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
31
43
  Luca.components.Panel::initialize.apply(@, arguments)
32
44
 
33
45
  if _.isString(@collection) and Luca.CollectionManager.get()
34
- @collection = Luca.CollectionManager.get().get(@collection)
46
+ @collection = Luca.CollectionManager.get().getOrCreate(@collection)
35
47
 
36
48
  if Luca.isBackboneCollection(@collection)
37
- @collection.bind "reset", @refresh
49
+ @collection.on "before:fetch", ()=>
50
+ @trigger "enable:loadmask" if @loadMask is true
51
+
52
+ @collection.bind "reset", ()=>
53
+ @trigger "disable:loadmask" if @loadMask is true
54
+ @refresh()
55
+
38
56
  @collection.bind "add", @refresh
39
57
  @collection.bind "remove", @refresh
58
+ else
59
+ throw "Collection Views must have a valid backbone collection"
60
+
61
+ if @collection.length > 0
62
+ @refresh()
40
63
 
41
64
  attributesForItem: (item)->
42
65
  _.extend {}, class: @itemClassName, "data-index": item.index
@@ -46,7 +69,7 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
46
69
  content = templateFn.call(@, item)
47
70
 
48
71
  if @itemRenderer? and _.isFunction( @itemRenderer )
49
- content = @itemRenderer.call(@, item)
72
+ content = @itemRenderer.call(@, item, item.model, item.index)
50
73
 
51
74
  if @itemProperty
52
75
  content = item.model.get(@itemProperty) || item.model[ @itemProperty ]
@@ -56,7 +79,6 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
56
79
 
57
80
  makeItem: (model, index)->
58
81
  item = if @prepareItem? then @prepareItem.call(@, model, index) else (model:model, index: index)
59
-
60
82
  make(@itemTagName, @attributesForItem(item), @contentForItem(item))
61
83
 
62
84
  getModels: ()->
@@ -66,12 +88,13 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
66
88
  @collection.models
67
89
 
68
90
  refresh: ()->
69
- panel = @
70
-
71
91
  @$bodyEl().empty()
72
92
 
73
- _( @getModels() ).each (model, index)->
74
- panel.$append( panel.makeItem(model, index) )
93
+ if @getModels().length is 0
94
+ @trigger("empty:results")
95
+
96
+ _( @getModels() ).each (model, index)=>
97
+ @$append( @makeItem(model, index) )
75
98
 
76
99
  registerEvent: (domEvent, selector, handler)->
77
100
  if !handler? and _.isFunction(selector)
@@ -83,4 +106,9 @@ _.def("Luca.components.CollectionView").extends("Luca.components.Panel").with
83
106
 
84
107
  render: ()->
85
108
  @refresh()
86
- @$attach() if @$el.parent().length > 0 and @container?
109
+ @$attach() if @$el.parent().length > 0 and @container?
110
+ @
111
+
112
+ # Private Helpers
113
+
114
+ make = Luca.View::make
@@ -1,4 +1,9 @@
1
1
  _.def('Luca.components.Controller').extends('Luca.containers.CardView').with
2
+
3
+ additionalClassNames:['luca-ui-controller']
4
+
5
+ activeAttribute: "active-section"
6
+
2
7
  initialize: (@options)->
3
8
  Luca.containers.CardView::initialize.apply @, arguments
4
9
 
@@ -6,13 +11,31 @@ _.def('Luca.components.Controller').extends('Luca.containers.CardView').with
6
11
 
7
12
  throw "Controllers must specify a defaultCard property and/or the first component must have a name" unless @defaultCard
8
13
 
9
- @state = new Backbone.Model
14
+ @state = new Backbone.Model
10
15
  active_section: @defaultCard
11
16
 
12
17
  each: (fn)->
13
18
  _( @components ).each (component)=>
14
19
  fn.apply @, [component]
15
20
 
21
+ activeSection: ()->
22
+ @get("activeSection")
23
+
24
+ controllers:(deep=false)->
25
+ @select 'ctype', 'controller', deep
26
+
27
+ availableSections: ()->
28
+ base = {}
29
+ base[ @name ] = @sectionNames()
30
+
31
+ _( @controllers() ).reduce (memo,controller)=>
32
+ memo[ controller.name ] = controller.sectionNames()
33
+ memo
34
+ , base
35
+
36
+ sectionNames: (deep=false)->
37
+ @pluck('name')
38
+
16
39
  default: (callback)->
17
40
  @navigate_to(@defaultCard, callback)
18
41
 
@@ -3,23 +3,20 @@ _.def('Luca.fields.CheckboxField').extends('Luca.core.Field').with
3
3
  events:
4
4
  "change input" : "change_handler"
5
5
 
6
- change_handler: (e)->
7
- me = my = $(e.currentTarget)
6
+ className: 'luca-ui-checkbox-field luca-ui-field'
7
+ template: 'fields/checkbox_field'
8
+ hooks: ["checked","unchecked"]
9
+ send_blanks: true
8
10
 
9
- @trigger "on:change", @, e
11
+ change_handler: (e)->
12
+ me = my = $(e.target)
10
13
 
11
- if me.checked is true
14
+ if me.is(":checked")
12
15
  @trigger "checked"
13
16
  else
14
17
  @trigger "unchecked"
15
18
 
16
- className: 'luca-ui-checkbox-field luca-ui-field'
17
-
18
- template: 'fields/checkbox_field'
19
-
20
- hooks: ["checked","unchecked"]
21
-
22
- send_blanks: true
19
+ @trigger "on:change", @, e, me.is(":checked")
23
20
 
24
21
  initialize: (@options={})->
25
22
  _.extend @, @options
@@ -37,4 +34,4 @@ _.def('Luca.fields.CheckboxField').extends('Luca.core.Field').with
37
34
  @input.attr('checked', checked)
38
35
 
39
36
  getValue:()->
40
- @input.attr('checked') is true
37
+ @input.is(":checked")
@@ -0,0 +1,14 @@
1
+ _.def("Luca.components.LabelField").extends("Luca.core.Field").with
2
+ className: "luca-ui-field luca-ui-label-field"
3
+
4
+ getValue: ()->
5
+ @$('input').attr('value')
6
+
7
+ formatter: (value)->
8
+ value ||= @getValue()
9
+ _.str.titleize( value )
10
+
11
+ setValue: (value)->
12
+ @trigger("change", value, @getValue())
13
+ @$('input').attr('value', value)
14
+ @$('.value').html( @formatter(value) )
@@ -50,13 +50,13 @@ _.def('Luca.fields.SelectField').extends('Luca.core.Field').with
50
50
  parseData: ()->
51
51
  @collection.data = _( @collection.data ).map (record)=>
52
52
  return record if not _.isArray( record )
53
+
53
54
  hash = {}
54
55
  hash[ @valueField ] = record[0]
55
- hash[ @displayField ] = record[1]
56
+ hash[ @displayField ] = record[1] || record[0]
56
57
 
57
58
  hash
58
59
 
59
-
60
60
  afterRender: ()->
61
61
  @input = $('select', @el)
62
62
 
@@ -1,4 +1,3 @@
1
- change_handler = (e)-> @trigger "on:change", @, e
2
1
 
3
2
  _.def('Luca.fields.TextField').extends('Luca.core.Field').with
4
3
  events:
@@ -12,8 +11,11 @@ _.def('Luca.fields.TextField').extends('Luca.core.Field').with
12
11
 
13
12
  send_blanks: true
14
13
 
14
+ keyEventThrottle: 300
15
+
15
16
  initialize: (@options={})->
16
- Luca.core.Field::initialize.apply @, arguments
17
+ if @enableKeyEvents
18
+ @registerEvent("keyup input","keyup_handler")
17
19
 
18
20
  @input_id ||= _.uniqueId('field')
19
21
  @input_name ||= @name
@@ -28,13 +30,16 @@ _.def('Luca.fields.TextField').extends('Luca.core.Field').with
28
30
  @$el.addClass('input-append')
29
31
  @addOn = @append
30
32
 
31
- @registerEvent("keydown input","keydown_handler") if @enableKeyEvents
33
+ Luca.core.Field::initialize.apply @, arguments
34
+
35
+ keyup_handler: (e)->
36
+ @trigger "on:keyup", @, e
32
37
 
33
38
  blur_handler: (e)->
34
- me = my = $( e.currentTarget )
39
+ @trigger "on:blur", @, e
35
40
 
36
41
  focus_handler: (e)->
37
- me = my = $( e.currentTarget )
42
+ @trigger "on:focus", @, e
38
43
 
39
- change_handler: change_handler
40
- keydown_handler: _.throttle ((e)-> change_handler.apply @, arguments), 300
44
+ change_handler: (e)->
45
+ @trigger "on:change", @, e
@@ -2,6 +2,7 @@ _.def('Luca.fields.TypeAheadField').extends('Luca.fields.TextField').with
2
2
  className: 'luca-ui-field'
3
3
 
4
4
  getSource: ()->
5
+ return @source.call(@) if _.isFunction(@source)
5
6
  @source || []
6
7
 
7
8
  matcher: (item)->