sproutit-sproutcore 1.0.0.20090407205609 → 1.0.0.20090408130025

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (574) hide show
  1. data/frameworks/sproutcore/Buildfile +63 -0
  2. data/frameworks/sproutcore/HISTORY +682 -0
  3. data/frameworks/sproutcore/README +22 -0
  4. data/frameworks/sproutcore/apps/sc_jsdoc/controllers/docs.js +149 -0
  5. data/frameworks/sproutcore/apps/sc_jsdoc/core.js +16 -0
  6. data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/body.css +17 -0
  7. data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/body.js +99 -0
  8. data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/images/sproutcore-logo.png +0 -0
  9. data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/strings.js +15 -0
  10. data/frameworks/sproutcore/apps/sc_jsdoc/main.js +27 -0
  11. data/frameworks/sproutcore/apps/sc_jsdoc/models/doc.js +21 -0
  12. data/frameworks/sproutcore/apps/sc_qunit/controllers/runner.js +209 -0
  13. data/frameworks/sproutcore/apps/sc_qunit/core.js +16 -0
  14. data/frameworks/sproutcore/apps/sc_qunit/english.lproj/body.css +17 -0
  15. data/frameworks/sproutcore/apps/sc_qunit/english.lproj/body.js +107 -0
  16. data/frameworks/sproutcore/apps/sc_qunit/english.lproj/images/sproutcore-logo.png +0 -0
  17. data/frameworks/sproutcore/apps/sc_qunit/english.lproj/strings.js +15 -0
  18. data/frameworks/sproutcore/apps/sc_qunit/main.js +18 -0
  19. data/frameworks/sproutcore/apps/sc_qunit/models/test.js +24 -0
  20. data/frameworks/sproutcore/apps/sc_qunit/views/test_iframe.js +52 -0
  21. data/frameworks/sproutcore/apps/tests/controllers/targets.js +47 -0
  22. data/frameworks/sproutcore/apps/tests/controllers/test.js +20 -0
  23. data/frameworks/sproutcore/apps/tests/controllers/tests.js +38 -0
  24. data/frameworks/sproutcore/apps/tests/core.js +35 -0
  25. data/frameworks/sproutcore/apps/tests/english.lproj/loading.rhtml +9 -0
  26. data/frameworks/sproutcore/apps/tests/english.lproj/main_page.css +19 -0
  27. data/frameworks/sproutcore/apps/tests/english.lproj/main_page.js +86 -0
  28. data/frameworks/sproutcore/apps/tests/english.lproj/strings.js +17 -0
  29. data/frameworks/sproutcore/apps/tests/fixtures/target.js +43 -0
  30. data/frameworks/sproutcore/apps/tests/fixtures/test.js +43 -0
  31. data/frameworks/sproutcore/apps/tests/main.js +39 -0
  32. data/frameworks/sproutcore/apps/tests/models/target.js +49 -0
  33. data/frameworks/sproutcore/apps/tests/models/test.js +20 -0
  34. data/frameworks/sproutcore/apps/tests/tests/controllers/targets.js +15 -0
  35. data/frameworks/sproutcore/apps/tests/tests/controllers/test.js +15 -0
  36. data/frameworks/sproutcore/apps/tests/tests/controllers/tests.js +15 -0
  37. data/frameworks/sproutcore/apps/tests/tests/models/target.js +15 -0
  38. data/frameworks/sproutcore/apps/tests/tests/models/test.js +15 -0
  39. data/frameworks/sproutcore/apps/welcome/core.js +23 -0
  40. data/frameworks/sproutcore/apps/welcome/english.lproj/loading.rhtml +8 -0
  41. data/frameworks/sproutcore/apps/welcome/english.lproj/main_page.js +43 -0
  42. data/frameworks/sproutcore/apps/welcome/english.lproj/strings.js +15 -0
  43. data/frameworks/sproutcore/apps/welcome/main.js +36 -0
  44. data/frameworks/sproutcore/design/Design Charts.graffle +15819 -0
  45. data/frameworks/sproutcore/design/Record State Table.numbers +0 -0
  46. data/frameworks/sproutcore/frameworks/datastore/core.js +14 -0
  47. data/frameworks/sproutcore/frameworks/datastore/data_sources/cascade.js +113 -0
  48. data/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +256 -0
  49. data/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +196 -0
  50. data/frameworks/sproutcore/frameworks/datastore/debug/json.js +71 -0
  51. data/frameworks/sproutcore/frameworks/datastore/debug/standard_setup.js +96 -0
  52. data/frameworks/sproutcore/frameworks/datastore/fixtures/author_fixtures.js +2503 -0
  53. data/frameworks/sproutcore/frameworks/datastore/fixtures/sample.js +17 -0
  54. data/frameworks/sproutcore/frameworks/datastore/models/fetched_attribute.js +92 -0
  55. data/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +38 -0
  56. data/frameworks/sproutcore/frameworks/datastore/models/record.js +430 -0
  57. data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +361 -0
  58. data/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +305 -0
  59. data/frameworks/sproutcore/frameworks/datastore/system/query.js +128 -0
  60. data/frameworks/sproutcore/frameworks/datastore/system/record_array.js +149 -0
  61. data/frameworks/sproutcore/frameworks/datastore/system/store.js +1689 -0
  62. data/frameworks/sproutcore/frameworks/datastore/tests/data_sources/fixtures.js +86 -0
  63. data/frameworks/sproutcore/frameworks/datastore/tests/integration/contact_model.js +114 -0
  64. data/frameworks/sproutcore/frameworks/datastore/tests/integration/mail_model.js +91 -0
  65. data/frameworks/sproutcore/frameworks/datastore/tests/integration/test_runner_model.js +56 -0
  66. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/destroy.js +73 -0
  67. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/readAttribute.js +48 -0
  68. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/refresh.js +42 -0
  69. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/storeDidChangeProperties.js +138 -0
  70. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/unknownProperty.js +46 -0
  71. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +71 -0
  72. data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +115 -0
  73. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/chain.js +40 -0
  74. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChanges.js +116 -0
  75. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChangesFromNestedStore.js +135 -0
  76. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/dataHashDidChange.js +110 -0
  77. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/discardChanges.js +99 -0
  78. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readDataHash.js +180 -0
  79. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readEditableDataHash.js +126 -0
  80. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/removeDataHash.js +163 -0
  81. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/writeDataHash.js +166 -0
  82. data/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +175 -0
  83. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/cancelRecord.js +54 -0
  84. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +126 -0
  85. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +127 -0
  86. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/createRecord.js +57 -0
  87. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataHashDidChange.js +78 -0
  88. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +247 -0
  89. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/destroyRecord.js +106 -0
  90. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/init.js +21 -0
  91. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushChanges.js +61 -0
  92. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/readDataHash.js +74 -0
  93. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/readEditableDataHash.js +74 -0
  94. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/recordDidChange.js +74 -0
  95. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/removeDataHash.js +144 -0
  96. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/retrieveRecord.js +137 -0
  97. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/writeDataHash.js +130 -0
  98. data/frameworks/sproutcore/frameworks/debug/core.js +1 -0
  99. data/frameworks/sproutcore/frameworks/deprecated/core.js +61 -0
  100. data/frameworks/sproutcore/frameworks/deprecated/lib/button_views.rb +330 -0
  101. data/frameworks/sproutcore/frameworks/deprecated/lib/collection_view.rb +83 -0
  102. data/frameworks/sproutcore/frameworks/deprecated/lib/core_views.rb +326 -0
  103. data/frameworks/sproutcore/frameworks/deprecated/lib/form_views.rb +253 -0
  104. data/frameworks/sproutcore/frameworks/deprecated/lib/index.rhtml +75 -0
  105. data/frameworks/sproutcore/frameworks/deprecated/lib/menu_views.rb +93 -0
  106. data/frameworks/sproutcore/frameworks/deprecated/server/rails_server.js +80 -0
  107. data/frameworks/sproutcore/frameworks/deprecated/server/rest_server.js +178 -0
  108. data/frameworks/sproutcore/frameworks/deprecated/server/server.js +674 -0
  109. data/frameworks/sproutcore/frameworks/deprecated/system/animator.js +679 -0
  110. data/frameworks/sproutcore/frameworks/deprecated/system/binding.js +36 -0
  111. data/frameworks/sproutcore/frameworks/deprecated/system/browser.js +77 -0
  112. data/frameworks/sproutcore/frameworks/deprecated/system/classic_responder.js +314 -0
  113. data/frameworks/sproutcore/frameworks/deprecated/system/event.js +60 -0
  114. data/frameworks/sproutcore/frameworks/deprecated/system/globals.js +20 -0
  115. data/frameworks/sproutcore/frameworks/deprecated/system/misc.js +60 -0
  116. data/frameworks/sproutcore/frameworks/deprecated/system/node_descriptor.js +72 -0
  117. data/frameworks/sproutcore/frameworks/deprecated/system/object.js +124 -0
  118. data/frameworks/sproutcore/frameworks/deprecated/system/path_module.js +433 -0
  119. data/frameworks/sproutcore/frameworks/deprecated/system/string.js +109 -0
  120. data/frameworks/sproutcore/frameworks/deprecated/tests/application/application.rhtml +125 -0
  121. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/clippingFrame.rhtml +401 -0
  122. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/frame.rhtml +357 -0
  123. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/isVisibleInWindow.rhtml +147 -0
  124. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/base.rhtml +298 -0
  125. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/incremental_rendering.rhtml +260 -0
  126. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/source_list_rendering.rhtml +143 -0
  127. data/frameworks/sproutcore/frameworks/deprecated/tests/views/popup_button.rhtml +128 -0
  128. data/frameworks/sproutcore/frameworks/deprecated/tests/views/text_field.rhtml +37 -0
  129. data/frameworks/sproutcore/frameworks/deprecated/views/collection.js +24 -0
  130. data/frameworks/sproutcore/frameworks/designer/coders/design.js +30 -0
  131. data/frameworks/sproutcore/frameworks/designer/coders/localization.js +28 -0
  132. data/frameworks/sproutcore/frameworks/designer/coders/object.js +347 -0
  133. data/frameworks/sproutcore/frameworks/designer/controllers/page_design.js +102 -0
  134. data/frameworks/sproutcore/frameworks/designer/css/css_rule.js +22 -0
  135. data/frameworks/sproutcore/frameworks/designer/css/css_style.js +29 -0
  136. data/frameworks/sproutcore/frameworks/designer/css/css_style_sheet.js +201 -0
  137. data/frameworks/sproutcore/frameworks/designer/ext/page.js +88 -0
  138. data/frameworks/sproutcore/frameworks/designer/ext/view.js +40 -0
  139. data/frameworks/sproutcore/frameworks/designer/views/controls/button.js +18 -0
  140. data/frameworks/sproutcore/frameworks/designer/views/designer.js +553 -0
  141. data/frameworks/sproutcore/frameworks/designer/views/label.js +17 -0
  142. data/frameworks/sproutcore/frameworks/designer/views/mixins/button.js +13 -0
  143. data/frameworks/sproutcore/frameworks/designer/views/tab.js +17 -0
  144. data/frameworks/sproutcore/frameworks/desktop/core.js +6 -0
  145. data/frameworks/sproutcore/frameworks/desktop/debug/drag.js +41 -0
  146. data/frameworks/sproutcore/frameworks/desktop/english.lproj/alert.css +56 -0
  147. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/a_sample_image.jpg +0 -0
  148. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/apple-logo1.jpeg +0 -0
  149. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/iframe.html +23 -0
  150. data/frameworks/sproutcore/frameworks/desktop/english.lproj/disclosure.css +71 -0
  151. data/frameworks/sproutcore/frameworks/desktop/english.lproj/icons.css +943 -0
  152. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/blank.gif +0 -0
  153. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_222222.png +0 -0
  154. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_454545.png +0 -0
  155. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_888888.png +0 -0
  156. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_ffffff.png +0 -0
  157. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/shared.png +0 -0
  158. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/indicator.gif +0 -0
  159. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/panels/sprite-x.png +0 -0
  160. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/panels/sprite-y.png +0 -0
  161. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/sc-theme-sprite.png +0 -0
  162. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/000000.png +0 -0
  163. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/ffffff.png +0 -0
  164. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/sticky-note.png +0 -0
  165. data/frameworks/sproutcore/frameworks/desktop/english.lproj/list_item.css +156 -0
  166. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu.css +83 -0
  167. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +99 -0
  168. data/frameworks/sproutcore/frameworks/desktop/english.lproj/palette.css +3 -0
  169. data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +94 -0
  170. data/frameworks/sproutcore/frameworks/desktop/english.lproj/picker.css +39 -0
  171. data/frameworks/sproutcore/frameworks/desktop/english.lproj/progress.css +31 -0
  172. data/frameworks/sproutcore/frameworks/desktop/english.lproj/radio.css +10 -0
  173. data/frameworks/sproutcore/frameworks/desktop/english.lproj/scroller.css +26 -0
  174. data/frameworks/sproutcore/frameworks/desktop/english.lproj/segmented.css +141 -0
  175. data/frameworks/sproutcore/frameworks/desktop/english.lproj/separator.css +19 -0
  176. data/frameworks/sproutcore/frameworks/desktop/english.lproj/slider.css +57 -0
  177. data/frameworks/sproutcore/frameworks/desktop/english.lproj/split.css +70 -0
  178. data/frameworks/sproutcore/frameworks/desktop/english.lproj/split_divider.css +8 -0
  179. data/frameworks/sproutcore/frameworks/desktop/english.lproj/strings.js +14 -0
  180. data/frameworks/sproutcore/frameworks/desktop/english.lproj/tab.css +12 -0
  181. data/frameworks/sproutcore/frameworks/desktop/english.lproj/text_field.css +29 -0
  182. data/frameworks/sproutcore/frameworks/desktop/english.lproj/toolbar.css +6 -0
  183. data/frameworks/sproutcore/frameworks/desktop/mixins/border.js +53 -0
  184. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_group.js +22 -0
  185. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_item.js +22 -0
  186. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +226 -0
  187. data/frameworks/sproutcore/frameworks/desktop/mixins/scrollable.js +247 -0
  188. data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +377 -0
  189. data/frameworks/sproutcore/frameworks/desktop/panes/menu.js +504 -0
  190. data/frameworks/sproutcore/frameworks/desktop/panes/modal.js +68 -0
  191. data/frameworks/sproutcore/frameworks/desktop/panes/palette.js +63 -0
  192. data/frameworks/sproutcore/frameworks/desktop/panes/panel.js +184 -0
  193. data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +402 -0
  194. data/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +46 -0
  195. data/frameworks/sproutcore/frameworks/desktop/protocols/drag_data_source.js +39 -0
  196. data/frameworks/sproutcore/frameworks/desktop/protocols/drag_source.js +81 -0
  197. data/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +175 -0
  198. data/frameworks/sproutcore/frameworks/desktop/protocols/responder.js +280 -0
  199. data/frameworks/sproutcore/frameworks/desktop/system/drag.js +721 -0
  200. data/frameworks/sproutcore/frameworks/desktop/system/key_bindings.js +40 -0
  201. data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +641 -0
  202. data/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +187 -0
  203. data/frameworks/sproutcore/frameworks/desktop/tests/integration/dialog.js +43 -0
  204. data/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/methods.js +10 -0
  205. data/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +152 -0
  206. data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/methods.js +10 -0
  207. data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +57 -0
  208. data/frameworks/sproutcore/frameworks/desktop/tests/panes/palette/methods.js +10 -0
  209. data/frameworks/sproutcore/frameworks/desktop/tests/panes/palette/ui.js +36 -0
  210. data/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/methods.js +10 -0
  211. data/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +40 -0
  212. data/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/methods.js +10 -0
  213. data/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +80 -0
  214. data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/methods.js +10 -0
  215. data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +38 -0
  216. data/frameworks/sproutcore/frameworks/desktop/tests/views/button/methods.js +45 -0
  217. data/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +140 -0
  218. data/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/methods.js +145 -0
  219. data/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/ui.js +99 -0
  220. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/methods.js +10 -0
  221. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selectPreviousItem.js +39 -0
  222. data/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/methods.js +10 -0
  223. data/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/ui.js +64 -0
  224. data/frameworks/sproutcore/frameworks/desktop/tests/views/grid/methods.js +10 -0
  225. data/frameworks/sproutcore/frameworks/desktop/tests/views/grid/ui.js +10 -0
  226. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/methods.js +10 -0
  227. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui.js +110 -0
  228. data/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +255 -0
  229. data/frameworks/sproutcore/frameworks/desktop/tests/views/menu_item/methods.js +10 -0
  230. data/frameworks/sproutcore/frameworks/desktop/tests/views/menu_item/ui.js +44 -0
  231. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/methods.js +128 -0
  232. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +240 -0
  233. data/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +113 -0
  234. data/frameworks/sproutcore/frameworks/desktop/tests/views/radio/ui.js +202 -0
  235. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +139 -0
  236. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +111 -0
  237. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroller/methods.js +63 -0
  238. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroller/ui.js +70 -0
  239. data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +94 -0
  240. data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +206 -0
  241. data/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/methods.js +81 -0
  242. data/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/ui.js +85 -0
  243. data/frameworks/sproutcore/frameworks/desktop/tests/views/separator.js +37 -0
  244. data/frameworks/sproutcore/frameworks/desktop/tests/views/source_list/methods.js +10 -0
  245. data/frameworks/sproutcore/frameworks/desktop/tests/views/source_list/ui.js +10 -0
  246. data/frameworks/sproutcore/frameworks/desktop/tests/views/split/methods.js +50 -0
  247. data/frameworks/sproutcore/frameworks/desktop/tests/views/split/ui.js +52 -0
  248. data/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +54 -0
  249. data/frameworks/sproutcore/frameworks/desktop/tests/views/tab/ui.js +88 -0
  250. data/frameworks/sproutcore/frameworks/desktop/tests/views/text_field/methods.js +76 -0
  251. data/frameworks/sproutcore/frameworks/desktop/tests/views/text_field/ui.js +198 -0
  252. data/frameworks/sproutcore/frameworks/desktop/tests/views/web/methods.js +10 -0
  253. data/frameworks/sproutcore/frameworks/desktop/tests/views/web/ui.js +110 -0
  254. data/frameworks/sproutcore/frameworks/desktop/views/button.js +320 -0
  255. data/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +98 -0
  256. data/frameworks/sproutcore/frameworks/desktop/views/collection.js +2141 -0
  257. data/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +44 -0
  258. data/frameworks/sproutcore/frameworks/desktop/views/form.js +595 -0
  259. data/frameworks/sproutcore/frameworks/desktop/views/grid.js +199 -0
  260. data/frameworks/sproutcore/frameworks/desktop/views/list.js +706 -0
  261. data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +523 -0
  262. data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +437 -0
  263. data/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +62 -0
  264. data/frameworks/sproutcore/frameworks/desktop/views/progress.js +207 -0
  265. data/frameworks/sproutcore/frameworks/desktop/views/radio.js +332 -0
  266. data/frameworks/sproutcore/frameworks/desktop/views/scene.js +56 -0
  267. data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +648 -0
  268. data/frameworks/sproutcore/frameworks/desktop/views/scroller.js +203 -0
  269. data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +509 -0
  270. data/frameworks/sproutcore/frameworks/desktop/views/select_field.js +292 -0
  271. data/frameworks/sproutcore/frameworks/desktop/views/separator.js +37 -0
  272. data/frameworks/sproutcore/frameworks/desktop/views/slider.js +178 -0
  273. data/frameworks/sproutcore/frameworks/desktop/views/source_list.js +1117 -0
  274. data/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +169 -0
  275. data/frameworks/sproutcore/frameworks/desktop/views/split.js +651 -0
  276. data/frameworks/sproutcore/frameworks/desktop/views/split_divider.js +55 -0
  277. data/frameworks/sproutcore/frameworks/desktop/views/tab.js +190 -0
  278. data/frameworks/sproutcore/frameworks/desktop/views/text_field.js +233 -0
  279. data/frameworks/sproutcore/frameworks/desktop/views/thumb.js +49 -0
  280. data/frameworks/sproutcore/frameworks/desktop/views/toolbar.js +49 -0
  281. data/frameworks/sproutcore/frameworks/desktop/views/web.js +86 -0
  282. data/frameworks/sproutcore/frameworks/foundation/TESTING +46 -0
  283. data/frameworks/sproutcore/frameworks/foundation/controllers/array.js +490 -0
  284. data/frameworks/sproutcore/frameworks/foundation/controllers/controller.js +317 -0
  285. data/frameworks/sproutcore/frameworks/foundation/controllers/object.js +421 -0
  286. data/frameworks/sproutcore/frameworks/foundation/core.js +111 -0
  287. data/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +172 -0
  288. data/frameworks/sproutcore/frameworks/foundation/english.lproj/blank.gif +0 -0
  289. data/frameworks/sproutcore/frameworks/foundation/english.lproj/bootstrap.rhtml +53 -0
  290. data/frameworks/sproutcore/frameworks/foundation/english.lproj/button_view.css +55 -0
  291. data/frameworks/sproutcore/frameworks/foundation/english.lproj/core.css +5 -0
  292. data/frameworks/sproutcore/frameworks/foundation/english.lproj/debug/control-test-pane.css +8 -0
  293. data/frameworks/sproutcore/frameworks/foundation/english.lproj/images/sproutcore-logo.png +0 -0
  294. data/frameworks/sproutcore/frameworks/foundation/english.lproj/static_layout.css +5 -0
  295. data/frameworks/sproutcore/frameworks/foundation/english.lproj/view.css +40 -0
  296. data/frameworks/sproutcore/frameworks/foundation/ext/object.js +81 -0
  297. data/frameworks/sproutcore/frameworks/foundation/ext/run_loop.js +158 -0
  298. data/frameworks/sproutcore/frameworks/foundation/fixtures/file_exists.json +1 -0
  299. data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +291 -0
  300. data/frameworks/sproutcore/frameworks/foundation/mixins/content_display.js +88 -0
  301. data/frameworks/sproutcore/frameworks/foundation/mixins/control.js +352 -0
  302. data/frameworks/sproutcore/frameworks/foundation/mixins/editable.js +146 -0
  303. data/frameworks/sproutcore/frameworks/foundation/mixins/responder.js +156 -0
  304. data/frameworks/sproutcore/frameworks/foundation/mixins/selection_support.js +154 -0
  305. data/frameworks/sproutcore/frameworks/foundation/mixins/static_layout.js +101 -0
  306. data/frameworks/sproutcore/frameworks/foundation/mixins/string.js +237 -0
  307. data/frameworks/sproutcore/frameworks/foundation/mixins/validatable.js +176 -0
  308. data/frameworks/sproutcore/frameworks/foundation/panes/main.js +47 -0
  309. data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +555 -0
  310. data/frameworks/sproutcore/frameworks/foundation/protocols/inline_editor_delegate.js +84 -0
  311. data/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +244 -0
  312. data/frameworks/sproutcore/frameworks/foundation/system/browser.js +64 -0
  313. data/frameworks/sproutcore/frameworks/foundation/system/builder.js +210 -0
  314. data/frameworks/sproutcore/frameworks/foundation/system/core_query.js +2015 -0
  315. data/frameworks/sproutcore/frameworks/foundation/system/cursor.js +129 -0
  316. data/frameworks/sproutcore/frameworks/foundation/system/error.js +93 -0
  317. data/frameworks/sproutcore/frameworks/foundation/system/event.js +817 -0
  318. data/frameworks/sproutcore/frameworks/foundation/system/image_cache.js +433 -0
  319. data/frameworks/sproutcore/frameworks/foundation/system/json.js +440 -0
  320. data/frameworks/sproutcore/frameworks/foundation/system/locale.js +288 -0
  321. data/frameworks/sproutcore/frameworks/foundation/system/page.js +106 -0
  322. data/frameworks/sproutcore/frameworks/foundation/system/ready.js +189 -0
  323. data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +865 -0
  324. data/frameworks/sproutcore/frameworks/foundation/system/request.js +255 -0
  325. data/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +368 -0
  326. data/frameworks/sproutcore/frameworks/foundation/system/routes.js +446 -0
  327. data/frameworks/sproutcore/frameworks/foundation/system/time.js +478 -0
  328. data/frameworks/sproutcore/frameworks/foundation/system/timer.js +549 -0
  329. data/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +158 -0
  330. data/frameworks/sproutcore/frameworks/foundation/system/utils.js +330 -0
  331. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array.js +118 -0
  332. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/controller.js +268 -0
  333. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object.js +433 -0
  334. data/frameworks/sproutcore/frameworks/foundation/tests/debug/control_test_pane/methods.js +10 -0
  335. data/frameworks/sproutcore/frameworks/foundation/tests/debug/control_test_pane/ui.js +113 -0
  336. data/frameworks/sproutcore/frameworks/foundation/tests/integration/creating_views.js +113 -0
  337. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/content.js +195 -0
  338. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/displayProperties.js +89 -0
  339. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/control/content.js +168 -0
  340. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/control/displayProperties.js +89 -0
  341. data/frameworks/sproutcore/frameworks/foundation/tests/system/builder.js +42 -0
  342. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +1323 -0
  343. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_dimensions.js +387 -0
  344. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_selector.js +405 -0
  345. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/setClass.js +49 -0
  346. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/within.js +66 -0
  347. data/frameworks/sproutcore/frameworks/foundation/tests/system/error.js +41 -0
  348. data/frameworks/sproutcore/frameworks/foundation/tests/system/json.js +14 -0
  349. data/frameworks/sproutcore/frameworks/foundation/tests/system/locale.js +128 -0
  350. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/begin.js +47 -0
  351. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/element.js +44 -0
  352. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/end.js +119 -0
  353. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/get.js +51 -0
  354. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_attr.js +50 -0
  355. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_basic.js +28 -0
  356. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_className.js +179 -0
  357. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_style.js +100 -0
  358. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/init.js +55 -0
  359. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/join.js +28 -0
  360. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/push_text.js +74 -0
  361. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/tag.js +45 -0
  362. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/update.js +205 -0
  363. data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +89 -0
  364. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/makeKeyPane.js +124 -0
  365. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/makeMainPane.js +68 -0
  366. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/root_responder.js +97 -0
  367. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/targetForAction.js +238 -0
  368. data/frameworks/sproutcore/frameworks/foundation/tests/system/routes.js +33 -0
  369. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/invalidate.js +38 -0
  370. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/invokeLater.js +201 -0
  371. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/isPaused.js +71 -0
  372. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/performAction.js +67 -0
  373. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/schedule.js +170 -0
  374. data/frameworks/sproutcore/frameworks/foundation/tests/system/user_defaults.js +27 -0
  375. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/normalizeURL.js +18 -0
  376. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/range.js +62 -0
  377. data/frameworks/sproutcore/frameworks/foundation/tests/validators/credit_card.js +35 -0
  378. data/frameworks/sproutcore/frameworks/foundation/tests/validators/date.js +21 -0
  379. data/frameworks/sproutcore/frameworks/foundation/tests/validators/number.js +47 -0
  380. data/frameworks/sproutcore/frameworks/foundation/tests/validators/password.js +13 -0
  381. data/frameworks/sproutcore/frameworks/foundation/tests/views/container/methods.js +10 -0
  382. data/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +83 -0
  383. data/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +39 -0
  384. data/frameworks/sproutcore/frameworks/foundation/tests/views/main_pane.js +31 -0
  385. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/append_remove.js +89 -0
  386. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/firstResponder.js +148 -0
  387. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/keyPane.js +133 -0
  388. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/sendEvent.js +165 -0
  389. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/clippingFrame.js +132 -0
  390. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/convertFrames.js +246 -0
  391. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/createChildViews.js +87 -0
  392. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/createLayer.js +97 -0
  393. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/destroyLayer.js +85 -0
  394. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/findLayerInParentLayer.js +52 -0
  395. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/init.js +50 -0
  396. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/insertBefore.js +200 -0
  397. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/isVisibleInWindow.js +102 -0
  398. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layer.js +150 -0
  399. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutChildViews.js +162 -0
  400. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutDidChange.js +127 -0
  401. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutStyle.js +248 -0
  402. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/parentViewDidChange.js +67 -0
  403. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/prepareContext.js +166 -0
  404. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/removeChild.js +189 -0
  405. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/render.js +83 -0
  406. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/replaceChild.js +29 -0
  407. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayer.js +142 -0
  408. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayerLocation.js +194 -0
  409. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/viewDidResize.js +185 -0
  410. data/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +125 -0
  411. data/frameworks/sproutcore/frameworks/foundation/validators/date.js +52 -0
  412. data/frameworks/sproutcore/frameworks/foundation/validators/email.js +45 -0
  413. data/frameworks/sproutcore/frameworks/foundation/validators/not_empty.js +33 -0
  414. data/frameworks/sproutcore/frameworks/foundation/validators/number.js +82 -0
  415. data/frameworks/sproutcore/frameworks/foundation/validators/password.js +86 -0
  416. data/frameworks/sproutcore/frameworks/foundation/validators/validator.js +311 -0
  417. data/frameworks/sproutcore/frameworks/foundation/views/container.js +136 -0
  418. data/frameworks/sproutcore/frameworks/foundation/views/field.js +276 -0
  419. data/frameworks/sproutcore/frameworks/foundation/views/image.js +158 -0
  420. data/frameworks/sproutcore/frameworks/foundation/views/label.js +261 -0
  421. data/frameworks/sproutcore/frameworks/foundation/views/view.js +2160 -0
  422. data/frameworks/sproutcore/frameworks/mobile/english.lproj/core.css +12 -0
  423. data/frameworks/sproutcore/frameworks/mobile/lib/index.rhtml +126 -0
  424. data/frameworks/sproutcore/frameworks/mobile/system/root_responder.js +109 -0
  425. data/frameworks/sproutcore/frameworks/mobile/tests/views/button/ui.js +9 -0
  426. data/frameworks/sproutcore/frameworks/mobile/views/button.js +190 -0
  427. data/frameworks/sproutcore/frameworks/runtime/README +11 -0
  428. data/frameworks/sproutcore/frameworks/runtime/core.js +777 -0
  429. data/frameworks/sproutcore/frameworks/runtime/license.js +28 -0
  430. data/frameworks/sproutcore/frameworks/runtime/mixins/array.js +403 -0
  431. data/frameworks/sproutcore/frameworks/runtime/mixins/delegate_support.js +70 -0
  432. data/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +1193 -0
  433. data/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +1149 -0
  434. data/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +135 -0
  435. data/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +108 -0
  436. data/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +128 -0
  437. data/frameworks/sproutcore/frameworks/runtime/protocols/sparse_array_delegate.js +131 -0
  438. data/frameworks/sproutcore/frameworks/runtime/system/binding.js +891 -0
  439. data/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +107 -0
  440. data/frameworks/sproutcore/frameworks/runtime/system/object.js +783 -0
  441. data/frameworks/sproutcore/frameworks/runtime/system/range_observer.js +99 -0
  442. data/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +214 -0
  443. data/frameworks/sproutcore/frameworks/runtime/system/set.js +246 -0
  444. data/frameworks/sproutcore/frameworks/runtime/system/sparse_array.js +286 -0
  445. data/frameworks/sproutcore/frameworks/runtime/tests/core/IsEqual.js +56 -0
  446. data/frameworks/sproutcore/frameworks/runtime/tests/core/beget.js +23 -0
  447. data/frameworks/sproutcore/frameworks/runtime/tests/core/clone.js +66 -0
  448. data/frameworks/sproutcore/frameworks/runtime/tests/core/guidFor.js +147 -0
  449. data/frameworks/sproutcore/frameworks/runtime/tests/core/inspect.js +27 -0
  450. data/frameworks/sproutcore/frameworks/runtime/tests/core/isArray.js +25 -0
  451. data/frameworks/sproutcore/frameworks/runtime/tests/core/itemType.js +38 -0
  452. data/frameworks/sproutcore/frameworks/runtime/tests/core/keys.js +20 -0
  453. data/frameworks/sproutcore/frameworks/runtime/tests/core/makeArray.js +30 -0
  454. data/frameworks/sproutcore/frameworks/runtime/tests/core/objectForPropertyPath.js +19 -0
  455. data/frameworks/sproutcore/frameworks/runtime/tests/core/tupleForPropertyPath.js +37 -0
  456. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable.js +592 -0
  457. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +467 -0
  458. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/propertyChanges.js +123 -0
  459. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/registerDependentKeys.js +79 -0
  460. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/propertyChanges.js +80 -0
  461. data/frameworks/sproutcore/frameworks/runtime/tests/system/array.js +263 -0
  462. data/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +190 -0
  463. data/frameworks/sproutcore/frameworks/runtime/tests/system/object/base.js +135 -0
  464. data/frameworks/sproutcore/frameworks/runtime/tests/system/object/bindings.js +339 -0
  465. data/frameworks/sproutcore/frameworks/runtime/tests/system/run_loop.js +120 -0
  466. data/frameworks/sproutcore/frameworks/runtime/tests/system/set.js +313 -0
  467. data/frameworks/sproutcore/frameworks/runtime/tests/system/sparse_array.js +84 -0
  468. data/frameworks/sproutcore/frameworks/testing/core.js +13 -0
  469. data/frameworks/sproutcore/frameworks/testing/english.lproj/additions.css +8 -0
  470. data/frameworks/sproutcore/frameworks/testing/english.lproj/testsuite.css +131 -0
  471. data/frameworks/sproutcore/frameworks/testing/extras.js +43 -0
  472. data/frameworks/sproutcore/frameworks/testing/jquery.js +3559 -0
  473. data/frameworks/sproutcore/frameworks/testing/qunit.js +819 -0
  474. data/frameworks/sproutcore/frameworks/testing/tests/debug/qunit.js +25 -0
  475. data/frameworks/sproutcore/frameworks/testing/utils.js +55 -0
  476. data/frameworks/sproutcore/lib/index.rhtml +118 -0
  477. data/frameworks/sproutcore/license.js +28 -0
  478. data/frameworks/sproutcore/themes/empty_theme/tests/mini_icons.rhtml +69 -0
  479. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/button.css +41 -0
  480. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/core.css +8 -0
  481. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/backButton.png +0 -0
  482. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/blueButton.png +0 -0
  483. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/cancel.png +0 -0
  484. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/grayButton.png +0 -0
  485. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/leftButton.png +0 -0
  486. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listArrow.png +0 -0
  487. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listArrowSel.png +0 -0
  488. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listGroup.png +0 -0
  489. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/loading.gif +0 -0
  490. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/pinstripes.png +0 -0
  491. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/rightButton.png +0 -0
  492. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/selection.png +0 -0
  493. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/thumb.png +0 -0
  494. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toggle.png +0 -0
  495. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toggleOn.png +0 -0
  496. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toolButton.png +0 -0
  497. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toolbar.png +0 -0
  498. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/whiteButton.png +0 -0
  499. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/strings.js +15 -0
  500. data/frameworks/sproutcore/themes/standard_theme/Source/Panel.drawit/Data +0 -0
  501. data/frameworks/sproutcore/themes/standard_theme/Source/Panel.drawit/QuickLook/Preview.jpg +0 -0
  502. data/frameworks/sproutcore/themes/standard_theme/Source/Panel.drawit/QuickLook/Thumbnail.jpg +0 -0
  503. data/frameworks/sproutcore/themes/standard_theme/Source/ToolbarView Pattern.drawit/Data +0 -0
  504. data/frameworks/sproutcore/themes/standard_theme/Source/ToolbarView Pattern.drawit/QuickLook/Preview.jpg +0 -0
  505. data/frameworks/sproutcore/themes/standard_theme/Source/ToolbarView Pattern.drawit/QuickLook/Thumbnail.jpg +0 -0
  506. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-x.drawit/Data +0 -0
  507. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-x.drawit/QuickLook/Preview.jpg +0 -0
  508. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-x.drawit/QuickLook/Thumbnail.jpg +0 -0
  509. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-y.drawit/Data +0 -0
  510. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-y.drawit/QuickLook/Preview.jpg +0 -0
  511. data/frameworks/sproutcore/themes/standard_theme/Source/panel-sprite-y.drawit/QuickLook/Thumbnail.jpg +0 -0
  512. data/frameworks/sproutcore/themes/standard_theme/english.lproj/button.css +333 -0
  513. data/frameworks/sproutcore/themes/standard_theme/english.lproj/checkbox.css +90 -0
  514. data/frameworks/sproutcore/themes/standard_theme/english.lproj/collection.css +53 -0
  515. data/frameworks/sproutcore/themes/standard_theme/english.lproj/core.css +47 -0
  516. data/frameworks/sproutcore/themes/standard_theme/english.lproj/disclosure.css +55 -0
  517. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-sprite.png +0 -0
  518. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-ysprite.png +0 -0
  519. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-toolbar-view.png +0 -0
  520. data/frameworks/sproutcore/themes/standard_theme/english.lproj/label.css +37 -0
  521. data/frameworks/sproutcore/themes/standard_theme/english.lproj/pane.css +8 -0
  522. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-fat.jpg +0 -0
  523. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-thin.jpg +0 -0
  524. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-edge.png +0 -0
  525. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-left-corner.png +0 -0
  526. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-right-corner.png +0 -0
  527. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/left-edge.png +0 -0
  528. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/overlay.png +0 -0
  529. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/right-edge.png +0 -0
  530. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-edge.png +0 -0
  531. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-left-corner.png +0 -0
  532. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-right-corner.png +0 -0
  533. data/frameworks/sproutcore/themes/standard_theme/english.lproj/progress.css +23 -0
  534. data/frameworks/sproutcore/themes/standard_theme/english.lproj/radio.css +113 -0
  535. data/frameworks/sproutcore/themes/standard_theme/english.lproj/segmented.css +141 -0
  536. data/frameworks/sproutcore/themes/standard_theme/english.lproj/slider.css +62 -0
  537. data/frameworks/sproutcore/themes/standard_theme/english.lproj/split_view.css +27 -0
  538. data/frameworks/sproutcore/themes/standard_theme/english.lproj/tab.css +12 -0
  539. data/frameworks/sproutcore/themes/standard_theme/english.lproj/text_field.css +13 -0
  540. data/frameworks/sproutcore/themes/standard_theme/english.lproj/toolbar.css +4 -0
  541. data/lib/thor/.autotest +7 -0
  542. data/lib/thor/CHANGELOG.rdoc +52 -0
  543. data/lib/thor/LICENSE +20 -0
  544. data/lib/thor/README.markdown +76 -0
  545. data/lib/thor/Rakefile +6 -0
  546. data/lib/thor/Thorfile +45 -0
  547. data/lib/thor/bin/rake2thor +83 -0
  548. data/lib/thor/bin/thor +7 -0
  549. data/lib/thor/lib/thor/error.rb +3 -0
  550. data/lib/thor/lib/thor/options.rb +267 -0
  551. data/lib/thor/lib/thor/ordered_hash.rb +64 -0
  552. data/lib/thor/lib/thor/runner.rb +305 -0
  553. data/lib/thor/lib/thor/task.rb +83 -0
  554. data/lib/thor/lib/thor/task_hash.rb +22 -0
  555. data/lib/thor/lib/thor/tasks/package.rb +18 -0
  556. data/lib/thor/lib/thor/tasks.rb +77 -0
  557. data/lib/thor/lib/thor/util.rb +75 -0
  558. data/lib/thor/lib/thor.rb +170 -0
  559. data/lib/thor/script/destroy +14 -0
  560. data/lib/thor/script/generate +14 -0
  561. data/lib/thor/spec/fixtures/task.thor +10 -0
  562. data/lib/thor/spec/options_spec.rb +271 -0
  563. data/lib/thor/spec/ordered_hash_spec.rb +84 -0
  564. data/lib/thor/spec/spec.opts +1 -0
  565. data/lib/thor/spec/spec_helper.rb +30 -0
  566. data/lib/thor/spec/task_spec.rb +11 -0
  567. data/lib/thor/spec/tasks_spec.rb +28 -0
  568. data/lib/thor/spec/thor_runner_spec.rb +194 -0
  569. data/lib/thor/spec/thor_spec.rb +206 -0
  570. data/lib/thor/spec/util_spec.rb +99 -0
  571. data/lib/thor/task.thor +15 -0
  572. data/lib/thor/thor.gemspec +29 -0
  573. metadata +3 -4
  574. data/sproutcore.gemspec +0 -47
