luca 0.8.599 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/.gitignore +3 -0
  2. data/.rvmrc +1 -0
  3. data/CHANGELOG +51 -2
  4. data/README.md +10 -247
  5. data/ROADMAP +6 -2
  6. data/app.rb +16 -2
  7. data/assets/javascripts/dependencies/bootstrap.min.js +7 -1
  8. data/assets/javascripts/dependencies/codemirror-coffeescript.js +347 -0
  9. data/assets/javascripts/dependencies/codemirror-css.js +124 -0
  10. data/assets/javascripts/dependencies/codemirror-html.js +410 -0
  11. data/assets/javascripts/dependencies/codemirror-javascript.js +361 -0
  12. data/assets/javascripts/dependencies/codemirror-less.js +232 -0
  13. data/assets/javascripts/dependencies/codemirror-vim.js +500 -0
  14. data/assets/javascripts/dependencies/codemirror.js +3076 -0
  15. data/assets/javascripts/dependencies.coffee +0 -1
  16. data/assets/javascripts/luca-ui-base.coffee +10 -3
  17. data/assets/javascripts/luca-ui-bootstrap.js +1 -0
  18. data/assets/javascripts/luca-ui-development-tools.coffee +9 -0
  19. data/assets/javascripts/luca-ui.coffee +6 -1
  20. data/assets/javascripts/sandbox/application.coffee +51 -0
  21. data/assets/javascripts/sandbox/router.coffee +14 -0
  22. data/assets/javascripts/sandbox/templates/main.luca +33 -0
  23. data/assets/javascripts/sandbox/templates/sandbox/navigation.luca +1 -0
  24. data/assets/javascripts/sandbox/templates/sandbox.luca +1 -0
  25. data/assets/javascripts/sandbox/views/top_navigation.coffee +4 -0
  26. data/assets/javascripts/sandbox.coffee +2 -2
  27. data/assets/stylesheets/bootstrap.min.css +395 -297
  28. data/assets/stylesheets/codemirror-blackboard.css +25 -0
  29. data/assets/stylesheets/codemirror-monokai.css +33 -0
  30. data/assets/stylesheets/codemirror.css +126 -0
  31. data/assets/stylesheets/luca-ui-bootstrap.css +0 -1
  32. data/assets/stylesheets/luca-ui-development-tools.css +5 -0
  33. data/assets/stylesheets/sandbox/sandbox.scss +1 -3
  34. data/assets/stylesheets/themes/amelia-bootstrap.css +826 -0
  35. data/assets/stylesheets/themes/slate-bootstrap.css +797 -0
  36. data/assets/stylesheets/themes/superhero-bootstrap.css +830 -0
  37. data/lib/luca/code_browser.rb +55 -0
  38. data/lib/luca/rails/version.rb +1 -1
  39. data/lib/luca/rails.rb +1 -0
  40. data/spec/components/fields/checkbox_array_spec.coffee +46 -0
  41. data/spec/components/form_view_spec.coffee +10 -4
  42. data/spec/containers/card_view_spec.coffee +7 -0
  43. data/spec/core/collection_spec.coffee +58 -4
  44. data/spec/core/container_spec.coffee +6 -6
  45. data/spec/core/view_spec.coffee +93 -7
  46. data/spec/framework_spec.coffee +15 -12
  47. data/src/components/application.coffee +126 -18
  48. data/src/components/base_toolbar.coffee +2 -2
  49. data/src/components/collection_loader_view.coffee +1 -2
  50. data/src/components/collection_view.coffee +77 -0
  51. data/src/components/controller.coffee +1 -4
  52. data/src/components/fields/button_field.coffee +1 -1
  53. data/src/components/fields/checkbox_array.coffee +2 -2
  54. data/src/components/fields/checkbox_field.coffee +3 -1
  55. data/src/components/fields/file_upload_field.coffee +1 -1
  56. data/src/components/fields/hidden_field.coffee +1 -1
  57. data/src/components/fields/select_field.coffee +1 -1
  58. data/src/components/fields/text_area_field.coffee +1 -1
  59. data/src/components/fields/text_field.coffee +10 -6
  60. data/src/components/fields/type_ahead_field.coffee +18 -5
  61. data/src/components/form_button_toolbar.coffee +1 -2
  62. data/src/components/form_view.coffee +44 -62
  63. data/src/components/grid_view.coffee +27 -20
  64. data/src/components/load_mask.coffee +3 -0
  65. data/src/components/nav_bar.coffee +26 -0
  66. data/src/components/record_manager.coffee +1 -3
  67. data/src/components/router.coffee +1 -1
  68. data/src/components/template.coffee +3 -15
  69. data/src/components/toolbar_dialog.coffee +25 -0
  70. data/src/containers/card_view.coffee +22 -23
  71. data/src/containers/column_view.coffee +1 -6
  72. data/src/containers/modal_view.coffee +20 -71
  73. data/src/containers/panel_toolbar.coffee +156 -0
  74. data/src/containers/panel_view.coffee +1 -1
  75. data/src/containers/split_view.coffee +1 -3
  76. data/src/containers/tab_view.coffee +29 -29
  77. data/src/containers/viewport.coffee +38 -3
  78. data/src/core/collection.coffee +80 -48
  79. data/src/core/container.coffee +153 -72
  80. data/src/core/core.coffee +181 -0
  81. data/src/core/field.coffee +4 -2
  82. data/src/core/model.coffee +1 -1
  83. data/src/core/observer.coffee +3 -3
  84. data/src/core/panel.coffee +143 -0
  85. data/src/core/registry.coffee +104 -0
  86. data/src/core/util.coffee +82 -0
  87. data/src/core/view.coffee +158 -85
  88. data/src/framework.coffee +112 -178
  89. data/src/index.coffee +0 -255
  90. data/src/managers/collection_manager.coffee +1 -0
  91. data/src/samples/definition.coffee +49 -0
  92. data/src/stylesheets/base.scss +0 -78
  93. data/src/stylesheets/components/form_view.scss +8 -3
  94. data/src/stylesheets/components/grid_view.scss +3 -7
  95. data/src/stylesheets/components/load_mask.scss +14 -0
  96. data/src/stylesheets/components/toolbar.scss +0 -15
  97. data/src/stylesheets/containers/container.scss +14 -2
  98. data/src/stylesheets/containers/panels.scss +23 -0
  99. data/src/stylesheets/tools/class_browser.scss +32 -0
  100. data/src/stylesheets/tools/code_editor.scss +24 -0
  101. data/src/stylesheets/tools/component_tester.scss +8 -0
  102. data/src/stylesheets/tools/console.scss +26 -0
  103. data/src/templates/components/collection_loader_view.luca +1 -1
  104. data/src/templates/components/form_view.luca +2 -13
  105. data/src/templates/components/grid_view.luca +0 -2
  106. data/src/templates/components/load_mask.luca +3 -0
  107. data/src/templates/components/nav_bar.luca +2 -0
  108. data/src/templates/containers/tab_view.luca +1 -0
  109. data/src/templates/fields/text_field.luca +4 -1
  110. data/src/tools/class_browser.coffee +39 -0
  111. data/src/tools/code_editor.coffee +258 -0
  112. data/src/tools/code_mirror_field.coffee +57 -0
  113. data/src/tools/coffee_script_editor.coffee +60 -0
  114. data/src/tools/collection_inspector.coffee +4 -0
  115. data/src/tools/component_tester.coffee +472 -0
  116. data/src/tools/components/class_browser_detail.coffee +10 -0
  117. data/src/tools/components/class_browser_list.coffee +74 -0
  118. data/src/tools/console.coffee +147 -0
  119. data/src/tools/development_console.coffee +147 -0
  120. data/src/tools/models/components.coffee +63 -0
  121. data/src/tools/templates/component_tester/help.luca +14 -0
  122. data/vendor/assets/javascripts/luca-ui-base.js +1389 -611
  123. data/vendor/assets/javascripts/luca-ui-bootstrap.js +9 -0
  124. data/vendor/assets/javascripts/luca-ui-development-tools.js +18719 -0
  125. data/vendor/assets/javascripts/luca-ui-spec.js +2065 -878
  126. data/vendor/assets/javascripts/luca-ui.js +1759 -852
  127. data/vendor/assets/javascripts/luca-ui.min.js +3 -3
  128. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +494 -440
  129. data/vendor/assets/stylesheets/luca-ui-development-tools.css +224 -0
  130. data/vendor/assets/stylesheets/luca-ui-spec.css +99 -140
  131. data/vendor/assets/stylesheets/luca-ui.css +99 -140
  132. data/views/index.erb +6 -3
  133. metadata +60 -18
  134. data/assets/javascripts/dependencies/jquery-console.js +0 -649
  135. data/assets/javascripts/development-console.coffee +0 -2
  136. data/assets/javascripts/sandbox/sandbox.coffee +0 -16
  137. data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +0 -33
  138. data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +0 -48
  139. data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +0 -24
  140. data/assets/javascripts/sandbox/templates/features/introduction.luca +0 -11
  141. data/assets/javascripts/sandbox/templates/features/view_helpers.luca +0 -43
  142. data/assets/javascripts/sandbox/templates/navigation.luca +0 -8
  143. data/assets/javascripts/sandbox/views/form_demo.coffee +0 -47
  144. data/assets/javascripts/sandbox/views/grid_demo.coffee +0 -23
  145. data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +0 -1
  146. data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +0 -38
  147. data/src/components/collection_inspector.coffee +0 -2
  148. data/src/components/development_console.coffee +0 -59
  149. data/src/stylesheets/components/development_console.scss +0 -47
