luca 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (310) hide show
  1. data/CHANGELOG +49 -0
  2. data/Gemfile +8 -1
  3. data/Gemfile.lock +97 -53
  4. data/Guardfile +3 -25
  5. data/README.md +5 -16
  6. data/ROADMAP +15 -9
  7. data/Rakefile +24 -75
  8. data/app.rb +10 -42
  9. data/app/assets/javascripts/luca/basic.coffee +1 -1
  10. data/app/assets/javascripts/luca/components/application.coffee +187 -104
  11. data/app/assets/javascripts/luca/components/collection_view.coffee +115 -51
  12. data/app/assets/javascripts/luca/components/controller.coffee +87 -10
  13. data/app/assets/javascripts/luca/components/fields/base.coffee +74 -13
  14. data/app/assets/javascripts/luca/components/fields/button_field.coffee +60 -13
  15. data/app/assets/javascripts/luca/components/fields/checkbox_array.coffee +12 -7
  16. data/app/assets/javascripts/luca/components/fields/select_field.coffee +82 -23
  17. data/app/assets/javascripts/luca/components/fields/text_area_field.coffee +25 -10
  18. data/app/assets/javascripts/luca/components/fields/text_field.coffee +9 -3
  19. data/app/assets/javascripts/luca/components/form_view.coffee +105 -33
  20. data/app/assets/javascripts/luca/components/grid_layout_view.coffee +42 -0
  21. data/app/assets/javascripts/luca/components/index.coffee +6 -0
  22. data/app/assets/javascripts/luca/components/nav_bar.coffee +60 -6
  23. data/app/assets/javascripts/luca/components/page.coffee +70 -0
  24. data/app/assets/javascripts/luca/components/simple_collection_view.coffee +10 -0
  25. data/app/assets/javascripts/luca/components/table_view.coffee +7 -3
  26. data/app/assets/javascripts/luca/components/table_view_scrollable.coffee +23 -0
  27. data/app/assets/javascripts/luca/concerns/collection_event_bindings.coffee +4 -1
  28. data/app/assets/javascripts/luca/concerns/development_tool_helpers.coffee +23 -14
  29. data/app/assets/javascripts/luca/concerns/dom_helpers.coffee +2 -2
  30. data/app/assets/javascripts/luca/concerns/filterable.coffee +8 -11
  31. data/app/assets/javascripts/luca/concerns/form_model_bindings.coffee +20 -0
  32. data/app/assets/javascripts/luca/concerns/modal_view.coffee +40 -15
  33. data/app/assets/javascripts/luca/concerns/query_collection_bindings.coffee +7 -1
  34. data/app/assets/javascripts/luca/concerns/state_model.coffee +40 -26
  35. data/app/assets/javascripts/luca/concerns/templating.coffee +3 -1
  36. data/app/assets/javascripts/luca/config.coffee +5 -0
  37. data/app/assets/javascripts/luca/containers/card_view.coffee +87 -52
  38. data/app/assets/javascripts/luca/containers/container.coffee +305 -108
  39. data/app/assets/javascripts/luca/containers/modal_view.coffee +9 -9
  40. data/app/assets/javascripts/luca/containers/page_controller.coffee +25 -0
  41. data/app/assets/javascripts/luca/containers/panel_toolbar.coffee +5 -6
  42. data/app/assets/javascripts/luca/containers/tab_view.coffee +19 -10
  43. data/app/assets/javascripts/luca/containers/viewport.coffee +12 -16
  44. data/app/assets/javascripts/luca/core/collection.coffee +19 -5
  45. data/app/assets/javascripts/luca/core/events.coffee +5 -5
  46. data/app/assets/javascripts/luca/core/model.coffee +1 -1
  47. data/app/assets/javascripts/luca/core/panel.coffee +18 -6
  48. data/app/assets/javascripts/luca/core/registry/component_definition.coffee +2 -1
  49. data/app/assets/javascripts/luca/core/registry/meta_data.coffee +2 -0
  50. data/app/assets/javascripts/luca/core/registry/registry.coffee +14 -11
  51. data/app/assets/javascripts/luca/core/templates.coffee +5 -1
  52. data/app/assets/javascripts/luca/core/view.coffee +200 -47
  53. data/app/assets/javascripts/luca/dependencies.coffee +2 -0
  54. data/app/assets/javascripts/luca/development/code_sync_manager.coffee +173 -0
  55. data/app/assets/javascripts/luca/development/component.coffee +76 -0
  56. data/app/assets/javascripts/luca/development/components.coffee +57 -0
  57. data/app/assets/javascripts/luca/development/console.coffee +1 -1
  58. data/app/assets/javascripts/luca/development/index.coffee +4 -1
  59. data/app/assets/javascripts/luca/framework.coffee +7 -3
  60. data/app/assets/javascripts/luca/index.coffee +2 -1
  61. data/app/assets/javascripts/luca/managers/collection_manager.coffee +2 -3
  62. data/app/assets/javascripts/luca/managers/index.coffee +1 -1
  63. data/app/assets/javascripts/luca/managers/socket_manager.coffee +31 -8
  64. data/app/assets/javascripts/luca/templates/components/nav_bar.jst.ejs +16 -1
  65. data/app/assets/javascripts/luca/templates/containers/tab_view.jst.ejs +1 -1
  66. data/app/assets/javascripts/luca/util/index.coffee +1 -0
  67. data/app/assets/javascripts/luca/util/keybindings.coffee +24 -0
  68. data/app/assets/javascripts/luca/util/logging.coffee +15 -0
  69. data/app/assets/javascripts/luca/util/luca.coffee +9 -1
  70. data/app/assets/stylesheets/luca/components/table_view.scss +85 -0
  71. data/app/assets/stylesheets/luca/components/viewport.scss +0 -4
  72. data/app/assets/stylesheets/luca/containers/container.scss +8 -0
  73. data/app/assets/stylesheets/luca/index.css +2 -2
  74. data/bin/luca +14 -0
  75. data/config.ru +1 -2
  76. data/docs/framework.json +1 -0
  77. data/docs/luca-framework-documentation.js +1 -0
  78. data/docs/{application.md → old/application.md} +0 -0
  79. data/docs/{collection.md → old/collection.md} +0 -0
  80. data/docs/{collection_manager.md → old/collection_manager.md} +0 -0
  81. data/docs/{container_philosophy.md → old/container_philosophy.md} +0 -0
  82. data/docs/{event_binding_helpers.md → old/event_binding_helpers.md} +0 -0
  83. data/docs/{method_caching_and_computed_properties.md → old/method_caching_and_computed_properties.md} +0 -0
  84. data/docs/{view.md → old/view.md} +0 -0
  85. data/lib/generators/luca/application/templates/javascripts/dependencies.coffee +2 -5
  86. data/lib/guard/luca.rb +84 -0
  87. data/lib/luca.rb +25 -1
  88. data/lib/luca/asset_compiler.rb +117 -0
  89. data/lib/luca/cli.rb +68 -0
  90. data/lib/luca/cli/generate.rb +37 -0
  91. data/lib/luca/cli/server.rb +20 -0
  92. data/lib/luca/cli/sync.rb +40 -0
  93. data/lib/luca/cli/watch.rb +16 -0
  94. data/lib/luca/collection.rb +64 -0
  95. data/lib/luca/collection/endpoint.rb +38 -0
  96. data/lib/luca/collection/file_backend.rb +121 -0
  97. data/lib/luca/collection/redis_backend.rb +153 -0
  98. data/lib/luca/compiled_asset.rb +61 -0
  99. data/lib/luca/component_definition.rb +356 -0
  100. data/lib/luca/luca_application.rb +258 -0
  101. data/lib/luca/project.rb +73 -0
  102. data/lib/luca/project_harness.rb +96 -0
  103. data/lib/luca/rails.rb +5 -3
  104. data/lib/luca/rails/engine.rb +8 -0
  105. data/lib/luca/rails/version.rb +1 -2
  106. data/lib/luca/server.rb +7 -0
  107. data/lib/luca/stylesheet.rb +35 -0
  108. data/lib/luca/template.rb +2 -0
  109. data/lib/luca/template_asset.rb +64 -0
  110. data/lib/luca/version.rb +3 -0
  111. data/lib/luca/watcher.rb +72 -0
  112. data/lib/railties/luca/tasks.rake +7 -0
  113. data/site/.bundle/config +2 -0
  114. data/site/.gitignore +5 -0
  115. data/site/.rvmrc +1 -0
  116. data/site/CHANGELOG.md +41 -0
  117. data/site/DOCS.md +41 -0
  118. data/site/Gemfile +8 -0
  119. data/site/Gemfile.lock +134 -0
  120. data/site/LICENSE.md +19 -0
  121. data/site/config.rb +84 -0
  122. data/site/helpers/site_helpers.rb +20 -0
  123. data/site/html5bp-docs/README.md +38 -0
  124. data/site/html5bp-docs/contribute.md +104 -0
  125. data/site/html5bp-docs/crossdomain.md +21 -0
  126. data/site/html5bp-docs/css.md +135 -0
  127. data/site/html5bp-docs/extend.md +507 -0
  128. data/site/html5bp-docs/faq.md +77 -0
  129. data/site/html5bp-docs/htaccess.md +323 -0
  130. data/site/html5bp-docs/html.md +170 -0
  131. data/site/html5bp-docs/js.md +31 -0
  132. data/site/html5bp-docs/misc.md +25 -0
  133. data/site/html5bp-docs/usage.md +109 -0
  134. data/site/readme.md +47 -0
  135. data/site/source/.htaccess +540 -0
  136. data/site/source/404.html +157 -0
  137. data/site/source/app/assets/javascripts/dependencies.js.coffee +6 -0
  138. data/site/source/app/assets/javascripts/docs-docs.js +1 -0
  139. data/site/source/app/assets/javascripts/docs/application.coffee +64 -0
  140. data/site/source/app/assets/javascripts/docs/collections/docs_documentation.coffee +17 -0
  141. data/site/source/app/assets/javascripts/docs/collections/github_repositories.coffee +7 -0
  142. data/site/source/app/assets/javascripts/docs/collections/index.coffee +1 -0
  143. data/site/source/app/assets/javascripts/docs/collections/luca_documentation.coffee +17 -0
  144. data/site/source/app/assets/javascripts/docs/collections/public_gists.coffee +4 -0
  145. data/site/source/app/assets/javascripts/docs/config.coffee +5 -0
  146. data/site/source/app/assets/javascripts/docs/index.coffee +12 -0
  147. data/site/source/app/assets/javascripts/docs/lib/router.coffee +3 -0
  148. data/{spec/components/application_spec.coffee → site/source/app/assets/javascripts/docs/lib/util.coffee} +0 -0
  149. data/site/source/app/assets/javascripts/docs/models/component.coffee +99 -0
  150. data/site/source/app/assets/javascripts/docs/models/github_repository.coffee +3 -0
  151. data/site/source/app/assets/javascripts/docs/models/index.coffee +1 -0
  152. data/site/source/app/assets/javascripts/docs/templates/component_documentation.jst.ejs +55 -0
  153. data/site/source/app/assets/javascripts/docs/templates/examples_browser/overview.jst.ejs +4 -0
  154. data/site/source/app/assets/javascripts/docs/templates/examples_browser/selector.jst.ejs +11 -0
  155. data/site/source/app/assets/javascripts/docs/templates/github_repository.jst.ejs +4 -0
  156. data/site/source/app/assets/javascripts/docs/templates/layouts/main.jst.ejs +4 -0
  157. data/site/source/app/assets/javascripts/docs/templates/left_navigation.jst.ejs +5 -0
  158. data/site/source/app/assets/javascripts/docs/templates/pages/getting_started.jst.ejs +78 -0
  159. data/site/source/app/assets/javascripts/docs/templates/pages/home.jst.ejs +57 -0
  160. data/site/source/app/assets/javascripts/docs/views/components/code_editor.coffee +45 -0
  161. data/{spec/components/collection_loader_view_spec.coffee → site/source/app/assets/javascripts/docs/views/components/code_editor/index.coffee} +0 -0
  162. data/site/source/app/assets/javascripts/docs/views/components/component_documentation.coffee +72 -0
  163. data/site/source/app/assets/javascripts/docs/views/index.coffee +3 -0
  164. data/site/source/app/assets/javascripts/docs/views/pages/browse_source.coffee +46 -0
  165. data/site/source/app/assets/javascripts/docs/views/pages/browse_source/details.coffee +37 -0
  166. data/site/source/app/assets/javascripts/docs/views/pages/browse_source/list.coffee +31 -0
  167. data/site/source/app/assets/javascripts/docs/views/pages/component_editor.coffee +10 -0
  168. data/site/source/app/assets/javascripts/docs/views/pages/examples_browser.coffee +102 -0
  169. data/site/source/app/assets/javascripts/docs/views/pages/examples_browser/docs.coffee +12 -0
  170. data/site/source/app/assets/javascripts/docs/views/pages/examples_browser/source.coffee +13 -0
  171. data/site/source/app/assets/javascripts/docs/views/pages/home.coffee +10 -0
  172. data/site/source/app/assets/javascripts/docs/views/views/api_browser/index.coffee +43 -0
  173. data/site/source/app/assets/javascripts/docs/views/views/collection_view_examples/grid_layout_view_example.coffee +14 -0
  174. data/site/source/app/assets/javascripts/docs/views/views/collection_view_examples/table_view_example.coffee +39 -0
  175. data/site/source/app/assets/javascripts/docs/views/views/form_view_examples/basic_example.coffee +38 -0
  176. data/site/source/app/assets/javascripts/docs/views/views/form_view_examples/complex_layout.coffee +110 -0
  177. data/site/source/app/assets/javascripts/docs/views/views/top_navigation.coffee +6 -0
  178. data/site/source/app/assets/javascripts/luca-docs.js +1 -0
  179. data/site/source/app/assets/javascripts/luca-framework-documentation.js +1 -0
  180. data/site/source/app/assets/javascripts/site.js.coffee +4 -0
  181. data/site/source/app/assets/javascripts/vendor/codemirror.js +4786 -0
  182. data/site/source/app/assets/javascripts/vendor/coffeescript.js +346 -0
  183. data/site/source/app/assets/javascripts/vendor/css.js +465 -0
  184. data/site/source/app/assets/javascripts/vendor/htmlmixed.js +84 -0
  185. data/site/source/app/assets/javascripts/vendor/javascript.js +422 -0
  186. data/site/source/app/assets/javascripts/vendor/js-beautify.js +1353 -0
  187. data/site/source/app/assets/javascripts/vendor/modernizr-2.6.1.min.js +4 -0
  188. data/site/source/app/assets/javascripts/vendor/vim.js +2511 -0
  189. data/site/source/app/assets/stylesheets/docs/api-browser.css.scss +5 -0
  190. data/site/source/app/assets/stylesheets/docs/application.css.scss +35 -0
  191. data/site/source/app/assets/stylesheets/docs/browse-source.css.scss +5 -0
  192. data/site/source/app/assets/stylesheets/docs/scrollable-table.css.scss +5 -0
  193. data/site/source/app/assets/stylesheets/site.css.scss +2 -0
  194. data/site/source/app/assets/stylesheets/vendor/codemirror.css +240 -0
  195. data/site/source/app/assets/stylesheets/vendor/prettify-tomorrow-night-bright.css +160 -0
  196. data/site/source/app/assets/stylesheets/vendor/twilight.css +26 -0
  197. data/site/source/crossdomain.xml +15 -0
  198. data/site/source/documentation.html.haml +1 -0
  199. data/site/source/favicon_base.png +0 -0
  200. data/site/source/humans.txt +15 -0
  201. data/site/source/images/background.png +0 -0
  202. data/site/source/images/middleman.png +0 -0
  203. data/site/source/index.html.haml +1 -0
  204. data/site/source/layouts/layout.haml +55 -0
  205. data/site/source/readme.md +63 -0
  206. data/site/source/robots.txt +3 -0
  207. data/spec/{components/grid_view_spec.coffee → javascripts/components/application_spec.coffee} +0 -0
  208. data/spec/{components/pagination_control_spec.coffee → javascripts/components/collection_loader_view_spec.coffee} +0 -0
  209. data/spec/{components → javascripts/components}/collection_view_spec.coffee +1 -1
  210. data/spec/{components → javascripts/components}/controller_spec.coffee +0 -0
  211. data/spec/{components → javascripts/components}/fields/checkbox_array_spec.coffee +0 -0
  212. data/spec/javascripts/components/form_view_spec.coffee +162 -0
  213. data/spec/{components/record_manager_spec.coffee → javascripts/components/grid_view_spec.coffee} +0 -0
  214. data/spec/{components → javascripts/components}/multi_collection_view_spec.coffee +0 -0
  215. data/spec/{components/template_spec.coffee → javascripts/components/pagination_control_spec.coffee} +0 -0
  216. data/spec/{concerns/paginatable_spec.coffee → javascripts/components/record_manager_spec.coffee} +0 -0
  217. data/spec/{components → javascripts/components}/table_view_spec.coffee +0 -0
  218. data/spec/{containers/modal_view_spec.coffee → javascripts/components/template_spec.coffee} +0 -0
  219. data/spec/{concerns → javascripts/concerns}/collection_event_bindings_spec.coffee +0 -0
  220. data/spec/{concerns → javascripts/concerns}/dom_helpers_spec.coffee +0 -0
  221. data/spec/{concerns → javascripts/concerns}/filterable_spec.coffee +0 -0
  222. data/spec/{concerns → javascripts/concerns}/model_presenter_spec.coffee +0 -0
  223. data/spec/{containers/panel_view_spec.coffee → javascripts/concerns/paginatable_spec.coffee} +0 -0
  224. data/spec/{concerns → javascripts/concerns}/state_model_spec.coffee +5 -0
  225. data/spec/javascripts/containers/card_view_spec.coffee +108 -0
  226. data/spec/{containers/tab_view_spec.coffee → javascripts/containers/modal_view_spec.coffee} +0 -0
  227. data/spec/{containers/viewport_spec.coffee → javascripts/containers/panel_view_spec.coffee} +0 -0
  228. data/spec/{core/observer_spec.coffee → javascripts/containers/tab_view_spec.coffee} +0 -0
  229. data/spec/{managers/socket_manager_spec.coffee → javascripts/containers/viewport_spec.coffee} +0 -0
  230. data/spec/{core → javascripts/core}/collection_spec.coffee +1 -1
  231. data/spec/{core → javascripts/core}/concerns_spec.coffee +0 -0
  232. data/spec/{core → javascripts/core}/container_spec.coffee +0 -0
  233. data/spec/{core → javascripts/core}/define_spec.coffee +0 -0
  234. data/spec/{core → javascripts/core}/events_spec.coffee +0 -0
  235. data/spec/{core → javascripts/core}/field_spec.coffee +0 -0
  236. data/spec/{core → javascripts/core}/framework_spec.coffee +0 -0
  237. data/spec/{core → javascripts/core}/model_spec.coffee +0 -0
  238. data/spec/javascripts/core/observer_spec.coffee +0 -0
  239. data/spec/{core → javascripts/core}/util_spec.coffee +0 -0
  240. data/spec/{core → javascripts/core}/view_spec.coffee +51 -39
  241. data/spec/{dependencies → javascripts/dependencies}/index.coffee +0 -0
  242. data/spec/{dependencies → javascripts/dependencies}/jasmine-html.js +0 -0
  243. data/spec/{dependencies → javascripts/dependencies}/jasmine.js +0 -0
  244. data/spec/{dependencies → javascripts/dependencies}/sinon.js +0 -0
  245. data/spec/{helper.coffee → javascripts/helper.coffee} +0 -0
  246. data/spec/{managers → javascripts/managers}/collection_manager_spec.coffee +0 -0
  247. data/spec/javascripts/managers/socket_manager_spec.coffee +0 -0
  248. data/spec/lib/component_definition_spec.rb +63 -0
  249. data/spec/lib/input_compiler_spec.rb +9 -0
  250. data/spec/lib/luca_application_spec.rb +30 -0
  251. data/spec/support/fixtures/application.coffee +45 -0
  252. data/spec/support/fixtures/component.coffee +34 -0
  253. data/tutorials/component-definitions.md +0 -0
  254. data/tutorials/component-definitions/01_intro.md +0 -0
  255. data/tutorials/component-driven-design.md +140 -0
  256. data/tutorials/structure-of-a-project.md +63 -0
  257. data/vendor/assets/javascripts/backbone-min.js +37 -33
  258. data/vendor/assets/javascripts/backbone-query.min.js +1 -1
  259. data/vendor/assets/javascripts/hogan.js +707 -0
  260. data/vendor/assets/javascripts/jquery.js +5 -4
  261. data/vendor/assets/javascripts/keymaster.min.js +4 -0
  262. data/vendor/assets/javascripts/luca-dependencies.min.js +8 -0
  263. data/vendor/assets/javascripts/luca-development.min.js +1 -0
  264. data/vendor/assets/javascripts/luca-spec.js +6 -6
  265. data/vendor/assets/javascripts/luca-ui.js +7386 -0
  266. data/vendor/assets/javascripts/luca-ui.min.js +5 -0
  267. data/vendor/assets/javascripts/luca.full.min.js +12 -0
  268. data/vendor/assets/javascripts/luca.min.js +5 -0
  269. data/vendor/assets/javascripts/underscore-min.js +1 -5
  270. data/vendor/assets/javascripts/underscore-string.min.js +1 -1
  271. data/vendor/assets/stylesheets/luca-components.css +202 -0
  272. data/vendor/assets/stylesheets/luca-development.css +23 -0
  273. data/vendor/assets/stylesheets/luca-ui.css +198 -0
  274. metadata +324 -94
  275. data/app/assets/javascripts/luca/components/base_toolbar.coffee +0 -17
  276. data/app/assets/javascripts/luca/components/form_button_toolbar.coffee +0 -28
  277. data/app/assets/javascripts/luca/components/grid_view.coffee +0 -269
  278. data/app/assets/javascripts/luca/components/page_controller.coffee +0 -7
  279. data/app/assets/javascripts/luca/components/template.coffee +0 -5
  280. data/app/assets/javascripts/luca/components/toolbar_dialog.coffee +0 -25
  281. data/lib/luca/code_browser.rb +0 -55
  282. data/lib/luca/command_line.rb +0 -69
  283. data/lib/luca/component_documentation.rb +0 -72
  284. data/site/assets/bootstrap.min.js +0 -7
  285. data/site/assets/dependencies.js +0 -94
  286. data/site/assets/glyphicons-halflings-white.png +0 -0
  287. data/site/assets/glyphicons-halflings.png +0 -0
  288. data/site/assets/luca-ui-bootstrap.css +0 -1331
  289. data/site/assets/luca-ui-bootstrap.js +0 -9
  290. data/site/assets/luca-ui-development-tools.css +0 -234
  291. data/site/assets/luca-ui-development-tools.js +0 -18561
  292. data/site/assets/luca-ui-development-tools.min.js +0 -15
  293. data/site/assets/luca-ui-full.min.js +0 -8
  294. data/site/assets/luca-ui.min.js +0 -4
  295. data/site/assets/sandbox.css +0 -62
  296. data/site/assets/sandbox.js +0 -469
  297. data/site/docs/application.html +0 -41
  298. data/site/docs/caching.html +0 -43
  299. data/site/docs/collection.html +0 -75
  300. data/site/docs/collection_manager.html +0 -71
  301. data/site/docs/containers.html +0 -118
  302. data/site/docs/events.html +0 -153
  303. data/site/docs/view.html +0 -128
  304. data/site/img/glyphicons-halflings-white.png +0 -0
  305. data/site/img/glyphicons-halflings.png +0 -0
  306. data/site/index.html +0 -20
  307. data/site/source-map.js +0 -1
  308. data/spec/components/form_view_spec.coffee +0 -84
  309. data/spec/containers/card_view_spec.coffee +0 -50
  310. data/spec/luca-spec.coffee +0 -9
