luca 0.6.6

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.
Files changed (233) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +17 -0
  3. data/Gemfile.lock +77 -0
  4. data/Guardfile +22 -0
  5. data/README.md +291 -0
  6. data/Rakefile +28 -0
  7. data/app.rb +46 -0
  8. data/assets/images/glyphicons-halflings-white.png +0 -0
  9. data/assets/images/glyphicons-halflings.png +0 -0
  10. data/assets/javascripts/dependencies/backbone-min.js +37 -0
  11. data/assets/javascripts/dependencies/backbone-query.min.js +1 -0
  12. data/assets/javascripts/dependencies/bootstrap.min.js +1 -0
  13. data/assets/javascripts/dependencies/jasmine-html.js +190 -0
  14. data/assets/javascripts/dependencies/jasmine.js +2476 -0
  15. data/assets/javascripts/dependencies/jquery.js +4 -0
  16. data/assets/javascripts/dependencies/modal.js +698 -0
  17. data/assets/javascripts/dependencies/modernizr.min.js +30 -0
  18. data/assets/javascripts/dependencies/prettify.js +28 -0
  19. data/assets/javascripts/dependencies/sinon.js +3469 -0
  20. data/assets/javascripts/dependencies/spin-min.js +2 -0
  21. data/assets/javascripts/dependencies/underscore-min.js +31 -0
  22. data/assets/javascripts/dependencies/underscore-string.min.js +14 -0
  23. data/assets/javascripts/dependencies.coffee +7 -0
  24. data/assets/javascripts/luca-ui-base.coffee +12 -0
  25. data/assets/javascripts/luca-ui-spec.coffee +2 -0
  26. data/assets/javascripts/luca-ui.coffee +3 -0
  27. data/assets/javascripts/sandbox/collections/sample.coffee +0 -0
  28. data/assets/javascripts/sandbox/config.coffee +7 -0
  29. data/assets/javascripts/sandbox/sandbox.coffee +16 -0
  30. data/assets/javascripts/sandbox/templates/features/collection_helpers.luca +33 -0
  31. data/assets/javascripts/sandbox/templates/features/form_demo_code.luca +48 -0
  32. data/assets/javascripts/sandbox/templates/features/grid_demo_code.luca +24 -0
  33. data/assets/javascripts/sandbox/templates/features/introduction.luca +11 -0
  34. data/assets/javascripts/sandbox/templates/features/view_helpers.luca +43 -0
  35. data/assets/javascripts/sandbox/templates/navigation.luca +8 -0
  36. data/assets/javascripts/sandbox/views/form_demo.coffee +47 -0
  37. data/assets/javascripts/sandbox/views/grid_demo.coffee +23 -0
  38. data/assets/javascripts/sandbox/views/pages/collection_events_sample.coffee +1 -0
  39. data/assets/javascripts/sandbox/views/pages/pages_controller.coffee +28 -0
  40. data/assets/javascripts/sandbox.coffee +4 -0
  41. data/assets/javascripts/spec-dependencies.coffee +4 -0
  42. data/assets/stylesheets/bootstrap-responsive.min.css +3 -0
  43. data/assets/stylesheets/bootstrap.min.css +610 -0
  44. data/assets/stylesheets/jasmine.css +166 -0
  45. data/assets/stylesheets/luca-ui-bootstrap.css +5 -0
  46. data/assets/stylesheets/luca-ui-spec.css +3 -0
  47. data/assets/stylesheets/luca-ui.css +3 -0
  48. data/assets/stylesheets/prettify.css +40 -0
  49. data/assets/stylesheets/sandbox/sandbox.scss +4 -0
  50. data/assets/stylesheets/sandbox.css +3 -0
  51. data/config.ru +11 -0
  52. data/lib/luca/command_line.rb +69 -0
  53. data/lib/luca/rails/engine.rb +12 -0
  54. data/lib/luca/rails/version.rb +6 -0
  55. data/lib/luca/rails.rb +9 -0
  56. data/lib/luca/template.rb +51 -0
  57. data/lib/luca/test_harness.rb +106 -0
  58. data/lib/luca.rb +1 -0
  59. data/lib/sprockets/luca_template.rb +49 -0
  60. data/lib/templates/spec_manifest_javascripts.erb +7 -0
  61. data/lib/templates/spec_manifest_stylesheets.erb +11 -0
  62. data/luca.gemspec +26 -0
  63. data/public/jasmine/index.html +26 -0
  64. data/public/sandbox/api.js +1 -0
  65. data/spec/components/application_spec.coffee +0 -0
  66. data/spec/components/collection_loader_view_spec.coffee +0 -0
  67. data/spec/components/controller_spec.coffee +0 -0
  68. data/spec/components/form_view_spec.coffee +13 -0
  69. data/spec/components/grid_view_spec.coffee +0 -0
  70. data/spec/components/record_manager_spec.coffee +0 -0
  71. data/spec/components/template_spec.coffee +0 -0
  72. data/spec/containers/card_view_spec.coffee +1 -0
  73. data/spec/containers/column_view_spec.coffee +0 -0
  74. data/spec/containers/modal_view_spec.coffee +0 -0
  75. data/spec/containers/panel_view_spec.coffee +0 -0
  76. data/spec/containers/split_view_spec.coffee +0 -0
  77. data/spec/containers/tab_view_spec.coffee +0 -0
  78. data/spec/containers/viewport_spec.coffee +0 -0
  79. data/spec/core/collection_spec.coffee +215 -0
  80. data/spec/core/container_spec.coffee +0 -0
  81. data/spec/core/field_spec.coffee +0 -0
  82. data/spec/core/observer_spec.coffee +0 -0
  83. data/spec/core/view_spec.coffee +87 -0
  84. data/spec/framework_spec.coffee +48 -0
  85. data/spec/helper.coffee +120 -0
  86. data/spec/managers/collection_manager_spec.coffee +95 -0
  87. data/spec/managers/socket_manager_spec.coffee +0 -0
  88. data/src/components/application.coffee +83 -0
  89. data/src/components/base_toolbar.coffee +16 -0
  90. data/src/components/collection_loader_view.coffee +37 -0
  91. data/src/components/controller.coffee +41 -0
  92. data/src/components/fields/button_field.coffee +40 -0
  93. data/src/components/fields/checkbox_field.coffee +41 -0
  94. data/src/components/fields/file_upload_field.coffee +15 -0
  95. data/src/components/fields/hidden_field.coffee +18 -0
  96. data/src/components/fields/select_field.coffee +100 -0
  97. data/src/components/fields/text_area_field.coffee +43 -0
  98. data/src/components/fields/text_field.coffee +42 -0
  99. data/src/components/fields/type_ahead_field.coffee +10 -0
  100. data/src/components/form_button_toolbar.coffee +26 -0
  101. data/src/components/form_view.coffee +205 -0
  102. data/src/components/grid_view.coffee +208 -0
  103. data/src/components/record_manager.coffee +215 -0
  104. data/src/components/router.coffee +34 -0
  105. data/src/components/template.coffee +19 -0
  106. data/src/containers/card_view.coffee +89 -0
  107. data/src/containers/column_view.coffee +48 -0
  108. data/src/containers/modal_view.coffee +85 -0
  109. data/src/containers/panel_view.coffee +24 -0
  110. data/src/containers/split_view.coffee +12 -0
  111. data/src/containers/tab_view.coffee +77 -0
  112. data/src/containers/viewport.coffee +16 -0
  113. data/src/core/collection.coffee +319 -0
  114. data/src/core/container.coffee +256 -0
  115. data/src/core/field.coffee +68 -0
  116. data/src/core/observer.coffee +17 -0
  117. data/src/core/view.coffee +190 -0
  118. data/src/framework.coffee +110 -0
  119. data/src/index.coffee +255 -0
  120. data/src/managers/collection_manager.coffee +168 -0
  121. data/src/managers/socket_manager.coffee +54 -0
  122. data/src/modules/deferrable.coffee +18 -0
  123. data/src/modules/local_storage.coffee +50 -0
  124. data/src/stylesheets/base.scss +78 -0
  125. data/src/stylesheets/components/form_view.scss +54 -0
  126. data/src/stylesheets/components/grid_view.scss +111 -0
  127. data/src/stylesheets/components/toolbar.scss +15 -0
  128. data/src/stylesheets/containers/container.scss +7 -0
  129. data/src/stylesheets/containers/modal_view.scss +0 -0
  130. data/src/stylesheets/containers/tab_view.scss +33 -0
  131. data/src/stylesheets/normalize.scss +430 -0
  132. data/src/templates/components/bootstrap_form_controls.luca +7 -0
  133. data/src/templates/components/collection_loader_view.luca +5 -0
  134. data/src/templates/components/form_view.luca +15 -0
  135. data/src/templates/components/grid_view.luca +9 -0
  136. data/src/templates/components/grid_view_empty_text.luca +3 -0
  137. data/src/templates/containers/basic.luca +1 -0
  138. data/src/templates/containers/tab_selector_container.luca +8 -0
  139. data/src/templates/containers/tab_view.luca +1 -0
  140. data/src/templates/containers/toolbar_wrapper.luca +1 -0
  141. data/src/templates/fields/button_field.luca +2 -0
  142. data/src/templates/fields/button_field_link.luca +5 -0
  143. data/src/templates/fields/checkbox_field.luca +9 -0
  144. data/src/templates/fields/file_upload_field.luca +8 -0
  145. data/src/templates/fields/hidden_field.luca +1 -0
  146. data/src/templates/fields/select_field.luca +7 -0
  147. data/src/templates/fields/text_area_field.luca +8 -0
  148. data/src/templates/fields/text_field.luca +13 -0
  149. data/src/templates/sample/contents.luca +1 -0
  150. data/src/templates/sample/welcome.luca +1 -0
  151. data/vendor/assets/images/glyphicons-halflings-white.png +0 -0
  152. data/vendor/assets/images/glyphicons-halflings.png +0 -0
  153. data/vendor/assets/javascripts/luca-spec-dependencies.js +6135 -0
  154. data/vendor/assets/javascripts/luca-ui-base.js +1527 -0
  155. data/vendor/assets/javascripts/luca-ui-spec.js +3654 -0
  156. data/vendor/assets/javascripts/luca-ui.js +2763 -0
  157. data/vendor/assets/luca-ui/base.css +85 -0
  158. data/vendor/assets/luca-ui/components/application.js +91 -0
  159. data/vendor/assets/luca-ui/components/base_toolbar.js +23 -0
  160. data/vendor/assets/luca-ui/components/controller.js +38 -0
  161. data/vendor/assets/luca-ui/components/fields/button_field.js +45 -0
  162. data/vendor/assets/luca-ui/components/fields/checkbox_field.js +43 -0
  163. data/vendor/assets/luca-ui/components/fields/file_upload_field.js +20 -0
  164. data/vendor/assets/luca-ui/components/fields/hidden_field.js +20 -0
  165. data/vendor/assets/luca-ui/components/fields/select_field.js +97 -0
  166. data/vendor/assets/luca-ui/components/fields/text_area_field.js +48 -0
  167. data/vendor/assets/luca-ui/components/fields/text_field.js +46 -0
  168. data/vendor/assets/luca-ui/components/fields/type_ahead_field.js +13 -0
  169. data/vendor/assets/luca-ui/components/form_button_toolbar.js +32 -0
  170. data/vendor/assets/luca-ui/components/form_view.css +32 -0
  171. data/vendor/assets/luca-ui/components/form_view.js +207 -0
  172. data/vendor/assets/luca-ui/components/grid_view.css +76 -0
  173. data/vendor/assets/luca-ui/components/grid_view.js +202 -0
  174. data/vendor/assets/luca-ui/components/record_manager.js +207 -0
  175. data/vendor/assets/luca-ui/components/router.js +36 -0
  176. data/vendor/assets/luca-ui/components/template.js +26 -0
  177. data/vendor/assets/luca-ui/components/toolbar.css +11 -0
  178. data/vendor/assets/luca-ui/containers/card_view.js +98 -0
  179. data/vendor/assets/luca-ui/containers/column_view.js +52 -0
  180. data/vendor/assets/luca-ui/containers/container.css +3 -0
  181. data/vendor/assets/luca-ui/containers/modal_view.css +0 -0
  182. data/vendor/assets/luca-ui/containers/modal_view.js +87 -0
  183. data/vendor/assets/luca-ui/containers/panel_view.js +34 -0
  184. data/vendor/assets/luca-ui/containers/split_view.js +13 -0
  185. data/vendor/assets/luca-ui/containers/tab_view.css +16 -0
  186. data/vendor/assets/luca-ui/containers/tab_view.js +80 -0
  187. data/vendor/assets/luca-ui/containers/viewport.js +18 -0
  188. data/vendor/assets/luca-ui/core/collection.js +221 -0
  189. data/vendor/assets/luca-ui/core/container.js +205 -0
  190. data/vendor/assets/luca-ui/core/field.js +59 -0
  191. data/vendor/assets/luca-ui/core/observer.js +42 -0
  192. data/vendor/assets/luca-ui/core/view.js +127 -0
  193. data/vendor/assets/luca-ui/framework.js +110 -0
  194. data/vendor/assets/luca-ui/index.js +5 -0
  195. data/vendor/assets/luca-ui/managers/collection_manager.js +98 -0
  196. data/vendor/assets/luca-ui/managers/socket_manager.js +52 -0
  197. data/vendor/assets/luca-ui/modules/deferrable.js +21 -0
  198. data/vendor/assets/luca-ui/modules/local_storage.js +81 -0
  199. data/vendor/assets/luca-ui/normalize.css +359 -0
  200. data/vendor/assets/luca-ui/stylesheets/base.css +85 -0
  201. data/vendor/assets/luca-ui/stylesheets/components/form_view.css +32 -0
  202. data/vendor/assets/luca-ui/stylesheets/components/grid_view.css +76 -0
  203. data/vendor/assets/luca-ui/stylesheets/components/toolbar.css +11 -0
  204. data/vendor/assets/luca-ui/stylesheets/containers/container.css +3 -0
  205. data/vendor/assets/luca-ui/stylesheets/containers/modal_view.css +0 -0
  206. data/vendor/assets/luca-ui/stylesheets/containers/tab_view.css +16 -0
  207. data/vendor/assets/luca-ui/stylesheets/normalize.css +359 -0
  208. data/vendor/assets/luca-ui/templates/components/bootstrap_form_controls.js +4 -0
  209. data/vendor/assets/luca-ui/templates/components/form_view.js +4 -0
  210. data/vendor/assets/luca-ui/templates/components/grid_view.js +4 -0
  211. data/vendor/assets/luca-ui/templates/components/grid_view_empty_text.js +4 -0
  212. data/vendor/assets/luca-ui/templates/containers/basic.js +4 -0
  213. data/vendor/assets/luca-ui/templates/containers/tab_selector_container.js +4 -0
  214. data/vendor/assets/luca-ui/templates/containers/tab_view.js +4 -0
  215. data/vendor/assets/luca-ui/templates/containers/toolbar_wrapper.js +4 -0
  216. data/vendor/assets/luca-ui/templates/fields/button_field.js +4 -0
  217. data/vendor/assets/luca-ui/templates/fields/button_field_link.js +4 -0
  218. data/vendor/assets/luca-ui/templates/fields/checkbox_field.js +4 -0
  219. data/vendor/assets/luca-ui/templates/fields/file_upload_field.js +4 -0
  220. data/vendor/assets/luca-ui/templates/fields/hidden_field.js +4 -0
  221. data/vendor/assets/luca-ui/templates/fields/select_field.js +4 -0
  222. data/vendor/assets/luca-ui/templates/fields/text_area_field.js +4 -0
  223. data/vendor/assets/luca-ui/templates/fields/text_field.js +4 -0
  224. data/vendor/assets/luca-ui/templates/sample/contents.js +4 -0
  225. data/vendor/assets/luca-ui/templates/sample/welcome.js +4 -0
  226. data/vendor/assets/stylesheets/luca-spec-dependencies.css +166 -0
  227. data/vendor/assets/stylesheets/luca-ui-bootstrap.css +1201 -0
  228. data/vendor/assets/stylesheets/luca-ui-spec.css +586 -0
  229. data/vendor/assets/stylesheets/luca-ui.css +586 -0
  230. data/views/index.erb +20 -0
  231. data/views/jasmine.erb +22 -0
  232. data/views/spec_harness.erb +29 -0
  233. metadata +361 -0
