luca 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/CHANGELOG +37 -14
  2. data/lib/luca/rails/version.rb +1 -1
  3. data/spec/components/collection_view_spec.coffee +24 -2
  4. data/spec/components/pagination_control_spec.coffee +0 -0
  5. data/spec/concerns/dom_helpers_spec.coffee +16 -0
  6. data/spec/concerns/filterable_spec.coffee +25 -0
  7. data/spec/concerns/model_presenter_spec.coffee +31 -0
  8. data/spec/concerns/paginatable_spec.coffee +0 -0
  9. data/spec/concerns/state_model_spec.coffee +0 -0
  10. data/spec/concerns_spec.coffee +88 -0
  11. data/spec/core/container_spec.coffee +74 -12
  12. data/spec/core/model_spec.coffee +6 -1
  13. data/spec/define_spec.coffee +0 -6
  14. data/spec/util_spec.coffee +24 -0
  15. data/src/components/application.coffee +32 -30
  16. data/src/components/base_toolbar.coffee +6 -4
  17. data/src/components/collection_loader_view.coffee +3 -1
  18. data/src/components/collection_view.coffee +42 -21
  19. data/src/components/controller.coffee +3 -1
  20. data/src/components/fields/button_field.coffee +19 -12
  21. data/src/components/fields/checkbox_array.coffee +8 -2
  22. data/src/components/fields/checkbox_field.coffee +18 -9
  23. data/src/components/fields/file_upload_field.coffee +5 -1
  24. data/src/components/fields/hidden_field.coffee +3 -1
  25. data/src/components/fields/label_field.coffee +4 -3
  26. data/src/components/fields/select_field.coffee +7 -8
  27. data/src/components/fields/text_field.coffee +3 -1
  28. data/src/components/fields/type_ahead_field.coffee +4 -2
  29. data/src/components/form_button_toolbar.coffee +4 -1
  30. data/src/components/form_view.coffee +49 -44
  31. data/src/components/grid_view.coffee +1 -1
  32. data/src/components/multi_collection_view.coffee +49 -22
  33. data/src/components/pagination_control.coffee +17 -13
  34. data/src/{modules → concerns}/application_event_bindings.coffee +1 -1
  35. data/src/{modules → concerns}/collection_event_bindings.coffee +1 -1
  36. data/src/{modules → concerns}/deferrable.coffee +1 -1
  37. data/src/{modules → concerns}/dom_helpers.coffee +11 -2
  38. data/src/{modules → concerns}/enhanced_properties.coffee +1 -1
  39. data/src/concerns/filterable.coffee +82 -0
  40. data/src/{modules → concerns}/grid_layout.coffee +1 -1
  41. data/src/{modules → concerns}/loadmaskable.coffee +1 -1
  42. data/src/{modules → concerns}/local_storage.coffee +0 -0
  43. data/src/{modules → concerns}/modal_view.coffee +1 -1
  44. data/src/concerns/model_presenter.coffee +23 -0
  45. data/src/concerns/paginatable.coffee +87 -0
  46. data/src/{modules → concerns}/state_model.coffee +1 -1
  47. data/src/{modules → concerns}/templating.coffee +1 -1
  48. data/src/concerns.coffee +70 -0
  49. data/src/containers/tab_view.coffee +7 -10
  50. data/src/core/collection.coffee +17 -1
  51. data/src/core/container.coffee +56 -31
  52. data/src/core/field.coffee +39 -38
  53. data/src/core/meta_data.coffee +37 -0
  54. data/src/core/model.coffee +18 -1
  55. data/src/core/view.coffee +25 -29
  56. data/src/define.coffee +54 -66
  57. data/src/framework.coffee +23 -18
  58. data/src/index.coffee +3 -1
  59. data/src/stylesheets/components/checkbox_array.scss +1 -1
  60. data/src/stylesheets/components/form_view.scss +5 -5
  61. data/src/stylesheets/components/viewport.scss +2 -1
  62. data/src/stylesheets/containers/container.scss +0 -5
  63. data/src/stylesheets/containers/tab_view.scss +5 -5
  64. data/src/tools/console.coffee +5 -5
  65. data/src/util.coffee +47 -0
  66. data/vendor/assets/javascripts/luca-ui-development-tools.js +5 -5
  67. data/vendor/assets/javascripts/luca-ui-development-tools.min.js +1 -1
  68. data/vendor/assets/javascripts/luca-ui-full.js +905 -416
  69. data/vendor/assets/javascripts/luca-ui-full.min.js +5 -5
  70. data/vendor/assets/javascripts/luca-ui.js +905 -416
  71. data/vendor/assets/javascripts/luca-ui.min.js +5 -4
  72. data/vendor/assets/stylesheets/luca-ui.css +15 -15
  73. metadata +27 -17
  74. data/spec/mixin_spec.coffee +0 -49
  75. data/src/modules/filterable.coffee +0 -60
  76. data/src/modules/paginatable.coffee +0 -79