@@ -21,6 +21,12 @@ Luca.concerns.QueryCollectionBindings =
21
21
 
22
22
  Luca.util.readAll(query)
23
23
 
24
+ getRemoteQuery: (options = {}) ->
25
+ @getQuery(options)
26
+
27
+ getLocalQuery: (options = {}) ->
28
+ @getQuery(options)
29
+
24
30
  # Private: returns the query that is applied to the underlying collection.
25
31
  # accepts the same options as Luca.Collection.query's initial query option.
26
32
  getQueryOptions: (options={})->
@@ -34,7 +40,7 @@ Luca.concerns.QueryCollectionBindings =
34
40
  # responds to @query() then it will use that interface.
35
41
  getModels: (query,options)->
36
42
  if @collection?.query
37
- query ||= @getQuery()
43
+ query ||= @getLocalQuery()
38
44
  options ||= @getQueryOptions()
39
45
  options.prepare ||= @prepareQuery
40
46
 
@@ -1,44 +1,58 @@
1
+
2
+ stateModel = Luca.register("Luca.ViewState").extends("Luca.Model")
3
+
1
4
  Luca.concerns.StateModel =
5
+ __onModelChange: (args...)->
6
+ statefulView = @
7
+ state = statefulView.state
8
+
9
+ @trigger.call(statefulView, "state:change", args... )
10
+
11
+ for changed, value of state.changedAttributes()
12
+ @trigger.call statefulView, "state:change:#{ changed }", state, value, state.previous(changed)
13
+
2
14
  __initializer: ()->