@@ -0,0 +1,256 @@
1
+ #### The Component Container
2
+ #
3
+ # The Component Container is a nestable component
4
+ # which is responsible for laying out the many components
5
+ # it contains, assigning them to a DOM container, and
6
+ # automatically instantiating and rendering the components
7
+ # in their proper place.
8
+ Luca.core.Container = Luca.View.extend
9
+ className: 'luca-ui-container'
10
+
11
+ componentClass: 'luca-ui-panel'
12
+
13
+ isContainer: true
14
+
15
+ hooks:[
16
+ "before:components",
17
+ "before:layout",
18
+ "after:components",
19
+ "after:layout",
20
+ "first:activation"
21
+ ]
22
+
23
+ rendered: false
24
+
25
+ components: []
26
+
27
+ initialize: (@options={})->
28
+ _.extend @, @options
29
+
30
+ @setupHooks( Luca.core.Container::hooks )
31
+
32
+ Luca.View::initialize.apply @, arguments
33
+
34
+ #### Rendering Pipeline
35
+ #
36
+ # A container has nested components. these components
37
+ # are automatically rendered inside their own DOM element
38
+ # and then CSS configuration is generally applied to these
39
+ # DOM elements. Each component is assigned to this DOM
40
+ # element by specifying a @container property on the component.
41
+ #
42
+ # Each component is instantiated by looking up its @ctype propery
43
+ # in the Luca Component Registry. Then the components are rendered
44
+ # by having their @render() method called on them.
45
+ #
46
+ # Any class which extends Luca.View will have its defined render method
47
+ # wrapped in a method which triggers "before:render", and "after:render"
48
+ # before and after the defined render method.
49
+ #
50
+ # so you can expect the following, for any container or nested container
51
+ #
52
+ # DOM Element Manipulation:
53
+ #
54
+ # beforeRender()
55
+ # beforeLayout()
56
+ # prepareLayout()
57
+ # afterLayout()
58
+ #
59
+ # Luca / Backbone Component Manipulation
60
+ #
61
+ # beforeComponents()
62
+ # prepareComponents()
63
+ # createComponents()
64
+ # renderComponents() ->
65
+ # calls render() on each component, starting this whole cycle
66
+ #
67
+ # afterComponents()
68
+ #
69
+ # DOM Injection
70
+ #
71
+ # render()
72
+ # afterRender()
73
+ #
74
+ # For Components which are originally hidden
75
+ # ( card view, tab view, etc )
76
+ #
77
+ # firstActivation()
78
+ #
79
+ beforeRender: ()->
80
+ @debug "container before render"
81
+ @doLayout()
82
+ @doComponents()
83
+
84
+ doLayout: ()->
85
+ @debug "container do layout"
86
+ @trigger "before:layout", @
87
+ @prepareLayout()
88
+ @trigger "after:layout", @
89
+
90
+ doComponents: ()->
91
+ @debug "container do components"
92
+
93
+ @trigger "before:components", @, @components
94
+ @prepareComponents()
95
+ @createComponents()
96
+ @renderComponents()
97
+ @trigger "after:components", @, @components
98
+
99
+ applyPanelConfig: (panel, panelIndex)->
100
+ style_declarations = []
101
+
102
+ style_declarations.push "height: #{ (if _.isNumber(panel.height) then panel.height + 'px' else panel.height ) }" if panel.height
103
+ style_declarations.push "width: #{ (if _.isNumber(panel.width) then panel.width + 'px' else panel.width ) }" if panel.width
104
+ style_declarations.push "float: #{ panel.float }" if panel.float
105
+
106
+ config =
107
+ classes: panel?.classes || @componentClass
108
+ id: "#{ @cid }-#{ panelIndex }"
109
+ style: style_declarations.join(';')
110
+
111
+ # prepare layout is where you would perform the DOM element
112
+ # creation / manipulation for how your container lays out
113
+ # its components. Minimally you will want to set the
114
+ # container property on each component.
115
+ prepareLayout: ()->
116
+ @debug "container prepare layout"
117
+ @componentContainers = _( @components ).map (component, index) =>
118
+ @applyPanelConfig.apply @, [ component, index ]
119
+
120
+ if @appendContainers
121
+ _( @componentContainers ).each (container)=>
122
+ @$el.append Luca.templates["containers/basic"](container)
123
+
124
+ # prepare components is where you would set necessary object
125
+ # attributes on the components themselves.
126
+ prepareComponents: ()->
127
+ @debug "container prepare components"
128
+ @components = _( @components ).map (object, index) =>
129
+ panel = @componentContainers[ index ]
130
+ object.container = if @appendContainers then "##{ panel.id }" else @el
131
+
132
+ object
133
+
134
+ createComponents: ()->
135
+ @debug "container create components"
136
+ map = @componentIndex =
137
+ name_index: {}
138
+ cid_index: {}
139
+
140
+ @components = _( @components ).map (object, index)=>
141
+ # you can include normal backbone views as components
142
+ # you will want to make sure your render method handles
143
+ # adding the views @$el to the appropriate @container
144
+ component = if _.isObject( object ) and object.render and object.trigger
145
+ object
146
+ else
147
+ object.ctype ||= Luca.defaultComponentType || "template"
148
+ Luca.util.lazyComponent( object )
149
+
150
+ # if we're using base backbone views, then they don't extend themselves
151
+ # with their passed options, so this is a workaround
152
+ if !component.container and component.options.container
153
+ component.container = component.options.container
154
+
155
+ if map and component.cid?
156
+ map.cid_index[ component.cid ] = index
157
+
158
+ if map and component.name?
159
+ map.name_index[ component.name ] = index
160
+
161
+ component
162
+
163
+ @debug "components created", @components
164
+ # Trigger the Rendering Pipeline process on all of the nested
165
+ # components
166
+ renderComponents: (@debugMode="")->
167
+ @debug "container render components"
168
+ _(@components).each (component)=>
169
+ component.getParent = ()=> @
170
+ $( component.container ).append $(component.el)
171
+
172
+ try
173
+ component.render()
174
+ catch e
175
+ console.log "Error Rendering Component #{ component.name || component.cid }", component
176
+ console.log e.message
177
+ console.log e.stack
178
+
179
+ #### Container Activation
180
+ #
181
+ # When a container is first activated is a good time to perform
182
+ # operations which are not needed unless that component becomes
183
+ # visible. This first activation event should be relayed to all
184
+ # of the nested components. Components which hide / display
185
+ # other components, such as a CardView or TabContainer
186
+ # will trigger first:activation on the components as they become
187
+ # displayed.
188
+ firstActivation: ()->
189
+ _( @components ).each (component)=>
190
+ activator = @
191
+
192
+ # apply the first:activation trigger on the component, in the context of the component
193
+ # passing as arguments the component itself, and the component doing the activation
194
+ unless component?.previously_activated is true
195
+ component?.trigger?.apply component, ["first:activation", [component, activator] ]
196
+ component.previously_activated = true
197
+
198
+ #### Component Finder Methods
199
+ select: (attribute, value, deep=false)->
200
+ components = _( @components ).map (component)->
201
+ matches = []
202
+ test = component[ attribute ]
203
+
204
+ matches.push( component ) if test is value
205
+
206
+ if deep is true and component.isContainer is true
207
+ matches.push component.select(attribute, value, true)
208
+
209
+ _.compact matches
210
+
211
+ _.flatten( components )
212
+
213
+ findComponentByName: (name, deep=false)->
214
+ @findComponent(name, "name_index", deep)
215
+
216
+ findComponentById: (id, deep=false)->
217
+ @findComponent(id, "cid_index", deep)
218
+
219
+ findComponent: (needle, haystack="name", deep=false)->
220
+ position = @componentIndex?[ haystack ][ needle ]
221
+ component = @components?[ position ]
222
+
223
+ return component if component
224
+
225
+ if deep is true
226
+ sub_container = _( @components ).detect (component)-> component?.findComponent?(needle, haystack, true)
227
+ sub_container?.findComponent?(needle, haystack, true)
228
+
229
+ # run a function for each component in this container
230
+ # and any nested containers in those components, recursively
231
+ # pass false as the second argument to skip the deep recursion
232
+ eachComponent: (fn, deep=true)->
233
+ _( @components ).each (component)=>
234
+ fn.apply component, [component]
235
+ component?.eachComponent?.apply component, [fn,deep] if deep
236
+
237
+ indexOf: (name)->
238
+ names = _( @components ).pluck('name')
239
+ _( names ).indexOf(name)
240
+
241
+ activeComponent: ()->
242
+ return @ unless @activeItem
243
+ return @components[ @activeItem ]
244
+
245
+ componentElements: ()-> $(".#{ @componentClass }", @el)
246
+
247
+ getComponent: (needle)->
248
+ @components[ needle ]
249
+
250
+ rootComponent: ()->
251
+ !@getParent?
252
+
253
+ getRootComponent: ()->
254
+ if @rootComponent() then @ else @getParent().getRootComponent()
255
+
256
+ Luca.register "container", "Luca.core.Container"
@@ -0,0 +1,68 @@
1
+ Luca.core.Field = Luca.View.extend
2
+ className: 'luca-ui-text-field luca-ui-field'
3
+
4
+ isField: true
5
+
6
+ template: 'fields/text_field'
7
+
8
+ labelAlign: 'top'
9
+
10
+ hooks:[
11
+ "before:validation",
12
+ "after:validation",
13
+ "on:change"
14
+ ]
15
+
16
+ # see: http://twitter.github.com/bootstrap/base-css.html
17
+ statuses: [
18
+ "warning"
19
+ "error"
20
+ "success"
21
+ ]
22
+
23
+ initialize: (@options={})->
24
+ _.extend @, @options
25
+ Luca.View::initialize.apply(@, arguments)
26
+
27
+ @input_id ||= _.uniqueId('field')
28
+ @input_name ||= @name
29
+ @helperText ||= ""
30
+ @label ||= "*#{ @label }" if @required and not @label?.match(/^\*/)
31
+ @inputStyles ||= ""
32
+
33
+ @disable() if @disabled
34
+
35
+ @updateState( @state )
36
+ @placeHolder ||= ""
37
+
38
+ beforeRender: ()->
39
+ if Luca.enableBootstrap
40
+ @$el.addClass('control-group')
41
+
42
+ @$el.addClass('required') if @required
43
+
44
+ @$el.html Luca.templates[ @template ]( @ )
45
+ @input = $('input', @el)
46
+
47
+ change_handler: (e)->
48
+ @trigger "on:change", @, e
49
+
50
+ disable: ()->
51
+ $("input",@el).attr('disabled', true)
52
+
53
+ enable: ()->
54
+ $("input", @el).attr('disabled', false)
55
+
56
+ getValue: ()->
57
+ @input.attr('value')
58
+
59
+ render: ()->
60
+ $( @container ).append( @$el )
61
+
62
+ setValue: (value)->
63
+ @input.attr('value', value)
64
+
65
+ updateState: (state)->
66
+ _( @statuses ).each (cls)=>
67
+ @$el.removeClass(cls)
68
+ @$el.addClass(state)
@@ -0,0 +1,17 @@
1
+ class Luca.Observer
2
+ constructor: (@options={})->
3
+ _.extend @, Backbone.Events
4
+ @type = @options.type
5
+
6
+ if @options.debugAll
7
+ @bind "event", (t, args...)=>
8
+ console.log "Observed #{ @type } #{ (t.name || t.id || t.cid) }", t, _(args).flatten()
9
+
10
+ relay: (triggerer, args...)->
11
+ @trigger "event", triggerer, args
12
+ @trigger "event:#{ args[0] }", triggerer, args.slice(1)
13
+
14
+ Luca.Observer.enableObservers = (options={})->
15
+ Luca.enableGlobalObserver = true
16
+ Luca.ViewObserver = new Luca.Observer _.extend(options, type:"view")
17
+ Luca.CollectionObserver = new Luca.Observer _.extend(options, type:"collection")
@@ -0,0 +1,190 @@
1
+ #### Luca Base View
2
+ Luca.View = Backbone.View.extend
3
+ base: 'Luca.View'
4
+
5
+ # The Luca.View class adds some very commonly used patterns
6
+ # and functionality to the stock Backbone.View class. Features
7
+ # such as auto event binding, the facilitation of deferred rendering
8
+ # against a Backbone.Model or Backbone.Collection reset event, Caching
9
+ # views into a global Component Registry, and more.
10
+
11
+ Luca.View.originalExtend = Backbone.View.extend
12
+
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
+
34
+ $(container).append( @$el )
35
+ @
36
+
37
+
38
+ definition.render = ()->
39
+ if @deferrable
40
+ @trigger "before:render", @
41
+
42
+ @deferrable.bind @deferrable_event, _.once ()=>
43
+ _base.apply(@, arguments)
44
+ @trigger "after:render", @
45
+
46
+ # we might not want to fetch immediately upon
47
+ # rendering, so we can pass a deferrable_trigger
48
+ # event and not fire the fetch until this event
49
+ # occurs
50
+ if !@deferrable_trigger
51
+ @immediate_trigger = true
52
+
53
+ if @immediate_trigger is true
54
+ @deferrable.fetch()
55
+ else
56
+ @bind @deferrable_trigger, _.once ()=>
57
+ @deferrable.fetch()
58
+
59
+ else
60
+ @trigger "before:render", @
61
+ _base.apply(@, arguments)
62
+ @trigger "after:render", @
63
+
64
+ Luca.View.originalExtend.apply @, [definition]
65
+
66
+ _.extend Luca.View.prototype,
67
+ debug: ()->
68
+ return unless @debugMode or window.LucaDebugMode?
69
+ console.log [(@name || @cid),message] for message in arguments
70
+
71
+ trigger: ()->
72
+ if Luca.enableGlobalObserver
73
+ Luca.ViewObserver ||= new Luca.Observer(type:"view")
74
+ Luca.ViewObserver.relay @, arguments
75
+
76
+ Backbone.View.prototype.trigger.apply @, arguments
77
+
78
+ hooks:[
79
+ "after:initialize"
80
+ "before:render"
81
+ "after:render"
82
+ "first:activation"
83
+ "activation"
84
+ "deactivation"
85
+ ]
86
+
87
+ # which event should we listen to on
88
+ # our deferrable property, before we
89
+ # trigger the actual rendering
90
+ deferrable_event: "reset"
91
+
92
+ initialize: (@options={})->
93
+
94
+ _.extend @, @options
95
+
96
+ @cid = _.uniqueId(@name) if @name?
97
+
98
+ #### View Caching
99
+ #
100
+ # Luca.View(s) which get created get stored in a global cache by their
101
+ # component id. This allows us to re-use views when it makes sense
102
+ Luca.cache( @cid, @ )
103
+
104
+ unique = _( Luca.View.prototype.hooks.concat( @hooks ) ).uniq()
105
+
106
+ @setupHooks( unique )
107
+
108
+ if @autoBindEventHandlers is true
109
+ _( @events ).each (handler,event)=>
110
+ if _.isString(handler)
111
+ _.bindAll @, handler
112
+
113
+
114
+ @trigger "after:initialize", @
115
+
116
+ @registerCollectionEvents()
117
+
118
+ $container: ()-> $(@container)
119
+ #### Hooks or Auto Event Binding
120
+ #
121
+ # views which inherit from Luca.View can define hooks
122
+ # or events which can be emitted from them. Automatically,
123
+ # any functions on the view which are named according to the
124
+ # convention will automatically get run.
125
+ #
126
+ # by default, all Luca.View classes come with the following:
127
+ #
128
+ # before:render : beforeRender()
129
+ # after:render : afterRender()
130
+ # after:initialize : afterInitialize()
131
+ # first:activation : firstActivation()
132
+ setupHooks: (set)->
133
+ set ||= @hooks
134
+
135
+ _(set).each (event)=>
136
+ parts = event.split(':')
137
+ prefix = parts.shift()
138
+
139
+ parts = _( parts ).map (p)-> _.capitalize(p)
140
+ fn = prefix + parts.join('')
141
+
142
+ @bind event, ()=> @[fn].apply @, arguments if @[fn]
143
+
144
+
145
+ #### Luca.Collection and Luca.CollectionManager integration
146
+
147
+ # under the hood, this will find your collection manager using
148
+ # Luca.CollectionManager.get, which is a function that returns
149
+ # the first instance of the CollectionManager class ever created.
150
+ #
151
+ # if you want to use more than one collection manager, over ride this
152
+ # function in your views with your own logic
153
+ getCollectionManager: ()->
154
+ @collectionManager || Luca.CollectionManager.get?.call()
155
+
156
+ ##### Collection Events
157
+ #
158
+ # By defining a hash of collectionEvents in the form of
159
+ #
160
+ # "books add" : "onBookAdd"
161
+ #
162
+ # the Luca.View will bind to the collection found in the
163
+ # collectionManager with that key, and bind to that event.
164
+ # a property of @booksCollection will be created on the view,
165
+ # and the "add" event will trigger "onBookAdd"
166
+ #
167
+ # you may also specify a function directly. this
168
+ #
169
+ registerCollectionEvents: ()->
170
+ manager = @getCollectionManager()
171
+
172
+ _( @collectionEvents ).each (handler, signature)=>
173
+ [key,event] = signature.split(" ")
174
+
175
+ collection = @["#{ key }Collection"] = manager.getOrCreate( key )
176
+
177
+ if !collection
178
+ throw "Could not find collection specified by #{ key }"
179
+
180
+ if _.isString(handler)
181
+ handler = @[handler]
182
+
183
+ unless _.isFunction(handler)
184
+ throw "invalid collectionEvents configuration"
185
+
186
+ try
187
+ collection.bind(event, handler)
188
+ catch e
189
+ console.log "Error Binding To Collection in registerCollectionEvents", @
190
+ throw e
@@ -0,0 +1,110 @@
1
+ _.mixin( _.string )
2
+
3
+ window.Luca =
4
+ VERSION: "0.6.6"
5
+ core: {}
6
+ containers: {}
7
+ components: {}
8
+ modules: {}
9
+ fields: {}
10
+ util: {}
11
+ registry:
12
+ classes: {}
13
+ namespaces:["Luca.containers","Luca.components"]
14
+ component_cache:
15
+ cid_index: {}
16
+ name_index: {}
17
+
18
+
19
+ # let's use the Twitter 2.0 Bootstrap Framework
20
+ # for what it is best at, and not try to solve this
21
+ # problem on our own!
22
+ Luca.enableBootstrap = true
23
+
24
+ # adds an additional namespace to look for luca ui
25
+ # components. useful for when you define a bunch of
26
+ # components in your own application's namespace
27
+ Luca.registry.addNamespace = (identifier)->
28
+ Luca.registry.namespaces.push( identifier )
29
+ Luca.registry.namespaces = _( Luca.registry.namespaces ).uniq()
30
+
31
+ # stores or looks up a component in the component cache
32
+ # by its backbone @cid or by its component_name
33
+ Luca.cache = (needle, component)->
34
+ Luca.component_cache.cid_index[ needle ] = component if component?
35
+
36
+ component = Luca.component_cache.cid_index[ needle ]
37
+
38
+ # optionally, cache it by tying its name to its cid for easier lookups
39
+ if component?.component_name?
40
+ Luca.component_cache.name_index[ component.component_name ] = component.cid
41
+ else if component?.name?
42
+ Luca.component_cache.name_index[ component.name ] = component.cid
43
+
44
+ return component if component?
45
+
46
+ # perform a lookup by name if the component_id didn't turn anything
47
+ lookup_id = Luca.component_cache.name_index[ needle ]
48
+
49
+ Luca.component_cache.cid_index[ lookup_id ]
50
+
51
+ # Takes an string like "deep.nested.value" and an object like window
52
+ # and returns the value of window.deep.nested.value
53
+ Luca.util.nestedValue = (accessor, source_object)->
54
+ _( accessor.split(/\./) ).inject (obj,key)->
55
+ obj = obj?[key]
56
+ , source_object
57
+
58
+ # Lookup a component in the Luca component registry
59
+ # by it's ctype identifier. If it doesn't exist,
60
+ # check any other registered namespace
61
+ Luca.registry.lookup = (ctype)->
62
+ c = Luca.registry.classes[ctype]
63
+
64
+ return c if c?
65
+
66
+ className = _.camelize _.capitalize( ctype )
67
+
68
+ parents = _( Luca.registry.namespaces ).map (namespace)-> Luca.util.nestedValue(namespace, (window || global))
69
+
70
+ _.first _.compact _( parents ).map (parent)-> parent[className]
71
+
72
+ # creates a new object from a hash with a ctype property
73
+ # matching something in the Luca registry
74
+ Luca.util.lazyComponent = (config)->
75
+ ctype = config.ctype
76
+
77
+ componentClass = Luca.registry.lookup( ctype )
78
+
79
+ throw "Invalid Component Type: #{ ctype }. Did you forget to register it?" unless componentClass
80
+
81
+ constructor = eval( componentClass )
82
+
83
+ new constructor(config)
84
+
85
+ # for lazy component creation
86
+ Luca.register = (component, constructor_class)->
87
+ exists = Luca.registry.classes[component]
88
+
89
+ if exists?
90
+ throw "Can not register component with the signature #{ component }. Already exists"
91
+ else
92
+ Luca.registry.classes[component] = constructor_class
93
+
94
+ Luca.available_templates = (filter="")->
95
+ available = _( Luca.templates ).keys()
96
+
97
+ if filter.length > 0
98
+ _( available ).select (tmpl)-> tmpl.match(filter)
99
+ else
100
+ available
101
+
102
+ Luca.util.isIE = ()->
103
+ try
104
+ Object.defineProperty({}, '', {})
105
+ return false
106
+ catch e
107
+ return true
108
+
109
+ $ do ->
110
+ $('body').addClass('luca-ui-enabled')