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.
Files changed (86) hide show
  1. data/CHANGELOG +30 -0
  2. data/Gemfile +1 -0
  3. data/Gemfile.lock +27 -0
  4. data/lib/luca/rails/version.rb +1 -1
  5. data/spec/components/controller_spec.coffee +58 -0
  6. data/spec/components/form_view_spec.coffee +4 -0
  7. data/spec/concerns/dom_helpers_spec.coffee +16 -0
  8. data/spec/{modules → concerns}/filterable_spec.coffee +0 -0
  9. data/spec/concerns/model_presenter_spec.coffee +31 -0
  10. data/spec/{modules → concerns}/paginatable_spec.coffee +0 -0
  11. data/spec/{modules → concerns}/state_model_spec.coffee +0 -0
  12. data/spec/concerns_spec.coffee +88 -0
  13. data/spec/core/container_spec.coffee +103 -6
  14. data/spec/core/field_spec.coffee +4 -0
  15. data/spec/core/model_spec.coffee +6 -1
  16. data/spec/define_spec.coffee +104 -7
  17. data/spec/framework_spec.coffee +30 -1
  18. data/spec/util_spec.coffee +24 -0
  19. data/src/components/application.coffee +62 -25
  20. data/src/components/base_toolbar.coffee +6 -4
  21. data/src/components/collection_loader_view.coffee +3 -1
  22. data/src/components/collection_view.coffee +36 -73
  23. data/src/components/controller.coffee +73 -35
  24. data/src/components/fields/button_field.coffee +20 -12
  25. data/src/components/fields/checkbox_array.coffee +8 -2
  26. data/src/components/fields/checkbox_field.coffee +18 -9
  27. data/src/components/fields/file_upload_field.coffee +5 -1
  28. data/src/components/fields/hidden_field.coffee +3 -1
  29. data/src/components/fields/label_field.coffee +4 -3
  30. data/src/components/fields/select_field.coffee +7 -8
  31. data/src/components/fields/text_area_field.coffee +3 -2
  32. data/src/components/fields/text_field.coffee +5 -4
  33. data/src/components/fields/type_ahead_field.coffee +4 -2
  34. data/src/components/form_button_toolbar.coffee +4 -1
  35. data/src/components/form_view.coffee +26 -24
  36. data/src/components/grid_view.coffee +3 -3
  37. data/src/components/multi_collection_view.coffee +6 -35
  38. data/src/components/pagination_control.coffee +1 -3
  39. data/src/components/router.coffee +2 -0
  40. data/src/components/table_view.coffee +7 -0
  41. data/src/concerns.coffee +70 -0
  42. data/src/{modules → concerns}/application_event_bindings.coffee +1 -1
  43. data/src/{modules → concerns}/collection_event_bindings.coffee +1 -1
  44. data/src/{modules → concerns}/deferrable.coffee +1 -1
  45. data/src/{modules → concerns}/dom_helpers.coffee +11 -2
  46. data/src/{modules → concerns}/enhanced_properties.coffee +1 -1
  47. data/src/{modules → concerns}/filterable.coffee +11 -11
  48. data/src/{modules → concerns}/grid_layout.coffee +1 -1
  49. data/src/{modules → concerns}/loadmaskable.coffee +1 -1
  50. data/src/{modules → concerns}/local_storage.coffee +0 -0
  51. data/src/{modules → concerns}/modal_view.coffee +1 -1
  52. data/src/concerns/model_presenter.coffee +23 -0
  53. data/src/{modules → concerns}/paginatable.coffee +9 -3
  54. data/src/concerns/query_collection_bindings.coffee +44 -0
  55. data/src/{modules → concerns}/state_model.coffee +1 -1
  56. data/src/{modules → concerns}/templating.coffee +1 -1
  57. data/src/containers/card_view.coffee +16 -9
  58. data/src/containers/tab_view.coffee +8 -11
  59. data/src/containers/viewport.coffee +3 -3
  60. data/src/core/collection.coffee +39 -28
  61. data/src/core/container.coffee +37 -15
  62. data/src/core/field.coffee +40 -39
  63. data/src/core/meta_data.coffee +93 -0
  64. data/src/core/model.coffee +18 -1
  65. data/src/core/registry.coffee +4 -3
  66. data/src/core/view.coffee +24 -30
  67. data/src/define.coffee +165 -79
  68. data/src/framework.coffee +97 -21
  69. data/src/index.coffee +4 -2
  70. data/src/managers/collection_manager.coffee +7 -3
  71. data/src/stylesheets/components/checkbox_array.scss +1 -1
  72. data/src/stylesheets/components/form_view.scss +5 -5
  73. data/src/stylesheets/components/viewport.scss +2 -1
  74. data/src/stylesheets/containers/container.scss +0 -5
  75. data/src/stylesheets/containers/tab_view.scss +5 -5
  76. data/src/templates/fields/text_area_field.jst.ejs +1 -1
  77. data/src/templates/fields/text_field.jst.ejs +1 -1
  78. data/src/util.coffee +47 -0
  79. data/vendor/assets/javascripts/luca-ui-full.js +1279 -494
  80. data/vendor/assets/javascripts/luca-ui-full.min.js +5 -5
  81. data/vendor/assets/javascripts/luca-ui-templates.js +2 -2
  82. data/vendor/assets/javascripts/luca-ui.js +1279 -494
  83. data/vendor/assets/javascripts/luca-ui.min.js +5 -4
  84. data/vendor/assets/stylesheets/luca-ui.css +15 -15
  85. metadata +27 -20
  86. data/spec/mixin_spec.coffee +0 -49
