luca 0.9.1 → 0.9.2
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 +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"}
|