3
15
  @stateful = @stateAttributes if @stateAttributes?
4
16
 
5
17
  return unless @stateful?
6
- return if @state?
7
18
 
19
+ statefulView = @
20
+
8
21
  if _.isObject(@stateful) and not @defaultState?
9
22
  @defaultState = @stateful
10
23
 
11
- @state = new Backbone.Model(@defaultState || {})
12
- @set = _.bind(@state.set, @state)
13
- @get = _.bind(@state.get, @state)
24
+ @state ||= new Luca.ViewState(@defaultState || {})
25
+
26
+ view = @
27
+
28
+ @get = ()->
29
+ view.state.get.apply(view.state, arguments)
30
+
31
+ @set = ()->
32
+ view.state.set.apply(view.state, arguments)
14
33
 
15
34
  for key, value of @state.toJSON()
16
35
  hook = "on" + _.str.capitalize(key) + "Change"
17
36
  getter = "get" + _.str.capitalize(key)
18
37
  unless _.isFunction(@[getter])
19
38
  1
20
- #console.log("State Change Getter", getter)
21
- # @[getter] = ()=> @state.get(key)
22
- # WE COULD CREATE AUTO GETTERS HERE
23
-
24
39
  if _.isFunction(@[hook])
25
40
  1
26
- #console.log("State Change Hook", hook)
27
- # @stateChangeEvents[ key ] = hook
28
- # WE COULD AUTO BIND TO STATE CHANGE EVENTS HERE
29
-
30
- unless _.isEmpty(@stateChangeEvents)
31
- for attribute, handler of @stateChangeEvents
32
- fn = if _.isString(handler) then @[handler] else handler
33
-
34
- if attribute is "*"
35
- @on "state:change", fn, @
36
- else
37
- @on "state:change:#{ attribute }", fn, @
38
-
39
- @state.on "change", (state)=>
40
- @trigger "state:change", state
41
-
42
- for changed, value of state.changedAttributes()
43
- @trigger "state:change:#{ changed }", state, value, state.previous(changed)
44
41
 