data/src/core/view.coffee CHANGED
@@ -1,6 +1,4 @@
1
1
  #### Luca Base View
2
- Luca.View = Backbone.View.extend
3
- base: 'Luca.View'
4
2
 
5
3
  # The Luca.View class adds some very commonly used patterns
6
4
  # and functionality to the stock Backbone.View class. Features
@@ -8,82 +6,19 @@ Luca.View = Backbone.View.extend
8
6
  # against a Backbone.Model or Backbone.Collection reset event, Caching
9
7
  # views into a global Component Registry, and more.
10
8
 
11
- Luca.View.originalExtend = Backbone.View.extend
9
+ _.def("Luca.View").extends("Backbone.View").with
12
10
 
13
- # By overriding Backbone.View.extend we are able to intercept
14
- # some method definitions and add special behavior around them
15
- # mostly related to render()
16
- Luca.View.extend = (definition)->
17
- #### Rendering
18
- #
19
- # Our base view class wraps the defined render() method
20
- # of the views which inherit from it, and does things like
21
- # trigger the before and after render events automatically.
22
- # In addition, if the view has a deferrable property on it
23
- # then it will make sure that the render method doesn't get called
24
- # until.
25
-
26
- _base = definition.render
27
-
28
- _base ||= ()->
29
- container = if _.isFunction(@container) then @container() else @container
30
-
31
- return @ unless $(container) and @$el
32
-
33
- $(container).append( @$el )
34
-
35
- return @
36
-
37
- definition.render = ()->
38
- if @layoutTemplate?
39
- @$el.html()
40
-
41
- if @deferrable
42
- @trigger "before:render", @
43
-
44
- @deferrable.bind @deferrable_event, _.once ()=>
45
- _base.apply(@, arguments)
46
- @trigger "after:render", @
47
-
48
- # we might not want to fetch immediately upon
49
- # rendering, so we can pass a deferrable_trigger
50
- # event and not fire the fetch until this event
51
- # occurs
52
- if !@deferrable_trigger
53
- @immediate_trigger = true
54
-
55
- if @immediate_trigger is true
56
- @deferrable.fetch()
57
- else
58
- @bind @deferrable_trigger, _.once ()=>
59
- @deferrable.fetch()
60
-
61
- return @
62
-
63
- else
64
- @trigger "before:render", @
65
- _base.apply(@, arguments)
66
- @trigger "after:render", @
67
-
68
- return @
69
-
70
- Luca.View.originalExtend.call(@, definition)
71
-
72
- _.extend Luca.View.prototype,
73
- applyStyles: (styles={})->
74
- for setting, value of styles
75
- @$el.css(setting,value)
76
-
77
- @
11
+ additionalClassNames:[]
78
12
 