@@ -0,0 +1,70 @@
1
+ Luca.concern = (mixinName)->
2
+ namespace = _( Luca.concern.namespaces ).detect (space)->
3
+ Luca.util.resolve(space)?[ mixinName ]?
4
+
5
+ namespace ||= "Luca.concerns"
6
+
7
+ resolved = Luca.util.resolve(namespace)[ mixinName ]
8
+
9
+ console.log "Could not find #{ mixinName } in ", Luca.concern.namespaces unless resolved?
10
+
11
+ resolved
12
+
13
+ Luca.concern.namespaces = [
14
+ "Luca.concerns"
15
+ ]
16
+
17
+ Luca.concern.namespace = (namespace)->
18
+ Luca.concern.namespaces.push(namespace)
19
+ Luca.concern.namespaces = _( Luca.concern.namespaces ).uniq()
20
+
21
+ Luca.concern.setup = ()->
22
+ if @concerns?.length > 0
23
+ for module in @concerns
24
+ Luca.concern(module)?.__initializer?.call(@, @, module)
25
+
26
+ # Luca.decorate('Luca.View').with('Luca.concerns.MyCustomMixin')
27
+ Luca.decorate = (target)->
28
+ try
29
+ if _.isString(target)
30
+ componentName = target
31
+ componentClass = Luca.util.resolve(componentName)
32
+
33
+ componentClass = target if _.isFunction(target)
34
+ componentPrototype = componentClass.prototype
35
+ componentName = componentName || componentClass.displayName
36
+ componentName ||= componentPrototype.displayName
37
+ catch e
38
+ console.log e.message
39
+ console.log e.stack
40
+ console.log "Error calling Luca.decorate on ", componentClass, componentPrototype, componentName
41
+
42
+ throw(e)
43
+
44
+ return with: (mixinName)->
45
+ mixinDefinition = Luca.concern(mixinName)
46
+ mixinDefinition.__displayName ||= mixinName
47
+
48
+ mixinPrivates = _( mixinDefinition ).chain().keys().select (key)->
49
+ "#{ key }".match(/^__/) or key is "classMethods"
50
+
51
+ sanitized = _( mixinDefinition ).omit( mixinPrivates.value() )
52
+
53
+ _.extend(componentPrototype, sanitized)
54
+
55
+ if mixinDefinition.classMethods?
56
+ for method, fn of mixinDefinition.classMethods
57
+ componentClass[ method ] = _.bind(fn, componentClass)
58
+
59
+ # When a mixin is included, we may want to do things
60
+ mixinDefinition?.__included?(componentName, componentClass, mixinDefinition)
61
+
62
+ superclassMixins = componentPrototype._superClass()::concerns
63
+
64
+ componentPrototype.concerns ||= []
65
+ componentPrototype.concerns.push( mixinName )
66
+ componentPrototype.concerns = componentPrototype.concerns.concat( superclassMixins )
67
+
68
+ componentPrototype.concerns = _( componentPrototype.concerns ).chain().uniq().compact().value()
69
+
70
+ componentPrototype
@@ -1,23 +1,20 @@
1
1
  _.def('Luca.containers.TabView').extends('Luca.containers.CardView').with
2
2
 
3
- hooks:[
4
- "before:select"
5
- "after:select"
6
- ]
7
-
8
- componentType: 'tab_view'
9
-
10
- className: 'luca-ui-tab-view tabbable'
3
+ tabView = Luca.register "Luca.containers.TabView"
4
+ tabView.triggers "before:select",
5
+ "after:select"
11
6
 
7
+ tabView.publicConfiguration
12
8
  tab_position: 'top'
13
-
14
9
  tabVerticalOffset: '50px'
15
10
 
11
+ tabView.privateConfiguration
12
+ additionalClassNames: 'tabbable'
16
13
  navClass: "nav-tabs"
17
-
18
14
  bodyTemplate: "containers/tab_view"