@@ -57,9 +57,9 @@ _.def('Luca.components.GridView').extend('Luca.components.Panel').with
57
57
 
58
58
  initialize: (@options={})->
59
59
  _.extend @, @options
60
- _.extend @, Luca.modules.Deferrable
60
+ _.extend @, Luca.concerns.Deferrable
61
61
 
62
- @loadMask = Luca.enableBootstrap unless @loadMask?
62
+ @loadMask = Luca.config.enableBoostrap unless @loadMask?
63
63
  @loadMaskEl ||= ".luca-ui-g-view-body" if @loadMask is true
64
64
 
65
65
  Luca.components.Panel::initialize.apply(@, arguments)
@@ -120,7 +120,7 @@ _.def('Luca.components.GridView').extend('Luca.components.Panel').with
120
120
  _( @additionalWrapperClasses ).each (containerClass)=>
121
121
  @wrapper?.addClass( containerClass )
122
122
 
123
- if Luca.enableBootstrap
123
+ if Luca.config.enableBoostrap
124
124
  @table.addClass('table')
125
125
 
126
126
  _( @tableStyle?.split(" ") ).each (style)=>
@@ -1,4 +1,4 @@
1
- multiView = Luca.define "Luca.components.MultiCollectionView"
1
+ multiView = Luca.register "Luca.components.MultiCollectionView"
2
2
 
3
3
  # The CollectionMultiView is a collection view with multiple renderings
4
4
  # of the list. ( e.g. Icons, Table, List ). It works by maintaining
@@ -24,7 +24,8 @@ multiView = Luca.define "Luca.components.MultiCollectionView"
24
24
  # ]
25
25
  multiView.extends "Luca.containers.CardView"
26
26
 
27
- multiView.behavesAs "LoadMaskable",
27
+ multiView.mixesIn "QueryCollectionBindings",
28
+ "LoadMaskable",
28
29
  "Filterable",
29
30
  "Paginatable"
30
31
 
@@ -33,7 +34,7 @@ multiView.triggers "before:refresh",
33
34
  "refresh",
34
35
  "empty:results"
35
36
 
36
- multiView.defaultsTo
37
+ multiView.defines
37
38
  version: 1
38
39
 
39
40
  stateful: true
@@ -48,48 +49,18 @@ multiView.defaultsTo
48
49
 
49
50
  validateComponent( view ) for view in @components
50
51
 
52
+ Luca.containers.CardView::initialize.apply(@, arguments)
53
+
51
54
  @on "refresh", @refresh, @
