luca 0.9.8 → 0.9.9

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 (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)->