79
13
  debug: ()->
80
14
  return unless @debugMode or window.LucaDebugMode?
81
15
  console.log [(@name || @cid),message] for message in arguments
82
16
 
83
17
  trigger: ()->
84
- if Luca.enableGlobalObserver and @observeEvents is true
85
- Luca.ViewObserver ||= new Luca.Observer(type:"view")
86
- Luca.ViewObserver.relay @, arguments
18
+ if Luca.enableGlobalObserver
19
+ if Luca.developmentMode is true or @observeEvents is true
20
+ Luca.ViewObserver ||= new Luca.Observer(type:"view")
21
+ Luca.ViewObserver.relay @, arguments
87
22
 
88
23
  Backbone.View.prototype.trigger.apply @, arguments
89
24
 
@@ -96,17 +31,16 @@ _.extend Luca.View.prototype,
96
31
  "deactivation"
97
32
  ]
98
33
 
99
- # which event should we listen to on
100
- # our deferrable property, before we
101
- # trigger the actual rendering
102
- deferrable_event: "reset"
103
-
104
34
  initialize: (@options={})->
105
35
 
106
36
  _.extend @, @options
107
37
 
108
38
  @cid = _.uniqueId(@name) if @name?
109
39
 
40
+ if template = @bodyTemplate
41
+ @$el.empty()
42
+ Luca.View::$html.call(@, Luca.template(template, @) )
43
+
110
44
  #### View Caching