19
15
  bodyEl: "div.tab-content"
20
16
 
17
+ tabView.defines
21
18
  initialize: (@options={})->
22
19
  @navClass = "nav-list"if @navStyle is "list"
23
20
 
@@ -91,6 +91,8 @@ collection.defines
91
91
  if models
92
92
  @reset models, silent: true, parse: options?.parse
93
93
 
94
+ Luca.concern.setup.call(@)
95
+
94
96
  @trigger "after:initialize"
95
97
 
96
98
  # Luca.Collections will append a query string to the URL
@@ -211,7 +213,7 @@ collection.defines
211
213
  # fetch will try to pull from the bootstrap if it is setup to do so
212
214
  # you can actually make the roundtrip to the server anyway if you pass
213
215
  # refresh = true in the options hash
214
- return @bootstrap() if @cached_models().length and not options.refresh
216
+ return @bootstrap() if @cached_models().length and not (options.refresh is true or options.remote is true)
215
217
 
216
218
  url = if _.isFunction(@url) then @url() else @url
217
219
 
@@ -350,6 +352,20 @@ _.extend Luca.Collection.prototype,
350
352
 
351
353
  Backbone.View.prototype.trigger.apply @, arguments
352
354
 
355
+ Luca.Collection._originalExtend = Backbone.Collection.extend
356
+
357
+ Luca.Collection.extend = (definition={})->
358
+ # for backward compatibility
359
+ definition.concerns ||= definition.concerns if definition.concerns?
360
+
361
+ componentClass = Luca.Collection._originalExtend.call(@, definition)
362
+
363
+ if definition.concerns? and _.isArray( definition.concerns )
364
+ for module in definition.concerns
365
+ Luca.decorate( componentClass ).with( module )
366
+
367
+ componentClass
368
+
353
369
  # Always include these parameters in every request to your REST API.
354
370
  #
355
371
  # either specify a function which returns a hash, or just a normal hash
@@ -9,7 +9,7 @@ container.triggers "before:components",
9
9
  "after:layout",
10
10
  "first:activation"
11
11
 
12
- container.defines
12
+ container.defines
13
13
  className: 'luca-ui-container'
14
14
 
15
15
  componentTag: 'div'
@@ -25,7 +25,7 @@ container.defines
25
25
  # @componentEvents provides declarative syntax for responding to events on
26
26
  # the components in this container. the format of the syntax is very similar
27
27
  # to the other event binding helpers:
28
- #
28
+ #
29
29
  # component_accessor component:trigger
30
30
  #
31
31
  # where component_accessor is either the name of the role, or a method on the container
@@ -115,6 +115,8 @@ container.defines
115
115
  applyDOMConfig.call(container, component, index)
116
116
 
117
117
  prepareComponents: ()->
118
+ container = @
119
+
118
120
  # accept components as an array of strings representing
119
121
  # the luca component type
120
122
  for component in @components when _.isString(component)
@@ -130,6 +132,26 @@ container.defines
130
132
  panel = @make(@componentTag, componentContainerElement, '')
131
133
  @$append( panel )
132
134
 
135
+ # if the container defines a @defaults property
136
+ # then we should make sure our child components inherit
137
+ # these values unless specifically defined
138
+ if container.defaults?
139
+ component = _.defaults(component, (container.defaults || {}))
140
+
141
+ # if the container defines an @extensions property as an array of
142
+ # configuration objects, then we will extend the component config with
143
+ # the object in the matching position of the @extensions array.
144
+ if _.isArray(container.extensions) and _.isObject(container.extensions?[ index ])
145
+ componentExtension = container.extensions[index]
146
+ component = _.extend(component, componentExtension)
147
+
148
+ # if the container defines an @extensions property as an object of nested hashes,
149
+ # then extensions is a key/value pair whose key represents the role of the component
150
+ # that we wish to extend / customize
151
+ if component.role? and _.isObject(container.extensions) and _.isObject(container.extensions[component.role])
152
+ componentExtension = container.extensions[component.role]
153
+ component = _.extend(component, componentExtension)
154
+
133
155
  unless component.container?
134
156
  component.container = "##{ componentContainerElement.id }" if @generateComponentElements
135
157
  component.container ||= @$bodyEl()
@@ -157,30 +179,31 @@ container.defines
157
179
  # adding the views @$el to the appropriate @container.
158
180
 
159
181
  # you can also just pass a string representing the component_type
