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.
- data/CHANGELOG +30 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +27 -0
- data/lib/luca/rails/version.rb +1 -1
- data/spec/components/controller_spec.coffee +58 -0
- data/spec/components/form_view_spec.coffee +4 -0
- data/spec/concerns/dom_helpers_spec.coffee +16 -0
- data/spec/{modules → concerns}/filterable_spec.coffee +0 -0
- data/spec/concerns/model_presenter_spec.coffee +31 -0
- data/spec/{modules → concerns}/paginatable_spec.coffee +0 -0
- data/spec/{modules → concerns}/state_model_spec.coffee +0 -0
- data/spec/concerns_spec.coffee +88 -0
- data/spec/core/container_spec.coffee +103 -6
- data/spec/core/field_spec.coffee +4 -0
- data/spec/core/model_spec.coffee +6 -1
- data/spec/define_spec.coffee +104 -7
- data/spec/framework_spec.coffee +30 -1
- data/spec/util_spec.coffee +24 -0
- data/src/components/application.coffee +62 -25
- data/src/components/base_toolbar.coffee +6 -4
- data/src/components/collection_loader_view.coffee +3 -1
- data/src/components/collection_view.coffee +36 -73
- data/src/components/controller.coffee +73 -35
- data/src/components/fields/button_field.coffee +20 -12
- data/src/components/fields/checkbox_array.coffee +8 -2
- data/src/components/fields/checkbox_field.coffee +18 -9
- data/src/components/fields/file_upload_field.coffee +5 -1
- data/src/components/fields/hidden_field.coffee +3 -1
- data/src/components/fields/label_field.coffee +4 -3
- data/src/components/fields/select_field.coffee +7 -8
- data/src/components/fields/text_area_field.coffee +3 -2
- data/src/components/fields/text_field.coffee +5 -4
- data/src/components/fields/type_ahead_field.coffee +4 -2
- data/src/components/form_button_toolbar.coffee +4 -1
- data/src/components/form_view.coffee +26 -24
- data/src/components/grid_view.coffee +3 -3
- data/src/components/multi_collection_view.coffee +6 -35
- data/src/components/pagination_control.coffee +1 -3
- data/src/components/router.coffee +2 -0
- data/src/components/table_view.coffee +7 -0
- data/src/concerns.coffee +70 -0
- data/src/{modules → concerns}/application_event_bindings.coffee +1 -1
- data/src/{modules → concerns}/collection_event_bindings.coffee +1 -1
- data/src/{modules → concerns}/deferrable.coffee +1 -1
- data/src/{modules → concerns}/dom_helpers.coffee +11 -2
- data/src/{modules → concerns}/enhanced_properties.coffee +1 -1
- data/src/{modules → concerns}/filterable.coffee +11 -11
- data/src/{modules → concerns}/grid_layout.coffee +1 -1
- data/src/{modules → concerns}/loadmaskable.coffee +1 -1
- data/src/{modules → concerns}/local_storage.coffee +0 -0
- data/src/{modules → concerns}/modal_view.coffee +1 -1
- data/src/concerns/model_presenter.coffee +23 -0
- data/src/{modules → concerns}/paginatable.coffee +9 -3
- data/src/concerns/query_collection_bindings.coffee +44 -0
- data/src/{modules → concerns}/state_model.coffee +1 -1
- data/src/{modules → concerns}/templating.coffee +1 -1
- data/src/containers/card_view.coffee +16 -9
- data/src/containers/tab_view.coffee +8 -11
- data/src/containers/viewport.coffee +3 -3
- data/src/core/collection.coffee +39 -28
- data/src/core/container.coffee +37 -15
- data/src/core/field.coffee +40 -39
- data/src/core/meta_data.coffee +93 -0
- data/src/core/model.coffee +18 -1
- data/src/core/registry.coffee +4 -3
- data/src/core/view.coffee +24 -30
- data/src/define.coffee +165 -79
- data/src/framework.coffee +97 -21
- data/src/index.coffee +4 -2
- data/src/managers/collection_manager.coffee +7 -3
- data/src/stylesheets/components/checkbox_array.scss +1 -1
- data/src/stylesheets/components/form_view.scss +5 -5
- data/src/stylesheets/components/viewport.scss +2 -1
- data/src/stylesheets/containers/container.scss +0 -5
- data/src/stylesheets/containers/tab_view.scss +5 -5
- data/src/templates/fields/text_area_field.jst.ejs +1 -1
- data/src/templates/fields/text_field.jst.ejs +1 -1
- data/src/util.coffee +47 -0
- data/vendor/assets/javascripts/luca-ui-full.js +1279 -494
- data/vendor/assets/javascripts/luca-ui-full.min.js +5 -5
- data/vendor/assets/javascripts/luca-ui-templates.js +2 -2
- data/vendor/assets/javascripts/luca-ui.js +1279 -494
- data/vendor/assets/javascripts/luca-ui.min.js +5 -4
- data/vendor/assets/stylesheets/luca-ui.css +15 -15
- metadata +27 -20
- 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.
|
60
|
+
_.extend @, Luca.concerns.Deferrable
|
61
61
|
|
62
|
-
@loadMask = Luca.
|
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.
|
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.
|
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.
|
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.
|
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
|
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 ()=>
|
data/src/concerns.coffee
ADDED
@@ -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.
|
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.
|
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 (()=>
|
28
|
-
@optionsSources.push (()=>
|
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
|
-
|
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: ()->
|
File without changes
|
@@ -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.
|
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
|
-
|
39
|
-
|
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
|
+
|