sproutcore 1.7.1.beta → 1.8.0

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 (445) hide show
  1. data/CHANGELOG +44 -0
  2. data/README.rdoc +20 -20
  3. data/VERSION.yml +3 -3
  4. data/lib/Buildfile +1 -1
  5. data/lib/buildtasks/build.rake +5 -0
  6. data/lib/buildtasks/manifest.rake +19 -1
  7. data/lib/frameworks/sproutcore/Buildfile +19 -17
  8. data/lib/frameworks/sproutcore/CHANGELOG.md +163 -29
  9. data/lib/frameworks/sproutcore/README.md +29 -8
  10. data/lib/frameworks/sproutcore/apps/statechart_routing/Buildfile +12 -0
  11. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/login_controller.js +11 -0
  12. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/main_controller.js +7 -0
  13. data/lib/frameworks/sproutcore/apps/statechart_routing/controllers/statechart_controller.js +17 -0
  14. data/lib/frameworks/sproutcore/apps/statechart_routing/core.js +25 -0
  15. data/lib/frameworks/sproutcore/apps/statechart_routing/main.js +15 -0
  16. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/_theme.css +18 -0
  17. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/bar_page.js +14 -0
  18. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/foo_page.js +14 -0
  19. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/loading.rhtml +9 -0
  20. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/login_page.js +61 -0
  21. data/lib/frameworks/sproutcore/apps/statechart_routing/resources/main_page.js +46 -0
  22. data/lib/frameworks/sproutcore/apps/statechart_routing/statechart.js +76 -0
  23. data/lib/frameworks/sproutcore/apps/statechart_routing/theme.js +27 -0
  24. data/lib/frameworks/sproutcore/apps/tests/controllers/targets.js +1 -1
  25. data/lib/frameworks/sproutcore/apps/tests/states/no_targets.js +1 -1
  26. data/lib/frameworks/sproutcore/apps/tests/states/ready_detail.js +1 -1
  27. data/lib/frameworks/sproutcore/apps/tests/states/ready_empty.js +1 -1
  28. data/lib/frameworks/sproutcore/apps/tests/states/ready_list.js +1 -1
  29. data/lib/frameworks/sproutcore/apps/tests/states/ready_no_tests.js +1 -1
  30. data/lib/frameworks/sproutcore/apps/welcome/controllers/targets.js +1 -1
  31. data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +14 -1
  32. data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +15 -15
  33. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +1 -1
  34. data/lib/frameworks/sproutcore/frameworks/animation/core.js +8 -5
  35. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +302 -70
  36. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +19 -14
  37. data/lib/frameworks/sproutcore/frameworks/bootstrap/tests/system/browser.js +471 -149
  38. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +3 -3
  39. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/object.js +42 -0
  40. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/run_loop.js +3 -2
  41. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/string.js +7 -0
  42. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +1 -1
  43. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/delegate_support.js +2 -2
  44. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/responder_context.js +3 -3
  45. data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/selection_support.js +1 -1
  46. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/body_overflow.js +63 -0
  47. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/keyboard.js +1 -1
  48. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +37 -2
  49. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/main.js +28 -6
  50. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +10 -3
  51. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/sparse_array_delegate.js +2 -2
  52. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/browser.js +66 -2
  53. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/builder.js +1 -1
  54. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/cursor.js +1 -1
  55. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +58 -57
  56. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +1 -1
  57. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js.orig +445 -0
  58. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +51 -31
  59. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/ready.js +5 -1
  60. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/render_context.js +53 -69
  61. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/responder.js +1 -1
  62. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +98 -72
  63. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/string.js +37 -3
  64. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/timer.js +7 -4
  65. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/array/array_case.js +21 -0
  66. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/object/content_destroyed.js +7 -7
  67. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/string.js +23 -1
  68. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/browser.js +66 -0
  69. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/event.js +22 -0
  70. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/locale.js +11 -11
  71. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/end.js +4 -4
  72. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/escape_html.js +41 -0
  73. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/helpers_className.js +1 -1
  74. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/helpers_style.js +8 -8
  75. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/render_context/update.js +17 -16
  76. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/selection_set/remove.js +1 -1
  77. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/build_children.js +1 -1
  78. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +15 -0
  79. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/createChildViews.js +5 -5
  80. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +50 -30
  81. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/acceleration.js +46 -0
  82. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +1 -43
  83. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +8 -34
  84. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +3 -2
  85. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +10 -1
  86. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +6 -5
  87. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +22 -2
  88. data/lib/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +2 -2
  89. data/lib/frameworks/sproutcore/frameworks/datastore/mixins/relationship_support.js +1 -1
  90. data/lib/frameworks/sproutcore/frameworks/datastore/models/child_attribute.js +0 -2
  91. data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +35 -0
  92. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +46 -19
  93. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +23 -9
  94. data/lib/frameworks/sproutcore/frameworks/datastore/models/single_attribute.js +2 -3
  95. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +1 -1
  96. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +2 -2
  97. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +294 -302
  98. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js.orig +1531 -0
  99. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +4 -2
  100. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +14 -11
  101. data/lib/frameworks/sproutcore/frameworks/datastore/tests/integration/many_array.js +63 -0
  102. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +1 -1
  103. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +4 -4
  104. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +50 -10
  105. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array_complex.js +4 -4
  106. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_complex.js +3 -3
  107. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/destroy.js +1 -1
  108. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/refresh.js +1 -1
  109. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +1 -1
  110. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +114 -67
  111. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChangesFromNestedStore.js +1 -1
  112. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readDataHash.js +1 -1
  113. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare.js +54 -1
  114. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation.js +29 -9
  115. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/parse.js +1 -1
  116. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +1 -1
  117. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/flush.js +1 -1
  118. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/cancelRecord.js +1 -1
  119. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +1 -1
  120. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +37 -45
  121. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/find.js +127 -127
  122. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushChanges.js +16 -0
  123. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushRelationships.js +42 -4
  124. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/readDataHash.js +1 -1
  125. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +13 -7
  126. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +8 -0
  127. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/resources/strings.js +2 -1
  128. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/system/datetime.js +1 -0
  129. data/lib/frameworks/sproutcore/frameworks/debug/core.js +3 -3
  130. data/lib/frameworks/sproutcore/frameworks/desktop/core.js +1 -1
  131. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +1 -1
  132. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +1 -1
  133. data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +1 -4
  134. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +19 -6
  135. data/lib/frameworks/sproutcore/frameworks/desktop/panes/modal.js +30 -1
  136. data/lib/frameworks/sproutcore/frameworks/desktop/panes/palette.js +1 -1
  137. data/lib/frameworks/sproutcore/frameworks/desktop/panes/panel.js +24 -1
  138. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +121 -28
  139. data/lib/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +15 -15
  140. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_data_source.js +1 -1
  141. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +2 -2
  142. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/responder.js +2 -2
  143. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/button.js +39 -15
  144. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/collection.js +3 -3
  145. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/disclosure.js +2 -2
  146. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/image_button.js +2 -2
  147. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/panel.js +14 -6
  148. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/popup_button.js +3 -3
  149. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/progress.js +11 -11
  150. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segment.js +4 -3
  151. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/segmented.js +1 -51
  152. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/slider.js +11 -16
  153. data/lib/frameworks/sproutcore/frameworks/desktop/resources/images/icons/sc-icon-error-48.png +0 -0
  154. data/lib/frameworks/sproutcore/frameworks/desktop/resources/slider.css +0 -2
  155. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +3 -3
  156. data/lib/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +3 -3
  157. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +9 -9
  158. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/content.js +11 -11
  159. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +2 -1
  160. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/reload.js +1 -1
  161. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/ui.js +107 -81
  162. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +3 -3
  163. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +68 -60
  164. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +57 -12
  165. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/integration.js +21 -19
  166. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroller.js +5 -0
  167. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +2 -2
  168. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/ui.js +32 -3
  169. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/split/methods.js +12 -0
  170. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/stacked/ui_comments.js +12 -0
  171. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +0 -8
  172. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +77 -132
  173. data/lib/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +5 -6
  174. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +16 -15
  175. data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +52 -52
  176. data/lib/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +1 -1
  177. data/lib/frameworks/sproutcore/frameworks/desktop/views/grid.js +1 -1
  178. data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +147 -147
  179. data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +11 -2
  180. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +2 -2
  181. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +5 -5
  182. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +22 -12
  183. data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +13 -7
  184. data/lib/frameworks/sproutcore/frameworks/desktop/views/scene.js +2 -2
  185. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +462 -441
  186. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +48 -62
  187. data/lib/frameworks/sproutcore/frameworks/desktop/views/segment.js +22 -2
  188. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +150 -32
  189. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +104 -45
  190. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_button.js +42 -20
  191. data/lib/frameworks/sproutcore/frameworks/desktop/views/slider.js +24 -24
  192. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +148 -154
  193. data/lib/frameworks/sproutcore/frameworks/desktop/views/stacked.js +2 -2
  194. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +2 -2
  195. data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +8 -7
  196. data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +2 -2
  197. data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +2 -0
  198. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/files.js +1 -1
  199. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/library.js +1 -1
  200. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/targets.js +1 -1
  201. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/controllers/view_configs.js +1 -1
  202. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/mixins/drop_down.js +1 -1
  203. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/states/ready.js +1 -1
  204. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/views/plist_item.js +1 -1
  205. data/lib/frameworks/sproutcore/frameworks/experimental/apps/greenhouse/views/web.js +1 -1
  206. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/controllers/page_design.js +2 -2
  207. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/css/css_style_sheet.js +2 -2
  208. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/designers/object_designer.js +1 -1
  209. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/designers/view_designer.js +2 -2
  210. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/mixins/snap_lines.js +3 -3
  211. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/designer_drop_target.js +1 -1
  212. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/drawing.js +21 -21
  213. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/designer/views/page_item_view.js +1 -1
  214. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form.js +59 -53
  215. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +2 -2
  216. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/tests/models/polymorphism/simple.js +1 -1
  217. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +6 -6
  218. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +2 -2
  219. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +2 -2
  220. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu.js +14 -10
  221. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu_item.js +17 -6
  222. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/popup_button.js +38 -14
  223. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/select.js +5 -13
  224. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_child.js +1 -1
  225. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/mixins/split_thumb.js +5 -3
  226. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/children.js +19 -0
  227. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/methods.js +20 -2
  228. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/tests/split_thumb.js +1 -1
  229. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/split_view/views/split.js +35 -12
  230. data/lib/frameworks/sproutcore/frameworks/formatters/README +6 -0
  231. data/lib/frameworks/sproutcore/frameworks/formatters/english.lproj/strings.js +174 -0
  232. data/lib/frameworks/sproutcore/frameworks/formatters/formatters/date_formatter.js +351 -0
  233. data/lib/frameworks/sproutcore/frameworks/formatters/tests/date_formatter.js +517 -0
  234. data/lib/frameworks/sproutcore/frameworks/foundation/core.js +1 -1
  235. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +345 -138
  236. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/button.js +5 -3
  237. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_value_support.js +176 -42
  238. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/editable.js +1 -1
  239. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/flowed_layout.js +137 -105
  240. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/gestureable.js +2 -2
  241. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_editable.js +2 -2
  242. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/inline_editor.js +16 -1
  243. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/static_layout.js +1 -1
  244. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/validatable.js +47 -47
  245. data/lib/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +3 -3
  246. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/helpers/sizing.js +1 -1
  247. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/label.js +28 -6
  248. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/render_delegate.js +1 -1
  249. data/lib/frameworks/sproutcore/frameworks/foundation/resources/benchmark.css +0 -5
  250. data/lib/frameworks/sproutcore/frameworks/foundation/resources/bootstrap.rhtml +34 -19
  251. data/lib/frameworks/sproutcore/frameworks/foundation/resources/button_view.css +0 -2
  252. data/lib/frameworks/sproutcore/frameworks/foundation/resources/label.css +1 -5
  253. data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +8 -9
  254. data/lib/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +2 -2
  255. data/lib/frameworks/sproutcore/frameworks/foundation/system/module.js +179 -47
  256. data/lib/frameworks/sproutcore/frameworks/foundation/system/task_queue.js +34 -1
  257. data/lib/frameworks/sproutcore/frameworks/foundation/system/text_selection.js +1 -1
  258. data/lib/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +26 -12
  259. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/misc.js +7 -7
  260. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_measurement.js +12 -4
  261. data/lib/frameworks/sproutcore/frameworks/foundation/system/utils/string_metric_optimization.js +202 -0
  262. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/content_value_support/content.js +77 -8
  263. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/flowed_layout/tests.js +1 -0
  264. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/beginEditing.js +2 -2
  265. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/commitEditing.js +4 -3
  266. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editable/discardEditing.js +4 -2
  267. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/beginEditing.js +2 -2
  268. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/commitEditing.js +4 -2
  269. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_editor/discardEditing.js +4 -2
  270. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/utils/pointInElement.js +2 -2
  271. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/label/ui.js +0 -8
  272. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +163 -149
  273. data/lib/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +1 -1
  274. data/lib/frameworks/sproutcore/frameworks/foundation/validators/date.js +1 -1
  275. data/lib/frameworks/sproutcore/frameworks/foundation/validators/date_time.js +1 -1
  276. data/lib/frameworks/sproutcore/frameworks/foundation/validators/password.js +1 -1
  277. data/lib/frameworks/sproutcore/frameworks/foundation/validators/validator.js +3 -3
  278. data/lib/frameworks/sproutcore/frameworks/foundation/views/field.js +16 -43
  279. data/lib/frameworks/sproutcore/frameworks/foundation/views/image.js +4 -3
  280. data/lib/frameworks/sproutcore/frameworks/foundation/views/inline_text_field.js +67 -54
  281. data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +49 -38
  282. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +285 -242
  283. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-buffer.js +13 -13
  284. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-buffered.js +19 -22
  285. data/lib/frameworks/sproutcore/frameworks/jquery/jquery-sc.js +9 -3
  286. data/lib/frameworks/sproutcore/frameworks/jquery/jquery.js +231 -186
  287. data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +145 -143
  288. data/lib/frameworks/sproutcore/frameworks/media/views/video.js +156 -154
  289. data/lib/frameworks/sproutcore/frameworks/qunit/qunit/qunit.js +5 -5
  290. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +3 -3
  291. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js.orig +540 -0
  292. data/lib/frameworks/sproutcore/frameworks/routing/tests/system/routes.js +2 -2
  293. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +15 -8
  294. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/base.js +5 -5
  295. data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +12 -0
  296. data/lib/frameworks/sproutcore/frameworks/runtime/ext/function.js +2 -2
  297. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +1 -1
  298. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/copyable.js +1 -1
  299. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +7 -7
  300. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +98 -32
  301. data/lib/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +7 -2
  302. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +14 -3
  303. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +98 -13
  304. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +8 -14
  305. data/lib/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +1 -1
  306. data/lib/frameworks/sproutcore/frameworks/runtime/system/error.js +2 -2
  307. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +23 -6
  308. data/lib/frameworks/sproutcore/frameworks/runtime/system/logger.js +69 -18
  309. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +57 -31
  310. data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +189 -14
  311. data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +82 -22
  312. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/chained.js +20 -0
  313. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +125 -4
  314. data/lib/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue.js +1 -1
  315. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +2 -2
  316. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/rangeStartForIndex.js +37 -0
  317. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/remove.js +2 -2
  318. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/logger.js +16 -0
  319. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/run_loop.js +75 -4
  320. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/string.js +41 -0
  321. data/lib/frameworks/sproutcore/frameworks/statechart/mixins/statechart_delegate.js +113 -0
  322. data/lib/frameworks/sproutcore/frameworks/statechart/private/state_path_matcher.js +312 -0
  323. data/lib/frameworks/sproutcore/frameworks/statechart/system/async.js +18 -22
  324. data/lib/frameworks/sproutcore/frameworks/statechart/system/state.js +508 -131
  325. data/lib/frameworks/sproutcore/frameworks/statechart/system/state_route_handler_context.js +78 -0
  326. data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +265 -44
  327. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/basic/with_concurrent_states.js +16 -0
  328. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/responder/responder_chain.js +11 -3
  329. data/lib/frameworks/sproutcore/frameworks/statechart/tests/private/state_path_matcher.js +116 -0
  330. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/add_substate.js +108 -0
  331. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/find_first_relative_current_state/with_concurrent.js +179 -0
  332. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/find_first_relative_current_state/without_concurrent.js +74 -0
  333. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/get_state.js +141 -0
  334. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/get_substate.js +340 -0
  335. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/route_triggered.js +161 -0
  336. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state/methods/try_to_handle_event.js +288 -0
  337. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/history_state/standard/without_concurrent_states/context.js +5 -33
  338. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/routing/with_concurrent_states/basic.js +213 -0
  339. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/routing/without_concurrent_states/basic.js +212 -0
  340. data/lib/frameworks/sproutcore/frameworks/statechart/tests/state_transitioning/standard/without_concurrent_states/core.js +8 -0
  341. data/lib/frameworks/sproutcore/frameworks/statechart/tests/{state/namespacing.js → statechart/methods/get_state.js} +3 -41
  342. data/lib/frameworks/sproutcore/frameworks/statechart/tests/statechart/{invoke_state_method.js → methods/invoke_state_method.js} +1 -1
  343. data/lib/frameworks/sproutcore/frameworks/statechart/tests/{event_handling/advanced → statechart}/respond_to_event.js +1 -1
  344. data/lib/frameworks/sproutcore/frameworks/statechart/tests/system/state_route_handler_context/methods/retry.js +64 -0
  345. data/lib/frameworks/sproutcore/frameworks/table/core.js +2 -0
  346. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/controls/button.js +0 -1
  347. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars.js +29 -5
  348. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/bind.js +4 -3
  349. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/collection.js +0 -0
  350. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/localization.js +0 -0
  351. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/ext/handlebars/view.js +0 -0
  352. data/lib/frameworks/sproutcore/frameworks/{handlebars → template_view}/handlebars.js +493 -357
  353. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/mixins/template_helpers/checkbox_support.js +0 -0
  354. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/mixins/template_helpers/text_field_support.js +13 -2
  355. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/panes/template.js +0 -0
  356. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/controls/button.js +0 -0
  357. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/mixins/template_helpers/checkbox_support.js +0 -0
  358. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/mixins/template_helpers/text_field_support.js +0 -0
  359. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/panes/template.js +0 -0
  360. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/collection.js +39 -14
  361. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/core.js +0 -0
  362. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/tests/views/template/handlebars.js +57 -6
  363. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/bindable_span.js +21 -6
  364. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/template.js +9 -3
  365. data/lib/frameworks/sproutcore/frameworks/{core_foundation → template_view}/views/template_collection.js +55 -26
  366. data/lib/frameworks/sproutcore/frameworks/testing/system/equiv.js +1 -1
  367. data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +122 -122
  368. data/lib/frameworks/sproutcore/frameworks/testing/system/runner.js +2 -2
  369. data/lib/frameworks/sproutcore/frameworks/testing/system/suite.js +4 -4
  370. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/base.css +1 -1
  371. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/reset.css +0 -1
  372. data/lib/frameworks/sproutcore/frameworks/yuireset/resources/view.css +4 -4
  373. data/lib/frameworks/sproutcore/lib/index.rhtml +55 -32
  374. data/lib/frameworks/sproutcore/license.js +2 -4
  375. data/lib/frameworks/sproutcore/themes/ace/resources/body.css +5 -1
  376. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/18px/button.css +2 -2
  377. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/24px/button.css +21 -13
  378. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/30px/button.css +17 -10
  379. data/lib/frameworks/sproutcore/themes/ace/resources/button/ace/44px/button.css +4 -3
  380. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/24px/button.css +20 -12
  381. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/30px/button.css +16 -8
  382. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/jumbo/button.css +17 -0
  383. data/lib/frameworks/sproutcore/themes/ace/resources/button/dark/small/button.css +17 -0
  384. data/lib/frameworks/sproutcore/themes/ace/resources/disclosure/ace/disclosure.css +2 -2
  385. data/lib/frameworks/sproutcore/themes/ace/resources/master-detail/master-detail.css +2 -2
  386. data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +5 -3
  387. data/lib/frameworks/sproutcore/themes/iphone_theme/english.lproj/core.css +1 -1
  388. data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/toolbar.css +1 -1
  389. data/lib/gen/app/USAGE +17 -4
  390. data/lib/gen/language/Buildfile +4 -4
  391. data/lib/gen/language/USAGE +4 -4
  392. data/lib/gen/page/templates/pages/@target_name@/Buildfile +7 -7
  393. data/lib/gen/{html_app → statechart_app}/Buildfile +0 -0
  394. data/lib/gen/{html_app → statechart_app}/README +0 -0
  395. data/lib/gen/statechart_app/USAGE +21 -0
  396. data/lib/gen/statechart_app/templates/apps/@target_name@/Buildfile +9 -0
  397. data/lib/gen/statechart_app/templates/apps/@target_name@/core.js +24 -0
  398. data/lib/gen/statechart_app/templates/apps/@target_name@/main.js +26 -0
  399. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/_theme.css +18 -0
  400. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/loading.rhtml +9 -0
  401. data/lib/gen/statechart_app/templates/apps/@target_name@/resources/main_page.js +21 -0
  402. data/lib/gen/statechart_app/templates/apps/@target_name@/statechart.js +8 -0
  403. data/lib/gen/statechart_app/templates/apps/@target_name@/states/ready_state.js +12 -0
  404. data/lib/gen/statechart_app/templates/apps/@target_name@/theme.js +24 -0
  405. data/lib/sproutcore/builders.rb +1 -0
  406. data/lib/sproutcore/builders/base.rb +19 -1
  407. data/lib/sproutcore/builders/chance_file.rb +6 -1
  408. data/lib/sproutcore/builders/handlebars.rb +1 -9
  409. data/lib/sproutcore/builders/javascript.rb +1 -10
  410. data/lib/sproutcore/builders/json.rb +25 -0
  411. data/lib/sproutcore/builders/less.rb +1 -1
  412. data/lib/sproutcore/builders/sass.rb +1 -1
  413. data/lib/sproutcore/builders/stylesheet.rb +1 -9
  414. data/lib/sproutcore/helpers/html5_manifest.rb +1 -1
  415. data/lib/sproutcore/helpers/static_helper.rb +42 -0
  416. data/lib/sproutcore/rack/proxy.rb +21 -3
  417. data/lib/sproutcore/rack/service.rb +3 -2
  418. data/lib/sproutcore/tools.rb +18 -25
  419. data/lib/sproutcore/tools/gen.rb +10 -3
  420. data/lib/sproutcore/tools/init.rb +11 -10
  421. data/spec/buildtasks/manifest/prepare_build_tasks/json_spec.rb +62 -0
  422. data/spec/fixtures/builder_tests/apps/handlebars_test/Buildfile +1 -1
  423. data/spec/fixtures/builder_tests/apps/json_test/sc_static.json +2 -0
  424. data/spec/lib/builders/json_spec.rb +53 -0
  425. data/sproutcore.gemspec +2 -2
  426. data/vendor/chance/lib/chance/parser.rb +1 -1
  427. metadata +222 -177
  428. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/datetime.js +0 -0
  429. data/lib/frameworks/sproutcore/frameworks/debug/invoke_once_last_debugging.js +0 -259
  430. data/lib/frameworks/sproutcore/frameworks/documentation/core.js +0 -0
  431. data/lib/frameworks/sproutcore/frameworks/foundation/system/chance.js +0 -69
  432. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/editable/ui.js +0 -44
  433. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/inline_text_field/ui.js +0 -64
  434. data/lib/frameworks/sproutcore/frameworks/mini/license.js +0 -30
  435. data/lib/gen/html_app/USAGE +0 -15
  436. data/lib/gen/html_app/templates/apps/@target_name@/@target_name@.js +0 -11
  437. data/lib/gen/html_app/templates/apps/@target_name@/resources/images/.gitkeep +0 -0
  438. data/lib/gen/html_app/templates/apps/@target_name@/resources/stylesheets/@target_name@.css +0 -6
  439. data/lib/gen/html_app/templates/apps/@target_name@/resources/templates/@target_name@.handlebars +0 -1
  440. data/lib/gen/html_project/Buildfile +0 -45
  441. data/lib/gen/html_project/INIT +0 -3
  442. data/lib/gen/html_project/README +0 -1
  443. data/lib/gen/html_project/USAGE +0 -2
  444. data/lib/gen/html_project/templates/@filename@/Buildfile +0 -5
  445. data/lib/gen/html_project/templates/@filename@/README +0 -4