52
55
  @on "after:card:switch", @refresh, @
53
56
  @on "after:components", propagateCollectionComponents, @
54
57
 
55
- @debug("multi collection , proto initialize")
56
-
57
- Luca.containers.CardView::initialize.apply(@, arguments)
58
-
59
58
  relayAfterRefresh: (models,query,options)->
60
59
  @trigger "after:refresh", models, query, options
61
60
 
62
61
  refresh: ()->
63
62
  @activeComponent()?.trigger("refresh")
64
63
 
65
- getCollection: ()->
66
- @collection
67
-
68
- applyQuery: (query={},queryOptions={})->
69
- @query = query
70
- @queryOptions = queryOptions
71
- @
72
-
73
- # Private: returns the query that is applied to the underlying collection.
74
- # accepts the same options as Luca.Collection.query's initial query option.
75
- getQuery: ()->
76
- @debug("Get Query")
77
- query = @query ||= {}
78
- for querySource in @querySources
79
- query = _.extend(query, (querySource()||{}) )
80
- query
81
-
82
- # Private: returns the query that is applied to the underlying collection.
83
- # accepts the same options as Luca.Collection.query's initial query option.
84
- getQueryOptions: ()->
85
- @debug("Get Query Options")
86
- options = @queryOptions ||= {}
87
-
88
- for optionSource in @optionsSources
89
- options = _.extend(options, (optionSource()||{}) )
90
-
91
- options
92
-
93
64
  propagateCollectionComponents = ()->
94
65
  container = @
95
66
 
@@ -17,7 +17,7 @@ paginationControl.defines
17
17
  afterInitialize: ()->
18
18
  _.bindAll @, "updateWithPageCount"
19
19
 
20
- @state.on "change", (state, numberOfPages)=>
20
+ @state?.on "change", (state, numberOfPages)=>
21
21
  @updateWithPageCount( state.get('numberOfPages') )
22
22
 
23
23
  limit: ()->
@@ -70,8 +70,6 @@ paginationControl.defines
70
70
  updateWithPageCount: (@pageCount, models=[])->
71
71
  modelCount = models.length
72
72
 
73
- console.log "Update With Page Count", @pageCount, modelCount
74
-
75
73
  @pageButtonContainer().empty()
76
74
 
77
75
  _( @pageCount ).times (index)=>
@@ -14,6 +14,8 @@ _.def("Luca.Router").extends("Backbone.Router").with
14
14
  @bind "route:#{ route_id }", ()=>
15
15
  @trigger.apply @, ["change:navigation", route_id ].concat( _( arguments ).flatten() )
16
16
 
17
+ Backbone.Router.initialize?.apply(@, arguments)
18
+
17
19
  #### Router Functions
18
20
 
19
21
  # Intercept calls to Backbone.Router.navigate so that we can at least
@@ -9,6 +9,8 @@ _.def("Luca.components.TableView").extends("Luca.components.CollectionView").wit
9
9
  stateful: true
10
10
  observeChanges: true
11
11
 
12
+ widths: []
13
+
12
14
  columns:[]
13
15
 
14
16
  emptyText: "There are no results to display"
@@ -19,13 +21,18 @@ _.def("Luca.components.TableView").extends("Luca.components.CollectionView").wit
19
21
  initialize: (@options={})->
20
22
  Luca.components.CollectionView::initialize.apply(@, arguments)
21
23
 
24
+ index = 0
22
25
  @columns = for column in @columns
26
+ if width = @widths[ index ]
27
+ column.width = width
28
+
23
29
  if _.isString(column)
24
30
  column = reader: column
25
31
 
26
32
  if !column.header?
27
33
  column.header = _.str.titleize(_.str.humanize(column.reader))
28
34
 
35
+ index++
29
36
  column
30
37
 
31
38
  @defer ()=>
@@ -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,4 +1,4 @@
1
- Luca.modules.ApplicationEventBindings =
1
+ Luca.concerns.ApplicationEventBindings =
2
2
  __initializer: ()->
3
3
  return if _.isEmpty(@applicationEvents)
4
4
 
