sproutit-sproutcore 1.0.20090721145236 → 1.0.20090721145251

Sign up to get free protection for your applications and to get access to all the features.
Files changed (933) hide show
  1. data/Rakefile +189 -54
  2. data/VERSION.yml +5 -0
  3. data/frameworks/sproutcore/Buildfile +64 -0
  4. data/frameworks/sproutcore/HISTORY +682 -0
  5. data/frameworks/sproutcore/README +23 -0
  6. data/frameworks/sproutcore/apps/docs/core.js +27 -0
  7. data/frameworks/sproutcore/apps/docs/english.lproj/loading.rhtml +9 -0
  8. data/frameworks/sproutcore/apps/docs/english.lproj/main_page.js +22 -0
  9. data/frameworks/sproutcore/apps/docs/english.lproj/strings.js +15 -0
  10. data/frameworks/sproutcore/apps/docs/main.js +30 -0
  11. data/frameworks/sproutcore/apps/tests/controllers/detail.js +16 -0
  12. data/frameworks/sproutcore/apps/tests/controllers/source.js +29 -0
  13. data/frameworks/sproutcore/apps/tests/controllers/target.js +26 -0
  14. data/frameworks/sproutcore/apps/tests/controllers/targets.js +86 -0
  15. data/frameworks/sproutcore/apps/tests/controllers/tests.js +33 -0
  16. data/frameworks/sproutcore/apps/tests/core.js +133 -0
  17. data/frameworks/sproutcore/apps/tests/data_source.js +96 -0
  18. data/frameworks/sproutcore/apps/tests/english.lproj/loading.rhtml +9 -0
  19. data/frameworks/sproutcore/apps/tests/english.lproj/main_page.css +39 -0
  20. data/frameworks/sproutcore/apps/tests/english.lproj/main_page.js +232 -0
  21. data/frameworks/sproutcore/apps/tests/english.lproj/strings.js +26 -0
  22. data/frameworks/sproutcore/apps/tests/fixtures/target.js +87 -0
  23. data/frameworks/sproutcore/apps/tests/fixtures/test.js +44 -0
  24. data/frameworks/sproutcore/apps/tests/main.js +28 -0
  25. data/frameworks/sproutcore/apps/tests/models/target.js +92 -0
  26. data/frameworks/sproutcore/apps/tests/models/test.js +48 -0
  27. data/frameworks/sproutcore/apps/tests/states/no_targets.js +26 -0
  28. data/frameworks/sproutcore/apps/tests/states/ready.js +56 -0
  29. data/frameworks/sproutcore/apps/tests/states/ready_detail.js +41 -0
  30. data/frameworks/sproutcore/apps/tests/states/ready_empty.js +48 -0
  31. data/frameworks/sproutcore/apps/tests/states/ready_list.js +41 -0
  32. data/frameworks/sproutcore/apps/tests/states/ready_loading.js +44 -0
  33. data/frameworks/sproutcore/apps/tests/states/ready_no_tests.js +31 -0
  34. data/frameworks/sproutcore/apps/tests/states/start.js +39 -0
  35. data/frameworks/sproutcore/apps/tests/tests/controllers/detail.js +15 -0
  36. data/frameworks/sproutcore/apps/tests/tests/controllers/source.js +15 -0
  37. data/frameworks/sproutcore/apps/tests/tests/controllers/target.js +15 -0
  38. data/frameworks/sproutcore/apps/tests/tests/controllers/targets.js +15 -0
  39. data/frameworks/sproutcore/apps/tests/tests/controllers/tests.js +15 -0
  40. data/frameworks/sproutcore/apps/tests/tests/models/target.js +15 -0
  41. data/frameworks/sproutcore/apps/tests/tests/models/test.js +15 -0
  42. data/frameworks/sproutcore/apps/tests/tests/views/offset_checkbox.js +15 -0
  43. data/frameworks/sproutcore/apps/tests/views/offset_checkbox.js +26 -0
  44. data/frameworks/sproutcore/apps/welcome/core.js +23 -0
  45. data/frameworks/sproutcore/apps/welcome/english.lproj/loading.rhtml +8 -0
  46. data/frameworks/sproutcore/apps/welcome/english.lproj/main_page.js +43 -0
  47. data/frameworks/sproutcore/apps/welcome/english.lproj/strings.js +15 -0
  48. data/frameworks/sproutcore/apps/welcome/main.js +36 -0
  49. data/frameworks/sproutcore/design/Record State Table.numbers +0 -0
  50. data/frameworks/sproutcore/frameworks/datastore/core.js +14 -0
  51. data/frameworks/sproutcore/frameworks/datastore/data_sources/cascade.js +113 -0
  52. data/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +273 -0
  53. data/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +311 -0
  54. data/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures_with_queries.js +238 -0
  55. data/frameworks/sproutcore/frameworks/datastore/debug/json.js +71 -0
  56. data/frameworks/sproutcore/frameworks/datastore/debug/standard_setup.js +96 -0
  57. data/frameworks/sproutcore/frameworks/datastore/fixtures/author_fixtures.js +2503 -0
  58. data/frameworks/sproutcore/frameworks/datastore/fixtures/sample.js +17 -0
  59. data/frameworks/sproutcore/frameworks/datastore/models/fetched_attribute.js +92 -0
  60. data/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +54 -0
  61. data/frameworks/sproutcore/frameworks/datastore/models/record.js +561 -0
  62. data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +423 -0
  63. data/frameworks/sproutcore/frameworks/datastore/system/many_array.js +158 -0
  64. data/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +488 -0
  65. data/frameworks/sproutcore/frameworks/datastore/system/query.js +979 -0
  66. data/frameworks/sproutcore/frameworks/datastore/system/record_array.js +287 -0
  67. data/frameworks/sproutcore/frameworks/datastore/system/store.js +2007 -0
  68. data/frameworks/sproutcore/frameworks/datastore/tests/data_sources/fixtures.js +121 -0
  69. data/frameworks/sproutcore/frameworks/datastore/tests/integration/contact_model.js +114 -0
  70. data/frameworks/sproutcore/frameworks/datastore/tests/integration/mail_model.js +91 -0
  71. data/frameworks/sproutcore/frameworks/datastore/tests/integration/test_runner_model.js +56 -0
  72. data/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +94 -0
  73. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/core_methods.js +30 -0
  74. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/destroy.js +73 -0
  75. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/normalize.js +238 -0
  76. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/readAttribute.js +48 -0
  77. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/refresh.js +42 -0
  78. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/storeDidChangeProperties.js +138 -0
  79. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/unknownProperty.js +46 -0
  80. data/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +71 -0
  81. data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +204 -0
  82. data/frameworks/sproutcore/frameworks/datastore/tests/system/many_array/core_methods.js +178 -0
  83. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/chain.js +40 -0
  84. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChanges.js +117 -0
  85. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChangesFromNestedStore.js +135 -0
  86. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/dataHashDidChange.js +110 -0
  87. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/discardChanges.js +99 -0
  88. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readDataHash.js +180 -0
  89. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readEditableDataHash.js +126 -0
  90. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/removeDataHash.js +163 -0
  91. data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/writeDataHash.js +166 -0
  92. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare_records.js +126 -0
  93. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation.js +165 -0
  94. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation_of_records.js +82 -0
  95. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/find_all.js +362 -0
  96. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/parsing.js +170 -0
  97. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/record_type_is.js +43 -0
  98. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/registered_comparisons.js +60 -0
  99. data/frameworks/sproutcore/frameworks/datastore/tests/system/query/registered_query_extensions.js +67 -0
  100. data/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +164 -0
  101. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/cancelRecord.js +54 -0
  102. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitChangesFromNestedStore.js +126 -0
  103. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +126 -0
  104. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/core_methods.js +73 -0
  105. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/createRecord.js +72 -0
  106. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataHashDidChange.js +78 -0
  107. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +249 -0
  108. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/destroyRecord.js +106 -0
  109. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/init.js +21 -0
  110. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushChanges.js +61 -0
  111. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/readDataHash.js +74 -0
  112. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/readEditableDataHash.js +74 -0
  113. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/recordDidChange.js +74 -0
  114. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/removeDataHash.js +144 -0
  115. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/retrieveRecord.js +137 -0
  116. data/frameworks/sproutcore/frameworks/datastore/tests/system/store/writeDataHash.js +130 -0
  117. data/frameworks/sproutcore/frameworks/debug/core.js +61 -0
  118. data/frameworks/sproutcore/frameworks/deprecated/core.js +59 -0
  119. data/frameworks/sproutcore/frameworks/deprecated/lib/button_views.rb +330 -0
  120. data/frameworks/sproutcore/frameworks/deprecated/lib/collection_view.rb +83 -0
  121. data/frameworks/sproutcore/frameworks/deprecated/lib/core_views.rb +326 -0
  122. data/frameworks/sproutcore/frameworks/deprecated/lib/form_views.rb +253 -0
  123. data/frameworks/sproutcore/frameworks/deprecated/lib/index.rhtml +75 -0
  124. data/frameworks/sproutcore/frameworks/deprecated/lib/menu_views.rb +93 -0
  125. data/frameworks/sproutcore/frameworks/deprecated/server/rails_server.js +80 -0
  126. data/frameworks/sproutcore/frameworks/deprecated/server/rest_server.js +178 -0
  127. data/frameworks/sproutcore/frameworks/deprecated/server/server.js +673 -0
  128. data/frameworks/sproutcore/frameworks/deprecated/system/animator.js +679 -0
  129. data/frameworks/sproutcore/frameworks/deprecated/system/binding.js +36 -0
  130. data/frameworks/sproutcore/frameworks/deprecated/system/browser.js +75 -0
  131. data/frameworks/sproutcore/frameworks/deprecated/system/classic_responder.js +312 -0
  132. data/frameworks/sproutcore/frameworks/deprecated/system/event.js +58 -0
  133. data/frameworks/sproutcore/frameworks/deprecated/system/globals.js +20 -0
  134. data/frameworks/sproutcore/frameworks/deprecated/system/misc.js +58 -0
  135. data/frameworks/sproutcore/frameworks/deprecated/system/node_descriptor.js +72 -0
  136. data/frameworks/sproutcore/frameworks/deprecated/system/object.js +122 -0
  137. data/frameworks/sproutcore/frameworks/deprecated/system/path_module.js +432 -0
  138. data/frameworks/sproutcore/frameworks/deprecated/system/string.js +107 -0
  139. data/frameworks/sproutcore/frameworks/deprecated/tests/application/application.rhtml +125 -0
  140. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/clippingFrame.rhtml +401 -0
  141. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/frame.rhtml +357 -0
  142. data/frameworks/sproutcore/frameworks/deprecated/tests/views/classic_view/isVisibleInWindow.rhtml +147 -0
  143. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/base.rhtml +298 -0
  144. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/incremental_rendering.rhtml +260 -0
  145. data/frameworks/sproutcore/frameworks/deprecated/tests/views/collection/source_list_rendering.rhtml +143 -0
  146. data/frameworks/sproutcore/frameworks/deprecated/tests/views/popup_button.rhtml +128 -0
  147. data/frameworks/sproutcore/frameworks/deprecated/tests/views/text_field.rhtml +37 -0
  148. data/frameworks/sproutcore/frameworks/deprecated/views/collection.js +24 -0
  149. data/frameworks/sproutcore/frameworks/designer/coders/design.js +29 -0
  150. data/frameworks/sproutcore/frameworks/designer/coders/localization.js +27 -0
  151. data/frameworks/sproutcore/frameworks/designer/coders/object.js +347 -0
  152. data/frameworks/sproutcore/frameworks/designer/controllers/page_design.js +102 -0
  153. data/frameworks/sproutcore/frameworks/designer/css/css_rule.js +22 -0
  154. data/frameworks/sproutcore/frameworks/designer/css/css_style.js +29 -0
  155. data/frameworks/sproutcore/frameworks/designer/css/css_style_sheet.js +201 -0
  156. data/frameworks/sproutcore/frameworks/designer/ext/page.js +86 -0
  157. data/frameworks/sproutcore/frameworks/designer/ext/view.js +38 -0
  158. data/frameworks/sproutcore/frameworks/designer/views/controls/button.js +17 -0
  159. data/frameworks/sproutcore/frameworks/designer/views/designer.js +569 -0
  160. data/frameworks/sproutcore/frameworks/designer/views/label.js +16 -0
  161. data/frameworks/sproutcore/frameworks/designer/views/mixins/button.js +11 -0
  162. data/frameworks/sproutcore/frameworks/designer/views/tab.js +16 -0
  163. data/frameworks/sproutcore/frameworks/desktop/core.js +6 -0
  164. data/frameworks/sproutcore/frameworks/desktop/debug/drag.js +41 -0
  165. data/frameworks/sproutcore/frameworks/desktop/english.lproj/alert.css +56 -0
  166. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/a_sample_image.jpg +0 -0
  167. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/apple-logo1.jpeg +0 -0
  168. data/frameworks/sproutcore/frameworks/desktop/english.lproj/debug/iframe.html +23 -0
  169. data/frameworks/sproutcore/frameworks/desktop/english.lproj/disclosure.css +71 -0
  170. data/frameworks/sproutcore/frameworks/desktop/english.lproj/drag.css +6 -0
  171. data/frameworks/sproutcore/frameworks/desktop/english.lproj/icons.css +943 -0
  172. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_222222.png +0 -0
  173. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_454545.png +0 -0
  174. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_888888.png +0 -0
  175. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/mini_ffffff.png +0 -0
  176. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/icons/shared.png +0 -0
  177. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/indicator.gif +0 -0
  178. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/panels/sprite-x.png +0 -0
  179. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/panels/sprite-y.png +0 -0
  180. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/sc-theme-sprite.png +0 -0
  181. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/000000.png +0 -0
  182. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/standard_fade/ffffff.png +0 -0
  183. data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/sticky-note.png +0 -0
  184. data/frameworks/sproutcore/frameworks/desktop/english.lproj/list_item.css +209 -0
  185. data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +100 -0
  186. data/frameworks/sproutcore/frameworks/desktop/english.lproj/modal.css +5 -0
  187. data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +95 -0
  188. data/frameworks/sproutcore/frameworks/desktop/english.lproj/picker.css +39 -0
  189. data/frameworks/sproutcore/frameworks/desktop/english.lproj/progress.css +31 -0
  190. data/frameworks/sproutcore/frameworks/desktop/english.lproj/radio.css +10 -0
  191. data/frameworks/sproutcore/frameworks/desktop/english.lproj/scroller.css +26 -0
  192. data/frameworks/sproutcore/frameworks/desktop/english.lproj/segmented.css +141 -0
  193. data/frameworks/sproutcore/frameworks/desktop/english.lproj/separator.css +19 -0
  194. data/frameworks/sproutcore/frameworks/desktop/english.lproj/slider.css +62 -0
  195. data/frameworks/sproutcore/frameworks/desktop/english.lproj/split.css +70 -0
  196. data/frameworks/sproutcore/frameworks/desktop/english.lproj/split_divider.css +9 -0
  197. data/frameworks/sproutcore/frameworks/desktop/english.lproj/strings.js +14 -0
  198. data/frameworks/sproutcore/frameworks/desktop/english.lproj/tab.css +12 -0
  199. data/frameworks/sproutcore/frameworks/desktop/english.lproj/toolbar.css +6 -0
  200. data/frameworks/sproutcore/frameworks/desktop/mixins/border.js +53 -0
  201. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_group.js +22 -0
  202. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +61 -0
  203. data/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +283 -0
  204. data/frameworks/sproutcore/frameworks/desktop/mixins/scrollable.js +247 -0
  205. data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +408 -0
  206. data/frameworks/sproutcore/frameworks/desktop/panes/menu.js +651 -0
  207. data/frameworks/sproutcore/frameworks/desktop/panes/modal.js +68 -0
  208. data/frameworks/sproutcore/frameworks/desktop/panes/palette.js +63 -0
  209. data/frameworks/sproutcore/frameworks/desktop/panes/panel.js +184 -0
  210. data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +400 -0
  211. data/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +46 -0
  212. data/frameworks/sproutcore/frameworks/desktop/protocols/drag_data_source.js +39 -0
  213. data/frameworks/sproutcore/frameworks/desktop/protocols/drag_source.js +81 -0
  214. data/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +175 -0
  215. data/frameworks/sproutcore/frameworks/desktop/protocols/responder.js +280 -0
  216. data/frameworks/sproutcore/frameworks/desktop/system/drag.js +827 -0
  217. data/frameworks/sproutcore/frameworks/desktop/system/key_bindings.js +40 -0
  218. data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +641 -0
  219. data/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +187 -0
  220. data/frameworks/sproutcore/frameworks/desktop/tests/integration/dialog.js +43 -0
  221. data/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/methods.js +10 -0
  222. data/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +152 -0
  223. data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/methods.js +55 -0
  224. data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +59 -0
  225. data/frameworks/sproutcore/frameworks/desktop/tests/panes/palette/methods.js +10 -0
  226. data/frameworks/sproutcore/frameworks/desktop/tests/panes/palette/ui.js +35 -0
  227. data/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/methods.js +10 -0
  228. data/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +40 -0
  229. data/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/methods.js +10 -0
  230. data/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +84 -0
  231. data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/methods.js +10 -0
  232. data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +38 -0
  233. data/frameworks/sproutcore/frameworks/desktop/tests/views/button/methods.js +45 -0
  234. data/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +159 -0
  235. data/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/methods.js +144 -0
  236. data/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/ui.js +99 -0
  237. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/content.js +249 -0
  238. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/deleteSelection.js +82 -0
  239. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/deselect.js +199 -0
  240. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/itemViewForContentIndex.js +288 -0
  241. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/layerIdFor.js +65 -0
  242. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/length.js +88 -0
  243. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/mouse.js +165 -0
  244. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/nowShowing.js +121 -0
  245. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/reload.js +177 -0
  246. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/select.js +240 -0
  247. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selectNextItem.js +191 -0
  248. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selectPreviousItem.js +197 -0
  249. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selection.js +141 -0
  250. data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/ui_diagram.js +182 -0
  251. data/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/methods.js +10 -0
  252. data/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/ui.js +64 -0
  253. data/frameworks/sproutcore/frameworks/desktop/tests/views/grid/methods.js +10 -0
  254. data/frameworks/sproutcore/frameworks/desktop/tests/views/grid/ui.js +10 -0
  255. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +183 -0
  256. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowHeightForContentIndex.js +133 -0
  257. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowOffsetForContentIndex.js +132 -0
  258. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_outline.js +56 -0
  259. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +167 -0
  260. data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_simple.js +127 -0
  261. data/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +284 -0
  262. data/frameworks/sproutcore/frameworks/desktop/tests/views/menu_item/methods.js +10 -0
  263. data/frameworks/sproutcore/frameworks/desktop/tests/views/menu_item/ui.js +44 -0
  264. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/methods.js +128 -0
  265. data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +240 -0
  266. data/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +113 -0
  267. data/frameworks/sproutcore/frameworks/desktop/tests/views/radio/ui.js +202 -0
  268. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +139 -0
  269. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +111 -0
  270. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroller/methods.js +102 -0
  271. data/frameworks/sproutcore/frameworks/desktop/tests/views/scroller/ui.js +70 -0
  272. data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +95 -0
  273. data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +222 -0
  274. data/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/methods.js +81 -0
  275. data/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/ui.js +100 -0
  276. data/frameworks/sproutcore/frameworks/desktop/tests/views/separator.js +37 -0
  277. data/frameworks/sproutcore/frameworks/desktop/tests/views/source_list/methods.js +10 -0
  278. data/frameworks/sproutcore/frameworks/desktop/tests/views/source_list/ui.js +10 -0
  279. data/frameworks/sproutcore/frameworks/desktop/tests/views/split/methods.js +50 -0
  280. data/frameworks/sproutcore/frameworks/desktop/tests/views/split/ui.js +52 -0
  281. data/frameworks/sproutcore/frameworks/desktop/tests/views/stacked/ui_comments.js +231 -0
  282. data/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +54 -0
  283. data/frameworks/sproutcore/frameworks/desktop/tests/views/tab/ui.js +88 -0
  284. data/frameworks/sproutcore/frameworks/desktop/tests/views/web/methods.js +10 -0
  285. data/frameworks/sproutcore/frameworks/desktop/tests/views/web/ui.js +110 -0
  286. data/frameworks/sproutcore/frameworks/desktop/views/button.js +331 -0
  287. data/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +105 -0
  288. data/frameworks/sproutcore/frameworks/desktop/views/collection.js +2757 -0
  289. data/frameworks/sproutcore/frameworks/desktop/views/disclosure.js +44 -0
  290. data/frameworks/sproutcore/frameworks/desktop/views/form.js +594 -0
  291. data/frameworks/sproutcore/frameworks/desktop/views/grid.js +201 -0
  292. data/frameworks/sproutcore/frameworks/desktop/views/list.js +540 -0
  293. data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +660 -0
  294. data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +587 -0
  295. data/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +68 -0
  296. data/frameworks/sproutcore/frameworks/desktop/views/progress.js +207 -0
  297. data/frameworks/sproutcore/frameworks/desktop/views/radio.js +332 -0
  298. data/frameworks/sproutcore/frameworks/desktop/views/scene.js +204 -0
  299. data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +690 -0
  300. data/frameworks/sproutcore/frameworks/desktop/views/scroller.js +226 -0
  301. data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +525 -0
  302. data/frameworks/sproutcore/frameworks/desktop/views/select_field.js +331 -0
  303. data/frameworks/sproutcore/frameworks/desktop/views/separator.js +37 -0
  304. data/frameworks/sproutcore/frameworks/desktop/views/slider.js +180 -0
  305. data/frameworks/sproutcore/frameworks/desktop/views/source_list.js +47 -0
  306. data/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +169 -0
  307. data/frameworks/sproutcore/frameworks/desktop/views/split.js +677 -0
  308. data/frameworks/sproutcore/frameworks/desktop/views/split_divider.js +55 -0
  309. data/frameworks/sproutcore/frameworks/desktop/views/stacked.js +101 -0
  310. data/frameworks/sproutcore/frameworks/desktop/views/tab.js +191 -0
  311. data/frameworks/sproutcore/frameworks/desktop/views/thumb.js +49 -0
  312. data/frameworks/sproutcore/frameworks/desktop/views/toolbar.js +49 -0
  313. data/frameworks/sproutcore/frameworks/desktop/views/web.js +86 -0
  314. data/frameworks/sproutcore/frameworks/foundation/TESTING +46 -0
  315. data/frameworks/sproutcore/frameworks/foundation/controllers/array.js +509 -0
  316. data/frameworks/sproutcore/frameworks/foundation/controllers/controller.js +45 -0
  317. data/frameworks/sproutcore/frameworks/foundation/controllers/object.js +323 -0
  318. data/frameworks/sproutcore/frameworks/foundation/controllers/tree.js +109 -0
  319. data/frameworks/sproutcore/frameworks/foundation/core.js +136 -0
  320. data/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +194 -0
  321. data/frameworks/sproutcore/frameworks/foundation/english.lproj/blank.gif +0 -0
  322. data/frameworks/sproutcore/frameworks/foundation/english.lproj/bootstrap.rhtml +68 -0
  323. data/frameworks/sproutcore/frameworks/foundation/english.lproj/button_view.css +55 -0
  324. data/frameworks/sproutcore/frameworks/foundation/english.lproj/core.css +221 -0
  325. data/frameworks/sproutcore/frameworks/foundation/english.lproj/debug/control-test-pane.css +9 -0
  326. data/frameworks/sproutcore/frameworks/foundation/english.lproj/images/sproutcore-logo.png +0 -0
  327. data/frameworks/sproutcore/frameworks/foundation/english.lproj/label.css +30 -0
  328. data/frameworks/sproutcore/frameworks/foundation/english.lproj/static_layout.css +5 -0
  329. data/frameworks/sproutcore/frameworks/foundation/english.lproj/strings.js +15 -0
  330. data/frameworks/sproutcore/frameworks/foundation/english.lproj/text_field.css +45 -0
  331. data/frameworks/sproutcore/frameworks/foundation/english.lproj/view.css +45 -0
  332. data/frameworks/sproutcore/frameworks/foundation/ext/object.js +81 -0
  333. data/frameworks/sproutcore/frameworks/foundation/ext/run_loop.js +158 -0
  334. data/frameworks/sproutcore/frameworks/foundation/fixtures/file_exists.json +1 -0
  335. data/frameworks/sproutcore/frameworks/foundation/license.js +19 -0
  336. data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +299 -0
  337. data/frameworks/sproutcore/frameworks/foundation/mixins/collection_content.js +171 -0
  338. data/frameworks/sproutcore/frameworks/foundation/mixins/content_display.js +88 -0
  339. data/frameworks/sproutcore/frameworks/foundation/mixins/control.js +352 -0
  340. data/frameworks/sproutcore/frameworks/foundation/mixins/editable.js +146 -0
  341. data/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +462 -0
  342. data/frameworks/sproutcore/frameworks/foundation/mixins/selection_support.js +232 -0
  343. data/frameworks/sproutcore/frameworks/foundation/mixins/static_layout.js +132 -0
  344. data/frameworks/sproutcore/frameworks/foundation/mixins/string.js +251 -0
  345. data/frameworks/sproutcore/frameworks/foundation/mixins/tree_item_content.js +159 -0
  346. data/frameworks/sproutcore/frameworks/foundation/mixins/validatable.js +176 -0
  347. data/frameworks/sproutcore/frameworks/foundation/panes/main.js +47 -0
  348. data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +584 -0
  349. data/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +887 -0
  350. data/frameworks/sproutcore/frameworks/foundation/protocols/inline_editor_delegate.js +84 -0
  351. data/frameworks/sproutcore/frameworks/foundation/system/application.js +36 -0
  352. data/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +492 -0
  353. data/frameworks/sproutcore/frameworks/foundation/system/browser.js +64 -0
  354. data/frameworks/sproutcore/frameworks/foundation/system/builder.js +210 -0
  355. data/frameworks/sproutcore/frameworks/foundation/system/core_query.js +2015 -0
  356. data/frameworks/sproutcore/frameworks/foundation/system/cursor.js +129 -0
  357. data/frameworks/sproutcore/frameworks/foundation/system/datetime.js +729 -0
  358. data/frameworks/sproutcore/frameworks/foundation/system/error.js +93 -0
  359. data/frameworks/sproutcore/frameworks/foundation/system/event.js +853 -0
  360. data/frameworks/sproutcore/frameworks/foundation/system/image_cache.js +433 -0
  361. data/frameworks/sproutcore/frameworks/foundation/system/json.js +440 -0
  362. data/frameworks/sproutcore/frameworks/foundation/system/locale.js +288 -0
  363. data/frameworks/sproutcore/frameworks/foundation/system/page.js +106 -0
  364. data/frameworks/sproutcore/frameworks/foundation/system/ready.js +195 -0
  365. data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +904 -0
  366. data/frameworks/sproutcore/frameworks/foundation/system/request.js +380 -0
  367. data/frameworks/sproutcore/frameworks/foundation/system/responder.js +120 -0
  368. data/frameworks/sproutcore/frameworks/foundation/system/responder_context.js +243 -0
  369. data/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +391 -0
  370. data/frameworks/sproutcore/frameworks/foundation/system/routes.js +487 -0
  371. data/frameworks/sproutcore/frameworks/foundation/system/time.js +478 -0
  372. data/frameworks/sproutcore/frameworks/foundation/system/timer.js +549 -0
  373. data/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +165 -0
  374. data/frameworks/sproutcore/frameworks/foundation/system/utils.js +425 -0
  375. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/array_case.js +182 -0
  376. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/enum_case.js +193 -0
  377. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/null_case.js +64 -0
  378. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/single_case.js +136 -0
  379. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/empty_case.js +82 -0
  380. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/multiple_case.js +111 -0
  381. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/single_case.js +193 -0
  382. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/single_enumerable_case.js +179 -0
  383. data/frameworks/sproutcore/frameworks/foundation/tests/controllers/tree/outline_case.js +108 -0
  384. data/frameworks/sproutcore/frameworks/foundation/tests/debug/control_test_pane/methods.js +10 -0
  385. data/frameworks/sproutcore/frameworks/foundation/tests/debug/control_test_pane/ui.js +113 -0
  386. data/frameworks/sproutcore/frameworks/foundation/tests/integration/creating_views.js +113 -0
  387. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/content.js +195 -0
  388. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/displayProperties.js +89 -0
  389. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/keyEquivalents.js +35 -0
  390. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/control/content.js +168 -0
  391. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/control/displayProperties.js +89 -0
  392. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +128 -0
  393. data/frameworks/sproutcore/frameworks/foundation/tests/mixins/string.js +17 -0
  394. data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/flat_case.js +325 -0
  395. data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/group_case.js +718 -0
  396. data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/outline_case.js +484 -0
  397. data/frameworks/sproutcore/frameworks/foundation/tests/system/builder.js +42 -0
  398. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +1323 -0
  399. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_dimensions.js +387 -0
  400. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_selector.js +405 -0
  401. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/setClass.js +49 -0
  402. data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/within.js +66 -0
  403. data/frameworks/sproutcore/frameworks/foundation/tests/system/datetime.js +151 -0
  404. data/frameworks/sproutcore/frameworks/foundation/tests/system/error.js +41 -0
  405. data/frameworks/sproutcore/frameworks/foundation/tests/system/json.js +14 -0
  406. data/frameworks/sproutcore/frameworks/foundation/tests/system/locale.js +128 -0
  407. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/begin.js +47 -0
  408. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/element.js +44 -0
  409. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/end.js +119 -0
  410. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/get.js +51 -0
  411. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_attr.js +50 -0
  412. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_basic.js +28 -0
  413. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_className.js +179 -0
  414. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_style.js +100 -0
  415. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/init.js +55 -0
  416. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/join.js +28 -0
  417. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/push_text.js +74 -0
  418. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/tag.js +45 -0
  419. data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/update.js +205 -0
  420. data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +127 -0
  421. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/makeKeyPane.js +124 -0
  422. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/makeMainPane.js +68 -0
  423. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/root_responder.js +101 -0
  424. data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/targetForAction.js +238 -0
  425. data/frameworks/sproutcore/frameworks/foundation/tests/system/routes.js +33 -0
  426. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/invalidate.js +38 -0
  427. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/invokeLater.js +201 -0
  428. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/isPaused.js +71 -0
  429. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/performAction.js +67 -0
  430. data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/schedule.js +170 -0
  431. data/frameworks/sproutcore/frameworks/foundation/tests/system/user_defaults.js +27 -0
  432. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/normalizeURL.js +18 -0
  433. data/frameworks/sproutcore/frameworks/foundation/tests/system/utils/range.js +62 -0
  434. data/frameworks/sproutcore/frameworks/foundation/tests/validators/credit_card.js +35 -0
  435. data/frameworks/sproutcore/frameworks/foundation/tests/validators/date.js +23 -0
  436. data/frameworks/sproutcore/frameworks/foundation/tests/validators/number.js +47 -0
  437. data/frameworks/sproutcore/frameworks/foundation/tests/validators/password.js +13 -0
  438. data/frameworks/sproutcore/frameworks/foundation/tests/views/container/methods.js +10 -0
  439. data/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +83 -0
  440. data/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +39 -0
  441. data/frameworks/sproutcore/frameworks/foundation/tests/views/label/ui.js +148 -0
  442. data/frameworks/sproutcore/frameworks/foundation/tests/views/main_pane.js +31 -0
  443. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/append_remove.js +89 -0
  444. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/firstResponder.js +148 -0
  445. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/keyPane.js +133 -0
  446. data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/sendEvent.js +165 -0
  447. data/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/methods.js +76 -0
  448. data/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +250 -0
  449. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/clippingFrame.js +133 -0
  450. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/convertFrames.js +246 -0
  451. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/createChildViews.js +122 -0
  452. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/createLayer.js +97 -0
  453. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/destroyLayer.js +85 -0
  454. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/findLayerInParentLayer.js +52 -0
  455. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/init.js +50 -0
  456. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/insertBefore.js +200 -0
  457. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/isVisible.js +51 -0
  458. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/isVisibleInWindow.js +113 -0
  459. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layer.js +150 -0
  460. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutChildViews.js +162 -0
  461. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutDidChange.js +127 -0
  462. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutStyle.js +328 -0
  463. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/parentViewDidChange.js +67 -0
  464. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/prepareContext.js +166 -0
  465. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/removeChild.js +189 -0
  466. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/render.js +83 -0
  467. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/replaceChild.js +29 -0
  468. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayer.js +146 -0
  469. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayerLocation.js +194 -0
  470. data/frameworks/sproutcore/frameworks/foundation/tests/views/view/viewDidResize.js +185 -0
  471. data/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +125 -0
  472. data/frameworks/sproutcore/frameworks/foundation/validators/date.js +52 -0
  473. data/frameworks/sproutcore/frameworks/foundation/validators/email.js +45 -0
  474. data/frameworks/sproutcore/frameworks/foundation/validators/not_empty.js +33 -0
  475. data/frameworks/sproutcore/frameworks/foundation/validators/number.js +82 -0
  476. data/frameworks/sproutcore/frameworks/foundation/validators/password.js +86 -0
  477. data/frameworks/sproutcore/frameworks/foundation/validators/validator.js +311 -0
  478. data/frameworks/sproutcore/frameworks/foundation/views/container.js +136 -0
  479. data/frameworks/sproutcore/frameworks/foundation/views/field.js +287 -0
  480. data/frameworks/sproutcore/frameworks/foundation/views/image.js +161 -0
  481. data/frameworks/sproutcore/frameworks/foundation/views/label.js +271 -0
  482. data/frameworks/sproutcore/frameworks/foundation/views/text_field.js +257 -0
  483. data/frameworks/sproutcore/frameworks/foundation/views/view.js +2405 -0
  484. data/frameworks/sproutcore/frameworks/mobile/english.lproj/core.css +12 -0
  485. data/frameworks/sproutcore/frameworks/mobile/lib/index.rhtml +126 -0
  486. data/frameworks/sproutcore/frameworks/mobile/system/root_responder.js +109 -0
  487. data/frameworks/sproutcore/frameworks/mobile/tests/views/button/ui.js +9 -0
  488. data/frameworks/sproutcore/frameworks/mobile/views/button.js +190 -0
  489. data/frameworks/sproutcore/frameworks/runtime/README +12 -0
  490. data/frameworks/sproutcore/frameworks/runtime/core.js +856 -0
  491. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/base.js +238 -0
  492. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/indexOf.js +33 -0
  493. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/insertAt.js +121 -0
  494. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/objectAt.js +34 -0
  495. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/popObject.js +50 -0
  496. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/pushObject.js +46 -0
  497. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/rangeObserver.js +371 -0
  498. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeAt.js +100 -0
  499. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeObject.js +49 -0
  500. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +94 -0
  501. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/shiftObject.js +50 -0
  502. data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/unshiftObject.js +47 -0
  503. data/frameworks/sproutcore/frameworks/runtime/license.js +28 -0
  504. data/frameworks/sproutcore/frameworks/runtime/mixins/array.js +613 -0
  505. data/frameworks/sproutcore/frameworks/runtime/mixins/copyable.js +64 -0
  506. data/frameworks/sproutcore/frameworks/runtime/mixins/delegate_support.js +108 -0
  507. data/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +1258 -0
  508. data/frameworks/sproutcore/frameworks/runtime/mixins/freezable.js +104 -0
  509. data/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +1305 -0
  510. data/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +141 -0
  511. data/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +148 -0
  512. data/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +152 -0
  513. data/frameworks/sproutcore/frameworks/runtime/protocols/observable_protocol.js +40 -0
  514. data/frameworks/sproutcore/frameworks/runtime/protocols/sparse_array_delegate.js +131 -0
  515. data/frameworks/sproutcore/frameworks/runtime/system/binding.js +915 -0
  516. data/frameworks/sproutcore/frameworks/runtime/system/enumerator.js +107 -0
  517. data/frameworks/sproutcore/frameworks/runtime/system/index_set.js +1166 -0
  518. data/frameworks/sproutcore/frameworks/runtime/system/object.js +801 -0
  519. data/frameworks/sproutcore/frameworks/runtime/system/range_observer.js +265 -0
  520. data/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +241 -0
  521. data/frameworks/sproutcore/frameworks/runtime/system/selection_set.js +649 -0
  522. data/frameworks/sproutcore/frameworks/runtime/system/set.js +375 -0
  523. data/frameworks/sproutcore/frameworks/runtime/system/sparse_array.js +295 -0
  524. data/frameworks/sproutcore/frameworks/runtime/tests/core/IsEqual.js +56 -0
  525. data/frameworks/sproutcore/frameworks/runtime/tests/core/beget.js +23 -0
  526. data/frameworks/sproutcore/frameworks/runtime/tests/core/clone.js +66 -0
  527. data/frameworks/sproutcore/frameworks/runtime/tests/core/compare.js +44 -0
  528. data/frameworks/sproutcore/frameworks/runtime/tests/core/console.js +16 -0
  529. data/frameworks/sproutcore/frameworks/runtime/tests/core/guidFor.js +147 -0
  530. data/frameworks/sproutcore/frameworks/runtime/tests/core/isArray.js +25 -0
  531. data/frameworks/sproutcore/frameworks/runtime/tests/core/itemType.js +38 -0
  532. data/frameworks/sproutcore/frameworks/runtime/tests/core/keys.js +20 -0
  533. data/frameworks/sproutcore/frameworks/runtime/tests/core/makeArray.js +30 -0
  534. data/frameworks/sproutcore/frameworks/runtime/tests/core/objectForPropertyPath.js +19 -0
  535. data/frameworks/sproutcore/frameworks/runtime/tests/core/tupleForPropertyPath.js +37 -0
  536. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +57 -0
  537. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable.js +611 -0
  538. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +587 -0
  539. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/propertyChanges.js +132 -0
  540. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/registerDependentKeys.js +79 -0
  541. data/frameworks/sproutcore/frameworks/runtime/tests/mixins/propertyChanges.js +80 -0
  542. data/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue/isObservingSuspended.js +55 -0
  543. data/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +265 -0
  544. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/add.js +195 -0
  545. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/clone.js +43 -0
  546. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/contains.js +74 -0
  547. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/create.js +42 -0
  548. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/indexAfter.js +38 -0
  549. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/indexBefore.js +38 -0
  550. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/intersects.js +74 -0
  551. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/max.js +40 -0
  552. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/min.js +40 -0
  553. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/rangeStartForIndex.js +36 -0
  554. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/remove.js +189 -0
  555. data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/without.js +89 -0
  556. data/frameworks/sproutcore/frameworks/runtime/tests/system/object/base.js +135 -0
  557. data/frameworks/sproutcore/frameworks/runtime/tests/system/object/bindings.js +339 -0
  558. data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/create.js +59 -0
  559. data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/destroy.js +75 -0
  560. data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/objectPropertyDidChange.js +117 -0
  561. data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/rangeDidChange.js +110 -0
  562. data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/update.js +65 -0
  563. data/frameworks/sproutcore/frameworks/runtime/tests/system/run_loop.js +120 -0
  564. data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/add.js +92 -0
  565. data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/copy.js +17 -0
  566. data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/indexSetForSource.js +85 -0
  567. data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/isEqual.js +60 -0
  568. data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/remove.js +87 -0
  569. data/frameworks/sproutcore/frameworks/runtime/tests/system/set.js +292 -0
  570. data/frameworks/sproutcore/frameworks/runtime/tests/system/sparse_array.js +122 -0
  571. data/frameworks/sproutcore/frameworks/testing/core.js +196 -0
  572. data/frameworks/sproutcore/frameworks/testing/english.lproj/additions.css +8 -0
  573. data/frameworks/sproutcore/frameworks/testing/english.lproj/runner.css +126 -0
  574. data/frameworks/sproutcore/frameworks/testing/english.lproj/testsuite.css +131 -0
  575. data/frameworks/sproutcore/frameworks/testing/extras.js +17 -0
  576. data/frameworks/sproutcore/frameworks/testing/jquery.js +3559 -0
  577. data/frameworks/sproutcore/frameworks/testing/qunit.js +827 -0
  578. data/frameworks/sproutcore/frameworks/testing/system/dump.js +205 -0
  579. data/frameworks/sproutcore/frameworks/testing/system/equiv.js +201 -0
  580. data/frameworks/sproutcore/frameworks/testing/system/plan.js +691 -0
  581. data/frameworks/sproutcore/frameworks/testing/system/runner.js +209 -0
  582. data/frameworks/sproutcore/frameworks/testing/system/suite.js +228 -0
  583. data/frameworks/sproutcore/frameworks/testing/utils.js +62 -0
  584. data/frameworks/sproutcore/lib/index.rhtml +121 -0
  585. data/frameworks/sproutcore/license.js +28 -0
  586. data/frameworks/sproutcore/themes/empty_theme/tests/mini_icons.rhtml +69 -0
  587. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/button.css +41 -0
  588. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/core.css +8 -0
  589. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/backButton.png +0 -0
  590. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/blueButton.png +0 -0
  591. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/cancel.png +0 -0
  592. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/grayButton.png +0 -0
  593. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/leftButton.png +0 -0
  594. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listArrow.png +0 -0
  595. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listArrowSel.png +0 -0
  596. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/listGroup.png +0 -0
  597. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/loading.gif +0 -0
  598. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/pinstripes.png +0 -0
  599. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/rightButton.png +0 -0
  600. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/selection.png +0 -0
  601. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/thumb.png +0 -0
  602. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toggle.png +0 -0
  603. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toggleOn.png +0 -0
  604. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toolButton.png +0 -0
  605. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/toolbar.png +0 -0
  606. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/images/whiteButton.png +0 -0
  607. data/frameworks/sproutcore/themes/iphone_theme/english.lproj/strings.js +15 -0
  608. data/frameworks/sproutcore/themes/standard_theme/english.lproj/button.css +331 -0
  609. data/frameworks/sproutcore/themes/standard_theme/english.lproj/checkbox.css +91 -0
  610. data/frameworks/sproutcore/themes/standard_theme/english.lproj/collection.css +134 -0
  611. data/frameworks/sproutcore/themes/standard_theme/english.lproj/core.css +60 -0
  612. data/frameworks/sproutcore/themes/standard_theme/english.lproj/disclosure.css +55 -0
  613. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-repeat-x.png +0 -0
  614. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-sprite.png +0 -0
  615. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-ysprite.png +0 -0
  616. data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-toolbar-view.png +0 -0
  617. data/frameworks/sproutcore/themes/standard_theme/english.lproj/label.css +11 -0
  618. data/frameworks/sproutcore/themes/standard_theme/english.lproj/list_item.css +30 -0
  619. data/frameworks/sproutcore/themes/standard_theme/english.lproj/pane.css +8 -0
  620. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-fat.jpg +0 -0
  621. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/background-thin.jpg +0 -0
  622. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-edge.png +0 -0
  623. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-left-corner.png +0 -0
  624. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/bottom-right-corner.png +0 -0
  625. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/left-edge.png +0 -0
  626. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/overlay.png +0 -0
  627. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/right-edge.png +0 -0
  628. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-edge.png +0 -0
  629. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-left-corner.png +0 -0
  630. data/frameworks/sproutcore/themes/standard_theme/english.lproj/panels/top-right-corner.png +0 -0
  631. data/frameworks/sproutcore/themes/standard_theme/english.lproj/progress.css +26 -0
  632. data/frameworks/sproutcore/themes/standard_theme/english.lproj/radio.css +122 -0
  633. data/frameworks/sproutcore/themes/standard_theme/english.lproj/segmented.css +279 -0
  634. data/frameworks/sproutcore/themes/standard_theme/english.lproj/slider.css +94 -0
  635. data/frameworks/sproutcore/themes/standard_theme/english.lproj/split_view.css +27 -0
  636. data/frameworks/sproutcore/themes/standard_theme/english.lproj/tab.css +18 -0
  637. data/frameworks/sproutcore/themes/standard_theme/english.lproj/text_field.css +10 -0
  638. data/frameworks/sproutcore/themes/standard_theme/english.lproj/toolbar.css +7 -0
  639. data/lib/sproutcore.rb +9 -1
  640. data/lib/sproutcore/tools/build.rb +1 -1
  641. data/lib/thor/CHANGELOG.rdoc +52 -0
  642. data/lib/thor/LICENSE +20 -0
  643. data/lib/thor/README.markdown +76 -0
  644. data/lib/thor/Rakefile +6 -0
  645. data/lib/thor/Thorfile +45 -0
  646. data/lib/thor/bin/rake2thor +83 -0
  647. data/lib/thor/bin/thor +7 -0
  648. data/lib/thor/lib/thor.rb +170 -0
  649. data/lib/thor/lib/thor/error.rb +3 -0
  650. data/lib/thor/lib/thor/options.rb +267 -0
  651. data/lib/thor/lib/thor/ordered_hash.rb +64 -0
  652. data/lib/thor/lib/thor/runner.rb +305 -0
  653. data/lib/thor/lib/thor/task.rb +83 -0
  654. data/lib/thor/lib/thor/task_hash.rb +22 -0
  655. data/lib/thor/lib/thor/tasks.rb +77 -0
  656. data/lib/thor/lib/thor/tasks/package.rb +18 -0
  657. data/lib/thor/lib/thor/util.rb +75 -0
  658. data/lib/thor/script/destroy +14 -0
  659. data/lib/thor/script/generate +14 -0
  660. data/lib/thor/task.thor +15 -0
  661. metadata +664 -351
  662. data/VERSION +0 -1
  663. data/spec/buildtasks/build/copy_spec.rb +0 -60
  664. data/spec/buildtasks/build/spec_helper.rb +0 -36
  665. data/spec/buildtasks/manifest/catalog_spec.rb +0 -48
  666. data/spec/buildtasks/manifest/hide_buildfiles_spec.rb +0 -125
  667. data/spec/buildtasks/manifest/localize_spec.rb +0 -97
  668. data/spec/buildtasks/manifest/prepare_build_tasks/combine_spec.rb +0 -246
  669. data/spec/buildtasks/manifest/prepare_build_tasks/css_spec.rb +0 -87
  670. data/spec/buildtasks/manifest/prepare_build_tasks/html_spec.rb +0 -175
  671. data/spec/buildtasks/manifest/prepare_build_tasks/javascript_spec.rb +0 -65
  672. data/spec/buildtasks/manifest/prepare_build_tasks/minify_spec.rb +0 -70
  673. data/spec/buildtasks/manifest/prepare_build_tasks/packed_spec.rb +0 -152
  674. data/spec/buildtasks/manifest/prepare_build_tasks/sass_spec.rb +0 -98
  675. data/spec/buildtasks/manifest/prepare_build_tasks/strings_spec.rb +0 -64
  676. data/spec/buildtasks/manifest/prepare_build_tasks/tests_spec.rb +0 -163
  677. data/spec/buildtasks/manifest/prepare_spec.rb +0 -43
  678. data/spec/buildtasks/manifest/spec_helper.rb +0 -35
  679. data/spec/buildtasks/target_spec.rb +0 -214
  680. data/spec/fixtures/builder_tests/Buildfile +0 -15
  681. data/spec/fixtures/builder_tests/apps/combine_test/a.js +0 -1
  682. data/spec/fixtures/builder_tests/apps/combine_test/b.js +0 -1
  683. data/spec/fixtures/builder_tests/apps/combine_test/c.js +0 -1
  684. data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/a.css +0 -1
  685. data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/b.css +0 -1
  686. data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/c.css +0 -1
  687. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/bar1_sample.rhtml +0 -2
  688. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/erb_sample.html.erb +0 -1
  689. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/icons/image.png +0 -0
  690. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/image.jpg +0 -0
  691. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/rhtml_sample.rhtml +0 -1
  692. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/strings.js +0 -4
  693. data/spec/fixtures/builder_tests/apps/html_test/english.lproj/style.css +0 -0
  694. data/spec/fixtures/builder_tests/apps/html_test/french.lproj/french-icons/fr.png +0 -0
  695. data/spec/fixtures/builder_tests/apps/html_test/french.lproj/strings.js +0 -4
  696. data/spec/fixtures/builder_tests/apps/html_test/lib/layout_template.rhtml +0 -1
  697. data/spec/fixtures/builder_tests/apps/html_test/scripts.js +0 -0
  698. data/spec/fixtures/builder_tests/apps/javascript_test/sc_static.js +0 -15
  699. data/spec/fixtures/builder_tests/apps/javascript_test/sc_super.js +0 -4
  700. data/spec/fixtures/builder_tests/apps/javascript_test/strings.js +0 -7
  701. data/spec/fixtures/builder_tests/apps/sass_test/sample.sass +0 -3
  702. data/spec/fixtures/builder_tests/apps/strings_test/lproj/strings.js +0 -8
  703. data/spec/fixtures/builder_tests/apps/stylesheet_test/build_directives.css +0 -9
  704. data/spec/fixtures/builder_tests/apps/stylesheet_test/sc_static.css +0 -12
  705. data/spec/fixtures/builder_tests/apps/test_test/lib/alt_layout.rhtml +0 -1
  706. data/spec/fixtures/builder_tests/apps/test_test/lib/test_layout.rhtml +0 -3
  707. data/spec/fixtures/builder_tests/apps/test_test/tests/qunit_test.js +0 -1
  708. data/spec/fixtures/builder_tests/apps/test_test/tests/qunit_test2.js +0 -1
  709. data/spec/fixtures/builder_tests/apps/test_test/tests/rhtml_test.rhtml +0 -4
  710. data/spec/fixtures/builder_tests/frameworks/debug/core.js +0 -0
  711. data/spec/fixtures/builder_tests/frameworks/debug/english.lproj/dummy.css +0 -0
  712. data/spec/fixtures/builder_tests/frameworks/qunit/core.js +0 -0
  713. data/spec/fixtures/builder_tests/frameworks/qunit/english.lproj/dummy.css +0 -0
  714. data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/req_style_1.css +0 -0
  715. data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/strings.js +0 -4
  716. data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/test.rhtml +0 -1
  717. data/spec/fixtures/builder_tests/frameworks/req_target_1/req_js_1.js +0 -0
  718. data/spec/fixtures/builder_tests/frameworks/req_target_2/english.lproj/req_style_2.css +0 -0
  719. data/spec/fixtures/builder_tests/frameworks/req_target_2/english.lproj/test.rhtml +0 -1
  720. data/spec/fixtures/builder_tests/frameworks/req_target_2/javascript.js +0 -1
  721. data/spec/fixtures/builder_tests/frameworks/req_target_2/lib/alt_layout.rhtml +0 -0
  722. data/spec/fixtures/builder_tests/frameworks/req_target_2/req_js_2.js +0 -0
  723. data/spec/fixtures/builder_tests/themes/sample_theme/Buildfile +0 -1
  724. data/spec/fixtures/buildfiles/basic/Buildfile +0 -16
  725. data/spec/fixtures/buildfiles/basic/task_module.rake +0 -6
  726. data/spec/fixtures/buildfiles/installed/Buildfile +0 -7
  727. data/spec/fixtures/buildfiles/installed/Buildfile2 +0 -5
  728. data/spec/fixtures/buildfiles/project_test/Buildfile +0 -4
  729. data/spec/fixtures/buildfiles/project_test/not_project/Buildfile +0 -2
  730. data/spec/fixtures/buildfiles/project_test/not_project/child/PLACEHOLDER +0 -0
  731. data/spec/fixtures/entry_for_project/Buildfile +0 -1
  732. data/spec/fixtures/entry_for_project/apps/test_app/entry.txt +0 -0
  733. data/spec/fixtures/entry_for_project/apps/test_app/frameworks/nested/PLACEHOLDER +0 -0
  734. data/spec/fixtures/entry_for_project/frameworks/shared/PLACEHOLDER +0 -0
  735. data/spec/fixtures/find_targets/custom/Buildfile +0 -8
  736. data/spec/fixtures/find_targets/custom/bars/bar1/bars/bar1/PLACEHOLDER +0 -0
  737. data/spec/fixtures/find_targets/custom/bars/bar1/bars/bar2/PLACEHOLDER +0 -0
  738. data/spec/fixtures/find_targets/custom/bars/bar1/foos/foo1/PLACEHOLDER +0 -0
  739. data/spec/fixtures/find_targets/custom/bars/bar1/foos/foo2/PLACEHOLDER +0 -0
  740. data/spec/fixtures/find_targets/custom/foos/custom_foos/Buildfile +0 -5
  741. data/spec/fixtures/find_targets/custom/foos/custom_foos/custom_foodir/foo1/PLACEHOLDER +0 -0
  742. data/spec/fixtures/find_targets/custom/foos/custom_foos/custom_foodir/foo2/PLACEHOLDER +0 -0
  743. data/spec/fixtures/find_targets/custom/foos/custom_foos/foos/not_foo1/PLACEHOLDER +0 -0
  744. data/spec/fixtures/find_targets/custom/foos/foo1/bars/bar1/PLACEHOLDER +0 -0
  745. data/spec/fixtures/find_targets/custom/foos/foo1/bars/bar2/PLACEHOLDER +0 -0
  746. data/spec/fixtures/find_targets/nested/Buildfile +0 -8
  747. data/spec/fixtures/find_targets/nested/apps/app1/Buildfile +0 -1
  748. data/spec/fixtures/find_targets/nested/apps/app1/apps/nested_app/PLACEHOLDER +0 -0
  749. data/spec/fixtures/find_targets/standard/Apps/app1/frameworks/framework1/PLACEHOLDER +0 -0
  750. data/spec/fixtures/find_targets/standard/Apps/app1/frameworks/framework2/PLACEHOLDER +0 -0
  751. data/spec/fixtures/find_targets/standard/clients/client1/PLACEHOLDER +0 -0
  752. data/spec/fixtures/find_targets/standard/frameworks/framework1/frameworks/framework1/PLACEHOLDER +0 -0
  753. data/spec/fixtures/find_targets/standard/frameworks/framework2/PLACEHOLDER +0 -0
  754. data/spec/fixtures/find_targets/standard/themes/theme1/PLACEHOLDER +0 -0
  755. data/spec/fixtures/find_targets/standard/themes/theme2/PLACEHOLDER +0 -0
  756. data/spec/fixtures/languages/apps/caps_long_names/English.lproj/PLACEHOLDER +0 -0
  757. data/spec/fixtures/languages/apps/caps_long_names/FreNCH.lproj/PLACEHOLDER +0 -0
  758. data/spec/fixtures/languages/apps/caps_long_names/UnknOWN.lproj/PLACEHOLDER +0 -0
  759. data/spec/fixtures/languages/apps/long_names/english.lproj/PLACEHOLDER +0 -0
  760. data/spec/fixtures/languages/apps/long_names/french.lproj/PLACEHOLDER +0 -0
  761. data/spec/fixtures/languages/apps/long_names/german.lproj/PLACEHOLDER +0 -0
  762. data/spec/fixtures/languages/apps/long_names/italian.lproj/PLACEHOLDER +0 -0
  763. data/spec/fixtures/languages/apps/long_names/japanese.lproj/PLACEHOLDER +0 -0
  764. data/spec/fixtures/languages/apps/long_names/spanish.lproj/PLACEHOLDER +0 -0
  765. data/spec/fixtures/languages/apps/long_names/unknown.lproj/PLACEHOLDER +0 -0
  766. data/spec/fixtures/languages/apps/no_names/PLACEHOLDER +0 -0
  767. data/spec/fixtures/languages/apps/short_names/de.lproj/PLACEHOLDER +0 -0
  768. data/spec/fixtures/languages/apps/short_names/en-CA.lproj/PLACEHOLDER +0 -0
  769. data/spec/fixtures/languages/apps/short_names/en-GB.lproj/PLACEHOLDER +0 -0
  770. data/spec/fixtures/languages/apps/short_names/en-US.lproj/PLACEHOLDER +0 -0
  771. data/spec/fixtures/languages/apps/short_names/en.lproj/PLACEHOLDER +0 -0
  772. data/spec/fixtures/languages/apps/short_names/es.lproj/PLACEHOLDER +0 -0
  773. data/spec/fixtures/languages/apps/short_names/foo.lproj/PLACEHOLDER +0 -0
  774. data/spec/fixtures/languages/apps/short_names/fr.lproj/PLACEHOLDER +0 -0
  775. data/spec/fixtures/languages/apps/short_names/it.lproj/PLACEHOLDER +0 -0
  776. data/spec/fixtures/languages/apps/short_names/ja.lproj/PLACEHOLDER +0 -0
  777. data/spec/fixtures/ordered_entries/apps/no_requires/1.js +0 -1
  778. data/spec/fixtures/ordered_entries/apps/no_requires/B.js +0 -1
  779. data/spec/fixtures/ordered_entries/apps/no_requires/a.js +0 -1
  780. data/spec/fixtures/ordered_entries/apps/no_requires/a/a.js +0 -1
  781. data/spec/fixtures/ordered_entries/apps/no_requires/a/b.js +0 -1
  782. data/spec/fixtures/ordered_entries/apps/no_requires/b/a.js +0 -1
  783. data/spec/fixtures/ordered_entries/apps/no_requires/c.js +0 -1
  784. data/spec/fixtures/ordered_entries/apps/no_requires/core.js +0 -1
  785. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/B.css +0 -0
  786. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a.css +0 -0
  787. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a/a.css +0 -0
  788. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a/b.css +0 -0
  789. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/b/a.css +0 -0
  790. data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/c.css +0 -0
  791. data/spec/fixtures/ordered_entries/apps/no_requires/lproj/strings.js +0 -1
  792. data/spec/fixtures/ordered_entries/apps/no_requires/utils.js +0 -1
  793. data/spec/fixtures/ordered_entries/apps/with_requires/a.js +0 -2
  794. data/spec/fixtures/ordered_entries/apps/with_requires/b.js +0 -3
  795. data/spec/fixtures/ordered_entries/apps/with_requires/c.js +0 -2
  796. data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/a.css +0 -2
  797. data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/b.css +0 -2
  798. data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/c.css +0 -2
  799. data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/d.js +0 -1
  800. data/spec/fixtures/real_world/Buildfile +0 -12
  801. data/spec/fixtures/real_world/apps/account/README +0 -1
  802. data/spec/fixtures/real_world/apps/calendar/README +0 -1
  803. data/spec/fixtures/real_world/apps/contacts/README_BEFORE_EDITING +0 -1
  804. data/spec/fixtures/real_world/apps/files/README +0 -1
  805. data/spec/fixtures/real_world/apps/mail/README +0 -1
  806. data/spec/fixtures/real_world/apps/mobile_photos/README +0 -1
  807. data/spec/fixtures/real_world/apps/photos/README +0 -1
  808. data/spec/fixtures/real_world/apps/uploader/README +0 -1
  809. data/spec/fixtures/real_world/frameworks/core_files/PLACEHOLDER +0 -0
  810. data/spec/fixtures/real_world/frameworks/core_photos/PLACEHOLDER +0 -0
  811. data/spec/fixtures/real_world/frameworks/shared/PLACEHOLDER +0 -0
  812. data/spec/fixtures/real_world/frameworks/sproutcore/Buildfile +0 -26
  813. data/spec/fixtures/real_world/frameworks/sproutcore/README +0 -1
  814. data/spec/fixtures/real_world/frameworks/sproutcore/apps/docs/PLACEHOLDER +0 -0
  815. data/spec/fixtures/real_world/frameworks/sproutcore/apps/test_runner/PLACEHOLDER +0 -0
  816. data/spec/fixtures/real_world/frameworks/sproutcore/core.js +0 -0
  817. data/spec/fixtures/real_world/frameworks/sproutcore/debug/debug-resource.html +0 -0
  818. data/spec/fixtures/real_world/frameworks/sproutcore/debug/sample_debug.js +0 -0
  819. data/spec/fixtures/real_world/frameworks/sproutcore/demo2.js +0 -0
  820. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/debug/sample_debug-loc.js +0 -0
  821. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo.css +0 -4
  822. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo.html +0 -1
  823. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo2.sass +0 -0
  824. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.haml +0 -0
  825. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.html.erb +0 -1
  826. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.rhtml +0 -0
  827. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/fixtures/sample_fixtures-loc.js +0 -0
  828. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/has_require.css +0 -4
  829. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/no_require.css +0 -1
  830. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/no_sc_resource.rhtml +0 -1
  831. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/protocols/sample-loc.js +0 -0
  832. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/sc_resource.css +0 -6
  833. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/sc_resource.rhtml +0 -3
  834. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/strings.js +0 -1
  835. data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/tests/sample-loc.js +0 -0
  836. data/spec/fixtures/real_world/frameworks/sproutcore/fixtures/sample-json-fixture.json +0 -1
  837. data/spec/fixtures/real_world/frameworks/sproutcore/fixtures/sample_fixtures.js +0 -0
  838. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/application/PLACEHOLDER +0 -0
  839. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/costello/core.js +0 -0
  840. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/data_store/PLACEHOLDER +0 -0
  841. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/debug/PLACEHOLDER +0 -0
  842. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/desktop/PLACEHOLDER +0 -0
  843. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/empty_theme/PLACEHOLDER +0 -0
  844. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/foundation/PLACEHOLDER +0 -0
  845. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/mobile/PLACEHOLDER +0 -0
  846. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/qunit/PLACEHOLDER +0 -0
  847. data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/uploader/PLACEHOLDER +0 -0
  848. data/spec/fixtures/real_world/frameworks/sproutcore/french.lproj/french-resource.js +0 -0
  849. data/spec/fixtures/real_world/frameworks/sproutcore/french.lproj/strings.js +0 -1
  850. data/spec/fixtures/real_world/frameworks/sproutcore/german.lproj/german-resource.js +0 -0
  851. data/spec/fixtures/real_world/frameworks/sproutcore/german.lproj/strings.js +0 -0
  852. data/spec/fixtures/real_world/frameworks/sproutcore/has_require.js +0 -4
  853. data/spec/fixtures/real_world/frameworks/sproutcore/lib/index.html +0 -1
  854. data/spec/fixtures/real_world/frameworks/sproutcore/no_require.js +0 -1
  855. data/spec/fixtures/real_world/frameworks/sproutcore/protocols/sample.js +0 -0
  856. data/spec/fixtures/real_world/frameworks/sproutcore/sc_resource.js +0 -6
  857. data/spec/fixtures/real_world/frameworks/sproutcore/tests/nested/sample1.js +0 -0
  858. data/spec/fixtures/real_world/frameworks/sproutcore/tests/nested/sample2.js +0 -0
  859. data/spec/fixtures/real_world/frameworks/sproutcore/tests/sample.js +0 -0
  860. data/spec/fixtures/real_world/frameworks/sproutcore/tests/sample.rhtml +0 -1
  861. data/spec/fixtures/real_world/frameworks/sproutcore/themes/standard_theme/README +0 -0
  862. data/spec/fixtures/real_world/frameworks/sproutcore/views/view.js +0 -1
  863. data/spec/fixtures/real_world/generators/sample_custom/Buildfile +0 -0
  864. data/spec/fixtures/recursive_project/Buildfile +0 -8
  865. data/spec/fixtures/recursive_project/frameworks/sproutcore/frameworks/costello/PLACEHOLDER +0 -0
  866. data/spec/lib/builders/combine_spec.rb +0 -67
  867. data/spec/lib/builders/html_spec.rb +0 -577
  868. data/spec/lib/builders/javascript_spec.rb +0 -81
  869. data/spec/lib/builders/sass_spec.rb +0 -43
  870. data/spec/lib/builders/spec_helper.rb +0 -30
  871. data/spec/lib/builders/strings_spec.rb +0 -52
  872. data/spec/lib/builders/stylesheet_spec.rb +0 -63
  873. data/spec/lib/builders/test_index_spec.rb +0 -44
  874. data/spec/lib/builders/test_spec.rb +0 -135
  875. data/spec/lib/buildfile/config_for_spec.rb +0 -81
  876. data/spec/lib/buildfile/define_spec.rb +0 -59
  877. data/spec/lib/buildfile/dup_spec.rb +0 -65
  878. data/spec/lib/buildfile/invoke_spec.rb +0 -130
  879. data/spec/lib/buildfile/load_spec.rb +0 -49
  880. data/spec/lib/buildfile/task/dup_spec.rb +0 -55
  881. data/spec/lib/buildfile/task_defined_spec.rb +0 -17
  882. data/spec/lib/buildfile_commands/build_task_spec.rb +0 -19
  883. data/spec/lib/buildfile_commands/config_spec.rb +0 -97
  884. data/spec/lib/buildfile_commands/import_spec.rb +0 -17
  885. data/spec/lib/buildfile_commands/namespace_spec.rb +0 -18
  886. data/spec/lib/buildfile_commands/proxies_spec.rb +0 -38
  887. data/spec/lib/buildfile_commands/replace_task_spec.rb +0 -29
  888. data/spec/lib/buildfile_commands/task_spec.rb +0 -36
  889. data/spec/lib/helpers/packing_optimizer/optimize_spec.rb +0 -26
  890. data/spec/lib/models/hash_struct/deep_clone_spec.rb +0 -27
  891. data/spec/lib/models/hash_struct/has_options_spec.rb +0 -32
  892. data/spec/lib/models/hash_struct/hash_spec.rb +0 -64
  893. data/spec/lib/models/hash_struct/merge_spec.rb +0 -26
  894. data/spec/lib/models/hash_struct/method_missing.rb +0 -41
  895. data/spec/lib/models/manifest/add_entry_spec.rb +0 -36
  896. data/spec/lib/models/manifest/add_transform_spec.rb +0 -90
  897. data/spec/lib/models/manifest/build_spec.rb +0 -78
  898. data/spec/lib/models/manifest/entry_for_spec.rb +0 -94
  899. data/spec/lib/models/manifest/find_entry.rb +0 -84
  900. data/spec/lib/models/manifest/prepare_spec.rb +0 -62
  901. data/spec/lib/models/manifest_entry/cacheable_url_spec.rb +0 -31
  902. data/spec/lib/models/manifest_entry/prepare_spec.rb +0 -54
  903. data/spec/lib/models/project/add_target_spec.rb +0 -44
  904. data/spec/lib/models/project/buildfile_spec.rb +0 -35
  905. data/spec/lib/models/project/find_targets_for_spec.rb +0 -77
  906. data/spec/lib/models/project/load_nearest_project_spec.rb +0 -23
  907. data/spec/lib/models/project/target_for_spec.rb +0 -33
  908. data/spec/lib/models/project/targets_spec.rb +0 -62
  909. data/spec/lib/models/target/compute_build_number_spec.rb +0 -125
  910. data/spec/lib/models/target/config_spec.rb +0 -30
  911. data/spec/lib/models/target/expand_required_targets_spec.rb +0 -48
  912. data/spec/lib/models/target/installed_languages_spec.rb +0 -47
  913. data/spec/lib/models/target/lproj_for_spec.rb +0 -38
  914. data/spec/lib/models/target/manifest_for_spec.rb +0 -42
  915. data/spec/lib/models/target/parent_target_spec.rb +0 -21
  916. data/spec/lib/models/target/prepare_spec.rb +0 -53
  917. data/spec/lib/models/target/required_targets_spec.rb +0 -119
  918. data/spec/lib/models/target/target_for_spec.rb +0 -56
  919. data/spec/lib/tools/build_number_spec.rb +0 -28
  920. data/spec/lib/tools/gen_spec.rb +0 -207
  921. data/spec/lib/tools/tools_spec.rb +0 -78
  922. data/spec/spec_helper.rb +0 -138
  923. data/sproutcore-abbot.gemspec +0 -640
  924. data/vendor/jsdoc/templates/jsdoc/allclasses.tmpl +0 -17
  925. data/vendor/jsdoc/templates/jsdoc/allfiles.tmpl +0 -56
  926. data/vendor/jsdoc/templates/jsdoc/class.tmpl +0 -487
  927. data/vendor/jsdoc/templates/jsdoc/index.tmpl +0 -38
  928. data/vendor/jsdoc/templates/jsdoc/symbol.tmpl +0 -35
  929. data/vendor/jsdoc/templates/sproutcore/allclasses.tmpl +0 -0
  930. data/vendor/jsdoc/templates/sproutcore/allfiles.tmpl +0 -56
  931. data/vendor/jsdoc/templates/sproutcore/class.tmpl +0 -674
  932. data/vendor/jsdoc/templates/sproutcore/index.tmpl +0 -55
  933. data/vendor/jsdoc/templates/sproutcore/symbol.tmpl +0 -35