111
45
  #
112
46
  # Luca.View(s) which get created get stored in a global cache by their
@@ -118,10 +52,11 @@ _.extend Luca.View.prototype,
118
52
  @setupHooks( unique )
119
53
 
120
54
  if @autoBindEventHandlers is true
121
- _( @events ).each (handler,event)=>
122
- if _.isString(handler)
123
- _.bindAll @, handler
55
+ @bindAllEventHandlers()
124
56
 
57
+ if @additionalClassNames
58
+ @additionalClassNames = @additionalClassNames.split(" ") if _.isString(@additionalClassNames)
59
+ @$el.addClass( additional ) for additional in @additionalClassNames
125
60
 
126
61
  @trigger "after:initialize", @
127
62
 
@@ -129,7 +64,36 @@ _.extend Luca.View.prototype,
129
64
 
130
65
  @delegateEvents()
131
66
 
132
- $container: ()-> $(@container)
67
+ #### JQuery / DOM Selector Helpers
68
+ $wrap: (wrapper)->
69
+ if !wrapper.match(/[<>]/)
70
+ wrapper = @make("div",class:wrapper)
71
+
72
+ @$el.wrap( wrapper )
73
+
74
+ $template: (template, variables={})->
75
+ @$el.html( Luca.template(template,variables) )
76
+
77
+ $html: (content)->
78
+ @$el.html( content )
79
+
80
+ $append: (content)->
81
+ @$el.append( content )
82
+
83
+ #### Containers
84
+ #
85
+ # Luca is heavily reliant on the concept of Container views. Views which
86
+ # contain other views and handle inter-component communication between the
87
+ # component views. The default render() operation consists of building the
88
+ # view's content, and then attaching that view to its container.
89
+ #
90
+ # 99% of the time this would happen automatically
91
+ $attach: ()->
92
+ @$container().append( @el )
93
+
94
+ $container: ()->
95
+ $(@container)
96
+
133
97
  #### Hooks or Auto Event Binding
134
98
  #
135
99
  # views which inherit from Luca.View can define hooks
@@ -147,13 +111,14 @@ _.extend Luca.View.prototype,
147
111
  set ||= @hooks
148
112
 
149
113
  _(set).each (eventId)=>
150
- parts = eventId.split(':')
151
- prefix = parts.shift()
114
+ fn = Luca.util.hook( eventId )
115
+
116
+ callback = ()=>
117
+ @[fn]?.apply @, arguments
152
118
 
153
- parts = _( parts ).map (p)-> _.string.capitalize(p)
154
- fn = prefix + parts.join('')
119
+ callback = _.once(callback) if eventId?.match(/once:/)
155
120
 
156
- @bind eventId, ()=> @[fn].apply @, arguments if @[fn]
121
+ @bind eventId, callback
157
122
 
158
123
 
159
124
  #### Luca.Collection and Luca.CollectionManager integration
@@ -207,3 +172,111 @@ _.extend Luca.View.prototype,
207
172
  @events ||= {}
208
173
  @events[ selector ] = handler
