sproutcore 1.10.3.1 → 1.11.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (380) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG +4 -8
  3. data/VERSION.yml +2 -2
  4. data/lib/frameworks/sproutcore/Buildfile +5 -4
  5. data/lib/frameworks/sproutcore/CHANGELOG.md +274 -40
  6. data/lib/frameworks/sproutcore/CONTRIBUTORS.md +133 -0
  7. data/lib/frameworks/sproutcore/README.md +31 -144
  8. data/lib/frameworks/sproutcore/apps/showcase/controllers/source_tree_controller.js +9 -4
  9. data/lib/frameworks/sproutcore/apps/showcase/resources/stylesheet.css +5 -0
  10. data/lib/frameworks/sproutcore/apps/showcase/system/views_item_content.js +1 -1
  11. data/lib/frameworks/sproutcore/apps/showcase/views/split_views.js +15 -2
  12. data/lib/frameworks/sproutcore/apps/showcase/views/stacked_views.js +1 -1
  13. data/lib/frameworks/sproutcore/apps/tests/english.lproj/main_page.js +11 -1
  14. data/lib/frameworks/sproutcore/frameworks/ajax/mixins/websocket_delegate.js +90 -0
  15. data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +81 -5
  16. data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +23 -4
  17. data/lib/frameworks/sproutcore/frameworks/ajax/system/websocket.js +475 -0
  18. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +149 -26
  19. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/websocket.js +197 -0
  20. data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/xhr_response_test.js +65 -0
  21. data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +4 -0
  22. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/horizontal_stack_layout.js +232 -52
  23. data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/vertical_stack_layout.js +235 -49
  24. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +23 -13
  25. data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/object.js +3 -1
  26. data/lib/frameworks/sproutcore/frameworks/core_foundation/core.js +81 -1
  27. data/lib/frameworks/sproutcore/frameworks/core_foundation/english.lproj/ordinal.js +17 -0
  28. data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/string.js +7 -0
  29. data/lib/frameworks/sproutcore/frameworks/{desktop/tests/views/disclosure/methods.js → core_foundation/french.lproj/ordinal.js} +7 -4
  30. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +2 -6
  31. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/main.js +1 -1
  32. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +104 -69
  33. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane_statechart.js +6 -1
  34. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/child_view_layout_protocol.js +59 -0
  35. data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/view_transition_protocol.js +18 -1
  36. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/application.js +192 -0
  37. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/bezier_curves.js +52 -0
  38. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/color.js +384 -64
  39. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/core_query.js +6 -14
  40. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/device.js +21 -35
  41. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +72 -36
  42. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +90 -34
  43. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +55 -7
  44. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/render_context.js +20 -15
  45. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/req_anim_frame.js +9 -10
  46. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +763 -542
  47. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +4 -3
  48. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +1 -7
  49. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/string.js +14 -0
  50. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/touch.js +538 -0
  51. data/lib/frameworks/sproutcore/frameworks/core_foundation/system/utils/rect.js +56 -1
  52. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/array/array_case.js +99 -4
  53. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/object/single_case.js +25 -19
  54. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/core_tests.js +75 -0
  55. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/ext/number_test.js +81 -0
  56. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +4 -4
  57. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/responder_context.js +4 -4
  58. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/string.js +19 -1
  59. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/color.js +36 -20
  60. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/design_modes_test.js +83 -0
  61. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/makeMainPane.js +7 -3
  62. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/mouse_events.js +338 -0
  63. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/root_responder.js +14 -89
  64. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/touch.js +106 -0
  65. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/sparse_array.js +2 -2
  66. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/touch.js +136 -0
  67. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/utils/rect.js +42 -1
  68. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/append_remove.js +11 -0
  69. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/child_view.js +5 -5
  70. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/design_mode_test.js +457 -0
  71. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/sendEvent.js +36 -10
  72. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/background_color.js +44 -0
  73. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/border_frame_test.js +51 -24
  74. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/childViewLayout_test.js +176 -1
  75. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/clippingFrame.js +46 -16
  76. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/convertFrames.js +69 -15
  77. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/didAppendToDocument.js +2 -2
  78. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout.js +7 -1
  79. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +30 -10
  80. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +376 -71
  81. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/static_layout.js +0 -10
  82. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +117 -34
  83. data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view_states_test.js +52 -2
  84. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +656 -42
  85. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +159 -38
  86. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/cursor.js +0 -7
  87. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/design_mode.js +206 -0
  88. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +0 -28
  89. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +21 -6
  90. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +372 -450
  91. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +28 -13
  92. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +22 -51
  93. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +59 -30
  94. data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +0 -29
  95. data/lib/frameworks/sproutcore/frameworks/datastore/mixins/relationship_support.js +22 -10
  96. data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +42 -36
  97. data/lib/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +54 -3
  98. data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +178 -59
  99. data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +2 -2
  100. data/lib/frameworks/sproutcore/frameworks/datastore/system/child_array.js +206 -132
  101. data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +214 -118
  102. data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +96 -13
  103. data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +14 -4
  104. data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +82 -42
  105. data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +272 -177
  106. data/lib/frameworks/sproutcore/frameworks/datastore/tests/integration/store_interaction_test.js +54 -0
  107. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/datetime_recordattribute.js +24 -16
  108. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +6 -3
  109. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/data_store.js +267 -35
  110. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +57 -46
  111. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +150 -53
  112. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array_complex.js +57 -17
  113. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_complex.js +13 -9
  114. data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/many.js +2 -2
  115. data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/simple.js +0 -0
  116. data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/single.js +12 -2
  117. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +20 -15
  118. data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +9 -2
  119. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/many_array/core_methods.js +80 -14
  120. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_dataSourceCallbacks.js +280 -0
  121. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_pushChanges.js +232 -0
  122. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/chain.js +31 -5
  123. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/parse.js +16 -2
  124. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/core_methods.js +60 -40
  125. data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/materializeRecord.js +78 -0
  126. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +13 -1
  127. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +20 -0
  128. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/{resources → english.lproj}/strings.js +0 -0
  129. data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/french.lproj/strings.js +45 -0
  130. data/lib/frameworks/sproutcore/frameworks/designer/designers/object_designer.js +7 -3
  131. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +125 -44
  132. data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +139 -48
  133. data/lib/frameworks/sproutcore/frameworks/desktop/panes/draggable.js +202 -0
  134. data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +59 -56
  135. data/lib/frameworks/sproutcore/frameworks/desktop/panes/palette.js +13 -49
  136. data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +466 -305
  137. data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_source.js +49 -12
  138. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/slider.js +79 -21
  139. data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/split.js +12 -2
  140. data/lib/frameworks/sproutcore/frameworks/desktop/resources/menu_item_view.css +8 -0
  141. data/lib/frameworks/sproutcore/frameworks/desktop/resources/overlay-scroller.css +187 -0
  142. data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +94 -30
  143. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +163 -3
  144. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/methods.js +97 -78
  145. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +61 -1
  146. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/methods.js +7 -3
  147. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +47 -22
  148. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/methods.js +66 -9
  149. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +21 -11
  150. data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +12 -18
  151. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/methods.js +17 -14
  152. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +2 -1
  153. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/methods.js +9 -6
  154. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/collection_fast_path.js +54 -21
  155. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/content.js +52 -20
  156. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/itemViewForContentIndex.js +94 -4
  157. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/keyboard.js +177 -0
  158. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/layerIdFor.js +13 -1
  159. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/length.js +9 -9
  160. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/mouse.js +18 -0
  161. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/methods.js +104 -0
  162. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/ui.js +48 -49
  163. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/grid/drag_and_drop.js +22 -18
  164. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/grid/methods.js +17 -5
  165. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/link_view_test.js +136 -0
  166. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/contentIndexesInRect.js +77 -0
  167. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/drag_and_drop.js +53 -16
  168. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/layoutForContentIndex.js +41 -0
  169. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +25 -25
  170. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowOffsetForContentIndex.js +102 -27
  171. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/{rowHeightForContentIndex.js → rowSizeForContentIndex.js} +7 -6
  172. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_outline.js +2 -0
  173. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +70 -75
  174. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_simple.js +29 -30
  175. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +57 -0
  176. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/menu_scroll_view/menu_scroll_view_test.js +206 -0
  177. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +15 -0
  178. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +15 -7
  179. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/integration.js +16 -11
  180. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +164 -12
  181. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/scale.js +387 -0
  182. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/touch.js +549 -0
  183. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +214 -45
  184. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroller.js +5 -5
  185. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +73 -22
  186. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +88 -3
  187. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/methods.js +8 -0
  188. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/slider/methods.js +16 -1
  189. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/slider/ui.js +54 -0
  190. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/split/dividers.js +21 -2
  191. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/static_content.js +31 -25
  192. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +109 -29
  193. data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +10 -1
  194. data/lib/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +3 -0
  195. data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +779 -603
  196. data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +106 -7
  197. data/lib/frameworks/sproutcore/frameworks/desktop/views/link_view.js +406 -0
  198. data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +437 -245
  199. data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +13 -0
  200. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +124 -62
  201. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +176 -597
  202. data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroller_view.js +206 -0
  203. data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +3 -0
  204. data/lib/frameworks/sproutcore/frameworks/desktop/views/progress.js +5 -4
  205. data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +3 -0
  206. data/lib/frameworks/sproutcore/frameworks/desktop/views/scene.js +56 -158
  207. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll_view.js +2560 -0
  208. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +458 -242
  209. data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +117 -54
  210. data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +18 -12
  211. data/lib/frameworks/sproutcore/frameworks/desktop/views/slider.js +162 -34
  212. data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +30 -15
  213. data/lib/frameworks/sproutcore/frameworks/desktop/views/split_divider.js +33 -7
  214. data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +22 -2
  215. data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +47 -22
  216. data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +0 -6
  217. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form.js +2 -1
  218. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form_row.js +21 -21
  219. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu.js +14 -3
  220. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/mixins/select_view_menu.js +24 -10
  221. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/ext/menu_resizing.js +1 -1
  222. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/bindings.js +7 -4
  223. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/check_selected.js +7 -9
  224. data/lib/frameworks/sproutcore/frameworks/{desktop/tests/panes/select_button/methods.js → experimental/frameworks/select_view/tests/views/select/method.js} +54 -76
  225. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/views/select/selected_item.js +35 -0
  226. data/lib/frameworks/sproutcore/frameworks/{desktop/tests/panes/select_button → experimental/frameworks/select_view/tests/views/select}/ui.js +107 -36
  227. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/select.js +225 -66
  228. data/lib/frameworks/sproutcore/frameworks/foundation/controllers/tree.js +39 -38
  229. data/lib/frameworks/sproutcore/frameworks/foundation/core.js +5 -18
  230. data/lib/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +12 -0
  231. data/lib/frameworks/sproutcore/frameworks/foundation/english.lproj/inflections.js +84 -0
  232. data/lib/frameworks/sproutcore/frameworks/foundation/french.lproj/inflections.js +41 -0
  233. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_mixin.js +1 -0
  234. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +7 -0
  235. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_display.js +3 -4
  236. data/lib/frameworks/sproutcore/frameworks/foundation/mixins/flowed_layout.js +6 -2
  237. data/lib/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +408 -239
  238. data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/canvas_image.js +1 -1
  239. data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +2 -1
  240. data/lib/frameworks/sproutcore/frameworks/foundation/spanish.lproj/inflections.js +38 -0
  241. data/lib/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +104 -76
  242. data/lib/frameworks/sproutcore/frameworks/foundation/system/string.js +20 -94
  243. data/lib/frameworks/sproutcore/frameworks/foundation/system/text_selection.js +33 -22
  244. data/lib/frameworks/sproutcore/frameworks/foundation/system/undo_manager.js +475 -0
  245. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +163 -1
  246. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/flowed_layout/tests.js +41 -0
  247. data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +2 -5
  248. data/lib/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/methods.js +268 -0
  249. data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/undo_manager.js +231 -0
  250. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +16 -0
  251. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +27 -0
  252. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/methods.js +24 -0
  253. data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +135 -6
  254. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/fade_transition.js +6 -0
  255. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/pop_transition.js +7 -0
  256. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/scale_transition.js +6 -0
  257. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/slide_transition.js +4 -0
  258. data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_dissolve_transition.js +3 -1
  259. data/lib/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +21 -21
  260. data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +65 -15
  261. data/lib/frameworks/sproutcore/frameworks/foundation/views/image.js +4 -1
  262. data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +1 -1
  263. data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +193 -213
  264. data/lib/frameworks/sproutcore/frameworks/jquery/{jquery-1.8.3-patched.js → jquery-1.11.1.js} +7507 -6684
  265. data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +28 -11
  266. data/lib/frameworks/sproutcore/frameworks/routing/tests/system/routes.js +26 -0
  267. data/lib/frameworks/sproutcore/frameworks/runtime/core.js +54 -25
  268. data/lib/frameworks/sproutcore/frameworks/runtime/ext/array.js +0 -6
  269. data/lib/frameworks/sproutcore/frameworks/runtime/ext/number.js +36 -0
  270. data/lib/frameworks/sproutcore/frameworks/runtime/ext/window.js +25 -0
  271. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +3 -3
  272. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +1 -1
  273. data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +156 -66
  274. data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +2 -2
  275. data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +150 -65
  276. data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +57 -11
  277. data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +68 -49
  278. data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +14 -6
  279. data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +23 -23
  280. data/lib/frameworks/sproutcore/frameworks/runtime/tests/ext/number_test.js +44 -0
  281. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +0 -10
  282. data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable/enumerable.js +340 -285
  283. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +104 -3
  284. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/observer_set.js +14 -1
  285. data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/string.js +15 -2
  286. data/lib/frameworks/sproutcore/frameworks/statechart/system/state.js +21 -18
  287. data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +52 -19
  288. data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/responder/pane.js +27 -24
  289. data/lib/frameworks/sproutcore/frameworks/template_view/controls/button.js +30 -0
  290. data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/bind.js +1 -1
  291. data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/collection.js +2 -0
  292. data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/view.js +1 -0
  293. data/lib/frameworks/sproutcore/frameworks/template_view/tests/mixins/template_helpers/checkbox_support.js +2 -2
  294. data/lib/frameworks/sproutcore/frameworks/template_view/tests/views/template/handlebars.js +4 -2
  295. data/lib/frameworks/sproutcore/frameworks/template_view/views/bindable_span.js +1 -1
  296. data/lib/frameworks/sproutcore/frameworks/template_view/views/template_collection.js +16 -14
  297. data/lib/frameworks/sproutcore/frameworks/testing/core.js +5 -3
  298. data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +13 -0
  299. data/lib/frameworks/sproutcore/lib/index.rhtml +2 -2
  300. data/lib/frameworks/sproutcore/phantomjs/test_runner.js +28 -7
  301. data/lib/frameworks/sproutcore/scripts/run_sc_server_master.sh +1 -1
  302. data/lib/frameworks/sproutcore/themes/ace/resources/_variables.css +2 -0
  303. data/lib/frameworks/sproutcore/themes/ace/resources/disclosure/ace/disclosure.css +1 -0
  304. data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +3 -4
  305. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal.css +15 -15
  306. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal_overlay.css +74 -0
  307. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical.css +11 -13
  308. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical_overlay.css +74 -0
  309. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob-active.png +0 -0
  310. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob-active@2x.png +0 -0
  311. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob.png +0 -0
  312. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob@2x.png +0 -0
  313. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/{22px → jumbo}/slider.css +9 -4
  314. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/track.png +0 -0
  315. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/track@2x.png +0 -0
  316. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob-active.png +0 -0
  317. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob-active@2x.png +0 -0
  318. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob.png +0 -0
  319. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob@2x.png +0 -0
  320. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/slider.css +32 -0
  321. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/track.png +0 -0
  322. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/track@2x.png +0 -0
  323. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/slider.css +13 -0
  324. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob-active.png +0 -0
  325. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob-active@2x.png +0 -0
  326. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob.png +0 -0
  327. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob@2x.png +0 -0
  328. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/slider.css +32 -0
  329. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/track.png +0 -0
  330. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/track@2x.png +0 -0
  331. data/lib/frameworks/sproutcore/themes/ace/resources/split/split.css +2 -3
  332. data/lib/sproutcore/builders/chance_file.rb +3 -3
  333. data/lib/sproutcore/helpers/minifier.rb +1 -0
  334. data/vendor/chance/lib/chance/instance.rb +34 -34
  335. data/vendor/chance/lib/chance/instance/spriting.rb +21 -16
  336. metadata +81 -58
  337. data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/visibility.js +0 -17
  338. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_fast_path.js +0 -710
  339. data/lib/frameworks/sproutcore/frameworks/desktop/mixins/scrollable.js +0 -267
  340. data/lib/frameworks/sproutcore/frameworks/desktop/resources/touch-scroller.css +0 -196
  341. data/lib/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +0 -224
  342. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/methods.js +0 -163
  343. data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/ui.js +0 -177
  344. data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +0 -2053
  345. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_button.js +0 -1024
  346. data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +0 -404
  347. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +0 -28
  348. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +0 -235
  349. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +0 -363
  350. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +0 -250
  351. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/README.md +0 -47
  352. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/models/record.js +0 -134
  353. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +0 -92
  354. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +0 -25
  355. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +0 -33
  356. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +0 -76
  357. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +0 -25
  358. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +0 -143
  359. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +0 -256
  360. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +0 -1164
  361. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +0 -332
  362. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +0 -236
  363. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +0 -347
  364. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +0 -15
  365. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +0 -10
  366. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +0 -804
  367. data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +0 -133
  368. data/lib/frameworks/sproutcore/frameworks/foundation/tasks/preload_bundle.js +0 -41
  369. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal_touch.css +0 -91
  370. data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical_touch.css +0 -92
  371. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/knob.png +0 -0
  372. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/knob_active.png +0 -0
  373. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/slider.css +0 -27
  374. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/knob.png +0 -0
  375. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/knob_active.png +0 -0
  376. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/slider.css +0 -27
  377. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/knob.png +0 -0
  378. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/knob_active.png +0 -0
  379. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/track.png +0 -0
  380. data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/track.png +0 -0