42
+ Luca.concerns.StateModel.__setupModelBindings.call(@, "on")
43
+
44
+ __setupModelBindings: (direction="on")->
45
+ statefulView = @
46
+ for attribute, handler of @stateChangeEvents
47
+ fn = if _.isString(handler) then statefulView[handler] else handler
48
+
49
+ if attribute is "*"
50
+ statefulView[direction]("state:change", fn, statefulView)
51
+ else
52
+ statefulView[direction]("state:change:#{ attribute }", fn, statefulView)
53
+
54
+ # Any time there is a model change event on the internal state machine
55
+ # we will trigger a general state:change event on the component as well
56
+ # as individual state:change:attribute events
57
+ state = statefulView.state
58
+ statefulView.state[direction]("change", Luca.concerns.StateModel.__onModelChange, statefulView)
@@ -4,8 +4,10 @@ Luca.concerns.Templating =
4
4
 
5
5
  if template = @bodyTemplate
6
6
  @$el.empty()
7
+
7
8
  try
8
9
  templateContent = Luca.template(template, templateVars)
9
10
  catch e
10
- console.log "Error Rendering #{ bodyTemplate} in View: #{ @identifier?() || @name || @cid }"
11
+ console.log "Error Rendering #{ template} in View: #{ @identifier?() || @name || @cid }"
12
+
11
13
  Luca.View::$html.call(@, templateContent)