@@ -0,0 +1,105 @@
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
+ /** @class
9
+
10
+ Renders a checkbox button view specifically.
11
+
12
+ This view is basically a button view preconfigured to generate the correct
13
+ HTML and to set to use a TOGGLE_BEHAVIOR for its buttons.
14
+
15
+ This view renders a simulated checkbox that can display a mixed state and
16
+ has other features not found in platform-native controls. If you want to
17
+ use the platform native version instead, see SC.CheckboxFieldView.
18
+
19
+ @extends SC.FieldView
20
+ @since SproutCore 1.0
21
+ */
22
+ SC.CheckboxView = SC.FieldView.extend(SC.StaticLayout, SC.Button,
23
+ /** @scope SC.CheckboxView.prototype */ {
24
+
25
+ classNames: ['sc-checkbox-view'],
26
+ tagName: 'label',
27
+
28
+ render: function(context, firstTime) {
29
+ var dt, elem ;
30
+
31
+ // add checkbox -- set name to view guid to separate it from others
32
+ if (firstTime) {
33
+ dt = this._field_currentDisplayTitle = this.get('displayTitle');
34
+
35
+ var blank = sc_static('blank');
36
+ var disabled = this.get('isEnabled') ? '' : 'disabled="disabled"';
37
+ context.push('<img src="', blank, '" class="button" />');
38
+ context.push('<input type="checkbox" name="%@" %@ />'.fmt(SC.guidFor(this),disabled));
39
+ context.push('<span class="label">', dt, '</span>');
40
+ context.attr('name', SC.guidFor(this));
41
+
42
+ // since we don't want to regenerate the contents each time
43
+ // actually search for and update the displayTitle.
44
+ } else {
45
+
46
+ if (elem = this.$input()[0]) {
47
+ if (this.get('isEnabled')) elem.disabled=NO;
48
+ else elem.disabled=YES;
49
+ elem = null ; // avoid memory leaks
50
+ }
51
+
52
+ dt = this.get('displayTitle');
53
+ if (dt !== this._field_currentDisplayTitle) {
54
+ this._field_currentDisplayTitle = dt;
55
+ this.$('span.label').text(dt);
56
+ }
57
+ }
58
+ },
59
+
60
+ // ..........................................
61
+ // SC.FIELD SUPPORT
62
+ //
63
+
64
+ /** @private - return the input tag */
65
+ $input: function() { return this.$('input'); },
66
+
67
+ /** @private - get the checked value from the input tag. If the value is
68
+ unchecked and the last value set was mixed, then return mixed. This
69
+ allows mixed states to remain unchanged. */
70
+ getFieldValue: function() {
71
+ var ret = this.$input().attr('checked');
72
+ if (ret) {
73
+ this._lastFieldValue = null; // clear last field value since it changed
74
+
75
+ // possibly return mixed state if that was the last value set and the
76
+ // current checked value is still empty.
77
+ } else {
78
+ if (this._lastFieldValue === SC.MIXED_STATE) ret = SC.MIXED_STATE ;
79
+ }
80
+ return ret ;
81
+ },
82
+
83
+ /** @private - set the checked value on the input tag. If the value is
84
+ mixed, treat that as unchecked and save the value. This way the mixed
85
+ state can be retained.
86
+ */
87
+ setFieldValue: function(v) {
88
+ this._lastFieldValue = v;
89
+ this.$input().attr('checked', (v === SC.MIXED_STATE) ? NO : !!v);
90
+ },
91
+
92
+ /** @private - Converts the field value to the toggleOnValue or mixed */
93
+ fieldValueForObject: function(obj) {
94
+ return this.computeIsSelectedForValue(obj) ;
95
+ },
96
+
97
+ /** @private - Converts the field value to the toggleOffValue. If the
98
+ value is MIXED_STATE, always return the current value */
99
+ objectForFieldValue: function(v) {
100
+ var ret = (v === SC.MIXED_STATE) ? this.get('value') :
101
+ (!!v) ? this.get('toggleOnValue') : this.get('toggleOffValue');
102
+ return ret ;
103
+ }
104
+
105
+ }) ;
@@ -0,0 +1,2757 @@
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
+ /**
12
+ Special drag operation passed to delegate if the collection view proposes
13
+ to perform a reorder event.
14
+ */
15
+ SC.DRAG_REORDER = 0x0010 ;
16
+
17
+ /** Indicates that selection points should be selected using horizontal
18
+ orientation.
19
+ */
20
+ SC.HORIZONTAL_ORIENTATION = 'horizontal';
21
+
22
+ /** Selection points should be selected using vertical orientation. */
23
+ SC.VERTICAL_ORIENTATION = 'vertical' ;
24
+
25
+ SC.BENCHMARK_RELOAD = NO ;
26
+
27
+ /**
28
+ @class
29
+
30
+ TODO: Document SC.CollectionView
31
+
32
+ Renders a collection of views from a source array of model objects.
33
+
34
+ The CollectionView is the root view class for rendering collections of
35
+ views based on a source array of objects. It can automatically create the
36
+ and layout the views, including displaying them in groups. It also
37
+ handles event input for the entire collection.
38
+
39
+ To use CollectionView, just create the view and set the 'content' property
40
+ to an array of objects. (Note that if you setup a binding, it will
41
+ always transform content to an array.) The view will create instances of
42
+ exampleView to render the array. You can also bind to the selection
43
+ property if you want to monitor selection. (be sure to set the isEnabled
44
+ property to allow selection.)
45
+
46
+ @extends SC.View
47
+ @extends SC.CollectionViewDelegate
48
+ @extends SC.CollectionContent
49
+ @since SproutCore 0.9
50
+ */
51
+ SC.CollectionView = SC.View.extend(
52
+ SC.CollectionViewDelegate,
53
+ SC.CollectionContent,
54
+ /** @scope SC.CollectionView.prototype */ {
55
+
56
+ classNames: ['sc-collection-view'],
57
+
58
+ ACTION_DELAY: 200,
59
+
60
+ // ......................................
61
+ // PROPERTIES
62
+ //
63
+
64
+ /**
65
+ An array of content objects
66
+
67
+ This array should contain the content objects you want the collection view
68
+ to display. An item view (based on the exampleView view class) will be
69
+ created for each content object, in the order the content objects appear
70
+ in this array.
71
+
72
+ If you make the collection editable, the collection view will also modify
73
+ this array using the observable array methods of SC.Array.
74
+
75
+ Usually you will want to bind this property to a controller property
76
+ that actually contains the array of objects you to display.
77
+
78
+ @type {SC.Array}
79
+ */
80
+ content: null,
81
+
82
+ /** @private */
83
+ contentBindingDefault: SC.Binding.multiple(),
84
+
85
+ /**
86
+ The current length of the content.
87
+
88
+ @property
89
+ @type {Numer}
90
+ */
91
+ length: 0,
92
+
93
+ /**
94
+ The set of indexes that are currently tracked by the collection view.
95
+ This property is used to determine the range of items the collection view
96
+ should monitor for changes.
97
+
98
+ The default implementation of this property returns an index set covering
99
+ the entire range of the content. It changes automatically whenever the
100
+ length changes.
101
+
102
+ Note that the returned index set for this property will always be frozen.
103
+ To change the nowShowing index set, you must create a new index set and
104
+ apply it.
105
+
106
+ @property
107
+ @type {SC.IndexSet}
108
+ */
109
+ nowShowing: function() {
110
+ var ret = this.computeNowShowing();
111
+ return ret ? ret.frozenCopy() : null;
112
+ }.property('length', 'clippingFrame').cacheable(),
113
+
114
+ /**
115
+ Indexes of selected content objects. This SC.SelectionSet is modified
116
+ automatically by the collection view when the user changes the selection
117
+ on the collection.
118
+
119
+ Any item views representing content objects in this set will have their
120
+ isSelected property set to YES automatically.
121
+
122
+ @type {SC.SelectionSet}
123
+ */
124
+ selection: null,
125
+
126
+ /**
127
+ Allow user to select content using the mouse and keyboard.
128
+
129
+ Set this property to NO to disallow the user from selecting items. If you
130
+ have items in your selectedIndexes property, they will still be reflected
131
+ visually.
132
+
133
+ @type {Boolean}
134
+ */
135
+ isSelectable: YES,
136
+
137
+ /** @private */
138
+ isSelectableBindingDefault: SC.Binding.bool(),
139
+
140
+ /**
141
+ Enable or disable the view.
142
+
143
+ The collection view will set the isEnabled property of its item views to
144
+ reflect the same view of this property. Whenever isEnabled is false,
145
+ the collection view will also be not selectable or editable, regardless of
146
+ the settings for isEditable & isSelectable.
147
+
148
+ @type {Boolean}
149
+ */
150
+ isEnabled: YES,
151
+
152
+ /** @private */
153
+ isEnabledBindingDefault: SC.Binding.bool(),
154
+
155
+ /**
156
+ Allow user to edit content views.
157
+
158
+ The collection view will set the isEditable property on its item views to
159
+ reflect the same value of this property. Whenever isEditable is false,
160
+ the user will not be able to reorder, add, or delete items regardless of
161
+ the canReorderContent and canDeleteContent and isDropTarget properties.
162
+
163
+ @type {Boolean}
164
+ */
165
+ isEditable: YES,
166
+
167
+ /** @private */
168
+ isEditableBindingDefault: SC.Binding.bool(),
169
+
170
+ /**
171
+ Allow user to reorder items using drag and drop.
172
+
173
+ If true, the user will can use drag and drop to reorder items in the list.
174
+ If you also accept drops, this will allow the user to drop items into
175
+ specific points in the list. Otherwise items will be added to the end.
176
+
177
+ @type {Boolean}
178
+ */
179
+ canReorderContent: NO,
180
+
181
+ /** @private */
182
+ canReorderContentBindingDefault: SC.Binding.bool(),
183
+
184
+ /**
185
+ Allow the user to delete items using the delete key
186
+
187
+ If true the user will be allowed to delete selected items using the delete
188
+ key. Otherwise deletes will not be permitted.
189
+
190
+ @type {Boolean}
191
+ */
192
+ canDeleteContent: NO,
193
+
194
+ /** @private */
195
+ canDeleteContentBindingDefault: SC.Binding.bool(),
196
+
197
+ /**
198
+ Allow user to edit the content by double clicking on it or hitting return.
199
+ This will only work if isEditable is YES and the item view implements
200
+ the beginEditing() method.
201
+
202
+ @type {Boolean}
203
+ */
204
+ canEditContent: NO,
205
+
206
+ /** @private */
207
+ canEditContentBindingDefault: SC.Binding.bool(),
208
+
209
+ /**
210
+ Accept drops for data other than reordering.
211
+
212
+ Setting this property to return true when the view is instantiated will
213
+ cause it to be registered as a drop target, activating the other drop
214
+ machinery.
215
+
216
+ @type {Boolean}
217
+ */
218
+ isDropTarget: NO,
219
+
220
+ /**
221
+ Use toggle selection instead of normal click behavior.
222
+
223
+ If set to true, then selection will use a toggle instead of the normal
224
+ click behavior. Command modifiers will be ignored and instead clicking
225
+ once will select an item and clicking on it again will deselect it.
226
+
227
+ @type {Boolean}
228
+ */
229
+ useToggleSelection: NO,
230
+
231
+ /**
232
+ Trigger the action method on a single click.
233
+
234
+ Normally, clicking on an item view in a collection will select the content
235
+ object and double clicking will trigger the action method on the
236
+ collection view.
237
+
238
+ If you set this property to YES, then clicking on a view will both select
239
+ it (if isSelected is true) and trigger the action method.
240
+
241
+ Use this if you are using the collection view as a menu of items.
242
+
243
+ @property {Boolean}
244
+ */
245
+ actOnSelect: NO,
246
+
247
+
248
+ /**
249
+ Select an item immediately on mouse down
250
+
251
+ Normally as soon as you begin a click the item will be selected.
252
+
253
+ In some UI scenarios, you might want to prevent selection until
254
+ the mouse is released, so you can perform, for instance, a drag operation
255
+ without actually selecting the target item.
256
+
257
+ @property {Boolean}
258
+ */
259
+ selectOnMouseDown: YES,
260
+
261
+ /**
262
+ The view class to use when creating new item views.
263
+
264
+ The collection view will automatically create an instance of the view
265
+ class you set here for each item in its content array. You should provide
266
+ your own subclass for this property to display the type of content you
267
+ want.
268
+
269
+ For best results, the view you set here should understand the following
270
+ properties:
271
+
272
+ - *content* The content object from the content array your view should display
273
+ - *isEnabled* True if the view should appear enabled
274
+ - *isSelected* True if the view should appear selected
275
+
276
+ In general you do not want your child views to actually respond to mouse
277
+ and keyboard events themselves. It is better to let the collection view
278
+ do that.
279
+
280
+ If you do implement your own event handlers such as mouseDown or mouseUp,
281
+ you should be sure to actually call the same method on the collection view
282
+ to give it the chance to perform its own selection housekeeping.
283
+
284
+ @property {SC.View}
285
+ */
286
+ exampleView: SC.ListItemView,
287
+
288
+ /**
289
+ If set, this key will be used to get the example view for a given
290
+ content object. The exampleView property will be ignored.
291
+
292
+ @property {String}
293
+ */
294
+ contentExampleViewKey: null,
295
+
296
+ /**
297
+ The view class to use when creating new group item views.
298
+
299
+ The collection view will automatically create an instance of the view
300
+ class you set here for each item in its content array. You should provide
301
+ your own subclass for this property to display the type of content you
302
+ want.
303
+
304
+ If you leave this set to null then the regular example view will be used
305
+ with the isGroupView property set to YES on the item view.
306
+
307
+ @property {SC.View}
308
+ */
309
+ groupExampleView: null,
310
+
311
+ /**
312
+ If set, this key will be used to get the example view for a given
313
+ content object. The groupExampleView property will be ignored.
314
+
315
+ @property {String}
316
+ */
317
+ contentGroupExampleViewKey: null,
318
+
319
+ /**
320
+ Invoked when the user double clicks on an item (or single clicks of
321
+ actOnSelect is true)
322
+
323
+ Set this to the name of the action you want to send down the
324
+ responder chain when the user double clicks on an item (or single clicks
325
+ if actOnSelect is true). You can optionally specify a specific target as
326
+ well using the target property.
327
+
328
+ If you do not specify an action, then the collection view will also try to
329
+ invoke the action named on the target item view.
330
+
331
+ Older versions of SproutCore expected the action property to contain an
332
+ actual function that would be run. This format is still supported but is
333
+ deprecated for future use. You should generally use the responder chain
334
+ to handle your action for you.
335
+
336
+ @property {String}
337
+ */
338
+ action: null,
339
+
340
+ /**
341
+ Optional target to send the action to when the user double clicks.
342
+
343
+ If you set the action property to the name of an action, you can
344
+ optionally specify the target object you want the action to be sent to.
345
+ This can be either an actual object or a property path that will resolve
346
+ to an object at the time that the action is invoked.
347
+
348
+ This property is ignored if you use the deprecated approach of making the
349
+ action property a function.
350
+
351
+ @property {String|Object}
352
+ */
353
+ target: null,
354
+
355
+ /**
356
+ Property on content items to use for display.
357
+
358
+ Built-in item views such as the LabelViews and ImageViews will use the
359
+ value of this property as a key on the content object to determine the
360
+ value they should display.
361
+
362
+ For example, if you set contentValueKey to 'name' and set the
363
+ exampleView to an SC.LabelView, then the label views created by the
364
+ colleciton view will display the value of the content.name.
365
+
366
+ If you are writing your own custom item view for a collection, you can
367
+ get this behavior automatically by including the SC.Control mixin on your
368
+ view. You can also ignore this property if you like. The collection view
369
+ itself does not use this property to impact rendering.
370
+
371
+ @property {String}
372
+ */
373
+ contentValueKey: null,
374
+
375
+ /**
376
+ Enables keyboard-based navigate, deletion, etc. if set to true.
377
+ */
378
+ acceptsFirstResponder: NO,
379
+
380
+ // ..........................................................
381
+ // SUBCLASS METHODS
382
+ //
383
+
384
+ /**
385
+ Override to return the computed layout dimensions of the collection view.
386
+ You can omit any dimensions you don't care about setting in your
387
+ computed value.
388
+
389
+ This layout is automatically applied whenever the content changes.
390
+
391
+ If you don't care about computing the layout at all, you can return null.
392
+
393
+ @returns {Hash} layout properties
394
+ */
395
+ computeLayout: function() { return null; },
396
+
397
+ /**
398
+ Override to compute the layout of the itemView for the content at the
399
+ specified index. This layout will be applied to the view just before it
400
+ is rendered.
401
+
402
+ @param {Number} contentIndex the index of content beind rendered by
403
+ itemView
404
+ @returns {Hash} a view layout
405
+ */
406
+ layoutForContentIndex: function(contentIndex) {
407
+ return null ;
408
+ },
409
+
410
+ /**
411
+ Override to return an IndexSet with the indexes that are at least
412
+ partially visible in the passed rectangle. This method is used by the
413
+ default implementation of computeNowShowing() to determine the new
414
+ nowShowing range after a scroll.
415
+
416
+ Override this method to implement incremental rendering.
417
+
418
+ The default simply returns the current content length.
419
+
420
+ @param {Rect} rect the visible rect
421
+ @returns {SC.IndexSet} now showing indexes
422
+ */
423
+ contentIndexesInRect: function(rect) {
424
+ return SC.IndexSet.create(0, this.get('length'));
425
+ },
426
+
427
+ /**
428
+ Compute the nowShowing index set. The default implementation simply
429
+ returns the full range. Override to implement incremental rendering.
430
+
431
+ You should not normally call this method yourself. Instead get the
432
+ nowShowing property.
433
+
434
+ @returns {SC.IndexSet} new now showing range
435
+ */
436
+ computeNowShowing: function() {
437
+ var r = this.contentIndexesInRect(this.get('clippingFrame')),
438
+ content = SC.makeArray(this.get('content')),
439
+ len = content.get('length');
440
+
441
+ // default show all.
442
+ if (!r) r = SC.IndexSet.create(0, len);
443
+
444
+ // make sure the index set doesn't contain any indexes greater than the
445
+ // actual content.
446
+ if (r.get('max') > len) r.remove(len, r.get('max')-len);
447
+
448
+ return r ;
449
+ },
450
+
451
+ /**
452
+ Override to show the insertion point during a drag.
453
+
454
+ Called during a drag to show the insertion point. Passed value is the
455
+ item view that you should display the insertion point before. If the
456
+ passed value is null, then you should show the insertion point AFTER that
457
+ last item view returned by the itemViews property.
458
+
459
+ Once this method is called, you are guaranteed to also recieve a call to
460
+ hideInsertionPoint() at some point in the future.
461
+
462
+ The default implementation of this method does nothing.
463
+
464
+ @param itemView {SC.ClassicView} view the insertion point should appear directly before. If null, show insertion point at end.
465
+ @param dropOperation {Number} the drop operation. will be SC.DROP_BEFORE, SC.DROP_AFTER, or SC.DROP_ON
466
+
467
+ @returns {void}
468
+ */
469
+ showInsertionPoint: function(itemView, dropOperation) {
470
+ },
471
+
472
+ /**
473
+ Override to hide the insertion point when a drag ends.
474
+
475
+ Called during a drag to hide the insertion point. This will be called
476
+ when the user exits the view, cancels the drag or completes the drag. It
477
+ will not be called when the insertion point changes during a drag.
478
+
479
+ You should expect to receive one or more calls to
480
+ showInsertionPointBefore() during a drag followed by at least one call to
481
+ this method at the end. Your method should not raise an error if it is
482
+ called more than once.
483
+
484
+ @returns {void}
485
+ */
486
+ hideInsertionPoint: function() {
487
+ },
488
+
489
+ // ..........................................................
490
+ // DELEGATE SUPPORT
491
+ //
492
+
493
+
494
+ /**
495
+ Delegate used to implement fine-grained control over collection view
496
+ behaviors.
497
+
498
+ You can assign a delegate object to this property that will be consulted
499
+ for various decisions regarding drag and drop, selection behavior, and
500
+ even rendering. The object you place here must implement some or all of
501
+ the SC.CollectionViewDelegate mixin.
502
+
503
+ If you do not supply a delegate but the content object you set implements
504
+ the SC.CollectionViewDelegate mixin, then the content will be
505
+ automatically set as the delegate. Usually you will work with a
506
+ CollectionView in this way rather than setting a delegate explicitly.
507
+
508
+ @type {SC.CollectionViewDelegate}
509
+ */
510
+ delegate: null,
511
+
512
+ /**
513
+ The delegate responsible for handling selection changes. This property
514
+ will be either the delegate, content, or the collection view itself,
515
+ whichever implements the SC.CollectionViewDelegate mixin.
516
+
517
+ @property
518
+ @type {Object}
519
+ */
520
+ selectionDelegate: function() {
521
+ var del = this.get('delegate'), content = this.get('content');
522
+ return this.delegateFor('isCollectionViewDelegate', del, content);
523
+ }.property('delegate', 'content').cacheable(),
524
+
525
+ /**
526
+ The delegate responsible for providing additional display information
527
+ about the content. If you bind a collection view to a controller, this
528
+ the content will usually also be the content delegate, though you
529
+ could implement your own delegate if you prefer.
530
+
531
+ @property
532
+ @type {Object}
533
+ */
534
+ contentDelegate: function() {
535
+ var del = this.get('delegate'), content = this.get('content');
536
+ return this.delegateFor('isCollectionContent', del, content);
537
+ }.property('delegate', 'content').cacheable(),
538
+
539
+ // ..........................................................
540
+ // CONTENT CHANGES
541
+ //
542
+
543
+ /**
544
+ Called whenever the content array or an item in the content array or a
545
+ property on an item in the content array changes. Reloads the appropriate
546
+ item view when the content array itself changes or calls
547
+ contentPropertyDidChange() if a property changes.
548
+
549
+ Normally you will not call this method directly though you may override
550
+ it if you need to change the way changes to observed ranges are handled.
551
+
552
+ @param {SC.Array} content the content array generating the change
553
+ @param {Object} object the changed object
554
+ @param {String} key the changed property or '[]' or an array change
555
+ @param {SC.IndexSet} indexes affected indexes or null for all items
556
+ @returns {void}
557
+ */
558
+ contentRangeDidChange: function(content, object, key, indexes) {
559
+ if (!object && (key === '[]')) {
560
+ this.reload(indexes); // note: if indexes == null, reloads all
561
+ } else {
562
+ this.contentPropertyDidChange(object, key, indexes);
563
+ }
564
+ },
565
+
566
+ /**
567
+ Called whenever a property on an item in the content array changes. This
568
+ is only called if you have set observesContentProperties to YES.
569
+
570
+ Override this property if you want to do some custom work whenever a
571
+ property on a content object changes.
572
+
573
+ The default implementation does nothing.
574
+
575
+ @param {Object} target the object that changed
576
+ @param {String} key the property that changed value
577
+ @param {SC.IndexSet} indexes the indexes in the content array affected
578
+ @returns {void}
579
+ */
580
+ contentPropertyDidChange: function(target, key, indexes) {
581
+ // Default Does Nothing
582
+ },
583
+
584
+ /**
585
+ Called whenever the view needs to updates it's contentRangeObserver to
586
+ reflect the current nowShowing index set. You will not usually call this
587
+ method yourself but you may override it if you need to provide some
588
+ custom range observer behavior.
589
+
590
+ Note that if you do implement this method, you are expected to maintain
591
+ the range observer object yourself. If a range observer has not been
592
+ created yet, this method should create it. If an observer already exists
593
+ this method should udpate it.
594
+
595
+ When you create a new range observer, the oberver must eventually call
596
+ contentRangeDidChange() for the collection view to function properly.
597
+
598
+ If you override this method you probably also need to override
599
+ destroyRangeObserver() to cleanup any existing range observer.
600
+
601
+ @returns {void}
602
+ */
603
+ updateContentRangeObserver: function() {
604
+ var nowShowing = this.get('nowShowing'),
605
+ observer = this._cv_contentRangeObserver,
606
+ content = this.get('content');
607
+
608
+ if (!content) return ; // nothing to do
609
+
610
+ if (observer) {
611
+ content.updateRangeObserver(observer, nowShowing);
612
+ } else {
613
+ var func = this.contentRangeDidChange;
614
+ observer = content.addRangeObserver(nowShowing, this, func, null);
615
+ this._cv_contentRangeObserver = observer ;
616
+ }
617
+
618
+ },
619
+
620
+ /**
621
+ Called whever the view needs to invalidate the current content range
622
+ observer. This is called whenever the content array changes. You will
623
+ not usually call this method yourself but you may override it if you
624
+ provide your own range observer behavior.
625
+
626
+ Note that if you override this method you should probably also override
627
+ updateRangeObserver() to create or update a range oberver as needed.
628
+
629
+ @returns {void}
630
+ */
631
+ removeContentRangeObserver: function() {
632
+ var content = this.get('content'),
633
+ observer = this._cv_contentRangeObserver ;
634
+
635
+ if (observer) {
636
+ if (content) content.removeRangeObserver(observer);
637
+ this._cv_contentRangeObserver = null ;
638
+ }
639
+ },
640
+
641
+ /**
642
+ Called whenever the content length changes. This will invalidate the
643
+ length property of the view itself causing the nowShowing to recompute
644
+ which will in turn update the UI accordingly.
645
+
646
+ @returns {void}
647
+ */
648
+ contentLengthDidChange: function() {
649
+ var content = this.get('content');
650
+ this.set('length', content ? content.get('length') : 0);
651
+ },
652
+
653
+ /** @private
654
+ Whenever content property changes to a new value:
655
+
656
+ - remove any old observers
657
+ - setup new observers (maybe wait until end of runloop to do this?)
658
+ - recalc height/reload content
659
+ - set content as delegate if delegate was old content
660
+ - reset selection
661
+
662
+ Whenever content array mutates:
663
+
664
+ - possibly stop observing property changes on objects, observe new objs
665
+ - reload effected item views
666
+ - update layout for receiver
667
+ */
668
+ _cv_contentDidChange: function() {
669
+ var content = this.get('content'),
670
+ lfunc = this.contentLengthDidChange ;
671
+
672
+ if (content === this._content) return this; // nothing to do
673
+
674
+ // cleanup old content
675
+ this.removeContentRangeObserver();
676
+ if (this._content) {
677
+ this._content.removeObserver('length', this, lfunc);
678
+ }
679
+
680
+ // cache
681
+ this._content = content;
682
+
683
+ // add new observers - range observer will be added lazily
684
+ if (content) {
685
+ content.addObserver('length', this, lfunc);
686
+ }
687
+
688
+ // notify all items changed
689
+ this.contentLengthDidChange();
690
+ this.contentRangeDidChange(content, null, '[]', null);
691
+
692
+ }.observes('content'),
693
+
694
+ // ..........................................................
695
+ // ITEM VIEWS
696
+ //
697
+
698
+ /** @private
699
+
700
+ The indexes that need to be reloaded. Must be one of YES, NO, or an
701
+ SC.IndexSet.
702
+
703
+ */
704
+ _invalidIndexes: NO,
705
+
706
+ /**
707
+ Regenerates the item views for the content items at the specified indexes.
708
+ If you pass null instead of an index set, regenerates all item views.
709
+
710
+ This method is called automatically whenever the content array changes in
711
+ an observable way, but you can call its yourself also if you need to
712
+ refresh the collection view for some reason.
713
+
714
+ Note that if the length of the content is shorter than the child views
715
+ and you call this method, then the child views will be removed no matter
716
+ what the index.
717
+
718
+ @param {SC.IndexSet} indexes
719
+ @returns {SC.CollectionView} receiver
720
+ */
721
+ reload: function(indexes) {
722
+ var invalid = this._invalidIndexes ;
723
+ if (indexes && invalid !== YES) {
724
+ if (invalid) invalid.add(indexes);
725
+ else invalid = this._invalidIndexes = indexes.clone();
726
+
727
+ } else this._invalidIndexes = YES ; // force a total reload
728
+
729
+ if (this.get('isVisibleInWindow')) this.invokeOnce(this.reloadIfNeeded);
730
+
731
+ return this ;
732
+ },
733
+
734
+ /**
735
+ Invoked once per runloop to actually reload any needed item views.
736
+ You can call this method at any time to actually force the reload to
737
+ happen immediately if any item views need to be reloaded.
738
+
739
+ Note that this method will also invoke two other callback methods if you
740
+ define them on your subclass:
741
+
742
+ - *willReload()* is called just before the items are reloaded
743
+ - *didReload()* is called jsut after items are reloaded
744
+
745
+ You can use these two methods to setup and teardown caching, which may
746
+ reduce overall cost of a reload. Each method will be passed an index set
747
+ of items that are reloaded or null if all items are reloaded.
748
+
749
+ @returns {SC.CollectionView} receiver
750
+ */
751
+ reloadIfNeeded: function() {
752
+ var invalid = this._invalidIndexes;
753
+ if (!invalid || !this.get('isVisibleInWindow')) return this ; // delay
754
+ this._invalidIndexes = NO ;
755
+
756
+ var content = this.get('content'),
757
+ len = content ? content.get('length'): 0,
758
+ layout = this.computeLayout(),
759
+ bench = SC.BENCHMARK_RELOAD,
760
+ nowShowing = this.get('nowShowing'),
761
+ itemViews = this._sc_itemViews,
762
+ containerView = this.get('containerView') || this,
763
+ views, idx, cvlen, view, childViews, layer ;
764
+
765
+ // if the set is defined but it contains the entire nowShowing range, just
766
+ // replace
767
+ if (invalid.isIndexSet && invalid.contains(nowShowing)) invalid = YES ;
768
+ if (this.willReload) this.willReload(invalid === YES ? null : invalid);
769
+
770
+ // if an index set, just update indexes
771
+ if (invalid.isIndexSet) {
772
+ childViews = containerView.get('childViews');
773
+ cvlen = childViews.get('length');
774
+
775
+ if (bench) {
776
+ SC.Benchmark.start(bench="%@#reloadIfNeeded (Partial)".fmt(this),YES);
777
+ }
778
+
779
+ invalid.forEach(function(idx) {
780
+
781
+ // get the existing item view, if there is one
782
+ var existing = itemViews ? itemViews[idx] : null;
783
+
784
+ // if nowShowing, then reload the item view.
785
+ if (nowShowing.contains(idx)) {
786
+ view = this.itemViewForContentIndex(idx, YES);
787
+ if (existing && existing.parentView === containerView) {
788
+
789
+ // if the existing view has a layer, remove it immediately from
790
+ // the parent. This is necessary because the old and new views
791
+ // will use the same layerId
792
+ layer = existing.get('layer');
793
+ if (layer && layer.parentNode) {
794
+ layer.parentNode.removeChild(layer);
795
+ }
796
+ layer = null ; // avoid leaks
797
+
798
+ containerView.replaceChild(view, existing);
799
+ } else {
800
+ containerView.appendChild(view);
801
+ }
802
+
803
+ // if not nowShowing, then remove the item view if needed
804
+ } else if (existing && existing.parentView === containerView) {
805
+ delete itemViews[idx];
806
+ containerView.removeChild(existing);
807
+ }
808
+ },this);
809
+
810
+ if (bench) SC.Benchmark.end(bench);
811
+
812
+ // if set is NOT defined, replace entire content with nowShowing
813
+ } else {
814
+
815
+ if (bench) {
816
+ SC.Benchmark.start(bench="%@#reloadIfNeeded (Full)".fmt(this),YES);
817
+ }
818
+
819
+ // truncate cached item views since they will all be removed from the
820
+ // container anyway.
821
+ if (itemViews) itemViews.length = 0 ;
822
+
823
+ views = [];
824
+ nowShowing.forEach(function(idx) {
825
+ views.push(this.itemViewForContentIndex(idx, YES));
826
+ }, this);
827
+
828
+ // below is an optimized version of:
829
+ //this.replaceAllChildren(views);
830
+ containerView.beginPropertyChanges();
831
+ containerView.destroyLayer().removeAllChildren();
832
+ containerView.set('childViews', views); // quick swap
833
+ containerView.replaceLayer();
834
+ containerView.endPropertyChanges();
835
+
836
+ if (bench) SC.Benchmark.end(bench);
837
+
838
+ }
839
+
840
+ // adjust my own layout if computed
841
+ if (layout) this.adjust(layout);
842
+ if (this.didReload) this.didReload(invalid === YES ? null : invalid);
843
+
844
+
845
+ return this ;
846
+ },
847
+
848
+ displayProperties: 'isFirstResponder isEnabled isActive'.w(),
849
+
850
+ /** @private
851
+ If we're asked to render the receiver view for the first time but the
852
+ child views still need to be added, go ahead and add them.
853
+ */
854
+ render: function(context, firstTime) {
855
+ if (firstTime && this._needsReload) this.reloadIfNeeded ;
856
+
857
+ // add classes for other state.
858
+ context.setClass('focus', this.get('isFirstResponder'));
859
+ context.setClass('disabled', !this.get('isEnabled'));
860
+ context.setClass('active', this.get('isActive'));
861
+
862
+ return sc_super();
863
+ },
864
+
865
+
866
+ _TMP_ATTRS: {},
867
+ _COLLECTION_CLASS_NAMES: 'sc-collection-item'.w(),
868
+ _GROUP_COLLECTION_CLASS_NAMES: 'sc-collection-item sc-group-item'.w(),
869
+
870
+ /**
871
+ Returns the item view for the content object at the specified index. Call
872
+ this method instead of accessing child views directly whenever you need
873
+ to get the view associated with a content index.
874
+
875
+ Although this method take two parameters, you should almost always call
876
+ it with just the content index. The other two parameters are used
877
+ internally by the CollectionView.
878
+
879
+ If you need to change the way the collection view manages item views
880
+ you can override this method as well. If you just want to change the
881
+ default options used when creating item views, override createItemView()
882
+ instead.
883
+
884
+ Note that if you override this method, then be sure to implement this
885
+ method so that it uses a cache to return the same item view for a given
886
+ index unless "force" is YES. In that case, generate a new item view and
887
+ replace the old item view in your cache with the new item view.
888
+
889
+ @param {Number} idx the content index
890
+ @param {Boolean} rebuild internal use only
891
+ @returns {SC.View} instantiated view
892
+ */
893
+ itemViewForContentIndex: function(idx, rebuild) {
894
+
895
+ // return from cache if possible
896
+ var content = this.get('content'),
897
+ itemViews = this._sc_itemViews,
898
+ item = content.objectAt(idx),
899
+ del = this.get('contentDelegate'),
900
+ groupIndexes = del.contentGroupIndexes(this, content),
901
+ isGroupView = NO,
902
+ key, ret, E, layout, layerId;
903
+
904
+ // use cache if available
905
+ if (!itemViews) itemViews = this._sc_itemViews = [] ;
906
+ if (!rebuild && (ret = itemViews[idx])) return ret ;
907
+
908
+ // otherwise generate...
909
+
910
+ // first, determine the class to use
911
+ isGroupView = groupIndexes && groupIndexes.contains(idx);
912
+ if (isGroupView) isGroupView = del.contentIndexIsGroup(this, content,idx);
913
+ if (isGroupView) {
914
+ key = this.get('contentGroupExampleViewKey');
915
+ if (key && item) E = item.get(key);
916
+ if (!E) E = this.get('groupExampleView') || this.get('exampleView');
917
+
918
+ } else {
919
+ key = this.get('contentExampleViewKey');
920
+ if (key && item) E = item.get(key);
921
+ if (!E) E = this.get('exampleView');
922
+ }
923
+
924
+ // collect some other state
925
+ var attrs = this._TMP_ATTRS;
926
+ attrs.contentIndex = idx;
927
+ attrs.content = item ;
928
+ attrs.owner = attrs.displayDelegate = this;
929
+ attrs.parentView = this.get('containerView') || this ;
930
+ attrs.page = this.page ;
931
+ attrs.layerId = this.layerIdFor(idx, item);
932
+ attrs.isEnabled = del.contentIndexIsEnabled(this, content, idx);
933
+ attrs.isSelected = del.contentIndexIsSelected(this, content, idx);
934
+ attrs.outlineLevel = del.contentIndexOutlineLevel(this, content, idx);
935
+ attrs.disclosureState = del.contentIndexDisclosureState(this, content, idx);
936
+ attrs.isGroupView = isGroupView;
937
+ attrs.isVisibleInWindow = this.isVisibleInWindow;
938
+ if (isGroupView) attrs.classNames = this._GROUP_COLLECTION_CLASS_NAMES;
939
+ else attrs.classNames = this._COLLECTION_CLASS_NAMES;
940
+
941
+ layout = this.layoutForContentIndex(idx);
942
+ if (layout) {
943
+ attrs.layout = layout;
944
+ } else {
945
+ delete attrs.layout ;
946
+ }
947
+
948
+ ret = this.createItemView(E, idx, attrs);
949
+ itemViews[idx] = ret ;
950
+ return ret ;
951
+ },
952
+
953
+ _TMP_LAYERID: [],
954
+
955
+ /**
956
+ Primitive to instantiate an item view. You will be passed the class
957
+ and a content index. You can override this method to perform any other
958
+ one time setup.
959
+
960
+ Note that item views may be created somewhat frequently so keep this fast.
961
+
962
+ *IMPORTANT:* The attrs hash passed is reused each time this method is
963
+ called. If you add properties to this hash be sure to delete them before
964
+ returning from this method.
965
+
966
+ @param {Class} exampleClass example view class
967
+ @param {Number} idx the content index
968
+ @param {Hash} attrs expected attributes
969
+ @returns {SC.View} item view instance
970
+ */
971
+ createItemView: function(exampleClass, idx, attrs) {
972
+ return exampleClass.create(attrs);
973
+ },
974
+
975
+ /**
976
+ Generates a layerId for the passed index and item. Usually the default
977
+ implementation is suitable.
978
+
979
+ @param {Number} idx the content index
980
+ @returns {String} layer id, must be suitable for use in HTML id attribute
981
+ */
982
+ layerIdFor: function(idx) {
983
+ var ret = this._TMP_LAYERID;
984
+ ret[0] = SC.guidFor(this);
985
+ ret[1] = idx;
986
+ return ret.join('-');
987
+ },
988
+
989
+ /**
990
+ Extracts the content index from the passed layerID. If the layer id does
991
+ not belong to the receiver or if no value could be extracted, returns NO.
992
+
993
+ @param {String} id the layer id
994
+ */
995
+ contentIndexForLayerId: function(id) {
996
+ if (!id || !(id = id.toString())) return null ; // nothing to do
997
+
998
+ var base = this._baseLayerId;
999
+ if (!base) base = this._baseLayerId = SC.guidFor(this)+"-";
1000
+
1001
+ // no match
1002
+ if ((id.length <= base.length) || (id.indexOf(base) !== 0)) return null ;
1003
+ var ret = Number(id.slice(id.lastIndexOf('-')+1));
1004
+ return isNaN(ret) ? null : ret ;
1005
+ },
1006
+
1007
+
1008
+ /**
1009
+ Find the first content item view for the passed event.
1010
+
1011
+ This method will go up the view chain, starting with the view that was the
1012
+ target of the passed event, looking for a child item. This will become
1013
+ the view that is selected by the mouse event.
1014
+
1015
+ This method only works for mouseDown & mouseUp events. mouseMoved events
1016
+ do not have a target.
1017
+
1018
+ @param {SC.Event} evt An event
1019
+ @returns {SC.View} the item view or null
1020
+ */
1021
+ itemViewForEvent: function(evt) {
1022
+ var responder = this.getPath('pane.rootResponder') ;
1023
+ if (!responder) return null ; // fast path
1024
+
1025
+ var base = SC.guidFor(this) + '-',
1026
+ baseLen = base.length,
1027
+ element = evt.target,
1028
+ layer = this.get('layer'),
1029
+ contentIndex = null,
1030
+ id, itemView, ret ;
1031
+
1032
+ // walk up the element hierarchy until we find this or an element with an
1033
+ // id matching the base guid (i.e. a collection item)
1034
+ while (element && element !== document && element !== layer) {
1035
+ id = element ? element.getAttribute('id') : null ;
1036
+ if (id && (contentIndex = this.contentIndexForLayerId(id)) !== null) {
1037
+ break;
1038
+ }
1039
+ element = element.parentNode ;
1040
+ }
1041
+
1042
+ // no matching element found?
1043
+ if (contentIndex===null || (element === layer)) {
1044
+ element = layer = null; // avoid memory leaks
1045
+ return null;
1046
+ }
1047
+
1048
+ // okay, found the DOM node for the view, go ahead and create it
1049
+ // first, find the contentIndex
1050
+ if (contentIndex >= this.get('length')) {
1051
+ throw "layout for item view %@ was found when item view does not exist (%@)".fmt(id, this);
1052
+ }
1053
+
1054
+ return this.itemViewForContentIndex(contentIndex);
1055
+ },
1056
+
1057
+ // ..........................................................
1058
+ // DISCLOSURE SUPPORT
1059
+ //
1060
+
1061
+ /**
1062
+ Expands any items in the passed selection array that have a disclosure
1063
+ state.
1064
+
1065
+ @param {SC.IndexSet} indexes the indexes to expand
1066
+ @returns {SC.CollectionView} receiver
1067
+ */
1068
+ expand: function(indexes) {
1069
+ if (!indexes) return this; // nothing to do
1070
+ var del = this.get('contentDelegate'),
1071
+ content = this.get('content');
1072
+
1073
+ indexes.forEach(function(i) {
1074
+ var state = del.contentIndexDisclosureState(this, content, i);
1075
+ if (state === SC.BRANCH_CLOSED) del.contentIndexExpand(this,content,i);
1076
+ }, this);
1077
+ return this;
1078
+ },
1079
+
1080
+ /**
1081
+ Collapses any items in the passed selection array that have a disclosure
1082
+ state.
1083
+
1084
+ @param {SC.IndexSet} indexes the indexes to expand
1085
+ @returns {SC.CollectionView} receiver
1086
+ */
1087
+ collapse: function(indexes) {
1088
+ if (!indexes) return this; // nothing to do
1089
+ var del = this.get('contentDelegate'),
1090
+ content = this.get('content');
1091
+
1092
+ indexes.forEach(function(i) {
1093
+ var state = del.contentIndexDisclosureState(this, content, i);
1094
+ if (state === SC.BRANCH_OPEN) del.contentIndexCollapse(this,content,i);
1095
+ }, this);
1096
+ return this;
1097
+ },
1098
+
1099
+ // ..........................................................
1100
+ // SELECTION SUPPORT
1101
+ //
1102
+
1103
+ /** @private
1104
+
1105
+ Called whenever the selection object is changed to a new value. Begins
1106
+ observing the selection for changes.
1107
+
1108
+ */
1109
+ _cv_selectionDidChange: function() {
1110
+ var sel = this.get('selection'),
1111
+ last = this._cv_selection,
1112
+ func = this._cv_selectionContentDidChange;
1113
+
1114
+ if (sel === last) return this; // nothing to do
1115
+ if (last) last.removeObserver('[]', this, func);
1116
+ if (sel) sel.addObserver('[]', this, func);
1117
+
1118
+ this._cv_selection = sel ;
1119
+ this._cv_selectionContentDidChange();
1120
+ }.observes('selection'),
1121
+
1122
+ /** @private
1123
+
1124
+ Called whenever the selection object or its content changes. This will
1125
+ repaint any items that changed their selection state.
1126
+
1127
+ */
1128
+ _cv_selectionContentDidChange: function() {
1129
+ var sel = this.get('selection'),
1130
+ last = this._cv_selindexes, // clone of last known indexes
1131
+ content = this.get('content'),
1132
+ diff ;
1133
+
1134
+ // save new last
1135
+ this._cv_selindexes = sel ? sel.frozenCopy() : null;
1136
+
1137
+ // determine which indexes are now invalid
1138
+ if (last) last = last.indexSetForSource(content);
1139
+ if (sel) sel = sel.indexSetForSource(content);
1140
+
1141
+ if (sel && last) diff = sel.without(last).add(last.without(sel));
1142
+ else diff = sel || last;
1143
+
1144
+ if (diff && diff.get('length')>0) this.reloadSelectionIndexes(diff);
1145
+ },
1146
+
1147
+ /** @private
1148
+ Contains the current item views that need their selection to be repainted.
1149
+ This may be either NO, YES, or an IndexSet.
1150
+ */
1151
+ _invalidSelection: NO,
1152
+
1153
+ /**
1154
+ Called whenever the selection changes. The passed index set will contain
1155
+ any affected indexes including those indexes that were previously
1156
+ selected and now should be deselected.
1157
+
1158
+ Pass null to reload the selection state for all items.
1159
+
1160
+ @param {SC.IndexSet} indexes affected indexes
1161
+ @returns {SC.CollectionView} reciever
1162
+ */
1163
+ reloadSelectionIndexes: function(indexes) {
1164
+ var invalid = this._invalidSelection ;
1165
+ if (indexes && (invalid !== YES)) {
1166
+ if (invalid) invalid.add(indexes)
1167
+ else invalid = this._invalidSelection = indexes.copy();
1168
+
1169
+ } else this._invalidSelection = YES ; // force a total reload
1170
+
1171
+ if (this.get('isVisibleInWindow')) {
1172
+ this.invokeOnce(this.reloadSelectionIndexesIfNeeded);
1173
+ }
1174
+
1175
+ return this ;
1176
+ },
1177
+
1178
+ /**
1179
+ Reloads the selection state if needed on any dirty indexes. Normally this
1180
+ will run once at the end of the runloop, but you can force the item views
1181
+ to reload their selection immediately by calling this method.
1182
+
1183
+ You can also override this method if needed to change the way the
1184
+ selection is reloaded on item views. The default behavior will simply
1185
+ find any item views in the nowShowing range that are affected and
1186
+ modify them.
1187
+
1188
+ @returns {SC.CollectionView} receiver
1189
+ */
1190
+ reloadSelectionIndexesIfNeeded: function() {
1191
+ var invalid = this._invalidSelection;
1192
+ if (!invalid || !this.get('isVisibleInWindow')) return this ;
1193
+
1194
+ var nowShowing = this.get('nowShowing'),
1195
+ reload = this._invalidIndexes,
1196
+ content = this.get('content'),
1197
+ sel = this.get('selection');
1198
+
1199
+ this._invalidSelection = NO; // reset invalid
1200
+
1201
+ // fast path. if we are going to reload everything anyway, just forget
1202
+ // about it. Also if we don't have a nowShowing, nothing to do.
1203
+ if (reload === YES || !nowShowing) return this ;
1204
+
1205
+ // if invalid is YES instead of index set, just reload everything
1206
+ if (invalid === YES) invalid = nowShowing;
1207
+
1208
+ // if we will reload some items anyway, don't bother
1209
+ if (reload && reload.isIndexSet) invalid = invalid.without(reload);
1210
+
1211
+ // iterate through each item and set the isSelected state.
1212
+ invalid.forEach(function(idx) {
1213
+ if (!nowShowing.contains(idx)) return; // not showing
1214
+ var view = this.itemViewForContentIndex(idx, NO);
1215
+ if (view) view.set('isSelected', sel ? sel.contains(content, idx) : NO);
1216
+ },this);
1217
+
1218
+ return this ;
1219
+ },
1220
+
1221
+ /**
1222
+ Selection primitive. Selects the passed IndexSet of items, optionally
1223
+ extending the current selection. If extend is NO or not passed then this
1224
+ will replace the selection with the passed value. Otherwise the indexes
1225
+ will be added to the current selection.
1226
+
1227
+ @param {Number|SC.IndexSet} indexes index or indexes to select
1228
+ @param extend {Boolean} optionally extend the selection
1229
+ @returns {SC.CollectionView} receiver
1230
+ */
1231
+ select: function(indexes, extend) {
1232
+
1233
+ var content = this.get('content'),
1234
+ del = this.get('selectionDelegate'),
1235
+ cdel = this.get('contentDelegate'),
1236
+ groupIndexes = cdel.contentGroupIndexes(this, content),
1237
+ sel;
1238
+
1239
+ // normalize
1240
+ if (SC.typeOf(indexes) === SC.T_NUMBER) {
1241
+ indexes = SC.IndexSet.create(indexes, 1);
1242
+ }
1243
+
1244
+ // if we are passed an empty index set or null, clear the selection.
1245
+ if (indexes && indexes.get('length')>0) {
1246
+
1247
+ // first remove any group indexes - these can never be selected
1248
+ if (groupIndexes && groupIndexes.get('length')>0) {
1249
+ indexes = indexes.copy().remove(groupIndexes);
1250
+ }
1251
+
1252
+ // give the delegate a chance to alter the items
1253
+ indexes = del.collectionViewShouldSelectIndexes(this, indexes, extend);
1254
+ if (!indexes || indexes.get('length')===0) return this; // nothing to do
1255
+
1256
+ } else indexes = null;
1257
+
1258
+ // build the selection object, merging if needed
1259
+ if (extend && (sel = this.get('selection'))) sel = sel.copy();
1260
+ else sel = SC.SelectionSet.create();
1261
+ if (indexes) sel.add(content, indexes);
1262
+
1263
+ // give delegate one last chance
1264
+ sel = del.collectionViewSelectionForProposedSelection(this, sel);
1265
+ if (!sel) sel = SC.SelectionSet.create(); // empty
1266
+
1267
+ // if we're not extending the selection, clear the selection anchor
1268
+ this._selectionAnchor = null ;
1269
+ this.set('selection', sel.freeze()) ;
1270
+ return this;
1271
+ },
1272
+
1273
+ /**
1274
+ Primtive to remove the indexes from the selection.
1275
+
1276
+ @param {Number|SC.IndexSet} indexes index or indexes to select
1277
+ @returns {SC.CollectionView} receiver
1278
+ */
1279
+ deselect: function(indexes) {
1280
+
1281
+ var sel = this.get('selection'),
1282
+ content = this.get('content'),
1283
+ del = this.get('selectionDelegate');
1284
+
1285
+ if (!sel || sel.get('length')===0) return this; // nothing to do
1286
+
1287
+ // normalize
1288
+ if (SC.typeOf(indexes) === SC.T_NUMBER) {
1289
+ indexes = SC.IndexSet.create(indexes, 1);
1290
+ }
1291
+
1292
+ // give the delegate a chance to alter the items
1293
+ indexes = del.collectionViewShouldDeselectIndexes(this, indexes) ;
1294
+ if (!indexes || indexes.get('length')===0) return this; // nothing to do
1295
+
1296
+ // now merge change - note we expect sel && indexes to not be null
1297
+ sel = sel.copy().remove(content, indexes);
1298
+ sel = del.collectionViewSelectionForProposedSelection(this, sel);
1299
+ if (!sel) sel = SC.SelectionSet.create(); // empty
1300
+
1301
+ this.set('selection', sel.freeze()) ;
1302
+ return this ;
1303
+ },
1304
+
1305
+ /** @private
1306
+ Finds the next selectable item, up to content length, by asking the
1307
+ delegate. If a non-selectable item is found, the index is skipped. If
1308
+ no item is found, selection index is returned unmodified.
1309
+
1310
+ Return value will always be in the range of the bottom of the current
1311
+ selection index and the proposed index.
1312
+
1313
+ @param {Number} proposedIndex the desired index to select
1314
+ @param {Number} bottom optional bottom of selection use as fallback
1315
+ @returns {Number} next selectable index.
1316
+ */
1317
+ _findNextSelectableItemFromIndex: function(proposedIndex, bottom) {
1318
+
1319
+ var lim = this.get('length'),
1320
+ range = SC.IndexSet.create(),
1321
+ content = this.get('content'),
1322
+ del = this.get('selectionDelegate'),
1323
+ cdel = this.get('contentDelegate'),
1324
+ groupIndexes = cdel.contentGroupIndexes(this, content),
1325
+ ret, sel ;
1326
+
1327
+ // fast path
1328
+ if (!groupIndexes && (del.collectionViewShouldSelectIndexes === this.collectionViewShouldSelectIndexes)) {
1329
+ return proposedIndex;
1330
+ }
1331
+
1332
+ // loop forwards looking for an index that is allowed by delegate
1333
+ // we could alternatively just pass the whole range but this might be
1334
+ // slow for the delegate
1335
+ while (proposedIndex < lim) {
1336
+ if (!groupIndexes || !groupIndexes.contains(proposedIndex)) {
1337
+ range.add(proposedIndex);
1338
+ ret = del.collectionViewShouldSelectIndexes(this, range);
1339
+ if (ret && ret.get('length') >= 1) return proposedIndex ;
1340
+ range.remove(proposedIndex);
1341
+ }
1342
+ proposedIndex++;
1343
+ }
1344
+
1345
+ // if nothing was found, return top of selection
1346
+ if (bottom === undefined) {
1347
+ sel = this.get('selection');
1348
+ bottom = sel ? sel.get('max') : -1 ;
1349
+ }
1350
+ return bottom ;
1351
+ },
1352
+
1353
+ /** @private
1354
+ Finds the previous selectable item, up to the first item, by asking the
1355
+ delegate. If a non-selectable item is found, the index is skipped. If
1356
+ no item is found, selection index is returned unmodified.
1357
+
1358
+ @param {Integer} proposedIndex the desired index to select
1359
+ @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.
1360
+ @private
1361
+ */
1362
+ _findPreviousSelectableItemFromIndex: function(proposedIndex, top) {
1363
+ var range = SC.IndexSet.create(),
1364
+ content = this.get('content'),
1365
+ del = this.get('selectionDelegate'),
1366
+ cdel = this.get('contentDelegate'),
1367
+ groupIndexes = cdel.contentGroupIndexes(this, content),
1368
+ ret ;
1369
+
1370
+ if (SC.none(proposedIndex)) proposedIndex = -1;
1371
+
1372
+ // fast path
1373
+ if (!groupIndexes && (del.collectionViewShouldSelectIndexes === this.collectionViewShouldSelectIndexes)) {
1374
+ return proposedIndex;
1375
+ }
1376
+
1377
+ // loop backwards looking for an index that is allowed by delegate
1378
+ // we could alternatively just pass the whole range but this might be
1379
+ // slow for the delegate
1380
+ while (proposedIndex >= 0) {
1381
+ if (!groupIndexes || !groupIndexes.contains(proposedIndex)) {
1382
+ range.add(proposedIndex);
1383
+ ret = del.collectionViewShouldSelectIndexes(this, range);
1384
+ if (ret && ret.get('length') >= 1) return proposedIndex ;
1385
+ range.remove(proposedIndex);
1386
+ }
1387
+ proposedIndex--;
1388
+ }
1389
+
1390
+ // if nothing was found, return top of selection
1391
+ if (top === undefined) {
1392
+ var sel = this.get('selection');
1393
+ top = sel ? sel.get('min') : -1 ;
1394
+ }
1395
+ if (SC.none(top)) top = -1;
1396
+ return top ;
1397
+ },
1398
+
1399
+ /**
1400
+ Select one or more items before the current selection, optionally
1401
+ extending the current selection. Also scrolls the selected item into
1402
+ view.
1403
+
1404
+ Selection does not wrap around.
1405
+
1406
+ @param extend {Boolean} (Optional) If true, the selection will be extended
1407
+ instead of replaced. Defaults to false.
1408
+ @param numberOfItems {Integer} (Optional) The number of previous to be
1409
+ selected. Defaults to 1
1410
+ @returns {SC.CollectionView} receiver
1411
+ */
1412
+ selectPreviousItem: function(extend, numberOfItems) {
1413
+ if (SC.none(numberOfItems)) numberOfItems = 1 ;
1414
+ if (SC.none(extend)) extend = false ;
1415
+
1416
+ var sel = this.get('selection'),
1417
+ content = this.get('content');
1418
+ if (sel) sel = sel.indexSetForSource(content);
1419
+
1420
+ var selTop = sel ? sel.get('min') : -1,
1421
+ selBottom = sel ? sel.get('max')-1 : -1,
1422
+ anchor = this._selectionAnchor;
1423
+ if (SC.none(anchor)) anchor = selTop;
1424
+
1425
+ // if extending, then we need to do some fun stuff to build the array
1426
+ if (extend) {
1427
+
1428
+ // If the selBottom is after the anchor, then reduce the selection
1429
+ if (selBottom > anchor) {
1430
+ selBottom = selBottom - numberOfItems ;
1431
+
1432
+ // otherwise, select the previous item from the top
1433
+ } else {
1434
+ selTop = this._findPreviousSelectableItemFromIndex(selTop - numberOfItems);
1435
+ }
1436
+
1437
+ // Ensure we are not out of bounds
1438
+ if (SC.none(selTop) || (selTop < 0)) selTop = 0 ;
1439
+ if (selBottom < selTop) selBottom = selTop ;
1440
+
1441
+ // if not extending, just select the item previous to the selTop
1442
+ } else {
1443
+ selTop = this._findPreviousSelectableItemFromIndex(selTop - numberOfItems);
1444
+ if (SC.none(selTop) || (selTop < 0)) selTop = 0 ;
1445
+ selBottom = selTop ;
1446
+ anchor = null ;
1447
+ }
1448
+
1449
+ var scrollToIndex = selTop ;
1450
+
1451
+ // now build new selection
1452
+ sel = SC.IndexSet.create(selTop, selBottom+1-selTop);
1453
+
1454
+ // ensure that the item is visible and set the selection
1455
+ this.scrollToContentIndex(scrollToIndex) ;
1456
+ this.select(sel) ;
1457
+ this._selectionAnchor = anchor ;
1458
+ return this ;
1459
+ },
1460
+
1461
+ /**
1462
+ Select one or more items folling the current selection, optionally
1463
+ extending the current selection. Also scrolls to selected item.
1464
+
1465
+ Selection does not wrap around.
1466
+
1467
+ @param extend {Boolean} (Optional) If true, the selection will be extended
1468
+ instead of replaced. Defaults to false.
1469
+ @param numberOfItems {Integer} (Optional) The number of items to be
1470
+ selected. Defaults to 1.
1471
+ @returns {SC.CollectionView} receiver
1472
+ */
1473
+ selectNextItem: function(extend, numberOfItems) {
1474
+ if (SC.none(numberOfItems)) numberOfItems = 1 ;
1475
+ if (SC.none(extend)) extend = false ;
1476
+
1477
+ var sel = this.get('selection'),
1478
+ content = this.get('content');
1479
+ if (sel) sel = sel.indexSetForSource(content);
1480
+
1481
+ var selTop = sel ? sel.get('min') : -1,
1482
+ selBottom = sel ? sel.get('max')-1 : -1,
1483
+ anchor = this._selectionAnchor,
1484
+ lim = this.get('length');
1485
+
1486
+ if (SC.none(anchor)) anchor = selTop;
1487
+
1488
+ // if extending, then we need to do some fun stuff to build the array
1489
+ if (extend) {
1490
+
1491
+ // If the selTop is before the anchor, then reduce the selection
1492
+ if (selTop < anchor) {
1493
+ selTop = selTop + numberOfItems ;
1494
+
1495
+ // otherwise, select the next item after the bottom
1496
+ } else {
1497
+ selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems, selBottom);
1498
+ }
1499
+
1500
+ // Ensure we are not out of bounds
1501
+ if (selBottom >= lim) selBottom = lim-1;
1502
+ if (selTop > selBottom) selTop = selBottom ;
1503
+
1504
+ // if not extending, just select the item next to the selBottom
1505
+ } else {
1506
+ selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems, selBottom);
1507
+
1508
+ if (selBottom >= lim) selBottom = lim-1;
1509
+ selTop = selBottom ;
1510
+ anchor = null ;
1511
+ }
1512
+
1513
+ var scrollToIndex = selBottom ;
1514
+
1515
+ // now build new selection
1516
+ sel = SC.IndexSet.create(selTop, selBottom-selTop+1);
1517
+
1518
+ // ensure that the item is visible and set the selection
1519
+ this.scrollToContentIndex(scrollToIndex) ;
1520
+ this.select(sel) ;
1521
+ this._selectionAnchor = anchor ;
1522
+ return this ;
1523
+ },
1524
+
1525
+ /**
1526
+ Deletes the selected content if canDeleteContent is YES. This will invoke
1527
+ delegate methods to provide fine-grained control. Returns YES if the
1528
+ deletion was possible, even if none actually occurred.
1529
+
1530
+ @returns {Boolean} YES if deletion is possible.
1531
+ */
1532
+ deleteSelection: function() {
1533
+
1534
+ // perform some basic checks...
1535
+ if (!this.get('canDeleteContent')) return NO;
1536
+
1537
+ var sel = this.get('selection'),
1538
+ content = this.get('content'),
1539
+ del = this.get('selectionDelegate'),
1540
+ indexes = sel&&content ? sel.indexSetForSource(content) : null;
1541
+
1542
+ if (!content || !indexes || indexes.get('length') === 0) return NO ;
1543
+
1544
+ // let the delegate decide what to actually delete. If this returns an
1545
+ // empty index set or null, just do nothing.
1546
+ indexes = del.collectionViewShouldDeleteIndexes(this, indexes);
1547
+ if (!indexes || indexes.get('length') === 0) return NO ;
1548
+
1549
+ // now have the delegate (or us) perform the deletion. The default
1550
+ // delegate implementation just uses standard SC.Array methods to do the
1551
+ // right thing.
1552
+ del.collectionViewDeleteContent(this, this.get('content'), indexes);
1553
+
1554
+ // also, fix up the selection by removing the actual items we removed
1555
+ // set selection directly instead of calling select() since we are just
1556
+ // fixing up the selection.
1557
+ sel = this.get('selection').copy().remove(content, indexes);
1558
+ this.set('selection', sel.freeze());
1559
+
1560
+ return YES ;
1561
+ },
1562
+
1563
+ // ..........................................................
1564
+ // SCROLLING
1565
+ //
1566
+
1567
+ /**
1568
+ Scroll the rootElement (if needed) to ensure that the item is visible.
1569
+
1570
+ @param {Number} contentIndex The index of the item to scroll to
1571
+ @returns {SC.CollectionView} receiver
1572
+ */
1573
+ scrollToContentIndex: function(contentIndex) {
1574
+ var itemView = this.itemViewForContentIndex(contentIndex) ;
1575
+ if (itemView) this.scrollToItemView(itemView) ;
1576
+ return this;
1577
+ },
1578
+
1579
+ /**
1580
+ Scroll to the passed item view. If the item view is not visible on screen
1581
+ this method will not work.
1582
+
1583
+ @param {SC.View} view The item view to scroll to
1584
+ @returns {SC.CollectionView} receiver
1585
+ */
1586
+ scrollToItemView: function(view) {
1587
+ if (!view.get('parentView')) return this; // nothing to do
1588
+ if (!view.get('layer')) {
1589
+ if (this.get('layer')) view.updateLayerLocation();
1590
+ else return this; // nothing to do
1591
+ }
1592
+
1593
+ var scrollable = this;
1594
+ while (scrollable && !scrollable.isPane) {
1595
+ if (scrollable.get('isScrollable')) scrollable.scrollToVisible(view);
1596
+ scrollable = scrollable.get('parentView');
1597
+ }
1598
+ return this ;
1599
+ },
1600
+
1601
+ // ..........................................................
1602
+ // KEYBOARD EVENTS
1603
+ //
1604
+
1605
+ /** @private */
1606
+ keyDown: function(evt) {
1607
+ var ret = this.interpretKeyEvents(evt) ;
1608
+ return !ret ? NO : ret ;
1609
+ },
1610
+
1611
+ /** @private */
1612
+ keyUp: function() { return true; },
1613
+
1614
+ /** @private
1615
+ Handle select all keyboard event.
1616
+ */
1617
+ selectAll: function(evt) {
1618
+ var content = this.get('content'),
1619
+ sel = content ? SC.IndexSet.create(0, content.get('length')) : null;
1620
+ this.select(sel, NO) ;
1621
+ return YES ;
1622
+ },
1623
+
1624
+ /** @private
1625
+ Handle delete keyboard event.
1626
+ */
1627
+ deleteBackward: function(evt) {
1628
+ return this.deleteSelection() ;
1629
+ },
1630
+
1631
+ /** @private
1632
+ Handle delete keyboard event.
1633
+ */
1634
+ deleteForward: function(evt) {
1635
+ return this.deleteSelection() ;
1636
+ },
1637
+
1638
+ /** @private
1639
+ Selects the same item on the next row or moves down one if itemsPerRow = 1
1640
+ */
1641
+ moveDown: function(sender, evt) {
1642
+ this.selectNextItem(false, this.get('itemsPerRow') || 1) ;
1643
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1644
+ return true ;
1645
+ },
1646
+
1647
+ /** @private
1648
+ Selects the same item on the next row or moves up one if itemsPerRow = 1
1649
+ */
1650
+ moveUp: function(sender, evt) {
1651
+ this.selectPreviousItem(false, this.get('itemsPerRow') || 1) ;
1652
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1653
+ return true ;
1654
+ },
1655
+
1656
+ /** @private
1657
+ Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
1658
+ If item is expandable, will collapse.
1659
+ */
1660
+ moveLeft: function(sender, evt) {
1661
+ if ((this.get('itemsPerRow') || 1) > 1) {
1662
+ this.selectPreviousItem(false, 1);
1663
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1664
+
1665
+ } else {
1666
+ var sel = this.get('selection'),
1667
+ content = this.get('content'),
1668
+ indexes = sel ? sel.indexSetForSource(content) : null;
1669
+
1670
+ // Collapse the element if it is expanded. However, if there is exactly
1671
+ // one item selected and the item is already collapsed or is a leaf
1672
+ // node, then select the (expanded) parent element instead as a
1673
+ // convenience to the user.
1674
+ if ( indexes ) {
1675
+ var del = undefined, // We'll load it lazily
1676
+ selectParent = false,
1677
+ index = undefined;
1678
+
1679
+ if ( indexes.get('length') === 1 ) {
1680
+ index = indexes.get('firstObject');
1681
+ del = this.get('contentDelegate');
1682
+ var state = del.contentIndexDisclosureState(this, content, index);
1683
+ if (state !== SC.BRANCH_OPEN) selectParent = true;
1684
+ }
1685
+
1686
+ if ( selectParent ) {
1687
+ // TODO: PERFORMANCE: It would be great to have a function like
1688
+ // SC.CollectionView.selectParentItem() or something similar
1689
+ // for performance reasons. But since we don't currently
1690
+ // have such a function, let's just iterate through the
1691
+ // previous items until we find the first one with a outline
1692
+ // level of one less than the selected item.
1693
+ var desiredOutlineLevel = del.contentIndexOutlineLevel(this, content, index) - 1;
1694
+ if ( desiredOutlineLevel >= 0 ) {
1695
+ var parentIndex = -1;
1696
+ while ( parentIndex < 0 ) {
1697
+ var previousItemIndex = this._findPreviousSelectableItemFromIndex(index - 1);
1698
+ if (previousItemIndex < 0 ) return false; // Sanity-check.
1699
+ index = previousItemIndex;
1700
+ var outlineLevel = del.contentIndexOutlineLevel(this, content, index);
1701
+ if ( outlineLevel === desiredOutlineLevel ) {
1702
+ parentIndex = previousItemIndex;
1703
+ }
1704
+ }
1705
+
1706
+ // If we found the parent, select it now.
1707
+ if ( parentIndex !== -1 ) {
1708
+ this.select(index);
1709
+ }
1710
+ }
1711
+ }
1712
+ else {
1713
+ this.collapse(indexes);
1714
+ }
1715
+ }
1716
+ }
1717
+
1718
+ return true ;
1719
+ },
1720
+
1721
+ /** @private
1722
+ Selects the next item if itemsPerRow > 1. Otherwise does nothing.
1723
+ */
1724
+ moveRight: function(sender, evt) {
1725
+ if ((this.get('itemsPerRow') || 1) > 1) {
1726
+ this.selectNextItem(false, 1) ;
1727
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1728
+ } else {
1729
+ var sel = this.get('selection'),
1730
+ content = this.get('content'),
1731
+ indexes = sel ? sel.indexSetForSource(content) : null;
1732
+ if (indexes) this.expand(indexes);
1733
+ }
1734
+
1735
+ return true ;
1736
+ },
1737
+
1738
+ /** @private */
1739
+ moveDownAndModifySelection: function(sender, evt) {
1740
+ this.selectNextItem(true, this.get('itemsPerRow') || 1) ;
1741
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1742
+ return true ;
1743
+ },
1744
+
1745
+ /** @private */
1746
+ moveUpAndModifySelection: function(sender, evt) {
1747
+ this.selectPreviousItem(true, this.get('itemsPerRow') || 1) ;
1748
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1749
+ return true ;
1750
+ },
1751
+
1752
+ /** @private
1753
+ Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
1754
+ */
1755
+ moveLeftAndModifySelection: function(sender, evt) {
1756
+ if ((this.get('itemsPerRow') || 1) > 1) {
1757
+ this.selectPreviousItem(true, 1) ;
1758
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1759
+ }
1760
+ return true ;
1761
+ },
1762
+
1763
+ /** @private
1764
+ Selects the next item if itemsPerRow > 1. Otherwise does nothing.
1765
+ */
1766
+ moveRightAndModifySelection: function(sender, evt) {
1767
+ if ((this.get('itemsPerRow') || 1) > 1) {
1768
+ this.selectNextItem(true, 1) ;
1769
+ this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
1770
+ }
1771
+ return true ;
1772
+ },
1773
+
1774
+
1775
+
1776
+ /** @private
1777
+ if content value is editable and we have one item selected, then edit.
1778
+ otherwise, invoke action.
1779
+ */
1780
+ insertNewline: function(sender, evt) {
1781
+ var canEdit = this.get('isEditable') && this.get('canEditContent'),
1782
+ sel, content, set, idx, itemView;
1783
+
1784
+ // first make sure we have a single item selected; get idx
1785
+ if (canEdit) {
1786
+ sel = this.get('selection') ;
1787
+ content = this.get('content');
1788
+ if (sel && sel.get('length') === 1) {
1789
+ set = sel.indexSetForSource(content);
1790
+ idx = set ? set.get('min') : -1;
1791
+ canEdit = idx>=0;
1792
+ }
1793
+ }
1794
+
1795
+ // next find itemView and ensure it supports editing
1796
+ if (canEdit) {
1797
+ itemView = this.itemViewForContentIndex(idx);
1798
+ canEdit = itemView && SC.typeOf(itemView.beginEditing)===SC.T_FUNCTION;
1799
+ }
1800
+
1801
+ // ok, we can edit..
1802
+ if (canEdit) {
1803
+ this.scrollToContentIndex(idx);
1804
+ itemView = this.itemViewForContentIndex(idx); // just in case
1805
+ itemView.beginEditing();
1806
+
1807
+ // invoke action
1808
+ } else {
1809
+ this.invokeLater(this._cv_action, 0, itemView, null) ;
1810
+ }
1811
+
1812
+ return YES ; // always handle
1813
+ },
1814
+
1815
+ // ..........................................................
1816
+ // MOUSE EVENTS
1817
+ //
1818
+
1819
+ /** @private
1820
+ Handles mouse down events on the collection view or on any of its
1821
+ children.
1822
+
1823
+ The default implementation of this method can handle a wide variety
1824
+ of user behaviors depending on how you have configured the various
1825
+ options for the collection view.
1826
+
1827
+ @param ev {Event} the mouse down event
1828
+ @returns {Boolean} Usually YES.
1829
+ */
1830
+ mouseDown: function(ev) {
1831
+
1832
+ // When the user presses the mouse down, we don't do much just yet.
1833
+ // Instead, we just need to save a bunch of state about the mouse down
1834
+ // so we can choose the right thing to do later.
1835
+
1836
+ // Toggle selection only triggers on mouse up. Do nothing.
1837
+ if (this.get('useToggleSelection')) return true;
1838
+
1839
+ // find the actual view the mouse was pressed down on. This will call
1840
+ // hitTest() on item views so they can implement non-square detection
1841
+ // modes. -- once we have an item view, get its content object as well.
1842
+ var itemView = this.itemViewForEvent(ev),
1843
+ content = this.get('content'),
1844
+ contentIndex = itemView ? itemView.get('contentIndex') : -1,
1845
+ info, anchor ;
1846
+
1847
+ info = this.mouseDownInfo = {
1848
+ event: ev,
1849
+ itemView: itemView,
1850
+ contentIndex: contentIndex,
1851
+ at: Date.now()
1852
+ };
1853
+
1854
+ // become first responder if possible.
1855
+ this.becomeFirstResponder() ;
1856
+
1857
+ // recieved a mouseDown on the collection element, but not on one of the
1858
+ // childItems... unless we do not allow empty selections, set it to empty.
1859
+ if (!itemView) {
1860
+ if (this.get('allowDeselectAll')) this.select(null, false);
1861
+ return YES ;
1862
+ }
1863
+
1864
+ // collection some basic setup info
1865
+ var sel = this.get('selection'), isSelected, modifierKeyPressed;
1866
+ if (sel) sel = sel.indexSetForSource(content);
1867
+
1868
+ isSelected = sel ? sel.contains(contentIndex) : NO;
1869
+ info.modifierKeyPressed = modifierKeyPressed = ev.ctrlKey || ev.metaKey ;
1870
+
1871
+ // holding down a modifier key while clicking a selected item should
1872
+ // deselect that item...deselect and bail.
1873
+ if (modifierKeyPressed && isSelected) {
1874
+ info.shouldDeselect = contentIndex >= 0;
1875
+
1876
+ // if the shiftKey was pressed, then we want to extend the selection
1877
+ // from the last selected item
1878
+ } else if (ev.shiftKey && sel && sel.get('length') > 0) {
1879
+ sel = this._findSelectionExtendedByShift(sel, contentIndex);
1880
+ anchor = this._selectionAnchor ;
1881
+ this.select(sel) ;
1882
+ this._selectionAnchor = anchor; //save the anchor
1883
+
1884
+ // If no modifier key was pressed, then clicking on the selected item
1885
+ // should clear the selection and reselect only the clicked on item.
1886
+ } else if (!modifierKeyPressed && isSelected) {
1887
+ info.shouldReselect = contentIndex >= 0;
1888
+
1889
+ // Otherwise, if selecting on mouse down, simply select the clicked on
1890
+ // item, adding it to the current selection if a modifier key was pressed.
1891
+ } else {
1892
+ if (this.get("selectOnMouseDown")) {
1893
+ this.select(contentIndex, modifierKeyPressed);
1894
+ } else {
1895
+ info.shouldSelect = contentIndex >= 0 ;
1896
+ }
1897
+ }
1898
+
1899
+ // saved for extend by shift ops.
1900
+ info.previousContentIndex = contentIndex;
1901
+
1902
+ return YES;
1903
+ },
1904
+
1905
+ /** @private */
1906
+ mouseUp: function(ev) {
1907
+
1908
+ var view = this.itemViewForEvent(ev),
1909
+ info = this.mouseDownInfo,
1910
+ idx = info.contentIndex,
1911
+ contentIndex, sel, isSelected, canEdit, itemView, content;
1912
+
1913
+ if (this.get('useToggleSelection')) {
1914
+ if (!view) return ; // do nothing when clicked outside of elements
1915
+
1916
+ // determine if item is selected. If so, then go on.
1917
+ sel = this.get('selection') ;
1918
+ contentIndex = (view) ? view.get('contentIndex') : -1 ;
1919
+ isSelected = sel && sel.include(contentIndex) ;
1920
+
1921
+ if (isSelected) this.deselect(contentIndex) ;
1922
+ else this.select(contentIndex, YES) ;
1923
+
1924
+ } else {
1925
+ contentIndex = (view) ? view.get('contentIndex') : -1 ;
1926
+
1927
+ // this will be set if the user simply clicked on an unselected item and
1928
+ // selectOnMouseDown was NO.
1929
+ if (info.shouldSelect) this.select(idx, info.modifierKeyPressed);
1930
+
1931
+ // This is true if the user clicked on a selected item with a modifier
1932
+ // key pressed.
1933
+ if (info.shouldDeselect) this.deselect(idx);
1934
+
1935
+ // This is true if the user clicked on a selected item without a
1936
+ // modifier-key pressed. When this happens we try to begin editing
1937
+ // on the content. If that is not allowed, then simply clear the
1938
+ // selection and reselect the clicked on item.
1939
+ if (info.shouldReselect) {
1940
+
1941
+ //debugger ;
1942
+ // - contentValueIsEditable is true
1943
+ canEdit = this.get('isEditable') && this.get('canEditContent') ;
1944
+
1945
+ // - the user clicked on an item that was already selected
1946
+ // ^ this is the only way shouldReset is set to YES
1947
+
1948
+ // - is the only item selected
1949
+ if (canEdit) {
1950
+ sel = this.get('selection') ;
1951
+ canEdit = sel && (sel.get('length') === 1);
1952
+ }
1953
+
1954
+ // - the item view responds to contentHitTest() and returns YES.
1955
+ // - the item view responds to beginEditing and returns YES.
1956
+ if (canEdit) {
1957
+ itemView = this.itemViewForContentIndex(idx) ;
1958
+ canEdit = itemView && (!itemView.contentHitTest || itemView.contentHitTest(ev)) ;
1959
+ canEdit = (canEdit && itemView.beginEditing) ? itemView.beginEditing() : NO ;
1960
+ }
1961
+
1962
+ // if cannot edit, just reselect
1963
+ if (!canEdit) this.select(idx, false) ;
1964
+ }
1965
+
1966
+ this._cleanupMouseDown() ;
1967
+ }
1968
+
1969
+ // handle actions on editing
1970
+ this._cv_performSelectAction(view, ev, 0, ev.clickCount);
1971
+
1972
+ return NO; // bubble event to allow didDoubleClick to be called...
1973
+ },
1974
+
1975
+ /** @private */
1976
+ _cleanupMouseDown: function() {
1977
+
1978
+ // delete items explicitly to avoid leaks on IE
1979
+ var info = this.mouseDownInfo, key;
1980
+ if (info) {
1981
+ for(key in info) {
1982
+ if (!info.hasOwnProperty(key)) continue;
1983
+ delete info[key];
1984
+ }
1985
+ }
1986
+ this.mouseDownInfo = null;
1987
+ },
1988
+
1989
+ /** @private */
1990
+ mouseMoved: function(ev) {
1991
+ var view = this.itemViewForEvent(ev),
1992
+ last = this._lastHoveredItem ;
1993
+
1994
+ // handle hover events.
1995
+ if (view !== last) {
1996
+ if (last && last.mouseOut) last.mouseOut(ev);
1997
+ if (view && view.mouseOver) view.mouseOver(ev);
1998
+ }
1999
+ this._lastHoveredItem = view ;
2000
+
2001
+ if (view && view.mouseMoved) view.mouseMoved(ev);
2002
+ return YES;
2003
+ },
2004
+
2005
+ /** @private */
2006
+ mouseOut: function(ev) {
2007
+ var view = this._lastHoveredItem ;
2008
+ this._lastHoveredItem = null ;
2009
+ if (view && view.mouseOut) view.mouseOut(ev) ;
2010
+ return YES ;
2011
+ },
2012
+
2013
+ /** @private */
2014
+ _findSelectionExtendedByShift: function(sel, contentIndex) {
2015
+
2016
+ // fast path. if we don't have a selection, just select index
2017
+ if (!sel || sel.get('length')===0) {
2018
+ return SC.IndexSet.create(contentIndex);
2019
+ }
2020
+
2021
+ // if we do have a selection, then figure out how to extend it.
2022
+ var content = this.get('content'),
2023
+ lim = content.get('length')-1,
2024
+ min = sel.get('min'),
2025
+ max = sel.get('max')-1,
2026
+ info = this.mouseDownInfo,
2027
+ anchor = this._selectionAnchor ;
2028
+ if (SC.none(anchor)) anchor = -1;
2029
+
2030
+ // clicked before the current selection set... extend it's beginning...
2031
+ if (contentIndex < min) {
2032
+ min = contentIndex;
2033
+ if (anchor<0) this._selectionAnchor = anchor = max; //anchor at end
2034
+
2035
+ // clicked after the current selection set... extend it's ending...
2036
+ } else if (contentIndex > max) {
2037
+ max = contentIndex;
2038
+ if (anchor<0) this._selectionAnchor = anchor = min; // anchor at start
2039
+
2040
+ // clicked inside the selection set... need to determine where the last
2041
+ // selection was and use that as an anchor.
2042
+ } else if (contentIndex >= min && contentIndex <= max) {
2043
+ if (anchor<0) this._selectionAnchor = anchor = min; //anchor at start
2044
+
2045
+ if (contentIndex === anchor) min = max = contentIndex ;
2046
+ else if (contentIndex > anchor) {
2047
+ min = anchor;
2048
+ max = contentIndex ;
2049
+ } else if (contentIndex < anchor) {
2050
+ min = contentIndex;
2051
+ max = anchor ;
2052
+ }
2053
+ }
2054
+
2055
+ return SC.IndexSet.create(min, max - min + 1);
2056
+ },
2057
+
2058
+ // ......................................
2059
+ // DRAG AND DROP SUPPORT
2060
+ //
2061
+
2062
+ /**
2063
+ When reordering its content, the collection view will store its reorder
2064
+ data using this special data type. The data type is unique to each
2065
+ collection view instance. You can use this data type to detect reorders
2066
+ if necessary.
2067
+
2068
+ @property
2069
+ @type String
2070
+ */
2071
+ reorderDataType: function() {
2072
+ return 'SC.CollectionView.Reorder.%@'.fmt(SC.guidFor(this)) ;
2073
+ }.property().cacheable(),
2074
+
2075
+ /**
2076
+ This property is set to the IndexSet of content objects that are the
2077
+ subject of a drag whenever a drag is initiated on the collection view.
2078
+ You can consult this property when implementing your collection view
2079
+ delegate methods, but otherwise you should not use this property in your
2080
+ code.
2081
+
2082
+ @type SC.IndexSet
2083
+ */
2084
+ dragContent: null,
2085
+
2086
+ /**
2087
+ This property is set to the proposed insertion index during a call to
2088
+ collectionViewValidateDragOperation(). Your delegate implementations can
2089
+ change the value of this property to enforce a drop some in some other
2090
+ location.
2091
+
2092
+ @type Number
2093
+ */
2094
+ proposedInsertionIndex: null,
2095
+
2096
+ /**
2097
+ This property is set to the proposed drop operation during a call to
2098
+ collectionViewValidateDragOperation(). Your delegate implementations can
2099
+ change the value of this property to enforce a different type of drop
2100
+ operation.
2101
+
2102
+ @type Number
2103
+ @property
2104
+ */
2105
+ proposedDropOperation: null,
2106
+
2107
+ /** @private
2108
+ mouseDragged event handler. Initiates a drag if the following conditions
2109
+ are met:
2110
+
2111
+ - collectionViewShouldBeginDrag() returns YES *OR*
2112
+ - the above method is not implemented and canReorderContent is true.
2113
+ - the dragDataTypes property returns a non-empty array
2114
+ - a mouse down event was saved by the mouseDown method.
2115
+ */
2116
+ mouseDragged: function(ev) {
2117
+
2118
+ var del = this.get('selectionDelegate'),
2119
+ content = this.get('content'),
2120
+ sel = this.get('selection'),
2121
+ info = this.mouseDownInfo,
2122
+ dragContent, dragDataTypes, dragView;
2123
+
2124
+ // if the mouse down event was cleared, there is nothing to do; return.
2125
+ if (!info || info.contentIndex<0) return YES ;
2126
+
2127
+ // Don't do anything unless the user has been dragging for 123msec
2128
+ if ((Date.now() - info.at) < 123) return YES ;
2129
+
2130
+ // OK, they must be serious, decide if a drag will be allowed.
2131
+ if (del.collectionViewShouldBeginDrag(this)) {
2132
+
2133
+ // First, get the selection to drag. Drag an array of selected
2134
+ // items appearing in this collection, in the order of the
2135
+ // collection.
2136
+ //
2137
+ // Compute the dragContent - the indexes we will be dragging.
2138
+ // if we don't select on mouse down, then the selection has not been
2139
+ // updated to whatever the user clicked. Instead use
2140
+ // mouse down content.
2141
+ if (!this.get("selectOnMouseDown")) {
2142
+ dragContent = SC.IndexSet.create(info.contentIndex);
2143
+ } else dragContent = sel ? sel.indexSetForSource(content) : null;
2144
+ if (!dragContent) return YES; // nothing to drag
2145
+
2146
+ dragContent = { content: content, indexes: dragContent };
2147
+ this.set('dragContent', dragContent) ;
2148
+
2149
+ // Get the set of data types supported by the delegate. If this returns
2150
+ // a null or empty array and reordering content is not also supported
2151
+ // then do not start the drag.
2152
+ dragDataTypes = this.get('dragDataTypes');
2153
+ if (dragDataTypes && dragDataTypes.get('length') > 0) {
2154
+
2155
+ // Build the drag view to use for the ghost drag. This
2156
+ // should essentially contain any visible drag items.
2157
+ dragView = del.collectionViewDragViewFor(this, dragContent.indexes);
2158
+ if (!dragView) dragView = this._cv_dragViewFor(dragContent.indexes);
2159
+
2160
+ // Initiate the drag
2161
+ SC.Drag.start({
2162
+ event: info.event,
2163
+ source: this,
2164
+ dragView: dragView,
2165
+ ghost: NO,
2166
+ slideBack: YES,
2167
+ dataSource: this
2168
+ });
2169
+
2170
+ // Also use this opportunity to clean up since mouseUp won't
2171
+ // get called.
2172
+ this._cleanupMouseDown() ;
2173
+ this._lastInsertionIndex = null ;
2174
+
2175
+ // Drag was not allowed by the delegate, so bail.
2176
+ } else this.set('dragContent', null) ;
2177
+
2178
+ return YES ;
2179
+ }
2180
+ },
2181
+
2182
+ /** @private
2183
+ Compute a default drag view by grabbing the raw layers and inserting them
2184
+ into a drag view.
2185
+ */
2186
+ _cv_dragViewFor: function(dragContent) {
2187
+ // find only the indexes that are in both dragContent and nowShowing.
2188
+ var indexes = this.get('nowShowing').without(dragContent);
2189
+ indexes = this.get('nowShowing').without(indexes);
2190
+
2191
+ var dragLayer = this.get('layer').cloneNode(false);
2192
+ var view = SC.View.create({ layer: dragLayer, parentView: this });
2193
+
2194
+ // cleanup weird stuff that might make the drag look out of place
2195
+ SC.$(dragLayer).css('backgroundColor', 'transparent')
2196
+ .css('border', 'none')
2197
+ .css('top', 0).css('left', 0);
2198
+
2199
+ indexes.forEach(function(i) {
2200
+ var itemView = this.itemViewForContentIndex(i),
2201
+ isSelected, layer;
2202
+
2203
+ // render item view without isSelected state.
2204
+ if (itemView) {
2205
+ isSelected = itemView.get('isSelected');
2206
+ itemView.set('isSelected', NO);
2207
+
2208
+ itemView.updateLayerIfNeeded();
2209
+ layer = itemView.get('layer');
2210
+ if (layer) layer = layer.cloneNode(true);
2211
+
2212
+ itemView.set('isSelected', isSelected);
2213
+ itemView.updateLayerIfNeeded();
2214
+ }
2215
+
2216
+ if (layer) dragLayer.appendChild(layer);
2217
+ layer = null;
2218
+
2219
+ }, this);
2220
+
2221
+ dragLayer = null;
2222
+ return view ;
2223
+ },
2224
+
2225
+
2226
+ /**
2227
+ Implements the drag data source protocol for the collection view. This
2228
+ property will consult the collection view delegate if one is provided. It
2229
+ will also do the right thing if you have set canReorderContent to YES.
2230
+
2231
+ @property
2232
+ @type Array
2233
+ */
2234
+ dragDataTypes: function() {
2235
+ // consult delegate.
2236
+ var del = this.get('selectionDelegate'),
2237
+ ret = del.collectionViewDragDataTypes(this),
2238
+ key ;
2239
+
2240
+ if (this.get('canReorderContent')) {
2241
+ ret = ret ? ret.copy() : [];
2242
+ key = this.get('reorderDataType');
2243
+ if (ret.indexOf(key) < 0) ret.push(key);
2244
+ }
2245
+
2246
+ return ret ? ret : [];
2247
+ }.property(),
2248
+
2249
+ /**
2250
+ Implements the drag data source protocol method. The implementation of
2251
+ this method will consult the collection view delegate if one has been
2252
+ provided. It also respects the canReoderContent method.
2253
+ */
2254
+ dragDataForType: function(drag, dataType) {
2255
+
2256
+ // if this is a reorder, then return drag content.
2257
+ if (this.get('canReorderContent')) {
2258
+ if (dataType === this.get('reorderDataType')) {
2259
+ return this.get('dragContent') ;
2260
+ }
2261
+ }
2262
+
2263
+ // otherwise, just pass along to the delegate
2264
+ var del = this.get('selectionDelegate');
2265
+ return del.collectionViewDragDataForType(this, drag, dataType);
2266
+ },
2267
+
2268
+ /**
2269
+ Implements the SC.DropTarget interface. The default implementation will
2270
+ consult the collection view delegate, if you implement those methods.
2271
+
2272
+ This method is called once when the drag enters the view area. It's
2273
+ return value will be stored on the drag object as allowedDragOperations,
2274
+ possibly further constrained by the drag source.
2275
+
2276
+ @param {SC.Drag} drag the drag object
2277
+ @param {SC.Event} evt the event triggering this change, if available
2278
+ @returns {Number} logical OR'd mask of allowed drag operations.
2279
+ */
2280
+ computeDragOperations: function(drag, evt) {
2281
+
2282
+ // the proposed drag operation is DRAG_REORDER only if we can reorder
2283
+ // content and the drag contains reorder content.
2284
+ var op = SC.DRAG_NONE,
2285
+ del = this.get('selectionDelegate');
2286
+
2287
+ if (this.get('canReorderContent')) {
2288
+ if (drag.get('dataTypes').indexOf(this.get('reorderDataType')) >= 0) {
2289
+ op = SC.DRAG_REORDER ;
2290
+ }
2291
+ }
2292
+
2293
+ // Now pass this onto the delegate.
2294
+ op = del.collectionViewComputeDragOperations(this, drag, op);
2295
+ if (op & SC.DRAG_REORDER) op = SC.DRAG_MOVE ;
2296
+
2297
+ return op ;
2298
+ },
2299
+
2300
+ /** @private
2301
+ Determines the allowed drop operation insertion point, operation type,
2302
+ and the drag operation to be performed. Used by dragUpdated() and
2303
+ performDragOperation().
2304
+
2305
+ @param {SC.Drag} drag the drag object
2306
+ @param {SC.Event} evt source of this request, if available
2307
+ @param {Number} dragOp allowed drag operation mask
2308
+ Returns three params: [drop index, drop operation, allowed drag ops]
2309
+ */
2310
+ _computeDropOperationState: function(drag, evt, dragOp) {
2311
+
2312
+ // get the insertion index for this location. This can be computed
2313
+ // by a subclass using whatever method. This method is not expected to
2314
+ // do any data valdidation, just to map the location to an insertion
2315
+ // index.
2316
+ var loc = this.convertFrameFromView(drag.get('location'), null),
2317
+ dropOp = SC.DROP_BEFORE,
2318
+ del = this.get('selectionDelegate'),
2319
+ canReorder = this.get('canReorderContent'),
2320
+ objects, content, isPreviousInDrag, isNextInDrag, len;
2321
+
2322
+ // STEP 1: Try with a DROP_ON option -- send straight to delegate if
2323
+ // supported by view.
2324
+
2325
+ // get the computed insertion index and possibly drop operation.
2326
+ // prefer to drop ON.
2327
+ var idx = this.insertionIndexForLocation(loc, SC.DROP_ON) ;
2328
+ if (SC.typeOf(idx) === SC.T_ARRAY) {
2329
+ dropOp = idx[1] ; // order matters here
2330
+ idx = idx[0] ;
2331
+ }
2332
+
2333
+ // if the return drop operation is DROP_ON, then just check it with the
2334
+ // delegate method. If the delegate method does not support dropping on,
2335
+ // then it will return DRAG_NONE, in which case we will try again with
2336
+ // drop before.
2337
+ if (dropOp === SC.DROP_ON) {
2338
+
2339
+ // Now save the insertion index and the dropOp. This may be changed by
2340
+ // the collection delegate.
2341
+ this.set('proposedInsertionIndex', idx) ;
2342
+ this.set('proposedDropOperation', dropOp) ;
2343
+ dragOp = del.collectionViewValidateDragOperation(this, drag, dragOp, idx, dropOp) ;
2344
+ idx = this.get('proposedInsertionIndex') ;
2345
+ dropOp = this.get('proposedDropOperation') ;
2346
+ this._dropInsertionIndex = this._dropOperation = null ;
2347
+
2348
+ // The delegate is OK with a drop on also, so just return.
2349
+ if (dragOp !== SC.DRAG_NONE) return [idx, dropOp, dragOp] ;
2350
+
2351
+ // The delegate is NOT OK with a drop on, try to get the insertion
2352
+ // index again, but this time prefer SC.DROP_BEFORE, then let the
2353
+ // rest of the method run...
2354
+ else {
2355
+ dropOp = SC.DROP_BEFORE ;
2356
+ idx = this.insertionIndexForLocation(loc, SC.DROP_BEFORE) ;
2357
+ if (SC.typeOf(idx) === SC.T_ARRAY) {
2358
+ dropOp = idx[1] ; // order matters here
2359
+ idx = idx[0] ;
2360
+ }
2361
+ }
2362
+ }
2363
+
2364
+ // if this is a reorder drag, set the proposed op to SC.DRAG_REORDER and
2365
+ // validate the insertion point. This only works if the insertion point
2366
+ // is DROP_BEFORE or DROP_AFTER. DROP_ON is not handled by reordering
2367
+ // content.
2368
+ if ((idx >= 0) && canReorder && (dropOp !== SC.DROP_ON)) {
2369
+
2370
+ objects = drag.dataForType(this.get('reorderDataType')) ;
2371
+ if (objects) {
2372
+ content = this.get('content') ;
2373
+
2374
+ // if the insertion index is in between two items in the drag itself,
2375
+ // then this is not allowed. Either use the last insertion index or
2376
+ // find the first index that is not in between selections. Stop when
2377
+ // we get to the beginning.
2378
+ if (dropOp === SC.DROP_BEFORE) {
2379
+ isPreviousInDrag = objects.indexes.contains(idx-1);
2380
+ isNextInDrag = objects.indexes.contains(idx);
2381
+ } else {
2382
+ isPreviousInDrag = objects.indexes.contains(idx);
2383
+ isNextInDrag = objects.indexes.contains(idx-1);
2384
+ }
2385
+
2386
+ if (isPreviousInDrag && isNextInDrag) {
2387
+ if (SC.none(this._lastInsertionIndex)) {
2388
+ if (dropOp === SC.DROP_BEFORE) {
2389
+ while ((idx >= 0) && objects.indexes.contains(idx)) idx--;
2390
+ } else {
2391
+ len = content ? content.get('length') : 0;
2392
+ while ((idx < len) && objects.indexes.contains(idx)) idx++;
2393
+ }
2394
+ } else idx = this._lastInsertionIndex ;
2395
+ }
2396
+
2397
+ // If we found a valid insertion point to reorder at, then set the op
2398
+ // to custom DRAG_REORDER.
2399
+ if (idx >= 0) dragOp = SC.DRAG_REORDER ;
2400
+ }
2401
+ }
2402
+
2403
+ // Now save the insertion index and the dropOp. This may be changed by
2404
+ // the collection delegate.
2405
+ this.set('proposedInsertionIndex', idx) ;
2406
+ this.set('proposedDropOperation', dropOp) ;
2407
+ dragOp = del.collectionViewValidateDragOperation(this, drag, dragOp, idx, dropOp) ;
2408
+ idx = this.get('proposedInsertionIndex') ;
2409
+ dropOp = this.get('proposedDropOperation') ;
2410
+ this._dropInsertionIndex = this._dropOperation = null ;
2411
+
2412
+ // return generated state
2413
+ return [idx, dropOp, dragOp] ;
2414
+ },
2415
+
2416
+ /**
2417
+ Implements the SC.DropTarget interface. The default implementation will
2418
+ determine the drop location and then consult the collection view delegate
2419
+ if you implement those methods. Otherwise it will handle reordering
2420
+ content on its own.
2421
+ */
2422
+ dragUpdated: function(drag, evt) {
2423
+
2424
+ var op = drag.get('allowedDragOperations'),
2425
+ state = this._computeDropOperationState(drag, evt, op),
2426
+ idx = state[0], dropOp = state[1], dragOp = state[2];
2427
+
2428
+ // if the insertion index or dropOp have changed, update the insertion
2429
+ // point
2430
+ if (dragOp !== SC.DRAG_NONE) {
2431
+ if ((this._lastInsertionIndex !== idx) || (this._lastDropOperation !== dropOp)) {
2432
+ var itemView = this.itemViewForContentIndex(idx) ;
2433
+ this.showInsertionPoint(itemView, dropOp) ;
2434
+ }
2435
+
2436
+ this._lastInsertionIndex = idx ;
2437
+ this._lastDropOperation = dropOp ;
2438
+ } else {
2439
+ this.hideInsertionPoint() ;
2440
+ this._lastInsertionIndex = this._lastDropOperation = null ;
2441
+ }
2442
+
2443
+ // Normalize drag operation to the standard kinds accepted by the drag
2444
+ // system.
2445
+ return (dragOp & SC.DRAG_REORDER) ? SC.DRAG_MOVE : dragOp;
2446
+ },
2447
+
2448
+ /**
2449
+ Implements the SC.DropTarget protocol. Hides any visible insertion
2450
+ point and clears some cached values.
2451
+ */
2452
+ dragExited: function() {
2453
+ this.hideInsertionPoint() ;
2454
+ this._lastInsertionIndex = this._lastDropOperation = null ;
2455
+ },
2456
+
2457
+ /**
2458
+ Implements the SC.DropTarget protocol.
2459
+ */
2460
+ acceptDragOperation: function(drag, op) { return YES; },
2461
+
2462
+ /**
2463
+ Implements the SC.DropTarget protocol. Consults the collection view
2464
+ delegate to actually perform the operation unless the operation is
2465
+ reordering content.
2466
+ */
2467
+ performDragOperation: function(drag, op) {
2468
+ // Get the correct insertion point, drop operation, etc.
2469
+ var state = this._computeDropOperationState(drag, null, op),
2470
+ idx = state[0], dropOp = state[1], dragOp = state[2],
2471
+ del = this.get('selectionDelegate'),
2472
+ performed, objects, data, content, shift;
2473
+
2474
+ // The dragOp is the kinds of ops allowed. The drag operation must
2475
+ // be included in that set.
2476
+ if (dragOp & SC.DRAG_REORDER) {
2477
+ op = (op & SC.DRAG_MOVE) ? SC.DRAG_REORDER : SC.DRAG_NONE ;
2478
+ } else op = op & dragOp ;
2479
+
2480
+ // If no allowed drag operation could be found, just return.
2481
+ if (op === SC.DRAG_NONE) return op;
2482
+
2483
+ // Some operation is allowed through, give the delegate a chance to
2484
+ // handle it.
2485
+ performed = del.collectionViewPerformDragOperation(this, drag, op, idx, dropOp) ;
2486
+
2487
+ // If the delegate did not handle the drag (i.e. returned SC.DRAG_NONE),
2488
+ // and the op type is REORDER, then do the reorder here.
2489
+ if ((performed === SC.DRAG_NONE) && (op & SC.DRAG_REORDER)) {
2490
+
2491
+ data = drag.dataForType(this.get('reorderDataType')) ;
2492
+ if (!data) return SC.DRAG_NONE ;
2493
+
2494
+ content = this.get('content') ;
2495
+ content.beginPropertyChanges(); // suspend notifications
2496
+
2497
+ // get each object, then remove it from the content. they will be
2498
+ // added again later.
2499
+ objects = [];
2500
+ shift = 0;
2501
+ data.indexes.forEach(function(i) {
2502
+ objects.push(content.objectAt(i-shift));
2503
+ content.removeAt(i-shift);
2504
+ shift++;
2505
+ if (i < idx) idx--;
2506
+ if ((dropOp === SC.DROP_AFTER) && (i === idx)) idx--;
2507
+ }, this);
2508
+
2509
+ // now insert objects into new insertion locaiton
2510
+ content.replace(idx, 0, objects);
2511
+ this.select(SC.IndexSet.create(idx, objects.length));
2512
+ content.endPropertyChanges(); // restart notifications
2513
+
2514
+ // make the op into its actual value
2515
+ op = SC.DRAG_MOVE ;
2516
+ }
2517
+
2518
+ return op;
2519
+ },
2520
+
2521
+ /**
2522
+ Default delegate method implementation, returns YES if canReorderContent
2523
+ is also true.
2524
+ */
2525
+ collectionViewShouldBeginDrag: function(view) {
2526
+ return this.get('canReorderContent') ;
2527
+ },
2528
+
2529
+
2530
+ // ..........................................................
2531
+ // INSERTION POINT
2532
+ //
2533
+
2534
+
2535
+ /**
2536
+ Get the preferred insertion point for the given location, including
2537
+ an insertion preference of before, after or on the named index.
2538
+
2539
+ You can implement this method in a subclass if you like to perform a
2540
+ more efficient check. The default implementation will loop through the
2541
+ item views looking for the first view to "switch sides" in the orientation
2542
+ you specify.
2543
+
2544
+ This method should return an array with two values. The first value is
2545
+ the insertion point index and the second value is the drop operation,
2546
+ which should be one of SC.DROP_BEFORE, SC.DROP_AFTER, or SC.DROP_ON.
2547
+
2548
+ The preferred drop operation passed in should be used as a hint as to
2549
+ the type of operation the view would prefer to receive. If the
2550
+ dropOperation is SC.DROP_ON, then you should return a DROP_ON mode if
2551
+ possible. Otherwise, you should never return DROP_ON.
2552
+
2553
+ For compatibility, you can also return just the insertion index. If you
2554
+ do this, then the collction view will assume the drop operation is
2555
+ SC.DROP_BEFORE.
2556
+
2557
+ If an insertion is NOT allowed, you should return -1 as the insertion
2558
+ point. In this case, the drop operation will be ignored.
2559
+
2560
+ @param loc {Point} the mouse location.
2561
+ @param dropOperation {DropOp} the preferred drop operation.
2562
+ @returns {Array} [proposed drop index, drop operation]
2563
+ */
2564
+ insertionIndexForLocation: function(loc, dropOperation) {
2565
+ var ret = 0 ;
2566
+
2567
+ // var content = this.get('content'),
2568
+ // nowShowing = this.get('nowShowing'),
2569
+ // orient = this.get('insertionOrientation'),
2570
+ // lastSide = null,
2571
+ // ret = null,
2572
+ // itemView, curSide, f;
2573
+ //
2574
+ // for(var idx=0; ((ret === null) && (idx<content.length)); idx++) {
2575
+ // // itemView = this.itemViewForContent(content.objectAt(idx));
2576
+ // itemView = this.itemViewForContentIndex(idx);
2577
+ // f = this.convertFrameFromView(itemView.get('frame'), itemView) ;
2578
+ //
2579
+ // // if we are a horizontal orientation, look for the first item that
2580
+ // // will "switch sides" on the x path an the maxY is greater than Y.
2581
+ // // This assumes you will flow top to bottom, but it should work if you
2582
+ // // flow LTR or RTL.
2583
+ // if (orient == SC.HORIZONTAL_ORIENTATION) {
2584
+ // if (SC.maxY(f) > loc.y) {
2585
+ // curSide = (SC.maxX(f) < loc.x) ? -1 : 1 ;
2586
+ // } else curSide = null ;
2587
+ //
2588
+ // // if we are a vertical orientation, look for the first item that
2589
+ // // will "switch sides" on the y path and the maxX is greater than X.
2590
+ // // This assumes you will flow LTR, but it should work if you flow
2591
+ // // bottom to top or top to bottom.
2592
+ // } else {
2593
+ // if (SC.minX(f) < loc.x) {
2594
+ // curSide = (SC.maxY(f) < loc.y) ? -1 : 1 ;
2595
+ // } else curSide = null ;
2596
+ // }
2597
+ //
2598
+ // // if we "switched" sides then return this item view.
2599
+ // if (curSide !== null) {
2600
+ //
2601
+ // // OK, we found an item view, while we have this data, decide if
2602
+ // // we should insert before or after the view
2603
+ // if ((lastSide !== null) && (curSide != lastSide)) {
2604
+ // ret = idx ;
2605
+ // if (orient == SC.HORIZONTAL_ORIENTATION) {
2606
+ // if (SC.midX(f) < loc.x) ret++ ;
2607
+ // } else {
2608
+ // if (SC.midY(f) < loc.y) ret++ ;
2609
+ // }
2610
+ // }
2611
+ // lastSide =curSide ;
2612
+ // }
2613
+ // }
2614
+ //
2615
+ // // Handle some edge cases
2616
+ // if ((ret === null) || (ret < 0)) ret = 0 ;
2617
+ // if (ret > content.length) ret = content.length ;
2618
+
2619
+ // Done. Phew. Return.
2620
+ return ret;
2621
+ },
2622
+
2623
+ // ..........................................................
2624
+ // INTERNAL SUPPORT
2625
+ //
2626
+
2627
+ /** @private - when we become visible, reload if needed. */
2628
+ _cv_isVisibleInWindowDidChange: function() {
2629
+ if (this.get('isVisibleInWindow')) {
2630
+ if (this._invalidIndexes) this.invokeOnce(this.reloadIfNeeded);
2631
+ if (this._invalidSelection) {
2632
+ this.invokeOnce(this.reloadSelectionIndexesIfNeeded);
2633
+ }
2634
+ }
2635
+ }.observes('isVisibleInWindow'),
2636
+
2637
+
2638
+ /**
2639
+ Default delegate method implementation, returns YES if isSelectable
2640
+ is also true.
2641
+ */
2642
+ collectionViewShouldSelectItem: function(view, item) {
2643
+ return this.get('isSelectable') ;
2644
+ },
2645
+
2646
+ _TMP_DIFF1: SC.IndexSet.create(),
2647
+ _TMP_DIFF2: SC.IndexSet.create(),
2648
+
2649
+ /** @private
2650
+
2651
+ Whenever the nowShowing range changes, update the range observer on the
2652
+ content item and instruct the view to reload any indexes that are not in
2653
+ the previous nowShowing range.
2654
+
2655
+ */
2656
+ _cv_nowShowingDidChange: function() {
2657
+ var nowShowing = this.get('nowShowing'),
2658
+ last = this._sccv_lastNowShowing,
2659
+ diff, diff1, diff2;
2660
+
2661
+ // find the differences between the two
2662
+ // NOTE: reuse a TMP IndexSet object to avoid creating lots of objects
2663
+ // during scrolling
2664
+ if (last && nowShowing && (last !== nowShowing)) {
2665
+ diff1 = this._TMP_DIFF1.add(last).remove(nowShowing);
2666
+ diff2 = this._TMP_DIFF2.add(nowShowing).remove(last);
2667
+ diff = diff1.add(diff2);
2668
+ } else diff = last || nowShowing ;
2669
+
2670
+ // if nowShowing has actually changed, then update
2671
+ if (diff && diff.get('length') > 0) {
2672
+ this._sccv_lastNowShowing = nowShowing ? nowShowing.frozenCopy() : null;
2673
+ this.updateContentRangeObserver();
2674
+ this.reload(diff);
2675
+ }
2676
+
2677
+ // cleanup tmp objects
2678
+ if (diff1) diff1.clear();
2679
+ if (diff2) diff2.clear();
2680
+
2681
+ }.observes('nowShowing'),
2682
+
2683
+ init: function() {
2684
+ sc_super();
2685
+ if (this.get('canReorderContent')) this._cv_canReorderContentDidChange();
2686
+ this._sccv_lastNowShowing = this.get('nowShowing').clone();
2687
+ if (this.content) this._cv_contentDidChange();
2688
+ if (this.selection) this._cv_selectionDidChange();
2689
+ },
2690
+
2691
+ /** @private
2692
+ Become a drop target whenever reordering content is enabled.
2693
+ */
2694
+ _cv_canReorderContentDidChange: function() {
2695
+ if (this.get('canReorderContent')) {
2696
+ if (!this.get('isDropTarget')) this.set('isDropTarget', YES);
2697
+ SC.Drag.addDropTarget(this);
2698
+ }
2699
+ }.observes('canReorderContent'),
2700
+
2701
+ /** @private
2702
+ Fires an action after a selection if enabled.
2703
+
2704
+ if actOnSelect is YES, then try to invoke the action, passing the
2705
+ current selection (saved as a separate array so that a change in sel
2706
+ in the meantime will not be lost)
2707
+ */
2708
+ _cv_performSelectAction: function(view, ev, delay, clickCount) {
2709
+ var sel;
2710
+ if (delay === undefined) delay = 0 ;
2711
+ if (clickCount === undefined) clickCount = 1;
2712
+ if ((clickCount>1) || this.get('actOnSelect')) {
2713
+ sel = this.get('selection');
2714
+ sel = sel ? sel.toArray() : [];
2715
+ if (this._cv_actionTimer) this._cv_actionTimer.invalidate();
2716
+ this._cv_actionTimer = this.invokeLater(this._cv_action, delay, view, ev, sel) ;
2717
+ }
2718
+ },
2719
+
2720
+ /** @private
2721
+ Perform the action. Supports legacy behavior as well as newer style
2722
+ action dispatch.
2723
+ */
2724
+ _cv_action: function(view, evt, context) {
2725
+ var action = this.get('action');
2726
+ var target = this.get('target') || null;
2727
+
2728
+ this._cv_actionTimer = null;
2729
+ if (action) {
2730
+ // if the action is a function, just call it
2731
+ if (SC.typeOf(action) === SC.T_FUNCTION) return this.action(view, evt) ;
2732
+
2733
+ // otherwise, use the new sendAction style
2734
+ var pane = this.get('pane') ;
2735
+ if (pane) {
2736
+ pane.rootResponder.sendAction(action, target, this, pane, context);
2737
+ }
2738
+ // SC.app.sendAction(action, target, this) ;
2739
+
2740
+ // if no action is specified, then trigger the support action,
2741
+ // if supported.
2742
+ } else if (!view) {
2743
+ return ; // nothing to do
2744
+
2745
+ // if the target view has its own internal action handler,
2746
+ // trigger that.
2747
+ } else if (SC.typeOf(view._action) == SC.T_FUNCTION) {
2748
+ return view._action(evt) ;
2749
+
2750
+ // otherwise call the action method to support older styles.
2751
+ } else if (SC.typeOf(view.action) == SC.T_FUNCTION) {
2752
+ return view.action(evt) ;
2753
+ }
2754
+ }
2755
+
2756
+
2757
+ });