luca 0.9.1 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/ROADMAP +15 -3
- data/Rakefile +33 -7
- data/app.rb +0 -1
- data/assets/javascripts/dependencies.coffee +0 -1
- data/assets/javascripts/sandbox/application.coffee +1 -1
- data/assets/javascripts/sandbox/templates/main.luca +52 -34
- data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +3 -1
- data/assets/stylesheets/bootstrap-responsive.min.css +0 -1
- data/assets/stylesheets/bootstrap.min.css +48 -29
- data/assets/stylesheets/sandbox/sandbox.scss +11 -28
- data/lib/luca/rails/version.rb +1 -1
- data/site/assets/dependencies.js +94 -0
- data/site/assets/glyphicons-halflings-white.png +0 -0
- data/site/assets/glyphicons-halflings.png +0 -0
- data/site/assets/luca-ui-bootstrap.css +1313 -0
- data/site/assets/luca-ui-bootstrap.js +9 -0
- data/site/assets/luca-ui-development-tools.css +224 -0
- data/site/assets/luca-ui-development-tools.js +18561 -0
- data/site/assets/sandbox.css +14 -0
- data/site/assets/sandbox.js +131 -0
- data/site/index.html +20 -0
- data/spec/core/collection_spec.coffee +6 -6
- data/spec/core/view_spec.coffee +1 -0
- data/spec/framework_spec.coffee +7 -0
- data/spec/managers/collection_manager_spec.coffee +2 -1
- data/src/components/application.coffee +8 -4
- data/src/components/collection_view.coffee +8 -2
- data/src/components/fields/checkbox_array.coffee +3 -1
- data/src/components/form_view.coffee +46 -21
- data/src/components/grid_view.coffee +2 -4
- data/src/components/nav_bar.coffee +3 -7
- data/src/containers/tab_view.coffee +15 -2
- data/src/containers/viewport.coffee +13 -4
- data/src/core/collection.coffee +68 -53
- data/src/core/core.coffee +7 -2
- data/src/core/panel.coffee +32 -17
- data/src/core/registry.coffee +11 -3
- data/src/core/util.coffee +17 -1
- data/src/core/view.coffee +6 -5
- data/src/framework.coffee +46 -2
- data/src/managers/collection_manager.coffee +22 -81
- data/src/stylesheets/components/checkbox_array.scss +5 -0
- data/src/templates/components/form_alert +0 -0
- data/src/templates/components/form_alert.luca +3 -0
- data/src/templates/containers/tab_view.luca +1 -1
- data/src/tools/console.coffee +3 -0
- data/vendor/assets/javascripts/luca-ui-base.js +266 -128
- data/vendor/assets/javascripts/luca-ui-development-tools.js +3 -161
- data/vendor/assets/javascripts/luca-ui-development-tools.min.js +15 -0
- data/vendor/assets/javascripts/luca-ui-spec.js +380 -176
- data/vendor/assets/javascripts/luca-ui.js +348 -166
- data/vendor/assets/javascripts/luca-ui.min.js +4 -3
- data/vendor/assets/stylesheets/luca-ui-bootstrap.css +50 -29
- data/vendor/assets/stylesheets/luca-ui-spec.css +2 -0
- data/vendor/assets/stylesheets/luca-ui.css +2 -0
- metadata +16 -4
- data/src/templates/components/form_view.luca +0 -4
- data/src/tools/development_console.coffee +0 -147
data/src/core/collection.coffee
CHANGED
@@ -12,54 +12,13 @@ _.def("Luca.Collection").extends( source ).with
|
|
12
12
|
# @resetEvents are 'add','remove',reset' and 'change'.
|
13
13
|
cachedMethods: []
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
config.args = undefined
|
19
|
-
@[ name ] = config.original
|
20
|
-
|
21
|
-
clearMethodCache: (method)->
|
22
|
-
@_methodCache[method].value = undefined
|
23
|
-
|
24
|
-
clearAllMethodsCache: ()->
|
25
|
-
for name, config of @_methodCache
|
26
|
-
@clearMethodCache(name)
|
27
|
-
|
28
|
-
setupMethodCaching: ()->
|
29
|
-
collection = @
|
30
|
-
membershipEvents = ["reset","add","remove"]
|
31
|
-
cache = @_methodCache = {}
|
32
|
-
|
33
|
-
_( @cachedMethods ).each (method)->
|
34
|
-
# store a reference to the unwrapped version of the method
|
35
|
-
# and a placeholder for the cached value
|
36
|
-
cache[ method ] =
|
37
|
-
name: method
|
38
|
-
original: collection[method]
|
39
|
-
value: undefined
|
40
|
-
|
41
|
-
# wrap the collection method with a basic memoize operation
|
42
|
-
collection[ method ] = ()->
|
43
|
-
cache[method].value ||= cache[method].original.apply collection, arguments
|
44
|
-
|
45
|
-
# bind to events on the collection, which once triggered, will
|
46
|
-
# invalidate the cached value. causing us to have to restore it
|
47
|
-
for membershipEvent in membershipEvents
|
48
|
-
collection.bind membershipEvent, ()->
|
49
|
-
collection.clearAllMethodsCache()
|
50
|
-
|
51
|
-
dependencies = method.split(':')[1]
|
52
|
-
|
53
|
-
if dependencies
|
54
|
-
for dependency in dependencies.split(",")
|
55
|
-
collection.bind "change:#{dependency}", ()->
|
56
|
-
collection.clearMethodCache(method: method)
|
15
|
+
# if filtering a collection should handle via a call to a REST API
|
16
|
+
# and return the filtered results that way, then leave this true
|
17
|
+
remoteFilter: false
|
57
18
|
|
58
19
|
initialize: (models=[], @options)->
|
59
20
|
_.extend @, @options
|
60
|
-
|
61
21
|
@setupMethodCaching()
|
62
|
-
|
63
22
|
@_reset()
|
64
23
|
|
65
24
|
# By specifying a @cache_key property or method, you can instruct
|
@@ -80,6 +39,8 @@ _.def("Luca.Collection").extends( source ).with
|
|
80
39
|
@name ||= @registerAs
|
81
40
|
@manager ||= @registerWith
|
82
41
|
|
42
|
+
@manager = if _.isFunction(@manager) then @manager() else @manager
|
43
|
+
|
83
44
|
# if they specify a
|
84
45
|
if @name and not @manager
|
85
46
|
@manager = Luca.CollectionManager.get()
|
@@ -162,15 +123,11 @@ _.def("Luca.Collection").extends( source ).with
|
|
162
123
|
_.uniq(parts).join("&")
|
163
124
|
|
164
125
|
resetFilter: ()->
|
165
|
-
@base_params = Luca.Collection.baseParams()
|
126
|
+
@base_params = _( Luca.Collection.baseParams() ).clone()
|
166
127
|
@
|
167
128
|
|
168
|
-
# if filtering a collection should handle via a call to a REST API
|
169
|
-
# and return the filtered results that way, then leave this true
|
170
|
-
remoteFilter: true
|
171
|
-
|
172
129
|
applyFilter: (filter={}, options={})->
|
173
|
-
if options.remote? is true
|
130
|
+
if options.remote? is true or @remoteFilter is true
|
174
131
|
@applyParams(filter)
|
175
132
|
@fetch _.extend(options,refresh:true)
|
176
133
|
else
|
@@ -179,9 +136,11 @@ _.def("Luca.Collection").extends( source ).with
|
|
179
136
|
# You can apply params to a collection, so that any upcoming requests
|
180
137
|
# made to the REST API are made with the key values specified
|
181
138
|
applyParams: (params)->
|
182
|
-
@base_params
|
139
|
+
@base_params = _( Luca.Collection.baseParams() ).clone()
|
183
140
|
_.extend @base_params, params
|
184
141
|
|
142
|
+
@
|
143
|
+
|
185
144
|
# If this collection is to be registered with some global collection
|
186
145
|
# tracker such as new Luca.CollectionManager() then we will register
|
187
146
|
# ourselves automatically
|
@@ -286,7 +245,7 @@ _.def("Luca.Collection").extends( source ).with
|
|
286
245
|
if @length > 0 and not @fetching
|
287
246
|
fn.apply scope, [@]
|
288
247
|
|
289
|
-
@bind "reset", (collection)=> fn.
|
248
|
+
@bind "reset", (collection)=> fn.call(scope,collection)
|
290
249
|
|
291
250
|
unless @fetching is true or !options.autoFetch or @length > 0
|
292
251
|
@fetch()
|
@@ -312,6 +271,62 @@ _.def("Luca.Collection").extends( source ).with
|
|
312
271
|
|
313
272
|
models
|
314
273
|
|
274
|
+
# Method Caching
|
275
|
+
#
|
276
|
+
# Method Caching is a way of saving the output of a method on your collection.
|
277
|
+
# And then expiring that value if any changes are detected to the models in
|
278
|
+
# the collection
|
279
|
+
restoreMethodCache: ()->
|
280
|
+
for name, config of @_methodCache
|
281
|
+
if config.original?
|
282
|
+
config.args = undefined
|
283
|
+
@[ name ] = config.original
|
284
|
+
|
285
|
+
clearMethodCache: (method)->
|
286
|
+
@_methodCache[method].value = undefined
|
287
|
+
|
288
|
+
clearAllMethodsCache: ()->
|
289
|
+
for name, config of @_methodCache
|
290
|
+
@clearMethodCache(name)
|
291
|
+
|
292
|
+
setupMethodCaching: ()->
|
293
|
+
collection = @
|
294
|
+
membershipEvents = ["reset","add","remove"]
|
295
|
+
cache = @_methodCache = {}
|
296
|
+
|
297
|
+
_( @cachedMethods ).each (method)->
|
298
|
+
# store a reference to the unwrapped version of the method
|
299
|
+
# and a placeholder for the cached value
|
300
|
+
cache[ method ] =
|
301
|
+
name: method
|
302
|
+
original: collection[method]
|
303
|
+
value: undefined
|
304
|
+
|
305
|
+
# wrap the collection method with a basic memoize operation
|
306
|
+
collection[ method ] = ()->
|
307
|
+
cache[method].value ||= cache[method].original.apply collection, arguments
|
308
|
+
|
309
|
+
# bind to events on the collection, which once triggered, will
|
310
|
+
# invalidate the cached value. causing us to have to restore it
|
311
|
+
for membershipEvent in membershipEvents
|
312
|
+
collection.bind membershipEvent, ()->
|
313
|
+
collection.clearAllMethodsCache()
|
314
|
+
|
315
|
+
dependencies = method.split(':')[1]
|
316
|
+
|
317
|
+
if dependencies
|
318
|
+
for dependency in dependencies.split(",")
|
319
|
+
collection.bind "change:#{dependency}", ()->
|
320
|
+
collection.clearMethodCache(method: method)
|
321
|
+
|
322
|
+
# make sure the querying interface from backbone.query is present
|
323
|
+
# in the case backbone-query isn't loaded. without it, it will
|
324
|
+
# just return the models
|
325
|
+
query: (filter={},options={})->
|
326
|
+
if Backbone.QueryCollection?
|
327
|
+
return Backbone.QueryCollection::query.apply(@, arguments)
|
328
|
+
else
|
329
|
+
@models
|
315
330
|
|
316
331
|
# Global Collection Observer
|
317
332
|
_.extend Luca.Collection.prototype,
|
@@ -329,7 +344,7 @@ Luca.Collection.baseParams = (obj)->
|
|
329
344
|
return Luca.Collection._baseParams = obj if obj
|
330
345
|
|
331
346
|
if _.isFunction( Luca.Collection._baseParams )
|
332
|
-
return Luca.Collection._baseParams
|
347
|
+
return Luca.Collection._baseParams()
|
333
348
|
|
334
349
|
if _.isObject( Luca.Collection._baseParams )
|
335
350
|
Luca.Collection._baseParams
|
data/src/core/core.coffee
CHANGED
@@ -59,8 +59,13 @@ class DefineProxy
|
|
59
59
|
|
60
60
|
at[@componentId] = Luca.extend(@superClassName,@componentName, properties)
|
61
61
|
|
62
|
-
|
63
|
-
|
62
|
+
if Luca.autoRegister is true
|
63
|
+
componentType = "view" if Luca.isViewPrototype( at[@componentId] )
|
64
|
+
componentType = "collection" if Luca.isCollectionPrototype( at[@componentId] )
|
65
|
+
componentType = "model" if Luca.isModelPrototype( at[@componentId] )
|
66
|
+
|
67
|
+
# automatically register this with the component registry
|
68
|
+
Luca.register( _.string.underscored(@componentId), @componentName, componentType)
|
64
69
|
|
65
70
|
at[@componentId]
|
66
71
|
|
data/src/core/panel.coffee
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# This is a helper for creating the DOM element that go along with
|
2
2
|
# a given component, if it is configured to use one via the topToolbar
|
3
3
|
# and bottomToolbar properties
|
4
|
-
attachToolbar = (config={})->
|
4
|
+
attachToolbar = (config={}, targetEl)->
|
5
5
|
config.orientation ||= "top"
|
6
6
|
config.ctype ||= @toolbarType || "panel_toolbar"
|
7
7
|
|
@@ -25,7 +25,7 @@ attachToolbar = (config={})->
|
|
25
25
|
when "bottom", "right"
|
26
26
|
if hasBody then "after" else "append"
|
27
27
|
|
28
|
-
@$bodyEl()[action]( container )
|
28
|
+
(targetEl || @$bodyEl() )[action]( container )
|
29
29
|
|
30
30
|
# A Panel is a basic Luca.View but with Toolbar extensions
|
31
31
|
#
|
@@ -42,10 +42,13 @@ _.def("Luca.components.Panel").extends("Luca.View").with
|
|
42
42
|
# hidden upon successful response
|
43
43
|
loadMask: false
|
44
44
|
loadMaskTemplate: ["components/load_mask"]
|
45
|
+
loadMaskTimeout: 3000
|
45
46
|
|
46
47
|
initialize: (@options={})->
|
47
48
|
Luca.View::initialize.apply(@, arguments)
|
48
49
|
|
50
|
+
_.bindAll @, "applyLoadMask", "disableLoadMask"
|
51
|
+
|
49
52
|
if @loadMask is true
|
50
53
|
@defer ()=>
|
51
54
|
@$el.addClass('with-mask')
|
@@ -61,22 +64,34 @@ _.def("Luca.components.Panel").extends("Luca.View").with
|
|
61
64
|
loadMaskTarget: ()->
|
62
65
|
if @loadMaskEl? then @$(@loadMaskEl) else @$bodyEl()
|
63
66
|
|
67
|
+
disableLoadMask: ()->
|
68
|
+
@$('.load-mask .bar').css("width","100%")
|
69
|
+
@$('.load-mask').hide()
|
70
|
+
clearInterval(@loadMaskInterval)
|
71
|
+
|
72
|
+
enableLoadMask: ()->
|
73
|
+
@$('.load-mask').show().find('.bar').css("width","0%")
|
74
|
+
maxWidth = @$('.load-mask .progress').width()
|
75
|
+
if maxWidth < 20 and (maxWidth = @$el.width()) < 20
|
76
|
+
maxWidth = @$el.parent().width()
|
77
|
+
|
78
|
+
@loadMaskInterval = setInterval ()=>
|
79
|
+
currentWidth = @$('.load-mask .bar').width()
|
80
|
+
newWidth = currentWidth + 12
|
81
|
+
@$('.load-mask .bar').css('width', newWidth)
|
82
|
+
, 200
|
83
|
+
|
84
|
+
return unless @loadMaskTimeout?
|
85
|
+
|
86
|
+
_.delay ()=>
|
87
|
+
@disableLoadMask()
|
88
|
+
, @loadMaskTimeout
|
89
|
+
|
64
90
|
applyLoadMask: ()->
|
65
91
|
if @$('.load-mask').is(":visible")
|
66
|
-
|
67
|
-
@$('.load-mask').hide()
|
68
|
-
clearInterval(@loadMaskInterval)
|
92
|
+
@disableLoadMask()
|
69
93
|
else
|
70
|
-
|
71
|
-
maxWidth = @$('.load-mask .progress').width()
|
72
|
-
if maxWidth < 20 and (maxWidth = @$el.width()) < 20
|
73
|
-
maxWidth = @$el.parent().width()
|
74
|
-
|
75
|
-
@loadMaskInterval = setInterval ()=>
|
76
|
-
currentWidth = @$('.load-mask .bar').width()
|
77
|
-
newWidth = currentWidth + 12
|
78
|
-
@$('.load-mask .bar').css('width', newWidth)
|
79
|
-
, 200
|
94
|
+
@enableLoadMask()
|
80
95
|
|
81
96
|
applyStyles: (styles={},body=false)->
|
82
97
|
|
@@ -114,7 +129,7 @@ _.def("Luca.components.Panel").extends("Luca.View").with
|
|
114
129
|
$(@el)
|
115
130
|
|
116
131
|
$wrap: (wrapper)->
|
117
|
-
if
|
132
|
+
if _.isString(wrapper) and not wrapper.match(/[<>]/)
|
118
133
|
wrapper = @make("div",class:wrapper)
|
119
134
|
|
120
135
|
@$el.wrap( wrapper )
|
@@ -140,4 +155,4 @@ _.def("Luca.components.Panel").extends("Luca.View").with
|
|
140
155
|
config.parent = @
|
141
156
|
config.orientation = orientation
|
142
157
|
|
143
|
-
attachToolbar.call(@, config)
|
158
|
+
attachToolbar.call(@, config, config.targetEl )
|
data/src/core/registry.coffee
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
registry =
|
2
2
|
classes:{}
|
3
|
+
model_classes: {}
|
4
|
+
collection_classes: {}
|
3
5
|
namespaces:['Luca.containers','Luca.components']
|
4
6
|
|
5
7
|
component_cache =
|
@@ -13,11 +15,17 @@ Luca.defaultComponentType = 'view'
|
|
13
15
|
|
14
16
|
# When you use _.def to define a component, you say
|
15
17
|
# which class it extends() from, and with() which enhancements.
|
16
|
-
|
17
18
|
# We register that component class for you:
|
18
|
-
Luca.register = (component, prototypeName)->
|
19
|
+
Luca.register = (component, prototypeName, componentType="view")->
|
19
20
|
Luca.trigger "component:registered", component, prototypeName
|
20
|
-
|
21
|
+
|
22
|
+
switch componentType
|
23
|
+
when "model"
|
24
|
+
registry.model_classes[ component ] = prototypeName
|
25
|
+
when "collection"
|
26
|
+
registry.model_classes[ component ] = prototypeName
|
27
|
+
else
|
28
|
+
registry.classes[ component ] = prototypeName
|
21
29
|
|
22
30
|
Luca.development_mode_register = (component, prototypeName)->
|
23
31
|
existing = registry.classes[component]
|
data/src/core/util.coffee
CHANGED
@@ -79,4 +79,20 @@ Luca.util.loadScript = (url, callback) ->
|
|
79
79
|
callback()
|
80
80
|
|
81
81
|
script.src = url
|
82
|
-
document.body.appendChild(script)
|
82
|
+
document.body.appendChild(script)
|
83
|
+
|
84
|
+
Luca.util.make = Backbone.View::make
|
85
|
+
|
86
|
+
# generates a badge element
|
87
|
+
# valid types are success, warning, important, info, inverse
|
88
|
+
Luca.util.label = (contents="", type, baseClass="label")->
|
89
|
+
cssClass = baseClass
|
90
|
+
cssClass += " #{ baseClass}-#{ type }" if type?
|
91
|
+
Luca.util.make("span",{class:cssClass},contents)
|
92
|
+
|
93
|
+
# generates a badge element
|
94
|
+
# valid types are success, warning, important, info, inverse
|
95
|
+
Luca.util.badge = (contents="", type, baseClass="badge")->
|
96
|
+
cssClass = baseClass
|
97
|
+
cssClass += " #{ baseClass }-#{ type }" if type?
|
98
|
+
Luca.util.make("span",{class:cssClass},contents)
|
data/src/core/view.coffee
CHANGED
@@ -66,7 +66,7 @@ _.def("Luca.View").extends("Backbone.View").with
|
|
66
66
|
|
67
67
|
#### JQuery / DOM Selector Helpers
|
68
68
|
$wrap: (wrapper)->
|
69
|
-
if
|
69
|
+
if _.isString(wrapper) and not wrapper.match(/[<>]/)
|
70
70
|
wrapper = @make("div",class:wrapper)
|
71
71
|
|
72
72
|
@$el.wrap( wrapper )
|
@@ -130,7 +130,7 @@ _.def("Luca.View").extends("Backbone.View").with
|
|
130
130
|
# if you want to use more than one collection manager, over ride this
|
131
131
|
# function in your views with your own logic
|
132
132
|
getCollectionManager: ()->
|
133
|
-
@collectionManager || Luca.CollectionManager.get
|
133
|
+
@collectionManager || Luca.CollectionManager.get?()
|
134
134
|
|
135
135
|
##### Collection Events
|
136
136
|
#
|
@@ -247,10 +247,11 @@ customizeRender = (definition)->
|
|
247
247
|
target ||= @deferrable
|
248
248
|
trigger = if @deferrable_event then @deferrable_event else "reset"
|
249
249
|
|
250
|
-
|
250
|
+
deferred = ()->
|
251
251
|
_base.call(view)
|
252
|
-
view.trigger
|
253
|
-
|
252
|
+
view.trigger("after:render", view)
|
253
|
+
|
254
|
+
view.defer(deferred).until(target, trigger)
|
254
255
|
|
255
256
|
view.trigger "before:render", @
|
256
257
|
|
data/src/framework.coffee
CHANGED
@@ -15,12 +15,11 @@
|
|
15
15
|
definition = payload.defines
|
16
16
|
inheritsFrom = payload.extends
|
17
17
|
|
18
|
-
|
19
18
|
if _.isFunction( fallback = _(args).last() )
|
20
19
|
return fallback()
|
21
20
|
|
22
21
|
_.extend Luca,
|
23
|
-
VERSION: "0.9.
|
22
|
+
VERSION: "0.9.2"
|
24
23
|
core: {}
|
25
24
|
containers: {}
|
26
25
|
components: {}
|
@@ -32,6 +31,10 @@ _.extend Luca,
|
|
32
31
|
# for triggering / binding to component definitions
|
33
32
|
_.extend Luca, Backbone.Events
|
34
33
|
|
34
|
+
# When using Luca.define() should we automatically register
|
35
|
+
# the component with the registry?
|
36
|
+
Luca.autoRegister = true
|
37
|
+
|
35
38
|
# if developmentMode is true, you have access to some neat development tools
|
36
39
|
Luca.developmentMode = false
|
37
40
|
|
@@ -72,6 +75,9 @@ Luca.supportsEvents = Luca.supportsBackboneEvents = (obj)->
|
|
72
75
|
Luca.isComponent = (obj)->
|
73
76
|
Luca.isBackboneModel(obj) or Luca.isBackboneView(obj) or Luca.isBackboneCollection(obj)
|
74
77
|
|
78
|
+
Luca.isComponentPrototype = (obj)->
|
79
|
+
Luca.isViewPrototype(obj) or Luca.isModelPrototype(obj) or Luca.isCollectionPrototype(obj)
|
80
|
+
|
75
81
|
Luca.isBackboneModel = (obj)->
|
76
82
|
_.isFunction(obj?.set) and _.isFunction(obj?.get) and _.isObject(obj?.attributes)
|
77
83
|
|
@@ -81,6 +87,44 @@ Luca.isBackboneView = (obj)->
|
|
81
87
|
Luca.isBackboneCollection = (obj)->
|
82
88
|
_.isFunction(obj?.fetch) and _.isFunction(obj?.reset)
|
83
89
|
|
90
|
+
Luca.isViewPrototype = (obj)->
|
91
|
+
obj? and obj::? and obj::make? and obj::$? and obj::render?
|
92
|
+
|
93
|
+
Luca.isModelPrototype = (obj)->
|
94
|
+
obj? and obj::? obj::save? and obj::changedAttributes?
|
95
|
+
|
96
|
+
Luca.isCollectionPrototype = (obj)->
|
97
|
+
obj? and obj::? and !Luca.isModelPrototype(obj) and obj::reset? and obj::select? and obj::reject?
|
98
|
+
|
99
|
+
Luca.inheritanceChain = (obj)->
|
100
|
+
_( Luca.parentClasses(obj) ).map (className)-> Luca.util.resolve(className)
|
101
|
+
|
102
|
+
Luca.parentClasses = (obj)->
|
103
|
+
list = []
|
104
|
+
|
105
|
+
if _.isString(obj)
|
106
|
+
obj = Luca.util.resolve(obj)
|
107
|
+
|
108
|
+
list.push( obj.displayName || obj::?.displayName || Luca.parentClass(obj) )
|
109
|
+
|
110
|
+
classes = until not Luca.parentClass(obj)?
|
111
|
+
obj = Luca.parentClass(obj)
|
112
|
+
|
113
|
+
list = list.concat(classes)
|
114
|
+
|
115
|
+
_.uniq list
|
116
|
+
|
117
|
+
Luca.parentClass = (obj)->
|
118
|
+
list = []
|
119
|
+
|
120
|
+
if _.isString( obj )
|
121
|
+
obj = Luca.util.resolve(obj)
|
122
|
+
|
123
|
+
if Luca.isComponent(obj)
|
124
|
+
obj.displayName
|
125
|
+
|
126
|
+
else if Luca.isComponentPrototype(obj)
|
127
|
+
obj::_superClass?()?.displayName
|
84
128
|
|
85
129
|
# This is a convenience method for accessing the templates
|
86
130
|
# available to the client side app, either the ones which ship with Luca
|
@@ -1,57 +1,28 @@
|
|
1
|
-
#### Collection Manager
|
2
|
-
#
|
3
|
-
# The purpose of the collection manager is to provide an interface
|
4
|
-
# for tracking the creation of collections, so that you only create
|
5
|
-
# one instance of a given collection class per instance of some scope
|
6
|
-
#
|
7
|
-
# For example:
|
8
|
-
|
9
|
-
# LucaApp = Luca.containers.Viewport.extend
|
10
|
-
# initialize: (@options={})->
|
11
|
-
# @collectionManager = new Luca.CollectionManager
|
12
|
-
# getScope: ()-> @someParentValue
|
13
|
-
# collection: (key,options={},models=[])->
|
14
|
-
# @collectionManager.getOrCreate(key,options,models)
|
15
|
-
#
|
16
|
-
# Now in the single global instance of LucaApp you have
|
17
|
-
# one central place to access a collection of models, one
|
18
|
-
# interface to listen to for add, remove, reset, change events
|
19
|
-
#
|
20
|
-
# If you don't want this, you can either do it the old fashioned way
|
21
|
-
# or just use the private option to get an unregistered instance.
|
22
|
-
#
|
23
|
-
|
24
|
-
#### View Event Binding Interface
|
25
|
-
#
|
26
|
-
# Luca.Views can specify a @collectionEvents property very similar to
|
27
|
-
# the DOM @events property in Backbone.Views and this provides a very
|
28
|
-
# clean API for binding to events on the collection manager and doing
|
29
|
-
# the necessary things on the view. This does assume that by default
|
30
|
-
# there is only one instance of the collection manager running, otherwise
|
31
|
-
# a configuration directive is provided at a view level to know which
|
32
|
-
# collection manager to pull from.
|
33
|
-
#
|
34
|
-
# Special Thanks to @tjbladez for this wonderful initialModelsa
|
35
|
-
#
|
36
|
-
|
37
|
-
instances = []
|
38
|
-
|
39
|
-
# _.def('Luca.CollectionManager').extends('Luca').with
|
40
1
|
class Luca.CollectionManager
|
2
|
+
name: "primary"
|
3
|
+
|
41
4
|
__collections: {}
|
42
5
|
|
43
6
|
constructor: (@options={})->
|
44
7
|
_.extend @, @options
|
8
|
+
|
9
|
+
manager = @
|
10
|
+
|
11
|
+
if existing = Luca.CollectionManager.get?(@name)
|
12
|
+
throw 'Attempt to create a collection manager with a name which already exists'
|
13
|
+
|
14
|
+
Luca.CollectionManager.instances ||= {}
|
15
|
+
|
45
16
|
_.extend @, Backbone.Events
|
17
|
+
_.extend @, Luca.Events
|
46
18
|
|
47
|
-
|
48
|
-
# manager, then you will have to specify which
|
49
|
-
# collection manager your views need to interact
|
50
|
-
# with for their collectionEvents configuration handling
|
51
|
-
instances.push(@)
|
19
|
+
Luca.CollectionManager.instances[ @name ] = manager
|
52
20
|
|
53
|
-
|
54
|
-
|
21
|
+
Luca.CollectionManager.get = (name)->
|
22
|
+
return manager unless name?
|
23
|
+
Luca.CollectionManager.instances[name]
|
24
|
+
|
25
|
+
@state = new Luca.Model()
|
55
26
|
|
56
27
|
if @initialCollections
|
57
28
|
@state.set({loaded_collections_count: 0, collections_count: @initialCollections.length })
|
@@ -84,42 +55,22 @@ class Luca.CollectionManager
|
|
84
55
|
|
85
56
|
return collection
|
86
57
|
|
87
|
-
#### Collection Prefix
|
88
|
-
#
|
89
|
-
# If you are doing things right, you are namespacing all of your collection
|
90
|
-
# definitions, for example
|
91
|
-
#
|
92
|
-
# LucaApp.collections.SomeCollection = Luca.Collection.extend
|
93
|
-
# registerAs: "some_collection"
|
94
|
-
# registerWith: ""
|
95
|
-
#
|
96
|
-
# You should override this attribute when you create or define your collection manager
|
97
|
-
#
|
98
|
-
#
|
99
|
-
collectionNamespace: Luca.Collection.namespace
|
100
58
|
|
101
|
-
|
59
|
+
collectionNamespace: Luca.Collection.namespace
|
102
60
|
|
103
|
-
|
104
|
-
# value ( @registerAs ) for your collection will be used to retrieve it
|
105
|
-
#
|
106
|
-
# if you plan to have multiple instances per key, but with some sort of
|
107
|
-
# scope based on a parent attribute, you should define a
|
61
|
+
|
108
62
|
currentScope: ()->
|
109
63
|
if current_scope = @getScope()
|
110
64
|
@__collections[ current_scope ] ||= {}
|
111
65
|
else
|
112
66
|
@__collections
|
113
67
|
|
114
|
-
# do something to each collection in the scope
|
115
68
|
each: (fn)->
|
116
69
|
_( @all() ).each(fn)
|
117
70
|
|
118
71
|
get:(key)->
|
119
72
|
@currentScope()[key]
|
120
73
|
|
121
|
-
# by default, we won't use a scope, but if you wish to use one
|
122
|
-
# you should define this method on your collection manager
|
123
74
|
getScope: ()-> undefined
|
124
75
|
|
125
76
|
getOrCreate: (key,collectionOptions={},initialModels=[])->
|
@@ -131,9 +82,6 @@ class Luca.CollectionManager
|
|
131
82
|
guess ||= (@collectionNamespace || (window || global) )[ "#{classified}Collection" ]
|
132
83
|
guess
|
133
84
|
|
134
|
-
# load collection, iterates over each name you have passed for the
|
135
|
-
# your collections in the currentScope, makes sure they exist and
|
136
|
-
# fetched
|
137
85
|
loadInitialCollections: ()->
|
138
86
|
collectionDidLoad = (collection) =>
|
139
87
|
collection.unbind "reset"
|
@@ -153,16 +101,9 @@ class Luca.CollectionManager
|
|
153
101
|
|
154
102
|
loadedCollectionsCount: ()->
|
155
103
|
@state.get("loaded_collections_count")
|
156
|
-
|
157
|
-
# and any reset events should be respected, bound to, etc. however
|
158
|
-
# if this ever isn't the case, you can create an instance
|
159
|
-
# of a collection which is "private" in that once it is
|
160
|
-
# returned from the collection manager, it isn't tracked so
|
161
|
-
# you can make sure any add / reset / remove / filter events
|
162
|
-
# don't effect other views
|
104
|
+
|
163
105
|
private: (key, collectionOptions={}, initialModels=[])->
|
164
106
|
@create(key,collectionOptions,initialModels,true)
|
165
107
|
|
166
|
-
Luca.CollectionManager.destroyAll = ()->
|
167
|
-
Luca.CollectionManager.instances =
|
168
|
-
Luca.CollectionManager.get = ()-> _( instances ).last()
|
108
|
+
Luca.CollectionManager.destroyAll = ()->
|
109
|
+
Luca.CollectionManager.instances = {}
|
File without changes
|
@@ -1,2 +1,2 @@
|
|
1
|
-
%ul
|
1
|
+
%ul{:id=>"<%= cid %>-tabs-selector",:class=>"nav <%= navClass %>"}
|
2
2
|
%div{:id=>"<%= cid %>-tab-view-content",:class=>"tab-content"}
|