@@ -25,9 +25,12 @@ Luca.enableGlobalObserver = Luca.config.enableGlobalObserver = false
25
25
  # for what it is best at, and not try to solve this
26
26
  # problem on our own!
27
27
  Luca.config.enableBoostrap = Luca.config.enableBootstrap = true
28
+ Luca.config.fluidWrapperClass = "container-fluid"
29
+ Luca.config.wrapperClass = "container"
28
30
 
29
31
  Luca.config.enhancedViewProperties = true
30
32
 
33
+ # Need to replace this with something like keymaster.js
31
34
  Luca.keys = Luca.config.keys =
32
35
  ENTER: 13
33
36
  ESCAPE: 27
@@ -37,6 +40,7 @@ Luca.keys = Luca.config.keys =
37
40
  KEYDOWN: 40
38
41
  SPACEBAR: 32
39
42
  FORWARDSLASH: 191
43
+ TAB: 9
40
44
 
41
45
  Luca.config.toolbarContainerClass = "toolbar-container"
42
46
 
@@ -47,3 +51,4 @@ Luca.keyMap = Luca.config.keyMap = _( Luca.keys ).inject (memo, value, symbol)->
47
51
  , {}
48
52
 
49
53
  Luca.config.showWarnings = true
54
+ Luca.config.default_socket_port = 9292
@@ -1,8 +1,3 @@
1
- component = Luca.define "Luca.containers.CardView"
2
- component.extends "Luca.Container"
3
-
4
- component.aliases "Luca.PageView"
5
- #
6
1
  # The CardView is a type of Container which has many sub-views
7
2
  # which are only going to be visible one at a time. A CardView
8
3
  # allows you to @activate() its cards, navigate through them using
@@ -23,75 +18,70 @@ component.aliases "Luca.PageView"
23
18
  # cardView.activeComponent().name # => "one"
24
19
  # cardView.activate('two')
25
20
  # cardView.activeComponent().name # => "two"
26
- #
27
- component.defaults
28
-
29
- className: 'luca-ui-card-view-wrapper'
21
+ component = Luca.register "Luca.containers.CardView"
22
+ component.extends "Luca.Container"
30
23
 
24
+ component.publicConfiguration
31
25
  activeCard: 0
32
-
33
26
  components: []
34
27
 
28
+ component.classInterface
29
+ # When the activate method is called and passed a callback
30
+ # what context should we run that callback in? Default is
31
+ # to call the callback in the context of the component that
32
+ # is currently being activated
33
+ activationContext: "current"
34
+
35
+ component.privateConfiguration
36
+ # Will automatically call beforeCardSwitch and afterCardSwitch
37
+ # methods if they exist on this view. These events will be triggered
38
+ # in response to a call to @activate()
35
39
  hooks:[
36
40
  'before:card:switch',
37
41
  'after:card:switch'
38
42
  ]
39
43
 
44
+ # Which css class should we apply to each of the cards
40
45
  componentClass: 'luca-ui-card'
41
- generateComponentElements: true
42
-
43
- initialize: (@options)->
44
- @components ||= @pages ||= @cards
45
- Luca.Container::initialize.apply @,arguments
46
- @setupHooks(@hooks)
47
-
48
- @defer( @simulateActivationEvent, @ ).until("after:render")
49
-
50
- simulateActivationEvent: ()->
51
- c = @activeComponent()
52
46
 
53
- if c? and @$el.is(":visible")
54
- c?.trigger "activation", @, c, c
55
-
56
- prepareComponents: ()->
57
- Luca.Container::prepareComponents?.apply(@, arguments)
58
- @componentElements().hide()
59
- @activeComponentElement().show()
60
-
61
- activeComponentElement: ()->
62
- @componentElements().eq( @activeCard )
63
-
64
- activeComponent: ()->
65
- @getComponent( @activeCard )
66
-
67
- customizeContainerEl: (containerEl, panel, panelIndex)->
68
- containerEl.style += if panelIndex is @activeCard then "display:block;" else "display:none;"
69
-
70
- containerEl
47
+ # Should we generate elements to append each component?
48
+ generateComponentElements: true
71
49
 
50
+ component.publicMethods
51
+ # Returns true if at the first
72
52
  atFirst: ()->
73
53
  @activeCard is 0
74
54
 
55
+ # Returns true if we're at the last card
75
56
  atLast: ()->
76
57
  @activeCard is @components.length - 1
77
58
 
59
+ # Activate the next component. If at the last, do nothing.
78
60
  next: ()->
79
61
  return if @atLast()
80
62
  @activate( @activeCard + 1)
81
63
 
64
+ # Activate the previous component. If at the first, do nothing.
82
65
  previous: ()->
83
66
  return if @atFirst()
84
67
  @activate( @activeCard - 1)
85
68
 
69
+ # Activates the next component after the current one.
70
+ # If at the last component, it will activate the first.
86
71
  cycle: ()->
87
72
  nextIndex = if @atLast() then 0 else @activeCard + 1
88
73
  @activate( nextIndex )
89
74
 
90
- find: (name)-> Luca(name)
91
-
92
- firstActivation: ()->
93
- @activeComponent()?.trigger "first:activation", @, @activeComponent()
75
+ # Find a direct component on this card by its name.
76
+ find: (name)->
77
+ _( @components ).detect (c)->
78
+ c.name is name
94
79
 
80
+ # Activates the component at the specified index. You may optionally specify
81
+ # the name of the component you wish to activate. You can pass false as your second
82
+ # argument, to disable the event handling that occurs when you activate a card on this container.
83
+ # If you pass a callback function to the activate method, that callback will be executed within
84
+ # the context of the activated component.
95
85
  activate: (index, silent=false, callback)->
96
86
  if _.isFunction(silent)
97
87
  silent = false
@@ -100,14 +90,12 @@ component.defaults
100
90
  return if index is @activeCard
101
91
 
102
92
  previous = @activeComponent()
103
- current = @getComponent(index)
104
93
 
105
- if !current
106
- index = @indexOf(index)
107
- current = @getComponent( index )
94
+ current = @getComponent(index)
108
95
 
109
- unless current
110
- return
96
+ if !current?
97
+ index = @indexOf(index)
98
+ return unless current = @getComponent(index)
111
99
 
112
100
  unless silent is true
113
101
  @trigger "before:card:switch", previous, current
@@ -120,10 +108,15 @@ component.defaults
120
108
  @componentElements().hide()
121
109
 
122
110
  unless current.previously_activated is true
123
- current.trigger "first:activation"
111
+ if current.rendered is true
112
+ current.trigger "first:activation"
113
+ else
114
+ current.once "after:render", ()->
115
+ current.rendered = true
116
+ current.trigger("first:activation")
124
117
  current.previously_activated = true
125
118
 
126
- @activeCard = index
119
+ @activeCard = index
127
120
  @activeComponentElement().show()
128
121
 
129
122
  unless silent is true
@@ -139,5 +132,47 @@ component.defaults
139
132
  if _.isFunction(callback)
140
133
  callback.apply activationContext, [@,previous,current]
141
134
 