@@ -1,4 +1,4 @@
1
- Luca.modules.CollectionEventBindings =
1
+ Luca.concerns.CollectionEventBindings =
2
2
  __initializer: ()->
3
3
  return if _.isEmpty( @collectionEvents )
4
4
 
@@ -1,7 +1,7 @@
1
1
  # TODO
2
2
  #
3
3
  # This is horrendous code. I need to replace it ASAP
4
- Luca.modules.Deferrable =
4
+ Luca.concerns.Deferrable =
5
5
  configure_collection: (setAsDeferrable=true)->
6
6
  return unless @collection
7
7
 
@@ -1,4 +1,4 @@
1
- Luca.modules.DomHelpers =
1
+ Luca.concerns.DomHelpers =
2
2
  __initializer: ()->
3
3
  additionalClasses = _( @additionalClassNames || [] ).clone()
4
4
 
@@ -24,12 +24,21 @@ Luca.modules.DomHelpers =
24
24
  for additional in additionalClasses
25
25
  @$el.addClass( additional )
26
26
 
27
+ if Luca.config.autoApplyClassHierarchyAsCssClasses is true
28
+ classes = @componentMetaData?()?.styleHierarchy() || []
29
+
30
+ for cssClass in classes when (cssClass isnt "luca-view" and cssClass isnt "backbone-view")
31
+ @$el.addClass(cssClass)
32
+
27
33
  $wrap: (wrapper)->
28
34
  if _.isString(wrapper) and not wrapper.match(/[<>]/)
29
- wrapper = @make("div",class:wrapper)
35
+ wrapper = @make("div",class:wrapper,"data-wrapper":true)
30
36
 
31
37
  @$el.wrap( wrapper )
32
38
 
39
+ $wrapper: ()->
40
+ @$el.parent('[data-wrapper="true"]')
41
+
33
42
  $template: (template, variables={})->
34
43
  @$el.html( Luca.template(template,variables) )
35
44
 
@@ -1,4 +1,4 @@
1
- Luca.modules.EnhancedProperties =
1
+ Luca.concerns.EnhancedProperties =
2
2
  __initializer: ()->
3
3
  return unless Luca.config.enhancedViewProperties is true
4
4
 
@@ -1,4 +1,4 @@
1
- Luca.modules.Filterable =
1
+ Luca.concerns.Filterable =
2
2
  __included: (component, module)->
3
3
  _.extend(Luca.Collection::, __filters:{})
4
4
 
@@ -24,21 +24,21 @@ Luca.modules.Filterable =
24
24
  @query ||= {}
25
25
  @queryOptions ||= {}
26
26
 
27
- @querySources.push (()=> filter.toQuery())
28
- @optionsSources.push (()=> filter.toOptions())
29
-
30
- if @debugMode is true
31
- console.log "Filterable"
32
- console.log @querySources
33
- console.log @optionsSources
27
+ @querySources.push ((options={})=> @getFilterState().toQuery())
28
+ @optionsSources.push ((options={})=> @getFilterState().toOptions())
34
29
 
35
30
  filter.on "change", ()=>
31
+ filter = _.clone( @getQuery() )
32
+ options = _.clone( @getQueryOptions() )
33
+
34
+ filter.limit = options.limit if options.limit?
35
+ filter.page = options.page if options.page?
36
+ filter.sortBy = options.sortBy if options.sortBy?
37
+
36
38
  if @isRemote()
37
- merged = _.extend(@getQuery(), @getQueryOptions())
38
- @collection.applyFilter(merged, @getQueryOptions())
39
+ @collection.applyFilter(filter, remote: true)
39
40
  else
40
41
  @trigger "refresh"
41
-
42
42
  module
43
43
 
44
44
  isRemote: ()->
@@ -1,4 +1,4 @@
1
- Luca.modules.GridLayout =
1
+ Luca.concerns.GridLayout =
2
2
  _initializer: ()->
3
3
  if @gridSpan
4
4
  @$el.addClass "span#{ @gridSpan }"