@@ -4,7 +4,7 @@
4
4
  // Portions ©2008-2011 Apple Inc. All rights reserved.
5
5
  // License: Licensed under MIT license (see license.js)
6
6
  // ==========================================================================
7
- /*global jQuery*/
7
+
8
8
 
9
9
  /**
10
10
  A constant indicating an unsupported method, property or other.
@@ -81,25 +81,44 @@ SC.platform = SC.Object.create({
81
81
  touch: (!SC.none(window.ontouchstart) || SC.browser.name === SC.BROWSER.android || 'ontouchstart' in document.documentElement) && SC.none(window._phantom),
82
82
 
83
83
  /**
84
- YES if the current browser supports bounce on scroll.
84
+ True if bouncing on scroll is expected in the current platform.
85
85
 
86
86
  @type Boolean
87
87
  */
88
88
  bounceOnScroll: SC.browser.os === SC.OS.ios,
89
89
 
90
90
  /**
91
- YES if the current browser supports pinch to zoom.
91
+ True if pinch-to-zoom is expected in the current platform.
92
92
 
93
93
  @type Boolean
94
94
  */
95
- pinchToZoom: SC.browser.os === SC.OS.ios,
95
+ pinchToZoom: SC.browser.os === SC.OS.ios,
96
+
97
+ /**
98
+ A hash that contains properties that indicate support for new HTML5
99
+ a attributes.
100
+
101
+ For example, to test to see if the `download` attribute is supported,
102
+ you would verify that `SC.platform.a.download` is true.
103
+
104
+ @type Array
105
+ */
106
+ a: function () {
107
+ var elem = document.createElement('a');
108
+
109
+ return {
110
+ download: !!('download' in elem),
111
+ media: !!('media' in elem),
112
+ ping: !!('ping' in elem),
113
+ };
114
+ }(),
96
115
 
97
116
  /**
98
117
  A hash that contains properties that indicate support for new HTML5
99
118
  input attributes.
100
119
 
101
- For example, to test to see if the placeholder attribute is supported,
102
- you would verify that SC.platform.input.placeholder is YES.
120
+ For example, to test to see if the `placeholder` attribute is supported,
121
+ you would verify that `SC.platform.input.placeholder` is true.
103
122
 
104
123
  @type Array
105
124
  */
@@ -117,7 +136,8 @@ SC.platform = SC.Object.create({
117
136
 
118
137
  return ret;
119
138
  }(['autocomplete', 'readonly', 'list', 'size', 'required', 'multiple', 'maxlength',
120
- 'pattern', 'min', 'max', 'step', 'placeholder']),
139
+ 'pattern', 'min', 'max', 'step', 'placeholder',
140
+ 'selectionStart', 'selectionEnd', 'selectionDirection']),
121
141
 
122
142
  /**
123
143
  YES if the application is currently running as a standalone application.
@@ -396,6 +416,34 @@ SC.platform = SC.Object.create({
396
416
  return !!document.createElement('canvas').getContext;
397
417
  }(),
398
418
 
419
+ /**
420
+ Whether the browser supports the XHR2 ProgressEvent specification. This
421
+ reliably implies support for XMLHttpRequest 'loadstart' and 'progress'
422
+ events, as well as the terminal 'load', 'error' and 'abort' events. Support
423
+ for 'loadend', which fires no matter how the request terminats, is a bit
424
+ spottier and should be verified separately using `supportsXHR2LoadEndEvent`.
425
+
426
+ @type Boolean
427
+ */
428
+ supportsXHR2ProgressEvent: ('ProgressEvent' in window),
429
+
430
+ /**
431
+ Whether the browser supports the XHR2 FormData specification.
432
+
433
+ @type Boolean
434
+ */
435
+ supportsXHR2FormData: ('FormData' in window),
436
+
437
+ /**
438
+ Whether the browser supports the XHR2 ProgressEvent's loadend event. If not
439
+ supported, you should handle 'load', 'error' and 'abort' events instead.
440
+
441
+ @type Boolean
442
+ */
443
+ supportsXHR2LoadEndEvent: function () {
444
+ return (new XMLHttpRequest).onloadend === null;
445
+ } (),
446
+
399
447
  /**
400
448
  Whether the browser supports the orientationchange event.
401
449
 
@@ -882,30 +882,35 @@ SC.RenderContext = SC.Builder.create(
882
882
  // Add the updated styles to the internal styles object.
883
883
  if (SC.typeOf(nameOrStyles) === SC.T_HASH) {
884
884
  for (var key in nameOrStyles) {
885
- if (!nameOrStyles.hasOwnProperty(key)) continue;
886
-
887
- value = nameOrStyles[key];
888
-
889
- didChange = this._deleteComboStyles(styles, key) || didChange;
890
- didChange = this._setOnHash(styles, key, value) || didChange;
885
+ // Call a separate function so that it may be optimized.
886
+ didChange = this._sc_setStyleFromObject(didChange, key, nameOrStyles, styles);
891
887
  }
892
888
  } else {
893
889
  didChange = this._deleteComboStyles(styles, nameOrStyles);
894
890
  didChange = this._setOnHash(styles, nameOrStyles, value) || didChange;
895
891
  }
896
892
 
897
- if (didChange) {
898
-
899
- // Set the styles on the element if we have one already.
900
- if (this._elem) {
901
- // Note: jQuery .css doesn't remove old styles
902
- this.$().css(styles);
903
- }
893
+ // Set the styles on the element if we have one already.
894
+ if (didChange && this._elem) {
895
+ // Note: jQuery .css doesn't remove old styles
896
+ this.$().css(styles);
904
897
  }
905
898
 
906
899
  return this;
907
900
  },
908
901
 
902
+ /** @private Sets the style by key from the styles object. This allows for optimization outside of the for..in loop. */
903
+ _sc_setStyleFromObject: function (didChange, key, stylesObject, styles) {
904
+ if (!stylesObject.hasOwnProperty(key)) return false;
905
+
906
+ var value = stylesObject[key];
907
+
908
+ didChange = this._deleteComboStyles(styles, key) || didChange;
909
+ didChange = this._setOnHash(styles, key, value) || didChange;
910
+
911
+ return didChange;
912
+ },
913
+
909
914
  /** @private */