135
+ component.privateMethods
136
+ initialize: (@options)->
137
+ @components ||= @pages ||= @cards
138
+ Luca.Container::initialize.apply @,arguments
139
+ @setupHooks(@hooks)
140
+ @defer( @simulateActivationEvent, @ ).until("after:render")
141
+
142
+ # Simulates the activation event being triggered on the
143
+ # active component that gets rendered inside of this card view.
144
+ simulateActivationEvent: ()->
145
+ c = @activeComponent()
146
+
147
+ if c? and (@visible || @$el.is(":visible"))
148
+ c?.trigger "activation", @, c, c
149
+ if !c.previously_activated
150
+ c.trigger "first:activation"
151
+ c.previously_activated = true
152
+
153
+ prepareComponents: ()->
154
+ Luca.Container::prepareComponents?.apply(@, arguments)
155
+ @componentElements().hide()
156
+ @activeComponentElement().show()
157
+
158
+ activeComponentElement: ()->
159
+ @componentElements().eq( @activeCard )
160
+
161
+ activeComponent: ()->
162
+ @getComponent( @activeCard )
163
+
164
+ customizeContainerEl: (containerEl, panel, panelIndex)->
165
+ containerEl.style += if panelIndex is @activeCard then "display:block;" else "display:none;"
166
+
167
+ containerEl
168
+
169
+
170
+
171
+ # The first time activate event is triggered on this component
172
+ # the @firstActivation hook is responsible for relaying that event
173
+ # to our @activeComponent() so that it knows it has been activated.
174
+ firstActivation: ()->
175
+ if activeComponent = @activeComponent()
176
+ activeComponent.trigger "first:activation", @, @activeComponent()
142
177
 
143
- Luca.containers.CardView.activationContext = "current"
178
+ component.register()
@@ -1,3 +1,148 @@
1
+ # The Luca.Container is the heart and soul of the Luca framework
2
+ # and the component driven design philosophy. The central idea
3
+ # is that every component should be designed as an isolated unit
4
+ # which completely encapsulates its features. It should not know about
5
+ # other components outside of it.
6
+ #
7
+ # It is the responsibility of a `Luca.Container` to define its
8
+ # child `@components`, render them, and broker communication between them
9
+ # in response to events which occur in the user interface.
10
+ #
11
+ # A common use case for this would be a page which has a filter form, and
12
+ # a grid of search results. The fields in the filter form are used to
13
+ # filter the table. Neither the form or the table know about each other,
14
+ # since both can be used in other contexts. A `Luca.Container` would be used
15
+ # to relay events from the form to the table, and in doing so create a higher
16
+ # level component which can be extended and re-used.
17
+ #
18
+ # #### Using a container to combine a Filter View and Results Table
19
+ #
20
+ # form = Luca.register "App.views.FilterForm"
21
+ # form.extends "Luca.components.FormView"
22
+ #
23
+ # form.contains
24
+ # type: "text"
25
+ # label: "Filter by"
26
+ # name: "filter_text"
27
+ # ,
28
+ # type: "button"
29
+ # className: "filter"
30
+ # value: "Filter"
31
+ #
32
+ #
33
+ # form.defines
34
+ # toolbar: false
35
+ #
36
+ # Elsewhere, we have a table that lists records in a collection:
37
+ #
38
+ # table = Luca.register "App.views.ResultsTable"
39
+ # table.extends "Luca.components.TableView"
40
+ # table.defines
41
+ # striped: true
42
+ # collection: "components"
43
+ # columns:[
44
+ # header: "Component Class"
45
+ # reader: "class_name"
46
+ # ,
47
+ # header: "Component Type Alias"
48
+ # reader: "type_alias"
49
+ # ]
50
+ #
51
+ # We can join these two components together by declaring their relationship
52
+ # in a `Luca.Container`. Remember the components we defined above are just
53
+ # prototypes. We can override specific instance configuration and properties
54
+ # in our container.
55
+ #
56
+ # #### Container Example
57
+ #
58
+ # container = Luca.register "App.views.ComponentFinder"
59
+ # container.extends "Luca.Container"
60
+ #
61
+ # # This is the same as defining a components property on the component.
62
+ # # The type alias is derived from the name of the component. It is
63
+ # # a short hand way of referencing a component you might reuse a lot.
64
+ # container.contains
65
+ # type: "filter_form"
66
+ # role: "filter"
67
+ # ,
68
+ # type: "results_table"
69
+ # # change the prototype's default
70
+ # striped: false
71
+ # role: "results"
72
+ # filterable: true
73
+ #
74
+ # # A Container will generally define some component event bindings
75
+ # # and handler methods to handle the communication between its sub
76
+ # # components. By default a container is able to access events
77
+ # # from all of its descendants in the hierarchy.
78
+ # container.defines
79
+ # # These will be applied to each of our components.
80
+ # defaults:
81
+ # attributes:
82
+ # "data-attribute": "whatever"
83
+ #
84
+ # componentEvents:
85
+ # # Any time any of our child components emit
86
+ # # the on:change event, pass it to the filterTable method
87
+ # "* on:change" : "filterTable"
88
+ #
89
+ # # Communicates between the filter and the table's
90
+ # # underlying collection. NOtice the use of the @role
91
+ # # property. It automatically creates getter helpers for us.
92
+ # filterTable: ()->
93
+ # filter = @getFilter()
94
+ # results = @getResults()
95
+ # # filter.getValues() is a hash of each field and its value
96
+ # results.applyFilter( filter.getValues() )
97
+ #
98
+ # ### DOM Layout Configuration
99
+ #
100
+ # Another responsibility of the container is to structurally layout its
101
+ # child components in the DOM. There are a number of different
102
+ # options available depending on how you need to do this. By default,
103
+ # a `Luca.Container` will simply append the @$el of all of its views
104
+ # to its own.
105
+ #
106
+ # The `Luca.components.Controller` is a container which hides every page
107
+ # but the active page. Similarly, there is the `Luca.containers.TabView`
108
+ # which does the same thing, but renders a tab selector menu for you. You
109
+ # can create any type of interface you want using containers.
110
+ #
111
+ # To make this easy for you, you can do a few different things:
112
+ #
113
+ # #### Use the Twitter Bootstrap Fluid Grid
114
+ #
115
+ # container = Luca.register "App.views.ColumnLayout"
116
+ # container.extends "App.views.ComponentFinder"
117
+ #
118
+ # container.contains
119
+ # span: 4
120
+ # type: "filter_form"
121
+ # role: "filter"
122
+ # ,
123
+ # span: 8
124
+ # type: "results_table"
125
+ # role: "results"
126
+ #
127
+ # container.defines
128
+ # rowFluid: true
129
+ #
130
+ # #### Using a layout template with CSS Selectors
131
+ # If you find yourself needing a container view with a complicated
132
+ # visual layout, you can provide your own DOM template as a `@bodyTemplate`
133
+ # and assign each child view in `@components` to its own specific CSS selector.
134
+ #
135
+ # ...
136
+ # container.contains
137
+ # role: "filter"
138
+ # container: "#filter-wrapper-dom-selector"
139
+ # ,
140
+ # role: "results"
141
+ # container: "#results-wrapper-dom-selector"
142
+ # ...
143
+ # container.defines
144
+ # # assumes the template will provide the CSS selectors used above
145
+ # bodyTemplate: "layouts/custom_template"
1
146
  container = Luca.register "Luca.Container"
2
147
 
3
148
  container.extends "Luca.Panel"
@@ -11,36 +156,95 @@ container.triggers "before:components",
11
156
 
12
157
  container.replaces "Luca.Container"
13
158
 