@@ -1,4 +1,4 @@
1
- Luca.modules.LoadMaskable =
1
+ Luca.concerns.LoadMaskable =
2
2
  __initializer: ()->
3
3
  return unless @loadMask is true
4
4
 
File without changes
@@ -1,4 +1,4 @@
1
- Luca.modules.ModalView =
1
+ Luca.concerns.ModalView =
2
2
  closeOnEscape: true
3
3
 
4
4
  showOnInitialize: false
@@ -0,0 +1,23 @@
1
+ Luca.concerns.ModelPresenter =
2
+ classMethods:
3
+ getPresenter: (format)->
4
+ @presenters?[format]
5
+
6
+ registerPresenter: (format, config)->
7
+ @presenters ||= {}
8
+ @presenters[ format ] = config
9
+
10
+ presentAs: (format)->
11
+ try
12
+ attributeList = @componentMetaData().componentDefinition().getPresenter(format)
13
+
14
+ return @toJSON() unless attributeList?
15
+
16
+ _( attributeList ).reduce (memo, attribute)=>
17
+ memo[ attribute ] = @read(attribute)
18
+ memo
19
+ , {}
20
+
21
+ catch e
22
+ console.log "Error presentAs", e.stack, e.message
23
+ return @toJSON()
@@ -1,4 +1,4 @@
1
- Luca.modules.Paginatable =
1
+ Luca.concerns.Paginatable =
2
2
  paginatorViewClass: 'Luca.components.PaginationControl'
3
3
  paginationSelector: ".toolbar.bottom"
4
4
 
@@ -35,8 +35,14 @@ Luca.modules.Paginatable =
35
35
  _.extend(options, pager: @pager)
36
36
 
37
37
  paginationState.on "change:page", (state)=>
38
- if @isRemote()
39
- filter = _.extend(@toQuery(), @toQueryOptions())
38
+ filter = _.clone( @getQuery() )
39
+ options = _.clone( @getQueryOptions() )
40
+
41
+ filter.limit = options.limit if options.limit?
42
+ filter.page = options.page if options.page?
43
+ filter.sortBy = options.sortBy if options.sortBy?
44
+
45
+ if @isRemote()
40
46
  @collection.applyFilter(filter, remote: true)
41
47
  else
42
48
  @trigger "refresh"
@@ -0,0 +1,44 @@
1
+ Luca.concerns.QueryCollectionBindings =
2
+ getCollection: ()->
3
+ @collection
4
+
5
+ loadModels: (models=[], options={})->
6
+ @getCollection()?.reset(models, options)
7
+
8
+ applyQuery: (query={},queryOptions={})->
9
+ @query = query
10
+ @queryOptions = queryOptions
11
+ @refresh()
12
+ @
13
+
14
+ # Private: returns the query that is applied to the underlying collection.
15
+ # accepts the same options as Luca.Collection.query's initial query option.
16
+ getQuery: (options={})->
17
+ query = @query ||= {}
18
+
19
+ for querySource in _( @querySources || [] ).compact()
20
+ query = _.extend(query, (querySource(options)||{}) )
21
+
22
+ query
23
+
24
+ # Private: returns the query that is applied to the underlying collection.
25
+ # accepts the same options as Luca.Collection.query's initial query option.
26
+ getQueryOptions: (options={})->
27
+ options = @queryOptions ||= {}
28
+
29
+ for optionSource in _( @optionsSources || [] ).compact()
30
+ options = _.extend(options, (optionSource(options)||{}) )
31
+
32
+ options
33
+
34
+ # Private: returns the models to be rendered. If the underlying collection
35
+ # responds to @query() then it will use that interface.
36
+ getModels: (query,options)->
37
+ if @collection?.query
38
+ query ||= @getQuery()
39
+ options ||= @getQueryOptions()
40
+
41
+ @collection.query(query, options)
42
+ else
43
+ @collection.models
44
+
@@ -1,4 +1,4 @@
1
- Luca.modules.StateModel =
1
+ Luca.concerns.StateModel =
2
2
  __initializer: ()->
3
3
  return unless @stateful is true
4
4
  return if @state? and not Luca.isBackboneModel(@state)