209
174
  @delegateEvents()
175
+
176
+ bindAllEventHandlers: ()->
177
+ _( @events ).each (handler,event)=>
178
+ if _.isString(handler)
179
+ _.bindAll @, handler
180
+
181
+ definitionClass: ()->
182
+ Luca.util.resolve(@displayName, window)?.prototype
183
+
184
+ # refreshCode happens whenever the Luca.Framework extension
185
+ # system is run after there are running instances of a given component
186
+
187
+ # in the context of views, what this means is that each eventHandler which
188
+ # is bound to a specific object via _.bind or _.bindAll, or autoBindEventHandlers
189
+ # is refreshed with the prototype method of the component that it inherits from,
190
+ # and then delegateEvents is called to refresh any of the updated event handlers
191
+
192
+ # in addition to this, all properties of the instance of a given view which are
193
+ # also backbone views will have the same process run against them
194
+ refreshCode: ()->
195
+ view = @
196
+
197
+ _( @eventHandlerProperties() ).each (prop)->
198
+ view[ prop ] = view.definitionClass()[prop]
199
+
200
+ if @autoBindEventHandlers is true
201
+ @bindAllEventHandlers()
202
+
203
+ @delegateEvents()
204
+
205
+ eventHandlerProperties: ()->
206
+ handlerIds = _( @events ).values()
207
+ _( handlerIds ).select (v)->
208
+ _.isString(v)
209
+
210
+ eventHandlerFunctions: ()->
211
+ handlerIds = _( @events ).values()
212
+ _( handlerIds ).map (handlerId)=>
213
+ if _.isFunction(handlerId) then handlerId else @[handlerId]
214
+
215
+ collections: ()-> Luca.util.selectProperties( Luca.isBackboneCollection, @ )
216
+ models: ()-> Luca.util.selectProperties( Luca.isBackboneModel, @ )
217
+ views: ()-> Luca.util.selectProperties( Luca.isBackboneView, @ )
218
+
219
+
220
+ originalExtend = Backbone.View.extend
221
+
222
+ customizeRender = (definition)->
223
+ #### Rendering
224
+ #
225
+ # Our base view class wraps the defined render() method
226
+ # of the views which inherit from it, and does things like
227
+ # trigger the before and after render events automatically.
228
+ # In addition, if the view has a deferrable property on it
229
+ # then it will make sure that the render method doesn't get called
230
+ # until.
231
+
232
+ _base = definition.render
233
+
234
+ _base ||= Luca.View::$attach
235
+
236
+
237
+ definition.render = ()->
238
+ view = @
239
+ # if a view has a deferrable property set
240
+
241
+ if @deferrable
242
+ target = @deferrable_target
243
+
244
+ unless Luca.isBackboneCollection(@deferrable)
245
+ @deferrable = @collection
246
+
247
+ target ||= @deferrable
248
+ trigger = if @deferrable_event then @deferrable_event else "reset"
249
+
250
+ view.defer ()->
251
+ _base.call(view)
252
+ view.trigger "after:render", view
253
+ .until(target,trigger)
254
+
255
+ view.trigger "before:render", @
256
+
257
+ autoTrigger = @deferrable_trigger || @deferUntil
258
+
259
+ if !autoTrigger?
260
+ target[ (@deferrable_method||"fetch") ].call(target)
261
+ else
262
+ fn = _.once ()=> @deferrable[ (@deferrable_method||"fetch") ]?()
263
+ (@deferrable_target || @ ).bind(@deferrable_trigger, fn)
264
+
265
+ return @
266
+
267
+ else
268
+ @trigger "before:render", @
269
+ _base.apply(@, arguments)
270
+ @trigger "after:render", @
271
+
272
+ return @
273
+
274
+ definition
275
+
276
+ # By overriding Backbone.View.extend we are able to intercept
277
+ # some method definitions and add special behavior around them
278
+ # mostly related to render()
279
+ Luca.View.extend = (definition)->
280
+ definition = customizeRender( definition )
281
+ originalExtend.call(@, definition)
282
+
data/src/framework.coffee CHANGED
@@ -1,18 +1,39 @@
1
- window.Luca =
2
- VERSION: "0.8.599"
1
+ # the Luca() browser utility function is meant to be a smart wrapper around various
2
+ # types of input which will return what the developer would expect given the
3
+ # context it is used.
4
+ (window || global).Luca = (payload, args...)->
5
+ if _.isString(payload) and result = Luca.cache(payload)
6
+ return result
7
+
8
+ if _.isString(payload) and result = Luca.find(payload)
9
+ return result
10
+
11
+ if _.isObject(payload) and payload.ctype?
12
+ return Luca.util.lazyComponent( payload )
13
+
14
+ if _.isObject(payload) and payload.defines and payload.extends
15
+ definition = payload.defines
16
+ inheritsFrom = payload.extends
17
+
18
+
19
+ if _.isFunction( fallback = _(args).last() )
20
+ return fallback()
21
+
22
+ _.extend Luca,
23
+ VERSION: "0.9.0"
3
24
  core: {}