14
- container.defines
15
- className: 'luca-ui-container'
16
-
17
- componentTag: 'div'
18
-
19
- componentClass: 'luca-ui-panel'
20
-
21
- isContainer: true
159
+ container.publicConfiguration
160
+ # @components should contain a list of object configurations for child view(s)
161
+ # of this container. The values specified in the configuration object will override the
162
+ # values defined as properties and methods on your view prototypes.
163
+ #
164
+ # There are special properties you can define in your components configuration items
165
+ # that will effect the container:
166
+ #
167
+ # - role: will create a camelized getter for you on the container. e.g. when role is `my_custom_role`,
168
+ # the container will have a method `getMyCustomRole()` that returns that child view.
169
+ #
170
+ # - name: a name for the child view. this allows you to access the component by name using
171
+ # the find() method on the container.
172
+ #
173
+ # - type: a type alias from the component registry. type alias are underscore'd strings
174
+ # matching the component class name. e.g. App.views.MyCustomView type alias is `my_custom_view`
175
+ #
176
+ # - component: a convenience property for setting type, role, and name to be equal.
177
+ components:[]
22
178
 
23
- rendered: false
179
+ # The `@defaults` property is an object of configuration parameters which will be set
180
+ # on each child component. Values explicitly defines in the components config will
181
+ # take precedence over the default.
182
+ defaults: {}
24
183
 
25
- components: []
184
+ # The `@extensions` property is useful when you are subclassing a container view
185
+ # which already defines an array of components, and you want to specifically override
186
+ # properties and settings on the children. The `@extensions` property expects either:
187
+ #
188
+ # An object whose keys match the names of the `@role` property defined on the child components.
189
+ # The value should be an object which will override any values defined on the parent class.
190
+ #
191
+ # or:
192
+ #
193
+ # An array of objects in the same array position / index as the target child view you wish to extend.
194
+ extensions: {}
26
195
 
27
196
  # @componentEvents provides declarative syntax for responding to events on
28
197
  # the components in this container. the format of the syntax is very similar
29
198
  # to the other event binding helpers:
30
199
  #
31
- # component_accessor component:trigger
32
- #
33
- # where component_accessor is either the name of the role, or a method on the container
34
- # which will find the component in question.
35
- #
36
- # myContainer = new Luca.Container
37
- # componentEvents:
38
- # "name component:trigger" : "handler"
39
- # "role component:trigger" : "handler"
40
- # "getter component:trigger" : "handler"
200
+ # `component_accessor component:trigger`
41
201
  #
202
+ # where component_accessor is either the name of the component, or a the role
203
+ # property on the component, component:trigger is the event that component fires.
204
+ # handler is a method on the container which will respond to the child component event.
205
+ # <pre>
206
+ # myContainer = new Luca.Container
207
+ # componentEvents:
208
+ # "name component:trigger" : "handler"
209
+ # "role component:trigger" : "handler"
210
+ # "getter component:trigger" : "handler"
211
+ # components:[
212
+ # name: "name"
213
+ # ]
214
+ # </pre>
42
215
  componentEvents: {}
43
216
 
217
+ container.privateConfiguration
218
+ className: 'luca-ui-container'
219
+
220
+ # This is a convenience attribute for identifying
221
+ # views which are luca containers
222
+ isContainer: true
223
+
224
+ # if set to true, we will generate DOM elements
225
+ # to wrap each of our components in. This should
226
+ # generally be avoided IMO as it pollutes the DOM,
227
+ # but is currently necessary for some container implementations
228
+ generateComponentElements: false
229
+
230
+ # if set to true, the DOM elements which wrap
231
+ # our components will be emptied prior to rendering
232
+ # the component inside this container.
233
+ emptyContainerElements: false
234
+
235
+ # if @generateComponentElements is true, which tag should this
236
+ # container wrap our components in?
237
+ componentTag: 'div'
238
+
239
+ # if @generateComponentElements is true, which class should we
240
+ # apply to the container elements which wrap our components?
241
+ componentClass: 'luca-ui-panel'
242
+
243
+ rendered: false
244
+
245
+
246
+
247
+ container.privateMethods
44
248
  initialize: (@options={})->
45
249
  _.extend @, @options
46
250
 
@@ -60,52 +264,12 @@ container.defines
60
264
 
61
265
  Luca.View::initialize.apply @, arguments
62
266
 
63
- # Rendering Pipeline
64
- #
65
- # A container has nested components. these components
66
- # are automatically rendered inside their own DOM element
67
- # and then CSS configuration is generally applied to these
68
- # DOM elements. Each component is assigned to this DOM
69
- # element by specifying a @container property on the component.
70
- #
71
- # Each component is instantiated by looking up its @ctype propery
72
- # in the Luca Component Registry. Then the components are rendered
73
- # by having their @render() method called on them.
74
- #
75
- # Any class which extends Luca.View will have its defined render method
76
- # wrapped in a method which triggers "before:render", and "after:render"
77
- # before and after the defined render method.
78
- #
79
- # so you can expect the following, for any container or nested container
80
- #
81
- # DOM Element Manipulation:
82
- #
83
- # beforeRender()
84
- # beforeLayout()
85
- # prepareLayout()
86
- # afterLayout()
87
- #
88
- # Luca / Backbone Component Manipulation
89
- #
90
- # beforeComponents()
91
- # prepareComponents()
92
- # createComponents()
93
- # beforeRenderComponents()
94
- # renderComponents() ->
95
- # calls render() on each component, starting this whole cycle
96
- #
97
- # afterComponents()
98
- #
99
- # DOM Injection
100
- #
101
- # render()
102
- # afterRender()
103
- #
104
- # For Components which are originally hidden
105
- # ( card view, tab view, etc )
106
- #
107
- # firstActivation()
108
- #
267
+ # Removing a container will call remove on all of the nested components as well.
268
+ remove: ()->
269
+ Luca.View::remove.apply(@, arguments)
270
+ @eachComponent (component)->
271
+ component.remove?()
272
+
109
273
  beforeRender: ()->
110
274
  doLayout.call(@)
111
275
  doComponents.call(@)
@@ -144,7 +308,6 @@ container.defines
144
308
  prepareComponents: ()->
145
309
  container = @
146
310
 
147
-
148
311
  _( @components ).each (component, index)=>
149
312
  ce = componentContainerElement = @componentContainers?[index]
150
313
 
@@ -205,8 +368,17 @@ container.defines
205
368
  component = if Luca.isComponent( object )
206
369
  object
207
370
  else
371
+ # if a component is tagged with a @component property
372
+ # we assume this is the kind of singleton component
373
+ # and set the type, role and name to the same value (if they're blank)
374
+ if object.component? and not (object.type || object.ctype)
375
+ object.type = object.component
376
+ object.name ||= object.component
377
+ object.role ||= object.component
378
+
208
379
  object.type ||= object.ctype
209
380
 
381
+ # guess the type based on the properties
210
382
  if !object.type?
211
383
  # TODO
212
384
  # Add support for all of the various components property aliases
@@ -238,8 +410,7 @@ container.defines
238
410
 
239
411
  map
240
412
 
241
- # Trigger the Rendering Pipeline process on all of the nested
242
- # components
413
+ # Trigger the Rendering Pipeline process on all of the nested components
243
414
  renderComponents: (@debugMode="")->
244
415
  @debug "container render components"
245
416
 
@@ -260,10 +431,14 @@ container.defines
260
431
  # so look into wtf is going on and which components are problematic
