sproutit-sproutcore 1.0.0.20090416161445 → 1.0.0.20090720093355
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Buildfile +4 -2
- data/frameworks/sproutcore/Buildfile +3 -2
- data/frameworks/sproutcore/README +2 -1
- data/frameworks/sproutcore/apps/docs/core.js +27 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/QuickLook/Preview.pdf +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/QuickLook/Thumbnail.tiff +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/data.plist +14378 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image10.png +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image11.png +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image13.png +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image14.png +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image8.png +0 -0
- data/frameworks/sproutcore/apps/docs/design/Doc Viewer.graffle/image9.tiff +0 -0
- data/frameworks/sproutcore/apps/docs/english.lproj/loading.rhtml +9 -0
- data/frameworks/sproutcore/apps/docs/english.lproj/main_page.js +22 -0
- data/frameworks/sproutcore/apps/{sc_jsdoc → docs}/english.lproj/strings.js +7 -7
- data/frameworks/sproutcore/apps/docs/main.js +30 -0
- data/frameworks/sproutcore/apps/tests/controllers/detail.js +16 -0
- data/frameworks/sproutcore/apps/tests/controllers/source.js +29 -0
- data/frameworks/sproutcore/apps/tests/controllers/target.js +26 -0
- data/frameworks/sproutcore/apps/tests/controllers/targets.js +65 -26
- data/frameworks/sproutcore/apps/tests/controllers/tests.js +14 -19
- data/frameworks/sproutcore/apps/tests/core.js +114 -16
- data/frameworks/sproutcore/apps/tests/data_source.js +96 -0
- data/frameworks/sproutcore/apps/tests/english.lproj/main_page.css +22 -2
- data/frameworks/sproutcore/apps/tests/english.lproj/main_page.js +168 -22
- data/frameworks/sproutcore/apps/tests/english.lproj/strings.js +14 -5
- data/frameworks/sproutcore/apps/tests/fixtures/target.js +81 -37
- data/frameworks/sproutcore/apps/tests/fixtures/test.js +38 -37
- data/frameworks/sproutcore/apps/tests/main.js +9 -20
- data/frameworks/sproutcore/apps/tests/models/target.js +74 -31
- data/frameworks/sproutcore/apps/tests/models/test.js +30 -2
- data/frameworks/sproutcore/{frameworks/desktop/mixins/collection_item.js → apps/tests/states/no_targets.js} +16 -12
- data/frameworks/sproutcore/apps/tests/states/ready.js +56 -0
- data/frameworks/sproutcore/apps/tests/states/ready_detail.js +41 -0
- data/frameworks/sproutcore/apps/tests/states/ready_empty.js +48 -0
- data/frameworks/sproutcore/apps/tests/states/ready_list.js +41 -0
- data/frameworks/sproutcore/apps/tests/states/ready_loading.js +44 -0
- data/frameworks/sproutcore/apps/tests/states/ready_no_tests.js +31 -0
- data/frameworks/sproutcore/apps/tests/states/start.js +39 -0
- data/frameworks/sproutcore/apps/tests/tests/controllers/{test.js → detail.js} +3 -3
- data/frameworks/sproutcore/apps/tests/tests/controllers/source.js +15 -0
- data/frameworks/sproutcore/apps/tests/tests/controllers/target.js +15 -0
- data/frameworks/sproutcore/apps/tests/tests/controllers/targets.js +3 -3
- data/frameworks/sproutcore/apps/tests/tests/views/offset_checkbox.js +15 -0
- data/frameworks/sproutcore/apps/tests/views/offset_checkbox.js +26 -0
- data/frameworks/sproutcore/design/CollectionView State Charts.graffle +4848 -0
- data/frameworks/sproutcore/design/Design Charts.graffle +8788 -6375
- data/frameworks/sproutcore/design/SproutCore Design Template.graffle/QuickLook/Preview.pdf +0 -0
- data/frameworks/sproutcore/design/SproutCore Design Template.graffle/QuickLook/Thumbnail.tiff +0 -0
- data/frameworks/sproutcore/design/SproutCore Design Template.graffle/data.plist +1452 -0
- data/frameworks/sproutcore/design/SproutCore Design Template.graffle/image8.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/QuickLook/Preview.pdf +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/QuickLook/Thumbnail.tiff +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/data.plist +24187 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image10.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image11.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image13.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image15.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image16.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image17.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image18.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image19.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image22.tiff +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image23.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image24.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image25.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image30.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image31.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image8.png +0 -0
- data/frameworks/sproutcore/design/TestRunner Design.graffle/image9.png +0 -0
- data/frameworks/sproutcore/frameworks/datastore/data_sources/cascade.js +2 -2
- data/frameworks/sproutcore/frameworks/datastore/data_sources/data_source.js +66 -49
- data/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures.js +146 -31
- data/frameworks/sproutcore/frameworks/datastore/data_sources/fixtures_with_queries.js +238 -0
- data/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +27 -11
- data/frameworks/sproutcore/frameworks/datastore/models/record.js +163 -32
- data/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +67 -5
- data/frameworks/sproutcore/frameworks/datastore/system/many_array.js +157 -0
- data/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +202 -19
- data/frameworks/sproutcore/frameworks/datastore/system/query.js +929 -78
- data/frameworks/sproutcore/frameworks/datastore/system/record_array.js +143 -5
- data/frameworks/sproutcore/frameworks/datastore/system/store.js +443 -125
- data/frameworks/sproutcore/frameworks/datastore/tests/data_sources/fixtures.js +38 -3
- data/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +94 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/models/record/core_methods.js +30 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/models/record/normalize.js +238 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +105 -16
- data/frameworks/sproutcore/frameworks/datastore/tests/system/many_array/core_methods.js +178 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/chain.js +1 -1
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChanges.js +9 -8
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/commitChangesFromNestedStore.js +6 -6
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/dataHashDidChange.js +6 -6
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/discardChanges.js +3 -3
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readDataHash.js +7 -7
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/readEditableDataHash.js +4 -4
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/removeDataHash.js +7 -7
- data/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/writeDataHash.js +7 -7
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/compare_records.js +126 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation.js +165 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/evaluation_of_records.js +82 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/find_all.js +362 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/parsing.js +170 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/record_type_is.js +43 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/registered_comparisons.js +60 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/query/registered_query_extensions.js +67 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/core_methods.js +2 -13
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/commitRecord.js +3 -4
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/core_methods.js +73 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/createRecord.js +15 -0
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/dataSourceCallbacks.js +4 -2
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/destroyRecord.js +1 -1
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/pushChanges.js +2 -2
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/recordDidChange.js +1 -1
- data/frameworks/sproutcore/frameworks/datastore/tests/system/store/retrieveRecord.js +2 -2
- data/frameworks/sproutcore/frameworks/debug/core.js +60 -0
- data/frameworks/sproutcore/frameworks/deprecated/core.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/server/server.js +0 -1
- data/frameworks/sproutcore/frameworks/deprecated/system/browser.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/system/classic_responder.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/system/event.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/system/misc.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/system/object.js +0 -2
- data/frameworks/sproutcore/frameworks/deprecated/system/path_module.js +0 -1
- data/frameworks/sproutcore/frameworks/deprecated/system/string.js +0 -2
- data/frameworks/sproutcore/frameworks/designer/coders/design.js +1 -2
- data/frameworks/sproutcore/frameworks/designer/coders/localization.js +1 -2
- data/frameworks/sproutcore/frameworks/designer/coders/object.js +1 -1
- data/frameworks/sproutcore/frameworks/designer/controllers/page_design.js +1 -1
- data/frameworks/sproutcore/frameworks/designer/ext/page.js +0 -2
- data/frameworks/sproutcore/frameworks/designer/ext/view.js +0 -2
- data/frameworks/sproutcore/frameworks/designer/views/controls/button.js +2 -3
- data/frameworks/sproutcore/frameworks/designer/views/designer.js +24 -8
- data/frameworks/sproutcore/frameworks/designer/views/label.js +1 -2
- data/frameworks/sproutcore/frameworks/designer/views/mixins/button.js +0 -2
- data/frameworks/sproutcore/frameworks/designer/views/tab.js +1 -2
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/alert.css +2 -2
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/drag.css +6 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/list_item.css +63 -10
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu_item_view.css +5 -4
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/modal.css +5 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/panel.css +1 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/slider.css +5 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/split_divider.css +1 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/tab.css +1 -1
- data/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +61 -0
- data/frameworks/sproutcore/frameworks/desktop/mixins/collection_view_delegate.js +136 -79
- data/frameworks/sproutcore/frameworks/desktop/panes/alert.js +55 -24
- data/frameworks/sproutcore/frameworks/desktop/panes/menu.js +295 -147
- data/frameworks/sproutcore/frameworks/desktop/panes/palette.js +1 -1
- data/frameworks/sproutcore/frameworks/desktop/panes/panel.js +1 -1
- data/frameworks/sproutcore/frameworks/desktop/panes/picker.js +18 -20
- data/frameworks/sproutcore/frameworks/desktop/panes/sheet.js +2 -2
- data/frameworks/sproutcore/frameworks/desktop/protocols/drop_target.js +4 -4
- data/frameworks/sproutcore/frameworks/desktop/system/drag.js +337 -231
- data/frameworks/sproutcore/frameworks/desktop/system/root_responder.js +3 -3
- data/frameworks/sproutcore/frameworks/desktop/tests/integration/dialog.js +1 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +2 -2
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/methods.js +46 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +4 -2
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/palette/ui.js +5 -6
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +11 -11
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +11 -7
- data/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +9 -9
- data/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +19 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/methods.js +0 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/content.js +249 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/deleteSelection.js +82 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/deselect.js +199 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/itemViewForContentIndex.js +288 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/layerIdFor.js +65 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/length.js +88 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/mouse.js +165 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/nowShowing.js +121 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/reload.js +177 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/select.js +240 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selectNextItem.js +191 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selectPreviousItem.js +197 -39
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/selection.js +141 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/ui_diagram.js +182 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +183 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowHeightForContentIndex.js +133 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowOffsetForContentIndex.js +132 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_outline.js +56 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +167 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_simple.js +127 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +30 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/views/menu_item/ui.js +8 -8
- data/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +9 -9
- data/frameworks/sproutcore/frameworks/desktop/tests/views/scroller/methods.js +45 -6
- data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +2 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +17 -1
- data/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/ui.js +44 -29
- data/frameworks/sproutcore/frameworks/desktop/tests/views/stacked/ui_comments.js +231 -0
- data/frameworks/sproutcore/frameworks/desktop/tests/views/web/ui.js +1 -1
- data/frameworks/sproutcore/frameworks/desktop/views/button.js +15 -4
- data/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +8 -1
- data/frameworks/sproutcore/frameworks/desktop/views/collection.js +1739 -1123
- data/frameworks/sproutcore/frameworks/desktop/views/form.js +0 -1
- data/frameworks/sproutcore/frameworks/desktop/views/grid.js +13 -11
- data/frameworks/sproutcore/frameworks/desktop/views/list.js +405 -571
- data/frameworks/sproutcore/frameworks/desktop/views/list_item.js +211 -74
- data/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +319 -169
- data/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +57 -51
- data/frameworks/sproutcore/frameworks/desktop/views/progress.js +2 -2
- data/frameworks/sproutcore/frameworks/desktop/views/scene.js +150 -2
- data/frameworks/sproutcore/frameworks/desktop/views/scroll.js +92 -50
- data/frameworks/sproutcore/frameworks/desktop/views/scroller.js +86 -63
- data/frameworks/sproutcore/frameworks/desktop/views/segmented.js +38 -22
- data/frameworks/sproutcore/frameworks/desktop/views/select_field.js +51 -12
- data/frameworks/sproutcore/frameworks/desktop/views/slider.js +2 -0
- data/frameworks/sproutcore/frameworks/desktop/views/source_list.js +17 -1087
- data/frameworks/sproutcore/frameworks/desktop/views/source_list_group.js +3 -3
- data/frameworks/sproutcore/frameworks/desktop/views/split.js +35 -9
- data/frameworks/sproutcore/frameworks/desktop/views/stacked.js +101 -0
- data/frameworks/sproutcore/frameworks/desktop/views/tab.js +23 -22
- data/frameworks/sproutcore/frameworks/desktop/views/toolbar.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/controllers/array.js +382 -363
- data/frameworks/sproutcore/frameworks/foundation/controllers/controller.js +7 -279
- data/frameworks/sproutcore/frameworks/foundation/controllers/object.js +212 -310
- data/frameworks/sproutcore/frameworks/foundation/controllers/tree.js +109 -0
- data/frameworks/sproutcore/frameworks/foundation/core.js +25 -0
- data/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +30 -8
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/bootstrap.rhtml +19 -4
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/core.css +219 -3
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/debug/control-test-pane.css +1 -0
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/label.css +30 -0
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/strings.js +15 -0
- data/frameworks/sproutcore/frameworks/{desktop → foundation}/english.lproj/text_field.css +19 -3
- data/frameworks/sproutcore/frameworks/foundation/english.lproj/view.css +6 -1
- data/frameworks/sproutcore/frameworks/foundation/license.js +19 -0
- data/frameworks/sproutcore/frameworks/foundation/mixins/button.js +15 -7
- data/frameworks/sproutcore/frameworks/foundation/mixins/collection_content.js +171 -0
- data/frameworks/sproutcore/frameworks/foundation/mixins/control.js +5 -5
- data/frameworks/sproutcore/frameworks/foundation/mixins/inline_text_field.js +462 -0
- data/frameworks/sproutcore/frameworks/foundation/mixins/selection_support.js +162 -84
- data/frameworks/sproutcore/frameworks/foundation/mixins/static_layout.js +33 -2
- data/frameworks/sproutcore/frameworks/foundation/mixins/string.js +17 -3
- data/frameworks/sproutcore/frameworks/foundation/mixins/tree_item_content.js +159 -0
- data/frameworks/sproutcore/frameworks/foundation/panes/pane.js +49 -20
- data/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +887 -0
- data/frameworks/sproutcore/frameworks/foundation/system/application.js +36 -0
- data/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +310 -62
- data/frameworks/sproutcore/frameworks/foundation/system/datetime.js +729 -0
- data/frameworks/sproutcore/frameworks/foundation/system/event.js +57 -21
- data/frameworks/sproutcore/frameworks/foundation/system/ready.js +11 -5
- data/frameworks/sproutcore/frameworks/foundation/system/render_context.js +55 -16
- data/frameworks/sproutcore/frameworks/foundation/system/request.js +152 -27
- data/frameworks/sproutcore/frameworks/foundation/system/responder.js +120 -0
- data/frameworks/sproutcore/frameworks/foundation/system/responder_context.js +243 -0
- data/frameworks/sproutcore/frameworks/foundation/system/root_responder.js +29 -6
- data/frameworks/sproutcore/frameworks/foundation/system/routes.js +143 -102
- data/frameworks/sproutcore/frameworks/foundation/system/user_defaults.js +9 -2
- data/frameworks/sproutcore/frameworks/foundation/system/utils.js +104 -9
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/array_case.js +182 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/enum_case.js +193 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/null_case.js +64 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array/single_case.js +136 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/empty_case.js +82 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/multiple_case.js +111 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/single_case.js +193 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object/single_enumerable_case.js +179 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/tree/outline_case.js +108 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/mixins/button/keyEquivalents.js +35 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +128 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/mixins/string.js +17 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/flat_case.js +325 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/group_case.js +718 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/outline_case.js +484 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_core.js +28 -28
- data/frameworks/sproutcore/frameworks/foundation/tests/system/core_query/jquery_selector.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/system/datetime.js +151 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/get.js +2 -2
- data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_attr.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_basic.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_className.js +12 -12
- data/frameworks/sproutcore/frameworks/foundation/tests/system/render_context/helpers_style.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/system/request.js +52 -14
- data/frameworks/sproutcore/frameworks/foundation/tests/system/root_responder/root_responder.js +27 -23
- data/frameworks/sproutcore/frameworks/foundation/tests/system/timer/schedule.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/validators/date.js +12 -10
- data/frameworks/sproutcore/frameworks/foundation/tests/views/label/ui.js +148 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/views/pane/append_remove.js +1 -1
- data/frameworks/sproutcore/frameworks/{desktop → foundation}/tests/views/text_field/methods.js +0 -0
- data/frameworks/sproutcore/frameworks/{desktop → foundation}/tests/views/text_field/ui.js +53 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/clippingFrame.js +1 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/convertFrames.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/createChildViews.js +35 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/findLayerInParentLayer.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/isVisible.js +51 -0
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/isVisibleInWindow.js +12 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/layoutStyle.js +83 -3
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/prepareContext.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/tests/views/view/updateLayer.js +4 -0
- data/frameworks/sproutcore/frameworks/foundation/views/container.js +1 -1
- data/frameworks/sproutcore/frameworks/foundation/views/field.js +27 -16
- data/frameworks/sproutcore/frameworks/foundation/views/image.js +4 -1
- data/frameworks/sproutcore/frameworks/foundation/views/label.js +16 -6
- data/frameworks/sproutcore/frameworks/{desktop → foundation}/views/text_field.js +39 -15
- data/frameworks/sproutcore/frameworks/foundation/views/view.js +328 -83
- data/frameworks/sproutcore/frameworks/runtime/README +1 -0
- data/frameworks/sproutcore/frameworks/runtime/core.js +110 -31
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/base.js +238 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/indexOf.js +33 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/insertAt.js +121 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/objectAt.js +34 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/popObject.js +50 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/pushObject.js +46 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/rangeObserver.js +371 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeAt.js +100 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/removeObject.js +49 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +94 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/shiftObject.js +50 -0
- data/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/unshiftObject.js +47 -0
- data/frameworks/sproutcore/frameworks/runtime/mixins/array.js +320 -110
- data/frameworks/sproutcore/frameworks/runtime/mixins/copyable.js +64 -0
- data/frameworks/sproutcore/frameworks/runtime/mixins/delegate_support.js +44 -6
- data/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +142 -77
- data/frameworks/sproutcore/frameworks/runtime/mixins/freezable.js +104 -0
- data/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +298 -142
- data/frameworks/sproutcore/frameworks/runtime/private/chain_observer.js +17 -11
- data/frameworks/sproutcore/frameworks/runtime/private/observer_queue.js +55 -15
- data/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +29 -5
- data/frameworks/sproutcore/frameworks/runtime/protocols/observable_protocol.js +40 -0
- data/frameworks/sproutcore/frameworks/runtime/system/binding.js +39 -15
- data/frameworks/sproutcore/frameworks/runtime/system/index_set.js +1166 -0
- data/frameworks/sproutcore/frameworks/runtime/system/object.js +33 -15
- data/frameworks/sproutcore/frameworks/runtime/system/range_observer.js +201 -35
- data/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +42 -15
- data/frameworks/sproutcore/frameworks/runtime/system/selection_set.js +649 -0
- data/frameworks/sproutcore/frameworks/runtime/system/set.js +183 -54
- data/frameworks/sproutcore/frameworks/runtime/system/sparse_array.js +20 -11
- data/frameworks/sproutcore/frameworks/runtime/tests/core/clone.js +2 -2
- data/frameworks/sproutcore/frameworks/runtime/tests/core/compare.js +44 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/core/console.js +16 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/core/keys.js +1 -1
- data/frameworks/sproutcore/frameworks/runtime/tests/core/makeArray.js +1 -1
- data/frameworks/sproutcore/frameworks/runtime/tests/core/objectForPropertyPath.js +5 -5
- data/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +57 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable.js +21 -2
- data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/observable.js +249 -129
- data/frameworks/sproutcore/frameworks/runtime/tests/mixins/observable/propertyChanges.js +11 -2
- data/frameworks/sproutcore/frameworks/runtime/tests/private/observer_queue/isObservingSuspended.js +55 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +81 -6
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/add.js +195 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/clone.js +43 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/contains.js +74 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/create.js +42 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/indexAfter.js +38 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/indexBefore.js +38 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/intersects.js +74 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/max.js +40 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/min.js +40 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/rangeStartForIndex.js +36 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/remove.js +189 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/index_set/without.js +89 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/object/base.js +1 -1
- data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/create.js +59 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/destroy.js +75 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/objectPropertyDidChange.js +117 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/rangeDidChange.js +110 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/range_observer/update.js +65 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/run_loop.js +3 -3
- data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/add.js +92 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/copy.js +17 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/indexSetForSource.js +85 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/isEqual.js +60 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/selection_set/remove.js +87 -0
- data/frameworks/sproutcore/frameworks/runtime/tests/system/set.js +4 -25
- data/frameworks/sproutcore/frameworks/runtime/tests/system/sparse_array.js +39 -1
- data/frameworks/sproutcore/frameworks/testing/core.js +183 -0
- data/frameworks/sproutcore/frameworks/testing/english.lproj/runner.css +126 -0
- data/frameworks/sproutcore/frameworks/testing/extras.js +0 -26
- data/frameworks/sproutcore/frameworks/testing/qunit.js +33 -25
- data/frameworks/sproutcore/frameworks/testing/system/dump.js +205 -0
- data/frameworks/sproutcore/frameworks/testing/system/equiv.js +201 -0
- data/frameworks/sproutcore/frameworks/testing/system/plan.js +691 -0
- data/frameworks/sproutcore/frameworks/testing/system/runner.js +209 -0
- data/frameworks/sproutcore/frameworks/testing/system/suite.js +228 -0
- data/frameworks/sproutcore/frameworks/testing/utils.js +8 -1
- data/frameworks/sproutcore/lib/index.rhtml +4 -1
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/10.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/100.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/102.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/110.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/120.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/127.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/18.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/19.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/2.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/24.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/26.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/27.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/28.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/29.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/30.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/31.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/33.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/37.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/41.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/16/99.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/10.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/100.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/102.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/110.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/120.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/127.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/18.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/19.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/2.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/24.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/26.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/27.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/28.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/29.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/30.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/31.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/33.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/37.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/41.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/24/99.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/10.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/100.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/102.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/110.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/120.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/127.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/18.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/19.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/2.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/24.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/26.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/27.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/28.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/29.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/30.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/31.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/33.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/37.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/41.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/32/99.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/48/10.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/48/18.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/48/19.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/icons/48/2.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sc-theme-repeat-x-2.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sc-theme-repeat-x.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sc-theme-sprite.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sc-theme-ysprite.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/shared-icons.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sproutcore-logo.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/Source/sticky-note.psd +0 -0
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/button.css +191 -193
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/checkbox.css +11 -10
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/collection.css +85 -4
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/core.css +15 -2
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/images/sc-theme-repeat-x.png +0 -0
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/label.css +0 -26
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/list_item.css +30 -0
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/progress.css +9 -6
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/radio.css +20 -11
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/segmented.css +192 -54
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/slider.css +56 -24
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/tab.css +13 -7
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/text_field.css +1 -4
- data/frameworks/sproutcore/themes/standard_theme/english.lproj/toolbar.css +4 -1
- data/lib/sproutcore/builders/minify.rb +2 -2
- data/lib/sproutcore/builders/test.rb +1 -1
- data/lib/sproutcore/buildfile.rb +1 -0
- data/lib/sproutcore/rack/dev.rb +1 -1
- data/lib/sproutcore/rack/filesystem.rb +265 -0
- data/lib/sproutcore/rack/proxy.rb +11 -3
- data/lib/sproutcore/rack/service.rb +11 -1
- data/lib/sproutcore/tools.rb +11 -1
- data/lib/sproutcore/tools/server.rb +6 -4
- data/vendor/jsdoc/README.txt +151 -0
- data/vendor/jsdoc/changes.txt +47 -0
- metadata +263 -308
- data/frameworks/sproutcore/apps/sc_jsdoc/controllers/docs.js +0 -149
- data/frameworks/sproutcore/apps/sc_jsdoc/core.js +0 -16
- data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/body.css +0 -17
- data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/body.js +0 -99
- data/frameworks/sproutcore/apps/sc_jsdoc/english.lproj/images/sproutcore-logo.png +0 -0
- data/frameworks/sproutcore/apps/sc_jsdoc/main.js +0 -27
- data/frameworks/sproutcore/apps/sc_jsdoc/models/doc.js +0 -21
- data/frameworks/sproutcore/apps/sc_qunit/controllers/runner.js +0 -209
- data/frameworks/sproutcore/apps/sc_qunit/core.js +0 -16
- data/frameworks/sproutcore/apps/sc_qunit/english.lproj/body.css +0 -17
- data/frameworks/sproutcore/apps/sc_qunit/english.lproj/body.js +0 -107
- data/frameworks/sproutcore/apps/sc_qunit/english.lproj/images/sproutcore-logo.png +0 -0
- data/frameworks/sproutcore/apps/sc_qunit/english.lproj/strings.js +0 -15
- data/frameworks/sproutcore/apps/sc_qunit/main.js +0 -18
- data/frameworks/sproutcore/apps/sc_qunit/models/test.js +0 -24
- data/frameworks/sproutcore/apps/sc_qunit/views/test_iframe.js +0 -52
- data/frameworks/sproutcore/apps/tests/controllers/test.js +0 -20
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/images/blank.gif +0 -0
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/menu.css +0 -83
- data/frameworks/sproutcore/frameworks/desktop/english.lproj/palette.css +0 -3
- data/frameworks/sproutcore/frameworks/desktop/tests/views/collection/methods.js +0 -10
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/methods.js +0 -10
- data/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui.js +0 -110
- data/frameworks/sproutcore/frameworks/foundation/mixins/responder.js +0 -156
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/array.js +0 -118
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/controller.js +0 -268
- data/frameworks/sproutcore/frameworks/foundation/tests/controllers/object.js +0 -433
- data/frameworks/sproutcore/frameworks/runtime/tests/system/array.js +0 -263
- data/frameworks/sproutcore/frameworks/testing/tests/debug/qunit.js +0 -25
- data/spec/buildtasks/manifest/spec_helper.rb +0 -35
- data/spec/buildtasks/target_spec.rb +0 -214
- data/spec/fixtures/builder_tests/Buildfile +0 -15
- data/spec/fixtures/builder_tests/apps/combine_test/a.js +0 -1
- data/spec/fixtures/builder_tests/apps/combine_test/b.js +0 -1
- data/spec/fixtures/builder_tests/apps/combine_test/c.js +0 -1
- data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/a.css +0 -1
- data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/b.css +0 -1
- data/spec/fixtures/builder_tests/apps/combine_test/english.lproj/c.css +0 -1
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/bar1_sample.rhtml +0 -2
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/erb_sample.html.erb +0 -1
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/icons/image.png +0 -0
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/image.jpg +0 -0
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/rhtml_sample.rhtml +0 -1
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/strings.js +0 -4
- data/spec/fixtures/builder_tests/apps/html_test/english.lproj/style.css +0 -0
- data/spec/fixtures/builder_tests/apps/html_test/french.lproj/french-icons/fr.png +0 -0
- data/spec/fixtures/builder_tests/apps/html_test/french.lproj/strings.js +0 -4
- data/spec/fixtures/builder_tests/apps/html_test/lib/layout_template.rhtml +0 -1
- data/spec/fixtures/builder_tests/apps/html_test/scripts.js +0 -0
- data/spec/fixtures/builder_tests/apps/javascript_test/sc_static.js +0 -15
- data/spec/fixtures/builder_tests/apps/javascript_test/sc_super.js +0 -4
- data/spec/fixtures/builder_tests/apps/javascript_test/strings.js +0 -7
- data/spec/fixtures/builder_tests/apps/sass_test/sample.sass +0 -3
- data/spec/fixtures/builder_tests/apps/strings_test/lproj/strings.js +0 -8
- data/spec/fixtures/builder_tests/apps/stylesheet_test/build_directives.css +0 -9
- data/spec/fixtures/builder_tests/apps/stylesheet_test/sc_static.css +0 -12
- data/spec/fixtures/builder_tests/apps/test_test/lib/alt_layout.rhtml +0 -1
- data/spec/fixtures/builder_tests/apps/test_test/lib/test_layout.rhtml +0 -3
- data/spec/fixtures/builder_tests/apps/test_test/tests/qunit_test.js +0 -1
- data/spec/fixtures/builder_tests/apps/test_test/tests/qunit_test2.js +0 -1
- data/spec/fixtures/builder_tests/apps/test_test/tests/rhtml_test.rhtml +0 -4
- data/spec/fixtures/builder_tests/frameworks/debug/core.js +0 -0
- data/spec/fixtures/builder_tests/frameworks/debug/english.lproj/dummy.css +0 -0
- data/spec/fixtures/builder_tests/frameworks/qunit/core.js +0 -0
- data/spec/fixtures/builder_tests/frameworks/qunit/english.lproj/dummy.css +0 -0
- data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/req_style_1.css +0 -0
- data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/strings.js +0 -4
- data/spec/fixtures/builder_tests/frameworks/req_target_1/english.lproj/test.rhtml +0 -1
- data/spec/fixtures/builder_tests/frameworks/req_target_1/req_js_1.js +0 -0
- data/spec/fixtures/builder_tests/frameworks/req_target_2/english.lproj/req_style_2.css +0 -0
- data/spec/fixtures/builder_tests/frameworks/req_target_2/english.lproj/test.rhtml +0 -1
- data/spec/fixtures/builder_tests/frameworks/req_target_2/javascript.js +0 -1
- data/spec/fixtures/builder_tests/frameworks/req_target_2/lib/alt_layout.rhtml +0 -0
- data/spec/fixtures/builder_tests/frameworks/req_target_2/req_js_2.js +0 -0
- data/spec/fixtures/builder_tests/themes/sample_theme/Buildfile +0 -1
- data/spec/fixtures/buildfiles/basic/Buildfile +0 -16
- data/spec/fixtures/buildfiles/basic/task_module.rake +0 -6
- data/spec/fixtures/buildfiles/installed/Buildfile +0 -7
- data/spec/fixtures/buildfiles/installed/Buildfile2 +0 -5
- data/spec/fixtures/buildfiles/project_test/Buildfile +0 -4
- data/spec/fixtures/buildfiles/project_test/not_project/Buildfile +0 -2
- data/spec/fixtures/buildfiles/project_test/not_project/child/PLACEHOLDER +0 -0
- data/spec/fixtures/entry_for_project/Buildfile +0 -1
- data/spec/fixtures/entry_for_project/apps/test_app/frameworks/nested/PLACEHOLDER +0 -0
- data/spec/fixtures/entry_for_project/frameworks/shared/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/Buildfile +0 -8
- data/spec/fixtures/find_targets/custom/bars/bar1/bars/bar1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/bars/bar1/bars/bar2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/bars/bar1/foos/foo1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/bars/bar1/foos/foo2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/foos/custom_foos/Buildfile +0 -5
- data/spec/fixtures/find_targets/custom/foos/custom_foos/custom_foodir/foo1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/foos/custom_foos/custom_foodir/foo2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/foos/custom_foos/foos/not_foo1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/foos/foo1/bars/bar1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/custom/foos/foo1/bars/bar2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/nested/Buildfile +0 -8
- data/spec/fixtures/find_targets/nested/apps/app1/Buildfile +0 -1
- data/spec/fixtures/find_targets/nested/apps/app1/apps/nested_app/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/Apps/app1/frameworks/framework1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/Apps/app1/frameworks/framework2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/clients/client1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/frameworks/framework1/frameworks/framework1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/frameworks/framework2/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/themes/theme1/PLACEHOLDER +0 -0
- data/spec/fixtures/find_targets/standard/themes/theme2/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/caps_long_names/English.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/caps_long_names/FreNCH.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/caps_long_names/UnknOWN.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/english.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/french.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/german.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/italian.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/japanese.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/spanish.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/long_names/unknown.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/no_names/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/de.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/en-CA.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/en-GB.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/en-US.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/en.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/es.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/foo.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/fr.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/it.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/languages/apps/short_names/ja.lproj/PLACEHOLDER +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/1.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/B.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/a.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/a/a.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/a/b.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/b/a.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/c.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/core.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/B.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a/a.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/a/b.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/b/a.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/english.lproj/c.css +0 -0
- data/spec/fixtures/ordered_entries/apps/no_requires/lproj/strings.js +0 -1
- data/spec/fixtures/ordered_entries/apps/no_requires/utils.js +0 -1
- data/spec/fixtures/ordered_entries/apps/with_requires/a.js +0 -2
- data/spec/fixtures/ordered_entries/apps/with_requires/b.js +0 -3
- data/spec/fixtures/ordered_entries/apps/with_requires/c.js +0 -2
- data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/a.css +0 -2
- data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/b.css +0 -2
- data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/c.css +0 -2
- data/spec/fixtures/ordered_entries/apps/with_requires/english.lproj/d.js +0 -1
- data/spec/fixtures/real_world/Buildfile +0 -12
- data/spec/fixtures/real_world/apps/account/README +0 -1
- data/spec/fixtures/real_world/apps/calendar/README +0 -1
- data/spec/fixtures/real_world/apps/contacts/README_BEFORE_EDITING +0 -1
- data/spec/fixtures/real_world/apps/files/README +0 -1
- data/spec/fixtures/real_world/apps/mail/README +0 -1
- data/spec/fixtures/real_world/apps/mobile_photos/README +0 -1
- data/spec/fixtures/real_world/apps/photos/README +0 -1
- data/spec/fixtures/real_world/apps/uploader/README +0 -1
- data/spec/fixtures/real_world/frameworks/core_files/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/core_photos/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/shared/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/Buildfile +0 -26
- data/spec/fixtures/real_world/frameworks/sproutcore/README +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/apps/docs/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/apps/test_runner/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/core.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/debug/debug-resource.html +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/debug/sample_debug.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/demo2.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/debug/sample_debug-loc.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo.css +0 -4
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo.html +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/demo2.sass +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.haml +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.html.erb +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/file_extension_test.rhtml +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/fixtures/sample_fixtures-loc.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/has_require.css +0 -4
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/no_require.css +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/no_sc_resource.rhtml +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/protocols/sample-loc.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/sc_resource.css +0 -6
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/sc_resource.rhtml +0 -3
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/strings.js +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/english.lproj/tests/sample-loc.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/fixtures/sample-json-fixture.json +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/fixtures/sample_fixtures.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/application/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/costello/core.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/data_store/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/debug/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/desktop/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/empty_theme/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/foundation/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/mobile/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/qunit/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/frameworks/uploader/PLACEHOLDER +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/french.lproj/french-resource.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/french.lproj/strings.js +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/german.lproj/german-resource.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/german.lproj/strings.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/has_require.js +0 -4
- data/spec/fixtures/real_world/frameworks/sproutcore/lib/index.html +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/no_require.js +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/protocols/sample.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/sc_resource.js +0 -6
- data/spec/fixtures/real_world/frameworks/sproutcore/tests/nested/sample1.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/tests/nested/sample2.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/tests/sample.js +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/tests/sample.rhtml +0 -1
- data/spec/fixtures/real_world/frameworks/sproutcore/themes/standard_theme/README +0 -0
- data/spec/fixtures/real_world/frameworks/sproutcore/views/view.js +0 -1
- data/spec/fixtures/real_world/generators/sample_custom/Buildfile +0 -0
- data/spec/fixtures/real_world/generators/sample_custom/templates/{filename}.js +0 -1
- data/spec/fixtures/recursive_project/Buildfile +0 -8
- data/spec/fixtures/recursive_project/frameworks/sproutcore/frameworks/costello/PLACEHOLDER +0 -0
- data/spec/lib/builders/combine_spec.rb +0 -67
- data/spec/lib/builders/html_spec.rb +0 -577
- data/spec/lib/builders/javascript_spec.rb +0 -81
- data/spec/lib/builders/sass_spec.rb +0 -43
- data/spec/lib/builders/spec_helper.rb +0 -30
- data/spec/lib/builders/strings_spec.rb +0 -52
- data/spec/lib/builders/stylesheet_spec.rb +0 -63
- data/spec/lib/builders/test_index_spec.rb +0 -44
- data/spec/lib/builders/test_spec.rb +0 -135
- data/spec/lib/buildfile/config_for_spec.rb +0 -81
- data/spec/lib/buildfile/define_spec.rb +0 -59
- data/spec/lib/buildfile/dup_spec.rb +0 -65
- data/spec/lib/buildfile/invoke_spec.rb +0 -130
- data/spec/lib/buildfile/load_spec.rb +0 -49
- data/spec/lib/buildfile/task/dup_spec.rb +0 -55
- data/spec/lib/buildfile/task_defined_spec.rb +0 -17
- data/spec/lib/buildfile_commands/build_task_spec.rb +0 -19
- data/spec/lib/buildfile_commands/config_spec.rb +0 -97
- data/spec/lib/buildfile_commands/import_spec.rb +0 -17
- data/spec/lib/buildfile_commands/namespace_spec.rb +0 -18
- data/spec/lib/buildfile_commands/proxies_spec.rb +0 -38
- data/spec/lib/buildfile_commands/replace_task_spec.rb +0 -29
- data/spec/lib/buildfile_commands/task_spec.rb +0 -36
- data/spec/lib/helpers/packing_optimizer/optimize_spec.rb +0 -26
- data/spec/lib/models/hash_struct/deep_clone_spec.rb +0 -27
- data/spec/lib/models/hash_struct/has_options_spec.rb +0 -32
- data/spec/lib/models/hash_struct/hash_spec.rb +0 -64
- data/spec/lib/models/hash_struct/merge_spec.rb +0 -26
- data/spec/lib/models/hash_struct/method_missing.rb +0 -41
- data/spec/lib/models/manifest/add_entry_spec.rb +0 -36
- data/spec/lib/models/manifest/add_transform_spec.rb +0 -90
- data/spec/lib/models/manifest/build_spec.rb +0 -78
- data/spec/lib/models/manifest/entry_for_spec.rb +0 -94
- data/spec/lib/models/manifest/find_entry.rb +0 -84
- data/spec/lib/models/manifest/prepare_spec.rb +0 -62
- data/spec/lib/models/manifest_entry/cacheable_url_spec.rb +0 -31
- data/spec/lib/models/manifest_entry/prepare_spec.rb +0 -54
- data/spec/lib/models/project/add_target_spec.rb +0 -44
- data/spec/lib/models/project/buildfile_spec.rb +0 -35
- data/spec/lib/models/project/find_targets_for_spec.rb +0 -77
- data/spec/lib/models/project/load_nearest_project_spec.rb +0 -23
- data/spec/lib/models/project/target_for_spec.rb +0 -33
- data/spec/lib/models/project/targets_spec.rb +0 -62
- data/spec/lib/models/target/compute_build_number_spec.rb +0 -125
- data/spec/lib/models/target/config_spec.rb +0 -30
- data/spec/lib/models/target/expand_required_targets_spec.rb +0 -48
- data/spec/lib/models/target/installed_languages_spec.rb +0 -47
- data/spec/lib/models/target/lproj_for_spec.rb +0 -38
- data/spec/lib/models/target/manifest_for_spec.rb +0 -42
- data/spec/lib/models/target/parent_target_spec.rb +0 -21
- data/spec/lib/models/target/prepare_spec.rb +0 -53
- data/spec/lib/models/target/required_targets_spec.rb +0 -119
- data/spec/lib/models/target/target_for_spec.rb +0 -56
- data/spec/lib/tools/build_number_spec.rb +0 -28
- data/spec/lib/tools/gen_spec.rb +0 -207
- data/spec/lib/tools/tools_spec.rb +0 -78
- data/spec/spec_helper.rb +0 -138
- data/vendor/github_gem_lint.rb +0 -22
- data/vendor/yui-compressor/yuicompressor-2.4.2.jar +0 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
|
4
|
+
// portions copyright @2009 Apple, Inc.
|
5
|
+
// License: Licened under MIT license (see license.js)
|
6
|
+
// ==========================================================================
|
7
|
+
|
8
|
+
/* Test SC.StackedView with a Comments example. */
|
9
|
+
|
10
|
+
htmlbody(["<style>",
|
11
|
+
'.sc-stacked-view { border-bottom: 1px red solid; }',
|
12
|
+
'.comment-view.sel { background-color: #ccc; }',
|
13
|
+
'.comment-view { margin: 0 10px; padding: 10px 0; border-bottom: 1px #ccc solid; }',
|
14
|
+
'.comment-view p { padding-top: 28px; padding-bottom: 32px; }',
|
15
|
+
'</style>'].join("\n"));
|
16
|
+
|
17
|
+
var CommentView = SC.View.extend(SC.StaticLayout, SC.Control, {
|
18
|
+
|
19
|
+
useStaticLayout: YES,
|
20
|
+
|
21
|
+
content: null,
|
22
|
+
|
23
|
+
classNames: 'comment-view',
|
24
|
+
|
25
|
+
contentPropertyDidChange: function(target, key) {
|
26
|
+
|
27
|
+
// update everything!
|
28
|
+
if (key === '*') {
|
29
|
+
this.updateFromLabel().updateCommentLabel();
|
30
|
+
} else if (key === 'from' || key === 'date') {
|
31
|
+
this.updateFromLabel();
|
32
|
+
} else if (key === 'comment') {
|
33
|
+
this.updateCommentLabel();
|
34
|
+
}
|
35
|
+
|
36
|
+
if (this.owner && this.owner.updateHeight) this.owner.updateHeight();
|
37
|
+
},
|
38
|
+
|
39
|
+
updateFromLabel: function() {
|
40
|
+
var content = this.get('content'),
|
41
|
+
from = content ? content.get('from') : 'Anonymous',
|
42
|
+
date = content ? content.get('date') : 'some date',
|
43
|
+
str = "%@ wrote %@: ".fmt(from, date);
|
44
|
+
this.fromLabel.set('value', str);
|
45
|
+
return this ;
|
46
|
+
},
|
47
|
+
|
48
|
+
updateCommentLabel: function() {
|
49
|
+
var content = this.get('content'),
|
50
|
+
comment = content ? content.get('comment') : '(No Comment)';
|
51
|
+
this.commentLabel.set('value', comment);
|
52
|
+
},
|
53
|
+
|
54
|
+
// ..........................................................
|
55
|
+
// BASE VIEWS
|
56
|
+
//
|
57
|
+
|
58
|
+
childViews: 'fromLabel commentLabel editButton replyButton'.w(),
|
59
|
+
|
60
|
+
fromLabel: SC.LabelView.extend({
|
61
|
+
tagName: "label",
|
62
|
+
layout: { left: 0, top: 0, right: 0, height: 18 }
|
63
|
+
}),
|
64
|
+
|
65
|
+
commentLabel: SC.LabelView.extend(SC.StaticLayout, {
|
66
|
+
useStaticLayout: YES,
|
67
|
+
tagName: "p"
|
68
|
+
}),
|
69
|
+
|
70
|
+
editButton: SC.ButtonView.extend({
|
71
|
+
title: "Edit",
|
72
|
+
titleMinWidth: 0,
|
73
|
+
layout: { bottom: 4, right: 58, height: 21, width: 50 }
|
74
|
+
}),
|
75
|
+
|
76
|
+
replyButton: SC.ButtonView.extend({
|
77
|
+
title: "Reply",
|
78
|
+
titleMinWidth: 0,
|
79
|
+
layout: { bottom: 4, right: 4, height: 21, width: 50 }
|
80
|
+
})
|
81
|
+
|
82
|
+
});
|
83
|
+
|
84
|
+
var content = [
|
85
|
+
SC.Object.create({
|
86
|
+
from: "Joe",
|
87
|
+
date: "Today",
|
88
|
+
comment: "I think this new class is a great idea! I've always wanted less control but more flexibility."
|
89
|
+
}),
|
90
|
+
SC.Object.create({
|
91
|
+
from: "Joe",
|
92
|
+
date: "Today",
|
93
|
+
comment: "I think this new class is a great idea! I've always wanted less control but more flexibility."
|
94
|
+
}),
|
95
|
+
SC.Object.create({
|
96
|
+
from: "Joe",
|
97
|
+
date: "Today",
|
98
|
+
comment: "I think this new class is a great idea! I've always wanted less control but more flexibility."
|
99
|
+
}),
|
100
|
+
SC.Object.create({
|
101
|
+
from: "Joe",
|
102
|
+
date: "Today",
|
103
|
+
comment: "I think this new class is a great idea! I've always wanted less control but more flexibility."
|
104
|
+
}),
|
105
|
+
SC.Object.create({
|
106
|
+
from: "Jane",
|
107
|
+
date: "Yesterday",
|
108
|
+
comment: "If only you would rewrite this in Flash. Then I could get really excited about it. I like it when Adobe controls my destiny."
|
109
|
+
})
|
110
|
+
];
|
111
|
+
|
112
|
+
var extra = SC.Object.create({
|
113
|
+
from: "Charles",
|
114
|
+
date: "Tomorrow",
|
115
|
+
comment: "Hello from the world of tomorrow!"
|
116
|
+
});
|
117
|
+
|
118
|
+
var pane = SC.ControlTestPane.design()
|
119
|
+
.add("basic", SC.StackedView, {
|
120
|
+
layout: { top: 0, left: 0, right: 0, height: 600 },
|
121
|
+
content: content,
|
122
|
+
exampleView: CommentView
|
123
|
+
});
|
124
|
+
|
125
|
+
pane.show(); // add a test to show the test pane
|
126
|
+
window.pane = pane ;
|
127
|
+
|
128
|
+
// ..........................................................
|
129
|
+
// BASIC TESTS
|
130
|
+
//
|
131
|
+
module("Basic Tests", pane.standardSetup());
|
132
|
+
|
133
|
+
test("removing an item should delete childView and adjust height", function() {
|
134
|
+
var view = pane.view('basic'),
|
135
|
+
item = content[0];
|
136
|
+
|
137
|
+
equals(view.getPath('childViews.length'), content.length, 'precond - should have child views equal to current content');
|
138
|
+
var oldHeight = view.get('frame').height; // save height.
|
139
|
+
|
140
|
+
SC.run(function() { content.removeAt(0); }); // remove first item
|
141
|
+
|
142
|
+
|
143
|
+
equals(view.getPath('childViews.length'), content.length, 'view should remove childView for removed content items');
|
144
|
+
var newHeight = view.get('frame').height;
|
145
|
+
ok(newHeight < oldHeight, 'view height should adjust to reflect new content. (old height: %@ current height: %@)'.fmt(oldHeight, newHeight));
|
146
|
+
|
147
|
+
// restore old content
|
148
|
+
SC.run(function() { content.insertAt(0, item); });
|
149
|
+
|
150
|
+
});
|
151
|
+
|
152
|
+
window.content = content ;
|
153
|
+
|
154
|
+
test("inserting an item should add childView and adjust height", function() {
|
155
|
+
var view = pane.view('basic'),
|
156
|
+
item = extra; // we will insert another one
|
157
|
+
|
158
|
+
equals(view.getPath('childViews.length'), content.length, 'precond - should have child views equal to current content');
|
159
|
+
var oldHeight = view.get('frame').height; // save height.
|
160
|
+
|
161
|
+
SC.run(function() { content.pushObject(item); }); // add another item
|
162
|
+
|
163
|
+
|
164
|
+
equals(view.getPath('childViews.length'), content.length, 'view should add childView for added content item');
|
165
|
+
var newHeight = view.get('frame').height;
|
166
|
+
ok(newHeight > oldHeight, 'view height should adjust to reflect new content. (old height: %@ current height: %@)'.fmt(oldHeight, newHeight));
|
167
|
+
|
168
|
+
// restore
|
169
|
+
SC.run(function() { content.popObject(); });
|
170
|
+
});
|
171
|
+
|
172
|
+
|
173
|
+
test("editing an item should automatically adjust the height", function() {
|
174
|
+
var view = pane.view('basic'),
|
175
|
+
item = content[0],
|
176
|
+
childView = view.childViews[0],
|
177
|
+
old = item.get('comment');
|
178
|
+
|
179
|
+
ok(childView, 'stacked view should have child view');
|
180
|
+
equals(childView.get('content'), item, 'first childView should own first content item');
|
181
|
+
|
182
|
+
var height = view.get('frame').height; // save old height
|
183
|
+
|
184
|
+
// change comment
|
185
|
+
SC.run(function() { item.set('comment', 'This is a new comment'); });
|
186
|
+
|
187
|
+
// should have updated UI and adjusted height of collection
|
188
|
+
equals(childView.$().find('p').text(), 'This is a new comment', 'Item view should now contain comment');
|
189
|
+
|
190
|
+
var newHeight = view.get('frame').height;
|
191
|
+
ok(newHeight < height, 'view height should adjust to reflect new content. (old height: %@ current height: %@)'.fmt(height, newHeight));
|
192
|
+
|
193
|
+
// restore
|
194
|
+
SC.run(function() { item.set('comment', old); });
|
195
|
+
|
196
|
+
newHeight = view.get('frame').height;
|
197
|
+
equals(newHeight, height, 'view height should restore to old height when content is edited again. (old height: %@ current height: %@)'.fmt(height, newHeight));
|
198
|
+
|
199
|
+
});
|
200
|
+
|
201
|
+
// ..........................................................
|
202
|
+
// SPECIAL CASES
|
203
|
+
//
|
204
|
+
|
205
|
+
// tests specific bug where a series of many edits strung together would
|
206
|
+
// cause the height to get out of sync.
|
207
|
+
test("adding, removing then editing items should still keep height the same", function() {
|
208
|
+
|
209
|
+
var view = pane.view('basic'),
|
210
|
+
item = content[0],
|
211
|
+
old = item.get('comment'),
|
212
|
+
height = view.get('frame').height; // save old height
|
213
|
+
|
214
|
+
SC.run(function() { content.removeAt(0); });
|
215
|
+
SC.run(function() { content.insertAt(0, item); });
|
216
|
+
SC.run(function() { content.pushObject(extra); });
|
217
|
+
SC.run(function() { content.popObject(); });
|
218
|
+
|
219
|
+
SC.run(function() { item.set('comment', 'Short comment'); });
|
220
|
+
SC.run(function() { item.set('comment', old); });
|
221
|
+
|
222
|
+
var newHeight = view.get('frame').height;
|
223
|
+
equals(newHeight, height, 'view height should restore to old height when content is edited again. (old height: %@ current height: %@)'.fmt(height, newHeight));
|
224
|
+
|
225
|
+
});
|
226
|
+
|
227
|
+
|
228
|
+
|
229
|
+
|
230
|
+
|
231
|
+
|
@@ -83,7 +83,7 @@
|
|
83
83
|
SC.Event.add(view.$('iframe')[0], 'load', this,
|
84
84
|
function() {
|
85
85
|
ok(view.$().height() > 150, "height of view should change based on content");
|
86
|
-
ok(view.$().width() >
|
86
|
+
ok(view.$().width() > 200, "width of view should change based on content");
|
87
87
|
start();
|
88
88
|
});
|
89
89
|
});
|
@@ -160,7 +160,7 @@ SC.ButtonView = SC.View.extend(SC.Control, SC.Button, SC.StaticLayout,
|
|
160
160
|
// display properties that should automatically cause a refresh.
|
161
161
|
// isCancel and isDefault also cause a refresh but this is implemented as
|
162
162
|
// a separate observer (see below)
|
163
|
-
displayProperties: ['href', 'icon', 'title', 'value'],
|
163
|
+
displayProperties: ['href', 'icon', 'title', 'value', 'toolTip'],
|
164
164
|
|
165
165
|
render: function(context, firstTime) {
|
166
166
|
// add href attr if tagName is anchor...
|
@@ -169,6 +169,13 @@ SC.ButtonView = SC.View.extend(SC.Control, SC.Button, SC.StaticLayout,
|
|
169
169
|
if (!href || (href.length === 0)) href = "javascript"+":;";
|
170
170
|
context.attr('href', href);
|
171
171
|
}
|
172
|
+
|
173
|
+
// If there is a toolTip set, grab it and localize if necessary.
|
174
|
+
var toolTip = this.get('toolTip') ;
|
175
|
+
if(SC.typeOf(toolTip) === SC.T_STRING) {
|
176
|
+
context.attr('title', this.get('localize') ? toolTip.loc() : toolTip) ;
|
177
|
+
context.attr('alt', this.get('localize') ? toolTip.loc() : toolTip) ;
|
178
|
+
}
|
172
179
|
|
173
180
|
// add some standard attributes & classes.
|
174
181
|
var classes = this._TEMPORARY_CLASS_HASH;
|
@@ -178,10 +185,14 @@ SC.ButtonView = SC.View.extend(SC.Control, SC.Button, SC.StaticLayout,
|
|
178
185
|
context.attr('role', 'button')
|
179
186
|
.setClass(classes).addClass(this.get('theme'));
|
180
187
|
// render inner html
|
181
|
-
|
182
|
-
.
|
188
|
+
if(firstTime){
|
189
|
+
context = context.push("<span class='sc-button-inner' style = 'min-width:%@px'>"
|
190
|
+
.fmt(this.get('titleMinWidth')));
|
183
191
|
this.renderTitle(context, firstTime) ; // from button mixin
|
184
|
-
|
192
|
+
context.push("</span>") ;
|
193
|
+
}else{
|
194
|
+
this.renderTitle(context, firstTime) ;
|
195
|
+
}
|
185
196
|
},
|
186
197
|
|
187
198
|
/** @private {String} used to store a previously defined key equiv */
|
@@ -26,7 +26,7 @@ SC.CheckboxView = SC.FieldView.extend(SC.StaticLayout, SC.Button,
|
|
26
26
|
tagName: 'label',
|
27
27
|
|
28
28
|
render: function(context, firstTime) {
|
29
|
-
var dt ;
|
29
|
+
var dt, elem ;
|
30
30
|
|
31
31
|
// add checkbox -- set name to view guid to separate it from others
|
32
32
|
if (firstTime) {
|
@@ -42,6 +42,13 @@ SC.CheckboxView = SC.FieldView.extend(SC.StaticLayout, SC.Button,
|
|
42
42
|
// since we don't want to regenerate the contents each time
|
43
43
|
// actually search for and update the displayTitle.
|
44
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
|
+
|
45
52
|
dt = this.get('displayTitle');
|
46
53
|
if (dt !== this._field_currentDisplayTitle) {
|
47
54
|
this._field_currentDisplayTitle = dt;
|
@@ -8,13 +8,6 @@
|
|
8
8
|
sc_require('mixins/collection_view_delegate') ;
|
9
9
|
sc_require('views/list_item');
|
10
10
|
|
11
|
-
SC.BENCHMARK_UPDATE_CHILDREN = YES ;
|
12
|
-
SC.BENCHMARK_RENDER = YES ;
|
13
|
-
SC.ENABLE_COLLECTION_PARTIAL_RENDER = YES ;
|
14
|
-
SC.DEBUG_PARTIAL_RENDER = NO ;
|
15
|
-
SC.SANITY_CHECK_PARTIAL_RENDER = YES ;
|
16
|
-
SC.VALIDATE_COLLECTION_CONSISTANCY = NO ;
|
17
|
-
|
18
11
|
/**
|
19
12
|
Special drag operation passed to delegate if the collection view proposes
|
20
13
|
to perform a reorder event.
|
@@ -29,16 +22,12 @@ SC.HORIZONTAL_ORIENTATION = 'horizontal';
|
|
29
22
|
/** Selection points should be selected using vertical orientation. */
|
30
23
|
SC.VERTICAL_ORIENTATION = 'vertical' ;
|
31
24
|
|
32
|
-
|
33
|
-
SC.ZOMBIE_GROUPS_ENABLED = YES ;
|
34
|
-
|
35
|
-
/** Enables an optimization that removes the root element from the DOM during
|
36
|
-
a render and then readds it when complete. This option is configurable for
|
37
|
-
perf testing purposes. You should not change it. */
|
38
|
-
SC.REMOVE_COLLECTION_ROOT_ELEMENT_DURING_RENDER = NO ;
|
25
|
+
SC.BENCHMARK_RELOAD = NO ;
|
39
26
|
|
40
27
|
/**
|
41
28
|
@class
|
29
|
+
|
30
|
+
TODO: Document SC.CollectionView
|
42
31
|
|
43
32
|
Renders a collection of views from a source array of model objects.
|
44
33
|
|
@@ -54,16 +43,20 @@ SC.REMOVE_COLLECTION_ROOT_ELEMENT_DURING_RENDER = NO ;
|
|
54
43
|
property if you want to monitor selection. (be sure to set the isEnabled
|
55
44
|
property to allow selection.)
|
56
45
|
|
57
|
-
@extends SC.
|
46
|
+
@extends SC.View
|
58
47
|
@extends SC.CollectionViewDelegate
|
59
|
-
|
48
|
+
@extends SC.CollectionContent
|
49
|
+
@since SproutCore 0.9
|
60
50
|
*/
|
61
|
-
SC.CollectionView = SC.View.extend(
|
62
|
-
|
63
|
-
|
51
|
+
SC.CollectionView = SC.View.extend(
|
52
|
+
SC.CollectionViewDelegate,
|
53
|
+
SC.CollectionContent,
|
54
|
+
/** @scope SC.CollectionView.prototype */ {
|
64
55
|
|
65
56
|
classNames: ['sc-collection-view'],
|
66
57
|
|
58
|
+
ACTION_DELAY: 200,
|
59
|
+
|
67
60
|
// ......................................
|
68
61
|
// PROPERTIES
|
69
62
|
//
|
@@ -82,57 +75,62 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
82
75
|
Usually you will want to bind this property to a controller property
|
83
76
|
that actually contains the array of objects you to display.
|
84
77
|
|
85
|
-
@type SC.Array
|
78
|
+
@type {SC.Array}
|
86
79
|
*/
|
87
|
-
content:
|
80
|
+
content: null,
|
88
81
|
|
89
82
|
/** @private */
|
90
83
|
contentBindingDefault: SC.Binding.multiple(),
|
91
84
|
|
92
85
|
/**
|
93
|
-
The
|
94
|
-
|
95
|
-
This array should contain the currently selected content objects. It is
|
96
|
-
modified automatically by the collection view when the user changes the
|
97
|
-
selection on the collection.
|
86
|
+
The current length of the content.
|
98
87
|
|
99
|
-
|
100
|
-
|
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.
|
101
97
|
|
102
|
-
The
|
103
|
-
|
104
|
-
|
105
|
-
views.
|
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.
|
106
101
|
|
107
|
-
|
108
|
-
|
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.
|
109
105
|
|
110
|
-
@
|
106
|
+
@property
|
107
|
+
@type {SC.IndexSet}
|
111
108
|
*/
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
109
|
+
nowShowing: function() {
|
110
|
+
var ret = this.computeNowShowing();
|
111
|
+
return ret ? ret.frozenCopy() : null;
|
112
|
+
}.property('length', 'clippingFrame').cacheable(),
|
116
113
|
|
117
114
|
/**
|
118
|
-
|
119
|
-
|
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.
|
120
118
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
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}
|
125
123
|
*/
|
126
|
-
|
124
|
+
selection: null,
|
127
125
|
|
128
126
|
/**
|
129
127
|
Allow user to select content using the mouse and keyboard.
|
130
128
|
|
131
129
|
Set this property to NO to disallow the user from selecting items. If you
|
132
|
-
have items in your
|
130
|
+
have items in your selectedIndexes property, they will still be reflected
|
133
131
|
visually.
|
134
132
|
|
135
|
-
@type Boolean
|
133
|
+
@type {Boolean}
|
136
134
|
*/
|
137
135
|
isSelectable: YES,
|
138
136
|
|
@@ -144,10 +142,10 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
144
142
|
|
145
143
|
The collection view will set the isEnabled property of its item views to
|
146
144
|
reflect the same view of this property. Whenever isEnabled is false,
|
147
|
-
the collection view will also be not selectable or editable, regardless of
|
148
|
-
settings for isEditable & isSelectable.
|
145
|
+
the collection view will also be not selectable or editable, regardless of
|
146
|
+
the settings for isEditable & isSelectable.
|
149
147
|
|
150
|
-
@type Boolean
|
148
|
+
@type {Boolean}
|
151
149
|
*/
|
152
150
|
isEnabled: YES,
|
153
151
|
|
@@ -162,7 +160,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
162
160
|
the user will not be able to reorder, add, or delete items regardless of
|
163
161
|
the canReorderContent and canDeleteContent and isDropTarget properties.
|
164
162
|
|
165
|
-
@type Boolean
|
163
|
+
@type {Boolean}
|
166
164
|
*/
|
167
165
|
isEditable: YES,
|
168
166
|
|
@@ -176,7 +174,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
176
174
|
If you also accept drops, this will allow the user to drop items into
|
177
175
|
specific points in the list. Otherwise items will be added to the end.
|
178
176
|
|
179
|
-
@type Boolean
|
177
|
+
@type {Boolean}
|
180
178
|
*/
|
181
179
|
canReorderContent: NO,
|
182
180
|
|
@@ -189,13 +187,25 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
189
187
|
If true the user will be allowed to delete selected items using the delete
|
190
188
|
key. Otherwise deletes will not be permitted.
|
191
189
|
|
192
|
-
@type Boolean
|
190
|
+
@type {Boolean}
|
193
191
|
*/
|
194
192
|
canDeleteContent: NO,
|
195
193
|
|
196
194
|
/** @private */
|
197
195
|
canDeleteContentBindingDefault: SC.Binding.bool(),
|
198
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
|
+
|
199
209
|
/**
|
200
210
|
Accept drops for data other than reordering.
|
201
211
|
|
@@ -203,7 +213,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
203
213
|
cause it to be registered as a drop target, activating the other drop
|
204
214
|
machinery.
|
205
215
|
|
206
|
-
@type Boolean
|
216
|
+
@type {Boolean}
|
207
217
|
*/
|
208
218
|
isDropTarget: NO,
|
209
219
|
|
@@ -212,9 +222,9 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
212
222
|
|
213
223
|
If set to true, then selection will use a toggle instead of the normal
|
214
224
|
click behavior. Command modifiers will be ignored and instead clicking
|
215
|
-
once will
|
225
|
+
once will select an item and clicking on it again will deselect it.
|
216
226
|
|
217
|
-
@type Boolean
|
227
|
+
@type {Boolean}
|
218
228
|
*/
|
219
229
|
useToggleSelection: NO,
|
220
230
|
|
@@ -225,12 +235,12 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
225
235
|
object and double clicking will trigger the action method on the
|
226
236
|
collection view.
|
227
237
|
|
228
|
-
If you set this property to
|
238
|
+
If you set this property to YES, then clicking on a view will both select
|
229
239
|
it (if isSelected is true) and trigger the action method.
|
230
240
|
|
231
241
|
Use this if you are using the collection view as a menu of items.
|
232
242
|
|
233
|
-
@
|
243
|
+
@property {Boolean}
|
234
244
|
*/
|
235
245
|
actOnSelect: NO,
|
236
246
|
|
@@ -244,7 +254,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
244
254
|
the mouse is released, so you can perform, for instance, a drag operation
|
245
255
|
without actually selecting the target item.
|
246
256
|
|
247
|
-
@
|
257
|
+
@property {Boolean}
|
248
258
|
*/
|
249
259
|
selectOnMouseDown: YES,
|
250
260
|
|
@@ -277,9 +287,34 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
277
287
|
|
278
288
|
/**
|
279
289
|
If set, this key will be used to get the example view for a given
|
280
|
-
content object.
|
290
|
+
content object. The exampleView property will be ignored.
|
291
|
+
|
292
|
+
@property {String}
|
281
293
|
*/
|
282
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,
|
283
318
|
|
284
319
|
/**
|
285
320
|
Invoked when the user double clicks on an item (or single clicks of
|
@@ -317,19 +352,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
317
352
|
*/
|
318
353
|
target: null,
|
319
354
|
|
320
|
-
/**
|
321
|
-
Set to YES whenever the content needs to update its children. If you
|
322
|
-
set this property, it will cause the view to update its children at the
|
323
|
-
end of the runloop or the next time it becomes visible.
|
324
|
-
|
325
|
-
Generally you will not need to change this property. Instead you should
|
326
|
-
call methods such as contentPropertyDidChange() or updateChildren()
|
327
|
-
directly instead.
|
328
|
-
|
329
|
-
@property {Boolean}
|
330
|
-
*/
|
331
|
-
isDirty: NO,
|
332
|
-
|
333
355
|
/**
|
334
356
|
Property on content items to use for display.
|
335
357
|
|
@@ -355,20 +377,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
355
377
|
*/
|
356
378
|
acceptsFirstResponder: NO,
|
357
379
|
|
358
|
-
/**
|
359
|
-
If your layout uses a grid or horizontal-based layout, then make sure this
|
360
|
-
property is always up to date with the current number of items per row.
|
361
|
-
|
362
|
-
The CollectionView will use this property to support keyboard navigation
|
363
|
-
using the arrow keys.
|
364
|
-
|
365
|
-
If your collection view is simply a vertical list of items then you do not
|
366
|
-
need to change this property.
|
367
|
-
|
368
|
-
@property {Number}
|
369
|
-
*/
|
370
|
-
itemsPerRow: 1,
|
371
|
-
|
372
380
|
// ..........................................................
|
373
381
|
// SUBCLASS METHODS
|
374
382
|
//
|
@@ -387,406 +395,1036 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
387
395
|
computeLayout: function() { return null; },
|
388
396
|
|
389
397
|
/**
|
390
|
-
Override to
|
391
|
-
|
392
|
-
|
393
|
-
rendering. The range you return here will be used to limit the number of
|
394
|
-
actual item views that are created by the collection view.
|
395
|
-
|
396
|
-
If you do not want to support incremental rendering, just return null.
|
397
|
-
|
398
|
-
@param {Rect} frame The frame you should use to determine the range.
|
399
|
-
@returns {Range} A hash that indicates the range of content objects to
|
400
|
-
render. ({ start: X, length: Y })
|
401
|
-
*/
|
402
|
-
contentRangeInFrame: function(frame) { return null; },
|
403
|
-
|
404
|
-
/**
|
405
|
-
Override to adjust the position of the itemView's layout property at the
|
406
|
-
specified content index.
|
407
|
-
|
408
|
-
Note: if useAdjust is NO, you should set the view's layout property in
|
409
|
-
such a way that no change notifications are triggered. For example,
|
410
|
-
|
411
|
-
{{{
|
412
|
-
var newLayout = this.myComputeLayoutForIndex(contentIndex) ;
|
413
|
-
if (useAdjust) itemView.adjust(newLayout) ;
|
414
|
-
else itemView.layout = newLayout ; // DON'T TRIGGER OBSERVERS!!!
|
415
|
-
}}}
|
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.
|
416
401
|
|
417
402
|
@param {Number} contentIndex the index of content beind rendered by
|
418
403
|
itemView
|
419
|
-
@returns {
|
404
|
+
@returns {Hash} a view layout
|
420
405
|
*/
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
// CONTENT CHANGES
|
425
|
-
//
|
406
|
+
layoutForContentIndex: function(contentIndex) {
|
407
|
+
return null ;
|
408
|
+
},
|
426
409
|
|
427
|
-
/**
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
var content = this.get('content') ;
|
433
|
-
if (content === this._content) return this; // nothing to do
|
434
|
-
|
435
|
-
var func = this._collection_contentPropertyDidChange ;
|
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.
|
436
415
|
|
437
|
-
|
438
|
-
if (this._content) this._content.removeObserver('[]', this, func) ;
|
439
|
-
if (content) content.addObserver('[]', this, func) ;
|
416
|
+
Override this method to implement incremental rendering.
|
440
417
|
|
441
|
-
|
442
|
-
this._content = content;
|
443
|
-
this._contentPropertyRevision = null ;
|
418
|
+
The default simply returns the current content length.
|
444
419
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
/** @private
|
451
|
-
Called whenever the content array or any items in the content array
|
452
|
-
changes. update children if this is a new property revision.
|
453
|
-
*/
|
454
|
-
_collection_contentPropertyDidChange: function(target, key, value, rev) {
|
455
|
-
if (!this._updatingContent && (!rev || (rev != this._contentPropertyRevision))) {
|
456
|
-
this._contentPropertyRevision = rev ;
|
457
|
-
this._updatingContent = true ;
|
458
|
-
this.contentPropertyDidChange(target, key);
|
459
|
-
this._updatingContent = false ;
|
460
|
-
}
|
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'));
|
461
425
|
},
|
462
426
|
|
463
427
|
/**
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
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 ;
|
473
449
|
},
|
474
450
|
|
475
|
-
/**
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
// using invokeOnce here doubles rendering speed!
|
483
|
-
this.invokeOnce(this.displayDidChange) ;
|
484
|
-
}
|
485
|
-
}.observes('isDirty', 'isVisibleInWindow'),
|
486
|
-
|
487
|
-
// ..........................................................
|
488
|
-
// SELECTION CHANGES
|
489
|
-
//
|
490
|
-
|
491
|
-
/** @private
|
492
|
-
Whenever selection array changes, start observing the [] property. Also
|
493
|
-
set childrenNeedFullUpdate to YES, which will trigger an update.
|
494
|
-
*/
|
495
|
-
_collection_selectionDidChange: function() {
|
496
|
-
var selection = this.get('selection') ;
|
497
|
-
if (selection === this._selection) return this; // nothing to do
|
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.
|
498
458
|
|
499
|
-
|
459
|
+
Once this method is called, you are guaranteed to also recieve a call to
|
460
|
+
hideInsertionPoint() at some point in the future.
|
500
461
|
|
501
|
-
|
502
|
-
if (this._selection) this._selection.removeObserver('[]', this, func) ;
|
503
|
-
if (selection) selection.addObserver('[]', this, func) ;
|
462
|
+
The default implementation of this method does nothing.
|
504
463
|
|
505
|
-
|
506
|
-
|
507
|
-
this._selectionPropertyRevision = null ;
|
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
|
508
466
|
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
}.observes('selection'),
|
513
|
-
|
514
|
-
/** @private
|
515
|
-
Called whenever the content array or any items in the selection array
|
516
|
-
changes. update children if this is a new property revision.
|
517
|
-
*/
|
518
|
-
_collection_selectionPropertyDidChange: function(target, key, value, rev) {
|
519
|
-
if (!this._updatingSelection && (!rev || (rev != this._selectionPropertyRevision))) {
|
520
|
-
this._selectionPropertyRevision = rev ;
|
521
|
-
this._updatingSelection = true ;
|
522
|
-
this.selectionPropertyDidChange(target, key);
|
523
|
-
this._updatingSelection = false ;
|
524
|
-
}
|
467
|
+
@returns {void}
|
468
|
+
*/
|
469
|
+
showInsertionPoint: function(itemView, dropOperation) {
|
525
470
|
},
|
526
471
|
|
527
472
|
/**
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
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() {
|
537
487
|
},
|
538
488
|
|
539
489
|
// ..........................................................
|
540
|
-
//
|
490
|
+
// DELEGATE SUPPORT
|
541
491
|
//
|
542
492
|
|
493
|
+
|
543
494
|
/**
|
544
|
-
|
545
|
-
|
546
|
-
the collection view to do a 'fast' revalidation of its content.
|
495
|
+
Delegate used to implement fine-grained control over collection view
|
496
|
+
behaviors.
|
547
497
|
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
// console.log(this.get('clippingFrame'));
|
553
|
-
var r = this.contentRangeInFrame(this.get('clippingFrame')) ;
|
554
|
-
if (!r) r = { start: 0, length: 0 } ; // default
|
555
|
-
|
556
|
-
// make sure the range isn't greater than the content length
|
557
|
-
var content = SC.makeArray(this.get('content'));
|
558
|
-
r.length = Math.min(SC.maxRange(r), content.get('length')) - r.start ;
|
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.
|
559
502
|
|
560
|
-
|
561
|
-
|
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,
|
562
511
|
|
563
512
|
/**
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
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}
|
568
519
|
*/
|
569
|
-
|
570
|
-
this.
|
571
|
-
|
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(),
|
572
524
|
|
573
|
-
/**
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
}.observes('nowShowingRange'),
|
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(),
|
587
538
|
|
588
|
-
//
|
589
|
-
//
|
590
|
-
//
|
539
|
+
// ..........................................................
|
540
|
+
// CONTENT CHANGES
|
541
|
+
//
|
591
542
|
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
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);
|
607
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.
|
608
569
|
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
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.
|
613
574
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
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
|
618
582
|
},
|
619
583
|
|
620
|
-
/**
|
621
|
-
|
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.
|
622
594
|
|
623
|
-
|
624
|
-
|
625
|
-
the view that is selected by the mouse event.
|
595
|
+
When you create a new range observer, the oberver must eventually call
|
596
|
+
contentRangeDidChange() for the collection view to function properly.
|
626
597
|
|
627
|
-
|
628
|
-
|
598
|
+
If you override this method you probably also need to override
|
599
|
+
destroyRangeObserver() to cleanup any existing range observer.
|
629
600
|
|
630
|
-
@
|
631
|
-
@returns {SC.View} the item view or null
|
601
|
+
@returns {void}
|
632
602
|
*/
|
633
|
-
|
634
|
-
var
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
// need to materialize an itemView under the mouse if possible
|
639
|
-
var baseGuid = SC.guidFor(this) ;
|
640
|
-
var baseGuidLen = baseGuid.length ;
|
641
|
-
var element = evt.target ;
|
642
|
-
var elementId = element.id.slice(0, baseGuidLen) ;
|
643
|
-
while (elementId !== baseGuid) {
|
644
|
-
element = element.parentNode ;
|
645
|
-
elementId = element.id.slice(0, baseGuidLen) ;
|
646
|
-
}
|
603
|
+
updateContentRangeObserver: function() {
|
604
|
+
var nowShowing = this.get('nowShowing'),
|
605
|
+
observer = this._cv_contentRangeObserver,
|
606
|
+
content = this.get('content');
|
647
607
|
|
648
|
-
if (
|
649
|
-
return null ; // we found ourself, so we're not over a child view
|
650
|
-
}
|
608
|
+
if (!content) return ; // nothing to do
|
651
609
|
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
var max = SC.maxRange(nowShowingRange) ;
|
659
|
-
var c = content.objectAt(idx) ;
|
660
|
-
while (SC.guidFor(c) !== contentGuid) {
|
661
|
-
c = content.objectAt(idx++) ;
|
662
|
-
if (idx == max) return null ; // couldn't find the content...
|
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 ;
|
663
616
|
}
|
664
617
|
|
665
|
-
// then create the view for that content
|
666
|
-
var itemView = this.createExampleView() ;
|
667
|
-
var selection = SC.makeArray(this.get('selection')) ;
|
668
|
-
itemView.set('content', c) ;
|
669
|
-
itemView.layerId = element.id ; // cannot use .set here, layerId is RO
|
670
|
-
SC.View.views[itemView.layerId] = itemView ; // register for event handling
|
671
|
-
itemView.set('isVisible', SC.valueInRange(idx, nowShowingRange)) ;
|
672
|
-
itemView.set('isSelected', (selection.indexOf(c) == -1) ? NO : YES) ;
|
673
|
-
|
674
|
-
// NOTE: *must* set the layout silently...
|
675
|
-
itemView.layout = this.itemViewLayoutAtContentIndex(idx) ;
|
676
|
-
itemView.set('parentView', this) ;
|
677
|
-
|
678
|
-
// prevent normal, non-materialized view behavior
|
679
|
-
// TODO: isMaterialized should do this automatically in SC.View
|
680
|
-
itemView.layerLocationNeedsUpdate = NO ;
|
681
|
-
itemView.childViewsNeedLayout = NO ;
|
682
|
-
itemView.layerNeedsUpdate = NO ;
|
683
|
-
|
684
|
-
// NOTE: still have to search for view, because itemView could contain
|
685
|
-
// nested views, and the mouseDown should go to them first...
|
686
|
-
var view = responder.targetViewForEvent(evt) ;
|
687
|
-
if (!view) return null ; // workaround for error on IE8, see Ticket #169
|
688
|
-
|
689
|
-
// work up the view hierarchy to find a match...
|
690
|
-
do {
|
691
|
-
// item clicked was the ContainerView itself... i.e. the user clicked
|
692
|
-
// outside the child items nothing to return...
|
693
|
-
if (view == this) return null ;
|
694
|
-
|
695
|
-
// sweet!... the view is not only in the collection, but it says we can
|
696
|
-
// hit it. hit it and quit it...
|
697
|
-
if (!view.hitTest || view.hitTest(evt)) return view ;
|
698
|
-
} while (view = view.get('parentView')) ;
|
699
|
-
|
700
|
-
// nothing was found...
|
701
|
-
return null ;
|
702
618
|
},
|
703
619
|
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
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.
|
709
628
|
|
710
|
-
|
711
|
-
return ExampleView.create({
|
712
|
-
classNames: ['sc-collection-item'],
|
713
|
-
owner: this,
|
714
|
-
displayDelegate: this,
|
715
|
-
parentView: this,
|
716
|
-
isVisible: YES,
|
717
|
-
isMaterialized: YES
|
718
|
-
});
|
719
|
-
} else throw "You must define an exampleView class to render collection items with" ;
|
720
|
-
},
|
721
|
-
|
722
|
-
// ......................................
|
723
|
-
// SELECTION
|
724
|
-
//
|
725
|
-
|
726
|
-
/** @private
|
727
|
-
Finds the smallest index of a content object in the selected array.
|
629
|
+
@returns {void}
|
728
630
|
*/
|
729
|
-
|
730
|
-
var content
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
var indexOfSelected = contentLength ; var idx = sel.length ;
|
737
|
-
while(--idx >= 0) {
|
738
|
-
var curIndex = content.indexOf(sel[idx]) ;
|
739
|
-
if ((curIndex >= 0) && (curIndex < indexOfSelected)) indexOfSelected = curIndex ;
|
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 ;
|
740
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.
|
741
645
|
|
742
|
-
|
646
|
+
@returns {void}
|
647
|
+
*/
|
648
|
+
contentLengthDidChange: function() {
|
649
|
+
var content = this.get('content');
|
650
|
+
this.set('length', content ? content.get('length') : 0);
|
743
651
|
},
|
744
652
|
|
745
653
|
/** @private
|
746
|
-
|
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
|
747
667
|
*/
|
748
|
-
|
749
|
-
var content = this.get('content')
|
750
|
-
|
751
|
-
|
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
|
+
}
|
752
679
|
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
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);
|
757
686
|
}
|
758
687
|
|
759
|
-
|
760
|
-
|
688
|
+
// notify all items changed
|
689
|
+
this.contentLengthDidChange();
|
690
|
+
this.contentRangeDidChange(content, null, '[]', null);
|
691
|
+
|
692
|
+
}.observes('content'),
|
761
693
|
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
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.
|
766
709
|
|
767
|
-
|
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.
|
768
713
|
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
@
|
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
|
774
720
|
*/
|
775
|
-
|
776
|
-
|
777
|
-
if (
|
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
|
778
728
|
|
779
|
-
|
780
|
-
var contentLength = content.get('length') ;
|
729
|
+
if (this.get('isVisibleInWindow')) this.invokeOnce(this.reloadIfNeeded);
|
781
730
|
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
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
|
+
}
|
789
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
|
+
|
790
1428
|
// If the selBottom is after the anchor, then reduce the selection
|
791
1429
|
if (selBottom > anchor) {
|
792
1430
|
selBottom = selBottom - numberOfItems ;
|
@@ -797,30 +1435,27 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
797
1435
|
}
|
798
1436
|
|
799
1437
|
// Ensure we are not out of bounds
|
800
|
-
if (selTop < 0) selTop = 0 ;
|
1438
|
+
if (SC.none(selTop) || (selTop < 0)) selTop = 0 ;
|
801
1439
|
if (selBottom < selTop) selBottom = selTop ;
|
802
1440
|
|
803
1441
|
// if not extending, just select the item previous to the selTop
|
804
1442
|
} else {
|
805
|
-
selTop = this._findPreviousSelectableItemFromIndex(
|
806
|
-
if (selTop < 0) selTop = 0 ;
|
1443
|
+
selTop = this._findPreviousSelectableItemFromIndex(selTop - numberOfItems);
|
1444
|
+
if (SC.none(selTop) || (selTop < 0)) selTop = 0 ;
|
807
1445
|
selBottom = selTop ;
|
808
1446
|
anchor = null ;
|
809
1447
|
}
|
810
1448
|
|
811
|
-
|
812
|
-
var items = [] ;
|
813
|
-
while(selTop <= selBottom) {
|
814
|
-
items[items.length] = content.objectAt(selTop++) ;
|
815
|
-
}
|
1449
|
+
var scrollToIndex = selTop ;
|
816
1450
|
|
817
|
-
//
|
818
|
-
|
819
|
-
this.scrollToContent(items[0]);
|
820
|
-
this.selectItems(items);
|
821
|
-
}
|
1451
|
+
// now build new selection
|
1452
|
+
sel = SC.IndexSet.create(selTop, selBottom+1-selTop);
|
822
1453
|
|
1454
|
+
// ensure that the item is visible and set the selection
|
1455
|
+
this.scrollToContentIndex(scrollToIndex) ;
|
1456
|
+
this.select(sel) ;
|
823
1457
|
this._selectionAnchor = anchor ;
|
1458
|
+
return this ;
|
824
1459
|
},
|
825
1460
|
|
826
1461
|
/**
|
@@ -833,215 +1468,144 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
833
1468
|
instead of replaced. Defaults to false.
|
834
1469
|
@param numberOfItems {Integer} (Optional) The number of items to be
|
835
1470
|
selected. Defaults to 1.
|
836
|
-
@returns {
|
1471
|
+
@returns {SC.CollectionView} receiver
|
837
1472
|
*/
|
838
1473
|
selectNextItem: function(extend, numberOfItems) {
|
839
1474
|
if (SC.none(numberOfItems)) numberOfItems = 1 ;
|
840
1475
|
if (SC.none(extend)) extend = false ;
|
841
|
-
|
842
|
-
var
|
843
|
-
|
844
|
-
|
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
|
+
|
845
1488
|
// if extending, then we need to do some fun stuff to build the array
|
846
|
-
var selTop, selBottom, anchor ;
|
847
1489
|
if (extend) {
|
848
|
-
selTop = this._indexOfSelectionTop() ;
|
849
|
-
selBottom = this._indexOfSelectionBottom() ;
|
850
|
-
anchor = SC.none(this._selectionAnchor) ? selTop : this._selectionAnchor ;
|
851
|
-
this._selectionAnchor = anchor ;
|
852
1490
|
|
853
1491
|
// If the selTop is before the anchor, then reduce the selection
|
854
1492
|
if (selTop < anchor) {
|
855
1493
|
selTop = selTop + numberOfItems ;
|
856
1494
|
|
857
|
-
// otherwise, select the next item after the
|
1495
|
+
// otherwise, select the next item after the bottom
|
858
1496
|
} else {
|
859
|
-
selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems);
|
1497
|
+
selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems, selBottom);
|
860
1498
|
}
|
861
1499
|
|
862
1500
|
// Ensure we are not out of bounds
|
863
|
-
if (selBottom >=
|
1501
|
+
if (selBottom >= lim) selBottom = lim-1;
|
864
1502
|
if (selTop > selBottom) selTop = selBottom ;
|
865
1503
|
|
866
1504
|
// if not extending, just select the item next to the selBottom
|
867
1505
|
} else {
|
868
|
-
selBottom = this._findNextSelectableItemFromIndex(
|
1506
|
+
selBottom = this._findNextSelectableItemFromIndex(selBottom + numberOfItems, selBottom);
|
869
1507
|
|
870
|
-
if (selBottom >=
|
1508
|
+
if (selBottom >= lim) selBottom = lim-1;
|
871
1509
|
selTop = selBottom ;
|
872
1510
|
anchor = null ;
|
873
1511
|
}
|
874
1512
|
|
875
|
-
|
876
|
-
var items = [] ;
|
877
|
-
while(selTop <= selBottom) {
|
878
|
-
items[items.length] = content.objectAt(selTop++) ;
|
879
|
-
}
|
880
|
-
|
881
|
-
// ensure that the item is visible and set the selection
|
882
|
-
if (items.length > 0) {
|
883
|
-
this.scrollToContent(items[0]);
|
884
|
-
this.selectItems(items);
|
885
|
-
}
|
1513
|
+
var scrollToIndex = selBottom ;
|
886
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) ;
|
887
1521
|
this._selectionAnchor = anchor ;
|
1522
|
+
return this ;
|
888
1523
|
},
|
889
|
-
|
890
|
-
/**
|
891
|
-
Scroll the rootElement (if needed) to ensure that the item is visible.
|
892
|
-
@param {SC.Record} record The record to scroll to
|
893
|
-
@returns {void}
|
894
|
-
*/
|
895
|
-
scrollToContent: function(record) {
|
896
|
-
var content, itemView, contentIndex, groupBy;
|
897
1524
|
|
898
|
-
// find the itemView. if not present, add one.
|
899
|
-
content = SC.makeArray(this.get('content'));
|
900
|
-
if (content.indexOf(record) < 0) return ; // do nothing if not in content.
|
901
|
-
|
902
|
-
itemView = this.itemViewForContent(record) ;
|
903
|
-
if (!itemView) {
|
904
|
-
content = SC.makeArray(this.get('content')) ;
|
905
|
-
contentIndex = content.indexOf(record) ;
|
906
|
-
groupBy = this.get('groupBy');
|
907
|
-
itemView = this._insertItemViewFor(record, groupBy, contentIndex);
|
908
|
-
}
|
909
|
-
if (itemView) this.scrollToItemView(itemView);
|
910
|
-
},
|
911
|
-
|
912
1525
|
/**
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
*/
|
917
|
-
scrollToItemView: function(view) {
|
918
|
-
// find first scrollable view.
|
919
|
-
var scrollable = this ;
|
920
|
-
while(scrollable && (scrollable != SC.window) && (!scrollable.get('isScrollable'))) {
|
921
|
-
scrollable = scrollable.get('parentNode') ;
|
922
|
-
}
|
923
|
-
if (!scrollable || (scrollable == SC.window)) return ; // no scrollable!
|
924
|
-
scrollable.scrollToVisible(view) ;
|
925
|
-
},
|
926
|
-
|
927
|
-
/**
|
928
|
-
Selects the passed array of items, optionally extending the
|
929
|
-
current selection.
|
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.
|
930
1529
|
|
931
|
-
@
|
932
|
-
@param extendSelection {Boolean} If true, extends the selection instead of
|
933
|
-
replacing it.
|
1530
|
+
@returns {Boolean} YES if deletion is possible.
|
934
1531
|
*/
|
935
|
-
|
936
|
-
var base = (extendSelection) ? this.get('selection') : [] ;
|
937
|
-
var sel = [] ;
|
938
|
-
|
939
|
-
items = SC.makeArray(items) ;
|
940
|
-
for (var i = 0, len = items.length; i < len; i++) {
|
941
|
-
if (this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, items[i])) {
|
942
|
-
sel.push(items[i]);
|
943
|
-
}
|
944
|
-
}
|
1532
|
+
deleteSelection: function() {
|
945
1533
|
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
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 ;
|
950
1543
|
|
951
|
-
//
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
/**
|
957
|
-
Removes the items from the selection.
|
958
|
-
*/
|
959
|
-
deselectItems: function(items) {
|
960
|
-
var base = SC.makeArray(this.get('selection')) ;
|
961
|
-
var sel = [] ;
|
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 ;
|
962
1548
|
|
963
|
-
|
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);
|
964
1553
|
|
965
|
-
|
966
|
-
set
|
967
|
-
|
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());
|
968
1559
|
|
969
|
-
|
1560
|
+
return YES ;
|
970
1561
|
},
|
971
1562
|
|
1563
|
+
// ..........................................................
|
1564
|
+
// SCROLLING
|
1565
|
+
//
|
1566
|
+
|
972
1567
|
/**
|
973
|
-
|
974
|
-
|
975
|
-
This will invoke delegate methods to provide fine-grained control.
|
1568
|
+
Scroll the rootElement (if needed) to ensure that the item is visible.
|
976
1569
|
|
977
|
-
@
|
1570
|
+
@param {Number} contentIndex The index of the item to scroll to
|
1571
|
+
@returns {SC.CollectionView} receiver
|
978
1572
|
*/
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
var sel = SC.makeArray(this.get('selection'));
|
984
|
-
if (!sel || sel.get('length') === 0) return NO ;
|
985
|
-
|
986
|
-
// let the delegate decide what to actually delete. If this returns an
|
987
|
-
// empty array or null, just do nothing.
|
988
|
-
sel = this.invokeDelegateMethod(this.delegate, 'collectionViewShouldDeleteContent', this, sel) ;
|
989
|
-
sel = SC.makeArray(sel) ; // ensure this is an array
|
990
|
-
if (!sel || sel.get('length') === 0) return YES ;
|
991
|
-
|
992
|
-
// now have the delegate (or us) perform the deletion. The collection
|
993
|
-
// view implements a default version of this method.
|
994
|
-
this.invokeDelegateMethod(this.delegate, 'collectionViewDeleteContent', this, sel) ;
|
995
|
-
return YES ;
|
1573
|
+
scrollToContentIndex: function(contentIndex) {
|
1574
|
+
var itemView = this.itemViewForContentIndex(contentIndex) ;
|
1575
|
+
if (itemView) this.scrollToItemView(itemView) ;
|
1576
|
+
return this;
|
996
1577
|
},
|
997
|
-
|
1578
|
+
|
998
1579
|
/**
|
999
|
-
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
// get the content. Bail if this cannot be used as an array.
|
1012
|
-
var content = this.get('content') ;
|
1013
|
-
if (!content) return NO; // nothing to do
|
1014
|
-
|
1015
|
-
// determine the method to use
|
1016
|
-
var hasDestroyObject = SC.$type(content.destroyObject) === SC.T_FUNCTION ;
|
1017
|
-
var hasRemoveObject = SC.$type(content.removeObject) === SC.T_FUNCTION ;
|
1018
|
-
if (!hasDestroyObject && !hasRemoveObject) return NO; // nothing to do
|
1019
|
-
|
1020
|
-
// suspend property notifications and remove the objects...
|
1021
|
-
if (content.beginPropertyChanges) content.beginPropertyChanges();
|
1022
|
-
var idx = sel.get('length') ;
|
1023
|
-
while(--idx >= 0) {
|
1024
|
-
var item = sel.objectAt(idx) ;
|
1025
|
-
if (hasDestroyObject) {
|
1026
|
-
content.destroyObject(item);
|
1027
|
-
} else {
|
1028
|
-
content.removeObject(item);
|
1029
|
-
}
|
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
|
1030
1591
|
}
|
1031
|
-
// begin notifying again...
|
1032
|
-
if (content.endPropertyChanges) content.endPropertyChanges() ;
|
1033
1592
|
|
1034
|
-
|
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 ;
|
1035
1599
|
},
|
1036
|
-
|
1037
|
-
//
|
1038
|
-
//
|
1039
|
-
//
|
1600
|
+
|
1601
|
+
// ..........................................................
|
1602
|
+
// KEYBOARD EVENTS
|
1603
|
+
//
|
1040
1604
|
|
1041
1605
|
/** @private */
|
1042
1606
|
keyDown: function(evt) {
|
1043
|
-
|
1044
|
-
return
|
1607
|
+
var ret = this.interpretKeyEvents(evt) ;
|
1608
|
+
return !ret ? NO : ret ;
|
1045
1609
|
},
|
1046
1610
|
|
1047
1611
|
/** @private */
|
@@ -1051,8 +1615,9 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1051
1615
|
Handle select all keyboard event.
|
1052
1616
|
*/
|
1053
1617
|
selectAll: function(evt) {
|
1054
|
-
var content =
|
1055
|
-
|
1618
|
+
var content = this.get('content'),
|
1619
|
+
sel = content ? SC.IndexSet.create(0, content.get('length')) : null;
|
1620
|
+
this.select(sel, NO) ;
|
1056
1621
|
return YES ;
|
1057
1622
|
},
|
1058
1623
|
|
@@ -1060,7 +1625,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1060
1625
|
Handle delete keyboard event.
|
1061
1626
|
*/
|
1062
1627
|
deleteBackward: function(evt) {
|
1063
|
-
// console.log('deleteBackward called on %@ with evt %@'.fmt(this, evt));
|
1064
1628
|
return this.deleteSelection() ;
|
1065
1629
|
},
|
1066
1630
|
|
@@ -1068,7 +1632,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1068
1632
|
Handle delete keyboard event.
|
1069
1633
|
*/
|
1070
1634
|
deleteForward: function(evt) {
|
1071
|
-
// console.log('deleteForward called on %@ with evt %@'.fmt(this, evt));
|
1072
1635
|
return this.deleteSelection() ;
|
1073
1636
|
},
|
1074
1637
|
|
@@ -1077,6 +1640,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1077
1640
|
*/
|
1078
1641
|
moveDown: function(sender, evt) {
|
1079
1642
|
this.selectNextItem(false, this.get('itemsPerRow') || 1) ;
|
1643
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1080
1644
|
return true ;
|
1081
1645
|
},
|
1082
1646
|
|
@@ -1085,14 +1649,72 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1085
1649
|
*/
|
1086
1650
|
moveUp: function(sender, evt) {
|
1087
1651
|
this.selectPreviousItem(false, this.get('itemsPerRow') || 1) ;
|
1652
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1088
1653
|
return true ;
|
1089
1654
|
},
|
1090
1655
|
|
1091
1656
|
/** @private
|
1092
1657
|
Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
|
1658
|
+
If item is expandable, will collapse.
|
1093
1659
|
*/
|
1094
1660
|
moveLeft: function(sender, evt) {
|
1095
|
-
if ((this.get('itemsPerRow') || 1) > 1)
|
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
|
+
|
1096
1718
|
return true ;
|
1097
1719
|
},
|
1098
1720
|
|
@@ -1100,19 +1722,30 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1100
1722
|
Selects the next item if itemsPerRow > 1. Otherwise does nothing.
|
1101
1723
|
*/
|
1102
1724
|
moveRight: function(sender, evt) {
|
1103
|
-
if ((this.get('itemsPerRow') || 1) > 1)
|
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
|
+
|
1104
1735
|
return true ;
|
1105
1736
|
},
|
1106
1737
|
|
1107
1738
|
/** @private */
|
1108
1739
|
moveDownAndModifySelection: function(sender, evt) {
|
1109
1740
|
this.selectNextItem(true, this.get('itemsPerRow') || 1) ;
|
1741
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1110
1742
|
return true ;
|
1111
1743
|
},
|
1112
1744
|
|
1113
1745
|
/** @private */
|
1114
1746
|
moveUpAndModifySelection: function(sender, evt) {
|
1115
1747
|
this.selectPreviousItem(true, this.get('itemsPerRow') || 1) ;
|
1748
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1116
1749
|
return true ;
|
1117
1750
|
},
|
1118
1751
|
|
@@ -1120,7 +1753,10 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1120
1753
|
Selects the previous item if itemsPerRow > 1. Otherwise does nothing.
|
1121
1754
|
*/
|
1122
1755
|
moveLeftAndModifySelection: function(sender, evt) {
|
1123
|
-
if ((this.get('itemsPerRow') || 1) > 1)
|
1756
|
+
if ((this.get('itemsPerRow') || 1) > 1) {
|
1757
|
+
this.selectPreviousItem(true, 1) ;
|
1758
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1759
|
+
}
|
1124
1760
|
return true ;
|
1125
1761
|
},
|
1126
1762
|
|
@@ -1128,10 +1764,58 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1128
1764
|
Selects the next item if itemsPerRow > 1. Otherwise does nothing.
|
1129
1765
|
*/
|
1130
1766
|
moveRightAndModifySelection: function(sender, evt) {
|
1131
|
-
if ((this.get('itemsPerRow') || 1) > 1)
|
1767
|
+
if ((this.get('itemsPerRow') || 1) > 1) {
|
1768
|
+
this.selectNextItem(true, 1) ;
|
1769
|
+
this._cv_performSelectAction(null, evt, this.ACTION_DELAY);
|
1770
|
+
}
|
1132
1771
|
return true ;
|
1133
1772
|
},
|
1134
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
|
+
|
1135
1819
|
/** @private
|
1136
1820
|
Handles mouse down events on the collection view or on any of its
|
1137
1821
|
children.
|
@@ -1144,324 +1828,231 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1144
1828
|
@returns {Boolean} Usually YES.
|
1145
1829
|
*/
|
1146
1830
|
mouseDown: function(ev) {
|
1147
|
-
// console.log('%@.mouseDown(%@)'.fmt(this, ev));
|
1148
|
-
// console.log(ev.originalEvent);
|
1149
1831
|
|
1150
1832
|
// When the user presses the mouse down, we don't do much just yet.
|
1151
1833
|
// Instead, we just need to save a bunch of state about the mouse down
|
1152
1834
|
// so we can choose the right thing to do later.
|
1153
1835
|
|
1154
|
-
// save the original mouse down event for use in dragging.
|
1155
|
-
this._mouseDownEvent = ev ;
|
1156
|
-
|
1157
1836
|
// Toggle selection only triggers on mouse up. Do nothing.
|
1158
|
-
if (this.useToggleSelection) return true;
|
1837
|
+
if (this.get('useToggleSelection')) return true;
|
1159
1838
|
|
1160
|
-
// Make sure that saved mouseDown state is always reset in case we do
|
1161
|
-
// not get a paired mouseUp. (Only happens if subclass does not call us
|
1162
|
-
// like it should)
|
1163
|
-
this._mouseDownAt = this._shouldSelect = this._shouldDeselect =
|
1164
|
-
this._shouldReselect = this._refreshSelection = false;
|
1165
|
-
|
1166
|
-
// debugger ;
|
1167
1839
|
// find the actual view the mouse was pressed down on. This will call
|
1168
1840
|
// hitTest() on item views so they can implement non-square detection
|
1169
1841
|
// modes. -- once we have an item view, get its content object as well.
|
1170
|
-
var
|
1171
|
-
|
1172
|
-
|
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
|
+
};
|
1173
1853
|
|
1174
1854
|
// become first responder if possible.
|
1175
1855
|
this.becomeFirstResponder() ;
|
1176
1856
|
|
1177
|
-
// console.log(mouseDownView);
|
1178
|
-
|
1179
1857
|
// recieved a mouseDown on the collection element, but not on one of the
|
1180
1858
|
// childItems... unless we do not allow empty selections, set it to empty.
|
1181
|
-
if (!
|
1182
|
-
if (this.get('allowDeselectAll')) this.
|
1183
|
-
return
|
1859
|
+
if (!itemView) {
|
1860
|
+
if (this.get('allowDeselectAll')) this.select(null, false);
|
1861
|
+
return YES ;
|
1184
1862
|
}
|
1185
1863
|
|
1186
1864
|
// collection some basic setup info
|
1187
|
-
var
|
1188
|
-
|
1189
|
-
var modifierKeyPressed = ev.ctrlKey || ev.metaKey ;
|
1190
|
-
if (mouseDownView.checkboxView && (SC.Event.element(ev) == ev.checkboxView.rootElement)) {
|
1191
|
-
modifierKeyPressed = true ;
|
1192
|
-
}
|
1193
|
-
this._modifierKeyPressed = modifierKeyPressed ;
|
1865
|
+
var sel = this.get('selection'), isSelected, modifierKeyPressed;
|
1866
|
+
if (sel) sel = sel.indexSetForSource(content);
|
1194
1867
|
|
1195
|
-
|
1868
|
+
isSelected = sel ? sel.contains(contentIndex) : NO;
|
1869
|
+
info.modifierKeyPressed = modifierKeyPressed = ev.ctrlKey || ev.metaKey ;
|
1196
1870
|
|
1197
1871
|
// holding down a modifier key while clicking a selected item should
|
1198
1872
|
// deselect that item...deselect and bail.
|
1199
1873
|
if (modifierKeyPressed && isSelected) {
|
1200
|
-
|
1874
|
+
info.shouldDeselect = contentIndex >= 0;
|
1875
|
+
|
1201
1876
|
// if the shiftKey was pressed, then we want to extend the selection
|
1202
1877
|
// from the last selected item
|
1203
|
-
} else if (ev.shiftKey &&
|
1204
|
-
|
1205
|
-
this.
|
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
|
1206
1883
|
|
1207
1884
|
// If no modifier key was pressed, then clicking on the selected item
|
1208
1885
|
// should clear the selection and reselect only the clicked on item.
|
1209
1886
|
} else if (!modifierKeyPressed && isSelected) {
|
1210
|
-
|
1887
|
+
info.shouldReselect = contentIndex >= 0;
|
1211
1888
|
|
1212
1889
|
// Otherwise, if selecting on mouse down, simply select the clicked on
|
1213
1890
|
// item, adding it to the current selection if a modifier key was pressed.
|
1214
1891
|
} else {
|
1215
|
-
if (this.get("selectOnMouseDown")){
|
1216
|
-
|
1217
|
-
} else
|
1892
|
+
if (this.get("selectOnMouseDown")) {
|
1893
|
+
this.select(contentIndex, modifierKeyPressed);
|
1894
|
+
} else {
|
1895
|
+
info.shouldSelect = contentIndex >= 0 ;
|
1896
|
+
}
|
1218
1897
|
}
|
1219
1898
|
|
1220
1899
|
// saved for extend by shift ops.
|
1221
|
-
|
1900
|
+
info.previousContentIndex = contentIndex;
|
1222
1901
|
|
1223
|
-
return
|
1902
|
+
return YES;
|
1224
1903
|
},
|
1225
1904
|
|
1226
1905
|
/** @private */
|
1227
1906
|
mouseUp: function(ev) {
|
1228
1907
|
|
1229
|
-
var
|
1230
|
-
|
1231
|
-
|
1908
|
+
var view = this.itemViewForEvent(ev),
|
1909
|
+
info = this.mouseDownInfo,
|
1910
|
+
idx = info.contentIndex,
|
1911
|
+
contentIndex, sel, isSelected, canEdit, itemView, content;
|
1232
1912
|
|
1233
|
-
if (this.useToggleSelection) {
|
1913
|
+
if (this.get('useToggleSelection')) {
|
1234
1914
|
if (!view) return ; // do nothing when clicked outside of elements
|
1235
1915
|
|
1236
1916
|
// determine if item is selected. If so, then go on.
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
1242
|
-
|
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) ;
|
1243
1923
|
|
1244
1924
|
} else {
|
1245
|
-
|
1925
|
+
contentIndex = (view) ? view.get('contentIndex') : -1 ;
|
1246
1926
|
|
1247
1927
|
// this will be set if the user simply clicked on an unselected item and
|
1248
1928
|
// selectOnMouseDown was NO.
|
1249
|
-
if (
|
1929
|
+
if (info.shouldSelect) this.select(idx, info.modifierKeyPressed);
|
1250
1930
|
|
1251
1931
|
// This is true if the user clicked on a selected item with a modifier
|
1252
1932
|
// key pressed.
|
1253
|
-
if (
|
1933
|
+
if (info.shouldDeselect) this.deselect(idx);
|
1254
1934
|
|
1255
1935
|
// This is true if the user clicked on a selected item without a
|
1256
1936
|
// modifier-key pressed. When this happens we try to begin editing
|
1257
1937
|
// on the content. If that is not allowed, then simply clear the
|
1258
1938
|
// selection and reselect the clicked on item.
|
1259
|
-
if (
|
1939
|
+
if (info.shouldReselect) {
|
1260
1940
|
|
1941
|
+
//debugger ;
|
1261
1942
|
// - contentValueIsEditable is true
|
1262
|
-
|
1943
|
+
canEdit = this.get('isEditable') && this.get('canEditContent') ;
|
1263
1944
|
|
1264
1945
|
// - the user clicked on an item that was already selected
|
1946
|
+
// ^ this is the only way shouldReset is set to YES
|
1947
|
+
|
1265
1948
|
// - is the only item selected
|
1266
1949
|
if (canEdit) {
|
1267
|
-
|
1268
|
-
canEdit = sel && (sel.get('length') === 1)
|
1950
|
+
sel = this.get('selection') ;
|
1951
|
+
canEdit = sel && (sel.get('length') === 1);
|
1269
1952
|
}
|
1270
1953
|
|
1271
1954
|
// - the item view responds to contentHitTest() and returns YES.
|
1272
1955
|
// - the item view responds to beginEditing and returns YES.
|
1273
1956
|
if (canEdit) {
|
1274
|
-
|
1957
|
+
itemView = this.itemViewForContentIndex(idx) ;
|
1275
1958
|
canEdit = itemView && (!itemView.contentHitTest || itemView.contentHitTest(ev)) ;
|
1276
1959
|
canEdit = (canEdit && itemView.beginEditing) ? itemView.beginEditing() : NO ;
|
1277
1960
|
}
|
1278
1961
|
|
1279
1962
|
// if cannot edit, just reselect
|
1280
|
-
if (!canEdit) this.
|
1963
|
+
if (!canEdit) this.select(idx, false) ;
|
1281
1964
|
}
|
1282
1965
|
|
1283
1966
|
this._cleanupMouseDown() ;
|
1284
1967
|
}
|
1968
|
+
|
1969
|
+
// handle actions on editing
|
1970
|
+
this._cv_performSelectAction(view, ev, 0, ev.clickCount);
|
1285
1971
|
|
1286
|
-
|
1287
|
-
if (canAct) this._action(ev, view) ;
|
1288
|
-
|
1289
|
-
return false; // bubble event to allow didDoubleClick to be called...
|
1972
|
+
return NO; // bubble event to allow didDoubleClick to be called...
|
1290
1973
|
},
|
1291
1974
|
|
1292
1975
|
/** @private */
|
1293
1976
|
_cleanupMouseDown: function() {
|
1294
|
-
|
1295
|
-
|
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;
|
1296
1987
|
},
|
1297
1988
|
|
1298
1989
|
/** @private */
|
1299
1990
|
mouseMoved: function(ev) {
|
1300
|
-
var view = this.itemViewForEvent(ev)
|
1991
|
+
var view = this.itemViewForEvent(ev),
|
1992
|
+
last = this._lastHoveredItem ;
|
1993
|
+
|
1301
1994
|
// handle hover events.
|
1302
|
-
if
|
1303
|
-
|
1995
|
+
if (view !== last) {
|
1996
|
+
if (last && last.mouseOut) last.mouseOut(ev);
|
1997
|
+
if (view && view.mouseOver) view.mouseOver(ev);
|
1304
1998
|
}
|
1305
1999
|
this._lastHoveredItem = view ;
|
1306
|
-
|
2000
|
+
|
2001
|
+
if (view && view.mouseMoved) view.mouseMoved(ev);
|
2002
|
+
return YES;
|
1307
2003
|
},
|
1308
2004
|
|
1309
2005
|
/** @private */
|
1310
2006
|
mouseOut: function(ev) {
|
1311
|
-
|
1312
2007
|
var view = this._lastHoveredItem ;
|
1313
2008
|
this._lastHoveredItem = null ;
|
1314
|
-
if (view && view.
|
1315
|
-
|
1316
|
-
|
1317
|
-
/** @private */
|
1318
|
-
doubleClick: function(ev) {
|
1319
|
-
var view = this.itemViewForEvent(ev) ;
|
1320
|
-
if (view) {
|
1321
|
-
this._action(view, ev) ;
|
1322
|
-
return true ;
|
1323
|
-
} else return false ;
|
2009
|
+
if (view && view.mouseOut) view.mouseOut(ev) ;
|
2010
|
+
return YES ;
|
1324
2011
|
},
|
1325
2012
|
|
1326
2013
|
/** @private */
|
1327
|
-
_findSelectionExtendedByShift: function(
|
1328
|
-
var content = this.get('content');
|
2014
|
+
_findSelectionExtendedByShift: function(sel, contentIndex) {
|
1329
2015
|
|
1330
|
-
//
|
1331
|
-
|
1332
|
-
|
1333
|
-
|
1334
|
-
var selectionBeginIndex = content.indexOf(selection[0]) ;
|
1335
|
-
var selectionEndIndex = content.indexOf(selection[selection.length-1]) ;
|
1336
|
-
|
1337
|
-
var previousMouseDownIndex = content.indexOf(this._previousMouseDownContent);
|
1338
|
-
// _previousMouseDownContent couldn't be found... either it hasn't been set yet or the record has been deleted by the user
|
1339
|
-
// fall back to the first selected item.
|
1340
|
-
if (previousMouseDownIndex == -1) previousMouseDownIndex = selectionBeginIndex;
|
1341
|
-
|
1342
|
-
var currentMouseDownIndex = content.indexOf(mouseDownContent);
|
1343
|
-
// sanity check...
|
1344
|
-
if (currentMouseDownIndex == -1) throw "Unable to extend selection to an item that's not in the content array!";
|
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
|
+
}
|
1345
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
|
+
|
1346
2030
|
// clicked before the current selection set... extend it's beginning...
|
1347
|
-
if (
|
1348
|
-
|
1349
|
-
|
2031
|
+
if (contentIndex < min) {
|
2032
|
+
min = contentIndex;
|
2033
|
+
if (anchor<0) this._selectionAnchor = anchor = max; //anchor at end
|
1350
2034
|
|
1351
2035
|
// clicked after the current selection set... extend it's ending...
|
1352
|
-
if (
|
1353
|
-
|
1354
|
-
|
2036
|
+
} else if (contentIndex > max) {
|
2037
|
+
max = contentIndex;
|
2038
|
+
if (anchor<0) this._selectionAnchor = anchor = min; // anchor at start
|
1355
2039
|
|
1356
2040
|
// clicked inside the selection set... need to determine where the last
|
1357
2041
|
// selection was and use that as an anchor.
|
1358
|
-
if (
|
1359
|
-
if (
|
1360
|
-
selectionBeginIndex = currentMouseDownIndex;
|
1361
|
-
selectionEndIndex = currentMouseDownIndex;
|
1362
|
-
} else if (currentMouseDownIndex > previousMouseDownIndex) {
|
1363
|
-
selectionBeginIndex = previousMouseDownIndex;
|
1364
|
-
selectionEndIndex = currentMouseDownIndex;
|
1365
|
-
} else if (currentMouseDownIndex < previousMouseDownIndex){
|
1366
|
-
selectionBeginIndex = currentMouseDownIndex;
|
1367
|
-
selectionEndIndex = previousMouseDownIndex;
|
1368
|
-
}
|
1369
|
-
}
|
1370
|
-
|
1371
|
-
// slice doesn't include the last index passed... silly..
|
1372
|
-
selectionEndIndex++;
|
1373
|
-
|
1374
|
-
// shouldn't need to sanity check that the selection is in bounds due to
|
1375
|
-
// the indexOf checks above...I'll have faith that indexOf hasn't lied to
|
1376
|
-
// me...
|
1377
|
-
return content.slice(selectionBeginIndex, selectionEndIndex);
|
1378
|
-
},
|
1379
|
-
|
1380
|
-
/** @private
|
1381
|
-
Finds the next selectable item, up to content length, by asking the
|
1382
|
-
delegate. If a non-selectable item is found, the index is skipped. If
|
1383
|
-
no item is found, selection index is returned unmodified.
|
1384
|
-
|
1385
|
-
@param {Integer} proposedIndex the desired index to select
|
1386
|
-
@returns {Integer} the next selectable index. This will always be in the range of the bottom of the current selection index and the proposed index.
|
1387
|
-
@private
|
1388
|
-
*/
|
1389
|
-
_findNextSelectableItemFromIndex: function(proposedIndex) {
|
1390
|
-
var content = this.get('content');
|
1391
|
-
var contentLength = content.get('length');
|
1392
|
-
var bottom = this._indexOfSelectionTop();
|
1393
|
-
|
1394
|
-
while (proposedIndex < contentLength &&
|
1395
|
-
this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, content.objectAt(proposedIndex)) === NO) {
|
1396
|
-
proposedIndex++;
|
1397
|
-
}
|
1398
|
-
return (proposedIndex < contentLength) ? proposedIndex : bottom;
|
1399
|
-
},
|
1400
|
-
|
1401
|
-
/** @private
|
1402
|
-
Finds the previous selectable item, up to the first item, by asking the
|
1403
|
-
delegate. If a non-selectable item is found, the index is skipped. If
|
1404
|
-
no item is found, selection index is returned unmodified.
|
1405
|
-
|
1406
|
-
@param {Integer} proposedIndex the desired index to select
|
1407
|
-
@returns {Integer} the previous selectable index. This will always be in the range of the top of the current selection index and the proposed index.
|
1408
|
-
@private
|
1409
|
-
*/
|
1410
|
-
_findPreviousSelectableItemFromIndex: function(proposedIndex) {
|
1411
|
-
var content = this.get('content');
|
1412
|
-
var contentLength = content.get('length');
|
1413
|
-
var top = this._indexOfSelectionTop();
|
1414
|
-
|
1415
|
-
while (proposedIndex >= 0 &&
|
1416
|
-
this.invokeDelegateMethod(this.delegate, 'collectionViewShouldSelectItem', this, content.objectAt(proposedIndex)) === NO) {
|
1417
|
-
proposedIndex--;
|
1418
|
-
}
|
1419
|
-
return (proposedIndex >= 0) ? proposedIndex : top ;
|
1420
|
-
},
|
1421
|
-
|
1422
|
-
/** @private
|
1423
|
-
if content value is editable and we have one item selected, then edit.
|
1424
|
-
otherwise, invoke action.
|
1425
|
-
*/
|
1426
|
-
insertNewline: function() {
|
1427
|
-
var sel, itemView;
|
1428
|
-
if (this.get('contentValueIsEditable')) {
|
1429
|
-
sel = this.get('selection') ;
|
1430
|
-
if (sel && sel.get('length') === 1) {
|
1431
|
-
itemView = this.itemViewForContent(sel.objectAt(0)) ;
|
1432
|
-
if (itemView && itemView.beginEditing) {
|
1433
|
-
this.scrollToItemView(itemView) ;
|
1434
|
-
itemView.beginEditing() ;
|
1435
|
-
}
|
1436
|
-
}
|
2042
|
+
} else if (contentIndex >= min && contentIndex <= max) {
|
2043
|
+
if (anchor<0) this._selectionAnchor = anchor = min; //anchor at start
|
1437
2044
|
|
1438
|
-
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
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
|
+
}
|
1443
2053
|
}
|
1444
|
-
|
1445
|
-
return
|
1446
|
-
},
|
1447
|
-
|
1448
|
-
// ......................................
|
1449
|
-
// FIRST RESPONDER
|
1450
|
-
//
|
1451
|
-
|
1452
|
-
/** @private
|
1453
|
-
Called whenever the collection becomes first responder.
|
1454
|
-
Adds the focused class to the element.
|
1455
|
-
*/
|
1456
|
-
didBecomeFirstResponder: function() {
|
1457
|
-
// console.log('didBecomeFirstResponder called on %@'.fmt(this));
|
1458
|
-
this.$().addClass('focus') ;
|
1459
|
-
},
|
1460
|
-
|
1461
|
-
/** @private */
|
1462
|
-
willLoseFirstResponder: function() {
|
1463
|
-
// console.log('willLoseFirstResponder called on %@'.fmt(this));
|
1464
|
-
this.$().removeClass('focus');
|
2054
|
+
|
2055
|
+
return SC.IndexSet.create(min, max - min + 1);
|
1465
2056
|
},
|
1466
2057
|
|
1467
2058
|
// ......................................
|
@@ -1482,22 +2073,21 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1482
2073
|
}.property().cacheable(),
|
1483
2074
|
|
1484
2075
|
/**
|
1485
|
-
This property is set to the
|
1486
|
-
of a drag whenever a drag is initiated on the collection view.
|
1487
|
-
consult this property when implementing your collection view
|
1488
|
-
methods, but otherwise you should not use this property in your
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
@type Array
|
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
|
1494
2083
|
*/
|
1495
2084
|
dragContent: null,
|
1496
2085
|
|
1497
2086
|
/**
|
1498
2087
|
This property is set to the proposed insertion index during a call to
|
1499
|
-
collectionViewValidateDragOperation(). Your delegate implementations can
|
1500
|
-
the value of this property to enforce a drop some in some other
|
2088
|
+
collectionViewValidateDragOperation(). Your delegate implementations can
|
2089
|
+
change the value of this property to enforce a drop some in some other
|
2090
|
+
location.
|
1501
2091
|
|
1502
2092
|
@type Number
|
1503
2093
|
*/
|
@@ -1505,11 +2095,12 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1505
2095
|
|
1506
2096
|
/**
|
1507
2097
|
This property is set to the proposed drop operation during a call to
|
1508
|
-
collectionViewValidateDragOperation(). Your delegate implementations can
|
1509
|
-
the value of this property to enforce a different type of drop
|
2098
|
+
collectionViewValidateDragOperation(). Your delegate implementations can
|
2099
|
+
change the value of this property to enforce a different type of drop
|
2100
|
+
operation.
|
1510
2101
|
|
1511
2102
|
@type Number
|
1512
|
-
@
|
2103
|
+
@property
|
1513
2104
|
*/
|
1514
2105
|
proposedDropOperation: null,
|
1515
2106
|
|
@@ -1523,56 +2114,58 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1523
2114
|
- a mouse down event was saved by the mouseDown method.
|
1524
2115
|
*/
|
1525
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
|
+
|
1526
2124
|
// if the mouse down event was cleared, there is nothing to do; return.
|
1527
|
-
if (
|
2125
|
+
if (!info || info.contentIndex<0) return YES ;
|
1528
2126
|
|
1529
2127
|
// Don't do anything unless the user has been dragging for 123msec
|
1530
|
-
if ((Date.now() -
|
2128
|
+
if ((Date.now() - info.at) < 123) return YES ;
|
1531
2129
|
|
1532
2130
|
// OK, they must be serious, decide if a drag will be allowed.
|
1533
|
-
if (
|
2131
|
+
if (del.collectionViewShouldBeginDrag(this)) {
|
1534
2132
|
|
1535
2133
|
// First, get the selection to drag. Drag an array of selected
|
1536
2134
|
// items appearing in this collection, in the order of the
|
1537
2135
|
// collection.
|
1538
2136
|
//
|
1539
|
-
//
|
1540
|
-
var content = this.get('content') || [] ;
|
1541
|
-
var dragContent;
|
1542
|
-
|
2137
|
+
// Compute the dragContent - the indexes we will be dragging.
|
1543
2138
|
// if we don't select on mouse down, then the selection has not been
|
1544
2139
|
// updated to whatever the user clicked. Instead use
|
1545
2140
|
// mouse down content.
|
1546
2141
|
if (!this.get("selectOnMouseDown")) {
|
1547
|
-
dragContent =
|
1548
|
-
} else
|
1549
|
-
|
1550
|
-
a = content.indexOf(a) ;
|
1551
|
-
b = content.indexOf(b) ;
|
1552
|
-
return (a<b) ? -1 : ((a>b) ? 1 : 0) ;
|
1553
|
-
});
|
1554
|
-
}
|
2142
|
+
dragContent = SC.IndexSet.create(info.contentIndex);
|
2143
|
+
} else dragContent = sel ? sel.indexSetForSource(content) : null;
|
2144
|
+
if (!dragContent) return YES; // nothing to drag
|
1555
2145
|
|
2146
|
+
dragContent = { content: content, indexes: dragContent };
|
1556
2147
|
this.set('dragContent', dragContent) ;
|
1557
2148
|
|
1558
2149
|
// Get the set of data types supported by the delegate. If this returns
|
1559
2150
|
// a null or empty array and reordering content is not also supported
|
1560
2151
|
// then do not start the drag.
|
1561
|
-
|
2152
|
+
dragDataTypes = this.get('dragDataTypes');
|
2153
|
+
if (dragDataTypes && dragDataTypes.get('length') > 0) {
|
2154
|
+
|
1562
2155
|
// Build the drag view to use for the ghost drag. This
|
1563
2156
|
// should essentially contain any visible drag items.
|
1564
|
-
|
1565
|
-
|
2157
|
+
dragView = del.collectionViewDragViewFor(this, dragContent.indexes);
|
2158
|
+
if (!dragView) dragView = this._cv_dragViewFor(dragContent.indexes);
|
1566
2159
|
|
1567
2160
|
// Initiate the drag
|
1568
2161
|
SC.Drag.start({
|
1569
|
-
event:
|
2162
|
+
event: info.event,
|
1570
2163
|
source: this,
|
1571
|
-
dragView:
|
2164
|
+
dragView: dragView,
|
1572
2165
|
ghost: NO,
|
1573
2166
|
slideBack: YES,
|
1574
2167
|
dataSource: this
|
1575
|
-
})
|
2168
|
+
});
|
1576
2169
|
|
1577
2170
|
// Also use this opportunity to clean up since mouseUp won't
|
1578
2171
|
// get called.
|
@@ -1580,13 +2173,55 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1580
2173
|
this._lastInsertionIndex = null ;
|
1581
2174
|
|
1582
2175
|
// Drag was not allowed by the delegate, so bail.
|
1583
|
-
} else
|
1584
|
-
this.set('dragContent', null) ;
|
1585
|
-
}
|
2176
|
+
} else this.set('dragContent', null) ;
|
1586
2177
|
|
1587
2178
|
return YES ;
|
1588
2179
|
}
|
1589
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
|
+
|
1590
2225
|
|
1591
2226
|
/**
|
1592
2227
|
Implements the drag data source protocol for the collection view. This
|
@@ -1597,26 +2232,18 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1597
2232
|
@type Array
|
1598
2233
|
*/
|
1599
2234
|
dragDataTypes: function() {
|
1600
|
-
// console.log('dragDataTypes called on %@'.fmt(this));
|
1601
|
-
|
1602
2235
|
// consult delegate.
|
1603
|
-
var
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
if (
|
1608
|
-
|
1609
|
-
|
1610
|
-
|
1611
|
-
ret = (ret) ? ret.slice() : [] ;
|
1612
|
-
|
1613
|
-
var key = this.get('reorderDataType') ;
|
1614
|
-
if (ret.indexOf(key) < 0) ret.push(key) ;
|
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);
|
1615
2244
|
}
|
1616
|
-
|
1617
|
-
|
1618
|
-
//data: { "_mouseDownContent": dragContent }
|
1619
|
-
|
2245
|
+
|
2246
|
+
return ret ? ret : [];
|
1620
2247
|
}.property(),
|
1621
2248
|
|
1622
2249
|
/**
|
@@ -1629,39 +2256,44 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1629
2256
|
// if this is a reorder, then return drag content.
|
1630
2257
|
if (this.get('canReorderContent')) {
|
1631
2258
|
if (dataType === this.get('reorderDataType')) {
|
1632
|
-
// console.log('dragContent is %@'.fmt(this.get('dragContent')));
|
1633
2259
|
return this.get('dragContent') ;
|
1634
2260
|
}
|
1635
2261
|
}
|
1636
2262
|
|
1637
|
-
// otherwise, just pass along to the delegate
|
1638
|
-
|
2263
|
+
// otherwise, just pass along to the delegate
|
2264
|
+
var del = this.get('selectionDelegate');
|
2265
|
+
return del.collectionViewDragDataForType(this, drag, dataType);
|
1639
2266
|
},
|
1640
2267
|
|
1641
2268
|
/**
|
1642
2269
|
Implements the SC.DropTarget interface. The default implementation will
|
1643
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.
|
1644
2279
|
*/
|
1645
2280
|
computeDragOperations: function(drag, evt) {
|
1646
|
-
|
1647
|
-
|
2281
|
+
|
1648
2282
|
// the proposed drag operation is DRAG_REORDER only if we can reorder
|
1649
2283
|
// content and the drag contains reorder content.
|
1650
|
-
var op
|
2284
|
+
var op = SC.DRAG_NONE,
|
2285
|
+
del = this.get('selectionDelegate');
|
2286
|
+
|
1651
2287
|
if (this.get('canReorderContent')) {
|
1652
|
-
|
1653
|
-
if (types.indexOf(this.get('reorderDataType')) >= 0) {
|
2288
|
+
if (drag.get('dataTypes').indexOf(this.get('reorderDataType')) >= 0) {
|
1654
2289
|
op = SC.DRAG_REORDER ;
|
1655
2290
|
}
|
1656
2291
|
}
|
1657
2292
|
|
1658
2293
|
// Now pass this onto the delegate.
|
1659
|
-
|
1660
|
-
op = this.invokeDelegateMethod(this.delegate, 'collectionViewComputeDragOperations', this, drag, op) ;
|
1661
|
-
|
2294
|
+
op = del.collectionViewComputeDragOperations(this, drag, op);
|
1662
2295
|
if (op & SC.DRAG_REORDER) op = SC.DRAG_MOVE ;
|
1663
2296
|
|
1664
|
-
// return
|
1665
2297
|
return op ;
|
1666
2298
|
},
|
1667
2299
|
|
@@ -1669,17 +2301,23 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1669
2301
|
Determines the allowed drop operation insertion point, operation type,
|
1670
2302
|
and the drag operation to be performed. Used by dragUpdated() and
|
1671
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]
|
1672
2309
|
*/
|
1673
|
-
_computeDropOperationState: function(drag, evt) {
|
2310
|
+
_computeDropOperationState: function(drag, evt, dragOp) {
|
1674
2311
|
|
1675
2312
|
// get the insertion index for this location. This can be computed
|
1676
2313
|
// by a subclass using whatever method. This method is not expected to
|
1677
2314
|
// do any data valdidation, just to map the location to an insertion
|
1678
2315
|
// index.
|
1679
|
-
var loc
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
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;
|
1683
2321
|
|
1684
2322
|
// STEP 1: Try with a DROP_ON option -- send straight to delegate if
|
1685
2323
|
// supported by view.
|
@@ -1687,7 +2325,7 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1687
2325
|
// get the computed insertion index and possibly drop operation.
|
1688
2326
|
// prefer to drop ON.
|
1689
2327
|
var idx = this.insertionIndexForLocation(loc, SC.DROP_ON) ;
|
1690
|
-
if (SC
|
2328
|
+
if (SC.typeOf(idx) === SC.T_ARRAY) {
|
1691
2329
|
dropOp = idx[1] ; // order matters here
|
1692
2330
|
idx = idx[0] ;
|
1693
2331
|
}
|
@@ -1696,64 +2334,63 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1696
2334
|
// delegate method. If the delegate method does not support dropping on,
|
1697
2335
|
// then it will return DRAG_NONE, in which case we will try again with
|
1698
2336
|
// drop before.
|
1699
|
-
if (dropOp
|
1700
|
-
// console.log('dropOp === SC.DROP_ON');
|
2337
|
+
if (dropOp === SC.DROP_ON) {
|
1701
2338
|
|
1702
2339
|
// Now save the insertion index and the dropOp. This may be changed by
|
1703
2340
|
// the collection delegate.
|
1704
2341
|
this.set('proposedInsertionIndex', idx) ;
|
1705
2342
|
this.set('proposedDropOperation', dropOp) ;
|
1706
|
-
dragOp =
|
2343
|
+
dragOp = del.collectionViewValidateDragOperation(this, drag, dragOp, idx, dropOp) ;
|
1707
2344
|
idx = this.get('proposedInsertionIndex') ;
|
1708
2345
|
dropOp = this.get('proposedDropOperation') ;
|
1709
2346
|
this._dropInsertionIndex = this._dropOperation = null ;
|
1710
2347
|
|
1711
2348
|
// The delegate is OK with a drop on also, so just return.
|
1712
|
-
if (dragOp !== SC.DRAG_NONE)
|
1713
|
-
// console.log('[idx, dropOp, dragOp] is [%@, %@, %@]'.fmt(idx, dropOp, dragOp));
|
1714
|
-
return [idx, dropOp, dragOp] ;
|
2349
|
+
if (dragOp !== SC.DRAG_NONE) return [idx, dropOp, dragOp] ;
|
1715
2350
|
|
1716
2351
|
// The delegate is NOT OK with a drop on, try to get the insertion
|
1717
2352
|
// index again, but this time prefer SC.DROP_BEFORE, then let the
|
1718
2353
|
// rest of the method run...
|
1719
|
-
|
2354
|
+
else {
|
1720
2355
|
dropOp = SC.DROP_BEFORE ;
|
1721
2356
|
idx = this.insertionIndexForLocation(loc, SC.DROP_BEFORE) ;
|
1722
|
-
if (SC
|
2357
|
+
if (SC.typeOf(idx) === SC.T_ARRAY) {
|
1723
2358
|
dropOp = idx[1] ; // order matters here
|
1724
2359
|
idx = idx[0] ;
|
1725
2360
|
}
|
1726
2361
|
}
|
1727
2362
|
}
|
1728
2363
|
|
1729
|
-
// console.log('this is a redorder drag, dropOp is %@'.fmt(dropOp)) ;
|
1730
|
-
|
1731
2364
|
// if this is a reorder drag, set the proposed op to SC.DRAG_REORDER and
|
1732
2365
|
// validate the insertion point. This only works if the insertion point
|
1733
|
-
// is DROP_BEFORE. DROP_ON is not handled by reordering
|
1734
|
-
|
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)) {
|
1735
2369
|
|
1736
|
-
|
2370
|
+
objects = drag.dataForType(this.get('reorderDataType')) ;
|
1737
2371
|
if (objects) {
|
1738
|
-
|
1739
|
-
var content = this.get('content') || [] ;
|
1740
|
-
// console.log('objects is %@, content is %@'.fmt(objects, content));
|
2372
|
+
content = this.get('content') ;
|
1741
2373
|
|
1742
2374
|
// if the insertion index is in between two items in the drag itself,
|
1743
2375
|
// then this is not allowed. Either use the last insertion index or
|
1744
2376
|
// find the first index that is not in between selections. Stop when
|
1745
2377
|
// we get to the beginning.
|
1746
|
-
|
1747
|
-
|
1748
|
-
|
1749
|
-
|
1750
|
-
|
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
|
+
}
|
1751
2385
|
|
1752
2386
|
if (isPreviousInDrag && isNextInDrag) {
|
1753
2387
|
if (SC.none(this._lastInsertionIndex)) {
|
1754
|
-
|
1755
|
-
idx
|
1756
|
-
}
|
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
|
+
}
|
1757
2394
|
} else idx = this._lastInsertionIndex ;
|
1758
2395
|
}
|
1759
2396
|
|
@@ -1763,14 +2400,11 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1763
2400
|
}
|
1764
2401
|
}
|
1765
2402
|
|
1766
|
-
// console.log('the dragOp is %@'.fmt(dragOp)) ;
|
1767
|
-
|
1768
2403
|
// Now save the insertion index and the dropOp. This may be changed by
|
1769
2404
|
// the collection delegate.
|
1770
2405
|
this.set('proposedInsertionIndex', idx) ;
|
1771
2406
|
this.set('proposedDropOperation', dropOp) ;
|
1772
|
-
|
1773
|
-
dragOp = this.invokeDelegateMethod(this.delegate, 'collectionViewValidateDragOperation', this, drag, dragOp, idx, dropOp) ;
|
2407
|
+
dragOp = del.collectionViewValidateDragOperation(this, drag, dragOp, idx, dropOp) ;
|
1774
2408
|
idx = this.get('proposedInsertionIndex') ;
|
1775
2409
|
dropOp = this.get('proposedDropOperation') ;
|
1776
2410
|
this._dropInsertionIndex = this._dropOperation = null ;
|
@@ -1786,15 +2420,16 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1786
2420
|
content on its own.
|
1787
2421
|
*/
|
1788
2422
|
dragUpdated: function(drag, evt) {
|
1789
|
-
// console.log('dragUpdated called in %@'.fmt(this));
|
1790
|
-
var state = this._computeDropOperationState(drag, evt) ;
|
1791
|
-
// console.log('state is %@'.fmt(state));
|
1792
|
-
var idx = state[0], dropOp = state[1], dragOp = state[2] ;
|
1793
2423
|
|
1794
|
-
|
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
|
1795
2430
|
if (dragOp !== SC.DRAG_NONE) {
|
1796
2431
|
if ((this._lastInsertionIndex !== idx) || (this._lastDropOperation !== dropOp)) {
|
1797
|
-
var itemView = this.
|
2432
|
+
var itemView = this.itemViewForContentIndex(idx) ;
|
1798
2433
|
this.showInsertionPoint(itemView, dropOp) ;
|
1799
2434
|
}
|
1800
2435
|
|
@@ -1805,7 +2440,8 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1805
2440
|
this._lastInsertionIndex = this._lastDropOperation = null ;
|
1806
2441
|
}
|
1807
2442
|
|
1808
|
-
// Normalize drag operation to the standard kinds accepted by the drag
|
2443
|
+
// Normalize drag operation to the standard kinds accepted by the drag
|
2444
|
+
// system.
|
1809
2445
|
return (dragOp & SC.DRAG_REORDER) ? SC.DRAG_MOVE : dragOp;
|
1810
2446
|
},
|
1811
2447
|
|
@@ -1818,15 +2454,6 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1818
2454
|
this._lastInsertionIndex = this._lastDropOperation = null ;
|
1819
2455
|
},
|
1820
2456
|
|
1821
|
-
// /**
|
1822
|
-
// Implements the SC.DropTarget protocol. Hides any visible insertion
|
1823
|
-
// point and clears some cached values.
|
1824
|
-
// */
|
1825
|
-
// dragEnded: function() {
|
1826
|
-
// this.hideInsertionPoint() ;
|
1827
|
-
// this._lastInsertionIndex = this._lastDropOperation = null ;
|
1828
|
-
// },
|
1829
|
-
|
1830
2457
|
/**
|
1831
2458
|
Implements the SC.DropTarget protocol.
|
1832
2459
|
*/
|
@@ -1838,61 +2465,52 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1838
2465
|
reordering content.
|
1839
2466
|
*/
|
1840
2467
|
performDragOperation: function(drag, op) {
|
1841
|
-
// console.log('performDragOperation called on %@ with drag.dataTypes %@'.fmt(this, drag.get('dataTypes')));
|
1842
|
-
// console.log('op is %@'.fmt(SC.Drag.inspectOperation(op)));
|
1843
2468
|
// Get the correct insertion point, drop operation, etc.
|
1844
|
-
var state = this._computeDropOperationState(drag, null, op)
|
1845
|
-
|
1846
|
-
|
1847
|
-
|
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
|
+
|
1848
2474
|
// The dragOp is the kinds of ops allowed. The drag operation must
|
1849
2475
|
// be included in that set.
|
1850
2476
|
if (dragOp & SC.DRAG_REORDER) {
|
1851
2477
|
op = (op & SC.DRAG_MOVE) ? SC.DRAG_REORDER : SC.DRAG_NONE ;
|
1852
|
-
} else
|
1853
|
-
op = op & dragOp ;
|
1854
|
-
}
|
1855
|
-
// console.log('after processing, op is %@'.fmt(SC.Drag.inspectOperation(op)));
|
2478
|
+
} else op = op & dragOp ;
|
1856
2479
|
|
1857
2480
|
// If no allowed drag operation could be found, just return.
|
1858
2481
|
if (op === SC.DRAG_NONE) return op;
|
1859
2482
|
|
1860
2483
|
// Some operation is allowed through, give the delegate a chance to
|
1861
2484
|
// handle it.
|
1862
|
-
|
1863
|
-
var performed = this.invokeDelegateMethod(this.delegate, 'collectionViewPerformDragOperation', this, drag, op, idx, dropOp) ;
|
2485
|
+
performed = del.collectionViewPerformDragOperation(this, drag, op, idx, dropOp) ;
|
1864
2486
|
|
1865
|
-
// console.log('performed is %@'.fmt(SC.Drag.inspectOperation(performed)));
|
1866
2487
|
// If the delegate did not handle the drag (i.e. returned SC.DRAG_NONE),
|
1867
2488
|
// and the op type is REORDER, then do the reorder here.
|
1868
|
-
// console.log('performed & SC.DRAG_NONE is %@, op & SC.DRAG_REORDER is %@'.fmt((performed & SC.DRAG_NONE),(op & SC.DRAG_REORDER)));
|
1869
2489
|
if ((performed === SC.DRAG_NONE) && (op & SC.DRAG_REORDER)) {
|
1870
|
-
var objects = drag.dataForType(this.get('reorderDataType')) ;
|
1871
|
-
// console.log('objects is %@'.fmt(objects));
|
1872
|
-
if (!objects) return SC.DRAG_NONE ;
|
1873
2490
|
|
1874
|
-
|
1875
|
-
|
2491
|
+
data = drag.dataForType(this.get('reorderDataType')) ;
|
2492
|
+
if (!data) return SC.DRAG_NONE ;
|
1876
2493
|
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
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);
|
1886
2508
|
|
1887
|
-
// now insert objects
|
1888
|
-
content.replace(idx, 0, objects)
|
2509
|
+
// now insert objects into new insertion locaiton
|
2510
|
+
content.replace(idx, 0, objects);
|
2511
|
+
this.select(SC.IndexSet.create(idx, objects.length));
|
1889
2512
|
content.endPropertyChanges(); // restart notifications
|
1890
|
-
|
1891
|
-
var outOfDateIndices = Math.min(old, idx) ;
|
1892
|
-
if (outOfDateIndices < 0 ) outOfDateIndices = 0 ;
|
1893
|
-
|
1894
|
-
this.rowHeightsDidChangeInRange({ start: outOfDateIndices, length: content.get('length')-outOfDateIndices }) ;
|
1895
|
-
|
2513
|
+
|
1896
2514
|
// make the op into its actual value
|
1897
2515
|
op = SC.DRAG_MOVE ;
|
1898
2516
|
}
|
@@ -1907,44 +2525,16 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1907
2525
|
collectionViewShouldBeginDrag: function(view) {
|
1908
2526
|
return this.get('canReorderContent') ;
|
1909
2527
|
},
|
2528
|
+
|
1910
2529
|
|
1911
|
-
//
|
1912
|
-
//
|
1913
|
-
//
|
1914
|
-
// },
|
1915
|
-
|
1916
|
-
/**
|
1917
|
-
If some state changes that causes the row height for a range of rows
|
1918
|
-
then you should call this method to notify the view that it needs to
|
1919
|
-
recalculate the row heights for the collection.
|
1920
|
-
|
1921
|
-
Anytime your content array changes, the rows are invalidated
|
1922
|
-
automatically so you only need to use this for cases where your rows
|
1923
|
-
heights may change without changing the content array itself.
|
1924
|
-
|
1925
|
-
If all rows heights have changed, you can pass null to invalidate the
|
1926
|
-
whole range.
|
1927
|
-
|
1928
|
-
@param {Range} range or null.
|
1929
|
-
@returns {SC.CollectionView} reciever
|
1930
|
-
*/
|
1931
|
-
rowHeightsDidChangeInRange: function(range) {},
|
2530
|
+
// ..........................................................
|
2531
|
+
// INSERTION POINT
|
2532
|
+
//
|
1932
2533
|
|
1933
|
-
/**
|
1934
|
-
The insertion orientation. This is used to determine which
|
1935
|
-
dimension we should pay attention to when determining insertion point for
|
1936
|
-
a mouse click.
|
1937
|
-
|
1938
|
-
{{{
|
1939
|
-
SC.HORIZONTAL_ORIENTATION: look at the X dimension only
|
1940
|
-
SC.VERTICAL_ORIENTATION: look at the Y dimension only
|
1941
|
-
}}}
|
1942
|
-
*/
|
1943
|
-
insertionOrientation: SC.HORIZONTAL_ORIENTATION,
|
1944
2534
|
|
1945
2535
|
/**
|
1946
2536
|
Get the preferred insertion point for the given location, including
|
1947
|
-
an insertion preference of before or
|
2537
|
+
an insertion preference of before, after or on the named index.
|
1948
2538
|
|
1949
2539
|
You can implement this method in a subclass if you like to perform a
|
1950
2540
|
more efficient check. The default implementation will loop through the
|
@@ -1953,12 +2543,12 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1953
2543
|
|
1954
2544
|
This method should return an array with two values. The first value is
|
1955
2545
|
the insertion point index and the second value is the drop operation,
|
1956
|
-
which should be one of SC.DROP_BEFORE or SC.DROP_ON.
|
2546
|
+
which should be one of SC.DROP_BEFORE, SC.DROP_AFTER, or SC.DROP_ON.
|
1957
2547
|
|
1958
2548
|
The preferred drop operation passed in should be used as a hint as to
|
1959
|
-
the type of operation the
|
1960
|
-
|
1961
|
-
|
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.
|
1962
2552
|
|
1963
2553
|
For compatibility, you can also return just the insertion index. If you
|
1964
2554
|
do this, then the collction view will assume the drop operation is
|
@@ -1971,155 +2561,180 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
1971
2561
|
@param dropOperation {DropOp} the preferred drop operation.
|
1972
2562
|
@returns {Array} [proposed drop index, drop operation]
|
1973
2563
|
*/
|
1974
|
-
insertionIndexForLocation: function(loc, dropOperation) {
|
1975
|
-
var
|
1976
|
-
|
1977
|
-
var
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
2007
|
-
|
2008
|
-
|
2009
|
-
|
2010
|
-
|
2011
|
-
|
2012
|
-
|
2013
|
-
|
2014
|
-
|
2015
|
-
|
2016
|
-
|
2017
|
-
}
|
2018
|
-
|
2019
|
-
//
|
2020
|
-
|
2021
|
-
|
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 ;
|
2022
2618
|
|
2023
2619
|
// Done. Phew. Return.
|
2024
2620
|
return ret;
|
2025
2621
|
},
|
2026
2622
|
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
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.
|
2044
2641
|
*/
|
2045
|
-
|
2046
|
-
return
|
2642
|
+
collectionViewShouldSelectItem: function(view, item) {
|
2643
|
+
return this.get('isSelectable') ;
|
2047
2644
|
},
|
2048
2645
|
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
Show the insertion point during a drag before the named item view.
|
2053
|
-
|
2054
|
-
This method has been deprecated in favor of the more generic
|
2055
|
-
showInsertionPoint() which can be used to show drops occurring both on
|
2056
|
-
and before an itemView. If you do not implement showInsertionPoint()
|
2057
|
-
yourself, the default implementation will call this method whenever the
|
2058
|
-
drop operation is SC.DROP_BEFORE.
|
2059
|
-
|
2060
|
-
@param itemView {SC.ClassicView} the item view to show before.
|
2061
|
-
@returns {void}
|
2062
|
-
*/
|
2063
|
-
showInsertionPointBefore: function(itemView) {},
|
2646
|
+
_TMP_DIFF1: SC.IndexSet.create(),
|
2647
|
+
_TMP_DIFF2: SC.IndexSet.create(),
|
2064
2648
|
|
2065
|
-
/**
|
2066
|
-
Override to hide the insertion point when a drag ends.
|
2067
|
-
|
2068
|
-
Called during a drag to hide the insertion point. This will be called
|
2069
|
-
when the user exits the view, cancels the drag or completes the drag. It
|
2070
|
-
will not be called when the insertion point changes during a drag.
|
2071
|
-
|
2072
|
-
You should expect to receive one or more calls to
|
2073
|
-
showInsertionPointBefore() during a drag followed by at least one call to
|
2074
|
-
this method at the end. Your method should not raise an error if it is
|
2075
|
-
called more than once.
|
2076
|
-
|
2077
|
-
@returns {void}
|
2078
|
-
*/
|
2079
|
-
hideInsertionPoint: function() {},
|
2649
|
+
/** @private
|
2080
2650
|
|
2081
|
-
|
2082
|
-
|
2083
|
-
|
2084
|
-
|
2085
|
-
|
2086
|
-
|
2087
|
-
|
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);
|
2088
2675
|
}
|
2089
2676
|
|
2090
|
-
|
2091
|
-
|
2092
|
-
|
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();
|
2093
2689
|
},
|
2094
2690
|
|
2095
|
-
/**
|
2096
|
-
|
2097
|
-
is also true.
|
2691
|
+
/** @private
|
2692
|
+
Become a drop target whenever reordering content is enabled.
|
2098
2693
|
*/
|
2099
|
-
|
2100
|
-
|
2101
|
-
|
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'),
|
2102
2700
|
|
2103
|
-
|
2104
|
-
|
2105
|
-
|
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
|
+
},
|
2106
2719
|
|
2107
2720
|
/** @private
|
2108
2721
|
Perform the action. Supports legacy behavior as well as newer style
|
2109
2722
|
action dispatch.
|
2110
2723
|
*/
|
2111
|
-
|
2112
|
-
// console.log('_action invoked on %@ with view %@, evt %@'.fmt(this, view, evt));
|
2724
|
+
_cv_action: function(view, evt, context) {
|
2113
2725
|
var action = this.get('action');
|
2114
2726
|
var target = this.get('target') || null;
|
2115
|
-
|
2727
|
+
|
2728
|
+
this._cv_actionTimer = null;
|
2116
2729
|
if (action) {
|
2117
2730
|
// if the action is a function, just call it
|
2118
|
-
if (SC
|
2731
|
+
if (SC.typeOf(action) === SC.T_FUNCTION) return this.action(view, evt) ;
|
2119
2732
|
|
2120
2733
|
// otherwise, use the new sendAction style
|
2121
2734
|
var pane = this.get('pane') ;
|
2122
|
-
if (pane)
|
2735
|
+
if (pane) {
|
2736
|
+
pane.rootResponder.sendAction(action, target, this, pane, context);
|
2737
|
+
}
|
2123
2738
|
// SC.app.sendAction(action, target, this) ;
|
2124
2739
|
|
2125
2740
|
// if no action is specified, then trigger the support action,
|
@@ -2129,13 +2744,14 @@ SC.CollectionView = SC.View.extend(SC.CollectionViewDelegate,
|
|
2129
2744
|
|
2130
2745
|
// if the target view has its own internal action handler,
|
2131
2746
|
// trigger that.
|
2132
|
-
} else if (SC
|
2747
|
+
} else if (SC.typeOf(view._action) == SC.T_FUNCTION) {
|
2133
2748
|
return view._action(evt) ;
|
2134
2749
|
|
2135
2750
|
// otherwise call the action method to support older styles.
|
2136
|
-
} else if (SC
|
2751
|
+
} else if (SC.typeOf(view.action) == SC.T_FUNCTION) {
|
2137
2752
|
return view.action(evt) ;
|
2138
2753
|
}
|
2139
2754
|
}
|
2140
2755
|
|
2756
|
+
|
2141
2757
|
});
|