160
- component = if Luca.isBackboneView( object )
182
+ component = if Luca.isComponent( object )
161
183
  object
162
184
  else
163
185
  object.type ||= object.ctype
164
186
 
165
187
  if !object.type?
188
+ # TODO
189
+ # Add support for all of the various components property aliases
166
190
  if object.components?
167
191
  object.type = object.ctype = 'container'
168
192
  else
169
193
  object.type = object.ctype = Luca.defaultComponentType
170
194
 
171
- # if the container defines a @defaults property
172
- # then we should make sure our child components inherit
173
- # these values unless specifically defined
174
- object = _.defaults(object, (container.defaults || {}))
175
-
176
195
  created = Luca.util.lazyComponent( object )
177
196
 
178
197
  # if we're using base backbone views, then they don't extend themselves
179
198
  # with their passed options, so this is a workaround to get them to
180
199
  # pick up the container config property
181
- if !component.container and component.options.container
200
+ if !component.container and component.options?.container
182
201
  component.container = component.options.container
183
202
 
203
+ if not component.container?
204
+ console.log component,index,@
205
+ console.error "could not assign container property to component on container #{ @name || @cid }"
206
+
184
207
  indexComponent( component ).at(index).in( @componentIndex )
185
208
 
186
209
  component
@@ -194,14 +217,14 @@ container.defines
194
217
  renderComponents: (@debugMode="")->
195
218
  @debug "container render components"
196
219
 
197
- container = @
220
+ container = @
198
221
  _(@components).each (component)->
199
- component.getParent = ()->
200
- container
222
+ component.getParent = ()->
223
+ container
201
224
 
202
225
  try
203
- $( component.container ).append( component.el )
204
- component.render()
226
+ @$( component.container ).eq(0).append( component.el )
227
+ component.render()
205
228
  catch e
206
229
  console.log "Error Rendering Component #{ component.name || component.cid }", component
207
230
 
@@ -232,7 +255,7 @@ container.defines
232
255
  #### Underscore Methods For Working with Components
233
256
  _: ()-> _( @components )
234
257
 
235
- pluck: (attribute)->
258
+ pluck: (attribute)->
236
259
  @_().pluck(attribute)
237
260
 
238
261
  invoke: (method)->
@@ -243,17 +266,17 @@ container.defines
243
266
 
244
267
  detect: (fn)->
245
268
  @_().detect(attribute)
246
-
269
+
247
270
  reject: (fn)->
248
271
  @_().reject(fn)
249
272
 
250
273
  map: (fn)->
251
274
  @_().map(fn)
252
275
 
253
- registerComponentEvents: ()->
276
+ registerComponentEvents: (eventList)->
254
277
  container = @
255
278
 
256
- for listener, handler of (@componentEvents||{})
279
+ for listener, handler of (eventList || @componentEvents||{})
257
280
  [componentNameOrRole,eventId] = listener.split(' ')
258
281
 
259
282
  unless _.isFunction( @[handler] )
@@ -262,7 +285,7 @@ container.defines
262
285
 
263
286
  if componentNameOrRole is "*"
264
287
  @eachComponent (component)=> component.on(eventId, @[handler], container)
265
- else
288
+ else
266
289
  component = @findComponentForEventBinding( componentNameOrRole )
267
290
 
268
291
  unless component? and Luca.isComponent(component)
@@ -273,18 +296,18 @@ container.defines
273
296
 
274
297
 
275
298
  subContainers: ()->
276
- @select (component)->
299
+ @select (component)->
277
300
  component.isContainer is true
278
301
 
279
302
  roles: ()->
280
303
  _( @allChildren() ).pluck('role')
281
-
304
+
282
305
  allChildren: ()->
283
306
  children = @components
284
307
  grandchildren = _( @subContainers() ).invoke('allChildren')
285
- @_allChildren ||= _([children,grandchildren]).chain().compact().flatten().uniq().value()
308
+ _([children,grandchildren]).chain().compact().flatten().value()
286
309
 
287
- findComponentForEventBinding: (nameRoleOrGetter, deep=false)->
310
+ findComponentForEventBinding: (nameRoleOrGetter, deep=true)->
288
311
  @findComponentByName(nameRoleOrGetter, deep) || @findComponentByGetter( nameRoleOrGetter, deep ) || @findComponentByRole( nameRoleOrGetter, deep )
289
312
 