@@ -0,0 +1,2141 @@
1
+ // ==========================================================================
2
+ // Project: SproutCore - JavaScript Application Framework
3
+ // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
4
+ // Portions ©2008-2009 Apple, Inc. All rights reserved.
5
+ // License: Licened under MIT license (see license.js)
6
+ // ==========================================================================
7
+
8
+ sc_require('mixins/collection_view_delegate') ;
9
+ sc_require('views/list_item');
10
+
11
+ SC.BENCHMARK_UPDATE_CHILDREN = YES ;
12
+ SC.BENCHMARK_RENDER = YES ;
13
+ SC.ENABLE_COLLECTION_PARTIAL_RENDER = YES ;
14
+ SC.DEBUG_PARTIAL_RENDER = NO ;
15
+ SC.SANITY_CHECK_PARTIAL_RENDER = YES ;
16
+ SC.VALIDATE_COLLECTION_CONSISTANCY = NO ;
17
+
18
+ /**
19
+ Special drag operation passed to delegate if the collection view proposes
20
+ to perform a reorder event.
21
+ */
22
+ SC.DRAG_REORDER = 0x0010 ;
23
+
24
+ /** Indicates that selection points should be selected using horizontal
25
+ orientation.
26
+ */
27
+ SC.HORIZONTAL_ORIENTATION = 'horizontal';
28
+
29
+ /** Selection points should be selected using vertical orientation. */
30
+ SC.VERTICAL_ORIENTATION = 'vertical' ;
31
+
32
+ /** Enables an optimization using zombie group views. This option is configurable for perf testing purposes. You should not change it. */
33
+ SC.ZOMBIE_GROUPS_ENABLED = YES ;
34
+
35
+ /** Enables an optimization that removes the root element from the DOM during
36
+ a render and then readds it when complete. This option is configurable for
37
+ perf testing purposes. You should not change it. */
38
+ SC.REMOVE_COLLECTION_ROOT_ELEMENT_DURING_RENDER = NO ;
39
+
40
+ /**
41
+ @class
42
+
43
+ Renders a collection of views from a source array of model objects.
44
+
45
+ The CollectionView is the root view class for rendering collections of
46
+ views based on a source array of objects. It can automatically create the
47
+ and layout the views, including displaying them in groups. It also
48
+ handles event input for the entire collection.
49
+
50
+ To use CollectionView, just create the view and set the 'content' property
51
+ to an array of objects. (Note that if you setup a binding, it will
52
+ always transform content to an array.) The view will create instances of
53
+ exampleView to render the array. You can also bind to the selection
54
+ property if you want to monitor selection. (be sure to set the isEnabled
55
+ property to allow selection.)
56
+
57
+ @extends SC.ClassicView
58
+ @extends SC.CollectionViewDelegate
59
+
60
+ */
61
+ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
62
+ /** @scope SC.CollectionView.prototype */
63
+ {
64
+
65
+ classNames: ['sc-collection-view'],
66
+
67
+ // ......................................
68
+ // PROPERTIES
69
+ //
70
+
71
+ /**
72
+ An array of content objects
73
+
74
+ This array should contain the content objects you want the collection view
75
+ to display. An item view (based on the exampleView view class) will be
76
+ created for each content object, in the order the content objects appear
77
+ in this array.
78
+
79
+ If you make the collection editable, the collection view will also modify
80
+ this array using the observable array methods of SC.Array.
81
+
82
+ Usually you will want to bind this property to a controller property
83
+ that actually contains the array of objects you to display.
84
+
85
+ @type SC.Array
86
+ */
87
+ content: [],
88
+
89
+ /** @private */
90
+ contentBindingDefault: SC.Binding.multiple(),
91
+
92
+ /**
93
+ The array of currently selected objects.
94
+
95
+ This array should contain the currently selected content objects. It is
96
+ modified automatically by the collection view when the user changes the
97
+ selection on the collection.
98
+
99
+ Any item views representing content objects in this array will have their
100
+ isSelected property set to YES automatically.
101
+
102
+ The CollectionView can deal with selection arrays that contain content
103
+ objects that do not belong to the content array itself. Sometimes this
104
+ will happen if you share the same selection across multiple collection
105
+ views.
106
+
107
+ Usually you will want to bind this property to a controller property that
108
+ actually manages the selection for your display.
109
+
110
+ @type Array
111
+ */
112
+ selection: [],
113
+
114
+ /** @private */
115
+ selectionBindingDefault: SC.Binding.multiple(),
116
+
117
+ /**
118
+ Delegate used to implement fine-grained control over collection view
119
+ behaviors.
120
+
121
+ You can assign a delegate object to this property that will be consulted
122
+ for various decisions regarding drag and drop, selection behavior, and
123
+ even rendering. The object you place here must implement some or all of
124
+ the SC.CollectionViewDelegate mixin.
125
+ */
126
+ delegate: null,
127
+
128
+ /**
129
+ Allow user to select content using the mouse and keyboard.
130
+
131
+ Set this property to NO to disallow the user from selecting items. If you
132
+ have items in your selection property, they will still be reflected
133
+ visually.
134
+
135
+ @type Boolean
136
+ */
137
+ isSelectable: YES,
138
+
139
+ /** @private */
140
+ isSelectableBindingDefault: SC.Binding.bool(),
141
+
142
+ /**
143
+ Enable or disable the view.
144
+
145
+ The collection view will set the isEnabled property of its item views to
146
+ reflect the same view of this property. Whenever isEnabled is false,
147
+ the collection view will also be not selectable or editable, regardless of the
148
+ settings for isEditable & isSelectable.
149
+
150
+ @type Boolean
151
+ */
152
+ isEnabled: YES,
153
+
154
+ /** @private */
155
+ isEnabledBindingDefault: SC.Binding.bool(),
156
+
157
+ /**
158
+ Allow user to edit content views.
159
+
160
+ The collection view will set the isEditable property on its item views to
161
+ reflect the same value of this property. Whenever isEditable is false,
162
+ the user will not be able to reorder, add, or delete items regardless of
163
+ the canReorderContent and canDeleteContent and isDropTarget properties.
164
+
165
+ @type Boolean
166
+ */
167
+ isEditable: YES,
168
+
169
+ /** @private */
170
+ isEditableBindingDefault: SC.Binding.bool(),
171
+
172
+ /**
173
+ Allow user to reorder items using drag and drop.
174
+
175
+ If true, the user will can use drag and drop to reorder items in the list.
176
+ If you also accept drops, this will allow the user to drop items into
177
+ specific points in the list. Otherwise items will be added to the end.
178
+
179
+ @type Boolean
180
+ */
181
+ canReorderContent: NO,
182
+
183
+ /** @private */
184
+ canReorderContentBindingDefault: SC.Binding.bool(),
185
+
186
+ /**
187
+ Allow the user to delete items using the delete key
188
+
189
+ If true the user will be allowed to delete selected items using the delete
190
+ key. Otherwise deletes will not be permitted.
191
+
192
+ @type Boolean
193
+ */
194
+ canDeleteContent: NO,
195
+
196
+ /** @private */
197
+ canDeleteContentBindingDefault: SC.Binding.bool(),
198
+
199
+ /**
200
+ Accept drops for data other than reordering.
201
+
202
+ Setting this property to return true when the view is instantiated will
203
+ cause it to be registered as a drop target, activating the other drop
204
+ machinery.
205
+
206
+ @type Boolean
207
+ */
208
+ isDropTarget: NO,
209
+
210
+ /**
211
+ Use toggle selection instead of normal click behavior.
212
+
213
+ If set to true, then selection will use a toggle instead of the normal
214
+ click behavior. Command modifiers will be ignored and instead clicking
215
+ once will enable an item and clicking on it again will disable it.
216
+
217
+ @type Boolean
218
+ */
219
+ useToggleSelection: NO,
220
+
221
+ /**
222
+ Trigger the action method on a single click.
223
+
224
+ Normally, clicking on an item view in a collection will select the content
225
+ object and double clicking will trigger the action method on the
226
+ collection view.
227
+
228
+ If you set this property to true, then clicking on a view will both select
229
+ it (if isSelected is true) and trigger the action method.
230
+
231
+ Use this if you are using the collection view as a menu of items.
232
+
233
+ @type Boolean
234
+ */
235
+ actOnSelect: NO,
236
+
237
+
238
+ /**
239
+ Select an item immediately on mouse down
240
+
241
+ Normally as soon as you begin a click the item will be selected.
242
+
243
+ In some UI scenarios, you might want to prevent selection until
244
+ the mouse is released, so you can perform, for instance, a drag operation
245
+ without actually selecting the target item.
246
+
247
+ @type Boolean
248
+ */
249
+ selectOnMouseDown: YES,
250
+
251
+ /**
252
+ The view class to use when creating new item views.
253
+
254
+ The collection view will automatically create an instance of the view
255
+ class you set here for each item in its content array. You should provide
256
+ your own subclass for this property to display the type of content you
257
+ want.
258
+
259
+ For best results, the view you set here should understand the following
260
+ properties:
261
+
262
+ - *content* The content object from the content array your view should display
263
+ - *isEnabled* True if the view should appear enabled
264
+ - *isSelected* True if the view should appear selected
265
+
266
+ In general you do not want your child views to actually respond to mouse
267
+ and keyboard events themselves. It is better to let the collection view
268
+ do that.
269
+
270
+ If you do implement your own event handlers such as mouseDown or mouseUp,
271
+ you should be sure to actually call the same method on the collection view
272
+ to give it the chance to perform its own selection housekeeping.
273
+
274
+ @property {SC.View}
275
+ */
276
+ exampleView: SC.ListItemView,
277
+
278
+ /**
279
+ If set, this key will be used to get the example view for a given
280
+ content object.
281
+ */
282
+ contentExampleViewKey: null,
283
+
284
+ /**
285
+ Invoked when the user double clicks on an item (or single clicks of
286
+ actOnSelect is true)
287
+
288
+ Set this to the name of the action you want to send down the
289
+ responder chain when the user double clicks on an item (or single clicks
290
+ if actOnSelect is true). You can optionally specify a specific target as
291
+ well using the target property.
292
+
293
+ If you do not specify an action, then the collection view will also try to
294
+ invoke the action named on the target item view.
295
+
296
+ Older versions of SproutCore expected the action property to contain an
297
+ actual function that would be run. This format is still supported but is
298
+ deprecated for future use. You should generally use the responder chain
299
+ to handle your action for you.
300
+
301
+ @property {String}
302
+ */
303
+ action: null,
304
+
305
+ /**
306
+ Optional target to send the action to when the user double clicks.
307
+
308
+ If you set the action property to the name of an action, you can
309
+ optionally specify the target object you want the action to be sent to.
310
+ This can be either an actual object or a property path that will resolve
311
+ to an object at the time that the action is invoked.
312
+
313
+ This property is ignored if you use the deprecated approach of making the
314
+ action property a function.
315
+
316
+ @property {String|Object}
317
+ */
318
+ target: null,
319
+
320
+ /**
321
+ Set to YES whenever the content needs to update its children. If you
322
+ set this property, it will cause the view to update its children at the
323
+ end of the runloop or the next time it becomes visible.
324
+
325
+ Generally you will not need to change this property. Instead you should
326
+ call methods such as contentPropertyDidChange() or updateChildren()
327
+ directly instead.
328
+
329
+ @property {Boolean}
330
+ */
331
+ isDirty: NO,
332
+
333
+ /**
334
+ Property on content items to use for display.
335
+
336
+ Built-in item views such as the LabelViews and ImageViews will use the
337
+ value of this property as a key on the content object to determine the
338
+ value they should display.
339
+
340
+ For example, if you set contentValueKey to 'name' and set the
341
+ exampleView to an SC.LabelView, then the label views created by the
342
+ colleciton view will display the value of the content.name.
343
+
344
+ If you are writing your own custom item view for a collection, you can
345
+ get this behavior automatically by including the SC.Control mixin on your
346
+ view. You can also ignore this property if you like. The collection view
347
+ itself does not use this property to impact rendering.
348
+
349
+ @property {String}
350
+ */
351
+ contentValueKey: null,
352
+
353
+ /**
354
+ Enables keyboard-based navigate, deletion, etc. if set to true.
355
+ */
356
+ acceptsFirstResponder: NO,
357
+
358
+ /**
359
+ If your layout uses a grid or horizontal-based layout, then make sure this
360
+ property is always up to date with the current number of items per row.
361
+
362
+ The CollectionView will use this property to support keyboard navigation
363
+ using the arrow keys.
364
+
365
+ If your collection view is simply a vertical list of items then you do not
366
+ need to change this property.
367
+
368
+ @property {Number}
369
+ */
370
+ itemsPerRow: 1,
371
+
372
+ // ..........................................................
373
+ // SUBCLASS METHODS
374
+ //
375
+
376
+ /**
377
+ Override to return the computed layout dimensions of the collection view.
378
+ You can omit any dimensions you don't care about setting in your
379
+ computed value.
380
+
381
+ This layout is automatically applied whenever the content changes.
382
+
383
+ If you don't care about computing the layout at all, you can return null.
384
+
385
+ @returns {Hash} layout properties
386
+ */
387
+ computeLayout: function() { return null; },
388
+
389
+ /**
390
+ Override to return the range of items to render for a given frame.
391
+
392
+ You can override this method to implement support for incremenetal
393
+ rendering. The range you return here will be used to limit the number of
394
+ actual item views that are created by the collection view.
395
+
396
+ If you do not want to support incremental rendering, just return null.
397
+
398
+ @param {Rect} frame The frame you should use to determine the range.
399
+ @returns {Range} A hash that indicates the range of content objects to
400
+ render. ({ start: X, length: Y })
401
+ */
402
+ contentRangeInFrame: function(frame) { return null; },
403
+
404
+ /**
405
+ Override to adjust the position of the itemView's layout property at the
406
+ specified content index.
407
+
408
+ Note: if useAdjust is NO, you should set the view's layout property in
409
+ such a way that no change notifications are triggered. For example,
410
+
411
+ {{{
412
+ var newLayout = this.myComputeLayoutForIndex(contentIndex) ;
413
+ if (useAdjust) itemView.adjust(newLayout) ;
414
+ else itemView.layout = newLayout ; // DON'T TRIGGER OBSERVERS!!!
415
+ }}}
416
+
417
+ @param {Number} contentIndex the index of content beind rendered by
418
+ itemView
419
+ @returns {Rect} a layout rectangle
420
+ */
421
+ itemViewLayoutAtContentIndex: function(contentIndex) {},
422
+
423
+ // ..........................................................
424
+ // CONTENT CHANGES
425
+ //
426
+
427
+ /** @private
428
+ Whenever content array changes, start observing the [] property. Also
429
+ set childrenNeedFullUpdate to YES, which will trigger an update.
430
+ */
431
+ _collection_contentDidChange: function() {
432
+ var content = this.get('content') ;
433
+ if (content === this._content) return this; // nothing to do
434
+
435
+ var func = this._collection_contentPropertyDidChange ;
436
+
437
+ // remove old observer, add new observer
438
+ if (this._content) this._content.removeObserver('[]', this, func) ;
439
+ if (content) content.addObserver('[]', this, func) ;
440
+
441
+ // cache
442
+ this._content = content;
443
+ this._contentPropertyRevision = null ;
444
+
445
+ // trigger property change handler...
446
+ var rev = (content) ? content.propertyRevision : -1 ;
447
+ this._collection_contentPropertyDidChange(this, '[]', content, rev) ;
448
+ }.observes('content'),
449
+
450
+ /** @private
451
+ Called whenever the content array or any items in the content array
452
+ changes. update children if this is a new property revision.
453
+ */
454
+ _collection_contentPropertyDidChange: function(target, key, value, rev) {
455
+ if (!this._updatingContent && (!rev || (rev != this._contentPropertyRevision))) {
456
+ this._contentPropertyRevision = rev ;
457
+ this._updatingContent = true ;
458
+ this.contentPropertyDidChange(target, key);
459
+ this._updatingContent = false ;
460
+ }
461
+ },
462
+
463
+ /**
464
+ Invoked whenever a the content array changes. The default implementation
465
+ will possibly recompute the view's layout size and the marks it as dirty
466
+ so that it can update its children.
467
+ */
468
+ contentPropertyDidChange: function(target, key) {
469
+ this.adjust(this.computeLayout()) ;
470
+ this.set('isDirty', YES) ;
471
+ this.invalidateNowShowingRange() ;
472
+ return this ;
473
+ },
474
+
475
+ /** @private
476
+ Anytime isDirty changes to YES or our visibility in window changes,
477
+ schedule a full update.
478
+ */
479
+ _collection_isDirtyDidChange: function() {
480
+ // don't test isVisibleInWindow here for a 10% perf gain
481
+ if (this.get('isDirty')) {
482
+ // using invokeOnce here doubles rendering speed!
483
+ this.invokeOnce(this.displayDidChange) ;
484
+ }
485
+ }.observes('isDirty', 'isVisibleInWindow'),
486
+
487
+ // ..........................................................
488
+ // SELECTION CHANGES
489
+ //
490
+
491
+ /** @private
492
+ Whenever selection array changes, start observing the [] property. Also
493
+ set childrenNeedFullUpdate to YES, which will trigger an update.
494
+ */
495
+ _collection_selectionDidChange: function() {
496
+ var selection = this.get('selection') ;
497
+ if (selection === this._selection) return this; // nothing to do
498
+
499
+ var func = this._collection_selectionPropertyDidChange ;
500
+
501
+ // remove old observer, add new observer
502
+ if (this._selection) this._selection.removeObserver('[]', this, func) ;
503
+ if (selection) selection.addObserver('[]', this, func) ;
504
+
505
+ // cache
506
+ this._selection = selection;
507
+ this._selectionPropertyRevision = null ;
508
+
509
+ // trigger property change handler...
510
+ var rev = (selection) ? selection.propertyRevision : -1 ;
511
+ this._collection_selectionPropertyDidChange(this, '[]', selection, rev) ;
512
+ }.observes('selection'),
513
+
514
+ /** @private
515
+ Called whenever the content array or any items in the selection array
516
+ changes. update children if this is a new property revision.
517
+ */
518
+ _collection_selectionPropertyDidChange: function(target, key, value, rev) {
519
+ if (!this._updatingSelection && (!rev || (rev != this._selectionPropertyRevision))) {
520
+ this._selectionPropertyRevision = rev ;
521
+ this._updatingSelection = true ;
522
+ this.selectionPropertyDidChange(target, key);
523
+ this._updatingSelection = false ;
524
+ }
525
+ },
526
+
527
+ /**
528
+ Invoked whenever a the selection array changes. The default
529
+ implementation will possibly recompute the view's layout size and the
530
+ marks it as dirty so that it can update its children.
531
+ */
532
+ selectionPropertyDidChange: function(target, key) {
533
+ this.adjust(this.computeLayout()) ;
534
+ this.set('isDirty', YES) ;
535
+ this.invalidateNowShowingRange() ;
536
+ return this ;
537
+ },
538
+
539
+ // ..........................................................
540
+ // NOW SHOWING RANGE
541
+ //
542
+
543
+ /**
544
+ The currently visible range. This is invalidated anytime the clipping
545
+ frame changes or anytime the view is resized. This in turn may cause
546
+ the collection view to do a 'fast' revalidation of its content.
547
+
548
+ @property
549
+ @type Range
550
+ */
551
+ nowShowingRange: function() {
552
+ // console.log(this.get('clippingFrame'));
553
+ var r = this.contentRangeInFrame(this.get('clippingFrame')) ;
554
+ if (!r) r = { start: 0, length: 0 } ; // default
555
+
556
+ // make sure the range isn't greater than the content length
557
+ var content = SC.makeArray(this.get('content'));
558
+ r.length = Math.min(SC.maxRange(r), content.get('length')) - r.start ;
559
+
560
+ return r ;
561
+ }.property('content', 'clippingFrame').cacheable(),
562
+
563
+ /**
564
+ Call this method if the nowShowingRange should be recalculated for some
565
+ reason. Usually the nowShowingRange will invalidate and recalculate on
566
+ its own but you can force the property to need an update if you
567
+ prefer.
568
+ */
569
+ invalidateNowShowingRange: function() {
570
+ this.notifyPropertyChange('nowShowingRange') ;
571
+ },
572
+
573
+ /** @private
574
+ Observer triggers whenever the nowShowingRange changes. If the range has
575
+ actually changed and we are on screen, then schedule fast update.
576
+ Otherwise, just mark as dirty.
577
+ */
578
+ nowShowingRangeDidChange: function() {
579
+ var range = this.get('nowShowingRange') ;
580
+ var old = this._collection_nowShowingRange ;
581
+ if (!old || !SC.rangesEqual(range, old)) {
582
+ this._collection_nowShowingRange = range ;
583
+ if (this.get('isVisibleInWindow')) this.displayDidChange() ;
584
+ else this.set('isDirty', YES);
585
+ }
586
+ }.observes('nowShowingRange'),
587
+
588
+ // ......................................
589
+ // RENDERING
590
+ //
591
+
592
+ itemViewAtContentIndex: function(contentIndex) {
593
+ var range = this.get('nowShowingRange') ;
594
+ var itemView = this.createExampleView() ;
595
+ var key, content = SC.makeArray(this.get('content')) ;
596
+ var selection = SC.makeArray(this.get('selection')) ;
597
+ content = content.objectAt(contentIndex) ;
598
+ if (!content) return null ;
599
+
600
+ var guids = this._itemViewGuids, guid;
601
+ if (!guids) this._itemViewGuids = guids = {};
602
+
603
+ // use cache of item view guids to avoid creating temporary objects
604
+ guid = SC.guidFor(content);
605
+ if (!(key = guids[guid])) {
606
+ key = guids[guid] = SC.guidFor(this)+'_'+guid;
607
+ }
608
+
609
+ itemView.set('content', content) ;
610
+ itemView.layerId = key ; // NOTE: cannot use .set here, layerId is RO
611
+ itemView.set('isVisible', SC.valueInRange(contentIndex, range)) ;
612
+ itemView.set('isSelected', (selection.indexOf(content) == -1) ? NO : YES) ;
613
+
614
+ // NOTE: *must* set the layout silently...
615
+ itemView.layout = this.itemViewLayoutAtContentIndex(contentIndex) ;
616
+ itemView.set('parentView', this) ;
617
+ return itemView ;
618
+ },
619
+
620
+ /**
621
+ Find the first content item view for the passed event.
622
+
623
+ This method will go up the view chain, starting with the view that was the
624
+ target of the passed event, looking for a child item. This will become
625
+ the view that is selected by the mouse event.
626
+
627
+ This method only works for mouseDown & mouseUp events. mouseMoved events
628
+ do not have a target.
629
+
630
+ @param {SC.Event} evt An event
631
+ @returns {SC.View} the item view or null
632
+ */
633
+ itemViewForEvent: function(evt) {
634
+ var responder = this.getPath('pane.rootResponder') ;
635
+
636
+ if (!responder) return null ; // fast path
637
+
638
+ // need to materialize an itemView under the mouse if possible
639
+ var baseGuid = SC.guidFor(this) ;
640
+ var baseGuidLen = baseGuid.length ;
641
+ var element = evt.target ;
642
+ var elementId = element.id.slice(0, baseGuidLen) ;
643
+ while (elementId !== baseGuid) {
644
+ element = element.parentNode ;
645
+ elementId = element.id.slice(0, baseGuidLen) ;
646
+ }
647
+
648
+ if (element.id.length === baseGuidLen) {
649
+ return null ; // we found ourself, so we're not over a child view
650
+ }
651
+
652
+ // okay, found the DOM node for the view, go ahead and create it
653
+ // first, find the content...
654
+ var contentGuid = element.id.slice(baseGuidLen+1) ;
655
+ var nowShowingRange = this.get('nowShowingRange') ;
656
+ var content = SC.makeArray(this.get('content')) ;
657
+ var idx = SC.minRange(nowShowingRange) ;
658
+ var max = SC.maxRange(nowShowingRange) ;
659
+ var c = content.objectAt(idx) ;
660
+ while (SC.guidFor(c) !== contentGuid) {
661
+ c = content.objectAt(idx++) ;
662
+ if (idx == max) return null ; // couldn't find the content...
663
+ }
664
+
665
+ // then create the view for that content
666
+ var itemView = this.createExampleView() ;
667
+ var selection = SC.makeArray(this.get('selection')) ;
668
+ itemView.set('content', c) ;
669
+ itemView.layerId = element.id ; // cannot use .set here, layerId is RO
670
+ SC.View.views[itemView.layerId] = itemView ; // register for event handling
671
+ itemView.set('isVisible', SC.valueInRange(idx, nowShowingRange)) ;
672
+ itemView.set('isSelected', (selection.indexOf(c) == -1) ? NO : YES) ;
673
+
674
+ // NOTE: *must* set the layout silently...
675
+ itemView.layout = this.itemViewLayoutAtContentIndex(idx) ;
676
+ itemView.set('parentView', this) ;
677
+
678
+ // prevent normal, non-materialized view behavior
679
+ // TODO: isMaterialized should do this automatically in SC.View
680
+ itemView.layerLocationNeedsUpdate = NO ;
681
+ itemView.childViewsNeedLayout = NO ;
682
+ itemView.layerNeedsUpdate = NO ;
683
+
684
+ // NOTE: still have to search for view, because itemView could contain
685
+ // nested views, and the mouseDown should go to them first...
686
+ var view = responder.targetViewForEvent(evt) ;
687
+ if (!view) return null ; // workaround for error on IE8, see Ticket #169
688
+
689
+ // work up the view hierarchy to find a match...
690
+ do {
691
+ // item clicked was the ContainerView itself... i.e. the user clicked
692
+ // outside the child items nothing to return...
693
+ if (view == this) return null ;
694
+
695
+ // sweet!... the view is not only in the collection, but it says we can
696
+ // hit it. hit it and quit it...
697
+ if (!view.hitTest || view.hitTest(evt)) return view ;
698
+ } while (view = view.get('parentView')) ;
699
+
700
+ // nothing was found...
701
+ return null ;
702
+ },
703
+
704
+ createExampleView: function(content) {
705
+ var exampleViewKey = this.get('contentExampleViewKey') ;
706
+ var ExampleView = (exampleViewKey) ?
707
+ content.get(exampleViewKey) :
708
+ this.get('exampleView') ;
709
+
710
+ if (ExampleView) {
711
+ return ExampleView.create({
712
+ classNames: ['sc-collection-item'],
713
+ owner: this,
714
+ displayDelegate: this,
715
+ parentView: this,
716
+ isVisible: YES,
717
+ isMaterialized: YES
718
+ });
719
+ } else throw "You must define an exampleView class to render collection items with" ;
720
+ },
721
+
722
+ // ......................................
723
+ // SELECTION
724
+ //
725
+
726
+ /** @private
727
+ Finds the smallest index of a content object in the selected array.
728
+ */
729
+ _indexOfSelectionTop: function() {
730
+ var content = this.get('content');
731
+ var sel = this.get('selection');
732
+ if (!content || !sel) return - 1;
733
+
734
+ // find the first item in the selection
735
+ var contentLength = content.get('length') ;
736
+ var indexOfSelected = contentLength ; var idx = sel.length ;
737
+ while(--idx >= 0) {
738
+ var curIndex = content.indexOf(sel[idx]) ;
739
+ if ((curIndex >= 0) && (curIndex < indexOfSelected)) indexOfSelected = curIndex ;
740
+ }
741
+
742
+ return (indexOfSelected >= contentLength) ? -1 : indexOfSelected ;
743
+ },
744
+
745
+ /** @private
746
+ Finds the largest index of a content object in the selection array.
747
+ */
748
+ _indexOfSelectionBottom: function() {
749
+ var content = this.get('content');
750
+ var sel = this.get('selection');
751
+ if (!content || !sel) return - 1;
752
+
753
+ var indexOfSelected = -1 ; var idx = sel.length ;
754
+ while(--idx >= 0) {
755
+ var curIndex = content.indexOf(sel[idx]) ;
756
+ if (curIndex > indexOfSelected) indexOfSelected = curIndex ;
757
+ }
758
+
759
+ return (indexOfSelected < 0) ? -1 : indexOfSelected ;
760
+ },
761
+
762
+ /**
763
+ Select one or more items before the current selection, optionally
764
+ extending the current selection. Also scrolls the selected item into
765
+ view.
766
+
767
+ Selection does not wrap around.
768
+
769
+ @param extend {Boolean} (Optional) If true, the selection will be extended
770
+ instead of replaced. Defaults to false.
771
+ @param numberOfItems {Integer} (Optional) The number of previous to be
772
+ selected. Defaults to 1
773
+ @returns {void}
774
+ */
775
+ selectPreviousItem: function(extend, numberOfItems) {
776
+ if (SC.none(numberOfItems)) numberOfItems = 1 ;
777
+ if (SC.none(extend)) extend = false ;
778
+
779
+ var content = this.get('content');
780
+ var contentLength = content.get('length') ;
781
+
782
+ // if extending, then we need to do some fun stuff to build the array
783
+ var selTop, selBottom, anchor ;
784
+ if (extend) {
785
+ selTop = this._indexOfSelectionTop() ;
786
+ selBottom = this._indexOfSelectionBottom() ;
787
+ anchor = SC.none(this._selectionAnchor) ? selTop : this._selectionAnchor ;
788
+ this._selectionAnchor = anchor ;
789
+
790
+ // If the selBottom is after the anchor, then reduce the selection
791
+ if (selBottom > anchor) {
792
+ selBottom = selBottom - numberOfItems ;
793
+
794
+ // otherwise, select the previous item from the top
795
+ } else {
796
+ selTop = this._findPreviousSelectableItemFromIndex(selTop - numberOfItems);
797
+ }
798
+
799
+ // Ensure we are not out of bounds
800
+ if (selTop < 0) selTop = 0 ;
801
+ if (selBottom < selTop) selBottom = selTop ;
802
+
803
+ // if not extending, just select the item previous to the selTop
804
+ } else {
805
+ selTop = this._findPreviousSelectableItemFromIndex(this._indexOfSelectionTop() - numberOfItems);
806
+ if (selTop < 0) selTop = 0 ;
807
+ selBottom = selTop ;
808
+ anchor = null ;
809
+ }
810
+
811
+ // now build array of new items to select
812
+ var items = [] ;
813
+ while(selTop <= selBottom) {
814
+ items[items.length] = content.objectAt(selTop++) ;
815
+ }
816
+
817
+ // ensure that the item is visible and set the selection
818
+ if (items.length > 0) {
819
+ this.scrollToContent(items[0]);
820
+ this.selectItems(items);
821
+ }
822
+
823
+ this._selectionAnchor = anchor ;
824
+ },
825
+
826
+ /**
827
+ Select one or more items folling the current selection, optionally
828
+ extending the current selection. Also scrolls to selected item.
829
+
830
+ Selection does not wrap around.
831
+
832
+ @param extend {Boolean} (Optional) If true, the selection will be extended
833
+ instead of replaced. Defaults to false.
834
+ @param numberOfItems {Integer} (Optional) The number of items to be
835
+ selected. Defaults to 1.
836
+ @returns {void}
837
+ */
838
+ selectNextItem: function(extend, numberOfItems) {
839
+ if (SC.none(numberOfItems)) numberOfItems = 1 ;
840
+ if (SC.none(extend)) extend = false ;
841
+
842
+ var content = this.get('content');
843
+ var contentLength = content.get('length') ;
844
+
845
+ // if extending, then we need to do some fun stuff to build the array
846
+ var selTop, selBottom, anchor ;
847
+ if (extend) {
848
+ selTop = this._indexOfSelectionTop() ;
849
+ selBottom = this._indexOfSelectionBottom() ;
850
+ anchor = SC.none(this._selectionAnchor) ? selTop : this._selectionAnchor ;
851
+ this._selectionAnchor = anchor ;
852
+
853
+ // If the selTop is before the anchor, then reduce the selection
854
+ if (selTop < anchor) {
855
+ selTop = selTop + numberOfItems ;
856
+
857
+ // otherwise, select the next item after the top
858
+ } else {
859
+ selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems);
860
+ }
861
+
862
+ // Ensure we are not out of bounds
863
+ if (selBottom >= contentLength) selBottom = contentLength-1;
864
+ if (selTop > selBottom) selTop = selBottom ;
865
+
866
+ // if not extending, just select the item next to the selBottom
867
+ } else {
868
+ selBottom = this._findNextSelectableItemFromIndex(this._indexOfSelectionBottom() + numberOfItems);
869
+
870
+ if (selBottom >= contentLength) selBottom = contentLength-1;
871
+ selTop = selBottom ;
872
+ anchor = null ;
873
+ }
874
+
875
+ // now build array of new items to select
876
+ var items = [] ;
877
+ while(selTop <= selBottom) {
878
+ items[items.length] = content.objectAt(selTop++) ;
879
+ }
880
+
881
+ // ensure that the item is visible and set the selection
882
+ if (items.length > 0) {
883
+ this.scrollToContent(items[0]);
884
+ this.selectItems(items);
885
+ }
886
+
887
+ this._selectionAnchor = anchor ;
888
+ },
889
+
890
+ /**
891
+ Scroll the rootElement (if needed) to ensure that the item is visible.
892
+ @param {SC.Record} record The record to scroll to
893
+ @returns {void}
894
+ */
895
+ scrollToContent: function(record) {
896
+ var content, itemView, contentIndex, groupBy;
897
+
898
+ // find the itemView. if not present, add one.
899
+ content = SC.makeArray(this.get('content'));
900
+ if (content.indexOf(record) < 0) return ; // do nothing if not in content.
901
+
902
+ itemView = this.itemViewForContent(record) ;
903
+ if (!itemView) {
904
+ content = SC.makeArray(this.get('content')) ;
905
+ contentIndex = content.indexOf(record) ;
906
+ groupBy = this.get('groupBy');
907
+ itemView = this._insertItemViewFor(record, groupBy, contentIndex);
908
+ }
909
+ if (itemView) this.scrollToItemView(itemView);
910
+ },
911
+
912
+ /**
913
+ Scroll the rootElement (if needed) to ensure that the item is visible.
914
+ @param {SC.ClassicView} view The item view to scroll to
915
+ @returns {void}
916
+ */
917
+ scrollToItemView: function(view) {
918
+ // find first scrollable view.
919
+ var scrollable = this ;
920
+ while(scrollable && (scrollable != SC.window) && (!scrollable.get('isScrollable'))) {
921
+ scrollable = scrollable.get('parentNode') ;
922
+ }
923
+ if (!scrollable || (scrollable == SC.window)) return ; // no scrollable!
924
+ scrollable.scrollToVisible(view) ;
925
+ },
926
+
927
+ /**
928
+ Selects the passed array of items, optionally extending the
929
+ current selection.
930
+
931
+ @param items {Array} The item or items to select.
932
+ @param extendSelection {Boolean} If true, extends the selection instead of
933
+ replacing it.
934
+ */
935
+ selectItems: function(items, extendSelection) {
936
+ var base = (extendSelection) ? this.get('selection') : [] ;
937
+ var sel = [] ;
938
+
939
+ items = SC.makeArray(items) ;
940
+ for (var i = 0, len = items.length; i < len; i++) {
941
+ if (this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, items[i])) {
942
+ sel.push(items[i]);
943
+ }
944
+ }
945
+
946
+ var set = SC.Set.create(base), obj ;
947
+ set.addEach(sel) ; // sel contains selectable items
948
+ sel.length = 0 ; // we don't want duplicates in the selection, so clear it
949
+ while (obj = set.pop()) sel.push(obj) ; // now fill it back up..
950
+
951
+ // if we're not extending the selection, clear the selection anchor
952
+ this._selectionAnchor = null ;
953
+ this.set('selection', sel) ;
954
+ },
955
+
956
+ /**
957
+ Removes the items from the selection.
958
+ */
959
+ deselectItems: function(items) {
960
+ var base = SC.makeArray(this.get('selection')) ;
961
+ var sel = [] ;
962
+
963
+ items = SC.makeArray(items) ;
964
+
965
+ var set = SC.Set.create(base), obj ;
966
+ set.removeEach(items) ;
967
+ while (obj = set.pop()) sel.push(obj) ;
968
+
969
+ this.set('selection', sel) ;
970
+ },
971
+
972
+ /**
973
+ Deletes the selected content if canDeleteContent is YES.
974
+
975
+ This will invoke delegate methods to provide fine-grained control.
976
+
977
+ @returns {Boolean} YES if deletion is possible, even if none actually occurred.
978
+ */
979
+ deleteSelection: function() {
980
+ // console.log('deleteSelection called on %@'.fmt(this));
981
+ // perform some basic checks...
982
+ if (!this.get('canDeleteContent')) return NO;
983
+ var sel = SC.makeArray(this.get('selection'));
984
+ if (!sel || sel.get('length') === 0) return NO ;
985
+
986
+ // let the delegate decide what to actually delete. If this returns an
987
+ // empty array or null, just do nothing.
988
+ sel = this.invokeDelegateMethod(this.delegate, 'collectionViewShouldDeleteContent', this, sel) ;
989
+ sel = SC.makeArray(sel) ; // ensure this is an array
990
+ if (!sel || sel.get('length') === 0) return YES ;
991
+
992
+ // now have the delegate (or us) perform the deletion. The collection
993
+ // view implements a default version of this method.
994
+ this.invokeDelegateMethod(this.delegate, 'collectionViewDeleteContent', this, sel) ;
995
+ return YES ;
996
+ },
997
+
998
+ /**
999
+ Default implementation of the delegate method.
1000
+
1001
+ This method will delete the passed items from the content array using
1002
+ standard array methods. This is often suitable if you are using an
1003
+ array controller or a real array for your content.
1004
+
1005
+ @param view {SC.CollectionView} this
1006
+ @param sel {Array} the items to delete
1007
+ @returns {Boolean} YES if the deletion was a success.
1008
+ */
1009
+ collectionViewDeleteContent: function(view, sel) {
1010
+
1011
+ // get the content. Bail if this cannot be used as an array.
1012
+ var content = this.get('content') ;
1013
+ if (!content) return NO; // nothing to do
1014
+
1015
+ // determine the method to use
1016
+ var hasDestroyObject = SC.$type(content.destroyObject) === SC.T_FUNCTION ;
1017
+ var hasRemoveObject = SC.$type(content.removeObject) === SC.T_FUNCTION ;
1018
+ if (!hasDestroyObject && !hasRemoveObject) return NO; // nothing to do
1019
+
1020
+ // suspend property notifications and remove the objects...
1021
+ if (content.beginPropertyChanges) content.beginPropertyChanges();
1022
+ var idx = sel.get('length') ;
1023
+ while(--idx >= 0) {
1024
+ var item = sel.objectAt(idx) ;
1025
+ if (hasDestroyObject) {
1026
+ content.destroyObject(item);
1027
+ } else {
1028
+ content.removeObject(item);
1029
+ }
1030
+ }
1031
+ // begin notifying again...
1032
+ if (content.endPropertyChanges) content.endPropertyChanges() ;
1033
+
1034
+ return YES ; // done!
1035
+ },
1036
+
1037
+ // ......................................
1038
+ // EVENT HANDLING
1039
+ //
1040
+
1041
+ /** @private */
1042
+ keyDown: function(evt) {
1043
+ // console.log('keyDown called on %@'.fmt(this));
1044
+ return this.interpretKeyEvents(evt) ;
1045
+ },
1046
+
1047
+ /** @private */
1048
+ keyUp: function() { return true; },
1049
+
1050
+ /** @private
1051
+ Handle select all keyboard event.
1052
+ */
1053
+ selectAll: function(evt) {
1054
+ var content = (this.get('content') || []).slice() ;
1055
+ this.selectItems(content, NO) ;
1056
+ return YES ;
1057
+ },
1058
+
1059
+ /** @private
1060
+ Handle delete keyboard event.
1061
+ */
1062
+ deleteBackward: function(evt) {
1063
+ // console.log('deleteBackward called on %@ with evt %@'.fmt(this, evt));
1064
+ return this.deleteSelection() ;
1065
+ },
1066
+
1067
+ /** @private
1068
+ Handle delete keyboard event.
1069
+ */
1070
+ deleteForward: function(evt) {
1071
+ // console.log('deleteForward called on %@ with evt %@'.fmt(this, evt));
1072
+ return this.deleteSelection() ;
1073
+ },
1074
+
1075
+ /** @private
1076
+ Selects the same item on the next row or moves down one if itemsPerRow = 1
1077
+ */
1078
+ moveDown: function(sender, evt) {
1079
+ this.selectNextItem(false, this.get('itemsPerRow') || 1) ;
1080
+ return true ;
1081
+ },
1082
+
1083
+ /** @private
1084
+ Selects the same item on the next row or moves up one if itemsPerRow = 1
1085
+ */
1086
+ moveUp: function(sender, evt) {
1087
+ this.selectPreviousItem(false, this.get('itemsPerRow') || 1) ;
1088
+ return true ;
1089
+ },
1090
+
1091
+ /** @private
1092
+ Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
1093
+ */
1094
+ moveLeft: function(sender, evt) {
1095
+ if ((this.get('itemsPerRow') || 1) > 1) this.selectPreviousItem(false, 1) ;
1096
+ return true ;
1097
+ },
1098
+
1099
+ /** @private
1100
+ Selects the next item if itemsPerRow > 1. Otherwise does nothing.
1101
+ */
1102
+ moveRight: function(sender, evt) {
1103
+ if ((this.get('itemsPerRow') || 1) > 1) this.selectNextItem(false, 1) ;
1104
+ return true ;
1105
+ },
1106
+
1107
+ /** @private */
1108
+ moveDownAndModifySelection: function(sender, evt) {
1109
+ this.selectNextItem(true, this.get('itemsPerRow') || 1) ;
1110
+ return true ;
1111
+ },
1112
+
1113
+ /** @private */
1114
+ moveUpAndModifySelection: function(sender, evt) {
1115
+ this.selectPreviousItem(true, this.get('itemsPerRow') || 1) ;
1116
+ return true ;
1117
+ },
1118
+
1119
+ /** @private
1120
+ Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
1121
+ */
1122
+ moveLeftAndModifySelection: function(sender, evt) {
1123
+ if ((this.get('itemsPerRow') || 1) > 1) this.selectPreviousItem(true, 1) ;
1124
+ return true ;
1125
+ },
1126
+
1127
+ /** @private
1128
+ Selects the next item if itemsPerRow > 1. Otherwise does nothing.
1129
+ */
1130
+ moveRightAndModifySelection: function(sender, evt) {
1131
+ if ((this.get('itemsPerRow') || 1) > 1) this.selectNextItem(true, 1) ;
1132
+ return true ;
1133
+ },
1134
+
1135
+ /** @private
1136
+ Handles mouse down events on the collection view or on any of its
1137
+ children.
1138
+
1139
+ The default implementation of this method can handle a wide variety
1140
+ of user behaviors depending on how you have configured the various
1141
+ options for the collection view.
1142
+
1143
+ @param ev {Event} the mouse down event
1144
+ @returns {Boolean} Usually YES.
1145
+ */
1146
+ mouseDown: function(ev) {
1147
+ // console.log('%@.mouseDown(%@)'.fmt(this, ev));
1148
+ // console.log(ev.originalEvent);
1149
+
1150
+ // When the user presses the mouse down, we don't do much just yet.
1151
+ // Instead, we just need to save a bunch of state about the mouse down
1152
+ // so we can choose the right thing to do later.
1153
+
1154
+ // save the original mouse down event for use in dragging.
1155
+ this._mouseDownEvent = ev ;
1156
+
1157
+ // Toggle selection only triggers on mouse up. Do nothing.
1158
+ if (this.useToggleSelection) return true;
1159
+
1160
+ // Make sure that saved mouseDown state is always reset in case we do
1161
+ // not get a paired mouseUp. (Only happens if subclass does not call us
1162
+ // like it should)
1163
+ this._mouseDownAt = this._shouldSelect = this._shouldDeselect =
1164
+ this._shouldReselect = this._refreshSelection = false;
1165
+
1166
+ // debugger ;
1167
+ // find the actual view the mouse was pressed down on. This will call
1168
+ // hitTest() on item views so they can implement non-square detection
1169
+ // modes. -- once we have an item view, get its content object as well.
1170
+ var mouseDownView = (this._mouseDownView = this.itemViewForEvent(ev));
1171
+ var mouseDownContent =
1172
+ (this._mouseDownContent = mouseDownView ? mouseDownView.get('content') : null);
1173
+
1174
+ // become first responder if possible.
1175
+ this.becomeFirstResponder() ;
1176
+
1177
+ // console.log(mouseDownView);
1178
+
1179
+ // recieved a mouseDown on the collection element, but not on one of the
1180
+ // childItems... unless we do not allow empty selections, set it to empty.
1181
+ if (!mouseDownView) {
1182
+ if (this.get('allowDeselectAll')) this.selectItems([], false);
1183
+ return true ;
1184
+ }
1185
+
1186
+ // collection some basic setup info
1187
+ var selection = this.get('selection') || [] ;
1188
+ var isSelected = (selection.indexOf(mouseDownContent) !== -1) ;
1189
+ var modifierKeyPressed = ev.ctrlKey || ev.metaKey ;
1190
+ if (mouseDownView.checkboxView && (SC.Event.element(ev) == ev.checkboxView.rootElement)) {
1191
+ modifierKeyPressed = true ;
1192
+ }
1193
+ this._modifierKeyPressed = modifierKeyPressed ;
1194
+
1195
+ this._mouseDownAt = Date.now();
1196
+
1197
+ // holding down a modifier key while clicking a selected item should
1198
+ // deselect that item...deselect and bail.
1199
+ if (modifierKeyPressed && isSelected) {
1200
+ this._shouldDeselect = mouseDownContent;
1201
+ // if the shiftKey was pressed, then we want to extend the selection
1202
+ // from the last selected item
1203
+ } else if (ev.shiftKey && selection.get('length') > 0) {
1204
+ selection = this._findSelectionExtendedByShift(selection, mouseDownContent) ;
1205
+ this.selectItems(selection) ;
1206
+
1207
+ // If no modifier key was pressed, then clicking on the selected item
1208
+ // should clear the selection and reselect only the clicked on item.
1209
+ } else if (!modifierKeyPressed && isSelected) {
1210
+ this._shouldReselect = mouseDownContent;
1211
+
1212
+ // Otherwise, if selecting on mouse down, simply select the clicked on
1213
+ // item, adding it to the current selection if a modifier key was pressed.
1214
+ } else {
1215
+ if (this.get("selectOnMouseDown")){
1216
+ this.selectItems(mouseDownContent, modifierKeyPressed);
1217
+ } else this._shouldSelect = mouseDownContent ;
1218
+ }
1219
+
1220
+ // saved for extend by shift ops.
1221
+ this._previousMouseDownContent = mouseDownContent;
1222
+
1223
+ return true;
1224
+ },
1225
+
1226
+ /** @private */
1227
+ mouseUp: function(ev) {
1228
+
1229
+ var canAct = this.get('actOnSelect') ;
1230
+ var view = this.itemViewForEvent(ev) ;
1231
+ var content, selection;
1232
+
1233
+ if (this.useToggleSelection) {
1234
+ if (!view) return ; // do nothing when clicked outside of elements
1235
+
1236
+ // determine if item is selected. If so, then go on.
1237
+ selection = this.get('selection') || [] ;
1238
+ content = (view) ? view.get('content') : null ;
1239
+ var isSelected = selection.include(content) ;
1240
+ if (isSelected) {
1241
+ this.deselectItems([content]) ;
1242
+ } else this.selectItems([content],true) ;
1243
+
1244
+ } else {
1245
+ content = (view) ? view.get('content') : null ;
1246
+
1247
+ // this will be set if the user simply clicked on an unselected item and
1248
+ // selectOnMouseDown was NO.
1249
+ if (this._shouldSelect) this.selectItems(this._shouldSelect, this._modifierKeyPressed);
1250
+
1251
+ // This is true if the user clicked on a selected item with a modifier
1252
+ // key pressed.
1253
+ if (this._shouldDeselect) this.deselectItems(this._shouldDeselect);
1254
+
1255
+ // This is true if the user clicked on a selected item without a
1256
+ // modifier-key pressed. When this happens we try to begin editing
1257
+ // on the content. If that is not allowed, then simply clear the
1258
+ // selection and reselect the clicked on item.
1259
+ if (this._shouldReselect) {
1260
+
1261
+ // - contentValueIsEditable is true
1262
+ var canEdit = this.get('contentValueIsEditable') ;
1263
+
1264
+ // - the user clicked on an item that was already selected
1265
+ // - is the only item selected
1266
+ if (canEdit) {
1267
+ var sel = this.get('selection') ;
1268
+ canEdit = sel && (sel.get('length') === 1) && (sel.objectAt(0) === this._shouldReselect) ;
1269
+ }
1270
+
1271
+ // - the item view responds to contentHitTest() and returns YES.
1272
+ // - the item view responds to beginEditing and returns YES.
1273
+ if (canEdit) {
1274
+ var itemView = this.itemViewForContent(this._shouldReselect) ;
1275
+ canEdit = itemView && (!itemView.contentHitTest || itemView.contentHitTest(ev)) ;
1276
+ canEdit = (canEdit && itemView.beginEditing) ? itemView.beginEditing() : NO ;
1277
+ }
1278
+
1279
+ // if cannot edit, just reselect
1280
+ if (!canEdit) this.selectItems(this._shouldReselect,false) ;
1281
+ }
1282
+
1283
+ this._cleanupMouseDown() ;
1284
+ }
1285
+
1286
+ this._mouseDownEvent = null ;
1287
+ if (canAct) this._action(ev, view) ;
1288
+
1289
+ return false; // bubble event to allow didDoubleClick to be called...
1290
+ },
1291
+
1292
+ /** @private */
1293
+ _cleanupMouseDown: function() {
1294
+ this._mouseDownAt = this._shouldDeselect = this._shouldReselect = this._refreshSelection = this._shouldSelect = false;
1295
+ this._mouseDownEvent = this._mouseDownContent = this._mouseDownView = null ;
1296
+ },
1297
+
1298
+ /** @private */
1299
+ mouseMoved: function(ev) {
1300
+ var view = this.itemViewForEvent(ev) ;
1301
+ // handle hover events.
1302
+ if(this._lastHoveredItem && ((view === null) || (view != this._lastHoveredItem)) && this._lastHoveredItem.mouseOut) {
1303
+ this._lastHoveredItem.mouseOut(ev);
1304
+ }
1305
+ this._lastHoveredItem = view ;
1306
+ if (view && view.mouseOver) view.mouseOver(ev) ;
1307
+ },
1308
+
1309
+ /** @private */
1310
+ mouseOut: function(ev) {
1311
+
1312
+ var view = this._lastHoveredItem ;
1313
+ this._lastHoveredItem = null ;
1314
+ if (view && view.didMouseOut) view.didMouseOut(ev) ;
1315
+ },
1316
+
1317
+ /** @private */
1318
+ doubleClick: function(ev) {
1319
+ var view = this.itemViewForEvent(ev) ;
1320
+ if (view) {
1321
+ this._action(view, ev) ;
1322
+ return true ;
1323
+ } else return false ;
1324
+ },
1325
+
1326
+ /** @private */
1327
+ _findSelectionExtendedByShift: function(selection, mouseDownContent) {
1328
+ var content = this.get('content');
1329
+
1330
+ // bounds of the collection...
1331
+ var contentLowerBounds = 0;
1332
+ var contentUpperBounds = (content.get('length') - 1);
1333
+
1334
+ var selectionBeginIndex = content.indexOf(selection[0]) ;
1335
+ var selectionEndIndex = content.indexOf(selection[selection.length-1]) ;
1336
+
1337
+ var previousMouseDownIndex = content.indexOf(this._previousMouseDownContent);
1338
+ // _previousMouseDownContent couldn't be found... either it hasn't been set yet or the record has been deleted by the user
1339
+ // fall back to the first selected item.
1340
+ if (previousMouseDownIndex == -1) previousMouseDownIndex = selectionBeginIndex;
1341
+
1342
+ var currentMouseDownIndex = content.indexOf(mouseDownContent);
1343
+ // sanity check...
1344
+ if (currentMouseDownIndex == -1) throw "Unable to extend selection to an item that's not in the content array!";
1345
+
1346
+ // clicked before the current selection set... extend it's beginning...
1347
+ if (currentMouseDownIndex < selectionBeginIndex) {
1348
+ selectionBeginIndex = currentMouseDownIndex;
1349
+ }
1350
+
1351
+ // clicked after the current selection set... extend it's ending...
1352
+ if (currentMouseDownIndex > selectionEndIndex) {
1353
+ selectionEndIndex = currentMouseDownIndex;
1354
+ }
1355
+
1356
+ // clicked inside the selection set... need to determine where the last
1357
+ // selection was and use that as an anchor.
1358
+ if ((currentMouseDownIndex > selectionBeginIndex) && (currentMouseDownIndex < selectionEndIndex)) {
1359
+ if (currentMouseDownIndex === previousMouseDownIndex) {
1360
+ selectionBeginIndex = currentMouseDownIndex;
1361
+ selectionEndIndex = currentMouseDownIndex;
1362
+ } else if (currentMouseDownIndex > previousMouseDownIndex) {
1363
+ selectionBeginIndex = previousMouseDownIndex;
1364
+ selectionEndIndex = currentMouseDownIndex;
1365
+ } else if (currentMouseDownIndex < previousMouseDownIndex){
1366
+ selectionBeginIndex = currentMouseDownIndex;
1367
+ selectionEndIndex = previousMouseDownIndex;
1368
+ }
1369
+ }
1370
+
1371
+ // slice doesn't include the last index passed... silly..
1372
+ selectionEndIndex++;
1373
+
1374
+ // shouldn't need to sanity check that the selection is in bounds due to
1375
+ // the indexOf checks above...I'll have faith that indexOf hasn't lied to
1376
+ // me...
1377
+ return content.slice(selectionBeginIndex, selectionEndIndex);
1378
+ },
1379
+
1380
+ /** @private
1381
+ Finds the next selectable item, up to content length, by asking the
1382
+ delegate. If a non-selectable item is found, the index is skipped. If
1383
+ no item is found, selection index is returned unmodified.
1384
+
1385
+ @param {Integer} proposedIndex the desired index to select
1386
+ @returns {Integer} the next selectable index. This will always be in the range of the bottom of the current selection index and the proposed index.
1387
+ @private
1388
+ */
1389
+ _findNextSelectableItemFromIndex: function(proposedIndex) {
1390
+ var content = this.get('content');
1391
+ var contentLength = content.get('length');
1392
+ var bottom = this._indexOfSelectionTop();
1393
+
1394
+ while (proposedIndex < contentLength &&
1395
+ this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, content.objectAt(proposedIndex)) === NO) {
1396
+ proposedIndex++;
1397
+ }
1398
+ return (proposedIndex < contentLength) ? proposedIndex : bottom;
1399
+ },
1400
+
1401
+ /** @private
1402
+ Finds the previous selectable item, up to the first item, by asking the
1403
+ delegate. If a non-selectable item is found, the index is skipped. If
1404
+ no item is found, selection index is returned unmodified.
1405
+
1406
+ @param {Integer} proposedIndex the desired index to select
1407
+ @returns {Integer} the previous selectable index. This will always be in the range of the top of the current selection index and the proposed index.
1408
+ @private
1409
+ */
1410
+ _findPreviousSelectableItemFromIndex: function(proposedIndex) {
1411
+ var content = this.get('content');
1412
+ var contentLength = content.get('length');
1413
+ var top = this._indexOfSelectionTop();
1414
+
1415
+ while (proposedIndex >= 0 &&
1416
+ this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, content.objectAt(proposedIndex)) === NO) {
1417
+ proposedIndex--;
1418
+ }
1419
+ return (proposedIndex >= 0) ? proposedIndex : top ;
1420
+ },
1421
+
1422
+ /** @private
1423
+ if content value is editable and we have one item selected, then edit.
1424
+ otherwise, invoke action.
1425
+ */
1426
+ insertNewline: function() {
1427
+ var sel, itemView;
1428
+ if (this.get('contentValueIsEditable')) {
1429
+ sel = this.get('selection') ;
1430
+ if (sel && sel.get('length') === 1) {
1431
+ itemView = this.itemViewForContent(sel.objectAt(0)) ;
1432
+ if (itemView && itemView.beginEditing) {
1433
+ this.scrollToItemView(itemView) ;
1434
+ itemView.beginEditing() ;
1435
+ }
1436
+ }
1437
+
1438
+ // invoke action!
1439
+ } else {
1440
+ sel = this.get('selection') ;
1441
+ itemView = (sel && sel.get('length') === 1) ? this.itemViewForContent(sel.objectAt(0)) : null ;
1442
+ this._action(itemView, null) ;
1443
+ }
1444
+
1445
+ return YES ; // always handle
1446
+ },
1447
+
1448
+ // ......................................
1449
+ // FIRST RESPONDER
1450
+ //
1451
+
1452
+ /** @private
1453
+ Called whenever the collection becomes first responder.
1454
+ Adds the focused class to the element.
1455
+ */
1456
+ didBecomeFirstResponder: function() {
1457
+ // console.log('didBecomeFirstResponder called on %@'.fmt(this));
1458
+ this.$().addClass('focus') ;
1459
+ },
1460
+
1461
+ /** @private */
1462
+ willLoseFirstResponder: function() {
1463
+ // console.log('willLoseFirstResponder called on %@'.fmt(this));
1464
+ this.$().removeClass('focus');
1465
+ },
1466
+
1467
+ // ......................................
1468
+ // DRAG AND DROP SUPPORT
1469
+ //
1470
+
1471
+ /**
1472
+ When reordering its content, the collection view will store its reorder
1473
+ data using this special data type. The data type is unique to each
1474
+ collection view instance. You can use this data type to detect reorders
1475
+ if necessary.
1476
+
1477
+ @property
1478
+ @type String
1479
+ */
1480
+ reorderDataType: function() {
1481
+ return 'SC.CollectionView.Reorder.%@'.fmt(SC.guidFor(this)) ;
1482
+ }.property().cacheable(),
1483
+
1484
+ /**
1485
+ This property is set to the array of content objects that are the subject
1486
+ of a drag whenever a drag is initiated on the collection view. You can
1487
+ consult this property when implementing your collection view delegate
1488
+ methods, but otherwise you should not use this property in your code.
1489
+
1490
+ Note that drag content will always appear in the same order the content
1491
+ appears in the source content array.
1492
+
1493
+ @type Array
1494
+ */
1495
+ dragContent: null,
1496
+
1497
+ /**
1498
+ This property is set to the proposed insertion index during a call to
1499
+ collectionViewValidateDragOperation(). Your delegate implementations can change
1500
+ the value of this property to enforce a drop some in some other location.
1501
+
1502
+ @type Number
1503
+ */
1504
+ proposedInsertionIndex: null,
1505
+
1506
+ /**
1507
+ This property is set to the proposed drop operation during a call to
1508
+ collectionViewValidateDragOperation(). Your delegate implementations can change
1509
+ the value of this property to enforce a different type of drop operation.
1510
+
1511
+ @type Number
1512
+ @field
1513
+ */
1514
+ proposedDropOperation: null,
1515
+
1516
+ /** @private
1517
+ mouseDragged event handler. Initiates a drag if the following conditions
1518
+ are met:
1519
+
1520
+ - collectionViewShouldBeginDrag() returns YES *OR*
1521
+ - the above method is not implemented and canReorderContent is true.
1522
+ - the dragDataTypes property returns a non-empty array
1523
+ - a mouse down event was saved by the mouseDown method.
1524
+ */
1525
+ mouseDragged: function(ev) {
1526
+ // if the mouse down event was cleared, there is nothing to do; return.
1527
+ if (this._mouseDownEvent === null) return YES ;
1528
+
1529
+ // Don't do anything unless the user has been dragging for 123msec
1530
+ if ((Date.now() - this._mouseDownAt) < 123) return YES ;
1531
+
1532
+ // OK, they must be serious, decide if a drag will be allowed.
1533
+ if (this.invokeDelegateMethod(this.delegate, 'collectionViewShouldBeginDrag', this)) {
1534
+
1535
+ // First, get the selection to drag. Drag an array of selected
1536
+ // items appearing in this collection, in the order of the
1537
+ // collection.
1538
+ //
1539
+ // Set this to the dragContent property.
1540
+ var content = this.get('content') || [] ;
1541
+ var dragContent;
1542
+
1543
+ // if we don't select on mouse down, then the selection has not been
1544
+ // updated to whatever the user clicked. Instead use
1545
+ // mouse down content.
1546
+ if (!this.get("selectOnMouseDown")) {
1547
+ dragContent = [this._mouseDownContent];
1548
+ } else {
1549
+ dragContent = this.get('selection').sort(function(a,b) {
1550
+ a = content.indexOf(a) ;
1551
+ b = content.indexOf(b) ;
1552
+ return (a<b) ? -1 : ((a>b) ? 1 : 0) ;
1553
+ });
1554
+ }
1555
+
1556
+ this.set('dragContent', dragContent) ;
1557
+
1558
+ // Get the set of data types supported by the delegate. If this returns
1559
+ // a null or empty array and reordering content is not also supported
1560
+ // then do not start the drag.
1561
+ if (this.get('dragDataTypes').get('length') > 0) {
1562
+ // Build the drag view to use for the ghost drag. This
1563
+ // should essentially contain any visible drag items.
1564
+ // var view = this.ghostViewFor(dragContent) ;
1565
+ var view = this.dragViewFor(dragContent) ;
1566
+
1567
+ // Initiate the drag
1568
+ SC.Drag.start({
1569
+ event: this._mouseDownEvent,
1570
+ source: this,
1571
+ dragView: view,
1572
+ ghost: NO,
1573
+ slideBack: YES,
1574
+ dataSource: this
1575
+ }) ;
1576
+
1577
+ // Also use this opportunity to clean up since mouseUp won't
1578
+ // get called.
1579
+ this._cleanupMouseDown() ;
1580
+ this._lastInsertionIndex = null ;
1581
+
1582
+ // Drag was not allowed by the delegate, so bail.
1583
+ } else {
1584
+ this.set('dragContent', null) ;
1585
+ }
1586
+
1587
+ return YES ;
1588
+ }
1589
+ },
1590
+
1591
+ /**
1592
+ Implements the drag data source protocol for the collection view. This
1593
+ property will consult the collection view delegate if one is provided. It
1594
+ will also do the right thing if you have set canReorderContent to YES.
1595
+
1596
+ @property
1597
+ @type Array
1598
+ */
1599
+ dragDataTypes: function() {
1600
+ // console.log('dragDataTypes called on %@'.fmt(this));
1601
+
1602
+ // consult delegate.
1603
+ var ret = this.invokeDelegateMethod(this.delegate, 'collectionViewDragDataTypes', this) ;
1604
+ var canReorderContent = this.get('canReorderContent') ;
1605
+
1606
+ // bail if ret returned null or empty array and cannot reorder.
1607
+ if ((!ret || ret.get('length')===0) && !canReorderContent) return [];
1608
+
1609
+ // add reorder type if needed.
1610
+ if (canReorderContent) {
1611
+ ret = (ret) ? ret.slice() : [] ;
1612
+
1613
+ var key = this.get('reorderDataType') ;
1614
+ if (ret.indexOf(key) < 0) ret.push(key) ;
1615
+ }
1616
+ return ret ;
1617
+
1618
+ //data: { "_mouseDownContent": dragContent }
1619
+
1620
+ }.property(),
1621
+
1622
+ /**
1623
+ Implements the drag data source protocol method. The implementation of
1624
+ this method will consult the collection view delegate if one has been
1625
+ provided. It also respects the canReoderContent method.
1626
+ */
1627
+ dragDataForType: function(drag, dataType) {
1628
+
1629
+ // if this is a reorder, then return drag content.
1630
+ if (this.get('canReorderContent')) {
1631
+ if (dataType === this.get('reorderDataType')) {
1632
+ // console.log('dragContent is %@'.fmt(this.get('dragContent')));
1633
+ return this.get('dragContent') ;
1634
+ }
1635
+ }
1636
+
1637
+ // otherwise, just pass along to the delegate.
1638
+ return this.invokeDelegateMethod(this.delegate, 'collectionViewDragDataForType', this, drag, dataType) ;
1639
+ },
1640
+
1641
+ /**
1642
+ Implements the SC.DropTarget interface. The default implementation will
1643
+ consult the collection view delegate, if you implement those methods.
1644
+ */
1645
+ computeDragOperations: function(drag, evt) {
1646
+ // console.log('computeDragOperations called on %@'.fmt(this));
1647
+
1648
+ // the proposed drag operation is DRAG_REORDER only if we can reorder
1649
+ // content and the drag contains reorder content.
1650
+ var op = SC.DRAG_NONE ;
1651
+ if (this.get('canReorderContent')) {
1652
+ var types = drag.get('dataTypes') ;
1653
+ if (types.indexOf(this.get('reorderDataType')) >= 0) {
1654
+ op = SC.DRAG_REORDER ;
1655
+ }
1656
+ }
1657
+
1658
+ // Now pass this onto the delegate.
1659
+ // op = this.invokeDelegateMethod(this.delegate, 'collectionViewValidateDrop', this, drag, SC.DROP_ANY, -1, op) ;
1660
+ op = this.invokeDelegateMethod(this.delegate, 'collectionViewComputeDragOperations', this, drag, op) ;
1661
+
1662
+ if (op & SC.DRAG_REORDER) op = SC.DRAG_MOVE ;
1663
+
1664
+ // return
1665
+ return op ;
1666
+ },
1667
+
1668
+ /** @private
1669
+ Determines the allowed drop operation insertion point, operation type,
1670
+ and the drag operation to be performed. Used by dragUpdated() and
1671
+ performDragOperation().
1672
+ */
1673
+ _computeDropOperationState: function(drag, evt) {
1674
+
1675
+ // get the insertion index for this location. This can be computed
1676
+ // by a subclass using whatever method. This method is not expected to
1677
+ // do any data valdidation, just to map the location to an insertion
1678
+ // index.
1679
+ var loc = drag.get('location') ;
1680
+ loc = this.convertFrameFromView(loc, null) ;
1681
+ var dropOp = SC.DROP_BEFORE ;
1682
+ var dragOp = SC.DRAG_NONE ;
1683
+
1684
+ // STEP 1: Try with a DROP_ON option -- send straight to delegate if
1685
+ // supported by view.
1686
+
1687
+ // get the computed insertion index and possibly drop operation.
1688
+ // prefer to drop ON.
1689
+ var idx = this.insertionIndexForLocation(loc, SC.DROP_ON) ;
1690
+ if (SC.$type(idx) === SC.T_ARRAY) {
1691
+ dropOp = idx[1] ; // order matters here
1692
+ idx = idx[0] ;
1693
+ }
1694
+
1695
+ // if the return drop operation is DROP_ON, then just check it with the
1696
+ // delegate method. If the delegate method does not support dropping on,
1697
+ // then it will return DRAG_NONE, in which case we will try again with
1698
+ // drop before.
1699
+ if (dropOp == SC.DROP_ON) {
1700
+ // console.log('dropOp === SC.DROP_ON');
1701
+
1702
+ // Now save the insertion index and the dropOp. This may be changed by
1703
+ // the collection delegate.
1704
+ this.set('proposedInsertionIndex', idx) ;
1705
+ this.set('proposedDropOperation', dropOp) ;
1706
+ dragOp = this.invokeDelegateMethod(this.delegate, 'collectionViewValidateDragOperation', this, drag, dragOp, idx, dropOp) ;
1707
+ idx = this.get('proposedInsertionIndex') ;
1708
+ dropOp = this.get('proposedDropOperation') ;
1709
+ this._dropInsertionIndex = this._dropOperation = null ;
1710
+
1711
+ // The delegate is OK with a drop on also, so just return.
1712
+ if (dragOp !== SC.DRAG_NONE) {
1713
+ // console.log('[idx, dropOp, dragOp] is [%@, %@, %@]'.fmt(idx, dropOp, dragOp));
1714
+ return [idx, dropOp, dragOp] ;
1715
+
1716
+ // The delegate is NOT OK with a drop on, try to get the insertion
1717
+ // index again, but this time prefer SC.DROP_BEFORE, then let the
1718
+ // rest of the method run...
1719
+ } else {
1720
+ dropOp = SC.DROP_BEFORE ;
1721
+ idx = this.insertionIndexForLocation(loc, SC.DROP_BEFORE) ;
1722
+ if (SC.$type(idx) === SC.T_ARRAY) {
1723
+ dropOp = idx[1] ; // order matters here
1724
+ idx = idx[0] ;
1725
+ }
1726
+ }
1727
+ }
1728
+
1729
+ // console.log('this is a redorder drag, dropOp is %@'.fmt(dropOp)) ;
1730
+
1731
+ // if this is a reorder drag, set the proposed op to SC.DRAG_REORDER and
1732
+ // validate the insertion point. This only works if the insertion point
1733
+ // is DROP_BEFORE. DROP_ON is not handled by reordering content.
1734
+ if ((idx >= 0) && this.get('canReorderContent') && (dropOp === SC.DROP_BEFORE)) {
1735
+
1736
+ var objects = drag.dataForType(this.get('reorderDataType')) ;
1737
+ if (objects) {
1738
+ // console.log('found objects');
1739
+ var content = this.get('content') || [] ;
1740
+ // console.log('objects is %@, content is %@'.fmt(objects, content));
1741
+
1742
+ // if the insertion index is in between two items in the drag itself,
1743
+ // then this is not allowed. Either use the last insertion index or
1744
+ // find the first index that is not in between selections. Stop when
1745
+ // we get to the beginning.
1746
+ var previousContent = (idx > 0) ? content.objectAt(idx-1) : null ;
1747
+ var nextContent = (idx < content.get('length')) ? content.objectAt(idx) : null;
1748
+
1749
+ var isPreviousInDrag = (previousContent) ? objects.indexOf(previousContent)>=0 : NO;
1750
+ var isNextInDrag = (nextContent) ? objects.indexOf(nextContent)>=0 : NO;
1751
+
1752
+ if (isPreviousInDrag && isNextInDrag) {
1753
+ if (SC.none(this._lastInsertionIndex)) {
1754
+ while((idx >= 0) && (objects.indexOf(content.objectAt(idx)) >= 0)) {
1755
+ idx-- ;
1756
+ }
1757
+ } else idx = this._lastInsertionIndex ;
1758
+ }
1759
+
1760
+ // If we found a valid insertion point to reorder at, then set the op
1761
+ // to custom DRAG_REORDER.
1762
+ if (idx >= 0) dragOp = SC.DRAG_REORDER ;
1763
+ }
1764
+ }
1765
+
1766
+ // console.log('the dragOp is %@'.fmt(dragOp)) ;
1767
+
1768
+ // Now save the insertion index and the dropOp. This may be changed by
1769
+ // the collection delegate.
1770
+ this.set('proposedInsertionIndex', idx) ;
1771
+ this.set('proposedDropOperation', dropOp) ;
1772
+ // dragOp = this.invokeDelegateMethod(this.delegate, 'collectionViewValidateDrop', this, drag, dropOp, idx, dragOp) ;
1773
+ dragOp = this.invokeDelegateMethod(this.delegate, 'collectionViewValidateDragOperation', this, drag, dragOp, idx, dropOp) ;
1774
+ idx = this.get('proposedInsertionIndex') ;
1775
+ dropOp = this.get('proposedDropOperation') ;
1776
+ this._dropInsertionIndex = this._dropOperation = null ;
1777
+
1778
+ // return generated state
1779
+ return [idx, dropOp, dragOp] ;
1780
+ },
1781
+
1782
+ /**
1783
+ Implements the SC.DropTarget interface. The default implementation will
1784
+ determine the drop location and then consult the collection view delegate
1785
+ if you implement those methods. Otherwise it will handle reordering
1786
+ content on its own.
1787
+ */
1788
+ dragUpdated: function(drag, evt) {
1789
+ // console.log('dragUpdated called in %@'.fmt(this));
1790
+ var state = this._computeDropOperationState(drag, evt) ;
1791
+ // console.log('state is %@'.fmt(state));
1792
+ var idx = state[0], dropOp = state[1], dragOp = state[2] ;
1793
+
1794
+ // if the insertion index or dropOp have changed, update the insertion point
1795
+ if (dragOp !== SC.DRAG_NONE) {
1796
+ if ((this._lastInsertionIndex !== idx) || (this._lastDropOperation !== dropOp)) {
1797
+ var itemView = this.itemViewForContent(this.get('content').objectAt(idx));
1798
+ this.showInsertionPoint(itemView, dropOp) ;
1799
+ }
1800
+
1801
+ this._lastInsertionIndex = idx ;
1802
+ this._lastDropOperation = dropOp ;
1803
+ } else {
1804
+ this.hideInsertionPoint() ;
1805
+ this._lastInsertionIndex = this._lastDropOperation = null ;
1806
+ }
1807
+
1808
+ // Normalize drag operation to the standard kinds accepted by the drag system.
1809
+ return (dragOp & SC.DRAG_REORDER) ? SC.DRAG_MOVE : dragOp;
1810
+ },
1811
+
1812
+ /**
1813
+ Implements the SC.DropTarget protocol. Hides any visible insertion
1814
+ point and clears some cached values.
1815
+ */
1816
+ dragExited: function() {
1817
+ this.hideInsertionPoint() ;
1818
+ this._lastInsertionIndex = this._lastDropOperation = null ;
1819
+ },
1820
+
1821
+ // /**
1822
+ // Implements the SC.DropTarget protocol. Hides any visible insertion
1823
+ // point and clears some cached values.
1824
+ // */
1825
+ // dragEnded: function() {
1826
+ // this.hideInsertionPoint() ;
1827
+ // this._lastInsertionIndex = this._lastDropOperation = null ;
1828
+ // },
1829
+
1830
+ /**
1831
+ Implements the SC.DropTarget protocol.
1832
+ */
1833
+ acceptDragOperation: function(drag, op) { return YES; },
1834
+
1835
+ /**
1836
+ Implements the SC.DropTarget protocol. Consults the collection view
1837
+ delegate to actually perform the operation unless the operation is
1838
+ reordering content.
1839
+ */
1840
+ performDragOperation: function(drag, op) {
1841
+ // console.log('performDragOperation called on %@ with drag.dataTypes %@'.fmt(this, drag.get('dataTypes')));
1842
+ // console.log('op is %@'.fmt(SC.Drag.inspectOperation(op)));
1843
+ // Get the correct insertion point, drop operation, etc.
1844
+ var state = this._computeDropOperationState(drag, null, op) ;
1845
+ var idx = state[0], dropOp = state[1], dragOp = state[2] ;
1846
+ // console.log('dragOp is %@'.fmt(SC.Drag.inspectOperation(dragOp)));
1847
+
1848
+ // The dragOp is the kinds of ops allowed. The drag operation must
1849
+ // be included in that set.
1850
+ if (dragOp & SC.DRAG_REORDER) {
1851
+ op = (op & SC.DRAG_MOVE) ? SC.DRAG_REORDER : SC.DRAG_NONE ;
1852
+ } else {
1853
+ op = op & dragOp ;
1854
+ }
1855
+ // console.log('after processing, op is %@'.fmt(SC.Drag.inspectOperation(op)));
1856
+
1857
+ // If no allowed drag operation could be found, just return.
1858
+ if (op === SC.DRAG_NONE) return op;
1859
+
1860
+ // Some operation is allowed through, give the delegate a chance to
1861
+ // handle it.
1862
+ // var performed = this.invokeDelegateMethod(this.delegate, 'collectionViewAcceptDrop', this, drag, dropOp, idx, op) ;
1863
+ var performed = this.invokeDelegateMethod(this.delegate, 'collectionViewPerformDragOperation', this, drag, op, idx, dropOp) ;
1864
+
1865
+ // console.log('performed is %@'.fmt(SC.Drag.inspectOperation(performed)));
1866
+ // If the delegate did not handle the drag (i.e. returned SC.DRAG_NONE),
1867
+ // and the op type is REORDER, then do the reorder here.
1868
+ // console.log('performed & SC.DRAG_NONE is %@, op & SC.DRAG_REORDER is %@'.fmt((performed & SC.DRAG_NONE),(op & SC.DRAG_REORDER)));
1869
+ if ((performed === SC.DRAG_NONE) && (op & SC.DRAG_REORDER)) {
1870
+ var objects = drag.dataForType(this.get('reorderDataType')) ;
1871
+ // console.log('objects is %@'.fmt(objects));
1872
+ if (!objects) return SC.DRAG_NONE ;
1873
+
1874
+ var content = this.get('content') ;
1875
+ content.beginPropertyChanges(); // suspend notifications
1876
+
1877
+ // find the old index and remove it.
1878
+ var old ;
1879
+ var objectsIdx = objects.get('length') ;
1880
+ while(--objectsIdx >= 0) {
1881
+ var obj = objects.objectAt(objectsIdx) ;
1882
+ old = content.indexOf(obj) ;
1883
+ if (old >= 0) content.removeAt(old) ;
1884
+ if ((old >= 0) && (old < idx)) idx--; //adjust idx
1885
+ }
1886
+
1887
+ // now insert objects at new location
1888
+ content.replace(idx, 0, objects) ;
1889
+ content.endPropertyChanges(); // restart notifications
1890
+
1891
+ var outOfDateIndices = Math.min(old, idx) ;
1892
+ if (outOfDateIndices < 0 ) outOfDateIndices = 0 ;
1893
+
1894
+ this.rowHeightsDidChangeInRange({ start: outOfDateIndices, length: content.get('length')-outOfDateIndices }) ;
1895
+
1896
+ // make the op into its actual value
1897
+ op = SC.DRAG_MOVE ;
1898
+ }
1899
+
1900
+ return op;
1901
+ },
1902
+
1903
+ /**
1904
+ Default delegate method implementation, returns YES if canReorderContent
1905
+ is also true.
1906
+ */
1907
+ collectionViewShouldBeginDrag: function(view) {
1908
+ return this.get('canReorderContent') ;
1909
+ },
1910
+
1911
+ // concludeDragOperation: function(op, drag) {
1912
+ // this.hideInsertionPoint() ;
1913
+ // this._lastInsertionIndex = null ;
1914
+ // },
1915
+
1916
+ /**
1917
+ If some state changes that causes the row height for a range of rows
1918
+ then you should call this method to notify the view that it needs to
1919
+ recalculate the row heights for the collection.
1920
+
1921
+ Anytime your content array changes, the rows are invalidated
1922
+ automatically so you only need to use this for cases where your rows
1923
+ heights may change without changing the content array itself.
1924
+
1925
+ If all rows heights have changed, you can pass null to invalidate the
1926
+ whole range.
1927
+
1928
+ @param {Range} range or null.
1929
+ @returns {SC.CollectionView} reciever
1930
+ */
1931
+ rowHeightsDidChangeInRange: function(range) {},
1932
+
1933
+ /**
1934
+ The insertion orientation. This is used to determine which
1935
+ dimension we should pay attention to when determining insertion point for
1936
+ a mouse click.
1937
+
1938
+ {{{
1939
+ SC.HORIZONTAL_ORIENTATION: look at the X dimension only
1940
+ SC.VERTICAL_ORIENTATION: look at the Y dimension only
1941
+ }}}
1942
+ */
1943
+ insertionOrientation: SC.HORIZONTAL_ORIENTATION,
1944
+
1945
+ /**
1946
+ Get the preferred insertion point for the given location, including
1947
+ an insertion preference of before or after the named index.
1948
+
1949
+ You can implement this method in a subclass if you like to perform a
1950
+ more efficient check. The default implementation will loop through the
1951
+ item views looking for the first view to "switch sides" in the orientation
1952
+ you specify.
1953
+
1954
+ This method should return an array with two values. The first value is
1955
+ the insertion point index and the second value is the drop operation,
1956
+ which should be one of SC.DROP_BEFORE or SC.DROP_ON.
1957
+
1958
+ The preferred drop operation passed in should be used as a hint as to
1959
+ the type of operation the drag and drop could would prefer to receive.
1960
+ If the dropOperaiton is SC.DROP_ON, then you should return a DROP_ON
1961
+ mode if possible. Otherwise, you should never return DROP_ON.
1962
+
1963
+ For compatibility, you can also return just the insertion index. If you
1964
+ do this, then the collction view will assume the drop operation is
1965
+ SC.DROP_BEFORE.
1966
+
1967
+ If an insertion is NOT allowed, you should return -1 as the insertion
1968
+ point. In this case, the drop operation will be ignored.
1969
+
1970
+ @param loc {Point} the mouse location.
1971
+ @param dropOperation {DropOp} the preferred drop operation.
1972
+ @returns {Array} [proposed drop index, drop operation]
1973
+ */
1974
+ insertionIndexForLocation: function(loc, dropOperation) {
1975
+ var content = this.get('content') ;
1976
+ var f, itemView, curSide, lastSide = null ;
1977
+ var orient = this.get('insertionOrientation') ;
1978
+ var ret= null ;
1979
+ for(var idx=0; ((ret === null) && (idx<content.length)); idx++) {
1980
+ itemView = this.itemViewForContent(content.objectAt(idx));
1981
+ f = this.convertFrameFromView(itemView.get('frame'), itemView) ;
1982
+
1983
+ // if we are a horizontal orientation, look for the first item that
1984
+ // will "switch sides" on the x path an the maxY is greater than Y.
1985
+ // This assumes you will flow top to bottom, but it should work if you
1986
+ // flow LTR or RTL.
1987
+ if (orient == SC.HORIZONTAL_ORIENTATION) {
1988
+ if (SC.maxY(f) > loc.y) {
1989
+ curSide = (SC.maxX(f) < loc.x) ? -1 : 1 ;
1990
+ } else curSide = null ;
1991
+
1992
+ // if we are a vertical orientation, look for the first item that
1993
+ // will "swithc sides" on the y path and the maxX is greater than X.
1994
+ // This assumes you will flow LTR, but it should work if you flow
1995
+ // bottom to top or top to bottom.
1996
+ } else {
1997
+ if (SC.minX(f) < loc.x) {
1998
+ curSide = (SC.maxY(f) < loc.y) ? -1 : 1 ;
1999
+ } else curSide = null ;
2000
+ }
2001
+
2002
+ // if we "switched" sides then return this item view.
2003
+ if (curSide !== null) {
2004
+
2005
+ // OK, we found an item view, while we have this data, decide if
2006
+ // we should insert before or after the view
2007
+ if ((lastSide !== null) && (curSide != lastSide)) {
2008
+ ret = idx ;
2009
+ if (orient == SC.HORIZONTAL_ORIENTATION) {
2010
+ if (SC.midX(f) < loc.x) ret++ ;
2011
+ } else {
2012
+ if (SC.midY(f) < loc.y) ret++ ;
2013
+ }
2014
+ }
2015
+ lastSide =curSide ;
2016
+ }
2017
+ }
2018
+
2019
+ // Handle some edge cases
2020
+ if ((ret === null) || (ret < 0)) ret = 0 ;
2021
+ if (ret > content.length) ret = content.length ;
2022
+
2023
+ // Done. Phew. Return.
2024
+ return ret;
2025
+ },
2026
+
2027
+ /**
2028
+ Override to show the insertion point during a drag.
2029
+
2030
+ Called during a drag to show the insertion point. Passed value is the
2031
+ item view that you should display the insertion point before. If the
2032
+ passed value is null, then you should show the insertion point AFTER that
2033
+ last item view returned by the itemViews property.
2034
+
2035
+ Once this method is called, you are guaranteed to also recieve a call to
2036
+ hideInsertionPoint() at some point in the future.
2037
+
2038
+ The default implementation of this method does nothing.
2039
+
2040
+ @param itemView {SC.ClassicView} view the insertion point should appear directly before. If null, show insertion point at end.
2041
+ @param dropOperation {Number} the drop operation. will be SC.DROP_BEFORE or SC.DROP_ON
2042
+
2043
+ @returns {void}
2044
+ */
2045
+ showInsertionPoint: function(itemView, dropOperation) {
2046
+ return (dropOperation === SC.DROP_BEFORE) ? this.showInsertionPointBefore(itemView) : this.hideInsertionPoint() ;
2047
+ },
2048
+
2049
+ /**
2050
+ @deprecated
2051
+
2052
+ Show the insertion point during a drag before the named item view.
2053
+
2054
+ This method has been deprecated in favor of the more generic
2055
+ showInsertionPoint() which can be used to show drops occurring both on
2056
+ and before an itemView. If you do not implement showInsertionPoint()
2057
+ yourself, the default implementation will call this method whenever the
2058
+ drop operation is SC.DROP_BEFORE.
2059
+
2060
+ @param itemView {SC.ClassicView} the item view to show before.
2061
+ @returns {void}
2062
+ */
2063
+ showInsertionPointBefore: function(itemView) {},
2064
+
2065
+ /**
2066
+ Override to hide the insertion point when a drag ends.
2067
+
2068
+ Called during a drag to hide the insertion point. This will be called
2069
+ when the user exits the view, cancels the drag or completes the drag. It
2070
+ will not be called when the insertion point changes during a drag.
2071
+
2072
+ You should expect to receive one or more calls to
2073
+ showInsertionPointBefore() during a drag followed by at least one call to
2074
+ this method at the end. Your method should not raise an error if it is
2075
+ called more than once.
2076
+
2077
+ @returns {void}
2078
+ */
2079
+ hideInsertionPoint: function() {},
2080
+
2081
+ dragViewFor: function(dragContent) {
2082
+ var view = SC.View.create() ;
2083
+
2084
+ var ary = dragContent ;
2085
+ for (var idx=0, len=ary.length; idx<len; idx++) {
2086
+ var itemView = this.itemViewForContent(ary[idx]) ;
2087
+ if (itemView) view.$().append(itemView.rootElement.cloneNode(true)) ;
2088
+ }
2089
+
2090
+ var frame = this.convertFrameToView(this.get('clippingFrame'), null) ;
2091
+ view.adjust({ top: frame.y, left: frame.x, width: frame.width, height: frame.height }) ;
2092
+ return view ;
2093
+ },
2094
+
2095
+ /**
2096
+ Default delegate method implementation, returns YES if isSelectable
2097
+ is also true.
2098
+ */
2099
+ collectionViewShouldSelectItem: function(view, item) {
2100
+ return this.get('isSelectable') ;
2101
+ },
2102
+
2103
+ // ......................................
2104
+ // INTERNAL
2105
+ //
2106
+
2107
+ /** @private
2108
+ Perform the action. Supports legacy behavior as well as newer style
2109
+ action dispatch.
2110
+ */
2111
+ _action: function(view, evt) {
2112
+ // console.log('_action invoked on %@ with view %@, evt %@'.fmt(this, view, evt));
2113
+ var action = this.get('action');
2114
+ var target = this.get('target') || null;
2115
+ // console.log('action %@, target %@'.fmt(action, target));
2116
+ if (action) {
2117
+ // if the action is a function, just call it
2118
+ if (SC.$type(action) == SC.T_FUNCTION) return this.action(view, evt) ;
2119
+
2120
+ // otherwise, use the new sendAction style
2121
+ var pane = this.get('pane') ;
2122
+ if (pane) pane.rootResponder.sendAction(action, target, this, pane);
2123
+ // SC.app.sendAction(action, target, this) ;
2124
+
2125
+ // if no action is specified, then trigger the support action,
2126
+ // if supported.
2127
+ } else if (!view) {
2128
+ return ; // nothing to do
2129
+
2130
+ // if the target view has its own internal action handler,
2131
+ // trigger that.
2132
+ } else if (SC.$type(view._action) == SC.T_FUNCTION) {
2133
+ return view._action(evt) ;
2134
+
2135
+ // otherwise call the action method to support older styles.
2136
+ } else if (SC.$type(view.action) == SC.T_FUNCTION) {
2137
+ return view.action(evt) ;
2138
+ }
2139
+ }
2140
+
2141
+ });