@@ -19,13 +19,13 @@
19
19
  */
20
20
  SC.Async = SC.Object.extend(
21
21
  /** @scope SC.Async.prototype */{
22
-
22
+
23
23
  func: null,
24
-
24
+
25
25
  arg1: null,
26
-
26
+
27
27
  arg2: null,
28
-
28
+
29
29
  /** @private
30
30
  Called by the statechart
31
31
  */
@@ -34,49 +34,45 @@ SC.Async = SC.Object.extend(
34
34
  arg1 = this.get('arg1'),
35
35
  arg2 = this.get('arg2'),
36
36
  funcType = SC.typeOf(func);
37
-
37
+
38
38
  if (funcType === SC.T_STRING) {
39
39
  state.tryToPerform(func, arg1, arg2);
40
- }
40
+ }
41
41
  else if (funcType === SC.T_FUNCTION) {
42
42
  func.apply(state, [arg1, arg2]);
43
43
  }
44
44
  }
45
-
45
+
46
46
  });
47
47
 
48
48
  /**
49
49
  Singleton
50
50
  */
51
51
  SC.Async.mixin(/** @scope SC.Async */{
52
-
52
+
53
53
  /**
54
54
  Call in either a state's enterState or exitState method when you
55
55
  want a state to perform an asynchronous action, such as an animation.
56
-
56
+
57
57
  Examples:
58
-
59
- {{
60
-
58
+
61
59
  SC.State.extend({
62
-
60
+
63
61
  enterState: function() {
64
62
  return SC.Async.perform('foo');
65
63
  },
66
-
64
+
67
65
  exitState: function() {
68
66
  return SC.Async.perform('bar', 100);
69
67
  }
70
-
68
+
71
69
  foo: function() { ... },
72
-
70
+
73
71
  bar: function(arg) { ... }
74
-
72
+
75
73
  });
76
-
77
- }}
78
-
79
- @param func {String|Function} the functio to be invoked on a state
74
+
75
+ @param func {String|Function} the function to be invoked on a state
80
76
  @param arg1 Optional. An argument to pass to the given function
81
77
  @param arg2 Optional. An argument to pass to the given function
82
78
  @return {SC.Async} a new instance of a SC.Async
@@ -84,5 +80,5 @@ SC.Async.mixin(/** @scope SC.Async */{
84
80
  perform: function(func, arg1, arg2) {
85
81
  return SC.Async.create({ func: func, arg1: arg1, arg2: arg2 });
86
82
  }
87
-
83
+
88
84
  });
@@ -110,6 +110,25 @@ SC.State = SC.Object.extend(
110
110
  */
111
111
  enteredSubstates: null,
112
112
 
113
+ /**
114
+ Can optionally assign what route this state is to represent.
115
+
116
+ If assigned then this state will be notified to handle the route when triggered
117
+ any time the app's location changes and matches this state's assigned route.
118
+ The handler invoked is this state's {@link #routeTriggered} method.
119
+
120
+ The value assigned to this property is dependent on the underlying routing
121
+ mechanism used by the application. The default routing mechanism is to use
122
+ SC.routes.
123
+
124
+ @property {String|Hash}
125
+
126
+ @see #routeTriggered
127
+ @see #location
128
+ @see SC.StatechartDelegate
129
+ */
130
+ representRoute: null,
131
+
113
132
  /**
114
133
  Indicates if this state should trace actions. Useful for debugging
115
134
  purposes. Managed by the statechart.
@@ -139,6 +158,49 @@ SC.State = SC.Object.extend(
139
158
  return owner ? owner : sc;
140
159
  }.property().cacheable(),
141
160
 
161
+ /**
162
+ Returns the statechart's assigned delegate. A statechart delegate is one
163
+ that adheres to the {@link SC.StatechartDelegate} mixin.
164
+
165
+ @property {SC.Object}
166
+
167
+ @see SC.StatechartDelegate
168
+ */
169
+ statechartDelegate: function() {
170
+ return this.getPath('statechart.statechartDelegate');
171
+ }.property().cacheable(),
172
+
173
+ /**
174
+ A volatile property used to get and set the app's current location.
175
+
176
+ This computed property defers to the the statechart's delegate to
177
+ actually update and acquire the app's location.
178
+
179
+ Note: Binding for this pariticular case is discouraged since in most
180
+ cases we need the location value immediately. If we were to use
181
+ bindings then the location value wouldn't be updated until at least
182
+ the end of one run loop. It is also advised that the delegate not
183
+ have its `statechartUpdateLocationForState` and
184
+ `statechartAcquireLocationForState` methods implemented where bindings
185
+ are used since they will inadvertenly stall the location value from
186
+ propogating immediately.
187
+
188
+ @property {String}
189
+
190
+ @see SC.StatechartDelegate#statechartUpdateLocationForState
191
+ @see SC.StatechartDelegate#statechartAcquireLocationForState
192
+ */
193
+ location: function(key, value) {
194
+ var sc = this.get('statechart'),
195
+ del = this.get('statechartDelegate');
196
+
197
+ if (value !== undefined) {
198
+ del.statechartUpdateLocationForState(sc, value, this);
199
+ }
200
+
201
+ return del.statechartAcquireLocationForState(sc, this);
202
+ }.property().idempotent(),
203
+
142
204
  init: function() {
143
205
  sc_super();
144
206
 
@@ -146,9 +208,14 @@ SC.State = SC.Object.extend(
146
208
  this._registeredStringEventHandlers = {};
147
209
  this._registeredRegExpEventHandlers = [];
148
210
  this._registeredStateObserveHandlers = {};
211
+ this._registeredSubstatePaths = {};
212
+ this._registeredSubstates = [];
213
+ this._isEnteringState = NO;
214
+ this._isExitingState = NO;
149
215
 
150
216
  // Setting up observes this way is faster then using .observes,
151
217
  // which adds a noticable increase in initialization time.
218
+
152
219
  var sc = this.get('statechart'),
153
220
  ownerKey = sc ? sc.get('statechartOwnerKey') : null,
154
221
  traceKey = sc ? sc.get('statechartTraceKey') : null;
@@ -168,13 +235,13 @@ SC.State = SC.Object.extend(
168
235
  sc.removeObserver(ownerKey, this, '_statechartOwnerDidChange');
169
236
  sc.removeObserver(traceKey, this, '_statechartTraceDidChange');
170
237
  }
171
-
238
+
172
239
  var substates = this.get('substates');
173
240
  if (substates) {
174
241
  substates.forEach(function(state) {
175
242
  state.destroy();
176
243
  });
177
- }
244
+ }
178
245
 
179
246
  this._teardownAllStateObserveHandlers();
180
247
 
@@ -193,6 +260,8 @@ SC.State = SC.Object.extend(
193
260
  this._registeredStringEventHandlers = null;
194
261
  this._registeredRegExpEventHandlers = null;
195
262
  this._registeredStateObserveHandlers = null;
263
+ this._registeredSubstatePaths = null;
264
+ this._registeredSubstates = null;
196
265
 
197
266
  sc_super();
198
267
  },
@@ -204,6 +273,7 @@ SC.State = SC.Object.extend(
204
273
  if (this.get('stateIsInitialized')) return;
205
274
 
206
275
  this._registerWithParentStates();
276
+ this._setupRouteHandling();
207
277
 
208
278
  var key = null,
209
279
  value = null,
@@ -217,9 +287,11 @@ SC.State = SC.Object.extend(
217
287
  len = 0,
218
288
  valueIsFunc = NO,
219
289
  historyState = null;
290
+
291
+ this.set('substates', substates);
220
292
 
221
293
  if (SC.kindOf(initialSubstate, SC.HistoryState) && initialSubstate.isClass) {
222
- historyState = this.createHistoryState(initialSubstate, { parentState: this, statechart: statechart });
294
+ historyState = this.createSubstate(initialSubstate);
223
295
  this.set('initialSubstate', historyState);
224
296
 
225
297
  if (SC.none(historyState.get('defaultState'))) {
@@ -250,10 +322,7 @@ SC.State = SC.Object.extend(
250
322
  }
251
323
 
252
324
  if (SC.kindOf(value, SC.State) && value.isClass && this[key] !== this.constructor) {
253
- state = this.createSubstate(value, { name: key, parentState: this, statechart: statechart });
254
- substates.push(state);
255
- this[key] = state;
256
- state.initState();
325
+ state = this._addSubstate(key, value);
257
326
  if (key === initialSubstate) {
258
327
  this.set('initialSubstate', state);
259
328
  matchedInitialSubstate = YES;
@@ -274,45 +343,224 @@ SC.State = SC.Object.extend(
274
343
  }
275
344
  }
276
345
  else if (substates.length > 0) {
277
- if (SC.none(initialSubstate) && !substatesAreConcurrent) {
278
- state = this.createEmptyState({ parentState: this, statechart: statechart });
279
- this.set('initialSubstate', state);
280
- substates.push(state);
281
- this[state.get('name')] = state;
282
- state.initState();
283
- this.stateLogWarning("state %@ has no initial substate defined. Will default to using an empty state as initial substate".fmt(this));
284
- }
285
- else if (!SC.none(initialSubstate) && substatesAreConcurrent) {
346
+ state = this._addEmptyInitialSubstateIfNeeded();
347
+ if (!state && initialSubstate && substatesAreConcurrent) {
286
348
  this.set('initialSubstate', null);
287
349
  this.stateLogWarning("Can not use %@ as initial substate since substates are all concurrent for state %@".fmt(initialSubstate, this));
288
350
  }
289
351
  }
290
352
 
291
- this.set('substates', substates);
353
+ this.notifyPropertyChange('substates');
292
354
  this.set('currentSubstates', []);
293
355
  this.set('enteredSubstates', []);
294
356
  this.set('stateIsInitialized', YES);
295
357
  },
296
358
 
359
+ /** @private
360
+
361
+ Used to bind this state with a route this state is to represent if a route has been assigned.
362
+
363
+ When invoked, the method will delegate the actual binding strategy to the statechart delegate
364
+ via the delegate's {@link SC.StatechartDelegate#statechartBindStateToRoute} method.
365
+
366
+ Note that a state cannot be bound to a route if this state is a concurrent state.
367
+
368
+ @see #representRoute
369
+ @see SC.StatechartDelegate#statechartBindStateToRoute
370
+ */
371
+ _setupRouteHandling: function() {
372
+ var route = this.get('representRoute'),
373
+ sc = this.get('statechart'),
374
+ del = this.get('statechartDelegate');
375
+
376
+ if (!route) return;
377
+
378
+ if (this.get('isConcurrentState')) {
379
+ this.stateLogError("State %@ cannot handle route '%@' since state is concurrent".fmt(this, route));
380
+ return;
381
+ }
382
+
383
+ del.statechartBindStateToRoute(sc, this, route, this.routeTriggered);
384
+ },
385
+
386
+ /**
387
+ Main handler that gets triggered whenever the app's location matches this state's assigned
388
+ route.
389
+
390
+ When invoked the handler will first refer to the statechart delegate to determine if it
391
+ should actually handle the route via the delegate's
392
+ {@see SC.StatechartDelegate#statechartShouldStateHandleTriggeredRoute} method. If the
393
+ delegate allows the handling of the route then the state will continue on with handling
394
+ the triggered route by calling the state's {@link #handleTriggeredRoute} method, otherwise
395
+ the state will cancel the handling and inform the delegate through the delegate's
396
+ {@see SC.StatechartDelegate#statechartStateCancelledHandlingRoute} method.
397
+
398
+ The handler will create a state route context ({@link SC.StateRouteContext}) object
399
+ that packages information about what is being currently handled. This context object gets
400
+ passed along to the delegate's invoked methods as well as the state transition process.
401
+
402
+ Note that this method is not intended to be directly called or overridden.
403
+
404
+ @see #representRoute
405
+ @see SC.StatechartDelegate#statechartShouldStateHandleRoute
406
+ @see SC.StatechartDelegate#statechartStateCancelledHandlingRoute
407
+ @see #createStateRouteHandlerContext
408
+ @see #handleTriggeredRoute
409
+ */
410
+ routeTriggered: function(params) {
411
+ if (this._isEnteringState) return;
412
+
413
+ var sc = this.get('statechart'),
414
+ del = this.get('statechartDelegate'),
415
+ loc = this.get('location');
416
+
417
+ var attr = {
418
+ state: this,
419
+ location: loc,
420
+ params: params,
421
+ handler: this.routeTriggered
422
+ };
423
+
424
+ var context = this.createStateRouteHandlerContext(attr);
425
+
426
+ if (del.statechartShouldStateHandleTriggeredRoute(sc, this, context)) {
427
+ if (this.get('trace') && loc) {
428
+ this.stateLogTrace("will handle route '%@'".fmt(loc));
429
+ }
430
+ this.handleTriggeredRoute(context);
431
+ } else {
432
+ del.statechartStateCancelledHandlingTriggeredRoute(sc, this, context);
433
+ }
434
+ },
435
+
297
436
  /**
298
- creates a substate for this state
437
+ Constructs a new instance of a state routing context object.
438
+
439
+ @param {Hash} attr attributes to apply to the constructed object
440
+ @return {SC.StateRouteContext}
441
+
442
+ @see #handleRoute
299
443
  */
300
- createSubstate: function(state, attrs) {
301
- return state.create(attrs);
444
+ createStateRouteHandlerContext: function(attr) {
445
+ return SC.StateRouteHandlerContext.create(attr);
302
446
  },
303
447
 
304
448
  /**
305
- Create a history state for this state
449
+ Invoked by this state's {@link #routeTriggered} method if the state is
450
+ actually allowed to handle the triggered route.
451
+
452
+ By default the method invokes a state transition to this state.
306
453
  */
307
- createHistoryState: function(state, attrs) {
308
- return state.create(attrs);
454
+ handleTriggeredRoute: function(context) {
455
+ this.gotoState(this, context);
456
+ },
457
+
458
+ /** @private */
459
+ _addEmptyInitialSubstateIfNeeded: function() {
460
+ var initialSubstate = this.get('initialSubstate'),
461
+ substatesAreConcurrent = this.get('substatesAreConcurrent');
462
+
463
+ if (initialSubstate || substatesAreConcurrent) return null;
464
+
465
+ var state = this.createSubstate(SC.EmptyState);
466
+ this.set('initialSubstate', state);
467
+ this.get('substates').push(state);
468
+ this[state.get('name')] = state;
469
+ state.initState();
470
+ this.stateLogWarning("state %@ has no initial substate defined. Will default to using an empty state as initial substate".fmt(this));
471
+ return state;
472
+ },
473
+
474
+ /** @private */
475
+ _addSubstate: function(name, state, attr) {
476
+ var substates = this.get('substates');
477
+
478
+ attr = SC.clone(attr) || {};
479
+ attr.name = name;
480
+ state = this.createSubstate(state, attr);
481
+ substates.push(state);
482
+ this[name] = state;
483
+ state.initState();
484
+ return state;
309
485
  },
310
486
 
311
487
  /**
312
- Create an empty state for this state's initial substate
488
+ Used to dynamically add a substate to this state. Once added successfully you
489
+ are then able to go to it from any other state within the owning statechart.
490
+
491
+ A couple of notes when adding a substate:
492
+
493
+ - If this state does not have any substates, then in addition to the
494
+ substate being added, an empty state will also be added and set as the
495
+ initial substate. To make the added substate the initial substate, set
496
+ this object's initialSubstate property.
497
+
498
+ - If this state is a current state, the added substate will not be entered.
499
+
500
+ - If this state is entered and its substates are concurrent, the added
501
+ substate will not be entered.
502
+
503
+ If this state is either entered or current and you'd like the added substate
504
+ to take affect, you will need to explicitly reenter this state by calling
505
+ its `reenter` method.
506
+
507
+ Be aware that the name of the state you are adding must not conflict with
508
+ the name of a property on this state or else you will get an error.
509
+ In addition, this state must be initialized to add substates.
510
+
511
+ @param {String} name a unique name for the given substate.
512
+ @param {SC.State} state a class that derives from `SC.State`
513
+ @param {Hash} [attr] liternal to be applied to the substate
514
+ @returns {SC.State} an instance of the given state class
313
515
  */
314
- createEmptyState: function(attrs) {
315
- return SC.EmptyState.create(attrs);
516
+ addSubstate: function(name, state, attr) {
517
+ if (SC.empty(name)) {
518
+ this.stateLogError("Can not add substate. name required");
519
+ return null;
520
+ }
521
+
522
+ if (this[name] !== undefined) {
523
+ this.stateLogError("Can not add substate '%@'. Already a defined property".fmt(name));
524
+ return null;
525
+ }
526
+
527
+ if (!this.get('stateIsInitialized')) {
528
+ this.stateLogError("Can not add substate '%@'. this state is not yet initialized".fmt(name));
529
+ return null;
530
+ }
531
+
532
+ var len = arguments.length;
533
+
534
+ if (len === 1) {
535
+ state = SC.State;
536
+ } else if (len === 2 && SC.typeOf(state) === SC.T_HASH) {
537
+ attr = state;
538
+ state = SC.State;
539
+ }
540
+
541
+ var stateIsValid = SC.kindOf(state, SC.State) && state.isClass;
542
+
543
+ if (!stateIsValid) {
544
+ this.stateLogError("Can not add substate '%@'. must provide a state class".fmt(name));
545
+ return null;
546
+ }
547
+
548
+ state = this._addSubstate(name, state, attr);
549
+ this._addEmptyInitialSubstateIfNeeded();
550
+ this.notifyPropertyChange('substates');
551
+
552
+ return state;
553
+ },
554
+
555
+ /**
556
+ creates a substate for this state
557
+ */
558
+ createSubstate: function(state, attr) {
559
+ attr = attr || {};
560
+ return state.create({
561
+ parentState: this,
562
+ statechart: this.get('statechart')
563
+ }, attr);
316
564
  },
317
565
 
318
566
  /** @private
@@ -384,7 +632,6 @@ SC.State = SC.Object.extend(
384
632
  this state with them.
385
633
  */
386
634
  _registerWithParentStates: function() {
387
- this._registerSubstate(this);
388
635
  var parent = this.get('parentState');
389
636
  while (!SC.none(parent)) {
390
637
  parent._registerSubstate(this);
@@ -399,25 +646,17 @@ SC.State = SC.Object.extend(
399
646
  var path = state.pathRelativeTo(this);
400
647
  if (SC.none(path)) return;
401
648
 
402
- // Create special private member variables to help
403
- // keep track of substates and access them.
404
- if (SC.none(this._registeredSubstatePaths)) {
405
- this._registeredSubstatePaths = {};
406
- this._registeredSubstates = [];
407
- }
408
-
409
649
  this._registeredSubstates.push(state);
410
650
 
411
651
  // Keep track of states based on their relative path
412
652
  // to this state.
413
653
  var regPaths = this._registeredSubstatePaths;
414
654
  if (regPaths[state.get('name')] === undefined) {
415
- regPaths[state.get('name')] = { __ki_paths__: [] };
655
+ regPaths[state.get('name')] = { };
416
656
  }
417
657
 
418
658
  var paths = regPaths[state.get('name')];
419
659
  paths[path] = state;
420
- paths.__ki_paths__.push(path);
421
660
  },
422
661
 
423
662
  /**
@@ -451,15 +690,37 @@ SC.State = SC.Object.extend(
451
690
  If the value is a state object, then the value will be returned if it is indeed
452
691
  a substate of this state, otherwise null is returned.
453
692
 
454
- If the given value is a string, then the string is assumed to be a path to a substate.
455
- The value is then parsed to find the closes match. If there is no match then null
456
- is returned. If there is more than one match then null is return and an error
457
- is generated indicating ambiguity of the given value.
693
+ If the given value is a string, then the string is assumed to be a path expression
694
+ to a substate. The value is then parsed to find the closes match. For path expression
695
+ syntax, refer to the {@link SC.StatePathMatcher} class.
696
+
697
+ If there is no match then null is returned. If there is more than one match then null
698
+ is return and an error is generated indicating ambiguity of the given value.
699
+
700
+ An optional callback can be provided to handle the scenario when either no
701
+ substate is found or there is more than one match. The callback is then given
702
+ the opportunity to further handle the outcome and return a result which the
703
+ getSubstate method will then return. The callback should have the following
704
+ signature:
705
+
706
+ function(state, value, paths)
707
+
708
+ - state: The state getState was invoked on
709
+ - value: The value supplied to getState
710
+ - paths: An array of substate paths that matched the given value
711
+
712
+ If there were no matches then `paths` is not provided to the callback.
458
713
 
459
- Note that when the value is a string, it is assumed to be a path relative to this
460
- state; not the root state of the statechart.
714
+ You can also optionally provide a target that the callback is invoked on. If no
715
+ target is provided then this state is used as the target.
716
+
717
+ @param value {State|String} used to identify a substate of this state
718
+ @param [callback] {Function} the callback
719
+ @param [target] {Object} the target
461
720
  */
462
- getSubstate: function(value) {
721
+ getSubstate: function(value, callback, target) {
722
+ if (!value) return null;
723
+
463
724
  var valueType = SC.typeOf(value);
464
725
 
465
726
  // If the value is an object then just check if the value is
@@ -473,107 +734,141 @@ SC.State = SC.Object.extend(
473
734
  return null;
474
735
  }
475
736
 
476
- // The value is a string. Therefore treat the value as a relative path to
477
- // a substate of this state.
478
-
479
- // Extract that last part of the string. Ex. 'foo' => 'foo', 'foo.bar' => 'bar'
480
- var matches = value.match(/(^|\.)(\w+)$/);
481
- if (!matches) return null;
737
+ var matcher = SC.StatePathMatcher.create({ state: this, expression: value }),
738
+ matches = [], key;
482
739
 
483
- // Get all the paths related to the matched value. If no paths then return null.
484
- var paths = this._registeredSubstatePaths[matches[2]];
485
- if (SC.none(paths)) return null;
486
-
487
- // Do a quick check to see if there is a path that exactly matches the given
488
- // value, and if so return the corresponding state
489
- var state = paths[value];
490
- if (!SC.none(state)) return state;
491
-
492
- // No exact match found. If the value given is a basic string with no ".", then check
493
- // if there is only one path containing that string. If so, return it. If there is
494
- // more than one path then it is ambiguous as to what state is trying to be reached.
495
- if (matches[1] === "") {
496
- if (paths.__ki_paths__.length === 1) return paths[paths.__ki_paths__[0]];
497
- if (paths.__ki_paths__.length > 1) {
498
- var msg = 'Can not find substate matching %@ in state %@. Ambiguous with the following: %@';
499
- this.stateLogError(msg.fmt(value, this, paths.__ki_paths__));
740
+ if (matcher.get('tokens').length === 0) return null;
741
+
742
+ var paths = this._registeredSubstatePaths[matcher.get('lastPart')];
743
+ if (!paths) return this._notifySubstateNotFound(callback, target, value);
744
+
745
+ for (key in paths) {
746
+ if (matcher.match(key)) {
747
+ matches.push(paths[key]);
500
748
  }
749
+ }
750
+
751
+ if (matches.length === 1) return matches[0];
752
+
753
+ if (matches.length > 1) {
754
+ var keys = [];
755
+ for (key in paths) { keys.push(key); }
756
+
757
+ if (callback) return this._notifySubstateNotFound(callback, target, value, keys);
758
+
759
+ var msg = "Can not find substate matching '%@' in state %@. Ambiguous with the following: %@";
760
+ this.stateLogError(msg.fmt(value, this.get('fullPath'), keys.join(', ')));
501
761
  }
502
762
 
503
- return null;
763
+ return this._notifySubstateNotFound(callback, target, value);
764
+ },
765
+
766
+ /** @private */
767
+ _notifySubstateNotFound: function(callback, target, value, keys) {
768
+ return callback ? callback.call(target || this, this, value, keys) : null;
504
769
  },
505
770
 
506
771
  /**
507
- Used to go to a state in the statechart either directly from this state if it is a current state,
508
- or from one of this state's current substates.
772
+ Will attempt to get a state relative to this state.
509
773
 
510
- Note that if the value given is a string, it will be assumed to be a path to a state. The path
511
- will be relative to the statechart's root state; not relative to this state.
774
+ A state is returned based on the following:
512
775
 
513
- Method can be called in the following ways:
776
+ 1. First check this state's substates for a match; and
777
+ 2. If no matching substate then attempt to get the state from
778
+ this state's parent state.
779
+
780
+ Therefore states are recursively traversed up to the root state
781
+ to identify a match, and if found is ultimately returned, otherwise
782
+ null is returned. In the case that the value supplied is ambiguous
783
+ an error message is returned.
514
784
 
515
- // With one argument
516
- gotoState(<state>)
517
-
518
- // With two arguments
519
- gotoState(<state>, <hash>)
520
-
521
- Where <state> is either a string or a SC.State object and <hash> is a regular JS hash object.
522
-
523
- @param state {SC.State|String} the state to go to
524
- @param context {Hash} Optional. context object that will be supplied to all states that are
525
- exited and entered during the state transition process
785
+ The value provided can either be a state object or a state path expression.
786
+ For path expression syntax, refer to the {@link SC.StatePathMatcher} class.
526
787
  */
527
- gotoState: function(state, context) {
528
- var fromState = null;
788
+ getState: function(value) {
789
+ if (value === this.get('name')) return this;
790
+ if (SC.kindOf(value, SC.State)) return value;
791
+ return this.getSubstate(value, this._handleSubstateNotFound);
792
+ },
793
+
794
+ /** @private */
795
+ _handleSubstateNotFound: function(state, value, keys) {
796
+ var parentState = this.get('parentState');
797
+
798
+ if (parentState) return parentState.getState(value);
529
799
 
530
- if (this.get('isCurrentState')) {
531
- fromState = this;
532
- } else if (this.get('hasCurrentSubstates')) {
533
- fromState = this.get('currentSubstates')[0];
800
+ if (keys) {
801
+ var msg = "Can not find state matching '%@'. Ambiguous with the following: %@";
802
+ this.stateLogError(msg.fmt(value, keys.join(', ')));
534
803
  }
535
804
 
536
- this.get('statechart').gotoState(state, fromState, context);
805
+ return null;
806
+ },
807
+
808
+ /**
809
+ Used to go to a state in the statechart either directly from this state if it is a current state,
810
+ or from the first relative current state from this state.
811
+
812
+ If the value given is a string then it is considered a state path expression. The path is then
813
+ used to find a state relative to this state based on rules of the {@link #getState} method.
814
+
815
+ @param value {SC.State|String} the state to go to
816
+ @param [context] {Hash|Object} context object that will be supplied to all states that are
817
+ exited and entered during the state transition process. Context can not be an instance of
818
+ SC.State.
819
+ */
820
+ gotoState: function(value, context) {
821
+ var state = this.getState(value);
822
+
823
+ if (!state) {
824
+ var msg = "can not go to state %@ from state %@. Invalid value.";
825
+ this.stateLogError(msg.fmt(value, this));
826
+ return;
827
+ }
828
+
829
+ var from = this.findFirstRelativeCurrentState(state);
830
+ this.get('statechart').gotoState(state, from, false, context);
537
831
  },
538
832
 
539
833
  /**
540
834
  Used to go to a given state's history state in the statechart either directly from this state if it
541
835
  is a current state or from one of this state's current substates.
542
836
 
543
- Note that if the value given is a string, it will be assumed to be a path to a state. The path
544
- will be relative to the statechart's root state; not relative to this state.
837
+ If the value given is a string then it is considered a state path expression. The path is then
838
+ used to find a state relative to this state based on rules of the {@link #getState} method.
545
839
 
546
840
  Method can be called in the following ways:
547
841
 
548
842
  // With one argument
549
- gotoHistoryState(<state>)
843
+ gotoHistoryState(<value>)
550
844
 
551
845
  // With two arguments
552
- gotoHistoryState(<state>, <boolean | hash>)
846
+ gotoHistoryState(<value>, <boolean | hash>)
553
847
 
554
848
  // With three arguments
555
- gotoHistoryState(<state>, <boolean>, <hash>)
849
+ gotoHistoryState(<value>, <boolean>, <hash>)
556
850
 
557
- Where <state> is either a string or a SC.State object and <hash> is a regular JS hash object.
851
+ Where <value> is either a string or a SC.State object and <hash> is a regular JS hash object.
558
852
 
559
- @param state {SC.State|String} the state whose history state to go to
560
- @param recusive {Boolean} Optional. Indicates whether to follow history states recusively starting
853
+ @param value {SC.State|String} the state whose history state to go to
854
+ @param [recusive] {Boolean} indicates whether to follow history states recusively starting
561
855
  from the given state
562
- @param context {Hash} Optional. context object that will be supplied to all states that are exited
563
- entered during the state transition process
856
+ @param [context] {Hash|Object} context object that will be supplied to all states that are exited
857
+ entered during the state transition process. Context can not be an instance of SC.State.
564
858
  */
565
- gotoHistoryState: function(state, recursive, context) {
566
- var fromState = null;
859
+ gotoHistoryState: function(value, recursive, context) {
860
+ var state = this.getState(value);
567
861
 
568
- if (this.get('isCurrentState')) {
569
- fromState = this;
570
- } else if (this.get('hasCurrentSubstates')) {
571
- fromState = this.get('currentSubstates')[0];
862
+ if (!state) {
863
+ var msg = "can not go to history state %@ from state %@. Invalid value.";
864
+ this.stateLogError(msg.fmt(value, this));
865
+ return;
572
866
  }
573
867
 
574
- this.get('statechart').gotoHistoryState(state, fromState, recursive, context);
868
+ var from = this.findFirstRelativeCurrentState(state);
869
+ this.get('statechart').gotoHistoryState(state, from, recursive, context);
575
870
  },
576
-
871
+
577
872
  /**
578
873
  Resumes an active goto state transition process that has been suspended.
579
874
  */
@@ -668,17 +963,57 @@ SC.State = SC.Object.extend(
668
963
  var entered = this.get('enteredSubstates');
669
964
  return !!entered && entered.get('length') > 0;
670
965
  }.property('enteredSubstates').cacheable(),
671
-
966
+
967
+ /**
968
+ Will attempt to find a current state in the statechart that is relative to
969
+ this state.
970
+
971
+ Ordered set of rules to find a relative current state:
972
+
973
+ 1. If this state is a current state then it will be returned
974
+
975
+ 2. If this state has no current states and this state has a parent state then
976
+ return parent state's first relative current state, otherwise return null
977
+
978
+ 3. If this state has more than one current state then use the given anchor state
979
+ to get a corresponding substate that can be used to find a current state relative
980
+ to the substate, if a substate was found.
981
+
982
+ 4. If (3) did not find a relative current state then default to returning
983
+ this state's first current substate.
984
+
985
+ @param anchor {State|String} Optional. a substate of this state used to help direct
986
+ finding a current state
987
+ @return {SC.State} a current state
988
+ */
989
+ findFirstRelativeCurrentState: function(anchor) {
990
+ if (this.get('isCurrentState')) return this;
991
+
992
+ var currentSubstates = this.get('currentSubstates') || [],
993
+ numCurrent = currentSubstates.get('length'),
994
+ parent = this.get('parentState');
995
+
996
+ if (numCurrent === 0) {
997
+ return parent ? parent.findFirstRelativeCurrentState() : null;
998
+ }
999
+
1000
+ if (numCurrent > 1) {
1001
+ anchor = this.getSubstate(anchor);
1002
+ if (anchor) return anchor.findFirstRelativeCurrentState();
1003
+ }
1004
+
1005
+ return currentSubstates[0];
1006
+ },
1007
+
672
1008
  /**
673
1009
  Used to re-enter this state. Call this only when the state a current state of
674
1010
  the statechart.
675
1011
  */
676
1012
  reenter: function() {
677
- var statechart = this.get('statechart');
678
- if (this.get('isCurrentState')) {
679
- statechart.gotoState(this);
1013
+ if (this.get('isEnteredState')) {
1014
+ this.gotoState(this);
680
1015
  } else {
681
- SC.Logger.error('Can not re-enter state %@ since it is not a current state in the statechart'.fmt(this));
1016
+ SC.Logger.error('Can not re-enter state %@ since it is not an entered state in the statechart'.fmt(this));
682
1017
  }
683
1018
  },
684
1019
 
@@ -728,31 +1063,39 @@ SC.State = SC.Object.extend(
728
1063
  */
729
1064
  tryToHandleEvent: function(event, arg1, arg2) {
730
1065
 
731
- var trace = this.get('trace');
1066
+ var trace = this.get('trace'),
1067
+ sc = this.get('statechart'),
1068
+ ret;
732
1069
 
733
1070
  // First check if the name of the event is the same as a registered event handler. If so,
734
1071
  // then do not handle the event.
735
1072
  if (this._registeredEventHandlers[event]) {
736
- this.stateLogWarning("state %@ can not handle event %@ since it is a registered event handler".fmt(this, event));
1073
+ this.stateLogWarning("state %@ can not handle event '%@' since it is a registered event handler".fmt(this, event));
737
1074
  return NO;
738
1075
  }
739
1076
 
740
1077
  if (this._registeredStateObserveHandlers[event]) {
741
- this.stateLogWarning("state %@ can not handle event %@ since it is a registered state observe handler".fmt(this, event));
1078
+ this.stateLogWarning("state %@ can not handle event '%@' since it is a registered state observe handler".fmt(this, event));
742
1079
  return NO;
743
1080
  }
744
1081
 
745
1082
  // Now begin by trying a basic method on the state to respond to the event
746
1083
  if (SC.typeOf(this[event]) === SC.T_FUNCTION) {
747
- if (trace) this.stateLogTrace("will handle event %@".fmt(event));
748
- return (this[event](arg1, arg2) !== NO);
1084
+ if (trace) this.stateLogTrace("will handle event '%@'".fmt(event));
1085
+ sc.stateWillTryToHandleEvent(this, event, event);
1086
+ ret = (this[event](arg1, arg2) !== NO);
1087
+ sc.stateDidTryToHandleEvent(this, event, event, ret);
1088
+ return ret;
749
1089
  }
750
1090
 
751
1091
  // Try an event handler that is associated with an event represented as a string
752
1092
  var handler = this._registeredStringEventHandlers[event];
753
1093
  if (handler) {
754
- if (trace) this.stateLogTrace("%@ will handle event %@".fmt(handler.name, event));
755
- return (handler.handler.call(this, event, arg1, arg2) !== NO);
1094
+ if (trace) this.stateLogTrace("%@ will handle event '%@'".fmt(handler.name, event));
1095
+ sc.stateWillTryToHandleEvent(this, event, handler.name);
1096
+ ret = (handler.handler.call(this, event, arg1, arg2) !== NO);
1097
+ sc.stateDidTryToHandleEvent(this, event, handler.name, ret);
1098
+ return ret;
756
1099
  }
757
1100
 
758
1101
  // Try an event handler that is associated with events matching a regular expression
@@ -763,16 +1106,22 @@ SC.State = SC.Object.extend(
763
1106
  for (; i < len; i += 1) {
764
1107
  handler = this._registeredRegExpEventHandlers[i];
765
1108
  if (event.match(handler.regexp)) {
766
- if (trace) this.stateLogTrace("%@ will handle event %@".fmt(handler.name, event));
767
- return (handler.handler.call(this, event, arg1, arg2) !== NO);
1109
+ if (trace) this.stateLogTrace("%@ will handle event '%@'".fmt(handler.name, event));
1110
+ sc.stateWillTryToHandleEvent(this, event, handler.name);
1111
+ ret = (handler.handler.call(this, event, arg1, arg2) !== NO);
1112
+ sc.stateDidTryToHandleEvent(this, event, handler.name, ret);
1113
+ return ret;
768
1114
  }
769
1115
  }
770
1116
 
771
1117
  // Final attempt. If the state has an unknownEvent function then invoke it to
772
1118
  // handle the event
773
1119
  if (SC.typeOf(this['unknownEvent']) === SC.T_FUNCTION) {
774
- if (trace) this.stateLogTrace("unknownEvent will handle event %@".fmt(event));
775
- return (this.unknownEvent(event, arg1, arg2) !== NO);
1120
+ if (trace) this.stateLogTrace("unknownEvent will handle event '%@'".fmt(event));
1121
+ sc.stateWillTryToHandleEvent(this, event, 'unknownEvent');
1122
+ ret = (this.unknownEvent(event, arg1, arg2) !== NO);
1123
+ sc.stateDidTryToHandleEvent(this, event, 'unknownEvent', ret);
1124
+ return ret;
776
1125
  }
777
1126
 
778
1127
  // Nothing was able to handle the given event for this state
@@ -799,7 +1148,16 @@ SC.State = SC.Object.extend(
799
1148
  When the enterState method is called, an optional context value may be supplied if
800
1149
  one was provided to the gotoState method.
801
1150
 
802
- @param context {Hash} Optional value if one was supplied to gotoState when invoked
1151
+ In the case that the context being supplied is a state context object
1152
+ ({@link SC.StateRouteHandlerContext}), an optional `enterStateByRoute` method can be invoked
1153
+ on this state if the state has implemented the method. If `enterStateByRoute` is
1154
+ not part of this state then the `enterState` method will be invoked by default. The
1155
+ `enterStateByRoute` is simply a convenience method that helps removes checks to
1156
+ determine if the context provide is a state route context object.
1157
+
1158
+ @param {Hash} [context] value if one was supplied to gotoState when invoked
1159
+
1160
+ @see #representRoute
803
1161
  */
804
1162
  enterState: function(context) { },
805
1163
 
@@ -809,9 +1167,12 @@ SC.State = SC.Object.extend(
809
1167
  Note: This is intended to be used by the owning statechart but it can be overridden if
810
1168
  you need to do something special.
811
1169
 
1170
+ @param {Hash} [context] value if one was supplied to gotoState when invoked
812
1171
  @see #enterState
813
1172
  */
814
- stateWillBecomeEntered: function() { },
1173
+ stateWillBecomeEntered: function(context) {
1174
+ this._isEnteringState = YES;
1175
+ },
815
1176
 
816
1177
  /**
817
1178
  Notification called just after enterState is invoked.
@@ -819,10 +1180,12 @@ SC.State = SC.Object.extend(
819
1180
  Note: This is intended to be used by the owning statechart but it can be overridden if
820
1181
  you need to do something special.
821
1182
 
1183
+ @param context {Hash} Optional value if one was supplied to gotoState when invoked
822
1184
  @see #enterState
823
1185
  */
824
- stateDidBecomeEntered: function() {
1186
+ stateDidBecomeEntered: function(context) {
825
1187
  this._setupAllStateObserveHandlers();
1188
+ this._isEnteringState = NO;
826
1189
  },
827
1190
 
828
1191
  /**
@@ -855,9 +1218,11 @@ SC.State = SC.Object.extend(
855
1218
  Note: This is intended to be used by the owning statechart but it can be overridden
856
1219
  if you need to do something special.
857
1220
 
1221
+ @param context {Hash} Optional value if one was supplied to gotoState when invoked
858
1222
  @see #exitState
859
1223
  */
860
- stateWillBecomeExited: function() {
1224
+ stateWillBecomeExited: function(context) {
1225
+ this._isExitingState = YES;
861
1226
  this._teardownAllStateObserveHandlers();
862
1227
  },
863
1228
 
@@ -867,9 +1232,12 @@ SC.State = SC.Object.extend(
867
1232
  Note: This is intended to be used by the owning statechart but it can be overridden
868
1233
  if you need to do something special.
869
1234
 
1235
+ @param context {Hash} Optional value if one was supplied to gotoState when invoked
870
1236
  @see #exitState
871
1237
  */
872
- stateDidBecomeExited: function() { },
1238
+ stateDidBecomeExited: function(context) {
1239
+ this._isExitingState = NO;
1240
+ },
873
1241
 
874
1242
  /** @private
875
1243
 
@@ -992,10 +1360,19 @@ SC.State = SC.Object.extend(
992
1360
  }.property('name', 'parentState').cacheable(),
993
1361
 
994
1362
  toString: function() {
995
- var className = SC._object_className(this.constructor);
996
- return "%@<%@, %@>".fmt(className, this.get('fullPath'), SC.guidFor(this));
1363
+ return this.get('fullPath');
997
1364
  },
998
1365
 
1366
+ /** @private */
1367
+ _enteredSubstatesDidChange: function() {
1368
+ this.notifyPropertyChange('enteredSubstates');
1369
+ }.observes('*enteredSubstates.[]'),
1370
+
1371
+ /** @private */
1372
+ _currentSubstatesDidChange: function() {
1373
+ this.notifyPropertyChange('currentSubstates');
1374
+ }.observes('*currentSubstates.[]'),
1375
+
999
1376
  /** @private */
1000
1377
  _statechartTraceDidChange: function() {
1001
1378
  this.notifyPropertyChange('trace');