290
313
  findComponentByGetter: (getter, deep=false)->
@@ -293,7 +316,7 @@ container.defines
293
316
 
294
317
  findComponentByRole: (role,deep=false)->
295
318
  _( @allChildren() ).detect (component)->
296
- component.role is role
319
+ component.role is role or component.type is role or component.ctype is role
297
320
 
298
321
  findComponentByName: (name, deep=false)->
299
322
  _( @allChildren() ).detect (component)->
@@ -311,7 +334,7 @@ container.defines
311
334
  return component if component
312
335
 
313
336
  if deep is true
314
- sub_container = _( @components ).detect (component)->
337
+ sub_container = _( @components ).detect (component)->
315
338
  component?.findComponent?(needle, haystack, true)
316
339
 
317
340
  sub_container?.findComponent?(needle, haystack, true)
@@ -346,7 +369,7 @@ container.defines
346
369
 
347
370
  getRootComponent: ()->
348
371
  if @isRootComponent() then @ else @getParent().getRootComponent()
349
-
372
+
350
373
 
351
374
  selectByAttribute: (attribute, value=undefined, deep=false)->
352
375
  components = _( @components ).map (component)->
@@ -365,7 +388,7 @@ container.defines
365
388
 
366
389
  # This is the method by which a container injects the rendered child views
367
390
  # into the DOM. It will get passed the container object, and the component
368
- # that is being rendered.
391
+ # that is being rendered.
369
392
  Luca.core.Container.componentRenderer = (container, component)->
370
393
  attachMethod = $( component.container )[ component.attachWith || "append" ]
371
394
  attachMethod( component.render().el )
@@ -406,7 +429,6 @@ createGetterMethods = ()->
406
429
 
407
430
  _( childrenWithGetter ).each (component)->
408
431
  container[ component.getter ] ||= ()->
409
- console.log "getter is being deprecated in favor of role"
410
432
  console.log component.getter, component, container
411
433
  component
412
434
 
@@ -428,8 +450,11 @@ doComponents = ()->
428
450
  @trigger "before:render:components", @, @components
429
451
  @renderComponents()
430
452
  @trigger "after:components", @, @components
431
- createGetterMethods.call(@)
432
- createMethodsToGetComponentsByRole.call(@)
453
+
454
+ unless @skipGetterMethods is true
455
+ createGetterMethods.call(@)
456
+ createMethodsToGetComponentsByRole.call(@)
457
+
433
458
  @registerComponentEvents()
434
459
 
435
460
  validateContainerConfiguration = ()->
@@ -447,4 +472,4 @@ indexComponent = (component)->
447
472
  if component.role?
448
473
  map.role_index[ component.role ] = index
449
474
  if component.name?
450
- map.name_index[ component.name ] = index
475
+ map.name_index[ component.name ] = index
@@ -1,26 +1,51 @@
1
- _.def('Luca.core.Field').extends('Luca.View').with
1
+ field = Luca.register "Luca.core.Field"
2
2
 
3
- className: 'luca-ui-text-field luca-ui-field'
4
-
5
- isField: true
3
+ field.extends "Luca.View"
6
4
 
7
- template: 'fields/text_field'
5
+ field.triggers "before:validation",
6
+ "after:validation",
7
+ "on:change"
8
8
 
9
+ field.publicConfiguration
9
10
  labelAlign: 'top'
10
-
11
- hooks:[
12
- "before:validation",
13
- "after:validation",
14
- "on:change"
15
- ]
16
-
17
- # see: http://twitter.github.com/bootstrap/base-css.html
11
+ className: 'luca-ui-text-field luca-ui-field'
18
12
  statuses: [
19
13
  "warning"
20
14
  "error"
21
15
  "success"
22
16
  ]
23
17
 
18
+ field.publicInterface
19
+ disable: ()->
20
+ @getInputElement().attr('disabled', true)
21
+
22
+ enable: ()->
23
+ @getInputElement().attr('disabled', false)
24
+
25
+ getValue: ()->
26
+ raw = @getInputElement()?.attr('value')
27
+
28
+ return raw if _.str.isBlank( raw )
29
+
30
+ switch @valueType
31
+ when "integer" then parseInt(raw)
32
+ when "string" then "#{ raw }"
33
+ when "float" then parseFloat(raw)
34
+ else raw
35
+
36
+ setValue: (value)->
37
+ @getInputElement()?.attr('value', value)
38
+
39
+ updateState: (state)->
40
+ _( @statuses ).each (cls)=>
41
+ @$el.removeClass(cls)
42
+ @$el.addClass(state)
43
+
44
+ field.privateConfiguration
45
+ isField: true
46
+ template: 'fields/text_field'
47
+
48
+ field.defines
24
49
  initialize: (@options={})->