910
915
  _deleteComboStyles: function (styles, key) {
911
916
  var comboStyles = SC.COMBO_STYLES[key],
@@ -926,10 +931,10 @@ SC.RenderContext = SC.Builder.create(
926
931
 
927
932
  /** @private Sets or unsets the key:value on the hash and returns whether a change occurred. */
928
933
  _setOnHash: function (hash, key, value) {
929
- /*jshint eqnull:true*/
930
934
  var cur = hash[key],
931
935
  didChange = true;
932
936
 
937
+ /*jshint eqnull:true */
933
938
  if (cur == null && value != null) {
934
939
  hash[key] = value;
935
940
  } else if (cur != null && value == null) {
@@ -1009,7 +1014,7 @@ SC.RenderContext = SC.Builder.create(
1009
1014
  attr = elAttrs.item(i);
1010
1015
  name = attr.nodeName;
1011
1016
  if (name.match(/^(?!class|style).*$/i)) {
1012
- attrs[name] = attr.nodeValue;
1017
+ attrs[name] = attr.value;
1013
1018
  }
1014
1019
  }
1015
1020
 
@@ -2,7 +2,7 @@
2
2
  Polyfill for cross-browser backwards compatible window.requestAnimationFrame
3
3
  support.
4
4
 
5
- Via Erik Möller:
5
+ Modified from Erik Möller:
6
6
  http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
7
7
  */
8
8
  (function() {
@@ -14,18 +14,17 @@
14
14
  'CancelRequestAnimationFrame'];
15
15
  }
16
16
 
17
- if (!window.requestAnimationFrame)
18
- window.requestAnimationFrame = function(callback, element) {
17
+ if (!window.requestAnimationFrame) {
18
+ window.requestAnimationFrame = function(callback) {
19
19
  var currTime = new Date().getTime();
20
20
  var timeToCall = Math.max(0, 16 - (currTime - lastTime));
21
- var id = window.setTimeout(function() { callback(currTime + timeToCall); },
22
- timeToCall);
21
+ var id = window.setTimeout(function() { callback(window.performance.now()); }, timeToCall);
23
22
  lastTime = currTime + timeToCall;
24
23
  return id;
25
24
  };
25
+ }
26
26
 
27
- if (!window.cancelAnimationFrame)
28
- window.cancelAnimationFrame = function(id) {
29
- clearTimeout(id);
30
- };
31
- }())
27
+ if (!window.cancelAnimationFrame) {
28
+ window.cancelAnimationFrame = function(id) { clearTimeout(id); };
29
+ }
30
+ }());
@@ -7,9 +7,10 @@
7
7
 
8
8
  sc_require('system/ready');
9
9
  sc_require('system/platform');
10
+ sc_require('system/touch');
10
11
 
11
12
  /** Set to NO to leave the backspace key under the control of the browser.*/
12
- SC.CAPTURE_BACKSPACE_KEY = NO;
13
+ SC.CAPTURE_BACKSPACE_KEY = NO ;
13
14
 
14
15
  /** @class
15
16
 
@@ -57,7 +58,7 @@ SC.RootResponder = SC.Object.extend(
57
58
  */
58
59
  panes: null,
59
60
 
60
- init: function () {
61
+ init: function() {
61
62
  sc_super();
62
63
  this.panes = SC.Set.create();
63
64
  },
@@ -91,24 +92,24 @@ SC.RootResponder = SC.Object.extend(
91
92
  @param {SC.Pane} pane
92
93
  @returns {SC.RootResponder}
93
94
  */
94
- makeMainPane: function (pane) {
95
- var currentMain = this.get('mainPane');
96
- if (currentMain === pane) return this; // nothing to do
95
+ makeMainPane: function(pane) {
96
+ var currentMain = this.get('mainPane') ;
97
+ if (currentMain === pane) return this ; // nothing to do
97
98
 
98
- this.beginPropertyChanges();
99
+ this.beginPropertyChanges() ;
99
100
 
100
101
  // change key focus if needed.
101
- if (this.get('keyPane') === currentMain) this.makeKeyPane(pane);
102
+ if (this.get('keyPane') === currentMain) this.makeKeyPane(pane) ;
102
103
 
103
104
  // change setting
104
- this.set('mainPane', pane);
105
+ this.set('mainPane', pane) ;
105
106
 
106
107
  // notify panes. This will allow them to remove themselves.
107
- if (currentMain) currentMain.blurMainTo(pane);
108
- if (pane) pane.focusMainFrom(currentMain);
108
+ if (currentMain) currentMain.blurMainTo(pane) ;
109
+ if (pane) pane.focusMainFrom(currentMain) ;
109
110
 
110
- this.endPropertyChanges();
111
- return this;
111
+ this.endPropertyChanges() ;
112
+ return this ;
112
113
  },
113
114
 
114
115
  // ..........................................................
@@ -136,7 +137,7 @@ SC.RootResponder = SC.Object.extend(
136
137
  @param {SC.MenuPane} pane
137
138
  @returns {SC.RootResponder} receiver
138
139
  */
139
- makeMenuPane: function (pane) {
140
+ makeMenuPane: function(pane) {
140
141
  // Does the specified pane accept being the menu pane? If not, there's
141
142
  // nothing to do.
142
143
  if (pane && !pane.get('acceptsMenuPane')) {
@@ -164,10 +165,11 @@ SC.RootResponder = SC.Object.extend(
164
165
  */
165
166
  keyPane: null,
166
167
 
167
- /** @property
168
- A stack of the previous key panes.
168
+ /** @private
169
+ A stack of previous key panes. Used to allow panes to resign key pane
170
+ status without having to know who had it before them.
169
171
 
170
- *IMPORTANT: Property is not observable*
172
+ NOTE: This property is not observable.
171
173
  */
172
174
  previousKeyPanes: [],
173
175
 
@@ -180,32 +182,39 @@ SC.RootResponder = SC.Object.extend(
180
182
  @param {SC.Pane} pane
181
183
  @returns {SC.RootResponder} receiver
182
184
  */
183
- makeKeyPane: function (pane) {
185
+ makeKeyPane: function(pane) {
186
+ // Quick note about previousKeyPanes: if a pane is destroyed while in the
187
+ // previous panes stack, it will retain a reference to it here, causing a
188
+ // brief leak. The reference will be removed as soon as the panes above it
189
+ // in the stack resign, so it's rarely an issue, and fixing it would require
190
+ // a dedicated method and some extra coordination that's probably not worth
191
+ // it.
192
+
184
193
  // Was a pane specified?
185
- var newKeyPane, previousKeyPane, previousKeyPanes;
194
+ var newKeyPane, previousKeyPane, previousKeyPanes ;
186
195
 
187
196
  if (pane) {
188
197
  // Does the specified pane accept being the key pane? If not, there's
189
198
  // nothing to do.
190
199
  if (!pane.get('acceptsKeyPane')) {
191
- return this;
200
+ return this ;
192
201
  }
193
202
  else {
194
203
  // It does accept key pane status? Then push the current keyPane to
195
204
  // the top of the stack and make the specified pane the new keyPane.
196
205
  // First, though, do a sanity-check to make sure it's not already the
197
206
  // key pane, in which case we have nothing to do.
198
- previousKeyPane = this.get('keyPane');
207
+ previousKeyPane = this.get('keyPane') ;
199
208
  if (previousKeyPane === pane) {
200
- return this;
209
+ return this ;
201
210
  }
202
211
  else {
203
212
  if (previousKeyPane) {
204
- previousKeyPanes = this.get('previousKeyPanes');
205
- previousKeyPanes.push(previousKeyPane);
213
+ previousKeyPanes = this.get('previousKeyPanes') ;
214
+ previousKeyPanes.push(previousKeyPane) ;
206
215
  }
207
216
 
208
- newKeyPane = pane;
217
+ newKeyPane = pane ;
209
218
  }
210
219
  }
211
220
  } else {
@@ -214,16 +223,16 @@ SC.RootResponder = SC.Object.extend(
214
223
  // attached and accepts key pane (its value for acceptsKeyPane might
215
224
  // have changed in the meantime). Otherwise, we'll keep going up the
216
225
  // stack.
217
- previousKeyPane = this.get('keyPane');
218
- previousKeyPanes = this.get('previousKeyPanes');
226
+ previousKeyPane = this.get('keyPane') ;
227
+ previousKeyPanes = this.get('previousKeyPanes') ;
219
228
 
220
- newKeyPane = null;
229
+ newKeyPane = null ;
221
230
  var candidate;
222
231
  while (previousKeyPanes.length > 0) {
223
232
  candidate = previousKeyPanes.pop();
224
233
  if (candidate.get('isPaneAttached') && candidate.get('acceptsKeyPane')) {
225
- newKeyPane = candidate;
226
- break;
234
+ newKeyPane = candidate ;
235
+ break ;
227
236
  }
228
237
  }
229
238
  }
@@ -232,20 +241,20 @@ SC.RootResponder = SC.Object.extend(
232
241
  // If we found an appropriate candidate, make it the new key pane.
233
242
  // Otherwise, make the main pane the key pane (if it accepts it).
234
243
  if (!newKeyPane) {
235
- var mainPane = this.get('mainPane');
236
- if (mainPane && mainPane.get('acceptsKeyPane')) newKeyPane = mainPane;
244
+ var mainPane = this.get('mainPane') ;
245
+ if (mainPane && mainPane.get('acceptsKeyPane')) newKeyPane = mainPane ;
237
246
  }
238
247
 
239
248
  // now notify old and new key views of change after edit
240
- if (previousKeyPane) previousKeyPane.willLoseKeyPaneTo(newKeyPane);
241
- if (newKeyPane) newKeyPane.willBecomeKeyPaneFrom(previousKeyPane);
249
+ if (previousKeyPane) previousKeyPane.willLoseKeyPaneTo(newKeyPane) ;
250
+ if (newKeyPane) newKeyPane.willBecomeKeyPaneFrom(previousKeyPane) ;
242
251
 
243
- this.set('keyPane', newKeyPane);
252
+ this.set('keyPane', newKeyPane) ;
244
253
 
245
- if (newKeyPane) newKeyPane.didBecomeKeyPaneFrom(previousKeyPane);
246
- if (previousKeyPane) previousKeyPane.didLoseKeyPaneTo(newKeyPane);
254
+ if (newKeyPane) newKeyPane.didBecomeKeyPaneFrom(previousKeyPane) ;
255
+ if (previousKeyPane) previousKeyPane.didLoseKeyPaneTo(newKeyPane) ;
247
256
 
248
- return this;
257
+ return this ;
249
258
  },
250
259
 
251
260
  // ..........................................................
@@ -264,14 +273,14 @@ SC.RootResponder = SC.Object.extend(
264
273
 
265
274
  @returns Rect
266
275
  */
267
- computeWindowSize: function () {
276
+ computeWindowSize: function() {
268
277
  var size, bod, docElement;
269
- if (!this._bod || !this._docElement) {
278
+ if(!this._bod || !this._docElement){
270
279
  bod = document.body;
271
280
  docElement = document.documentElement;
272
- this._bod = bod;
273
- this._docElement = docElement;
274
- } else {
281
+ this._bod=bod;
282
+ this._docElement=docElement;
283
+ }else{
275
284
  bod = this._bod;
276
285
  docElement = this._docElement;
277
286
  }
@@ -280,7 +289,7 @@ SC.RootResponder = SC.Object.extend(
280
289
  size = {
281
290
  width: window.innerWidth,
282
291
  height: window.innerHeight
283
- };
292
+ } ;
284
293
  } else if (docElement && docElement.clientHeight) {
285
294
  size = {
286
295
  width: docElement.clientWidth,
@@ -290,7 +299,7 @@ SC.RootResponder = SC.Object.extend(
290
299
  size = {
291
300
  width: bod.clientWidth,
292
301
  height: bod.clientHeight
293
- };
302
+ } ;
294
303
  }
295
304
  return size;
296
305
  },
@@ -300,27 +309,46 @@ SC.RootResponder = SC.Object.extend(
300
309
 
301
310
  @returns {Boolean}
302
311
  */
303
- resize: function () {
312
+ resize: function() {
304
313
  this._resize();
314
+ this._assignDesignMode();
305
315
 
306
316
  return YES; //always allow normal processing to continue.
307
317
  },
308
318
 
309
- _resize: function () {
319
+ /** @private */
320
+ _resize: function() {
310
321
  // calculate new window size...
311
322
  var newSize = this.computeWindowSize(), oldSize = this.get('currentWindowSize');
312
323
  this.set('currentWindowSize', newSize); // update size
313
324
 
314
325
  if (!SC.rectsEqual(newSize, oldSize)) {
326
+ SC.run(function() {
327
+ //Notify orientation change. This is faster than waiting for the orientation
328
+ //change event.
329
+ SC.device.windowSizeDidChange(newSize);
330
+
331
+ // notify panes
332
+ if (this.panes) {
333
+ if (oldSize !== newSize) {
334
+ this.panes.invoke('windowSizeDidChange', oldSize, newSize);
335
+ }
336
+ }
337
+ }, this);
338
+ }
339
+ },
315
340
 
316
- //Notify orientation change. This is faster than waiting for the orientation
317
- //change event.
318
- SC.device.windowSizeDidChange(newSize);
341
+ /** @private */
342
+ _assignDesignMode: function () {
343
+ var newDesignMode = this.computeDesignMode(),
344
+ oldDesignMode = this.get('currentDesignMode');
345
+
346
+ if (oldDesignMode !== newDesignMode) {
347
+ this.set('currentDesignMode', newDesignMode);
319
348
 
320
- // notify panes
321
349
  if (this.panes) {
322
- SC.run(function () {
323
- this.panes.invoke('windowSizeDidChange', oldSize, newSize);
350
+ SC.run(function() {
351
+ this.panes.invoke('updateDesignMode', oldDesignMode, newDesignMode);
324
352
  }, this);
325
353
  }
326
354
  }
@@ -340,46 +368,46 @@ SC.RootResponder = SC.Object.extend(
340
368
  Handle window focus. Change hasFocus and add sc-focus CSS class
341
369
  (removing sc-blur). Also notify panes.
342
370
  */
343
- focus: function (evt) {
371
+ focus: function(evt) {
344
372
  if (!this.get('hasFocus')) {
345
373
  SC.$('body').addClass('sc-focus').removeClass('sc-blur');
346
374
 
347
375
  SC.run(function () {
348
- // If the app is getting focus again set the first responder to the first
349
- // valid firstResponder view in the view's tree
350
- if (!SC.TABBING_ONLY_INSIDE_DOCUMENT && !SC.browser.isIE8OrLower) {
351
- var keyPane = SC.RootResponder.responder.get('keyPane');
352
- if (keyPane) {
353
- var nextValidKeyView = keyPane.get('nextValidKeyView');
354
- if (nextValidKeyView) keyPane.makeFirstResponder(nextValidKeyView);
355
- }
376
+ // If the app is getting focus again set the first responder to the first
377
+ // valid firstResponder view in the view's tree
378
+ if(!SC.TABBING_ONLY_INSIDE_DOCUMENT && !SC.browser.isIE8OrLower){
379
+ var keyPane = SC.RootResponder.responder.get('keyPane');
380
+ if (keyPane) {
381
+ var nextValidKeyView = keyPane.get('nextValidKeyView');
382
+ if (nextValidKeyView) keyPane.makeFirstResponder(nextValidKeyView);
356
383
  }
384
+ }
357
385
 
358
386
  this.set('hasFocus', YES);
359
387
  }, this);
360
388
  }
361
389
 
362
- return YES; // allow default
390
+ return YES ; // allow default
363
391
  },
364
392
 
365
393
  /**
366
394
  Handle window focus event for IE. Listening to the focus event is not
367
395
  reliable as per every focus event you receive you immediately get a blur
368
- event (Only on IE of course;)
396
+ event (Only on IE of course ;)
369
397
  */
370
- focusin: function (evt) {
371
- if (this._focusTimeout) clearTimeout(this._focusTimeout);
398
+ focusin: function(evt) {
399
+ if(this._focusTimeout) clearTimeout(this._focusTimeout);
372
400
  this.focus(evt);
373
401
  },
374
402
 
375
403
  /**
376
404
  Handle window blur event for IE. Listening to the focus event is not
377
405
  reliable as per every focus event you receive you immediately get a blur
378
- event (Only on IE of course;)
406
+ event (Only on IE of course ;)
379
407
  */
380
- focusout: function (evt) {
408
+ focusout: function(evt) {
381
409
  var that = this;
382
- this._focusTimeout = setTimeout(function () { that.blur(evt); }, 300);
410
+ this._focusTimeout = setTimeout(function(){that.blur(evt);}, 300);
383
411
  },
384
412
 
385
413
 
@@ -387,20 +415,128 @@ SC.RootResponder = SC.Object.extend(
387
415
  Handle window focus. Change hasFocus and add sc-focus CSS class (removing
388
416
  sc-blur). Also notify panes.
389
417
  */
390
- blur: function (evt) {
418
+ blur: function(evt) {
391
419
  if (this.get('hasFocus')) {
392
420
  SC.$('body').addClass('sc-blur').removeClass('sc-focus');
393
421
 
394
- SC.run(function () {
422
+ SC.run(function() {
395
423
  this.set('hasFocus', NO);
396
424
  }, this);
397
425
  }
398
- return YES; // allow default
426
+ return YES ; // allow default
427
+ },
428
+
429
+ dragDidStart: function(drag) {
430
+ this._mouseDownView = drag ;
431
+ this._drag = drag ;
432
+ },
433
+
434
+ // ------------------------------------------------------------------------
435
+ // Design Modes
436
+ //
437
+
438
+ /** @private */
439
+ currentDesignMode: null,
440
+
441
+ /** @private Managed by SC.Application. */
442
+ designModes: function (key, value) {
443
+ if (SC.none(value)) {
444
+ // Clear previous values.
445
+ if (this._designModeNames) {
446
+ delete this._designModeNames;
447
+ delete this._designModeThresholds;
448
+ }
449
+
450
+ value = null;
451
+ } else {
452
+ this._prepOrderedArrays(value);
453
+ }
454
+
455
+ this._assignDesignMode();
456
+
457
+ return value;
458
+ }.property().cacheable(),
459
+
460
+ /** @private Determine the design mode based on area and pixel density. */
461
+ computeDesignMode: function () {
462
+ var designMode = null,
463
+ designModeNames = this._designModeNames,
464
+ designModeThresholds = this._designModeThresholds,
465
+ currentWindowSize,
466
+ area;
467
+
468
+ // Fast path!
469
+ if (!designModeNames) { return null; }
470
+
471
+ currentWindowSize = this.get('currentWindowSize');
472
+ area = (currentWindowSize.width * currentWindowSize.height);
473
+ var i, len;
474
+ for (i = 0, len = designModeThresholds.get('length'); i < len; i++) {
475
+ var layoutWidthThreshold = designModeThresholds.objectAt(i);
476
+ if (area < layoutWidthThreshold) {
477
+ designMode = designModeNames.objectAt(i);
478
+ break;
479
+ }
480
+ }
481
+
482
+ // If no smaller designMode was found, use the biggest designMode.
483
+ if (SC.none(designMode) && designModeNames && designModeNames.get('length') > 0) {
484
+ designMode = designModeNames.objectAt(i);
485
+ }
486
+
487
+ return SC.device.orientation === SC.PORTRAIT_ORIENTATION ? designMode + '_p' : designMode + '_l';
488
+ },
489
+
490
+ /** @private (semi-private)
491
+ Returns the fallback design mode for the given design mode. This is
492
+ primarily used by SC.View for the case where an adjustment isn't found
493
+ for the current design mode and we want to apply the next best design
494
+ mode as a fallback.
495
+ */
496
+ fallbackDesignMode: function (designMode) {
497
+ var designModeNames = this._designModeNames,
498
+ index,
499
+ ret = null;
500
+
501
+ index = designModeNames.indexOf(designMode);
502
+ if (index >= 0) {
503
+ ret = designModeNames[index - 1];
504
+ }
505
+
506
+ return ret;
399
507
  },
400
508
 
401
- dragDidStart: function (drag) {
402
- this._mouseDownView = drag;
403
- this._drag = drag;
509
+ /** @private Prepares ordered design modes & widths arrays when designModes changes. */
510
+ _prepOrderedArrays: function (designModes) {
511
+ var designModeNames,
512
+ designModeThresholds;
513
+
514
+ // Order the design modes for easier access later.
515
+ if (designModes) {
516
+ designModeNames = this._designModeNames = [];
517
+ designModeThresholds = this._designModeThresholds = [];
518
+
519
+ var key;
520
+
521
+ outer:
522
+ for (key in designModes) {
523
+ var i, value;
524
+
525
+ // Assume that the keys will be ordered smallest to largest so run backwards.
526
+ value = designModes[key];
527
+ inner:
528
+ for (i = designModeThresholds.length - 1; i >= 0; i--) {
529
+ if (designModeThresholds[i] < value) {
530
+ // Exit early!
531
+ break inner;
532
+ }
533
+ }
534
+
535
+ i += 1;
536
+ designModeNames.splice(i, 0, key);
537
+ designModeThresholds.splice(i, 0, value);
538
+ }
539
+ }
404
540
  },
405
541
 
406
542
  // .......................................................
@@ -436,8 +572,8 @@ SC.RootResponder = SC.Object.extend(
436
572
  @returns {Boolean} YES if action was performed, NO otherwise
437
573
  @test in targetForAction
438
574
  */
439
- sendAction: function (action, target, sender, pane, context, firstResponder) {
440
- target = this.targetForAction(action, target, sender, pane, firstResponder);
575
+ sendAction: function( action, target, sender, pane, context, firstResponder) {
576
+ target = this.targetForAction(action, target, sender, pane, firstResponder) ;
441
577
 
442
578
  // HACK: If the target is a ResponderContext, forward the action.
443
579
  if (target && target.isResponderContext) {
@@ -445,14 +581,14 @@ SC.RootResponder = SC.Object.extend(
445
581
  } else return target && target.tryToPerform(action, sender);
446
582
  },
447
583
 
448
- _responderFor: function (target, methodName, firstResponder) {
584
+ _responderFor: function(target, methodName, firstResponder) {
449
585
  var defaultResponder = target ? target.get('defaultResponder') : null;
450
586
 
451
587
  if (target) {
452
588
  target = firstResponder || target.get('firstResponder') || target;
453
589
  do {
454
- if (target.respondsTo(methodName)) return target;
455
- } while ((target = target.get('nextResponder')));
590
+ if (target.respondsTo(methodName)) return target ;
591
+ } while ((target = target.get('nextResponder'))) ;
456
592
  }
457
593
 
458
594
  // HACK: Eventually we need to normalize the sendAction() method between
@@ -489,11 +625,11 @@ SC.RootResponder = SC.Object.extend(
489
625
  @param {firstResponder} a first responder to use
490
626
  @returns {Object} target object or null if none found
491
627
  */
492
- targetForAction: function (methodName, target, sender, pane, firstResponder) {
628
+ targetForAction: function(methodName, target, sender, pane, firstResponder) {
493
629
 
494
630
  // 1. no action, no target...
495
631
  if (!methodName || (SC.typeOf(methodName) !== SC.T_STRING)) {
496
- return null;
632
+ return null ;
497
633
  }
498
634
 
499
635
  // 2. an explicit target was passed...
@@ -505,13 +641,13 @@ SC.RootResponder = SC.Object.extend(
505
641
 
506
642
  if (target && !target.isResponderContext) {
507
643
  if (target.respondsTo && !target.respondsTo(methodName)) {
508
- target = null;
644
+ target = null ;
509
645
  } else if (SC.typeOf(target[methodName]) !== SC.T_FUNCTION) {
510
- target = null;
646
+ target = null ;
511
647
  }
512
648
  }
513
649
 
514
- return target;
650
+ return target ;
515
651
  }
516
652
 
517
653
  // 3. an explicit pane was passed...
@@ -522,32 +658,32 @@ SC.RootResponder = SC.Object.extend(
522
658
 
523
659
  // 4. no target or pane passed... try to find target in the active panes
524
660
  // and the defaultResponder
525
- var keyPane = this.get('keyPane'), mainPane = this.get('mainPane');
661
+ var keyPane = this.get('keyPane'), mainPane = this.get('mainPane') ;
526
662
 
527
663
  // ...check key and main panes first
528
664
  if (keyPane && (keyPane !== pane)) {
529
- target = this._responderFor(keyPane, methodName);
665
+ target = this._responderFor(keyPane, methodName) ;
530
666
  }
531
667
  if (!target && mainPane && (mainPane !== keyPane)) {
532
- target = this._responderFor(mainPane, methodName);
668
+ target = this._responderFor(mainPane, methodName) ;
533
669
  }
534
670
 
535
671
  // ...still no target? check the defaultResponder...
536
672
  if (!target && (target = this.get('defaultResponder'))) {
537
673
  if (SC.typeOf(target) === SC.T_STRING) {
538
- target = SC.objectForPropertyPath(target);
539
- if (target) this.set('defaultResponder', target); // cache if found
674
+ target = SC.objectForPropertyPath(target) ;
675
+ if (target) this.set('defaultResponder', target) ; // cache if found
540
676
  }
541
677
  if (target && !target.isResponderContext) {
542
678
  if (target.respondsTo && !target.respondsTo(methodName)) {
543
- target = null;
679
+ target = null ;
544
680
  } else if (SC.typeOf(target[methodName]) !== SC.T_FUNCTION) {
545
- target = null;
681
+ target = null ;
546
682
  }
547
683
  }
548
684
  }
549
685
 
550
- return target;
686
+ return target ;
551
687
  },
552
688
 
553
689
  /**
@@ -558,7 +694,10 @@ SC.RootResponder = SC.Object.extend(
558
694
  @returns {SC.View} view instance or null
559
695
  */
560
696
  targetViewForEvent: function (evt) {
561
- return evt.target ? SC.$(evt.target).view()[0] : null;
697
+ var ret = null;
698
+ if (evt.target) { ret = SC.viewFor(evt.target); }
699
+
700
+ return ret;
562
701
  },
563
702
 
564
703
  /**
@@ -575,19 +714,19 @@ SC.RootResponder = SC.Object.extend(
575
714
  @param {Object} target
576
715
  @returns {Object} object that handled the event or null if not handled
577
716
  */
578
- sendEvent: function (action, evt, target) {
579
- var pane, ret;
717
+ sendEvent: function(action, evt, target) {
718
+ var pane, ret ;
580
719
 
581
- SC.run(function () {
720
+ SC.run(function() {
582
721
  // get the target pane
583
- if (target) pane = target.get('pane');
584
- else pane = this.get('menuPane') || this.get('keyPane') || this.get('mainPane');
722
+ if (target) pane = target.get('pane') ;
723
+ else pane = this.get('menuPane') || this.get('keyPane') || this.get('mainPane') ;
585
724
 
586
725
  // if we found a valid pane, send the event to it
587
- ret = (pane) ? pane.sendEvent(action, evt, target) : null;
726
+ ret = (pane) ? pane.sendEvent(action, evt, target) : null ;
588
727
  }, this);
589
728
 
590
- return ret;
729
+ return ret ;
591
730
  },
592
731
 
593
732
  // .......................................................
@@ -607,16 +746,16 @@ SC.RootResponder = SC.Object.extend(
607
746
  @param {Boolean} useCapture
608
747
  @returns {SC.RootResponder} receiver
609
748
  */
610
- listenFor: function (keyNames, target, receiver, useCapture) {
749
+ listenFor: function(keyNames, target, receiver, useCapture) {
611
750
  receiver = receiver ? receiver : this;
612
- keyNames.forEach(function (keyName) {
613
- var method = receiver[keyName];
614
- if (method) SC.Event.add(target, keyName, receiver, method, null, useCapture);
615
- }, this);
751
+ keyNames.forEach( function(keyName) {
752
+ var method = receiver[keyName] ;
753
+ if (method) SC.Event.add(target, keyName, receiver, method, null, useCapture) ;
754
+ },this) ;
616
755
 
617
- target = null;
756
+ target = null ;
618
757
 
619
- return receiver;
758
+ return receiver ;
620
759
  },
621
760
 
622
761
  /**
@@ -626,20 +765,20 @@ SC.RootResponder = SC.Object.extend(
626
765
 
627
766
  @returns {void}
628
767
  */
629
- setup: function () {
768
+ setup: function() {
630
769
  // handle basic events
631
- this.listenFor(['touchstart', 'touchmove', 'touchend', 'touchcancel', 'keydown', 'keyup', 'beforedeactivate', 'mousedown', 'mouseup', 'click', 'dblclick', 'mousemove', 'contextmenu'], document)
770
+ this.listenFor(['touchstart', 'touchmove', 'touchend', 'touchcancel', 'keydown', 'keyup', 'beforedeactivate', 'mousedown', 'mouseup', 'dragenter', 'dragover', 'dragleave', 'drop', 'click', 'dblclick', 'mousemove', 'contextmenu'], document)
632
771
  .listenFor(['resize'], window);
633
772
 
634
- if (SC.browser.isIE8OrLower) this.listenFor(['focusin', 'focusout'], document);
773
+ if(SC.browser.isIE8OrLower) this.listenFor(['focusin', 'focusout'], document);
635
774
  else this.listenFor(['focus', 'blur'], window);
636
775
 
637
776
  // handle special case for keypress- you can't use normal listener to block
638
777
  // the backspace key on Mozilla
639
778
  if (this.keypress) {
640
779
  if (SC.CAPTURE_BACKSPACE_KEY && SC.browser.isMozilla) {
641
- var responder = this;
642
- document.onkeypress = function (e) {
780
+ var responder = this ;
781
+ document.onkeypress = function(e) {
643
782
  e = SC.Event.normalizeEvent(e);
644
783
  return responder.keypress.call(responder, e);
645
784
  };
@@ -702,19 +841,19 @@ SC.RootResponder = SC.Object.extend(
702
841
  }
703
842
 
704
843
  // handle these two events specially in IE
705
- ['drag', 'selectstart'].forEach(function (keyName) {
706
- var method = this[keyName];
844
+ ['drag', 'selectstart'].forEach(function(keyName) {
845
+ var method = this[keyName] ;
707
846
  if (method) {
708
847
  if (SC.browser.isIE) {
709
- var responder = this;
848
+ var responder = this ;
710
849
 
711
- document.body['on' + keyName] = function (e) {
850
+ document.body['on' + keyName] = function(e) {
712
851
  // return method.call(responder, SC.Event.normalizeEvent(e));
713
852
  return method.call(responder, SC.Event.normalizeEvent(event || window.event)); // this is IE :(
714
853
  };
715
854
 
716
855
  // be sure to cleanup memory leaks
717
- SC.Event.add(window, 'unload', this, function () {
856
+ SC.Event.add(window, 'unload', this, function() {
718
857
  document.body['on' + keyName] = null;
719
858
  });
720
859
 
@@ -741,8 +880,8 @@ SC.RootResponder = SC.Object.extend(
741
880
  }
742
881
  SC.Event.add(document, mousewheel, this, this.mousewheel);
743
882
 
744
- // do some initial set
745
- this.set('currentWindowSize', this.computeWindowSize());
883
+ // Do some initial set up.
884
+ this.set('currentWindowSize', this.computeWindowSize()) ;
746
885
 
747
886
  // TODO: Is this workaround still valid?
748
887
  if (SC.browser.os === SC.OS.ios && SC.browser.name === SC.BROWSER.safari) {
@@ -757,7 +896,7 @@ SC.RootResponder = SC.Object.extend(
757
896
  // Monkey patch RunLoop if we're in MobileSafari
758
897
  var f = SC.RunLoop.prototype.endRunLoop, patch;
759
898
 
760
- patch = function () {
899
+ patch = function() {
761
900
  // Call original endRunLoop implementation.
762
901
  if (f) f.apply(this, arguments);
763
902
 
@@ -832,10 +971,10 @@ SC.RootResponder = SC.Object.extend(
832
971
  // Once the actual event name is determined, simply remove all the extras.
833
972
  // This should prevent any problems with browsers that fire multiple events.
834
973
  ['transitionend', variation1, variation2, variation3].forEach(function (keyName) {
835
- if (keyName != actualEventName) {
974
+ if (keyName !== actualEventName) {
836
975
  SC.Event.remove(document, keyName, this, this[keyName]);
837
976
  this[keyName] = null;
838
- }
977
+ }
839
978
  });
840
979
  },
841
980
 
@@ -860,10 +999,10 @@ SC.RootResponder = SC.Object.extend(
860
999
  // Once the actual event name is determined, simply remove all the extras.
861
1000
  // This should prevent any problems with browsers that fire multiple events.
862
1001
  ['animationend', variation1, variation2, variation3].forEach(function (keyName) {
863
- if (keyName != actualEventName) {
1002
+ if (keyName !== actualEventName) {
864
1003
  SC.Event.remove(document, keyName, this, this[keyName]);
865
1004
  this[keyName] = null;
866
- }
1005
+ }
867
1006
  });
868
1007
 
869
1008
  actualEventName = SC.platform.animationiterationEventName;
@@ -871,7 +1010,7 @@ SC.RootResponder = SC.Object.extend(
871
1010
  variation2 = lowerDomPrefix + 'AnimationIteration';
872
1011
  variation3 = domPrefix + 'AnimationIteration';
873
1012
  ['animationiteration', variation1, variation2, variation3].forEach(function (keyName) {
874
- if (keyName != actualEventName) {
1013
+ if (keyName !== actualEventName) {
875
1014
  SC.Event.remove(document, keyName, this, this[keyName]);
876
1015
  this[keyName] = null;
877
1016
  }
@@ -882,7 +1021,7 @@ SC.RootResponder = SC.Object.extend(
882
1021
  variation2 = lowerDomPrefix + 'AnimationStart';
883
1022
  variation3 = domPrefix + 'AnimationStart';
884
1023
  ['animationstart', variation1, variation2, variation3].forEach(function (keyName) {
885
- if (keyName != actualEventName) {
1024
+ if (keyName !== actualEventName) {
886
1025
  SC.Event.remove(document, keyName, this, this[keyName]);
887
1026
  this[keyName] = null;
888
1027
  }
@@ -892,12 +1031,6 @@ SC.RootResponder = SC.Object.extend(
892
1031
  // ...........................................................................
893
1032
  // TOUCH SUPPORT
894
1033
  //
895
- /*
896
- There are three events: touchStart, touchEnd and touchesDragged.
897
-
898
- The touchStart and touchEnd events are called individually for each touch.
899
- The touchesDragged events are sent to whichever view owns the touch event.
900
- */
901
1034
 
902
1035
  /**
903
1036
  @private
@@ -920,8 +1053,10 @@ SC.RootResponder = SC.Object.extend(
920
1053
 
921
1054
  When views receive a touch event, they have the option to subscribe to it.
922
1055
  They are then mapped to touch events and vice-versa. This returns touches mapped to the view.
1056
+
1057
+ This method is also available on SC.Touch objects, and you will usually call it from there.
923
1058
  */
924
- touchesForView: function (view) {
1059
+ touchesForView: function(view) {
925
1060
  if (this._touchedViews[SC.guidFor(view)]) {
926
1061
  return this._touchedViews[SC.guidFor(view)].touches;
927
1062
  }
@@ -929,43 +1064,54 @@ SC.RootResponder = SC.Object.extend(
929
1064
 
930
1065
  /**
931
1066
  Computes a hash with x, y, and d (distance) properties, containing the average position
932
- of all touches, and the average distance of all touches from that average.
1067
+ of all touches, and the average distance of all touches from that average. This is useful
1068
+ for implementing scaling.
933
1069
 
934
- This is useful for implementing scaling.
1070
+ This method is also available on SC.Touch objects, and you will usually call it from there.
1071
+
1072
+ @param {SC.View} view The view whose touches should be averaged.
1073
+ @param {SC.Touch} additionalTouch This method uses touchesForView; if you call it from
1074
+ touchStart, that touch will not yet be included in touchesForView. To accommodate this,
1075
+ you should pass the view to this method (or pass YES to SC.Touch#averagedTouchesForView's
1076
+ `addSelf` argument).
935
1077
  */
936
- averagedTouchesForView: function (view, added) {
937
- var len,
938
- t = this.touchesForView(view),
1078
+ averagedTouchesForView: function(view, additionalTouch) {
1079
+ var t = this.touchesForView(view),
1080
+ len, averaged, additionalTouchIsDuplicate;
939
1081
 
940
- // cache per view to avoid gc
1082
+ // Each view gets its own cached average touches object for performance.
941
1083
  averaged = view._scrr_averagedTouches || (view._scrr_averagedTouches = {});
942
1084
 
943
- if ((!t || t.length === 0) && !added) {
1085
+ // FAST PATH: no touches to track.
1086
+ if ((!t || t.length === 0) && !additionalTouch) {
944
1087
  averaged.x = 0;
945
1088
  averaged.y = 0;
946
1089
  averaged.d = 0;
1090
+ averaged.velocityX = 0;
1091
+ averaged.velocityY = 0;
947
1092
  averaged.touchCount = 0;
948
-
949
- } else {
950
- // make array of touches using cached array
1093
+ }
1094
+ // Otherwise, average the touches.
1095
+ else {
1096
+ // Cache the array object used by this method. (Cleared at the end to prevent memory leaks.)
951
1097
  var touches = this._averagedTouches_touches || (this._averagedTouches_touches = []);
952
- touches.length = 0;
953
1098
 
954
1099
  // copy touches into array
955
1100
  if (t) {
956
1101
  var i;
957
1102
  len = t.length;
958
- for (i = 0; i < len; i++) {
1103
+ for(i = 0; i < len; i++) {
959
1104
  touches.push(t[i]);
1105
+ if (additionalTouch && t[i] === additionalTouch) additionalTouchIsDuplicate = YES;
960
1106
  }
961
1107
  }
962
1108
 
963
- // add added if needed
964
- if (added) touches.push(added);
1109
+ // Add additionalTouch if present and not duplicated.
1110
+ if (additionalTouch && !additionalTouchIsDuplicate) touches.push(additionalTouch);
965
1111
 
966
1112
  // prepare variables for looping
967
1113
  var idx, touch,
968
- ax = 0, ay = 0, dx, dy, ad = 0;
1114
+ ax = 0, ay = 0, dx, dy, ad = 0, avx = 0, avy = 0;
969
1115
  len = touches.length;
970
1116
 
971
1117
  // first, add
@@ -973,11 +1119,15 @@ SC.RootResponder = SC.Object.extend(
973
1119
  touch = touches[idx];
974
1120
  ax += touch.pageX;
975
1121
  ay += touch.pageY;
1122
+ avx += touch.velocityX;
1123
+ avy += touch.velocityY;
976
1124
  }
977
1125
 
978
1126
  // now, average
979
1127
  ax /= len;
980
1128
  ay /= len;
1129
+ avx /= len;
1130
+ avy /= len;
981
1131
 
982
1132
  // distance
983
1133
  for (idx = 0; idx < len; idx++) {
@@ -996,19 +1146,26 @@ SC.RootResponder = SC.Object.extend(
996
1146
 
997
1147
  averaged.x = ax;
998
1148
  averaged.y = ay;
1149
+ averaged.velocityX = avx;
1150
+ averaged.velocityY = avy;
999
1151
  averaged.d = ad;
1000
1152
  averaged.touchCount = len;
1153
+
1154
+ // Clear the touches array to prevent touch object leaks.
1155
+ touches.length = 0;
1001
1156
  }
1002
1157
 
1003
1158
  return averaged;
1004
1159
  },
1005
1160
 
1006
- assignTouch: function (touch, view) {
1161
+ assignTouch: function(touch, view) {
1007
1162
  // sanity-check
1008
1163
  if (touch.hasEnded) throw new Error("Attempt to assign a touch that is already finished.");
1009
1164
 
1010
- // unassign from old view if necessary
1165
+ // Fast path, the touch is already assigned to the view.
1011
1166
  if (touch.view === view) return;
1167
+
1168
+ // unassign from old view if necessary
1012
1169
  if (touch.view) {
1013
1170
  this.unassignTouch(touch);
1014
1171
  }
@@ -1029,12 +1186,14 @@ SC.RootResponder = SC.Object.extend(
1029
1186
  this._touchedViews[SC.guidFor(view)].touchCount++;
1030
1187
  },
1031
1188
 
1032
- unassignTouch: function (touch) {
1189
+ unassignTouch: function(touch) {
1033
1190
  // find view entry
1034
1191
  var view, viewEntry;
1035
1192
 
1036
- // get view
1193
+ // Fast path, the touch is not assigned to a view.
1037
1194
  if (!touch.view) return; // touch.view should===touch.touchResponder eventually :)
1195
+
1196
+ // get view
1038
1197
  view = touch.view;
1039
1198
 
1040
1199
  // get view entry
@@ -1053,7 +1212,7 @@ SC.RootResponder = SC.Object.extend(
1053
1212
  touch.view = undefined;
1054
1213
  },
1055
1214
 
1056
- _flushQueuedTouchResponder: function () {
1215
+ _flushQueuedTouchResponder: function(){
1057
1216
  if (this._queuedTouchResponder) {
1058
1217
  var queued = this._queuedTouchResponder;
1059
1218
  this._queuedTouchResponder = null;
@@ -1062,60 +1221,42 @@ SC.RootResponder = SC.Object.extend(
1062
1221
  },
1063
1222
 
1064
1223
  /**
1065
- The touch responder for any given touch is the view which will receive touch events
1066
- for that touch. Quite simple.
1067
-
1068
- makeTouchResponder takes a potential responder as an argument, and, by calling touchStart on each
1069
- nextResponder, finds the actual responder. As a side-effect of how it does this, touchStart is called
1070
- on the new responder before touchCancelled is called on the old one (touchStart has to accept the touch
1071
- before it can be considered cancelled).
1072
-
1073
- You usually don't have to think about this at all. However, if you don't want your view to,
1074
- for instance, prevent scrolling in a ScrollView, you need to make sure to transfer control
1075
- back to the previous responder:
1076
-
1077
- if (Math.abs(touch.pageY - touch.startY) > this.MAX_SWIPE)
1078
- touch.restoreLastTouchResponder();
1079
-
1080
- You don't call makeTouchResponder on RootResponder directly. Instead, it gets called for you
1081
- when you return YES to captureTouch or touchStart.
1082
-
1083
- You do, however, use a form of makeTouchResponder to return to a previous touch responder. Consider
1084
- a button view inside a ScrollView: if the touch moves too much, the button should give control back
1085
- to the scroll view.
1086
-
1087
- if (Math.abs(touch.pageX - touch.startX) > 4) {
1088
- if (touch.nextTouchResponder)
1089
- touch.makeTouchResponder(touch.nextTouchResponder);
1090
- }
1091
-
1092
- This will give control back to the containing view. Maybe you only want to do it if it is a ScrollView?
1093
-
1094
- if (
1095
- Math.abs(touch.pageX - touch.startX) > 4 &&
1096
- touch.nextTouchResponder &&
1097
- touch.nextTouchResponder.isScrollable
1098
- )
1099
- touch.makeTouchResponder(touch.nextTouchResponder);
1100
-
1101
- Possible gotcha: while you can do touch.nextTouchResponder, the responders are not chained in a linked list like
1102
- normal responders, because each touch has its own responder stack. To navigate through the stack (or, though
1103
- it is not recommended, change it), use touch.touchResponders (the raw stack array).
1104
-
1105
- makeTouchResponder is called with an event object. However, it usually triggers custom touchStart/touchCancelled
1106
- events on the views. The event object is passed so that functions such as stopPropagation may be called.
1224
+ This method attempts to change the responder for a particular touch. The touch's responder is the
1225
+ view which will receive touch events for that touch.
1226
+
1227
+ You will usually not call this method directly, instead calling one of the convenience methods on
1228
+ the touch itself. See documentation for SC.Touch for more.
1229
+
1230
+ Possible gotchas:
1231
+
1232
+ - Because this method must search for a view which implements touchStart (without returning NO),
1233
+ touchStart is called on the new responder before touchCancelled is called on the old one.
1234
+ - While a touch exposes its current responder at `touchResponder` and any previous stacked one at
1235
+ `nextTouchResponder`, their relationship is ad hoc and arbitrary, and so are not chained by
1236
+ `nextResponder` like in a standard responder chain. To query the touch's current responder stack
1237
+ (or, though it's not recommended, change it), check touch.touchResponders.
1238
+
1239
+ @param {SC.Touch} touch
1240
+ @param {SC.Responder} responder The view to assign to the touch. (It, or if bubbling then an ancestor,
1241
+ must implement touchStart.)
1242
+ @param {Boolean} shouldStack Whether the new responder should replace the old one, or stack with it.
1243
+ Stacked responders are easy to revert via `SC.Touch#restoreLastTouchResponder`.
1244
+ @param {Boolean|SC.Responder} bubblesTo If YES, will attempt to find a `touchStart` responder up the
1245
+ responder chain. If NO or undefined, will only check the passed responder. If you pass a responder
1246
+ for this argument, the attempt will bubble until it reaches the passed responder, allowing you to
1247
+ restrict the bubbling to a portion of the responder chain. ((Note that this responder will not be
1248
+ given an opportunity to respond to the event.)
1249
+ @returns {Boolean} Whether a valid touch responder was found and assigned.
1107
1250
  */
1108
- makeTouchResponder: function (touch, responder, shouldStack, upViewChain) {
1109
-
1251
+ makeTouchResponder: function(touch, responder, shouldStack, bubblesTo) {
1110
1252
  // In certain cases (SC.Gesture being one), we have to call makeTouchResponder
1111
1253
  // from inside makeTouchResponder so we queue it up here.
1112
1254
  if (this._isMakingTouchResponder) {
1113
- this._queuedTouchResponder = [touch, responder, shouldStack, upViewChain];
1114
- return;
1255
+ this._queuedTouchResponder = [touch, responder, shouldStack, bubblesTo];
1256
+ return YES; // um?
1115
1257
  }
1116
1258
  this._isMakingTouchResponder = YES;
1117
1259
 
1118
-
1119
1260
  var stack = touch.touchResponders, touchesForView;
1120
1261
 
1121
1262
  // find the actual responder (if any, I suppose)
@@ -1125,33 +1266,38 @@ SC.RootResponder = SC.Object.extend(
1125
1266
  if (touch.touchResponder === responder) {
1126
1267
  this._isMakingTouchResponder = NO;
1127
1268
  this._flushQueuedTouchResponder();
1128
- return;
1269
+ return YES; // more um
1129
1270
  }
1130
1271
 
1131
1272
  // send touchStart
1132
1273
  // get the target pane
1133
1274
  var pane;
1134
- if (responder) pane = responder.get('pane');
1135
- else pane = this.get('keyPane') || this.get('mainPane');
1275
+ if (responder) pane = responder.get('pane') ;
1276
+ else pane = this.get('keyPane') || this.get('mainPane') ;
1136
1277
 
1137
1278
  // if the responder is not already in the stack...
1138
-
1139
1279
  if (stack.indexOf(responder) < 0) {
1140
- // if we need to go up the view chain, do so
1141
- if (upViewChain) {
1280
+
1281
+ // if we need to go up the view chain, do so via SC.Pane#sendEvent.
1282
+ if (bubblesTo) {
1142
1283
  // if we found a valid pane, send the event to it
1143
1284
  try {
1144
- responder = (pane) ? pane.sendEvent("touchStart", touch, responder) : null;
1285
+ responder = pane ? pane.sendEvent("touchStart", touch, responder, bubblesTo) : null ;
1145
1286
  } catch (e) {
1146
1287
  SC.Logger.error("Error in touchStart: " + e);
1147
1288
  responder = null;
1148
1289
  }
1149
1290
  } else {
1150
-
1291
+ // If the responder doesn't currently have a touch, or it does but it accepts multitouch, test it. Otherwise it's cool.
1151
1292
  if (responder && ((responder.get ? responder.get("acceptsMultitouch") : responder.acceptsMultitouch) || !responder.hasTouch)) {
1152
- if (!responder.touchStart(touch)) responder = null;
1153
- } else {
1154
- // do nothing; the responder is the responder, and may stay the responder, and all will be fine
1293
+ // If it doesn't respond to touchStart, it's no good.
1294
+ if (!responder.respondsTo("touchStart")) {
1295
+ responder = null;
1296
+ }
1297
+ // If it returns NO from touchStart, it's no good. Otherwise it's cool.
1298
+ else if (responder.touchStart(touch) === NO) {
1299
+ responder = null;
1300
+ }
1155
1301
  }
1156
1302
  }
1157
1303
  }
@@ -1204,26 +1350,38 @@ SC.RootResponder = SC.Object.extend(
1204
1350
  }
1205
1351
  }
1206
1352
 
1207
-
1353
+ // Unflag that this method is running, and flush the queue if any.
1208
1354
  this._isMakingTouchResponder = NO;
1209
- this._flushQueuedTouchResponder();
1355
+ this._flushQueuedTouchResponder(); // this may need to be &&'ed with the responder to give the correct return value...
1210
1356
 
1357
+ return !!responder;
1211
1358
  },
1212
1359
 
1213
1360
  /**
1214
- captureTouch is used to find the view to handle a touch. It starts at the starting point and works down
1215
- to the touch's target, looking for a view which captures the touch. If no view is found, it uses the target
1216
- view.
1361
+ Before the touchStart event is sent up the usual responder chain, the views along that same responder chain
1362
+ are given the opportunity to capture the touch event, preventing child views (including the target) from
1363
+ hearing about it. This of course proceeds in the opposite direction from a usual event bubbling, starting at
1364
+ the target's first ancestor and proceeding towards the target. This method implements the capture phase.
1365
+
1366
+ If no view captures the touch, this method will return NO, and makeTouchResponder is then called for the
1367
+ target, proceeding with standard target-to-pane event bubbling for `touchStart`.
1217
1368
 
1218
- Then, it triggers a touchStart event starting at whatever the found view was; this propagates up the view chain
1219
- until a view responds YES. This view becomes the touch's owner.
1369
+ For an example of captureTouch in action, see SC.ScrollView's touch handling, which by default captures the
1370
+ touch and holds it for 150ms to allow it to determine whether the user is tapping or scrolling.
1220
1371
 
1221
- You usually do not call captureTouch, and if you do call it, you'd call it on the touch itself:
1222
- touch.captureTouch(startingPoint, shouldStack)
1372
+ You will usually not call this method yourself, and if you do, you should call the corresponding convenience
1373
+ method on the touch itself.
1223
1374
 
1224
- If shouldStack is YES, the previous responder will be kept so that it may be returned to later.
1375
+ @param {SC.Touch} touch The touch to offer up for capture.
1376
+ @param {?SC.Responder} startingPoint The view whose children should be given an opportunity to capture
1377
+ the event. (The starting point itself is not asked.)
1378
+ @param {Boolean} shouldStack Whether any capturing responder should stack with existing responders.
1379
+ Stacked responders are easy to revert via `SC.Touch#restoreLastTouchResponder`.
1380
+
1381
+ @returns {Boolean} Whether or not the touch was captured. If it was not, you should pass it to
1382
+ `makeTouchResponder` for standard event bubbling.
1225
1383
  */
1226
- captureTouch: function (touch, startingPoint, shouldStack) {
1384
+ captureTouch: function(touch, startingPoint, shouldStack) {
1227
1385
  if (!startingPoint) startingPoint = this;
1228
1386
 
1229
1387
  var target = touch.targetView, view = target,
@@ -1234,7 +1392,8 @@ SC.RootResponder = SC.Object.extend(
1234
1392
  SC.Logger.info(' -- Received one touch on %@'.fmt(target.toString()));
1235
1393
  }
1236
1394
  //@endif
1237
- // work up the chain until we get the root
1395
+ // Generate the captureTouch responder chain by working backwards from the target
1396
+ // to the starting point. (Don't include the starting point.)
1238
1397
  while (view && (view !== startingPoint)) {
1239
1398
  chain.unshift(view);
1240
1399
  view = view.get('nextResponder');
@@ -1254,26 +1413,24 @@ SC.RootResponder = SC.Object.extend(
1254
1413
  //@endif
1255
1414
 
1256
1415
  // if so, make it the touch's responder
1257
- this.makeTouchResponder(touch, view, shouldStack, YES); // triggers touchStart/Cancel/etc. event.
1258
- return; // and that's all we need
1416
+ this.makeTouchResponder(touch, view, shouldStack, startingPoint); // (touch, target, should stack, bubbles back to startingPoint, or all the way up.)
1417
+ return YES; // and that's all we need
1259
1418
  }
1260
1419
  }
1261
1420
 
1262
1421
  //@if (debug)
1263
- if (SC.LOG_TOUCH_EVENTS) SC.Logger.info(" -- Didn't find a view that returned YES to captureTouch, so we're calling touchStart");
1422
+ if (SC.LOG_TOUCH_EVENTS) SC.Logger.info(" -- Didn't find a view that returned YES to captureTouch.");
1264
1423
  //@endif
1265
1424
 
1266
- // if we did not capture the touch (obviously we didn't)
1267
- // we need to figure out what view _will_
1268
- // Thankfully, makeTouchResponder does exactly that: starts at the view it is supplied and keeps calling startTouch
1269
- this.makeTouchResponder(touch, target, shouldStack, YES);
1425
+ return NO;
1270
1426
  },
1271
1427
 
1428
+ //@if(debug)
1272
1429
  /** @private
1273
1430
  Artificially calls endTouch for any touch which is no longer present. This is necessary because
1274
1431
  _sometimes_, WebKit ends up not sending endtouch.
1275
1432
  */
1276
- endMissingTouches: function (presentTouches) {
1433
+ endMissingTouches: function(presentTouches) {
1277
1434
  var idx, len = presentTouches.length, map = {}, end = [];
1278
1435
 
1279
1436
  // make a map of what touches _are_ present
@@ -1288,19 +1445,24 @@ SC.RootResponder = SC.Object.extend(
1288
1445
  }
1289
1446
 
1290
1447
  // end said touches
1448
+ if (end.length) {
1449
+ console.warn('Ending missing touches: ' + end.toString());
1450
+ }
1291
1451
  for (idx = 0, len = end.length; idx < len; idx++) {
1292
1452
  this.endTouch(end[idx]);
1293
1453
  this.finishTouch(end[idx]);
1294
1454
  }
1295
1455
  },
1456
+ //@endif
1296
1457
 
1297
1458
  _touchCount: 0,
1459
+
1298
1460
  /** @private
1299
1461
  Ends a specific touch (for a bit, at least). This does not "finish" a touch; it merely calls
1300
1462
  touchEnd, touchCancelled, etc. A re-dispatch (through recapture or makeTouchResponder) will terminate
1301
1463
  the process; it would have to be restarted separately, through touch.end().
1302
1464
  */
1303
- endTouch: function (touchEntry, action, evt) {
1465
+ endTouch: function(touchEntry, action, evt) {
1304
1466
  if (!action) { action = "touchEnd"; }
1305
1467
 
1306
1468
  var responderIdx, responders, responder, originalResponder;
@@ -1333,16 +1495,15 @@ SC.RootResponder = SC.Object.extend(
1333
1495
  @private
1334
1496
  "Finishes" a touch. That is, it eradicates it from our touch entries and removes all responder, etc. properties.
1335
1497
  */
1336
- finishTouch: function (touch) {
1337
- var elem;
1338
-
1498
+ finishTouch: function(touch) {
1339
1499
  // ensure the touch is indeed unassigned.
1340
1500
  this.unassignTouch(touch);
1341
1501
 
1342
1502
  // If we rescued this touch's initial element, we should remove it
1343
1503
  // from the DOM and garbage collect now. See setup() for an
1344
1504
  // explanation of this bug/workaround.
1345
- if (elem = touch._rescuedElement) {
1505
+ var elem = touch._rescuedElement;
1506
+ if (elem) {
1346
1507
  if (elem.swapNode && elem.swapNode.parentNode) {
1347
1508
  elem.swapNode.parentNode.replaceChild(elem, elem.swapNode);
1348
1509
  } else if (elem.parentNode === SC.touchHoldingPen) {
@@ -1353,7 +1514,6 @@ SC.RootResponder = SC.Object.extend(
1353
1514
  elem = null;
1354
1515
  }
1355
1516
 
1356
-
1357
1517
  // clear responders (just to be thorough)
1358
1518
  touch.touchResponders = null;
1359
1519
  touch.touchResponder = null;
@@ -1375,18 +1535,19 @@ SC.RootResponder = SC.Object.extend(
1375
1535
  @param {Event} evt the event
1376
1536
  @returns {Boolean}
1377
1537
  */
1378
- touchstart: function (evt) {
1538
+ touchstart: function(evt) {
1379
1539
  // Starting iOS5 touch events are handled by textfields.
1380
1540
  // As a workaround just let the browser to use the default behavior.
1381
- if (this.ignoreTouchHandle(evt)) return YES;
1541
+ if(this.ignoreTouchHandle(evt)) return YES;
1382
1542
 
1383
1543
  var hidingTouchIntercept = NO;
1384
1544
 
1385
- SC.run(function () {
1386
- // sometimes WebKit is a bit... iffy:
1545
+ SC.run(function() {
1546
+ //@if(debug)
1547
+ // When using breakpoints on touch start, we will lose the end touch event.
1387
1548
  this.endMissingTouches(evt.touches);
1549
+ //@endif
1388
1550
 
1389
- // as you were...
1390
1551
  // loop through changed touches, calling touchStart, etc.
1391
1552
  var idx, touches = evt.changedTouches, len = touches.length,
1392
1553
  touch, touchEntry;
@@ -1418,18 +1579,16 @@ SC.RootResponder = SC.Object.extend(
1418
1579
  // set the event (so default action, etc. can be stopped)
1419
1580
  touchEntry.event = evt; // will be unset momentarily
1420
1581
 
1421
- // send out event thing: creates a chain, goes up it, then down it,
1422
- // with startTouch and cancelTouch. in this case, only startTouch, as
1423
- // there are no existing touch responders. We send the touchEntry
1424
- // because it is cached (we add the helpers only once)
1425
- this.captureTouch(touchEntry, this);
1582
+ // First we allow any view in the responder chain to capture the touch, before triggering the standard touchStart
1583
+ // handler chain.
1584
+ var captured = this.captureTouch(touchEntry, this);
1585
+ if (!captured) this.makeTouchResponder(touchEntry, touchEntry.targetView, NO, YES); // (touch, target, shouldn't stack, bubbles all the way)
1426
1586
 
1427
1587
  // Unset the reference to the original event so we can garbage collect.
1428
1588
  touchEntry.event = null;
1429
1589
  }
1430
1590
  }, this);
1431
1591
 
1432
-
1433
1592
  // hack for text fields
1434
1593
  if (hidingTouchIntercept) {
1435
1594
  return YES;
@@ -1442,12 +1601,12 @@ SC.RootResponder = SC.Object.extend(
1442
1601
  @private
1443
1602
  used to keep track of when a specific type of touch event was last handled, to see if it needs to be re-handled
1444
1603
  */
1445
- touchmove: function (evt) {
1604
+ touchmove: function(evt) {
1446
1605
  // Starting iOS5 touch events are handled by textfields.
1447
1606
  // As a workaround just let the browser to use the default behavior.
1448
- if (this.ignoreTouchHandle(evt)) return YES;
1607
+ if(this.ignoreTouchHandle(evt)) return YES;
1449
1608
 
1450
- SC.run(function () {
1609
+ SC.run(function() {
1451
1610
  // pretty much all we gotta do is update touches, and figure out which views need updating.
1452
1611
  var touches = evt.changedTouches, touch, touchEntry,
1453
1612
  idx, len = touches.length, view, changedTouches, viewTouches, firstTouch,
@@ -1472,7 +1631,23 @@ SC.RootResponder = SC.Object.extend(
1472
1631
 
1473
1632
  if (touchEntry.hidesTouchIntercept) hidingTouchIntercept = YES;
1474
1633
 
1475
- // update touch
1634
+ // update touch velocity (moving average)
1635
+ var duration = evt.timeStamp - touchEntry.timeStamp,
1636
+ velocityLambda, latestXVelocity, latestYVelocity;
1637
+ // Given uneven timing between events, we should give less weight to shorter (less accurate)
1638
+ // events, with no consideration at all given zero-time events.
1639
+ if (duration !== 0) {
1640
+ // Lambda (how heavily we're weighting the latest number)
1641
+ velocityLambda = Math.min(1, duration / 80);
1642
+ // X
1643
+ latestXVelocity = (touch.pageX - touchEntry.pageX) / duration;
1644
+ touchEntry.velocityX = (1.0 - velocityLambda) * touchEntry.velocityX + velocityLambda * (latestXVelocity);
1645
+ // Y
1646
+ latestYVelocity = (touch.pageY - touchEntry.pageY) / duration;
1647
+ touchEntry.velocityY = (1.0 - velocityLambda) * touchEntry.velocityY + velocityLambda * (latestYVelocity);
1648
+ }
1649
+
1650
+ // update touch position et al.
1476
1651
  touchEntry.pageX = touch.pageX;
1477
1652
  touchEntry.pageY = touch.pageY;
1478
1653
  touchEntry.clientX = touch.clientX;
@@ -1480,6 +1655,7 @@ SC.RootResponder = SC.Object.extend(
1480
1655
  touchEntry.screenX = touch.screenX;
1481
1656
  touchEntry.screenY = touch.screenY;
1482
1657
  touchEntry.timeStamp = evt.timeStamp;
1658
+ touchEntry.type = evt.type;
1483
1659
  touchEntry.event = evt;
1484
1660
 
1485
1661
  // if the touch entry has a view
@@ -1513,15 +1689,22 @@ SC.RootResponder = SC.Object.extend(
1513
1689
  // the first VIEW touch should be the touch info sent
1514
1690
  viewTouches = this.touchesForView(view);
1515
1691
  firstTouch = viewTouches.firstObject();
1692
+
1693
+ // Load the event up with data from the first touch. THIS IS FOR CONVENIENCE ONLY in cases where the developer
1694
+ // only cares about one touch.
1516
1695
  evt.pageX = firstTouch.pageX;
1517
1696
  evt.pageY = firstTouch.pageY;
1518
1697
  evt.clientX = firstTouch.clientX;
1519
1698
  evt.clientY = firstTouch.clientY;
1520
1699
  evt.screenX = firstTouch.screenX;
1521
1700
  evt.screenY = firstTouch.screenY;
1522
- evt.touchContext = this; // so it can call touchesForView
1701
+ evt.startX = firstTouch.startX;
1702
+ evt.startY = firstTouch.startY;
1703
+ evt.velocityX = firstTouch.velocityX;
1704
+ evt.velocityY = firstTouch.velocityY;
1705
+ evt.touchContext = this; // Injects the root responder so it can call e.g. `touchesForView`.
1523
1706
 
1524
- // and go
1707
+ // Give the view a chance to handle touchesDragged. (Don't bubble; viewTouches is view-specific.)
1525
1708
  view.tryToPerform("touchesDragged", evt, viewTouches);
1526
1709
  }
1527
1710
 
@@ -1538,14 +1721,14 @@ SC.RootResponder = SC.Object.extend(
1538
1721
  return evt.hasCustomEventHandling;
1539
1722
  },
1540
1723
 
1541
- touchend: function (evt) {
1724
+ touchend: function(evt) {
1542
1725
  var hidesTouchIntercept = NO;
1543
1726
 
1544
1727
  // Starting iOS5 touch events are handled by textfields.
1545
1728
  // As a workaround just let the browser to use the default behavior.
1546
- if (this.ignoreTouchHandle(evt)) return YES;
1729
+ if(this.ignoreTouchHandle(evt)) return YES;
1547
1730
 
1548
- SC.run(function () {
1731
+ SC.run(function() {
1549
1732
  var touches = evt.changedTouches, touch, touchEntry,
1550
1733
  idx, len = touches.length,
1551
1734
  action = evt.isCancel ? "touchCancelled" : "touchEnd";
@@ -1559,7 +1742,23 @@ SC.RootResponder = SC.Object.extend(
1559
1742
  // check if there is an entry
1560
1743
  if (!touchEntry) continue;
1561
1744
 
1562
- // continue work
1745
+ // update touch velocity (moving average)
1746
+ var duration = evt.timeStamp - touchEntry.timeStamp,
1747
+ velocityLambda, latestXVelocity, latestYVelocity;
1748
+ // Given uneven timing between events, we should give less weight to shorter (less accurate)
1749
+ // events, with no consideration at all given zero-time events.
1750
+ if (duration !== 0) {
1751
+ // Lambda (how heavily we're weighting the latest number)
1752
+ velocityLambda = Math.min(1, duration / 80);
1753
+ // X
1754
+ latestXVelocity = (touch.pageX - touchEntry.pageX) / duration;
1755
+ touchEntry.velocityX = (1.0 - velocityLambda) * touchEntry.velocityX + velocityLambda * (latestXVelocity);
1756
+ // Y
1757
+ latestYVelocity = (touch.pageY - touchEntry.pageY) / duration;
1758
+ touchEntry.velocityY = (1.0 - velocityLambda) * touchEntry.velocityY + velocityLambda * (latestYVelocity);
1759
+ }
1760
+
1761
+ // update touch position et al.
1563
1762
  touchEntry.timeStamp = evt.timeStamp;
1564
1763
  touchEntry.pageX = touch.pageX;
1565
1764
  touchEntry.pageY = touch.pageY;
@@ -1579,8 +1778,8 @@ SC.RootResponder = SC.Object.extend(
1579
1778
  }
1580
1779
 
1581
1780
  if (this._drag) {
1582
- this._drag.tryToPerform('mouseUp', touch);
1583
- this._drag = null;
1781
+ this._drag.tryToPerform('mouseUp', touch) ;
1782
+ this._drag = null ;
1584
1783
  }
1585
1784
 
1586
1785
  // unassign
@@ -1602,7 +1801,7 @@ SC.RootResponder = SC.Object.extend(
1602
1801
  Handle touch cancel event. Works just like cancelling a touch for any other reason.
1603
1802
  touchend handles it as a special case (sending cancel instead of end if needed).
1604
1803
  */
1605
- touchcancel: function (evt) {
1804
+ touchcancel: function(evt) {
1606
1805
  evt.isCancel = YES;
1607
1806
  this.touchend(evt);
1608
1807
  },
@@ -1611,10 +1810,10 @@ SC.RootResponder = SC.Object.extend(
1611
1810
  Ignore Touch events on textfields and links. starting iOS 5 textfields
1612
1811
  get touch events. Textfields just need to get the default focus action.
1613
1812
  */
1614
- ignoreTouchHandle: function (evt) {
1615
- if (SC.browser.isMobileSafari) {
1813
+ ignoreTouchHandle: function(evt) {
1814
+ if(SC.browser.isMobileSafari){
1616
1815
  var tag = evt.target.tagName;
1617
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "A" || tag === "SELECT") {
1816
+ if(tag==="INPUT" || tag==="TEXTAREA" || tag==="A" || tag==="SELECT"){
1618
1817
  evt.allowDefault();
1619
1818
  return YES;
1620
1819
  }
@@ -1635,8 +1834,8 @@ SC.RootResponder = SC.Object.extend(
1635
1834
 
1636
1835
  @returns {Object} Object that handled evet or null
1637
1836
  */
1638
- attemptKeyEquivalent: function (evt) {
1639
- var ret = null;
1837
+ attemptKeyEquivalent: function(evt) {
1838
+ var ret = null ;
1640
1839
 
1641
1840
  // keystring is a method name representing the keys pressed (i.e
1642
1841
  // 'alt_shift_escape')
@@ -1650,24 +1849,24 @@ SC.RootResponder = SC.Object.extend(
1650
1849
  mainPane = this.get('mainPane');
1651
1850
 
1652
1851
  if (menuPane) {
1653
- ret = menuPane.performKeyEquivalent(keystring, evt);
1852
+ ret = menuPane.performKeyEquivalent(keystring, evt) ;
1654
1853
  if (ret) return ret;
1655
1854
  }
1656
1855
 
1657
1856
  // Try the keyPane. If it's modal, then try the equivalent there but on
1658
1857
  // nobody else.
1659
1858
  if (keyPane) {
1660
- ret = keyPane.performKeyEquivalent(keystring, evt);
1661
- if (ret || keyPane.get('isModal')) return ret;
1859
+ ret = keyPane.performKeyEquivalent(keystring, evt) ;
1860
+ if (ret || keyPane.get('isModal')) return ret ;
1662
1861
  }
1663
1862
 
1664
1863
  // if not, then try the main pane
1665
- if (!ret && mainPane && (mainPane !== keyPane)) {
1864
+ if (!ret && mainPane && (mainPane!==keyPane)) {
1666
1865
  ret = mainPane.performKeyEquivalent(keystring, evt);
1667
- if (ret || mainPane.get('isModal')) return ret;
1866
+ if (ret || mainPane.get('isModal')) return ret ;
1668
1867
  }
1669
1868
 
1670
- return ret;
1869
+ return ret ;
1671
1870
  },
1672
1871
 
1673
1872
  _lastModifiers: null,
@@ -1677,7 +1876,7 @@ SC.RootResponder = SC.Object.extend(
1677
1876
  We turn this into a flagsChanged keyboard event. Normally this does not
1678
1877
  stop the normal browser behavior.
1679
1878
  */
1680
- _handleModifierChanges: function (evt) {
1879
+ _handleModifierChanges: function(evt) {
1681
1880
  // if the modifier keys have changed, then notify the first responder.
1682
1881
  var m;
1683
1882
  m = this._lastModifiers = (this._lastModifiers || { alt: false, ctrl: false, shift: false });
@@ -1699,7 +1898,7 @@ SC.RootResponder = SC.Object.extend(
1699
1898
  }
1700
1899
  evt.modifiers = m; // save on event
1701
1900
 
1702
- return (changed) ? (this.sendEvent('flagsChanged', evt) ? evt.hasCustomEventHandling : YES) : YES;
1901
+ return (changed) ? (this.sendEvent('flagsChanged', evt) ? evt.hasCustomEventHandling : YES) : YES ;
1703
1902
  },
1704
1903
 
1705
1904
  /** @private
@@ -1708,7 +1907,7 @@ SC.RootResponder = SC.Object.extend(
1708
1907
  handles the event, then it will be sent as a regular keyDown event.
1709
1908
  This function is only valid when called with a keydown event.
1710
1909
  */
1711
- _isFunctionOrNonPrintableKey: function (evt) {
1910
+ _isFunctionOrNonPrintableKey: function(evt) {
1712
1911
  return !!(evt.altKey || evt.ctrlKey || evt.metaKey || SC.FUNCTION_KEYS[evt.which]);
1713
1912
  },
1714
1913
 
@@ -1716,7 +1915,7 @@ SC.RootResponder = SC.Object.extend(
1716
1915
  Determines if the event simply reflects a modifier key change. These
1717
1916
  events may generate a flagsChanged event, but are otherwise ignored.
1718
1917
  */
1719
- _isModifierKey: function (evt) {
1918
+ _isModifierKey: function(evt) {
1720
1919
  return !!SC.MODIFIER_KEYS[evt.charCode];
1721
1920
  },
1722
1921
 
@@ -1747,16 +1946,16 @@ SC.RootResponder = SC.Object.extend(
1747
1946
  https://developer.mozilla.org/en/DOM/KeyboardEvent
1748
1947
  http://msdn.microsoft.com/library/ff974342.aspx
1749
1948
  */
1750
- keydown: function (evt) {
1949
+ keydown: function(evt) {
1751
1950
  if (SC.none(evt)) return YES;
1752
1951
  var keyCode = evt.keyCode;
1753
- if (SC.browser.isMozilla && evt.keyCode === 9) {
1952
+ if (SC.browser.isMozilla && evt.keyCode===9) {
1754
1953
  this.keydownCounter = 1;
1755
1954
  }
1756
1955
  // Fix for IME input (japanese, mandarin).
1757
1956
  // If the KeyCode is 229 wait for the keyup and
1758
1957
  // trigger a keyDown if it is is enter onKeyup.
1759
- if (keyCode === 229) {
1958
+ if (keyCode===229){
1760
1959
  this._IMEInputON = YES;
1761
1960
  return this.sendEvent('keyDown', evt);
1762
1961
  }
@@ -1771,7 +1970,7 @@ SC.RootResponder = SC.Object.extend(
1771
1970
  }
1772
1971
 
1773
1972
  // Firefox does NOT handle delete here...
1774
- if (SC.browser.isMozilla && (evt.which === 8)) return true;
1973
+ if (SC.browser.isMozilla && (evt.which === 8)) return true ;
1775
1974
 
1776
1975
  // modifier keys are handled separately by the 'flagsChanged' event
1777
1976
  // send event for modifier key changes, but only stop processing if this
@@ -1785,29 +1984,29 @@ SC.RootResponder = SC.Object.extend(
1785
1984
  // if this is a function or non-printable key, try to use this as a key
1786
1985
  // equivalent. Otherwise, send as a keyDown event so that the focused
1787
1986
  // responder can do something useful with the event.
1788
- ret = YES;
1987
+ ret = YES ;
1789
1988
  if (this._isFunctionOrNonPrintableKey(evt)) {
1790
1989
  // otherwise, send as keyDown event. If no one was interested in this
1791
1990
  // keyDown event (probably the case), just let the browser do its own
1792
1991
  // processing.
1793
1992
 
1794
1993
  // Arrow keys are handled in keypress for firefox
1795
- if (keyCode >= 37 && keyCode <= 40 && SC.browser.isMozilla) return YES;
1994
+ if (keyCode>=37 && keyCode<=40 && SC.browser.isMozilla) return YES;
1796
1995
 
1797
- ret = this.sendEvent('keyDown', evt);
1996
+ ret = this.sendEvent('keyDown', evt) ;
1798
1997
 
1799
1998
  // attempt key equivalent if key not handled
1800
1999
  if (!ret) {
1801
2000
  SC.run(function () {
1802
- ret = !this.attemptKeyEquivalent(evt);
2001
+ ret = !this.attemptKeyEquivalent(evt) ;
1803
2002
  }, this);
1804
2003
  } else {
1805
- ret = evt.hasCustomEventHandling;
1806
- if (ret) forceBlock = NO; // code asked explicitly to let delete go
2004
+ ret = evt.hasCustomEventHandling ;
2005
+ if (ret) forceBlock = NO ; // code asked explicitly to let delete go
1807
2006
  }
1808
2007
  }
1809
2008
 
1810
- return forceBlock ? NO : ret;
2009
+ return forceBlock ? NO : ret ;
1811
2010
  },
1812
2011
 
1813
2012
  /** @private
@@ -1818,14 +2017,14 @@ SC.RootResponder = SC.Object.extend(
1818
2017
  Normally ignore any function or non-printable key events. Otherwise, just
1819
2018
  trigger a keyDown.
1820
2019
  */
1821
- keypress: function (evt) {
2020
+ keypress: function(evt) {
1822
2021
  var ret,
1823
2022
  keyCode = evt.keyCode,
1824
2023
  isFirefox = SC.browser.isMozilla;
1825
2024
 
1826
- if (isFirefox && evt.keyCode === 9) {
2025
+ if (isFirefox && evt.keyCode===9) {
1827
2026
  this.keydownCounter++;
1828
- if (this.keydownCounter == 2) return YES;
2027
+ if (this.keydownCounter === 2) return YES;
1829
2028
  }
1830
2029
 
1831
2030
  // delete is handled in keydown() for most browsers
@@ -1833,27 +2032,27 @@ SC.RootResponder = SC.Object.extend(
1833
2032
  //get the keycode and set it for which.
1834
2033
  evt.which = keyCode;
1835
2034
  ret = this.sendEvent('keyDown', evt);
1836
- return ret ? (SC.allowsBackspaceToPreviousPage || evt.hasCustomEventHandling) : YES;
2035
+ return ret ? (SC.allowsBackspaceToPreviousPage || evt.hasCustomEventHandling) : YES ;
1837
2036
 
1838
2037
  // normal processing. send keyDown for printable keys...
1839
2038
  //there is a special case for arrow key repeating of events in FF.
1840
2039
  } else {
1841
2040
  var isFirefoxArrowKeys = (keyCode >= 37 && keyCode <= 40 && isFirefox),
1842
- charCode = evt.charCode;
2041
+ charCode = evt.charCode;
1843
2042
 
1844
- if ((charCode !== undefined && charCode === 0 && evt.keyCode !== 9) && !isFirefoxArrowKeys) return YES;
2043
+ if ((charCode !== undefined && charCode === 0 && evt.keyCode!==9) && !isFirefoxArrowKeys) return YES;
1845
2044
  if (isFirefoxArrowKeys) evt.which = keyCode;
1846
2045
  // we only want to rethrow if this is a printable key so that we don't
1847
2046
  // duplicate the event sent in keydown when a modifier key is pressed.
1848
2047
  if (isFirefoxArrowKeys || this._isPrintableKey(evt)) {
1849
2048
  return this.sendEvent('keyDown', evt) ? evt.hasCustomEventHandling : YES;
1850
- }
2049
+ }
1851
2050
  }
1852
2051
  },
1853
2052
 
1854
- keyup: function (evt) {
2053
+ keyup: function(evt) {
1855
2054
  // to end the simulation of keypress in firefox set the _ffevt to null
1856
- if (this._ffevt) this._ffevt = null;
2055
+ if(this._ffevt) this._ffevt=null;
1857
2056
 
1858
2057
  // modifier keys are handled separately by the 'flagsChanged' event
1859
2058
  // send event for modifier key changes, but only stop processing if this is only a modifier change
@@ -1862,7 +2061,7 @@ SC.RootResponder = SC.Object.extend(
1862
2061
  // Fix for IME input (japanese, mandarin).
1863
2062
  // If the KeyCode is 229 wait for the keyup and
1864
2063
  // trigger a keyDown if it is is enter onKeyup.
1865
- if (this._IMEInputON && evt.keyCode === 13) {
2064
+ if (this._IMEInputON && evt.keyCode===13){
1866
2065
  evt.isIMEInput = YES;
1867
2066
  this.sendEvent('keyDown', evt);
1868
2067
  this._IMEInputON = NO;
@@ -1879,10 +2078,10 @@ SC.RootResponder = SC.Object.extend(
1879
2078
  want to avoid this. Think of an autocomplete menu, you want to click on
1880
2079
  the menu but don't loose focus.
1881
2080
  */
1882
- beforedeactivate: function (evt) {
2081
+ beforedeactivate: function(evt) {
1883
2082
  var toElement = evt.toElement;
1884
- if (toElement && toElement.tagName && toElement.tagName !== "IFRAME") {
1885
- var view = SC.$(toElement).view()[0];
2083
+ if (toElement && toElement.tagName && toElement.tagName!=="IFRAME") {
2084
+ var view = SC.viewFor(toElement);
1886
2085
  //The following line is necessary to allow/block text selection for IE,
1887
2086
  // in combination with the selectstart event.
1888
2087
  if (view && view.get('blocksIEDeactivate')) return NO;
@@ -1894,30 +2093,30 @@ SC.RootResponder = SC.Object.extend(
1894
2093
  // MOUSE HANDLING
1895
2094
  //
1896
2095
 
1897
- mousedown: function (evt) {
2096
+ mousedown: function(evt) {
1898
2097
  // First, save the click count. The click count resets if the mouse down
1899
2098
  // event occurs more than 250 ms later than the mouse up event or more
1900
2099
  // than 8 pixels away from the mouse down event or if the button used is different.
1901
- this._clickCount += 1;
2100
+ this._clickCount += 1 ;
1902
2101
  if (!this._lastMouseUpAt || this._lastClickWhich !== evt.which || ((Date.now() - this._lastMouseUpAt) > 250)) {
1903
- this._clickCount = 1;
2102
+ this._clickCount = 1 ;
1904
2103
  } else {
1905
2104
  var deltaX = this._lastMouseDownX - evt.clientX,
1906
2105
  deltaY = this._lastMouseDownY - evt.clientY,
1907
- distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
2106
+ distance = Math.sqrt(deltaX*deltaX + deltaY*deltaY) ;
1908
2107
 
1909
- if (distance > 8.0) this._clickCount = 1;
2108
+ if (distance > 8.0) this._clickCount = 1 ;
1910
2109
  }
1911
- evt.clickCount = this._clickCount;
2110
+ evt.clickCount = this._clickCount ;
1912
2111
 
1913
2112
  this._lastClickWhich = evt.which;
1914
- this._lastMouseDownX = evt.clientX;
1915
- this._lastMouseDownY = evt.clientY;
2113
+ this._lastMouseDownX = evt.clientX ;
2114
+ this._lastMouseDownY = evt.clientY ;
1916
2115
 
1917
2116
  var view = this.targetViewForEvent(evt);
1918
2117
 
1919
- view = this._mouseDownView = this.sendEvent('mouseDown', evt, view);
1920
- if (view && view.respondsTo('mouseDragged')) this._mouseCanDrag = YES;
2118
+ view = this._mouseDownView = this.sendEvent('mouseDown', evt, view) ;
2119
+ if (view && view.respondsTo('mouseDragged')) this._mouseCanDrag = YES ;
1921
2120
 
1922
2121
  // Determine if any views took responsibility for the
1923
2122
  // event. If so, save that information so we can prevent
@@ -1935,7 +2134,7 @@ SC.RootResponder = SC.Object.extend(
1935
2134
  implemented, then no mouseUp event will be sent, but a click will be
1936
2135
  sent.
1937
2136
  */
1938
- mouseup: function (evt) {
2137
+ mouseup: function(evt) {
1939
2138
  var clickOrDoubleClickDidTrigger = NO,
1940
2139
  dragView = this._drag,
1941
2140
  handler = null;
@@ -1949,41 +2148,41 @@ SC.RootResponder = SC.Object.extend(
1949
2148
  var view = this._mouseDownView,
1950
2149
  targetView = this.targetViewForEvent(evt);
1951
2150
 
1952
- // record click count.
1953
- evt.clickCount = this._clickCount;
2151
+ // record click count.
2152
+ evt.clickCount = this._clickCount ;
1954
2153
 
1955
- // attempt the mouseup call only if there's a target.
1956
- // don't want a mouseup going to anyone unless they handled the mousedown...
1957
- if (view) {
1958
- handler = this.sendEvent('mouseUp', evt, view);
2154
+ // attempt the mouseup call only if there's a target.
2155
+ // don't want a mouseup going to anyone unless they handled the mousedown...
2156
+ if (view) {
2157
+ handler = this.sendEvent('mouseUp', evt, view) ;
1959
2158
 
1960
- // try doubleClick
1961
- if (!handler && (this._clickCount === 2)) {
1962
- handler = this.sendEvent('doubleClick', evt, view);
1963
- clickOrDoubleClickDidTrigger = YES;
1964
- }
2159
+ // try doubleClick
2160
+ if (!handler && (this._clickCount === 2)) {
2161
+ handler = this.sendEvent('doubleClick', evt, view) ;
2162
+ clickOrDoubleClickDidTrigger = YES;
2163
+ }
1965
2164
 
1966
- // try single click
1967
- if (!handler) {
1968
- handler = this.sendEvent('click', evt, view);
1969
- clickOrDoubleClickDidTrigger = YES;
1970
- }
2165
+ // try single click
2166
+ if (!handler) {
2167
+ handler = this.sendEvent('click', evt, view) ;
2168
+ clickOrDoubleClickDidTrigger = YES;
1971
2169
  }
2170
+ }
1972
2171
 
1973
- // try whoever's under the mouse if we haven't handle the mouse up yet
1974
- if (!handler && !clickOrDoubleClickDidTrigger) {
2172
+ // try whoever's under the mouse if we haven't handle the mouse up yet
2173
+ if (!handler && !clickOrDoubleClickDidTrigger) {
1975
2174
 
1976
- // try doubleClick
1977
- if (this._clickCount === 2) {
1978
- handler = this.sendEvent('doubleClick', evt, targetView);
1979
- }
2175
+ // try doubleClick
2176
+ if (this._clickCount === 2) {
2177
+ handler = this.sendEvent('doubleClick', evt, targetView);
2178
+ }
1980
2179
 
1981
- // try singleClick
1982
- if (!handler) {
1983
- handler = this.sendEvent('click', evt, targetView);
1984
- }
2180
+ // try singleClick
2181
+ if (!handler) {
2182
+ handler = this.sendEvent('click', evt, targetView) ;
1985
2183
  }
1986
2184
  }
2185
+ }
1987
2186
 
1988
2187
  // cleanup
1989
2188
  this._mouseCanDrag = NO;
@@ -1991,7 +2190,7 @@ SC.RootResponder = SC.Object.extend(
1991
2190
 
1992
2191
  // Save timestamp of mouseup at last possible moment.
1993
2192
  // (This is used to calculate double click events)
1994
- this._lastMouseUpAt = Date.now();
2193
+ this._lastMouseUpAt = Date.now() ;
1995
2194
 
1996
2195
  // Determine if any views took responsibility for the
1997
2196
  // event. If so, save that information so we can prevent
@@ -2012,7 +2211,7 @@ SC.RootResponder = SC.Object.extend(
2012
2211
  @param {Event} evt the click event
2013
2212
  @returns {Boolean} whether the event should be propagated to the browser
2014
2213
  */
2015
- click: function (evt) {
2214
+ click: function(evt) {
2016
2215
  if (!this._lastMouseUpCustomHandling || !this._lastMouseDownCustomHandling) {
2017
2216
  evt.preventDefault();
2018
2217
  evt.stopPropagation();
@@ -2022,7 +2221,7 @@ SC.RootResponder = SC.Object.extend(
2022
2221
  return YES;
2023
2222
  },
2024
2223
 
2025
- dblclick: function (evt) {
2224
+ dblclick: function(evt){
2026
2225
  if (SC.browser.isIE8OrLower) {
2027
2226
  this._clickCount = 2;
2028
2227
  // this._onmouseup(evt);
@@ -2030,11 +2229,11 @@ SC.RootResponder = SC.Object.extend(
2030
2229
  }
2031
2230
  },
2032
2231
 
2033
- mousewheel: function (evt) {
2034
- var view = this.targetViewForEvent(evt),
2035
- handler = this.sendEvent('mouseWheel', evt, view);
2232
+ mousewheel: function(evt) {
2233
+ var view = this.targetViewForEvent(evt) ,
2234
+ handler = this.sendEvent('mouseWheel', evt, view) ;
2036
2235
 
2037
- return (handler) ? evt.hasCustomEventHandling : YES;
2236
+ return (handler) ? evt.hasCustomEventHandling : YES ;
2038
2237
  },
2039
2238
 
2040
2239
  _lastHovered: null,
@@ -2048,7 +2247,7 @@ SC.RootResponder = SC.Object.extend(
2048
2247
  If there is a target mouseDown view, then mouse moved events will also
2049
2248
  trigger calls to mouseDragged.
2050
2249
  */
2051
- mousemove: function (evt) {
2250
+ mousemove: function(evt) {
2052
2251
 
2053
2252
  if (SC.browser.isIE) {
2054
2253
  if (this._lastMoveX === evt.clientX && this._lastMoveY === evt.clientY) return;
@@ -2059,7 +2258,7 @@ SC.RootResponder = SC.Object.extend(
2059
2258
  this._lastMoveX = evt.clientX;
2060
2259
  this._lastMoveY = evt.clientY;
2061
2260
 
2062
- SC.run(function () {
2261
+ SC.run(function() {
2063
2262
  var dragView = this._drag;
2064
2263
 
2065
2264
  // make sure the view gets focus no matter what. FF is inconsistent
@@ -2068,60 +2267,217 @@ SC.RootResponder = SC.Object.extend(
2068
2267
  // only do mouse[Moved|Entered|Exited|Dragged] if not in a drag session
2069
2268
  // drags send their own events, e.g. drag[Moved|Entered|Exited]
2070
2269
  if (dragView) {
2071
- //IE triggers mousemove at the same time as mousedown
2072
- if (SC.browser.isIE) {
2073
- if (this._lastMouseDownX !== evt.clientX || this._lastMouseDownY !== evt.clientY) {
2270
+ //IE triggers mousemove at the same time as mousedown
2271
+ if(SC.browser.isIE){
2272
+ if (this._lastMouseDownX !== evt.clientX || this._lastMouseDownY !== evt.clientY) {
2074
2273
  dragView.tryToPerform('mouseDragged', evt);
2075
- }
2274
+ }
2076
2275
  } else {
2077
2276
  dragView.tryToPerform('mouseDragged', evt);
2078
- }
2079
- } else {
2277
+ }
2278
+ } else {
2080
2279
  var lh = this._lastHovered || [], nh = [], loc, len,
2081
- view = this.targetViewForEvent(evt);
2280
+ view = this.targetViewForEvent(evt) ;
2281
+
2282
+ // first collect all the responding view starting with the
2283
+ // target view from the given mouse move event
2284
+ while (view && (view !== this)) {
2285
+ nh.push(view);
2286
+ view = view.get('nextResponder');
2287
+ }
2288
+ // next exit views that are no longer part of the
2289
+ // responding chain
2290
+ for (loc=0, len=lh.length; loc < len; loc++) {
2291
+ view = lh[loc] ;
2292
+ if (nh.indexOf(view) === -1 && !view.isDestroyed) { // Usually we don't want to have to manually check isDestroyed, but in this case we're explicitly checking an out-of-date cache.
2293
+ view.tryToPerform('mouseExited', evt);
2294
+ }
2295
+ }
2296
+ // finally, either perform mouse moved or mouse entered depending on
2297
+ // whether a responding view was or was not part of the last
2298
+ // hovered views
2299
+ for (loc=0, len=nh.length; loc < len; loc++) {
2300
+ view = nh[loc];
2301
+ if (lh.indexOf(view) !== -1) {
2302
+ view.tryToPerform('mouseMoved', evt);
2303
+ } else {
2304
+ view.tryToPerform('mouseEntered', evt);
2305
+ }
2306
+ }
2307
+ // Keep track of the view that were last hovered
2308
+ this._lastHovered = nh;
2309
+ // also, if a mouseDownView exists, call the mouseDragged action, if
2310
+ // it exists.
2311
+ if (this._mouseDownView) {
2312
+ if(SC.browser.isIE){
2313
+ if (this._lastMouseDownX !== evt.clientX && this._lastMouseDownY !== evt.clientY) {
2314
+ this._mouseDownView.tryToPerform('mouseDragged', evt);
2315
+ }
2316
+ }
2317
+ else {
2318
+ this._mouseDownView.tryToPerform('mouseDragged', evt);
2319
+ }
2320
+ }
2321
+ }
2322
+ }, this);
2323
+ },
2082
2324
 
2083
- // first collect all the responding view starting with the
2084
- // target view from the given mouse move event
2085
- while (view && (view !== this)) {
2086
- nh.push(view);
2087
- view = view.get('nextResponder');
2088
- }
2089
- // next exit views that are no longer part of the
2090
- // responding chain
2091
- for (loc = 0, len = lh.length; loc < len; loc++) {
2092
- view = lh[loc];
2093
- if (nh.indexOf(view) === -1) {
2094
- view.tryToPerform('mouseExited', evt);
2095
- }
2096
- }
2097
- // finally, either perform mouse moved or mouse entered depending on
2098
- // whether a responding view was or was not part of the last
2099
- // hovered views
2100
- for (loc = 0, len = nh.length; loc < len; loc++) {
2101
- view = nh[loc];
2102
- if (lh.indexOf(view) !== -1) {
2103
- view.tryToPerform('mouseMoved', evt);
2104
- } else {
2105
- view.tryToPerform('mouseEntered', evt);
2106
- }
2325
+ // These event handlers prevent default file handling, and enable the dataDrag API.
2326
+ /** @private The dragenter event comes from the browser when a data-ful drag enters any element. */
2327
+ dragenter: function(evt) {
2328
+ SC.run(function() { this._dragenter(evt); }, this);
2329
+ },
2330
+ /** @private */
2331
+ _dragenter: function(evt) {
2332
+ if (!this._dragCounter) {
2333
+ this._dragCounter = 1;
2334
+ }
2335
+ else this._dragCounter++;
2336
+ return this._dragover(evt);
2337
+ },
2338
+ /** @private The dragleave event comes from the browser when a data-ful drag leaves any element. */
2339
+ dragleave: function(evt) {
2340
+ SC.run(function() { this._dragleave(evt); }, this);
2341
+ },
2342
+ /** @private */
2343
+ _dragleave: function(evt) {
2344
+ this._dragCounter--;
2345
+ var ret = this._dragover(evt);
2346
+ return ret;
2347
+ },
2348
+ /** @private
2349
+ Dragleave doesn't fire reliably in all browsers, so this method forces it (scheduled below). Note
2350
+ that, being scheduled via SC.Timer, this method is already in a run loop.
2351
+ */
2352
+ _forceDragLeave: function() {
2353
+ // Give it another runloop to ensure that we're not in the middle of a drag.
2354
+ this.invokeLast(function() {
2355
+ if (this._dragCounter === 0) return;
2356
+ this._dragCounter = 0;
2357
+ var evt = this._lastDraggedEvt;
2358
+ this._dragover(evt);
2359
+ });
2360
+ },
2361
+ /** @private This event fires continuously while the dataful drag is over the document. */
2362
+ dragover: function(evt) {
2363
+ SC.run(function() { this._dragover(evt); }, this);
2364
+ },
2365
+ /** @private */
2366
+ _dragover: function(evt) {
2367
+ // If it's a file being dragged, prevent the default (leaving the app and opening the file).
2368
+ if (evt.dataTransfer.types && (evt.dataTransfer.types.contains('Files') || evt.dataTransfer.types.contains('text/uri-list'))) {
2369
+ evt.preventDefault();
2370
+ evt.stopPropagation();
2371
+ // Set the default drag effect to 'none'. Views may reverse this if they wish.
2372
+ evt.dataTransfer.dropEffect = 'none';
2373
+ }
2374
+
2375
+ // Walk the responder chain, alerting anyone that would like to know.
2376
+ var ld = this._lastDraggedOver || [], nd = [], loc, len,
2377
+ view = this.targetViewForEvent(evt);
2378
+
2379
+ // Build the responder chain, starting with the view's target and (presumably) moving
2380
+ // up through parentViews to the pane.
2381
+ while (view && (view !== this)) {
2382
+ nd.push(view);
2383
+ view = view.get('nextResponder');
2384
+ }
2385
+
2386
+ // Invalidate the force-drag-leave timer, if we have one set up.
2387
+ if (this._dragLeaveTimer) this._dragLeaveTimer.invalidate();
2388
+
2389
+ // If this is our final drag event then we've left the document and everybody gets a
2390
+ // dataDragExited.
2391
+ if (this._dragCounter === 0) {
2392
+ for (loc = 0, len = nd.length; loc < len; loc++) {
2393
+ view = nd[loc];
2394
+ view.tryToPerform('dataDragExited', evt);
2395
+ }
2396
+ this._lastDraggedOver = this._lastDraggedEvt = this._dragLeaveTimer = null;
2397
+ }
2398
+ // Otherwise, we process the responder chain normally, ignoring dragleaves.
2399
+ // (We skip dragleave events because they are sent after the adjacent dragenter event; checking
2400
+ // through both stacks would result in views being exited, re-entered and re-exited each time.
2401
+ // As a consequence, views are left ignorant of a very small number of dragleave events; those
2402
+ // shouldn't end up being the crucial just-before-drop events, though, so they should be of no
2403
+ // consequence.)
2404
+ else if (evt.type !== 'dragleave') {
2405
+ // First, exit views that are no longer part of the responder chain, child to parent.
2406
+ for (loc = 0, len = ld.length; loc < len; loc++) {
2407
+ view = ld[loc];
2408
+ if (nd.indexOf(view) === -1) {
2409
+ view.tryToPerform('dataDragExited', evt);
2107
2410
  }
2108
- // Keep track of the view that were last hovered
2109
- this._lastHovered = nh;
2110
- // also, if a mouseDownView exists, call the mouseDragged action, if
2111
- // it exists.
2112
- if (this._mouseDownView) {
2113
- if (SC.browser.isIE) {
2114
- if (this._lastMouseDownX !== evt.clientX && this._lastMouseDownY !== evt.clientY) {
2115
- this._mouseDownView.tryToPerform('mouseDragged', evt);
2116
- }
2117
- }
2118
- else {
2119
- this._mouseDownView.tryToPerform('mouseDragged', evt);
2120
- }
2411
+ }
2412
+ // Next, enter views that have just joined the responder chain, parent to child.
2413
+ for (loc = nd.length - 1; loc >= 0; loc--) {
2414
+ view = nd[loc];
2415
+ if (ld.indexOf(view) === -1) {
2416
+ view.tryToPerform('dataDragEntered', evt);
2121
2417
  }
2122
2418
  }
2123
- }, this);
2419
+ // Finally, send hover events to everybody.
2420
+ for (loc = 0, len = nd.length; loc < len; loc++) {
2421
+ view = nd[loc];
2422
+ view.tryToPerform('dataDragHovered', evt);
2423
+ }
2424
+ this._lastDraggedOver = nd;
2425
+ this._lastDraggedEvt = evt;
2426
+ // For browsers that don't reliably call a dragleave for every dragenter, we have a timer fallback.
2427
+ this._dragLeaveTimer = SC.Timer.schedule({ target: this, action: '_forceDragLeave', interval: 300 });
2428
+ }
2429
+ },
2430
+
2431
+ /** @private This event is called if the most recent dragover event returned with a non-"none" dropEffect. */
2432
+ drop: function(evt) {
2433
+ SC.run(function() { this._drop(evt); }, this);
2124
2434
  },
2435
+ /** @private */
2436
+ _drop: function(evt) {
2437
+ // If it's a file being dragged, prevent the default (leaving the app and opening the file).
2438
+ if (evt.dataTransfer.types && (evt.dataTransfer.types.contains('Files') || evt.dataTransfer.types.contains('text/uri-list'))) {
2439
+ evt.preventDefault();
2440
+ evt.stopPropagation();
2441
+ // Set the default drag effect to 'none'. Views may reverse this if they wish.
2442
+ evt.dataTransfer.dropEffect = 'none';
2443
+ }
2444
+
2445
+ // Bubble up the responder chain until we have a successful responder.
2446
+ var ld = this._lastDraggedOver || [], nd = [], loc, len,
2447
+ view = this.targetViewForEvent(evt);
2448
+
2449
+ // First collect all the responding view starting with the target view from the given drag event.
2450
+ while (view && (view !== this)) {
2451
+ nd.push(view);
2452
+ view = view.get('nextResponder');
2453
+ }
2454
+ // Next, exit views that are no longer part of the responding chain. (This avoids the pixel-wide
2455
+ // edge case where a drop event fires on a new view without a final dragover event.)
2456
+ for (loc = 0, len = ld.length; loc < len; loc++) {
2457
+ view = ld[loc];
2458
+ if (nd.indexOf(view) === -1) {
2459
+ view.tryToPerform('dataDragExited', evt);
2460
+ }
2461
+ }
2462
+ // Next, bubble the drop event itself until we find someone that successfully responds.
2463
+ for (loc = 0, len = nd.length; loc < len; loc++) {
2464
+ view = nd[loc];
2465
+ if (view.tryToPerform('dataDragDropped', evt)) break;
2466
+ }
2467
+ // Finally, notify all interested views that the drag is dead and gone.
2468
+ for (loc = 0, len = nd.length; loc < len; loc++) {
2469
+ view = nd[loc];
2470
+ view.tryToPerform('dataDragExited', evt);
2471
+ }
2472
+
2473
+ // Reset caches and counters.
2474
+ this._lastDraggedOver = null;
2475
+ this._lastDraggedAt = null;
2476
+ this._dragCounter = 0;
2477
+ if (this._dragLeaveTimer) this._dragLeaveTimer.invalidate();
2478
+ this._dragLeaveTimer = null;
2479
+ },
2480
+
2125
2481
 
2126
2482
  // these methods are used to prevent unnecessary text-selection in IE,
2127
2483
  // there could be some more work to improve this behavior and make it
@@ -2130,22 +2486,22 @@ SC.RootResponder = SC.Object.extend(
2130
2486
 
2131
2487
  _mouseCanDrag: YES,
2132
2488
 
2133
- selectstart: function (evt) {
2489
+ selectstart: function(evt) {
2134
2490
  var targetView = this.targetViewForEvent(evt),
2135
2491
  result = this.sendEvent('selectStart', evt, targetView);
2136
2492
 
2137
2493
  // If the target view implements mouseDragged, then we want to ignore the
2138
2494
  // 'selectstart' event.
2139
2495
  if (targetView && targetView.respondsTo('mouseDragged')) {
2140
- return (result !== null ? YES : NO) && !this._mouseCanDrag;
2496
+ return (result !==null ? YES: NO) && !this._mouseCanDrag;
2141
2497
  } else {
2142
- return (result !== null ? YES : NO);
2498
+ return (result !==null ? YES: NO);
2143
2499
  }
2144
2500
  },
2145
2501
 
2146
- drag: function () { return false; },
2502
+ drag: function() { return false; },
2147
2503
 
2148
- contextmenu: function (evt) {
2504
+ contextmenu: function(evt) {
2149
2505
  var view = this.targetViewForEvent(evt),
2150
2506
  ret;
2151
2507
 
@@ -2162,179 +2518,44 @@ SC.RootResponder = SC.Object.extend(
2162
2518
 
2163
2519
  /* @private Handler for animationstart events. */
2164
2520
  animationstart: function (evt) {
2165
- var view = this.targetViewForEvent(evt);
2166
- this.sendEvent('animationDidStart', evt, view);
2521
+ var view = this.targetViewForEvent(evt) ;
2522
+ this.sendEvent('animationDidStart', evt, view) ;
2167
2523
 
2168
2524
  return view ? evt.hasCustomEventHandling : YES;
2169
2525
  },
2170
2526
 
2171
2527
  /* @private Handler for animationiteration events. */
2172
2528
  animationiteration: function (evt) {
2173
- var view = this.targetViewForEvent(evt);
2174
- this.sendEvent('animationDidIterate', evt, view);
2529
+ var view = this.targetViewForEvent(evt) ;
2530
+ this.sendEvent('animationDidIterate', evt, view) ;
2175
2531
 
2176
2532
  return view ? evt.hasCustomEventHandling : YES;
2177
2533
  },
2178
2534
 
2179
2535
  /* @private Handler for animationend events. */
2180
2536
  animationend: function (evt) {
2181
- var view = this.targetViewForEvent(evt);
2182
- this.sendEvent('animationDidEnd', evt, view);
2537
+ var view = this.targetViewForEvent(evt) ;
2538
+ this.sendEvent('animationDidEnd', evt, view) ;
2183
2539
 
2184
2540
  return view ? evt.hasCustomEventHandling : YES;
2185
2541
  },
2186
2542
 
2187
2543
  /* @private Handler for transitionend events. */
2188
2544
  transitionend: function (evt) {
2189
- var view = this.targetViewForEvent(evt);
2190
- this.sendEvent('transitionDidEnd', evt, view);
2545
+ var view = this.targetViewForEvent(evt) ;
2546
+ this.sendEvent('transitionDidEnd', evt, view) ;
2191
2547
 
2192
2548
  return view ? evt.hasCustomEventHandling : YES;
2193
2549
  }
2194
2550
 
2195
2551
  });
2196
2552
 
2197
- /**
2198
- @class SC.Touch
2199
- Represents a touch.
2200
-
2201
- Views receive touchStart and touchEnd.
2202
- */
2203
- SC.Touch = function (touch, touchContext) {
2204
- // get the raw target view (we'll refine later)
2205
- this.touchContext = touchContext;
2206
- this.identifier = touch.identifier; // for now, our internal id is WebKit's id.
2207
-
2208
- var target = touch.target, targetView;
2209
- if (target && SC.$(target).hasClass("touch-intercept")) {
2210
- touch.target.style.webkitTransform = "translate3d(0px,-5000px,0px)";
2211
- target = document.elementFromPoint(touch.pageX, touch.pageY);
2212
- if (target) targetView = SC.$(target).view()[0];
2213
-
2214
- this.hidesTouchIntercept = NO;
2215
- if (target.tagName === "INPUT") {
2216
- this.hidesTouchIntercept = touch.target;
2217
- } else {
2218
- touch.target.style.webkitTransform = "translate3d(0px,0px,0px)";
2219
- }
2220
- } else {
2221
- targetView = touch.target ? SC.$(touch.target).view()[0] : null;
2222
- }
2223
- this.targetView = targetView;
2224
- this.target = target;
2225
- this.hasEnded = NO;
2226
- this.type = touch.type;
2227
- this.clickCount = 1;
2228
-
2229
- this.view = undefined;
2230
- this.touchResponder = this.nextTouchResponder = undefined;
2231
- this.touchResponders = [];
2232
-
2233
- this.startX = this.pageX = touch.pageX;
2234
- this.startY = this.pageY = touch.pageY;
2235
- this.clientX = touch.clientX;
2236
- this.clientY = touch.clientY;
2237
- this.screenX = touch.screenX;
2238
- this.screenY = touch.screenY;
2239
- };
2240
-
2241
- SC.Touch.prototype = {
2242
- /**@scope SC.Touch.prototype*/
2243
-
2244
- unhideTouchIntercept: function () {
2245
- var intercept = this.hidesTouchIntercept;
2246
- if (intercept) {
2247
- setTimeout(function () { intercept.style.webkitTransform = "translate3d(0px,0px,0px)"; }, 500);
2248
- }
2249
- },
2250
-
2251
- /**
2252
- Indicates that you want to allow the normal default behavior. Sets
2253
- the hasCustomEventHandling property to YES but does not cancel the event.
2254
- */
2255
- allowDefault: function () {
2256
- if (this.event) this.event.hasCustomEventHandling = YES;
2257
- },
2258
-
2259
- /**
2260
- If the touch is associated with an event, prevents default action on the event.
2261
- */
2262
- preventDefault: function () {
2263
- if (this.event) this.event.preventDefault();
2264
- },
2265
-
2266
- stopPropagation: function () {
2267
- if (this.event) this.event.stopPropagation();
2268
- },
2269
-
2270
- stop: function () {
2271
- if (this.event) this.event.stop();
2272
- },
2273
-
2274
- /**
2275
- Removes from and calls touchEnd on the touch responder.
2276
- */
2277
- end: function () {
2278
- this.touchContext.endTouch(this);
2279
- },
2280
-
2281
- /**
2282
- Changes the touch responder for the touch. If shouldStack === YES,
2283
- the current responder will be saved so that the next responder may
2284
- return to it.
2285
- */
2286
- makeTouchResponder: function (responder, shouldStack, upViewChain) {
2287
- this.touchContext.makeTouchResponder(this, responder, shouldStack, upViewChain);
2288
- },
2289
-
2290
-
2291
- /**
2292
- Captures, or recaptures, the touch. This works from the touch's raw target view
2293
- up to the startingPoint, and finds either a view that returns YES to captureTouch() or
2294
- touchStart().
2295
- */
2296
- captureTouch: function (startingPoint, shouldStack) {
2297
- this.touchContext.captureTouch(this, startingPoint, shouldStack);
2298
- },
2299
-
2300
- /**
2301
- Returns all touches for a specified view. Put as a convenience on the touch itself; this method
2302
- is also available on the event.
2303
- */
2304
- touchesForView: function (view) {
2305
- return this.touchContext.touchesForView(view);
2306
- },
2307
-
2308
- /**
2309
- Same as touchesForView, but sounds better for responders.
2310
- */
2311
- touchesForResponder: function (responder) {
2312
- return this.touchContext.touchesForView(responder);
2313
- },
2314
-
2315
- /**
2316
- Returns average data--x, y, and d (distance)--for the touches owned by the supplied view.
2317
-
2318
- addSelf adds this touch to the set being considered. This is useful from touchStart. If
2319
- you use it from anywhere else, it will make this touch be used twice--so use caution.
2320
- */
2321
- averagedTouchesForView: function (view, addSelf) {
2322
- return this.touchContext.averagedTouchesForView(view, (addSelf ? this : null));
2323
- }
2324
- };
2325
-
2326
- SC.mixin(SC.Touch, {
2327
- create: function (touch, touchContext) {
2328
- return new SC.Touch(touch, touchContext);
2329
- }
2330
- });
2331
-
2332
2553
  /*
2333
2554
  Invoked when the document is ready, but before main is called. Creates
2334
2555
  an instance and sets up event listeners as needed.
2335
2556
  */
2336
- SC.ready(SC.RootResponder, SC.RootResponder.ready = function () {
2557
+ SC.ready(SC.RootResponder, SC.RootResponder.ready = function() {
2337
2558
  var r;
2338
- r = SC.RootResponder.responder = SC.RootResponder.create();
2339
- r.setup();
2559
+ r = SC.RootResponder.responder = SC.RootResponder.create() ;
2560
+ r.setup() ;
2340
2561
  });