4
25
  containers: {}
5
26
  components: {}
6
27
  modules: {}
7
28
  util: {}
8
29
  fields: {}
9
- component_cache:
10
- cid_index: {}
11
- name_index: {}
12
- registry:
13
- classes: {}
14
- namespaces:["Luca.containers","Luca.components"]
30
+ registry:{}
31
+
32
+ # for triggering / binding to component definitions
33
+ _.extend Luca, Backbone.Events
15
34
 
35
+ # if developmentMode is true, you have access to some neat development tools
36
+ Luca.developmentMode = false
16
37
 
17
38
  # The Global Observer is very helpful in development
18
39
  # it observes every event triggered on every view, collection, model
@@ -25,6 +46,32 @@ Luca.enableGlobalObserver = false
25
46
  # problem on our own!
26
47
  Luca.enableBootstrap = true
27
48
 
49
+ Luca.keys =
50
+ ENTER: 13
51
+ ESCAPE: 27
52
+ KEYLEFT: 37
53
+ KEYUP: 38
54
+ KEYRIGHT: 39
55
+ KEYDOWN: 40
56
+ SPACEBAR: 32
57
+ FORWARDSLASH: 191
58
+
59
+ # build a reverse map
60
+ Luca.keyMap = _( Luca.keys ).inject (memo, value, symbol)->
61
+ memo[value] = symbol.toLowerCase()
62
+ memo
63
+ , {}
64
+
65
+ Luca.find = ()->
66
+ # TODO Implement
67
+ undefined
68
+
69
+ Luca.supportsEvents = Luca.supportsBackboneEvents = (obj)->
70
+ Luca.isComponent(obj) or (_.isFunction( obj?.trigger ) or _.isFunction(obj?.bind))
71
+
72
+ Luca.isComponent = (obj)->
73
+ Luca.isBackboneModel(obj) or Luca.isBackboneView(obj) or Luca.isBackboneCollection(obj)
74
+
28
75
  Luca.isBackboneModel = (obj)->
29
76
  _.isFunction(obj?.set) and _.isFunction(obj?.get) and _.isObject(obj?.attributes)
30
77
 
@@ -34,101 +81,6 @@ Luca.isBackboneView = (obj)->
34
81
  Luca.isBackboneCollection = (obj)->
35
82
  _.isFunction(obj?.fetch) and _.isFunction(obj?.reset)
36
83
 