25
50
  _.extend @, @options
26
51
 
@@ -29,6 +54,7 @@ _.def('Luca.core.Field').extends('Luca.View').with
29
54
  @input_class ||= ""
30
55
  @input_type ||= ""
31
56
  @helperText ||= ""
57
+ @label = @name if not @label? or @label.length is 0
32
58
  @label ||= "*#{ @label }" if @required and not @label?.match(/^\*/)
33
59
  @inputStyles ||= ""
34
60
  @input_value ||= @value || ""
@@ -53,30 +79,5 @@ _.def('Luca.core.Field').extends('Luca.View').with
53
79
  change_handler: (e)->
54
80
  @trigger "on:change", @, e
55
81
 
56
- disable: ()->
57
- @getInputElement().attr('disabled', true)
58
-
59
- enable: ()->
60
- @getInputElement().attr('disabled', false)
61
-
62
- getValue: ()->
63
- raw = @getInputElement()?.attr('value')
64
-
65
- return raw if _.str.isBlank( raw )
66
-
67
- switch @valueType
68
- when "integer" then parseInt(raw)
69
- when "string" then "#{ raw }"
70
- when "float" then parseFloat(raw)
71
- else raw
72
-
73
- setValue: (value)->
74
- @getInputElement()?.attr('value', value)
75
-
76
82
  getInputElement: ()->
77
83
  @input ||= @$('input').eq(0)
78
-
79
- updateState: (state)->
80
- _( @statuses ).each (cls)=>
81
- @$el.removeClass(cls)
82
- @$el.addClass(state)
@@ -0,0 +1,37 @@
1
+ Luca.registry.componentMetaData = {}
2
+
3
+ Luca.registry.getMetaDataFor = (componentName)->
4
+ new MetaDataProxy(Luca.registry.componentMetaData[ componentName ])
5
+
6
+ Luca.registry.addMetaData = (componentName, key, value)->
7
+ data = Luca.registry.componentMetaData[ componentName ] ||= {}
8
+ data[ key ] = _(value).clone()
9
+ data
10
+
11
+
12
+ class MetaDataProxy
13
+ constructor: (@meta={})->
14
+ @
15
+
16
+ superClass: ()->
17
+ Luca.util.resolve(@meta["super class name"])
18
+
19
+ componentDefinition: ()->
20
+ Luca.util.resolve(@meta["display name"])
21
+
22
+ styleHierarchy: ()->
23
+ list = _( @classHierarchy() ).map (cls)->
24
+ Luca.util.toCssClass(cls, 'views', 'components', 'core','fields','containers')
25
+
26
+ _( list ).without('backbone-view','luca-view')
27
+
28
+ classHierarchy: ()->
29
+ list = [ @meta["display name"], @meta["super class name"]]
30
+
31
+ proxy = @superClass()?.prototype?.componentMetaData?()
32
+
33
+ until not proxy
34
+ list = list.concat( proxy?.classHierarchy() )
35
+ proxy = proxy.superClass()?.prototype?.componentMetaData?()
36
+
37
+ _( list ).uniq()
@@ -8,12 +8,13 @@ model.defines
8
8
  initialize: ()->
9
9
  Backbone.Model::initialize(@, arguments)
10
10
  setupComputedProperties.call(@)
11
+ Luca.concern.setup.call(@)
11
12
 
12
13
  read: (attr)->
13
14
  if _.isFunction(@[attr])
14
15
  @[attr].call(@)
15
16
  else
16
- @get(attr)
17
+ @get(attr) || @[attr]
17
18
 
18
19
  get: (attr)->
19
20
  if @computed?.hasOwnProperty(attr)
@@ -37,3 +38,19 @@ setupComputedProperties = ()->
37
38
  @trigger "change:#{attr}"
38
39
 
39
40
  @trigger "change:#{attr}" if @has(dep)
