luca 0.9.65 → 0.9.76

Sign up to get free protection for your applications and to get access to all the features.
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)