37
- # adds an additional namespace to look for luca ui
38
- # components. useful for when you define a bunch of
39
- # components in your own application's namespace
40
- Luca.registry.addNamespace = (identifier)->
41
- Luca.registry.namespaces.push( identifier )
42
- Luca.registry.namespaces = _( Luca.registry.namespaces ).uniq()
43
-
44
- # stores or looks up a component in the component cache
45
- # by its backbone @cid or by its component_name
46
- Luca.cache = (needle, component)->
47
- Luca.component_cache.cid_index[ needle ] = component if component?
48
-
49
- component = Luca.component_cache.cid_index[ needle ]
50
-
51
- # optionally, cache it by tying its name to its cid for easier lookups
52
- if component?.component_name?
53
- Luca.component_cache.name_index[ component.component_name ] = component.cid
54
- else if component?.name?
55
- Luca.component_cache.name_index[ component.name ] = component.cid
56
-
57
- return component if component?
58
-
59
- # perform a lookup by name if the component_id didn't turn anything
60
- lookup_id = Luca.component_cache.name_index[ needle ]
61
-
62
- Luca.component_cache.cid_index[ lookup_id ]
63
-
64
- # Takes an string like "deep.nested.value" and an object like window
65
- # and returns the value of window.deep.nested.value. useful for defining
66
- # references on objects which don't yet exist, as strings, which get
67
- # evaluated at runtime when such references will be available
68
- Luca.util.resolve = (accessor, source_object)->
69
- _( accessor.split(/\./) ).inject (obj,key)->
70
- obj = obj?[key]
71
- , source_object
72
-
73
- # A better name for Luca.util.nestedValue
74
- Luca.util.nestedValue = Luca.util.resolve
75
-
76
- # turns a word like form_view into FormView
77
- Luca.util.classify = (string="")->
78
- _.string.camelize( _.string.capitalize( string ) )
79
-
80
- # Lookup a component in the Luca component registry
81
- # by it's ctype identifier. If it doesn't exist,
82
- # check any other registered namespace
83
- Luca.registry.lookup = (ctype)->
84
- c = Luca.registry.classes[ctype]
85
-
86
- return c if c?
87
-
88
- className = Luca.util.classify(ctype)
89
-
90
- parents = _( Luca.registry.namespaces ).map (namespace)-> Luca.util.nestedValue(namespace, (window || global))
91
-
92
- _( parents ).chain().map((parent)-> parent[className]).compact().value()?[0]
93
-
94
- # one of the main benefits of Luca is the ability to structure your app as
95
- # large blocks of JSON configuration. In order to convert an object into
96
- # a Luca component, we lookup the object's class by converting its ctype / type
97
- # property into a class that has been registered in the component registry
98
- Luca.util.lazyComponent = (config)->
99
- ctype = config.ctype || config.type
100
-
101
- componentClass = Luca.registry.lookup( ctype )
102
-
103
- throw "Invalid Component Type: #{ ctype }. Did you forget to register it?" unless componentClass
104
-
105
- constructor = eval( componentClass )
106
-
107
- new constructor(config)
108
-
109
- # for lazy component creation
110
- Luca.register = (component, constructor_class)->
111
- exists = Luca.registry.classes[component]
112
-
113
- if exists? and !window.TestRun?
114
- console.log "Attempting to register component with the signature #{ component }. Already exists"
115
- else
116
- Luca.registry.classes[component] = constructor_class
117
-
118
- Luca.available_templates = (filter="")->
119
- available = _( Luca.templates ).keys()
120
-
121
- if filter.length > 0
122
- _( available ).select (tmpl)-> tmpl.match(filter)
123
- else
124
- available
125
-
126
- Luca.util.isIE = ()->
127
- try
128
- Object.defineProperty({}, '', {})
129
- return false
130
- catch e
131
- return true
132
84
 
133
85
  # This is a convenience method for accessing the templates
134
86
  # available to the client side app, either the ones which ship with Luca
@@ -140,6 +92,9 @@ Luca.util.isIE = ()->
140
92
  Luca.template = (template_name, variables)->
141
93
  window.JST ||= {}
142
94
 
95
+ if _.isFunction(template_name)
96
+ return template_name(variables)
97
+
143
98
  luca = Luca.templates?[ template_name ]
144
99
  jst = JST?[ template_name ]
145
100
 
@@ -152,7 +107,7 @@ Luca.template = (template_name, variables)->
152
107
  jst = _( JST ).detect (fn,template_id)->
153
108
  needle.exec( template_id )
154
109
 
155
- throw "Could not find template with #{ template_name }" unless luca || jst
110
+ throw "Could not find template named #{ template_name }" unless luca || jst
156
111
 
157
112
  template = luca || jst
158
113
 
@@ -160,77 +115,56 @@ Luca.template = (template_name, variables)->
160
115
 
161
116
  template
162
117
 
