luca 0.9.6 → 0.9.7

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 (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"