41
+
42
+
43
+ Luca.Model._originalExtend = Backbone.Model.extend
44
+
45
+ Luca.Model.extend = (definition={})->
46
+ # for backward compatibility
47
+ definition.concerns ||= definition.concerns if definition.concerns?
48
+
49
+ componentClass = Luca.Model._originalExtend.call(@, definition)
50
+
51
+ if definition.concerns? and _.isArray( definition.concerns )
52
+ for module in definition.concerns
53
+ Luca.decorate( componentClass ).with( module )
54
+
55
+ componentClass
56
+
data/src/core/view.coffee CHANGED
@@ -4,9 +4,9 @@ view.extends "Backbone.View"
4
4
 
5
5
  # includes are extensions to the prototype, and have no special behavior
6
6
  view.includes "Luca.Events",
7
- "Luca.modules.DomHelpers"
7
+ "Luca.concerns.DomHelpers"
8
8
 
9
- # mixins are includes with special property / method conventions
9
+ # concerns are includes with special property / method conventions
10
10
  # which customize the components through the use of __initializer and
11
11
  # __included method names. These will be called every time an instance
12
12
  # is created, and the first time the mixin is used to enhance a component.
@@ -48,12 +48,10 @@ view.defines
48
48
 
49
49
  @setupHooks _( Luca.View::hooks.concat( @hooks ) ).uniq()
50
50
 
51
- if @mixins?.length > 0
52
- for module in @mixins
53
- Luca.mixin(module)?.__initializer?.call(@, @, module)
51
+ Luca.concern.setup.call(@)
54
52
 
55
53
  @delegateEvents()
56
-
54
+
57
55
  @trigger "after:initialize", @
58
56
 
59
57
  #### Hooks or Auto Event Binding
@@ -69,18 +67,7 @@ view.defines
69
67
  # after:render : afterRender()
70
68
  # after:initialize : afterInitialize()
71
69
  # first:activation : firstActivation()
72
- setupHooks: (set)->
73
- set ||= @hooks
74
-
75
- _(set).each (eventId)=>
76
- fn = Luca.util.hook( eventId )
77
-
78
- callback = ()->
79
- @[fn]?.apply @, arguments
80
-
81
- callback = _.once(callback) if eventId?.match(/once:/)
82
-
83
- @on eventId, callback, @
70
+ setupHooks: Luca.util.setupHooks
84
71
 
85
72
  registerEvent: (selector, handler)->
86
73
  @events ||= {}
@@ -90,13 +77,18 @@ view.defines
90
77
  definitionClass: ()->
91
78
  Luca.util.resolve(@displayName, window)?.prototype
92
79
 
93
- collections: ()-> Luca.util.selectProperties( Luca.isBackboneCollection, @ )
94
- models: ()-> Luca.util.selectProperties( Luca.isBackboneModel, @ )
95
- views: ()-> Luca.util.selectProperties( Luca.isBackboneView, @ )
80
+ collections: ()->
81
+ Luca.util.selectProperties( Luca.isBackboneCollection, @ )
96
82
 
97
- debug: ()->
83
+ models: ()->
84
+ Luca.util.selectProperties( Luca.isBackboneModel, @ )
85
+
86
+ views: ()->
87
+ Luca.util.selectProperties( Luca.isBackboneView, @ )
88
+
89
+ debug: (args...)->
98
90
  return unless @debugMode or window.LucaDebugMode?
99
- console.log [(@name || @cid),message] for message in arguments
91
+ console.log [(@name || @cid), args...]
100
92
 
101
93
  trigger: ()->
102
94
  if Luca.enableGlobalObserver
@@ -163,14 +155,18 @@ bindEventHandlers = (events={})->
163
155
  if _.isString(handler)
164
156
  _.bindAll @, handler
165
157
 
166
- Luca.View.extend = (definition)->
158
+ Luca.View.deferrableEvent = "reset"
159
+
160
+ Luca.View.extend = (definition={})->
167
161
  definition = Luca.View.renderWrapper( definition )
162
+ # for backward compatibility
163
+ definition.concerns ||= definition.concerns if definition.concerns?
168
164
 
169
- if definition.mixins? and _.isArray( definition.mixins )
170
- for module in definition.mixins
171
- Luca.decorate( definition ).with( module )
165
+ componentClass = Luca.View._originalExtend.call(@, definition)
172
166
 
173
- Luca.View._originalExtend.call(@, definition)
167
+ if definition.concerns? and _.isArray( definition.concerns )
168
+ for module in definition.concerns
169
+ Luca.decorate( componentClass ).with( module )
174
170
 
171
+ componentClass
175
172
 
176
- Luca.View.deferrableEvent = "reset"