163
- #### Component Definition And Inheritance
164
- #
165
- # this is a nice way of extending / inheriting
166
- # this allows for syntactic sugar such as:
167
- #
168
- # Luca.define("TestClass").extends("Luca.View").with
169
- # property: "value"
170
- # name: "whatever"
171
- #
172
- # All instances of TestClass defined this way, will have
173
- # _className properties of 'TestClass' as well as a reference
174
- # to the extended class 'Luca.View' so that you can inspect
175
- # an instance of TestClass and know that it inherits from 'Luca.View'
176
- class DefineProxy
177
- constructor:(componentName)->
178
- @namespace = (window || global)
179
- @componentId = @componentName = componentName
180
-
181
- if componentName.match(/\./)
182
- @namespaced = true
183
- parts = componentName.split('.')
184
- @componentId = parts.pop()
185
- @namespace = parts.join('.')
186
-
187
- # automatically add the namespace to the namespace registry
188
- Luca.registry.addNamespace( parts.join('.') )
189
-
190
- in: (@namespace)-> @
191
- from: (@superClassName)-> @
192
- extends: (@superClassName)-> @
193
- extend: (@superClassName)-> @
194
- with: (properties)->
195
- at = if @namespaced then Luca.util.resolve(@namespace, (window || global)) else (window||global)
196
-
197
- if @namespaced and _.isUndefined(at)
198
- eval("window.#{ @namespace } = {}")
199
- at = Luca.util.resolve(@namespace,(window || global))
200
-
201
- at[@componentId] = Luca.extend(@superClassName,@componentName, properties)
202
-
203
- # automatically register this with the component registry
204
- Luca.register( _.string.underscored(@componentId), @componentName)
205
-
206
- at[@componentId]
207
-
208
- Luca.define = (componentName)->
209
- new DefineProxy(componentName)
210
-
211
- # An alias for Luca.define
212
- # which I think reads better:
213
- #
214
- # Luca.component('Whatever').extends('Something').with(enhancements)
215
- Luca.component = Luca.define
216
-
217
- Luca.extend = (superClassName, childName, properties={})->
218
- superClass = Luca.util.resolve( superClassName, (window || global) )
219
-
220
- unless _.isFunction(superClass?.extend)
221
- throw "#{ superClassName } is not a valid component to extend from"
222
-
223
- properties._className = childName
224
-
225
- properties._superClass = ()->
226
- superClass._className ||= superClassName
227
- superClass
228
-
229
- superClass.extend(properties)
230
-
231
- _.mixin
232
- component: Luca.define
233
-
234
- #### Once We Are Ready To go....
235
- $ do ->
236
- $('body').addClass('luca-ui-enabled')
118
+ Luca.available_templates = (filter="")->
119
+ available = _( Luca.templates ).keys()
120
+
121
+ if filter.length > 0
122
+ _( available ).select (tmpl)-> tmpl.match(filter)
123
+ else
124
+ available
125
+
126
+
127
+
128
+ UnderscoreExtensions =
129
+ module: (base,module)->
130
+ _.extend base, module
131
+ if base.included and _(base.included).isFunction()
132
+ base.included.apply(base)
133
+
134
+ delete: (object, key)->
135
+ value = object[key]
136
+ delete object[key]
137
+ value
138
+
139
+ # this function will ensure a function gets called at least once
140
+ # afrer x delay. by setting defaults, we can use this on backbone
141
+ # view definitions
142
+ idle: (code, delay=1000)->
143
+ delay = 0 if window.DISABLE_IDLE
144
+ handle = undefined
145
+ ()->
146
+ window.clearTimeout(handle) if handle
147
+ handle = window.setTimeout(_.bind(code, @), delay)
148
+
149
+ idleShort: (code, delay=100)->
150
+ delay = 0 if window.DISABLE_IDLE
151
+ handle = undefined
152
+ ()->
153
+ window.clearTimeout(handle) if handle
154
+ handle = window.setTimeout(_.bind(code, @), delay)
155
+
156
+ idleMedium: (code, delay=2000)->
157
+ delay = 0 if window.DISABLE_IDLE
158
+ handle = undefined
159
+ ()->
160
+ window.clearTimeout(handle) if handle
161
+ handle = window.setTimeout(_.bind(code, @), delay)
162
+
163
+ idleLong: (code, delay=5000)->
164
+ delay = 0 if window.DISABLE_IDLE
165
+ handle = undefined
166
+ ()->
167
+ window.clearTimeout(handle) if handle
168
+ handle = window.setTimeout(_.bind(code, @), delay)
169
+
170
+ _.mixin(UnderscoreExtensions)