luca 0.9.65 → 0.9.76
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|