261
432
  containerElement = @$( component.container ).eq(0) if containerElement.length is 0
262
433
 
434
+ if @emptyContainerElements is true
435
+ containerElement.empty()
436
+
263
437
  containerElement.append( component.el )
264
438
 
265
439
  component.trigger "after:attach"
266
440
  component.render()
441
+ component.rendered = true
267
442
  catch e
268
443
  console.log "Error Rendering Component #{ component.name || component.cid }", component
269
444
 
@@ -273,8 +448,6 @@ container.defines
273
448
 
274
449
  throw e unless Luca.silenceRenderErrors? is true
275
450
 
276
- #### Container Activation
277
- #
278
451
  # When a container is first activated is a good time to perform
279
452
  # operations which are not needed unless that component becomes
280
453
  # visible. This first activation event should be relayed to all
@@ -291,28 +464,7 @@ container.defines
291
464
  component?.trigger?.call component, "first:activation", component, activator
292
465
  component.previously_activated = true
293
466
 
294
- #### Underscore Methods For Working with Components
295
- _: ()-> _( @components )
296
-
297
- pluck: (attribute)->
298
- @_().pluck(attribute)
299
-
300
- invoke: (method)->
301
- @_().invoke(method)
302
-
303
- select: (fn)->
304
- @_().select(fn)
305
-
306
- detect: (fn)->
307
- @_().detect(attribute)
308
-
309
- reject: (fn)->
310
- @_().reject(fn)
311
-
312
- map: (fn)->
313
- @_().map(fn)
314
-
315
- registerComponentEvents: (eventList)->
467
+ registerComponentEvents: (eventList, direction="on")->
316
468
  container = @
317
469
 
318
470
  for listener, handler of (eventList || @componentEvents||{})
@@ -331,31 +483,71 @@ container.defines
331
483
  console.log "Error registering component event", listener, componentNameOrRole, eventId
332
484
  throw "Invalid component event definition: #{ componentNameOrRole }"
333
485
 
334
- component?.bind eventId, @[handler], container
486
+ component[direction](eventId, @[handler], container)
487
+
488
+ container.publicMethods
489
+ # Returns an underscore.js object that wraps the components array
490
+ _: ()-> _( @components )
491
+
492
+ # Return the value of attribute of each component
493
+ pluck: (attribute)->
494
+ @_().pluck(attribute)
495
+
496
+ # Invoke the passed method name on each component
497
+ invoke: (method)->
498
+ @_().invoke(method)
499
+
500
+ # Select any component for which the passed iterator returns true
501
+ select: (iterator)->
502
+ @_().select(iterator)
335
503
 
504
+ # Find the first matching component for which the passed iterator returns true
505
+ detect: (iterator)->
506
+ @_().detect(iterator)
336
507
 
508
+ # Return a list of components without the components for which the passed iterator returns true
509
+ reject: (iterator)->
510
+ @_().reject(iterator)
511
+
512
+ # Run the passed iterator over each component and return the result in an array
513
+ map: (fn)->
514
+ @_().map(fn)
515
+
516
+ # Returns a list of nested components which are also containers
337
517
  subContainers: ()->
338
518
  @select (component)->
339
519
  component.isContainer is true
340
520
 
341
521
  roles: ()->
342
- _( @allChildren() ).pluck('role')
522
+ _( @allChildren() ).chain().pluck('role').compact().value()
343
523
 
344
524
  allChildren: ()->
345
525
  children = @components
346
- grandchildren = _( @subContainers() ).invoke('allChildren')
526
+
527
+ grandchildren = _( @subContainers() ).map (component)->
528
+ component?.allChildren?()
529
+
347
530
  _([children,grandchildren]).chain().compact().flatten().value()
348
531
 
532
+ # Find a direct component on this card by its name.
533
+ find: (name)->
534
+ _( @components ).detect (c)->
535
+ c.name is name
536
+
349
537
  findComponentForEventBinding: (nameRoleOrGetter, deep=true)->
350
538
  @findComponentByName(nameRoleOrGetter, deep) || @findComponentByGetter( nameRoleOrGetter, deep ) || @findComponentByRole( nameRoleOrGetter, deep )
351
539
 
352
540
  findComponentByGetter: (getter, deep=false)->
353
541
  _( @allChildren() ).detect (component)->
354
- component.getter is getter
542
+ component?.getter is getter
355
543
 
356
544
  findComponentByRole: (role,deep=false)->
357
545
  _( @allChildren() ).detect (component)->
358
- component.role is role or component.type is role or component.ctype is role
546
+ component?.role is role or component?.type is role or component?.ctype is role
547
+
548
+ findComponentByType: (desired,deep=false)->
549
+ _( @allChildren() ).detect (component)->
550
+ desired is (component.type || component.ctype)
359
551
 
360
552
  findComponentByName: (name, deep=false)->
361
553
  _( @allChildren() ).detect (component)->
@@ -389,10 +581,17 @@ container.defines
389
581
  fn.call component, component, index
390
582
  component?.eachComponent?.apply component, [fn,deep] if deep
391
583
 
392
- indexOf: (name)->
584
+ indexOfComponentName: (name)->
393
585
  names = _( @components ).pluck('name')
394
586
  _( names ).indexOf(name)
395
587
 
588
+ indexOf: (nameOrComponent)->
589
+ if _.isString(nameOrComponent)
590
+ return @indexOfComponentName(nameOrComponent)
591
+
592
+ if _.isObject(nameOrComponent)
593
+ _( @components ).indexOf( nameOrComponent )
594
+
396
595
  activeComponent: ()->
397
596
  return @ unless @activeItem
398
597
  return @components[ @activeItem ]
@@ -425,6 +624,8 @@ container.defines
425
624
  _.flatten( components )
426
625
 
427
626
 
627
+ container.register()
628
+
428
629
  # This is the method by which a container injects the rendered child views
429
630
  # into the DOM. It will get passed the container object, and the component
430
631
  # that is being rendered.
@@ -464,22 +665,21 @@ createGetterMethods = ()->
464
665
  container = @
465
666
 
466
667
  childrenWithGetter = _( @allChildren() ).select (component)->
467
- component.getter?
668
+ component?.getter?
468
669
 
469
670
  _( childrenWithGetter ).each (component)->
470
- container[ component.getter ] ||= ()->
471
- component
671
+ container[ component.getter ] ||= ()-> component
472
672
 
473
673
  createMethodsToGetComponentsByRole = ()->
474
674
  container = @
475
675
 
476
676
  childrenWithRole = _( @allChildren() ).select (component)->
477
- component.role?
677
+ component?.role?
478
678
 
479
679
  _( childrenWithRole ).each (component)->
480
680
  getter = _.str.camelize( "get_" + component.role )
481
- container[ getter ] ||= ()->
482
- component
681
+ getterFn = ()-> component
682
+ container[ getter ] ||= _.bind(getterFn, container)
483
683
 
484
684
  doComponents = ()->
485
685
  @trigger "before:components", @, @components
@@ -499,9 +699,6 @@ doComponents = ()->
499
699
  validateContainerConfiguration = ()->
500
700
  true
501
701
 
502
-
503
- # Private Helpers
504
- #
505
702
  # indexComponent( component ).at( index ).in( componentsInternalIndexMap )
506
703
  indexComponent = (component)->
507
704
  at: (index)->