sproutcore 1.10.3.1 → 1.11.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/CHANGELOG +4 -8
- data/VERSION.yml +2 -2
- data/lib/frameworks/sproutcore/Buildfile +5 -4
- data/lib/frameworks/sproutcore/CHANGELOG.md +274 -40
- data/lib/frameworks/sproutcore/CONTRIBUTORS.md +133 -0
- data/lib/frameworks/sproutcore/README.md +31 -144
- data/lib/frameworks/sproutcore/apps/showcase/controllers/source_tree_controller.js +9 -4
- data/lib/frameworks/sproutcore/apps/showcase/resources/stylesheet.css +5 -0
- data/lib/frameworks/sproutcore/apps/showcase/system/views_item_content.js +1 -1
- data/lib/frameworks/sproutcore/apps/showcase/views/split_views.js +15 -2
- data/lib/frameworks/sproutcore/apps/showcase/views/stacked_views.js +1 -1
- data/lib/frameworks/sproutcore/apps/tests/english.lproj/main_page.js +11 -1
- data/lib/frameworks/sproutcore/frameworks/ajax/mixins/websocket_delegate.js +90 -0
- data/lib/frameworks/sproutcore/frameworks/ajax/system/request.js +81 -5
- data/lib/frameworks/sproutcore/frameworks/ajax/system/response.js +23 -4
- data/lib/frameworks/sproutcore/frameworks/ajax/system/websocket.js +475 -0
- data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/request.js +149 -26
- data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/websocket.js +197 -0
- data/lib/frameworks/sproutcore/frameworks/ajax/tests/system/xhr_response_test.js +65 -0
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/loader.js +4 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/horizontal_stack_layout.js +232 -52
- data/lib/frameworks/sproutcore/frameworks/core_foundation/child_view_layouts/vertical_stack_layout.js +235 -49
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +23 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/object.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/core.js +81 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/english.lproj/ordinal.js +17 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/string.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/{desktop/tests/views/disclosure/methods.js → core_foundation/french.lproj/ordinal.js} +7 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/layout.js +2 -6
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/main.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +104 -69
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane_statechart.js +6 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/child_view_layout_protocol.js +59 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/protocols/view_transition_protocol.js +18 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/application.js +192 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/bezier_curves.js +52 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/color.js +384 -64
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/core_query.js +6 -14
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/device.js +21 -35
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +72 -36
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/locale.js +90 -34
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +55 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/render_context.js +20 -15
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/req_anim_frame.js +9 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +763 -542
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/selection_set.js +4 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +1 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/string.js +14 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/touch.js +538 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/utils/rect.js +56 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/array/array_case.js +99 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/controllers/object/single_case.js +25 -19
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/core_tests.js +75 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/ext/number_test.js +81 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +4 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/responder_context.js +4 -4
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/string.js +19 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/color.js +36 -20
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/design_modes_test.js +83 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/makeMainPane.js +7 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/mouse_events.js +338 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/root_responder.js +14 -89
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/root_responder/touch.js +106 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/sparse_array.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/touch.js +136 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/system/utils/rect.js +42 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/append_remove.js +11 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/child_view.js +5 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/design_mode_test.js +457 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/pane/sendEvent.js +36 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/background_color.js +44 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/border_frame_test.js +51 -24
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/childViewLayout_test.js +176 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/clippingFrame.js +46 -16
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/convertFrames.js +69 -15
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/didAppendToDocument.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layout.js +7 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutDidChange.js +30 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +376 -71
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/static_layout.js +0 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/viewDidResize.js +117 -34
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/view_states_test.js +52 -2
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +656 -42
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/animation.js +159 -38
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/cursor.js +0 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/design_mode.js +206 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/enabled.js +0 -28
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +21 -6
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout.js +372 -450
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +28 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/manipulation.js +22 -51
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/statechart.js +59 -30
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/theming.js +0 -29
- data/lib/frameworks/sproutcore/frameworks/datastore/mixins/relationship_support.js +22 -10
- data/lib/frameworks/sproutcore/frameworks/datastore/models/children_attribute.js +42 -36
- data/lib/frameworks/sproutcore/frameworks/datastore/models/many_attribute.js +54 -3
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +178 -59
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/system/child_array.js +206 -132
- data/lib/frameworks/sproutcore/frameworks/datastore/system/many_array.js +214 -118
- data/lib/frameworks/sproutcore/frameworks/datastore/system/nested_store.js +96 -13
- data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +14 -4
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +82 -42
- data/lib/frameworks/sproutcore/frameworks/datastore/system/store.js +272 -177
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/integration/store_interaction_test.js +54 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/datetime_recordattribute.js +24 -16
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/many_attribute.js +6 -3
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/data_store.js +267 -35
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record.js +57 -46
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array.js +150 -53
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_array_complex.js +57 -17
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/nested_records/nested_record_complex.js +13 -9
- data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/many.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/simple.js +0 -0
- data/lib/frameworks/sproutcore/frameworks/{experimental/frameworks/polymorphism → datastore}/tests/models/polymorphism/single.js +12 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/writeAttribute.js +20 -15
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record_attribute.js +9 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/many_array/core_methods.js +80 -14
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_dataSourceCallbacks.js +280 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/autonomous_pushChanges.js +232 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/nested_store/chain.js +31 -5
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/parse.js +16 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/core_methods.js +60 -40
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/store/materializeRecord.js +78 -0
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +13 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +20 -0
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/{resources → english.lproj}/strings.js +0 -0
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/localized/french.lproj/strings.js +45 -0
- data/lib/frameworks/sproutcore/frameworks/designer/designers/object_designer.js +7 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_row_delegate.js +125 -44
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/alert.js +139 -48
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/draggable.js +202 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +59 -56
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/palette.js +13 -49
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +466 -305
- data/lib/frameworks/sproutcore/frameworks/desktop/protocols/drag_source.js +49 -12
- data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/slider.js +79 -21
- data/lib/frameworks/sproutcore/frameworks/desktop/render_delegates/split.js +12 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/menu_item_view.css +8 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/overlay-scroller.css +187 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +94 -30
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/alert/ui.js +163 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/methods.js +97 -78
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +61 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/methods.js +7 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/panel/ui.js +47 -22
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/methods.js +66 -9
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/picker/ui.js +21 -11
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/sheet/ui.js +12 -18
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/methods.js +17 -14
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/button/ui.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/checkbox/methods.js +9 -6
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/collection_fast_path.js +54 -21
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/content.js +52 -20
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/itemViewForContentIndex.js +94 -4
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/keyboard.js +177 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/layerIdFor.js +13 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/length.js +9 -9
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/collection/mouse.js +18 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/date_field/methods.js +104 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/disclosure/ui.js +48 -49
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/grid/drag_and_drop.js +22 -18
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/grid/methods.js +17 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/link_view_test.js +136 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/contentIndexesInRect.js +77 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/drag_and_drop.js +53 -16
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/layoutForContentIndex.js +41 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowDelegate.js +25 -25
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/rowOffsetForContentIndex.js +102 -27
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/{rowHeightForContentIndex.js → rowSizeForContentIndex.js} +7 -6
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_outline.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_row_heights.js +70 -75
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list/ui_simple.js +29 -30
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/list_item.js +57 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/menu_scroll_view/menu_scroll_view_test.js +206 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/progress/ui.js +15 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/radio/methods.js +15 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/integration.js +16 -11
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/methods.js +164 -12
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/scale.js +387 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/touch.js +549 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroll/ui.js +214 -45
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/scroller.js +5 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/methods.js +73 -22
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/segmented/ui.js +88 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select/methods.js +8 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/slider/methods.js +16 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/slider/ui.js +54 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/split/dividers.js +21 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/static_content.js +31 -25
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/tab/methods.js +109 -29
- data/lib/frameworks/sproutcore/frameworks/desktop/views/button.js +10 -1
- data/lib/frameworks/sproutcore/frameworks/desktop/views/checkbox.js +3 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +779 -603
- data/lib/frameworks/sproutcore/frameworks/desktop/views/date_field.js +106 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/views/link_view.js +406 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/list.js +437 -245
- data/lib/frameworks/sproutcore/frameworks/desktop/views/list_item.js +13 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +124 -62
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroll.js +176 -597
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_scroller_view.js +206 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/popup_button.js +3 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/progress.js +5 -4
- data/lib/frameworks/sproutcore/frameworks/desktop/views/radio.js +3 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scene.js +56 -158
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll_view.js +2560 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroller.js +458 -242
- data/lib/frameworks/sproutcore/frameworks/desktop/views/segmented.js +117 -54
- data/lib/frameworks/sproutcore/frameworks/desktop/views/select.js +18 -12
- data/lib/frameworks/sproutcore/frameworks/desktop/views/slider.js +162 -34
- data/lib/frameworks/sproutcore/frameworks/desktop/views/split.js +30 -15
- data/lib/frameworks/sproutcore/frameworks/desktop/views/split_divider.js +33 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/views/static_content.js +22 -2
- data/lib/frameworks/sproutcore/frameworks/desktop/views/tab.js +47 -22
- data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +0 -6
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/forms/views/form_row.js +21 -21
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/ext/menu.js +14 -3
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/mixins/select_view_menu.js +24 -10
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/ext/menu_resizing.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/bindings.js +7 -4
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/mixins/select_view_menu/check_selected.js +7 -9
- data/lib/frameworks/sproutcore/frameworks/{desktop/tests/panes/select_button/methods.js → experimental/frameworks/select_view/tests/views/select/method.js} +54 -76
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/tests/views/select/selected_item.js +35 -0
- data/lib/frameworks/sproutcore/frameworks/{desktop/tests/panes/select_button → experimental/frameworks/select_view/tests/views/select}/ui.js +107 -36
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/select_view/views/select.js +225 -66
- data/lib/frameworks/sproutcore/frameworks/foundation/controllers/tree.js +39 -38
- data/lib/frameworks/sproutcore/frameworks/foundation/core.js +5 -18
- data/lib/frameworks/sproutcore/frameworks/foundation/debug/control_test_pane.js +12 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/english.lproj/inflections.js +84 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/french.lproj/inflections.js +41 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_mixin.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/auto_resize.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/content_display.js +3 -4
- data/lib/frameworks/sproutcore/frameworks/foundation/mixins/flowed_layout.js +6 -2
- data/lib/frameworks/sproutcore/frameworks/foundation/private/tree_item_observer.js +408 -239
- data/lib/frameworks/sproutcore/frameworks/foundation/render_delegates/canvas_image.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +2 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/spanish.lproj/inflections.js +38 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/system/benchmark.js +104 -76
- data/lib/frameworks/sproutcore/frameworks/foundation/system/string.js +20 -94
- data/lib/frameworks/sproutcore/frameworks/foundation/system/text_selection.js +33 -22
- data/lib/frameworks/sproutcore/frameworks/foundation/system/undo_manager.js +475 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/auto_resize_test.js +163 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/flowed_layout/tests.js +41 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/mixins/staticLayout.js +2 -5
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/private/tree_item_observer/methods.js +268 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/system/undo_manager.js +231 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/container/ui.js +16 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/image/ui.js +27 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/methods.js +24 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/tests/views/text_field/ui.js +135 -6
- data/lib/frameworks/sproutcore/frameworks/foundation/transitions/fade_transition.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/transitions/pop_transition.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/transitions/scale_transition.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/transitions/slide_transition.js +4 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/transitions/swap_dissolve_transition.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/credit_card.js +21 -21
- data/lib/frameworks/sproutcore/frameworks/foundation/views/container.js +65 -15
- data/lib/frameworks/sproutcore/frameworks/foundation/views/image.js +4 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/views/label.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +193 -213
- data/lib/frameworks/sproutcore/frameworks/jquery/{jquery-1.8.3-patched.js → jquery-1.11.1.js} +7507 -6684
- data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +28 -11
- data/lib/frameworks/sproutcore/frameworks/routing/tests/system/routes.js +26 -0
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +54 -25
- data/lib/frameworks/sproutcore/frameworks/runtime/ext/array.js +0 -6
- data/lib/frameworks/sproutcore/frameworks/runtime/ext/number.js +36 -0
- data/lib/frameworks/sproutcore/frameworks/runtime/ext/window.js +25 -0
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/array.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/enumerable.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/mixins/observable.js +156 -66
- data/lib/frameworks/sproutcore/frameworks/runtime/private/observer_set.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +150 -65
- data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +57 -11
- data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +68 -49
- data/lib/frameworks/sproutcore/frameworks/runtime/system/run_loop.js +14 -6
- data/lib/frameworks/sproutcore/frameworks/runtime/system/string.js +23 -23
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/ext/number_test.js +44 -0
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/array.js +0 -10
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/mixins/enumerable/enumerable.js +340 -285
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/binding.js +104 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/observer_set.js +14 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/tests/system/string.js +15 -2
- data/lib/frameworks/sproutcore/frameworks/statechart/system/state.js +21 -18
- data/lib/frameworks/sproutcore/frameworks/statechart/system/statechart.js +52 -19
- data/lib/frameworks/sproutcore/frameworks/statechart/tests/event_handling/responder/pane.js +27 -24
- data/lib/frameworks/sproutcore/frameworks/template_view/controls/button.js +30 -0
- data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/bind.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/collection.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/template_view/ext/handlebars/view.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/template_view/tests/mixins/template_helpers/checkbox_support.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/template_view/tests/views/template/handlebars.js +4 -2
- data/lib/frameworks/sproutcore/frameworks/template_view/views/bindable_span.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/template_view/views/template_collection.js +16 -14
- data/lib/frameworks/sproutcore/frameworks/testing/core.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/testing/system/plan.js +13 -0
- data/lib/frameworks/sproutcore/lib/index.rhtml +2 -2
- data/lib/frameworks/sproutcore/phantomjs/test_runner.js +28 -7
- data/lib/frameworks/sproutcore/scripts/run_sc_server_master.sh +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/_variables.css +2 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/disclosure/ace/disclosure.css +1 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/picker/popover/popover.css +3 -4
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal.css +15 -15
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal_overlay.css +74 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical.css +11 -13
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical_overlay.css +74 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob-active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob-active@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/knob@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/{22px → jumbo}/slider.css +9 -4
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/track.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/jumbo/track@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob-active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob-active@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/knob@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/slider.css +32 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/track.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/regular/track@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/slider.css +13 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob-active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob-active@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/knob@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/slider.css +32 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/track.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/small/track@2x.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/split/split.css +2 -3
- data/lib/sproutcore/builders/chance_file.rb +3 -3
- data/lib/sproutcore/helpers/minifier.rb +1 -0
- data/vendor/chance/lib/chance/instance.rb +34 -34
- data/vendor/chance/lib/chance/instance/spriting.rb +21 -16
- metadata +81 -58
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/visibility.js +0 -17
- data/lib/frameworks/sproutcore/frameworks/desktop/mixins/collection_fast_path.js +0 -710
- data/lib/frameworks/sproutcore/frameworks/desktop/mixins/scrollable.js +0 -267
- data/lib/frameworks/sproutcore/frameworks/desktop/resources/touch-scroller.css +0 -196
- data/lib/frameworks/sproutcore/frameworks/desktop/system/undo_manager.js +0 -224
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/methods.js +0 -163
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/views/select_field/ui.js +0 -177
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +0 -2053
- data/lib/frameworks/sproutcore/frameworks/desktop/views/select_button.js +0 -1024
- data/lib/frameworks/sproutcore/frameworks/desktop/views/select_field.js +0 -404
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +0 -28
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +0 -235
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +0 -363
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +0 -250
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/README.md +0 -47
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/polymorphism/models/record.js +0 -134
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +0 -92
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +0 -25
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +0 -33
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +0 -76
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +0 -25
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +0 -143
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +0 -256
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +0 -1164
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +0 -332
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +0 -236
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +0 -347
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +0 -15
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +0 -10
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +0 -804
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +0 -133
- data/lib/frameworks/sproutcore/frameworks/foundation/tasks/preload_bundle.js +0 -41
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/horizontal/horizontal_touch.css +0 -91
- data/lib/frameworks/sproutcore/themes/ace/resources/scroller/vertical/vertical_touch.css +0 -92
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/knob_active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/14px/slider.css +0 -27
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/knob_active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/16px/slider.css +0 -27
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/knob.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/knob_active.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/22px/track.png +0 -0
- data/lib/frameworks/sproutcore/themes/ace/resources/slider/ace/track.png +0 -0
@@ -0,0 +1,2560 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2014 7x7 Software Inc. All rights reserved.
|
4
|
+
// Portions ©2008-2011 Apple Inc. All rights reserved.
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
|
+
// ==========================================================================
|
7
|
+
sc_require('views/scroller');
|
8
|
+
|
9
|
+
|
10
|
+
SC.SCROLL = {
|
11
|
+
|
12
|
+
/**
|
13
|
+
The rate of deceleration in pixels per square millisecond after scrolling from a drag gesture.
|
14
|
+
|
15
|
+
@static
|
16
|
+
@type Number
|
17
|
+
@default 3.0
|
18
|
+
*/
|
19
|
+
DRAG_SCROLL_DECELERATION: 3.0,
|
20
|
+
|
21
|
+
/**
|
22
|
+
The number of pixels a gesture needs to move before it should be considered a scroll gesture.
|
23
|
+
|
24
|
+
@static
|
25
|
+
@type Number
|
26
|
+
@default 5
|
27
|
+
*/
|
28
|
+
SCROLL_GESTURE_THRESHOLD: 5,
|
29
|
+
|
30
|
+
/**
|
31
|
+
The number of pixels a gesture needs to move in only a single direction, before it should be
|
32
|
+
considered as a locked scrolling direction (i.e. no gestures in the other direction will scroll
|
33
|
+
in that direction).
|
34
|
+
|
35
|
+
@static
|
36
|
+
@type Number
|
37
|
+
@default 50
|
38
|
+
*/
|
39
|
+
SCROLL_LOCK_GESTURE_THRESHOLD: 50,
|
40
|
+
|
41
|
+
/**
|
42
|
+
The number of pixels a gesture needs to expand or contract before it should be considered a scale gesture.
|
43
|
+
|
44
|
+
@static
|
45
|
+
@type Number
|
46
|
+
@default 5
|
47
|
+
*/
|
48
|
+
SCALE_GESTURE_THRESHOLD: 3
|
49
|
+
|
50
|
+
};
|
51
|
+
|
52
|
+
|
53
|
+
/** @class
|
54
|
+
Implements a complete scroll view. SproutCore implements its own JS-based scrolling in order
|
55
|
+
to unify scrolling behavior across platforms, and to enable progressive rendering (via the
|
56
|
+
clipping frame) during scroll on all devices.
|
57
|
+
|
58
|
+
Important Properties
|
59
|
+
-----
|
60
|
+
|
61
|
+
ScrollView positions its contentView according to three properties: `verticalScrollOffset`,
|
62
|
+
`horizontalScrollOffset`, and `scale`. These properties are bindable and observable, but you
|
63
|
+
should not override them.
|
64
|
+
|
65
|
+
Gutter vs. Overlaid Scrollers
|
66
|
+
-----
|
67
|
+
|
68
|
+
Scroll views use swappable scroll-bar views with various behavior (see `verticalScrollerView`
|
69
|
+
and `horizontalScrollerView`). `SC.ScrollerView` is a gutter-based scroller which persists and
|
70
|
+
takes up fourteen pixels. (By default, no scroller is shown for content that is too small to
|
71
|
+
scroll; see `autohidesHorizontalScroller` and `autohidesVerticalScroller`.) `SC.OverlayScrollerView`
|
72
|
+
is a gutterless view which fades when not scrolling. If you would like your view to always have
|
73
|
+
OS X-style fading overlaid scrollers, you can use the following:
|
74
|
+
|
75
|
+
SC.ScrollView.extend({
|
76
|
+
horizontalOverlay: true,
|
77
|
+
verticalOverlay: true
|
78
|
+
});
|
79
|
+
|
80
|
+
@extends SC.View
|
81
|
+
@since SproutCore 1.0
|
82
|
+
*/
|
83
|
+
SC.ScrollView = SC.View.extend({
|
84
|
+
/** @scope SC.ScrollView.prototype */
|
85
|
+
|
86
|
+
// ---------------------------------------------------------------------------------------------
|
87
|
+
// Properties
|
88
|
+
//
|
89
|
+
|
90
|
+
/** @private Flag used to determine whether to animate the adjustment. */
|
91
|
+
_sc_animationDuration: null,
|
92
|
+
|
93
|
+
/** @private The animation timing to use. */
|
94
|
+
_sc_animationTiming: null,
|
95
|
+
|
96
|
+
/** @private The cached height of the container. */
|
97
|
+
_sc_containerHeight: 0,
|
98
|
+
|
99
|
+
/** @private The cached offset of the container. */
|
100
|
+
_sc_containerOffset: null,
|
101
|
+
|
102
|
+
/** @private The cached width of the container. */
|
103
|
+
_sc_containerWidth: 0,
|
104
|
+
|
105
|
+
/** @private The cached height of the content. */
|
106
|
+
_sc_contentHeight: 0,
|
107
|
+
|
108
|
+
/** @private Flag used to react accordingly when the content's height changes. */
|
109
|
+
_sc_contentHeightDidChange: false,
|
110
|
+
|
111
|
+
/** @private The cached scale of the content. */
|
112
|
+
_sc_contentScale: 1,
|
113
|
+
|
114
|
+
/** @private Flag used to react accordingly when the content's scale changes. */
|
115
|
+
_sc_contentScaleDidChange: false,
|
116
|
+
|
117
|
+
/** @private The cached width of the content. */
|
118
|
+
_sc_contentWidth: 0,
|
119
|
+
|
120
|
+
/** @private Flag used to react accordingly when the content's width changes. */
|
121
|
+
_sc_contentWidthDidChange: false,
|
122
|
+
|
123
|
+
/** @private The anchor horizontal offset of the touch gesture. */
|
124
|
+
_sc_gestureAnchorHOffset: null,
|
125
|
+
|
126
|
+
/** @private The anchor position of the initial touch gesture. */
|
127
|
+
_sc_gestureAnchorTotalD: null,
|
128
|
+
|
129
|
+
/** @private The anchor position of the initial touch gesture. */
|
130
|
+
_sc_gestureAnchorTotalX: null,
|
131
|
+
|
132
|
+
/** @private The anchor position of the initial touch gesture. */
|
133
|
+
_sc_gestureAnchorTotalY: null,
|
134
|
+
|
135
|
+
/** @private The anchor vertical offset of the touch gesture. */
|
136
|
+
_sc_gestureAnchorVOffset: null,
|
137
|
+
|
138
|
+
/** @private The anchor position of the last touch gesture. */
|
139
|
+
_sc_gestureAnchorX: null,
|
140
|
+
|
141
|
+
/** @private The anchor position of the last touch gesture. */
|
142
|
+
_sc_gestureAnchorY: null,
|
143
|
+
|
144
|
+
/** @private The anchor distance from center of the last touch gesture. */
|
145
|
+
_sc_gestureAnchorD: null,
|
146
|
+
|
147
|
+
/** @private The original scale before a touch gesture. */
|
148
|
+
_sc_gestureAnchorScale: null,
|
149
|
+
|
150
|
+
/** @private The timer used to fade out this scroller. */
|
151
|
+
_sc_horizontalFadeOutTimer: null,
|
152
|
+
|
153
|
+
/** @private The actual horizontal scroll offset. */
|
154
|
+
_sc_horizontalScrollOffset: null,
|
155
|
+
|
156
|
+
/** @private The percentage offset scrolled horizontally. Used to maintain the horizontal position when the content size changes. */
|
157
|
+
_sc_horizontalPct: null,
|
158
|
+
|
159
|
+
/** @private Flag is true when scaling. Used in capturing touches. */
|
160
|
+
_sc_isTouchScaling: false,
|
161
|
+
|
162
|
+
/** @private Flag is true when scrolling horizontally. Used in capturing touches. */
|
163
|
+
_sc_isTouchScrollingH: false,
|
164
|
+
|
165
|
+
/** @private Flag is true when scrolling is locked to horizontal. */
|
166
|
+
_sc_isTouchScrollingHOnly: false,
|
167
|
+
|
168
|
+
/** @private Flag is true when scrolling vertically. Used in capturing touches. */
|
169
|
+
_sc_isTouchScrollingV: false,
|
170
|
+
|
171
|
+
/** @private Flag is true when scrolling is locked to vertical. */
|
172
|
+
_sc_isTouchScrollingVOnly: false,
|
173
|
+
|
174
|
+
/** @private The minimum delay before applying a fade transition. */
|
175
|
+
_sc_minimumFadeOutDelay: function () {
|
176
|
+
// The fade out delay is never less than 100ms (so that the current run loop can complete) and is never less than the fade in duration (so that it can fade fully in).
|
177
|
+
return Math.max(Math.max(this.get('fadeOutDelay') || 0, 0.1), this.get('fadeInDuration') || 0) * 1000;
|
178
|
+
}.property('fadeOutDelay').cacheable(),
|
179
|
+
|
180
|
+
/** @private The amount of slip while over dragging (drag past bounds). 1.0 or 100% would slip completely, and 0.0 or 0% would not slip at all. */
|
181
|
+
_sc_overDragSlip: 0.5,
|
182
|
+
|
183
|
+
/** @private Timer used to pass a touch through to its content if we don't start scrolling in that time. */
|
184
|
+
_sc_passTouchToContentTimer: null,
|
185
|
+
|
186
|
+
/** @private The actual scale. */
|
187
|
+
_sc_scale: null,
|
188
|
+
|
189
|
+
/** @private Flag used to indicate when we should resize the content width manually. */
|
190
|
+
_sc_shouldResizeContentWidth: false,
|
191
|
+
|
192
|
+
/** @private Flag used to indicate when we should resize the content height manually. */
|
193
|
+
_sc_shouldResizeContentHeight: false,
|
194
|
+
|
195
|
+
/** @private The offset center x of a multi-touch gesture. */
|
196
|
+
_sc_touchCenterX: null,
|
197
|
+
|
198
|
+
/** @private The offset center y of a multi-touch gesture. */
|
199
|
+
_sc_touchCenterY: null,
|
200
|
+
|
201
|
+
/** @private The timer used to fade out this scroller. */
|
202
|
+
_sc_verticalFadeOutTimer: null,
|
203
|
+
|
204
|
+
/** @private The actual vertical scroll offset. */
|
205
|
+
_sc_verticalScrollOffset: null,
|
206
|
+
|
207
|
+
/** @private The percentage offset scrolled vertically. Used to maintain the vertical position when the content size changes. */
|
208
|
+
_sc_verticalPct: null,
|
209
|
+
|
210
|
+
/** @see SC.View.prototype.acceptsMultitouch
|
211
|
+
|
212
|
+
@type Boolean
|
213
|
+
@default true
|
214
|
+
*/
|
215
|
+
acceptsMultitouch: true,
|
216
|
+
|
217
|
+
/** @private Animation curves. Kept private b/c it will likely become a computed property. */
|
218
|
+
animationCurveDecelerate: SC.easingCurve(0.35,0.34,0.84,1), // 'cubic-bezier(.35,.34,.84,1)', // http://cubic-bezier.com
|
219
|
+
|
220
|
+
/** @private Animation curves. Kept private b/c it will likely become a computed property. */
|
221
|
+
animationCurveReverse: SC.easingCurve(0.45,-0.47,0.73,1.3), // 'cubic-bezier(0.45,-0.47,0.73,1.3)',
|
222
|
+
|
223
|
+
/** @private Animation curves. Kept private b/c it will likely become a computed property. */
|
224
|
+
animationCurveSnap: SC.easingCurve(0.28,0.36,0.52,1), // 'cubic-bezier(.28,.36,.52,1)',
|
225
|
+
|
226
|
+
/**
|
227
|
+
If true, the horizontal scroller will automatically hide if the contentView is smaller than the
|
228
|
+
visible area. The `hasHorizontalScroller` property must be set to true in order for this property
|
229
|
+
to have any effect.
|
230
|
+
|
231
|
+
@type Boolean
|
232
|
+
@default true
|
233
|
+
*/
|
234
|
+
autohidesHorizontalScroller: true,
|
235
|
+
|
236
|
+
/**
|
237
|
+
If true, the vertical scroller will automatically hide if the contentView is smaller than the
|
238
|
+
visible area. The `hasVerticalScroller` property must be set to true in order for this property
|
239
|
+
to have any effect.
|
240
|
+
|
241
|
+
@type Boolean
|
242
|
+
@default true
|
243
|
+
*/
|
244
|
+
autohidesVerticalScroller: true,
|
245
|
+
|
246
|
+
/**
|
247
|
+
Determines whether scaling is allowed.
|
248
|
+
|
249
|
+
@type Boolean
|
250
|
+
@default false
|
251
|
+
*/
|
252
|
+
canScale: false,
|
253
|
+
|
254
|
+
/**
|
255
|
+
Returns true if the view has both a horizontal scroller and the scroller is visible.
|
256
|
+
|
257
|
+
@field
|
258
|
+
@type Boolean
|
259
|
+
@readonly
|
260
|
+
*/
|
261
|
+
canScrollHorizontal: function () {
|
262
|
+
return !!(this.get('hasHorizontalScroller') && // This property isn't bindable.
|
263
|
+
this.get('horizontalScrollerView') && // This property isn't bindable.
|
264
|
+
this.get('isHorizontalScrollerVisible'));
|
265
|
+
}.property('isHorizontalScrollerVisible').cacheable(),
|
266
|
+
|
267
|
+
/**
|
268
|
+
Returns true if the view has both a vertical scroller and the scroller is visible.
|
269
|
+
|
270
|
+
@field
|
271
|
+
@type Boolean
|
272
|
+
@readonly
|
273
|
+
*/
|
274
|
+
canScrollVertical: function () {
|
275
|
+
return !!(this.get('hasVerticalScroller') && // This property isn't bindable.
|
276
|
+
this.get('verticalScrollerView') && // This property isn't bindable.
|
277
|
+
this.get('isVerticalScrollerVisible'));
|
278
|
+
}.property('isVerticalScrollerVisible').cacheable(),
|
279
|
+
|
280
|
+
/**
|
281
|
+
@type Array
|
282
|
+
@default ['sc-scroll-view']
|
283
|
+
@see SC.View#classNames
|
284
|
+
*/
|
285
|
+
classNames: ['sc-scroll-view'],
|
286
|
+
|
287
|
+
/**
|
288
|
+
The container view that will wrap your content view. You can replace this property with your own
|
289
|
+
custom class if you prefer.
|
290
|
+
|
291
|
+
@type SC.ContainerView
|
292
|
+
@default SC.ContainerView
|
293
|
+
*/
|
294
|
+
containerView: SC.ContainerView,
|
295
|
+
|
296
|
+
/**
|
297
|
+
The content view you want the scroll view to manage.
|
298
|
+
|
299
|
+
@type SC.View
|
300
|
+
@default null
|
301
|
+
*/
|
302
|
+
contentView: null,
|
303
|
+
|
304
|
+
/**
|
305
|
+
The scroll deceleration rate.
|
306
|
+
|
307
|
+
@type Number
|
308
|
+
@default SC.SCROLL.DRAG_SCROLL_DECELERATION
|
309
|
+
*/
|
310
|
+
decelerationRate: SC.SCROLL.DRAG_SCROLL_DECELERATION,
|
311
|
+
|
312
|
+
/** @private
|
313
|
+
Whether to delay touches from passing through to the content. By default, if the touch moves enough to
|
314
|
+
trigger a scroll within 150ms, this view will retain control of the touch, and content views will not
|
315
|
+
have a chance to handle it. This is generally the behavior you want.
|
316
|
+
|
317
|
+
If you set this to NO, the touch will not trigger a scroll until you pass control back to this view via
|
318
|
+
`touch.restoreLastTouchResponder`, for example when the touch has dragged by a certain amount. You should
|
319
|
+
use this option only if you know what you're doing.
|
320
|
+
|
321
|
+
@type Boolean
|
322
|
+
@default true
|
323
|
+
*/
|
324
|
+
delaysContentTouches: true,
|
325
|
+
|
326
|
+
/**
|
327
|
+
Determines how long (in seconds) scrollbars wait before fading out.
|
328
|
+
|
329
|
+
@property Number
|
330
|
+
@default 0.4
|
331
|
+
*/
|
332
|
+
fadeOutDelay: 0.4,
|
333
|
+
|
334
|
+
/**
|
335
|
+
True if the view should maintain a horizontal scroller. This property must be set when the
|
336
|
+
view is created.
|
337
|
+
|
338
|
+
@type Boolean
|
339
|
+
@default true
|
340
|
+
*/
|
341
|
+
hasHorizontalScroller: true,
|
342
|
+
|
343
|
+
/**
|
344
|
+
True if the view should maintain a vertical scroller. This property must be set when the
|
345
|
+
view is created.
|
346
|
+
|
347
|
+
@type Boolean
|
348
|
+
@default true
|
349
|
+
*/
|
350
|
+
hasVerticalScroller: true,
|
351
|
+
|
352
|
+
/**
|
353
|
+
The horizontal alignment for non-filling content inside of the ScrollView. Possible values:
|
354
|
+
|
355
|
+
- SC.ALIGN_LEFT
|
356
|
+
- SC.ALIGN_RIGHT
|
357
|
+
- SC.ALIGN_CENTER
|
358
|
+
|
359
|
+
@type String
|
360
|
+
@default SC.ALIGN_CENTER
|
361
|
+
*/
|
362
|
+
horizontalAlign: SC.ALIGN_CENTER,
|
363
|
+
|
364
|
+
/**
|
365
|
+
Determines whether the horizontal scroller should fade out while in overlay mode. Has no effect
|
366
|
+
if `horizontalOverlay` is set to false.
|
367
|
+
|
368
|
+
@property Boolean
|
369
|
+
@default true
|
370
|
+
*/
|
371
|
+
horizontalFade: true,
|
372
|
+
|
373
|
+
/**
|
374
|
+
Amount to scroll one horizontal line.
|
375
|
+
|
376
|
+
Used by the default implementation of scrollLeftLine() and
|
377
|
+
scrollRightLine().
|
378
|
+
|
379
|
+
@type Number
|
380
|
+
@default 20
|
381
|
+
*/
|
382
|
+
horizontalLineScroll: 20,
|
383
|
+
|
384
|
+
/**
|
385
|
+
Use this to overlay the horizontal scroller.
|
386
|
+
|
387
|
+
This ensures that the content container will not resize to accommodate the horizontal scroller,
|
388
|
+
hence overlaying the scroller on top of the container.
|
389
|
+
|
390
|
+
@field
|
391
|
+
@type Boolean
|
392
|
+
@default true
|
393
|
+
*/
|
394
|
+
horizontalOverlay: false,
|
395
|
+
|
396
|
+
/**
|
397
|
+
Amount to scroll one horizontal page.
|
398
|
+
|
399
|
+
Used by the default implementation of scrollLeftPage() and scrollRightPage().
|
400
|
+
|
401
|
+
@field
|
402
|
+
@type Number
|
403
|
+
@default value of frame.width
|
404
|
+
@observes frame
|
405
|
+
*/
|
406
|
+
horizontalPageScroll: function () {
|
407
|
+
return this.get('frame').width;
|
408
|
+
}.property('frame'),
|
409
|
+
|
410
|
+
/**
|
411
|
+
The current horizontal scroll offset. Changing this value will update both the position of the
|
412
|
+
contentView and the horizontal scroller, if there is one.
|
413
|
+
|
414
|
+
@field
|
415
|
+
@type Number
|
416
|
+
@default 0
|
417
|
+
*/
|
418
|
+
horizontalScrollOffset: function (key, value) {
|
419
|
+
var containerWidth = this._sc_containerWidth,
|
420
|
+
contentWidth = this._sc_contentWidth,
|
421
|
+
min = this.get('minimumHorizontalScrollOffset'),
|
422
|
+
max = this.get('maximumHorizontalScrollOffset');
|
423
|
+
|
424
|
+
/* jshint eqnull:true */
|
425
|
+
if (value != null) {
|
426
|
+
// When touch scrolling, we allow scroll to pass the limits by a small amount.
|
427
|
+
if (!this._sc_isTouchScrollingH) {
|
428
|
+
// Constrain to the set limits.
|
429
|
+
value = Math.max(min, Math.min(max, value));
|
430
|
+
}
|
431
|
+
|
432
|
+
// Record the relative percentage offset for maintaining position while scaling.
|
433
|
+
if (contentWidth > 0) {
|
434
|
+
this._sc_horizontalPct = (value + (containerWidth / 2)) / contentWidth;
|
435
|
+
}
|
436
|
+
|
437
|
+
// Use the cached value.
|
438
|
+
} else {
|
439
|
+
value = this._sc_horizontalScrollOffset;
|
440
|
+
|
441
|
+
// Default value.
|
442
|
+
if (value == null) {
|
443
|
+
var horizontalAlign = this.get('initialHorizontalAlign');
|
444
|
+
|
445
|
+
value = this._sc_alignedHorizontalOffset(horizontalAlign, containerWidth, contentWidth);
|
446
|
+
}
|
447
|
+
}
|
448
|
+
|
449
|
+
// Update the actual value.
|
450
|
+
this._sc_horizontalScrollOffset = value;
|
451
|
+
|
452
|
+
return value;
|
453
|
+
}.property().cacheable(),
|
454
|
+
|
455
|
+
/**
|
456
|
+
Use to control the positioning of the horizontal scroller. If you do not set 'horizontalOverlay' to
|
457
|
+
true, then the content view will be automatically sized to meet the left edge of the vertical
|
458
|
+
scroller, wherever it may be.
|
459
|
+
|
460
|
+
This allows you to easily, for example, have “one pixel higher and one pixel lower” scroll bars
|
461
|
+
that blend into their parent views.
|
462
|
+
|
463
|
+
If you do set 'horizontalOverlay' to true, then the scroller view will “float on top” of the content view.
|
464
|
+
|
465
|
+
Example: { left: -1, bottom: 0, right: -1 }
|
466
|
+
|
467
|
+
@type Object
|
468
|
+
@default null
|
469
|
+
*/
|
470
|
+
horizontalScrollerLayout: null,
|
471
|
+
|
472
|
+
/**
|
473
|
+
The horizontal scroller view class. This will be replaced with a view instance when the
|
474
|
+
ScrollView is created unless `hasHorizontalScroller` is false.
|
475
|
+
|
476
|
+
If `horizontalOverlay` is `true`, the default view used will be an SC.OverlayScrollerView,
|
477
|
+
otherwise SC.ScrollerView will be used.
|
478
|
+
|
479
|
+
@type SC.View
|
480
|
+
@default SC.ScrollerView | SC.OverlayScrollerView
|
481
|
+
*/
|
482
|
+
horizontalScrollerView: null,
|
483
|
+
|
484
|
+
/**
|
485
|
+
Your content view's initial horizontal alignment, if wider than the container. This allows you to e.g.
|
486
|
+
center the content view when zoomed out, but begin with it zoomed in and left-aligned. If not specified,
|
487
|
+
defaults to value of `horizontalAlign`. May be:
|
488
|
+
|
489
|
+
- SC.ALIGN_LEFT
|
490
|
+
- SC.ALIGN_RIGHT
|
491
|
+
- SC.ALIGN_CENTER
|
492
|
+
|
493
|
+
@type String
|
494
|
+
@default SC.ALIGN_LEFT
|
495
|
+
*/
|
496
|
+
initialHorizontalAlign: SC.outlet('horizontalAlign'),
|
497
|
+
|
498
|
+
/**
|
499
|
+
Your content view's initial vertical alignment, if taller than the container. This allows you to e.g.
|
500
|
+
center the content view when zoomed out, but begin with it zoomed in and top-aligned. If not specified,
|
501
|
+
defaults to the value of `verticalAlign`. May be:
|
502
|
+
|
503
|
+
- SC.ALIGN_TOP
|
504
|
+
- SC.ALIGN_BOTTOM
|
505
|
+
- SC.ALIGN_MIDDLE
|
506
|
+
|
507
|
+
@type String
|
508
|
+
@default SC.ALIGN_TOP
|
509
|
+
*/
|
510
|
+
initialVerticalAlign: SC.outlet('verticalAlign'),
|
511
|
+
|
512
|
+
/**
|
513
|
+
True if the horizontal scroller should be visible. You can change this property value anytime to
|
514
|
+
show or hide the horizontal scroller. If you do not want to use a horizontal scroller at all, you
|
515
|
+
should instead set `hasHorizontalScroller` to false to avoid creating a scroller view in the first
|
516
|
+
place.
|
517
|
+
|
518
|
+
@type Boolean
|
519
|
+
@default true
|
520
|
+
*/
|
521
|
+
isHorizontalScrollerVisible: true,
|
522
|
+
|
523
|
+
/**
|
524
|
+
Walk like a duck.
|
525
|
+
|
526
|
+
@type Boolean
|
527
|
+
@default true
|
528
|
+
@readOnly
|
529
|
+
*/
|
530
|
+
isScrollable: true,
|
531
|
+
|
532
|
+
/**
|
533
|
+
True if the vertical scroller should be visible. You can change this property value anytime to
|
534
|
+
show or hide the vertical scroller. If you do not want to use a vertical scroller at all, you
|
535
|
+
should instead set `hasVerticalScroller` to false to avoid creating a scroller view in the first
|
536
|
+
place.
|
537
|
+
|
538
|
+
@type Boolean
|
539
|
+
@default true
|
540
|
+
*/
|
541
|
+
isVerticalScrollerVisible: true,
|
542
|
+
|
543
|
+
/**
|
544
|
+
The maximum horizontal scroll offset allowed given the current contentView size and the size of
|
545
|
+
the scroll view. If horizontal scrolling is disabled, this will always return 0.
|
546
|
+
|
547
|
+
@field
|
548
|
+
@type Number
|
549
|
+
@default 0
|
550
|
+
*/
|
551
|
+
maximumHorizontalScrollOffset: function () {
|
552
|
+
return Math.max(this._sc_contentWidth - this._sc_containerWidth, 0);
|
553
|
+
}.property('_sc_containerWidth', '_sc_contentWidth').cacheable(),
|
554
|
+
|
555
|
+
/**
|
556
|
+
The maximum scale.
|
557
|
+
|
558
|
+
@type Number
|
559
|
+
@default 2.0
|
560
|
+
*/
|
561
|
+
maximumScale: 2.0,
|
562
|
+
|
563
|
+
/**
|
564
|
+
The maximum vertical scroll offset allowed given the current contentView size and the size of
|
565
|
+
the scroll view. If vertical scrolling is disabled, this will always return 0 (or whatever
|
566
|
+
alignment dictates).
|
567
|
+
|
568
|
+
@field
|
569
|
+
@type Number
|
570
|
+
@default 0
|
571
|
+
*/
|
572
|
+
maximumVerticalScrollOffset: function () {
|
573
|
+
return Math.max(this._sc_contentHeight - this._sc_containerHeight, 0);
|
574
|
+
}.property('_sc_containerHeight', '_sc_contentHeight').cacheable(),
|
575
|
+
|
576
|
+
/**
|
577
|
+
The minimum horizontal scroll offset allowed given the current contentView size and the size of
|
578
|
+
the scroll view. If horizontal scrolling is disabled, this will always return 0 (or whatever alignment dictates).
|
579
|
+
|
580
|
+
@field
|
581
|
+
@type Number
|
582
|
+
@default 0
|
583
|
+
*/
|
584
|
+
minimumHorizontalScrollOffset: function () {
|
585
|
+
return Math.min(this._sc_contentWidth - this._sc_containerWidth, 0);
|
586
|
+
}.property('_sc_containerWidth', '_sc_contentWidth').cacheable(),
|
587
|
+
|
588
|
+
/**
|
589
|
+
The minimum scale.
|
590
|
+
|
591
|
+
@type Number
|
592
|
+
@default 0.25
|
593
|
+
*/
|
594
|
+
minimumScale: 0.25,
|
595
|
+
|
596
|
+
/**
|
597
|
+
The minimum vertical scroll offset allowed given the current contentView size and the size of
|
598
|
+
the scroll view. If vertical scrolling is disabled, this will always return 0 (or whatever alignment dictates).
|
599
|
+
|
600
|
+
@field
|
601
|
+
@type Number
|
602
|
+
@default 0
|
603
|
+
*/
|
604
|
+
minimumVerticalScrollOffset: function () {
|
605
|
+
return Math.min(this._sc_contentHeight - this._sc_containerHeight, 0);
|
606
|
+
}.property('_sc_containerHeight', '_sc_contentHeight').cacheable(),
|
607
|
+
|
608
|
+
/**
|
609
|
+
The current scale. Setting this will adjust the scale of the contentView.
|
610
|
+
|
611
|
+
If the contentView implements the SC.Scalable protocol, it will instead pass the scale to the contentView's
|
612
|
+
`applyScale` method instead.
|
613
|
+
|
614
|
+
Note that on platforms that allow bounce, setting scale outside of the minimum/maximumScale bounds will
|
615
|
+
result in a bounce. It is up to the developer to alert this view when the action is over and it should
|
616
|
+
bounce back.
|
617
|
+
|
618
|
+
@field
|
619
|
+
@type Number
|
620
|
+
@default 1.0
|
621
|
+
*/
|
622
|
+
scale: function (key, value) {
|
623
|
+
/* jshint eqnull:true */
|
624
|
+
if (value != null) {
|
625
|
+
if (!this.get('canScale')) {
|
626
|
+
value = 1;
|
627
|
+
} else {
|
628
|
+
var min = this.get('minimumScale'),
|
629
|
+
max = this.get('maximumScale');
|
630
|
+
|
631
|
+
// When touch scaling, we allow scaling to pass the limits by a small amount.
|
632
|
+
if (this._sc_isTouchScaling) {
|
633
|
+
min = min - (min * 0.1);
|
634
|
+
max = max + (max * 0.1);
|
635
|
+
if ((value < min || value > max)) {
|
636
|
+
value = Math.min(Math.max(min, value), max);
|
637
|
+
}
|
638
|
+
|
639
|
+
// Constrain to the set limits.
|
640
|
+
} else {
|
641
|
+
if ((value < min || value > max)) {
|
642
|
+
value = Math.min(Math.max(min, value), max);
|
643
|
+
}
|
644
|
+
}
|
645
|
+
}
|
646
|
+
} else {
|
647
|
+
value = this._sc_scale;
|
648
|
+
|
649
|
+
// Default value.
|
650
|
+
if (value == null) {
|
651
|
+
value = 1;
|
652
|
+
}
|
653
|
+
}
|
654
|
+
|
655
|
+
// Update the actual value.
|
656
|
+
this._sc_scale = value;
|
657
|
+
|
658
|
+
return value;
|
659
|
+
}.property('canScale', 'minimumScale', 'maximumScale').cacheable(),
|
660
|
+
|
661
|
+
/**
|
662
|
+
This determines how much a gesture must pinch or spread apart (in pixels) before it is registered as a scale action.
|
663
|
+
|
664
|
+
You can change this value for all instances of SC.ScrollView in your application by overriding
|
665
|
+
`SC.SCROLL.SCALE_GESTURE_THRESHOLD` at launch time.
|
666
|
+
|
667
|
+
@type Number
|
668
|
+
@default SC.SCROLL.SCALE_GESTURE_THRESHOLD
|
669
|
+
*/
|
670
|
+
scaleGestureThreshold: SC.SCROLL.SCALE_GESTURE_THRESHOLD,
|
671
|
+
|
672
|
+
/**
|
673
|
+
This determines how far (in pixels) a gesture must move before it is registered as a scroll.
|
674
|
+
|
675
|
+
You can change this value for all instances of SC.ScrollView in your application by overriding
|
676
|
+
`SC.SCROLL.SCROLL_THRESHOLD` at launch time.
|
677
|
+
|
678
|
+
@type Number
|
679
|
+
@default SC.SCROLL.SCROLL_GESTURE_THRESHOLD
|
680
|
+
*/
|
681
|
+
scrollGestureThreshold: SC.SCROLL.SCROLL_GESTURE_THRESHOLD,
|
682
|
+
|
683
|
+
/**
|
684
|
+
Once a vertical or horizontal scroll has been triggered, this determines how far (in pixels) the gesture
|
685
|
+
must move on the other axis to trigger a two-axis scroll. If your scroll view's content is omnidirectional
|
686
|
+
(e.g. a map) you should set this value to 0.
|
687
|
+
|
688
|
+
You can change this value for all instances of SC.ScrollView in your application by overriding
|
689
|
+
`SC.SCROLL.SCROLL_LOCK_GESTURE_THRESHOLD` at launch time.
|
690
|
+
|
691
|
+
@type Number
|
692
|
+
@default SC.SCROLL.SCROLL_LOCK_GESTURE_THRESHOLD
|
693
|
+
*/
|
694
|
+
scrollLockGestureThreshold: SC.SCROLL.SCROLL_LOCK_GESTURE_THRESHOLD,
|
695
|
+
|
696
|
+
/** @private
|
697
|
+
Once a vertical or horizontal scroll has been triggered, this determines how far (in pixels) the gesture
|
698
|
+
must move on the other axis to trigger a two-axis scroll. If your scroll view's content is omnidirectional
|
699
|
+
(e.g. a map) you should set this value to 0.
|
700
|
+
|
701
|
+
You can change this value for all instances of SC.ScrollView in your application by overriding
|
702
|
+
`SC.SCROLL.TOUCH.DEFAULT_SECONDARY_SCROLL_THRESHOLD` at launch time.
|
703
|
+
|
704
|
+
@type Number
|
705
|
+
@default SC.SCROLL.TOUCH.DEFAULT_SECONDARY_SCROLL_THRESHOLD
|
706
|
+
*/
|
707
|
+
// scrollSecondaryGestureThreshold: SC.SCROLL.TOUCH.DEFAULT_SECONDARY_SCROLL_THRESHOLD,
|
708
|
+
|
709
|
+
/**
|
710
|
+
The vertical alignment for non-filling content inside of the ScrollView. Possible values:
|
711
|
+
|
712
|
+
- SC.ALIGN_TOP
|
713
|
+
- SC.ALIGN_BOTTOM
|
714
|
+
- SC.ALIGN_MIDDLE
|
715
|
+
|
716
|
+
@type String
|
717
|
+
@default SC.ALIGN_TOP
|
718
|
+
*/
|
719
|
+
verticalAlign: SC.ALIGN_TOP,
|
720
|
+
|
721
|
+
/**
|
722
|
+
Determines whether the vertical scroller should fade out while in overlay mode. Has no effect if
|
723
|
+
`verticalOverlay` is set to false.
|
724
|
+
|
725
|
+
@property Boolean
|
726
|
+
@default true
|
727
|
+
*/
|
728
|
+
verticalFade: true,
|
729
|
+
|
730
|
+
/**
|
731
|
+
Amount to scroll one vertical line.
|
732
|
+
|
733
|
+
Used by the default implementation of scrollDownLine() and scrollUpLine().
|
734
|
+
|
735
|
+
@type Number
|
736
|
+
@default 20
|
737
|
+
*/
|
738
|
+
verticalLineScroll: 20,
|
739
|
+
|
740
|
+
/**
|
741
|
+
Use this to overlay the vertical scroller.
|
742
|
+
|
743
|
+
This ensures that the content container will not resize to accommodate the vertical scroller,
|
744
|
+
hence overlaying the scroller on top of the container.
|
745
|
+
|
746
|
+
@field
|
747
|
+
@type Boolean
|
748
|
+
@default true
|
749
|
+
*/
|
750
|
+
verticalOverlay: false,
|
751
|
+
|
752
|
+
/**
|
753
|
+
Amount to scroll one vertical page.
|
754
|
+
|
755
|
+
Used by the default implementation of scrollUpPage() and scrollDownPage().
|
756
|
+
|
757
|
+
@field
|
758
|
+
@type Number
|
759
|
+
@default value of frame.height
|
760
|
+
@observes frame
|
761
|
+
*/
|
762
|
+
verticalPageScroll: function () {
|
763
|
+
return this.get('frame').height;
|
764
|
+
}.property('frame'),
|
765
|
+
|
766
|
+
/**
|
767
|
+
The current vertical scroll offset. Changing this value will update both the position of the
|
768
|
+
contentView and the vertical scroller, if there is one.
|
769
|
+
|
770
|
+
@field
|
771
|
+
@type Number
|
772
|
+
@default 0
|
773
|
+
*/
|
774
|
+
verticalScrollOffset: function (key, value) {
|
775
|
+
var containerHeight = this._sc_containerHeight,
|
776
|
+
contentHeight = this._sc_contentHeight,
|
777
|
+
min = this.get('minimumVerticalScrollOffset'),
|
778
|
+
max = this.get('maximumVerticalScrollOffset');
|
779
|
+
|
780
|
+
/* jshint eqnull:true */
|
781
|
+
if (value != null) {
|
782
|
+
|
783
|
+
// When touch scrolling, we allow scroll to pass the limits by a small amount.
|
784
|
+
if (!this._sc_isTouchScrollingV) {
|
785
|
+
// Constrain to the set limits.
|
786
|
+
value = Math.max(min, Math.min(max, value));
|
787
|
+
}
|
788
|
+
|
789
|
+
// Record the relative percentage offset for maintaining position while scaling.
|
790
|
+
if (contentHeight > 0) {
|
791
|
+
this._sc_verticalPct = (value + (containerHeight / 2)) / contentHeight;
|
792
|
+
}
|
793
|
+
|
794
|
+
// Use the cached value.
|
795
|
+
} else {
|
796
|
+
value = this._sc_verticalScrollOffset;
|
797
|
+
|
798
|
+
// Default value.
|
799
|
+
if (value == null) {
|
800
|
+
var verticalAlign = this.get('initialVerticalAlign');
|
801
|
+
|
802
|
+
value = this._sc_alignedVerticalOffset(verticalAlign, containerHeight, contentHeight);
|
803
|
+
}
|
804
|
+
}
|
805
|
+
|
806
|
+
// Update the actual value.
|
807
|
+
this._sc_verticalScrollOffset = value;
|
808
|
+
|
809
|
+
return value;
|
810
|
+
}.property().cacheable(),
|
811
|
+
|
812
|
+
/**
|
813
|
+
Use to control the positioning of the vertical scroller. If you do not set 'verticalOverlay' to
|
814
|
+
true, then the content view will be automatically sized to meet the left edge of the vertical
|
815
|
+
scroller, wherever it may be.
|
816
|
+
|
817
|
+
This allows you to easily, for example, have “one pixel higher and one pixel lower” scroll bars
|
818
|
+
that blend into their parent views.
|
819
|
+
|
820
|
+
If you do set 'verticalOverlay' to true, then the scroller view will “float on top” of the content view.
|
821
|
+
|
822
|
+
Example: { top: -1, bottom: -1, right: 0 }
|
823
|
+
|
824
|
+
@type Object
|
825
|
+
@default null
|
826
|
+
*/
|
827
|
+
verticalScrollerLayout: null,
|
828
|
+
|
829
|
+
/**
|
830
|
+
The vertical scroller view class. This will be replaced with a view instance when the
|
831
|
+
ScrollView is created unless `hasVerticalScroller` is false.
|
832
|
+
|
833
|
+
If `verticalOverlay` is `true`, the default view used will be an SC.OverlayScrollerView,
|
834
|
+
otherwise SC.ScrollerView will be used.
|
835
|
+
|
836
|
+
@type SC.View
|
837
|
+
@default SC.ScrollerView | SC.OverlayScrollerView
|
838
|
+
*/
|
839
|
+
verticalScrollerView: null,
|
840
|
+
|
841
|
+
// ---------------------------------------------------------------------------------------------
|
842
|
+
// Methods
|
843
|
+
//
|
844
|
+
|
845
|
+
/** @private Aligns the content horizontally. */
|
846
|
+
_sc_alignedHorizontalOffset: function (horizontalAlign, containerWidth, contentWidth) {
|
847
|
+
switch (horizontalAlign) {
|
848
|
+
case SC.ALIGN_RIGHT:
|
849
|
+
return 0 - (containerWidth - contentWidth);
|
850
|
+
case SC.ALIGN_CENTER:
|
851
|
+
return 0 - ((containerWidth - contentWidth) / 2);
|
852
|
+
default: // SC.ALIGN_LEFT
|
853
|
+
return 0;
|
854
|
+
}
|
855
|
+
},
|
856
|
+
|
857
|
+
/** @private Aligns the content vertically. */
|
858
|
+
_sc_alignedVerticalOffset: function (verticalAlign, containerHeight, contentHeight) {
|
859
|
+
switch (verticalAlign) {
|
860
|
+
case SC.ALIGN_BOTTOM:
|
861
|
+
return 0 - (containerHeight - contentHeight);
|
862
|
+
case SC.ALIGN_MIDDLE:
|
863
|
+
return 0 - ((containerHeight - contentHeight) / 2);
|
864
|
+
default: // SC.ALIGN_TOP
|
865
|
+
return 0;
|
866
|
+
}
|
867
|
+
},
|
868
|
+
|
869
|
+
/** @private Manually animates the content view. */
|
870
|
+
_sc_animateContentView: function (contentAdjustMap) {
|
871
|
+
var easingCurve = this._sc_animationTiming,
|
872
|
+
totalDuration = this._sc_animationDuration * 1000,
|
873
|
+
start = new Date(),
|
874
|
+
contentView = this.get('contentView'),
|
875
|
+
contentViewLayout = contentView.get('layout'),
|
876
|
+
leftStart = contentViewLayout.left,
|
877
|
+
leftDelta = contentAdjustMap.left - leftStart,
|
878
|
+
scaleStart = contentViewLayout.scale,
|
879
|
+
scaleDelta = contentAdjustMap.scale - scaleStart,
|
880
|
+
topStart = contentViewLayout.top,
|
881
|
+
topDelta = contentAdjustMap.top - topStart,
|
882
|
+
self = this;
|
883
|
+
|
884
|
+
function animationFrame() {
|
885
|
+
if (self._sc_isAnimating) {
|
886
|
+
var duration = new Date() - start,
|
887
|
+
percent = Math.min(duration / totalDuration, 1); // Capped at 100%
|
888
|
+
|
889
|
+
SC.run(function () {
|
890
|
+
var currentLeft = leftStart + leftDelta * easingCurve.value(percent),
|
891
|
+
currentScale = scaleStart + scaleDelta * easingCurve.value(percent),
|
892
|
+
currentTop = topStart + topDelta * easingCurve.value(percent);
|
893
|
+
|
894
|
+
contentAdjustMap.left = currentLeft;
|
895
|
+
contentAdjustMap.top = currentTop;
|
896
|
+
contentAdjustMap.scale = currentScale;
|
897
|
+
|
898
|
+
contentView.adjust(contentAdjustMap);
|
899
|
+
});
|
900
|
+
|
901
|
+
// Keep animating as long as we haven't hit 100%.
|
902
|
+
if (percent < 1) {
|
903
|
+
window.requestAnimationFrame(animationFrame);
|
904
|
+
} else {
|
905
|
+
// Clear out the animation flags.
|
906
|
+
self._sc_isAnimating = false;
|
907
|
+
self._sc_animationDuration = null;
|
908
|
+
self._sc_animationTiming = null;
|
909
|
+
}
|
910
|
+
}
|
911
|
+
}
|
912
|
+
|
913
|
+
// Start the animation.
|
914
|
+
self._sc_isAnimating = true;
|
915
|
+
animationFrame();
|
916
|
+
},
|
917
|
+
|
918
|
+
/* @private Cancels any content view animation if it exists. */
|
919
|
+
_sc_cancelAnimation: function () {
|
920
|
+
if (this._sc_isAnimating) {
|
921
|
+
var contentView = this.get('contentView');
|
922
|
+
|
923
|
+
// UNUSED. Animate using SC.View.prototype.animate. Cancelling the animation in place proved problematic.
|
924
|
+
// if (contentView.get('viewState') === SC.CoreView.ATTACHED_SHOWN_ANIMATING) {
|
925
|
+
// // Stop the animation in place.
|
926
|
+
// contentView.cancelAnimation(SC.LayoutState.CURRENT);
|
927
|
+
|
928
|
+
var curLayout = contentView.get('layout');
|
929
|
+
|
930
|
+
// Update offsets to match actual placement.
|
931
|
+
this.set('horizontalScrollOffset', -curLayout.left);
|
932
|
+
this.set('verticalScrollOffset', -curLayout.top);
|
933
|
+
this.set('scale', curLayout.scale);
|
934
|
+
|
935
|
+
// Clear out the animation flags.
|
936
|
+
this._sc_isAnimating = false;
|
937
|
+
this._sc_animationDuration = null;
|
938
|
+
this._sc_animationTiming = null;
|
939
|
+
}
|
940
|
+
|
941
|
+
},
|
942
|
+
|
943
|
+
/** @private Reposition our content view if necessary according to aligment. */
|
944
|
+
_sc_containerViewFrameDidChange: function () {
|
945
|
+
// Run the content view size change code (updates min & max offsets, sets content alignment if necessary, shows scrollers if necessary)
|
946
|
+
var containerFrame = this.getPath('containerView.frame'),
|
947
|
+
contentView = this.get('contentView');
|
948
|
+
|
949
|
+
// Cache the current height and width of the container view, so we can only watch for size changes.
|
950
|
+
this.set('_sc_containerHeight', containerFrame.height);
|
951
|
+
this.set('_sc_containerWidth', containerFrame.width);
|
952
|
+
|
953
|
+
if (contentView) {
|
954
|
+
var didAdjust = false;
|
955
|
+
|
956
|
+
if (this._sc_shouldResizeContentHeight) {
|
957
|
+
contentView.adjust('height', containerFrame.height);
|
958
|
+
didAdjust = true;
|
959
|
+
}
|
960
|
+
|
961
|
+
if (this._sc_shouldResizeContentWidth) {
|
962
|
+
contentView.adjust('width', containerFrame.width);
|
963
|
+
didAdjust = true;
|
964
|
+
}
|
965
|
+
|
966
|
+
// Update the scrollers regardless.
|
967
|
+
if (!didAdjust) { this._sc_contentViewSizeDidChange(); }
|
968
|
+
}
|
969
|
+
|
970
|
+
},
|
971
|
+
|
972
|
+
/** @private Whenever the contentView of the container changes, set up new observers and clean up old observers. */
|
973
|
+
_sc_contentViewDidChange: function () {
|
974
|
+
var newView = this.get('contentView'), // Our content view.
|
975
|
+
containerView = this.get('containerView'),
|
976
|
+
frameChangeFunc = this._sc_contentViewFrameDidChange;
|
977
|
+
|
978
|
+
// Clean up observers on the previous content view.
|
979
|
+
this._sc_removeContentViewObservers();
|
980
|
+
|
981
|
+
// Reset caches.
|
982
|
+
this._sc_shouldResizeContentWidth = false;
|
983
|
+
this._sc_shouldResizeContentHeight = false;
|
984
|
+
this._sc_contentHeight = 0;
|
985
|
+
this._sc_contentWidth = 0;
|
986
|
+
this._sc_contentScale = 1;
|
987
|
+
|
988
|
+
// Assign the content view to our container view. This ensures that it is instantiated.
|
989
|
+
containerView.set('contentView', newView);
|
990
|
+
newView = this.contentView = containerView.get('contentView'); // Actual content view.
|
991
|
+
|
992
|
+
if (newView) {
|
993
|
+
/* jshint eqnull:true */
|
994
|
+
|
995
|
+
// Be wary of content views that replace their layers.
|
996
|
+
// newView.addObserver('layer', this, layerChangeFunc);
|
997
|
+
|
998
|
+
if (!newView.useStaticLayout) {
|
999
|
+
// Ensure that scale transforms occur from the top-left corner (per our math).
|
1000
|
+
newView.adjust({
|
1001
|
+
transformOriginX: 0,
|
1002
|
+
transformOriginY: 0
|
1003
|
+
});
|
1004
|
+
|
1005
|
+
// When a view wants an accelerated layer and isn't a fixed size, we convert it to a fixed
|
1006
|
+
// size and resize it when our container resizes.
|
1007
|
+
if (!newView.get('isFixedSize')) {
|
1008
|
+
var contentViewLayout = newView.get('layout');
|
1009
|
+
|
1010
|
+
// Fix the width.
|
1011
|
+
if (contentViewLayout.width == null) {
|
1012
|
+
this._sc_shouldResizeContentWidth = true; // Flag to indicate that when the container's width changes, we should update the content's width.
|
1013
|
+
|
1014
|
+
newView.adjust({
|
1015
|
+
right: null,
|
1016
|
+
width: this._sc_containerWidth
|
1017
|
+
});
|
1018
|
+
}
|
1019
|
+
|
1020
|
+
// Fix the height.
|
1021
|
+
if (contentViewLayout.height == null) {
|
1022
|
+
this._sc_shouldResizeContentHeight = true; // Flag to indicate that when the container's height changes, we should update the content's height.
|
1023
|
+
|
1024
|
+
newView.adjust({
|
1025
|
+
bottom: null,
|
1026
|
+
height: this._sc_containerHeight
|
1027
|
+
});
|
1028
|
+
}
|
1029
|
+
}
|
1030
|
+
}
|
1031
|
+
|
1032
|
+
// TODO: Can we remove this if a calculated property exists?
|
1033
|
+
newView.addObserver('frame', this, frameChangeFunc);
|
1034
|
+
|
1035
|
+
// Initialize once.
|
1036
|
+
this._sc_contentViewFrameDidChange();
|
1037
|
+
}
|
1038
|
+
|
1039
|
+
// Cache the current content view so that we can properly clean up when it changes.
|
1040
|
+
this._sc_contentView = newView;
|
1041
|
+
},
|
1042
|
+
|
1043
|
+
/** @private */
|
1044
|
+
// _sc_contentViewLayerDidChange: function () {
|
1045
|
+
// ???
|
1046
|
+
// },
|
1047
|
+
|
1048
|
+
/** @private Check frame changes for size changes. */
|
1049
|
+
_sc_contentViewFrameDidChange: function () {
|
1050
|
+
var lastHeight = this._sc_contentHeight,
|
1051
|
+
lastScale = this._sc_contentScale,
|
1052
|
+
lastWidth = this._sc_contentWidth,
|
1053
|
+
newFrame = this.getPath('contentView.borderFrame');
|
1054
|
+
|
1055
|
+
if (newFrame) {
|
1056
|
+
// Determine whether the scale has changed.
|
1057
|
+
if (lastScale !== newFrame.scale) {
|
1058
|
+
this._sc_contentScaleDidChange = true;
|
1059
|
+
this.set('_sc_contentScale', newFrame.scale);
|
1060
|
+
}
|
1061
|
+
|
1062
|
+
if (lastWidth !== newFrame.width) {
|
1063
|
+
this._sc_contentWidthDidChange = true;
|
1064
|
+
this.set('_sc_contentWidth', newFrame.width);
|
1065
|
+
}
|
1066
|
+
|
1067
|
+
if (lastHeight !== newFrame.height) {
|
1068
|
+
this._sc_contentHeightDidChange = true;
|
1069
|
+
this.set('_sc_contentHeight', newFrame.height);
|
1070
|
+
}
|
1071
|
+
|
1072
|
+
// If any of the size values changed, update.
|
1073
|
+
if (this._sc_contentScaleDidChange || this._sc_contentWidthDidChange || this._sc_contentHeightDidChange) {
|
1074
|
+
// Filter the observer input.
|
1075
|
+
this.invokeOnce(this._sc_contentViewSizeDidChange);
|
1076
|
+
}
|
1077
|
+
}
|
1078
|
+
},
|
1079
|
+
|
1080
|
+
/** @private When the content view's size changes, we need to update our scroll offset properties. */
|
1081
|
+
_sc_contentViewSizeDidChange: function () {
|
1082
|
+
var maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset'),
|
1083
|
+
maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset'),
|
1084
|
+
containerHeight, containerWidth,
|
1085
|
+
contentHeight, contentWidth;
|
1086
|
+
|
1087
|
+
containerHeight = this._sc_containerHeight;
|
1088
|
+
containerWidth = this._sc_containerWidth;
|
1089
|
+
contentHeight = this._sc_contentHeight;
|
1090
|
+
contentWidth = this._sc_contentWidth;
|
1091
|
+
|
1092
|
+
var value;
|
1093
|
+
if (contentWidth) {
|
1094
|
+
if (maximumHorizontalScrollOffset === 0) {
|
1095
|
+
// Align horizontally.
|
1096
|
+
value = this._sc_alignedHorizontalOffset(this.get('horizontalAlign'), containerWidth, contentWidth);
|
1097
|
+
this.set('horizontalScrollOffset', value); // Note: Trigger for _sc_scrollOffsetHorizontalDidChange
|
1098
|
+
|
1099
|
+
} else {
|
1100
|
+
/* jshint eqnull:true */
|
1101
|
+
// If the horizontal position has never been set, use the initial alignment.
|
1102
|
+
if (this._sc_horizontalPct == null) {
|
1103
|
+
this._sc_horizontalScrollOffset = null;
|
1104
|
+
this.notifyPropertyChange('horizontalScrollOffset');
|
1105
|
+
|
1106
|
+
// If the scale of the content view changes, we want to maintain relative position so that zooming remains centered.
|
1107
|
+
} else if (this._sc_contentScaleDidChange) {
|
1108
|
+
if (this._sc_touchCenterX != null) {
|
1109
|
+
value = (this._sc_horizontalPct * contentWidth) - this._sc_touchCenterX;
|
1110
|
+
} else {
|
1111
|
+
value = (this._sc_horizontalPct * contentWidth) - (containerWidth / 2);
|
1112
|
+
}
|
1113
|
+
this.set('horizontalScrollOffset', value); // Note: Trigger for _sc_scrollOffsetHorizontalDidChange
|
1114
|
+
|
1115
|
+
// Live scale gesture. Update the anchor so that the scroll deltas are calculated correctly.
|
1116
|
+
if (this._sc_gestureAnchorHOffset != null) {
|
1117
|
+
this._sc_gestureAnchorHOffset = value;
|
1118
|
+
}
|
1119
|
+
}
|
1120
|
+
}
|
1121
|
+
}
|
1122
|
+
|
1123
|
+
if (contentHeight) {
|
1124
|
+
if (maximumVerticalScrollOffset === 0) {
|
1125
|
+
// Align vertically.
|
1126
|
+
value = this._sc_alignedVerticalOffset(this.get('verticalAlign'), containerHeight, contentHeight);
|
1127
|
+
this.set('verticalScrollOffset', value); // Note: Trigger for _sc_scrollOffsetHorizontalDidChange
|
1128
|
+
|
1129
|
+
} else {
|
1130
|
+
/* jshint eqnull:true */
|
1131
|
+
// If the vertical position has never been set, use the initial alignment.
|
1132
|
+
if (this._sc_verticalPct == null) {
|
1133
|
+
this._sc_verticalScrollOffset = null;
|
1134
|
+
this.notifyPropertyChange('verticalScrollOffset');
|
1135
|
+
|
1136
|
+
// If the scale of the content view changes, we want to maintain relative position so that zooming remains centered.
|
1137
|
+
} else if (this._sc_contentScaleDidChange) {
|
1138
|
+
if (this._sc_touchCenterY != null) {
|
1139
|
+
value = (this._sc_verticalPct * contentHeight) - this._sc_touchCenterY;
|
1140
|
+
} else {
|
1141
|
+
value = (this._sc_verticalPct * contentHeight) - (containerHeight / 2);
|
1142
|
+
}
|
1143
|
+
this.set('verticalScrollOffset', value); // Note: Trigger for _sc_scrollOffsetVerticalDidChange
|
1144
|
+
|
1145
|
+
// Live scale gesture. Update the anchor so that the scroll deltas are calculated correctly.
|
1146
|
+
if (this._sc_gestureAnchorVOffset != null) {
|
1147
|
+
this._sc_gestureAnchorVOffset = value;
|
1148
|
+
}
|
1149
|
+
}
|
1150
|
+
}
|
1151
|
+
}
|
1152
|
+
|
1153
|
+
// Reset our flags.
|
1154
|
+
this._sc_contentScaleDidChange = false;
|
1155
|
+
this._sc_contentHeightDidChange = false;
|
1156
|
+
this._sc_contentWidthDidChange = false;
|
1157
|
+
|
1158
|
+
// TODO: Updating scrollers may change the container size, which will cause this to run again. Can we bring
|
1159
|
+
// this into a single call?
|
1160
|
+
this._sc_updateScrollers();
|
1161
|
+
},
|
1162
|
+
|
1163
|
+
/** @private Fade in the horizontal scroller. Each scroller fades in/out independently. */
|
1164
|
+
_sc_fadeInHorizontalScroller: function () {
|
1165
|
+
var canScrollHorizontal = this.get('canScrollHorizontal'),
|
1166
|
+
horizontalScroller = this.get('horizontalScrollerView'),
|
1167
|
+
delay;
|
1168
|
+
|
1169
|
+
if (canScrollHorizontal && horizontalScroller && horizontalScroller.get('fadeIn')) {
|
1170
|
+
if (this._sc_horizontalFadeOutTimer) {
|
1171
|
+
// Reschedule the current timer (avoid creating a new instance).
|
1172
|
+
this._sc_horizontalFadeOutTimer.startTime = null;
|
1173
|
+
this._sc_horizontalFadeOutTimer.schedule();
|
1174
|
+
} else {
|
1175
|
+
// Fade in.
|
1176
|
+
horizontalScroller.fadeIn();
|
1177
|
+
|
1178
|
+
// Wait the minimum time before fading out again.
|
1179
|
+
delay = this.get('_sc_minimumFadeOutDelay');
|
1180
|
+
this._sc_horizontalFadeOutTimer = this.invokeLater(this._sc_fadeOutHorizontalScroller, delay);
|
1181
|
+
}
|
1182
|
+
}
|
1183
|
+
},
|
1184
|
+
|
1185
|
+
/** @private Fade in the vertical scroller. Each scroller fades in/out independently. */
|
1186
|
+
_sc_fadeInVerticalScroller: function () {
|
1187
|
+
var canScrollVertical = this.get('canScrollVertical'),
|
1188
|
+
verticalScroller = this.get('verticalScrollerView'),
|
1189
|
+
delay;
|
1190
|
+
|
1191
|
+
if (canScrollVertical && verticalScroller && verticalScroller.get('fadeIn')) {
|
1192
|
+
if (this._sc_verticalFadeOutTimer) {
|
1193
|
+
// Reschedule the current timer (avoid creating a new instance).
|
1194
|
+
this._sc_verticalFadeOutTimer.startTime = null;
|
1195
|
+
this._sc_verticalFadeOutTimer.schedule();
|
1196
|
+
|
1197
|
+
} else {
|
1198
|
+
// Fade in.
|
1199
|
+
verticalScroller.fadeIn();
|
1200
|
+
|
1201
|
+
// Wait the minimum time before fading out again.
|
1202
|
+
delay = this.get('_sc_minimumFadeOutDelay');
|
1203
|
+
this._sc_verticalFadeOutTimer = this.invokeLater(this._sc_fadeOutVerticalScroller, delay);
|
1204
|
+
}
|
1205
|
+
}
|
1206
|
+
},
|
1207
|
+
|
1208
|
+
/** @private Fade out the horizontal scroller. */
|
1209
|
+
_sc_fadeOutHorizontalScroller: function () {
|
1210
|
+
var horizontalScroller = this.get('horizontalScrollerView');
|
1211
|
+
|
1212
|
+
if (horizontalScroller && horizontalScroller.get('fadeOut')) {
|
1213
|
+
// Fade out.
|
1214
|
+
horizontalScroller.fadeOut();
|
1215
|
+
}
|
1216
|
+
|
1217
|
+
this._sc_horizontalFadeOutTimer = null;
|
1218
|
+
},
|
1219
|
+
|
1220
|
+
/** @private Fade out the vertical scroller. */
|
1221
|
+
_sc_fadeOutVerticalScroller: function () {
|
1222
|
+
var verticalScroller = this.get('verticalScrollerView');
|
1223
|
+
|
1224
|
+
if (verticalScroller && verticalScroller.get('fadeOut')) {
|
1225
|
+
// Fade out.
|
1226
|
+
verticalScroller.fadeOut();
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
this._sc_verticalFadeOutTimer = null;
|
1230
|
+
},
|
1231
|
+
|
1232
|
+
/** @private Adjust the content alignment horizontally on change. */
|
1233
|
+
_sc_horizontalAlignDidChange: function () {
|
1234
|
+
var maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset');
|
1235
|
+
|
1236
|
+
// Align horizontally (Unless content width is zero).
|
1237
|
+
if (maximumHorizontalScrollOffset === 0 && this._sc_contentWidth) {
|
1238
|
+
var horizontalAlign = this.get('horizontalAlign'),
|
1239
|
+
value;
|
1240
|
+
|
1241
|
+
value = this._sc_alignedHorizontalOffset(horizontalAlign, this._sc_containerWidth, this._sc_contentWidth);
|
1242
|
+
this.set('horizontalScrollOffset', value);
|
1243
|
+
}
|
1244
|
+
},
|
1245
|
+
|
1246
|
+
/** @private
|
1247
|
+
Calculates the maximum offset given content and container sizes, and the
|
1248
|
+
alignment.
|
1249
|
+
*/
|
1250
|
+
_sc_maximumScrollOffset: function (contentSize, containerSize, align, canScroll) {
|
1251
|
+
// If we can't scroll, we pretend our content size is no larger than the container.
|
1252
|
+
if (canScroll === NO) contentSize = Math.min(contentSize, containerSize);
|
1253
|
+
|
1254
|
+
// if our content size is larger than or the same size as the container, it's quite
|
1255
|
+
// simple to calculate the answer. Otherwise, we need to do some fancy-pants
|
1256
|
+
// alignment logic (read: simple math)
|
1257
|
+
if (contentSize >= containerSize) return contentSize - containerSize;
|
1258
|
+
|
1259
|
+
// alignment, yeah
|
1260
|
+
if (align === SC.ALIGN_LEFT || align === SC.ALIGN_TOP) {
|
1261
|
+
// if we left-align something, and it is smaller than the view, does that not mean
|
1262
|
+
// that it's maximum (and minimum) offset is 0, because it should be positioned at 0?
|
1263
|
+
return 0;
|
1264
|
+
} else if (align === SC.ALIGN_MIDDLE || align === SC.ALIGN_CENTER) {
|
1265
|
+
// middle align means the difference divided by two, because we want equal parts on each side.
|
1266
|
+
return 0 - Math.round((containerSize - contentSize) / 2);
|
1267
|
+
} else {
|
1268
|
+
// right align means the entire difference, because we want all that space on the left
|
1269
|
+
return 0 - (containerSize - contentSize);
|
1270
|
+
}
|
1271
|
+
},
|
1272
|
+
|
1273
|
+
/** @private
|
1274
|
+
Calculates the minimum offset given content and container sizes, and the
|
1275
|
+
alignment.
|
1276
|
+
*/
|
1277
|
+
_sc_minimumScrollOffset: function (contentSize, containerSize, align, canScroll) {
|
1278
|
+
// If we can't scroll, we pretend our content size is no larger than the container.
|
1279
|
+
if (canScroll === NO) contentSize = Math.min(contentSize, containerSize);
|
1280
|
+
|
1281
|
+
// if the content is larger than the container, we have no need to change the minimum
|
1282
|
+
// away from the natural 0 position.
|
1283
|
+
if (contentSize > containerSize) return 0;
|
1284
|
+
|
1285
|
+
// alignment, yeah
|
1286
|
+
if (align === SC.ALIGN_LEFT || align === SC.ALIGN_TOP) {
|
1287
|
+
// if we left-align something, and it is smaller than the view, does that not mean
|
1288
|
+
// that it's maximum (and minimum) offset is 0, because it should be positioned at 0?
|
1289
|
+
return 0;
|
1290
|
+
} else if (align === SC.ALIGN_MIDDLE || align === SC.ALIGN_CENTER) {
|
1291
|
+
// middle align means the difference divided by two, because we want equal parts on each side.
|
1292
|
+
return 0 - Math.round((containerSize - contentSize) / 2);
|
1293
|
+
} else {
|
1294
|
+
// right align means the entire difference, because we want all that space on the left
|
1295
|
+
return 0 - (containerSize - contentSize);
|
1296
|
+
}
|
1297
|
+
},
|
1298
|
+
|
1299
|
+
/** @private Registers/deregisters view with SC.Drag for autoscrolling. */
|
1300
|
+
_sc_registerAutoscroll: function () {
|
1301
|
+
if (this.get('isVisibleInWindow') && this.get('isEnabledInPane')) {
|
1302
|
+
SC.Drag.addScrollableView(this);
|
1303
|
+
} else {
|
1304
|
+
SC.Drag.removeScrollableView(this);
|
1305
|
+
}
|
1306
|
+
},
|
1307
|
+
|
1308
|
+
/** @private Reposition the content view to match the current scroll offsets and scale. */
|
1309
|
+
_sc_repositionContentView: function () {
|
1310
|
+
var contentView = this.get('contentView');
|
1311
|
+
|
1312
|
+
if (contentView) {
|
1313
|
+
this.invokeOnce(this._sc_repositionContentViewUnfiltered);
|
1314
|
+
}
|
1315
|
+
},
|
1316
|
+
|
1317
|
+
/** @private Reposition the content view to match the current scroll offsets and scale. */
|
1318
|
+
_sc_repositionContentViewUnfiltered: function () {
|
1319
|
+
var containerView = this.get('containerView'),
|
1320
|
+
contentView = this.get('contentView'),
|
1321
|
+
horizontalScrollOffset = this.get('horizontalScrollOffset'),
|
1322
|
+
verticalScrollOffset = this.get('verticalScrollOffset'),
|
1323
|
+
scale = this.get('scale');
|
1324
|
+
|
1325
|
+
// If the content is statically laid out, use margins in the container layer to move it.
|
1326
|
+
// TODO: Remove static layout support.
|
1327
|
+
if (contentView.useStaticLayout) {
|
1328
|
+
var containerViewLayer = containerView.get('layer');
|
1329
|
+
|
1330
|
+
// Set the margins on the layer.
|
1331
|
+
containerViewLayer.style.marginLeft = -horizontalScrollOffset + 'px';
|
1332
|
+
containerViewLayer.style.marginTop = -verticalScrollOffset + 'px';
|
1333
|
+
|
1334
|
+
// Otherwise call adjust on the content.
|
1335
|
+
} else {
|
1336
|
+
// Constrain the offsets to full (actual) pixels to prevent blurry text et cetera. Note that this assumes
|
1337
|
+
// that the scroll view itself is living at a scale of 1, and may give blurry subpixel results if scaled.
|
1338
|
+
var horizontalAlign = this.get('horizontalAlign'),
|
1339
|
+
verticalAlign = this.get('verticalAlign'),
|
1340
|
+
left, top;
|
1341
|
+
|
1342
|
+
left = -horizontalScrollOffset;
|
1343
|
+
|
1344
|
+
// Round according to the alignment to avoid jitter at the edges. For example, we don't want 0.55 rounding up to 1 when left aligned. This also prevents implied percentage values (i.e. 0.0 > value > 1.0 == %)!
|
1345
|
+
switch (horizontalAlign) {
|
1346
|
+
case SC.ALIGN_CENTER:
|
1347
|
+
left = Math.round(left);
|
1348
|
+
break;
|
1349
|
+
case SC.ALIGN_RIGHT:
|
1350
|
+
left = Math.ceil(left);
|
1351
|
+
break;
|
1352
|
+
default: // SC.ALIGN_LEFT
|
1353
|
+
left = Math.floor(left);
|
1354
|
+
}
|
1355
|
+
|
1356
|
+
top = -verticalScrollOffset;
|
1357
|
+
|
1358
|
+
switch (verticalAlign) {
|
1359
|
+
case SC.ALIGN_MIDDLE:
|
1360
|
+
top = Math.round(top);
|
1361
|
+
break;
|
1362
|
+
case SC.ALIGN_BOTTOM:
|
1363
|
+
top = Math.ceil(top);
|
1364
|
+
break;
|
1365
|
+
default: // SC.ALIGN_TOP
|
1366
|
+
top = Math.floor(top);
|
1367
|
+
}
|
1368
|
+
|
1369
|
+
// Cancel any active animation in place.
|
1370
|
+
// this._sc_cancelAnimation();
|
1371
|
+
|
1372
|
+
var contentAdjustMap = SC.ScrollView._SC_CONTENT_ADJUST_MAP; // Shared object used to avoid continually initializing/destroying objects.
|
1373
|
+
|
1374
|
+
// Create the content adjust map once. Note: This is a shared object, all properties must be overwritten each time.
|
1375
|
+
if (!contentAdjustMap) { contentAdjustMap = SC.ScrollView._SC_CONTENT_ADJUST_MAP = {}; }
|
1376
|
+
|
1377
|
+
contentAdjustMap.left = left;
|
1378
|
+
contentAdjustMap.top = top;
|
1379
|
+
contentAdjustMap.scale = scale;
|
1380
|
+
|
1381
|
+
if (this._sc_animationDuration) {
|
1382
|
+
// UNUSED. Animate using SC.View.prototype.animate. Cancelling the animation in place proved problematic.
|
1383
|
+
// contentView.animate({ left: left, top: top, scale: scale }, {
|
1384
|
+
// duration: this._sc_animationDuration,
|
1385
|
+
// timing: this._sc_animationTiming
|
1386
|
+
// });
|
1387
|
+
|
1388
|
+
// // Run the animation immediately (don't wait for next Run Loop).
|
1389
|
+
// // Note: The next run loop will be queued none-the-less, so we may want to avoid that entirely in the future.
|
1390
|
+
// contentView._animate();
|
1391
|
+
this._sc_animateContentView(contentAdjustMap);
|
1392
|
+
|
1393
|
+
} else {
|
1394
|
+
contentView.adjust(contentAdjustMap);
|
1395
|
+
}
|
1396
|
+
}
|
1397
|
+
},
|
1398
|
+
|
1399
|
+
/** @private Re-position the scrollers and content depending on the need to scroll or not. */
|
1400
|
+
_sc_repositionScrollers: function () {
|
1401
|
+
this.invokeOnce(this._sc_repositionScrollersUnfiltered);
|
1402
|
+
},
|
1403
|
+
|
1404
|
+
/** @private Re-position the scrollers and content depending on the need to scroll or not. */
|
1405
|
+
_sc_repositionScrollersUnfiltered: function () {
|
1406
|
+
var hasHorizontalScroller = this.get('hasHorizontalScroller'),
|
1407
|
+
hasVerticalScroller = this.get('hasVerticalScroller'),
|
1408
|
+
canScrollHorizontal = this.get('canScrollHorizontal'),
|
1409
|
+
canScrollVertical = this.get('canScrollVertical'),
|
1410
|
+
containerLayoutMap = SC.ScrollView._SC_CONTAINER_LAYOUT_MAP, // Shared object used to avoid continually initializing/destroying objects.
|
1411
|
+
horizontalScrollerView = this.get('horizontalScrollerView'),
|
1412
|
+
horizontalScrollerHeight = horizontalScrollerView && canScrollHorizontal ? horizontalScrollerView.get('scrollbarThickness') : 0,
|
1413
|
+
verticalScrollerView = this.get('verticalScrollerView'),
|
1414
|
+
verticalScrollerWidth = verticalScrollerView && canScrollVertical ? verticalScrollerView.get('scrollbarThickness') : 0,
|
1415
|
+
layout; // The new layout to be applied to each scroller.
|
1416
|
+
|
1417
|
+
// Create the container layout map once. Note: This is a shared object, all properties must be overwritten each time.
|
1418
|
+
if (!containerLayoutMap) { containerLayoutMap = SC.ScrollView._SC_CONTAINER_LAYOUT_MAP = {}; }
|
1419
|
+
|
1420
|
+
// Set the standard.
|
1421
|
+
containerLayoutMap.bottom = 0;
|
1422
|
+
containerLayoutMap.right = 0;
|
1423
|
+
|
1424
|
+
// Adjust the horizontal scroller.
|
1425
|
+
if (hasHorizontalScroller) {
|
1426
|
+
var horizontalOverlay = this.get('horizontalOverlay'),
|
1427
|
+
horizontalScrollerLayout = this.get('horizontalScrollerLayout');
|
1428
|
+
|
1429
|
+
// Adjust the scroller view accordingly. Allow for a custom default scroller layout to be set.
|
1430
|
+
if (horizontalScrollerLayout) {
|
1431
|
+
layout = {
|
1432
|
+
left: horizontalScrollerLayout.left,
|
1433
|
+
bottom: horizontalScrollerLayout.bottom,
|
1434
|
+
right: horizontalScrollerLayout.right + verticalScrollerWidth,
|
1435
|
+
height: horizontalScrollerHeight
|
1436
|
+
};
|
1437
|
+
} else {
|
1438
|
+
layout = {
|
1439
|
+
left: 0,
|
1440
|
+
bottom: 0,
|
1441
|
+
right: verticalScrollerWidth,
|
1442
|
+
height: horizontalScrollerHeight
|
1443
|
+
};
|
1444
|
+
}
|
1445
|
+
horizontalScrollerView.set('layout', layout);
|
1446
|
+
|
1447
|
+
// Adjust the content view accordingly.
|
1448
|
+
if (canScrollHorizontal && !horizontalOverlay) {
|
1449
|
+
containerLayoutMap.bottom = horizontalScrollerHeight;
|
1450
|
+
}
|
1451
|
+
|
1452
|
+
// Set the visibility of the scroller immediately.
|
1453
|
+
horizontalScrollerView.set('isVisible', canScrollHorizontal);
|
1454
|
+
this._sc_fadeInHorizontalScroller();
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
// Adjust the vertical scroller.
|
1458
|
+
if (hasVerticalScroller) {
|
1459
|
+
var verticalOverlay = this.get('verticalOverlay'),
|
1460
|
+
verticalScrollerLayout = this.get('verticalScrollerLayout');
|
1461
|
+
|
1462
|
+
// Adjust the scroller view accordingly. Allow for a custom default scroller layout to be set.
|
1463
|
+
if (verticalScrollerLayout) {
|
1464
|
+
layout = {
|
1465
|
+
top: verticalScrollerLayout.top,
|
1466
|
+
right: verticalScrollerLayout.right,
|
1467
|
+
bottom: verticalScrollerLayout.bottom + horizontalScrollerHeight,
|
1468
|
+
width: verticalScrollerWidth
|
1469
|
+
};
|
1470
|
+
} else {
|
1471
|
+
layout = {
|
1472
|
+
top: 0,
|
1473
|
+
right: 0,
|
1474
|
+
bottom: horizontalScrollerHeight,
|
1475
|
+
width: verticalScrollerWidth
|
1476
|
+
};
|
1477
|
+
}
|
1478
|
+
verticalScrollerView.set('layout', layout);
|
1479
|
+
|
1480
|
+
// Prepare to adjust the content view accordingly.
|
1481
|
+
if (canScrollVertical && !verticalOverlay) {
|
1482
|
+
containerLayoutMap.right = verticalScrollerWidth;
|
1483
|
+
}
|
1484
|
+
|
1485
|
+
// Set the visibility of the scroller immediately.
|
1486
|
+
verticalScrollerView.set('isVisible', canScrollVertical);
|
1487
|
+
this._sc_fadeInVerticalScroller();
|
1488
|
+
}
|
1489
|
+
|
1490
|
+
// Adjust the container view accordingly (i.e. to make space for scrollers or take space back).
|
1491
|
+
var containerView = this.get('containerView');
|
1492
|
+
containerView.adjust(containerLayoutMap);
|
1493
|
+
},
|
1494
|
+
|
1495
|
+
/** @private Clean up observers on the content view. */
|
1496
|
+
_sc_removeContentViewObservers: function () {
|
1497
|
+
var oldView = this._sc_contentView,
|
1498
|
+
frameChangeFunc = this._sc_contentViewFrameDidChange;
|
1499
|
+
// layerChangeFunc = this._sc_contentViewLayerDidChange;
|
1500
|
+
|
1501
|
+
if (oldView) {
|
1502
|
+
oldView.removeObserver('frame', this, frameChangeFunc);
|
1503
|
+
// oldView.removeObserver('layer', this, layerChangeFunc);
|
1504
|
+
|
1505
|
+
this._sc_shouldResizeContentWidth = false;
|
1506
|
+
this._sc_shouldResizeContentHeight = false;
|
1507
|
+
}
|
1508
|
+
},
|
1509
|
+
|
1510
|
+
/** @private Whenever the scale changes, update the scrollers and adjust the location of the content view. */
|
1511
|
+
_sc_scaleDidChange: function () {
|
1512
|
+
var contentView = this.get('contentView'),
|
1513
|
+
scale = this.get('scale');
|
1514
|
+
|
1515
|
+
// If the content is statically laid out, use margins in the container layer to move it.
|
1516
|
+
// TODO: Remove static layout support.
|
1517
|
+
if (contentView) {
|
1518
|
+
if (contentView.useStaticLayout) {
|
1519
|
+
//@if(debug)
|
1520
|
+
// If the scale is not 1 then assume the developer is trying to scale static content.
|
1521
|
+
if (scale !== 1) {
|
1522
|
+
SC.warn("Developer Warning: SC.ScrollView's `scale` feature does not support statically laid out content views.");
|
1523
|
+
}
|
1524
|
+
//@endif
|
1525
|
+
|
1526
|
+
// Reposition the content view to apply the scale.
|
1527
|
+
} else {
|
1528
|
+
// Apply this change.
|
1529
|
+
this._sc_repositionContentView();
|
1530
|
+
}
|
1531
|
+
}
|
1532
|
+
},
|
1533
|
+
|
1534
|
+
/** @private Whenever the scroll offsets change, update the scrollers and adjust the location of the content view. */
|
1535
|
+
_sc_scrollOffsetHorizontalDidChange: function () {
|
1536
|
+
this._sc_repositionContentView();
|
1537
|
+
this.invokeLast(this._sc_fadeInHorizontalScroller);
|
1538
|
+
},
|
1539
|
+
|
1540
|
+
/** @private Whenever the scroll offsets change, update the scrollers and adjust the location of the content view. */
|
1541
|
+
_sc_scrollOffsetVerticalDidChange: function () {
|
1542
|
+
this._sc_repositionContentView();
|
1543
|
+
this.invokeLast(this._sc_fadeInVerticalScroller);
|
1544
|
+
},
|
1545
|
+
|
1546
|
+
/** @private Update the scrollers. */
|
1547
|
+
_sc_updateScrollers: function () {
|
1548
|
+
var horizontalScrollerView = this.get('horizontalScrollerView'),
|
1549
|
+
verticalScrollerView = this.get('verticalScrollerView'),
|
1550
|
+
minimumHorizontalScrollOffset = this.get('minimumHorizontalScrollOffset'),
|
1551
|
+
minimumVerticalScrollOffset = this.get('minimumVerticalScrollOffset'),
|
1552
|
+
maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset'),
|
1553
|
+
maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset'),
|
1554
|
+
containerHeight, containerWidth,
|
1555
|
+
contentHeight, contentWidth;
|
1556
|
+
|
1557
|
+
containerHeight = this._sc_containerHeight;
|
1558
|
+
containerWidth = this._sc_containerWidth;
|
1559
|
+
contentHeight = this._sc_contentHeight;
|
1560
|
+
contentWidth = this._sc_contentWidth;
|
1561
|
+
|
1562
|
+
// Update the minimum and maximum scrollable distance on the scrollers as well as their visibility.
|
1563
|
+
var proportion;
|
1564
|
+
if (horizontalScrollerView) {
|
1565
|
+
horizontalScrollerView.set('minimum', minimumHorizontalScrollOffset);
|
1566
|
+
horizontalScrollerView.set('maximum', maximumHorizontalScrollOffset);
|
1567
|
+
|
1568
|
+
if (this.get('autohidesHorizontalScroller')) {
|
1569
|
+
this.setIfChanged('isHorizontalScrollerVisible', contentWidth > containerWidth);
|
1570
|
+
}
|
1571
|
+
|
1572
|
+
// Constrain the proportion to 100%.
|
1573
|
+
proportion = Math.min(containerWidth / contentWidth, 1.0);
|
1574
|
+
horizontalScrollerView.setIfChanged('proportion', proportion);
|
1575
|
+
}
|
1576
|
+
|
1577
|
+
if (verticalScrollerView) {
|
1578
|
+
verticalScrollerView.set('minimum', minimumVerticalScrollOffset);
|
1579
|
+
verticalScrollerView.set('maximum', maximumVerticalScrollOffset);
|
1580
|
+
|
1581
|
+
if (this.get('autohidesVerticalScroller')) {
|
1582
|
+
this.setIfChanged('isVerticalScrollerVisible', contentHeight > containerHeight);
|
1583
|
+
}
|
1584
|
+
|
1585
|
+
// Constrain the proportion to 100%.
|
1586
|
+
proportion = Math.min(containerHeight / contentHeight, 1.0);
|
1587
|
+
verticalScrollerView.setIfChanged('proportion', proportion);
|
1588
|
+
}
|
1589
|
+
},
|
1590
|
+
|
1591
|
+
/** @private Adjust the content alignment vertically on change. */
|
1592
|
+
_sc_verticalAlignDidChange: function () {
|
1593
|
+
var maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset');
|
1594
|
+
|
1595
|
+
// Align vertically (Unless content height is zero).
|
1596
|
+
if (maximumVerticalScrollOffset === 0 && this._sc_contentHeight) {
|
1597
|
+
var verticalAlign = this.get('verticalAlign'),
|
1598
|
+
value;
|
1599
|
+
|
1600
|
+
value = this._sc_alignedVerticalOffset(verticalAlign, this._sc_containerHeight, this._sc_contentHeight);
|
1601
|
+
this.set('verticalScrollOffset', value);
|
1602
|
+
}
|
1603
|
+
},
|
1604
|
+
|
1605
|
+
/** @private Instantiate the container view and the scrollers as needed. */
|
1606
|
+
createChildViews: function () {
|
1607
|
+
var childViews = [];
|
1608
|
+
|
1609
|
+
// Set up the container view.
|
1610
|
+
var containerView = this.get('containerView');
|
1611
|
+
|
1612
|
+
//@if(debug)
|
1613
|
+
// Provide some debug-mode only developer support to prevent problems.
|
1614
|
+
if (!containerView) {
|
1615
|
+
throw new Error("Developer Error: SC.ScrollView must have a containerView class set before it is instantiated.");
|
1616
|
+
}
|
1617
|
+
//@endif
|
1618
|
+
|
1619
|
+
containerView = this.containerView = this.createChildView(containerView, {
|
1620
|
+
contentView: this.contentView // Initialize the view with the currently set container view.
|
1621
|
+
});
|
1622
|
+
this.contentView = containerView.get('contentView'); // Replace our content view with the instantiated version.
|
1623
|
+
childViews.push(containerView);
|
1624
|
+
|
1625
|
+
// Set up the scrollers.
|
1626
|
+
var scrollerView;
|
1627
|
+
|
1628
|
+
// Create a horizontal scroller view if needed.
|
1629
|
+
if (!this.get('hasHorizontalScroller')) {
|
1630
|
+
// Remove the class entirely.
|
1631
|
+
this.horizontalScrollerView = null;
|
1632
|
+
} else {
|
1633
|
+
scrollerView = this.get('horizontalScrollerView');
|
1634
|
+
|
1635
|
+
// Use a default scroller view.
|
1636
|
+
/* jshint eqnull:true */
|
1637
|
+
if (scrollerView == null) {
|
1638
|
+
scrollerView = this.get('horizontalOverlay') ? SC.OverlayScrollerView : SC.ScrollerView;
|
1639
|
+
}
|
1640
|
+
|
1641
|
+
// Replace the class property with an instance.
|
1642
|
+
scrollerView = this.horizontalScrollerView = this.createChildView(scrollerView, {
|
1643
|
+
isVisible: !this.get('autohidesHorizontalScroller'),
|
1644
|
+
layoutDirection: SC.LAYOUT_HORIZONTAL,
|
1645
|
+
value: this.get('horizontalScrollOffset'),
|
1646
|
+
valueBinding: '.owner.horizontalScrollOffset', // Bind the value of the scroller to our horizontal offset.
|
1647
|
+
minimum: this.get('minimumHorizontalScrollOffset'),
|
1648
|
+
maximum: this.get('maximumHorizontalScrollOffset')
|
1649
|
+
});
|
1650
|
+
|
1651
|
+
// Add the scroller view to the child views array.
|
1652
|
+
childViews.push(scrollerView);
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
// Create a vertical scroller view if needed.
|
1656
|
+
if (!this.get('hasVerticalScroller')) {
|
1657
|
+
// Remove the class entirely.
|
1658
|
+
this.verticalScrollerView = null;
|
1659
|
+
} else {
|
1660
|
+
scrollerView = this.get('verticalScrollerView');
|
1661
|
+
|
1662
|
+
// Use a default scroller view.
|
1663
|
+
/* jshint eqnull:true */
|
1664
|
+
if (scrollerView == null) {
|
1665
|
+
scrollerView = this.get('verticalOverlay') ? SC.OverlayScrollerView : SC.ScrollerView;
|
1666
|
+
}
|
1667
|
+
|
1668
|
+
// Replace the class property with an instance.
|
1669
|
+
scrollerView = this.verticalScrollerView = this.createChildView(scrollerView, {
|
1670
|
+
isVisible: !this.get('autohidesVerticalScroller'),
|
1671
|
+
layoutDirection: SC.LAYOUT_VERTICAL,
|
1672
|
+
value: this.get('verticalScrollOffset'),
|
1673
|
+
valueBinding: '.owner.verticalScrollOffset', // Bind the value of the scroller to our vertical offset.
|
1674
|
+
minimum: this.get('minimumVerticalScrollOffset'),
|
1675
|
+
maximum: this.get('maximumVerticalScrollOffset')
|
1676
|
+
});
|
1677
|
+
|
1678
|
+
// Add the scroller view to the child views array.
|
1679
|
+
childViews.push(scrollerView);
|
1680
|
+
}
|
1681
|
+
|
1682
|
+
// Set the childViews array.
|
1683
|
+
this.childViews = childViews;
|
1684
|
+
},
|
1685
|
+
|
1686
|
+
/** @private */
|
1687
|
+
destroy: function() {
|
1688
|
+
// Clean up.
|
1689
|
+
this._sc_removeContentViewObservers();
|
1690
|
+
this.removeObserver('contentView', this, this._sc_contentViewDidChange);
|
1691
|
+
|
1692
|
+
this.removeObserver('horizontalAlign', this, this._sc_horizontalAlignDidChange);
|
1693
|
+
this.removeObserver('verticalAlign', this, this._sc_verticalAlignDidChange);
|
1694
|
+
|
1695
|
+
sc_super();
|
1696
|
+
},
|
1697
|
+
|
1698
|
+
/** @private SC.View */
|
1699
|
+
didCreateLayer: function () {
|
1700
|
+
// Observe the scroll offsets for changes and initialize once.
|
1701
|
+
this.addObserver('horizontalScrollOffset', this, this._sc_scrollOffsetHorizontalDidChange);
|
1702
|
+
this.addObserver('verticalScrollOffset', this, this._sc_scrollOffsetVerticalDidChange);
|
1703
|
+
this._sc_scrollOffsetHorizontalDidChange();
|
1704
|
+
this._sc_scrollOffsetVerticalDidChange();
|
1705
|
+
|
1706
|
+
// Observe the scroller visibility properties for changes and initialize once.
|
1707
|
+
this.addObserver('isHorizontalScrollerVisible', this, this._sc_repositionScrollers);
|
1708
|
+
this.addObserver('isVerticalScrollerVisible', this, this._sc_repositionScrollers);
|
1709
|
+
this._sc_repositionScrollers();
|
1710
|
+
|
1711
|
+
// Observe the scale for changes and initialize once.
|
1712
|
+
this.addObserver('scale', this, this._sc_scaleDidChange);
|
1713
|
+
this._sc_scaleDidChange();
|
1714
|
+
|
1715
|
+
// Observe our container view frame for changes and initialize once.
|
1716
|
+
var containerView = this.get('containerView');
|
1717
|
+
containerView.addObserver('frame', this, this._sc_containerViewFrameDidChange);
|
1718
|
+
this._sc_containerViewFrameDidChange();
|
1719
|
+
|
1720
|
+
// Observe for changes in enablement and visibility for registering with SC.Drag auto-scrolling and initialize once.
|
1721
|
+
this.addObserver('isVisibleInWindow', this, this._sc_registerAutoscroll);
|
1722
|
+
this.addObserver('isEnabledInPane', this, this._sc_registerAutoscroll);
|
1723
|
+
this._sc_registerAutoscroll();
|
1724
|
+
},
|
1725
|
+
|
1726
|
+
/** SC.Object.prototype */
|
1727
|
+
init: function () {
|
1728
|
+
sc_super();
|
1729
|
+
|
1730
|
+
// Observe the content view for changes and initialize once.
|
1731
|
+
this.addObserver('contentView', this, this._sc_contentViewDidChange);
|
1732
|
+
this._sc_contentViewDidChange();
|
1733
|
+
|
1734
|
+
// Observe the alignment properties for changes. No need to initialize, the default alignment property
|
1735
|
+
// will be used.
|
1736
|
+
this.addObserver('horizontalAlign', this, this._sc_horizontalAlignDidChange);
|
1737
|
+
this.addObserver('verticalAlign', this, this._sc_verticalAlignDidChange);
|
1738
|
+
},
|
1739
|
+
|
1740
|
+
/**
|
1741
|
+
Scrolls the receiver in the horizontal and vertical directions by the amount specified, if
|
1742
|
+
allowed. The actual scroll amount will be constrained by the current scroll minimums and
|
1743
|
+
maximums. (If you wish to scroll outside of those bounds, you should call `scrollTo` directly.)
|
1744
|
+
|
1745
|
+
If you only want to scroll in one direction, pass null or 0 for the other direction.
|
1746
|
+
|
1747
|
+
@param {Number} x change in the x direction (or hash)
|
1748
|
+
@param {Number} y change in the y direction
|
1749
|
+
@returns {SC.ScrollView} receiver
|
1750
|
+
*/
|
1751
|
+
scrollBy: function (x, y) {
|
1752
|
+
// Normalize (deprecated).
|
1753
|
+
if (y === undefined && SC.typeOf(x) === SC.T_HASH) {
|
1754
|
+
//@if(debug)
|
1755
|
+
// Add some developer support. It's faster to pass the arguments individually so that we don't need to do this normalization and the
|
1756
|
+
// developer isn't creating an extra Object needlessly.
|
1757
|
+
SC.warn("Developer Warning: Passing an object to SC.ScrollView.scrollBy is deprecated. Please pass both the x and y arguments.");
|
1758
|
+
//@endif
|
1759
|
+
|
1760
|
+
y = x.y;
|
1761
|
+
x = x.x;
|
1762
|
+
}
|
1763
|
+
|
1764
|
+
// If null, undefined, or 0, pass null; otherwise just add current offset.
|
1765
|
+
x = (x) ? this.get('horizontalScrollOffset') + x : null;
|
1766
|
+
y = (y) ? this.get('verticalScrollOffset') + y : null;
|
1767
|
+
|
1768
|
+
// Constrain within min and max. (Calls to scrollBy are generally convenience calls that should not have to
|
1769
|
+
// worry about exceeding bounds and making the followup call. Features that want to allow overscroll should call
|
1770
|
+
// scrollTo directly.)
|
1771
|
+
if (x !== null) {
|
1772
|
+
x = Math.min(Math.max(this.get('minimumHorizontalScrollOffset'), x), this.get('maximumHorizontalScrollOffset'));
|
1773
|
+
}
|
1774
|
+
|
1775
|
+
if (y !== null) {
|
1776
|
+
y = Math.min(Math.max(this.get('minimumVerticalScrollOffset'), y), this.get('maximumVerticalScrollOffset'));
|
1777
|
+
}
|
1778
|
+
|
1779
|
+
return this.scrollTo(x, y);
|
1780
|
+
},
|
1781
|
+
|
1782
|
+
/**
|
1783
|
+
Scrolls the receiver down one or more lines if allowed. If number of
|
1784
|
+
lines is not specified, scrolls one line.
|
1785
|
+
|
1786
|
+
@param {Number} lines number of lines
|
1787
|
+
@returns {SC.ScrollView} receiver
|
1788
|
+
*/
|
1789
|
+
scrollDownLine: function (lines) {
|
1790
|
+
if (lines === undefined) lines = 1;
|
1791
|
+
return this.scrollBy(null, this.get('verticalLineScroll') * lines);
|
1792
|
+
},
|
1793
|
+
|
1794
|
+
/**
|
1795
|
+
Scrolls the receiver down one or more page if allowed. If number of
|
1796
|
+
pages is not specified, scrolls one page. The page size is determined by
|
1797
|
+
the verticalPageScroll value. By default this is the size of the current
|
1798
|
+
scrollable area.
|
1799
|
+
|
1800
|
+
@param {Number} pages number of lines
|
1801
|
+
@returns {SC.ScrollView} receiver
|
1802
|
+
*/
|
1803
|
+
scrollDownPage: function (pages) {
|
1804
|
+
if (pages === undefined) pages = 1;
|
1805
|
+
return this.scrollBy(null, this.get('verticalPageScroll') * pages);
|
1806
|
+
},
|
1807
|
+
|
1808
|
+
/**
|
1809
|
+
Scrolls the receiver left one or more lines if allowed. If number of
|
1810
|
+
lines is not specified, scrolls one line.
|
1811
|
+
|
1812
|
+
@param {Number} lines number of lines
|
1813
|
+
@returns {SC.ScrollView} receiver
|
1814
|
+
*/
|
1815
|
+
scrollLeftLine: function (lines) {
|
1816
|
+
if (lines === undefined) lines = 1;
|
1817
|
+
return this.scrollTo(0 - this.get('horizontalLineScroll') * lines, null);
|
1818
|
+
},
|
1819
|
+
|
1820
|
+
/**
|
1821
|
+
Scrolls the receiver left one or more page if allowed. If number of
|
1822
|
+
pages is not specified, scrolls one page. The page size is determined by
|
1823
|
+
the verticalPageScroll value. By default this is the size of the current
|
1824
|
+
scrollable area.
|
1825
|
+
|
1826
|
+
@param {Number} pages number of lines
|
1827
|
+
@returns {SC.ScrollView} receiver
|
1828
|
+
*/
|
1829
|
+
scrollLeftPage: function (pages) {
|
1830
|
+
if (pages === undefined) pages = 1;
|
1831
|
+
return this.scrollBy(0 - (this.get('horizontalPageScroll') * pages), null);
|
1832
|
+
},
|
1833
|
+
|
1834
|
+
/**
|
1835
|
+
Scrolls the receiver right one or more lines if allowed. If number of
|
1836
|
+
lines is not specified, scrolls one line.
|
1837
|
+
|
1838
|
+
@param {Number} lines number of lines
|
1839
|
+
@returns {SC.ScrollView} receiver
|
1840
|
+
*/
|
1841
|
+
scrollRightLine: function (lines) {
|
1842
|
+
if (lines === undefined) lines = 1;
|
1843
|
+
return this.scrollTo(this.get('horizontalLineScroll') * lines, null);
|
1844
|
+
},
|
1845
|
+
|
1846
|
+
/**
|
1847
|
+
Scrolls the receiver right one or more page if allowed. If number of
|
1848
|
+
pages is not specified, scrolls one page. The page size is determined by
|
1849
|
+
the verticalPageScroll value. By default this is the size of the current
|
1850
|
+
scrollable area.
|
1851
|
+
|
1852
|
+
@param {Number} pages number of lines
|
1853
|
+
@returns {SC.ScrollView} receiver
|
1854
|
+
*/
|
1855
|
+
scrollRightPage: function (pages) {
|
1856
|
+
if (pages === undefined) pages = 1;
|
1857
|
+
return this.scrollBy(this.get('horizontalPageScroll') * pages, null);
|
1858
|
+
},
|
1859
|
+
|
1860
|
+
/**
|
1861
|
+
Scrolls to the specified x,y coordinates. This should be the offset into the contentView that
|
1862
|
+
you want to appear at the top-left corner of the scroll view.
|
1863
|
+
|
1864
|
+
This method will contain the actual scroll based on whether the view can scroll in the named
|
1865
|
+
direction and the maximum distance it can scroll.
|
1866
|
+
|
1867
|
+
If you only want to scroll in one direction, pass null for the other direction.
|
1868
|
+
|
1869
|
+
@param {Number} x the x scroll location
|
1870
|
+
@param {Number} y the y scroll location
|
1871
|
+
@returns {SC.ScrollView} receiver
|
1872
|
+
*/
|
1873
|
+
scrollTo: function (x, y) {
|
1874
|
+
// Normalize (deprecated).
|
1875
|
+
if (y === undefined && SC.typeOf(x) === SC.T_HASH) {
|
1876
|
+
//@if(debug)
|
1877
|
+
// Add some developer support. It's faster to pass the arguments individually so that we don't need to do this normalization and the
|
1878
|
+
// developer isn't creating an extra Object needlessly.
|
1879
|
+
SC.warn("Developer Warning: Passing an object to SC.ScrollView.scrollTo is deprecated. Please pass both the x and y arguments.");
|
1880
|
+
//@endif
|
1881
|
+
|
1882
|
+
y = x.y;
|
1883
|
+
x = x.x;
|
1884
|
+
}
|
1885
|
+
|
1886
|
+
if (!SC.none(x)) {
|
1887
|
+
this.set('horizontalScrollOffset', x);
|
1888
|
+
}
|
1889
|
+
|
1890
|
+
if (!SC.none(y)) {
|
1891
|
+
this.set('verticalScrollOffset', y);
|
1892
|
+
}
|
1893
|
+
|
1894
|
+
return this;
|
1895
|
+
},
|
1896
|
+
|
1897
|
+
/**
|
1898
|
+
Scroll to the supplied rectangle.
|
1899
|
+
|
1900
|
+
If the rectangle is bigger than the viewport, the top-left
|
1901
|
+
will be preferred.
|
1902
|
+
|
1903
|
+
(Note that if your content is scaled, the rectangle must be
|
1904
|
+
relative to the contentView's scale, not the ScrollView's.)
|
1905
|
+
|
1906
|
+
@param {Rect} rect Rectangle to which to scroll.
|
1907
|
+
@returns {Boolean} YES if scroll position was changed.
|
1908
|
+
*/
|
1909
|
+
scrollToRect: function (rect) {
|
1910
|
+
// find current visible frame.
|
1911
|
+
var vo = SC.cloneRect(this.get('containerView').get('frame')),
|
1912
|
+
origX = this.get('horizontalScrollOffset'),
|
1913
|
+
origY = this.get('verticalScrollOffset'),
|
1914
|
+
scale = this.get('scale');
|
1915
|
+
|
1916
|
+
vo.x = origX;
|
1917
|
+
vo.y = origY;
|
1918
|
+
|
1919
|
+
// Scale rect.
|
1920
|
+
if (scale !== 1) {
|
1921
|
+
rect = SC.cloneRect(rect);
|
1922
|
+
rect.x *= scale;
|
1923
|
+
rect.y *= scale;
|
1924
|
+
rect.height *= scale;
|
1925
|
+
rect.width *= scale;
|
1926
|
+
}
|
1927
|
+
|
1928
|
+
// if bottom edge is not visible, shift origin
|
1929
|
+
vo.y += Math.max(0, SC.maxY(rect) - SC.maxY(vo));
|
1930
|
+
vo.x += Math.max(0, SC.maxX(rect) - SC.maxX(vo));
|
1931
|
+
|
1932
|
+
// if top edge is not visible, shift origin
|
1933
|
+
vo.y -= Math.max(0, SC.minY(vo) - SC.minY(rect));
|
1934
|
+
vo.x -= Math.max(0, SC.minX(vo) - SC.minX(rect));
|
1935
|
+
|
1936
|
+
// scroll to that origin.
|
1937
|
+
if ((origX !== vo.x) || (origY !== vo.y)) {
|
1938
|
+
this.scrollTo(vo.x, vo.y);
|
1939
|
+
return YES;
|
1940
|
+
} else {
|
1941
|
+
return NO;
|
1942
|
+
}
|
1943
|
+
},
|
1944
|
+
|
1945
|
+
/**
|
1946
|
+
Scrolls the receiver up one or more lines if allowed. If number of
|
1947
|
+
lines is not specified, scrolls one line.
|
1948
|
+
|
1949
|
+
@param {Number} lines number of lines
|
1950
|
+
@returns {SC.ScrollView} receiver
|
1951
|
+
*/
|
1952
|
+
scrollUpLine: function (lines) {
|
1953
|
+
if (lines === undefined) lines = 1;
|
1954
|
+
return this.scrollBy(null, 0 - this.get('verticalLineScroll') * lines);
|
1955
|
+
},
|
1956
|
+
|
1957
|
+
/**
|
1958
|
+
Scrolls the receiver up one or more page if allowed. If number of
|
1959
|
+
pages is not specified, scrolls one page. The page size is determined by
|
1960
|
+
the verticalPageScroll value. By default this is the size of the current
|
1961
|
+
scrollable area.
|
1962
|
+
|
1963
|
+
@param {Number} pages number of lines
|
1964
|
+
@returns {SC.ScrollView} receiver
|
1965
|
+
*/
|
1966
|
+
scrollUpPage: function (pages) {
|
1967
|
+
if (pages === undefined) pages = 1;
|
1968
|
+
return this.scrollBy(null, 0 - (this.get('verticalPageScroll') * pages));
|
1969
|
+
},
|
1970
|
+
|
1971
|
+
/**
|
1972
|
+
Scroll the view to make the view's frame visible. For this to make sense,
|
1973
|
+
the view should be a subview of the contentView. Otherwise the results
|
1974
|
+
will be undefined.
|
1975
|
+
|
1976
|
+
@param {SC.View} view view to scroll or null to scroll receiver visible
|
1977
|
+
@returns {Boolean} YES if scroll position was changed
|
1978
|
+
*/
|
1979
|
+
scrollToVisible: function (view) {
|
1980
|
+
|
1981
|
+
// if no view is passed, do default
|
1982
|
+
if (arguments.length === 0) return sc_super();
|
1983
|
+
|
1984
|
+
var contentView = this.get('contentView');
|
1985
|
+
if (!contentView) return NO; // nothing to do if no contentView.
|
1986
|
+
|
1987
|
+
// get the frame for the view - should work even for views with static
|
1988
|
+
// layout, assuming it has been added to the screen.
|
1989
|
+
var viewFrame = view.get('borderFrame');
|
1990
|
+
if (!viewFrame) return NO; // nothing to do
|
1991
|
+
|
1992
|
+
// convert view's frame to an offset from the contentView origin. This
|
1993
|
+
// will become the new scroll offset after some adjustment.
|
1994
|
+
viewFrame = contentView.convertFrameFromView(viewFrame, view.get('parentView'));
|
1995
|
+
|
1996
|
+
return this.scrollToRect(viewFrame);
|
1997
|
+
},
|
1998
|
+
|
1999
|
+
/** @private SC.View */
|
2000
|
+
willDestroyLayer: function () {
|
2001
|
+
// Clean up.
|
2002
|
+
this.removeObserver('horizontalScrollOffset', this, this._sc_scrollOffsetHorizontalDidChange);
|
2003
|
+
this.removeObserver('verticalScrollOffset', this, this._sc_scrollOffsetVerticalDidChange);
|
2004
|
+
this.removeObserver('isHorizontalScrollerVisible', this, this._sc_repositionScrollers);
|
2005
|
+
this.removeObserver('isVerticalScrollerVisible', this, this._sc_repositionScrollers);
|
2006
|
+
|
2007
|
+
this.removeObserver('scale', this, this._sc_scaleDidChange);
|
2008
|
+
|
2009
|
+
var containerView = this.get('containerView');
|
2010
|
+
containerView.removeObserver('frame', this, this._sc_containerViewFrameDidChange);
|
2011
|
+
|
2012
|
+
// Be sure to remove this view as a scrollable view for SC.Drag.
|
2013
|
+
this.removeObserver('isVisibleInWindow', this, this._sc_registerAutoscroll);
|
2014
|
+
this.removeObserver('isEnabledInPane', this, this._sc_registerAutoscroll);
|
2015
|
+
SC.Drag.removeScrollableView(this);
|
2016
|
+
},
|
2017
|
+
|
2018
|
+
// ---------------------------------------------------------------------------------------------
|
2019
|
+
// Interaction
|
2020
|
+
//
|
2021
|
+
|
2022
|
+
/** @private
|
2023
|
+
This method gives our descendent views a chance to capture the touch via captureTouch, and subsequently to handle the
|
2024
|
+
touch, via touchStart. If no view elects to do so, control is returned to the scroll view for standard scrolling.
|
2025
|
+
*/
|
2026
|
+
_sc_beginTouchesInContent: function (touch) {
|
2027
|
+
// Clean up.
|
2028
|
+
this._sc_passTouchToContentTimer = null;
|
2029
|
+
|
2030
|
+
// If the touch is not a scroll or scale, see if any of our descendent views want to handle the touch. If not,
|
2031
|
+
// we keep our existing respondership and all is well.
|
2032
|
+
if (!touch.captureTouch(this, true)) {
|
2033
|
+
touch.makeTouchResponder(touch.targetView, true, this);
|
2034
|
+
}
|
2035
|
+
},
|
2036
|
+
|
2037
|
+
/** @private */
|
2038
|
+
_sc_touchEnded: function (touch, wasCancelled) {
|
2039
|
+
// When the last touch ends, we stop touch scrolling.
|
2040
|
+
var hasTouch = this.get('hasTouch');
|
2041
|
+
if (hasTouch) {
|
2042
|
+
// Update the average distance to center of the touch to include the new touch. This is used to recognize pinch/zoom movement of the touch.
|
2043
|
+
var avgTouch = touch.averagedTouchesForView(this);
|
2044
|
+
|
2045
|
+
this._sc_gestureAnchorD = this._sc_gestureAnchorTotalD = avgTouch.d;
|
2046
|
+
this._sc_gestureAnchorX = this._sc_gestureAnchorTotalX = avgTouch.x;
|
2047
|
+
this._sc_gestureAnchorY = this._sc_gestureAnchorTotalY = avgTouch.y;
|
2048
|
+
|
2049
|
+
if (this._sc_containerOffset) {
|
2050
|
+
this._sc_touchCenterX = avgTouch.x - this._sc_containerOffset.x;
|
2051
|
+
this._sc_touchCenterY = avgTouch.y - this._sc_containerOffset.y;
|
2052
|
+
}
|
2053
|
+
|
2054
|
+
} else {
|
2055
|
+
|
2056
|
+
// If we were scrolling, continue scrolling at present velocity with deceleration.
|
2057
|
+
if (this._sc_isTouchScrollingV || this._sc_isTouchScrollingH || this._sc_isTouchScaling) {
|
2058
|
+
var decelerationRate = this.get('decelerationRate'),
|
2059
|
+
containerHeight = this._sc_containerHeight,
|
2060
|
+
containerWidth = this._sc_containerWidth,
|
2061
|
+
durationH = 0,
|
2062
|
+
durationV = 0,
|
2063
|
+
c2x, c2y;
|
2064
|
+
|
2065
|
+
if (this._sc_isTouchScrollingH) {
|
2066
|
+
var horizontalScrollOffset = this.get('horizontalScrollOffset'),
|
2067
|
+
maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset'),
|
2068
|
+
minimumHorizontalScrollOffset = this.get('minimumHorizontalScrollOffset'),
|
2069
|
+
horizontalVelocity = this._sc_touchVelocityH;
|
2070
|
+
|
2071
|
+
// Past the maximum.
|
2072
|
+
if (horizontalScrollOffset > maximumHorizontalScrollOffset) {
|
2073
|
+
this.set('horizontalScrollOffset', maximumHorizontalScrollOffset);
|
2074
|
+
|
2075
|
+
// Moving away from maximum. Change direction.
|
2076
|
+
if (horizontalVelocity < 0.2) {
|
2077
|
+
this._sc_animationTiming = this.get('animationCurveReverse');
|
2078
|
+
|
2079
|
+
// Stopped or moving back towards maximum. Maintain direction, snap at the end.
|
2080
|
+
} else {
|
2081
|
+
this._sc_animationTiming = this.get('animationCurveSnap');
|
2082
|
+
}
|
2083
|
+
|
2084
|
+
// 0.8 seconds for a full screen animation (most will be 50% or less of screen)
|
2085
|
+
durationH = 0.8 * (horizontalScrollOffset - maximumHorizontalScrollOffset) / containerWidth;
|
2086
|
+
|
2087
|
+
// Bounce back from min.
|
2088
|
+
} else if (horizontalScrollOffset < minimumHorizontalScrollOffset) {
|
2089
|
+
this.set('horizontalScrollOffset', minimumHorizontalScrollOffset);
|
2090
|
+
|
2091
|
+
// Moving away from minimum. Change direction.
|
2092
|
+
if (horizontalVelocity > 0.2) {
|
2093
|
+
this._sc_animationTiming = this.get('animationCurveReverse');
|
2094
|
+
|
2095
|
+
// Stopped or moving back towards minimum. Maintain direction, snap at the end.
|
2096
|
+
} else {
|
2097
|
+
this._sc_animationTiming = this.get('animationCurveSnap');
|
2098
|
+
}
|
2099
|
+
|
2100
|
+
// 0.8 seconds for a full screen animation (most will be 50% or less of screen)
|
2101
|
+
durationH = 0.8 * (minimumHorizontalScrollOffset - horizontalScrollOffset) / containerWidth;
|
2102
|
+
|
2103
|
+
// Slide.
|
2104
|
+
} else {
|
2105
|
+
// Set the final position we should slide to as we decelerate based on last velocity.
|
2106
|
+
horizontalScrollOffset -= (Math.abs(horizontalVelocity) * horizontalVelocity * 1000) / (2 * decelerationRate);
|
2107
|
+
|
2108
|
+
// Constrain within bounds.
|
2109
|
+
if (horizontalScrollOffset > maximumHorizontalScrollOffset) {
|
2110
|
+
// Generate an animation curve that bounces past the end point.
|
2111
|
+
c2x = (horizontalScrollOffset - maximumHorizontalScrollOffset) / containerWidth;
|
2112
|
+
c2y = 2 * c2x;
|
2113
|
+
this._sc_animationTiming = SC.easingCurve(0.0,0.5,c2x.toFixed(1),c2y.toFixed(1)); // 'cubic-bezier(0.0,0.5,%@,%@)'.fmt(c2x.toFixed(1), c2y.toFixed(1));
|
2114
|
+
|
2115
|
+
horizontalScrollOffset = maximumHorizontalScrollOffset;
|
2116
|
+
|
2117
|
+
} else if (horizontalScrollOffset < minimumHorizontalScrollOffset) {
|
2118
|
+
// Generate an animation curve that bounces past the end point.
|
2119
|
+
c2x = (minimumHorizontalScrollOffset - horizontalScrollOffset) / containerWidth;
|
2120
|
+
c2y = 2 * c2x;
|
2121
|
+
this._sc_animationTiming = SC.easingCurve(0.0,0.5,c2x.toFixed(1),c2y.toFixed(1)); // 'cubic-bezier(0.0,0.5,%@,%@)'.fmt(c2x.toFixed(1), c2y.toFixed(1));
|
2122
|
+
|
2123
|
+
horizontalScrollOffset = minimumHorizontalScrollOffset;
|
2124
|
+
|
2125
|
+
} else {
|
2126
|
+
this._sc_animationTiming = this.get('animationCurveDecelerate');
|
2127
|
+
}
|
2128
|
+
|
2129
|
+
this.set('horizontalScrollOffset', horizontalScrollOffset);
|
2130
|
+
|
2131
|
+
durationH = Math.abs(horizontalVelocity / decelerationRate);
|
2132
|
+
}
|
2133
|
+
}
|
2134
|
+
|
2135
|
+
if (this._sc_isTouchScrollingV) {
|
2136
|
+
var verticalScrollOffset = this.get('verticalScrollOffset'),
|
2137
|
+
maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset'),
|
2138
|
+
minimumVerticalScrollOffset = this.get('minimumVerticalScrollOffset'),
|
2139
|
+
verticalVelocity = this._sc_touchVelocityV;
|
2140
|
+
|
2141
|
+
// Past the maximum.
|
2142
|
+
if (verticalScrollOffset > maximumVerticalScrollOffset) {
|
2143
|
+
this.set('verticalScrollOffset', maximumVerticalScrollOffset);
|
2144
|
+
|
2145
|
+
// Moving away from maximum. Change direction.
|
2146
|
+
if (verticalVelocity < 0.2) {
|
2147
|
+
this._sc_animationTiming = this.get('animationCurveReverse');
|
2148
|
+
|
2149
|
+
// Stopped or moving back towards maximum. Maintain direction, snap at the end.
|
2150
|
+
} else {
|
2151
|
+
this._sc_animationTiming = this.get('animationCurveSnap');
|
2152
|
+
}
|
2153
|
+
|
2154
|
+
// 0.8 seconds for a full screen animation (most will be 50% or less of screen)
|
2155
|
+
durationV = 0.8 * (verticalScrollOffset - maximumVerticalScrollOffset) / containerHeight;
|
2156
|
+
|
2157
|
+
// Bounce back from min.
|
2158
|
+
} else if (verticalScrollOffset < minimumVerticalScrollOffset) {
|
2159
|
+
this.set('verticalScrollOffset', minimumVerticalScrollOffset);
|
2160
|
+
|
2161
|
+
// Moving away from minimum. Change direction.
|
2162
|
+
if (verticalVelocity > 0.2) {
|
2163
|
+
this._sc_animationTiming = this.get('animationCurveReverse');
|
2164
|
+
|
2165
|
+
// Stopped or moving back towards minimum. Maintain direction, snap at the end.
|
2166
|
+
} else {
|
2167
|
+
this._sc_animationTiming = this.get('animationCurveSnap');
|
2168
|
+
}
|
2169
|
+
|
2170
|
+
// 0.8 seconds for a full screen animation (most will be 50% or less of screen)
|
2171
|
+
durationV = 0.8 * (minimumVerticalScrollOffset - verticalScrollOffset) / containerHeight;
|
2172
|
+
|
2173
|
+
// Slide.
|
2174
|
+
} else {
|
2175
|
+
// Set the final position we should slide to as we decelerate based on last velocity.
|
2176
|
+
verticalScrollOffset -= (Math.abs(verticalVelocity) * verticalVelocity * 1000) / (2 * decelerationRate);
|
2177
|
+
|
2178
|
+
// Constrain within bounds.
|
2179
|
+
if (verticalScrollOffset > maximumVerticalScrollOffset) {
|
2180
|
+
// Generate an animation curve that bounces past the end point.
|
2181
|
+
c2x = (verticalScrollOffset - maximumVerticalScrollOffset) / containerHeight;
|
2182
|
+
c2y = 2 * c2x;
|
2183
|
+
this._sc_animationTiming = SC.easingCurve(0.0, 0.5,c2x.toFixed(1), c2y.toFixed(1)); 'cubic-bezier(0.0,0.5,%@,%@)'.fmt(c2x.toFixed(1), c2y.toFixed(1));
|
2184
|
+
|
2185
|
+
verticalScrollOffset = maximumVerticalScrollOffset;
|
2186
|
+
|
2187
|
+
} else if (verticalScrollOffset < minimumVerticalScrollOffset) {
|
2188
|
+
// Generate an animation curve that bounces past the end point.
|
2189
|
+
c2x = (minimumVerticalScrollOffset - verticalScrollOffset) / containerHeight;
|
2190
|
+
c2y = 2 * c2x;
|
2191
|
+
this._sc_animationTiming = SC.easingCurve(0.0, 0.5,c2x.toFixed(1), c2y.toFixed(1)); 'cubic-bezier(0.0,0.5,%@,%@)'.fmt(c2x.toFixed(1), c2y.toFixed(1));
|
2192
|
+
|
2193
|
+
verticalScrollOffset = minimumVerticalScrollOffset;
|
2194
|
+
|
2195
|
+
} else {
|
2196
|
+
this._sc_animationTiming = this.get('animationCurveDecelerate');
|
2197
|
+
}
|
2198
|
+
|
2199
|
+
this.set('verticalScrollOffset', verticalScrollOffset);
|
2200
|
+
|
2201
|
+
durationV = Math.abs(verticalVelocity / decelerationRate);
|
2202
|
+
}
|
2203
|
+
}
|
2204
|
+
|
2205
|
+
var scale = this.get('scale'),
|
2206
|
+
maximumScale = this.get('maximumScale'),
|
2207
|
+
minimumScale = this.get('minimumScale'),
|
2208
|
+
durationS = 0;
|
2209
|
+
|
2210
|
+
// Bounce back from max.
|
2211
|
+
if (scale > maximumScale) {
|
2212
|
+
this.set('scale', maximumScale);
|
2213
|
+
durationS = 0.25;
|
2214
|
+
|
2215
|
+
// Bounce back from min.
|
2216
|
+
} else if (scale < minimumScale) {
|
2217
|
+
this.set('scale', minimumScale);
|
2218
|
+
durationS = 0.25;
|
2219
|
+
|
2220
|
+
// Slide.
|
2221
|
+
} else {
|
2222
|
+
|
2223
|
+
}
|
2224
|
+
|
2225
|
+
// Determine how long the deceleration should take (we can't animate left/top separately, so use the largest duration for both).
|
2226
|
+
// This variable also acts as a flag so that when the content view is repositioned, it will be animated.
|
2227
|
+
this._sc_animationDuration = Math.max(Math.max(durationH, durationV), durationS);
|
2228
|
+
|
2229
|
+
// Clear up all caches from touchesDragged.
|
2230
|
+
this._sc_touchVelocityH = null;
|
2231
|
+
this._sc_touchVelocityV = null;
|
2232
|
+
|
2233
|
+
// Pass the initial touch on to the content view if it hasn't tried yet (i.e. a tap) and the touch wasn't cancelled.
|
2234
|
+
} else if (this._sc_passTouchToContentTimer) {
|
2235
|
+
// Clean up.
|
2236
|
+
this._sc_passTouchToContentTimer.invalidate();
|
2237
|
+
this._sc_passTouchToContentTimer = null;
|
2238
|
+
|
2239
|
+
if (!wasCancelled) {
|
2240
|
+
// If the content has handled the touch, then immediately end it.
|
2241
|
+
if (touch.makeTouchResponder(touch.targetView, true, this)) {
|
2242
|
+
touch.end();
|
2243
|
+
}
|
2244
|
+
}
|
2245
|
+
}
|
2246
|
+
|
2247
|
+
// Clean up all caches from touchStart & touchesDragged
|
2248
|
+
this._sc_gestureAnchorX = this._sc_gestureAnchorY = this._sc_gestureAnchorD = null;
|
2249
|
+
this._sc_gestureAnchorTotalX = this._sc_gestureAnchorTotalY = this._sc_gestureAnchorTotalD = null;
|
2250
|
+
this._sc_gestureAnchorScale = null;
|
2251
|
+
this._sc_gestureAnchorHOffset = null;
|
2252
|
+
this._sc_gestureAnchorVOffset = null;
|
2253
|
+
this._sc_containerOffset = null;
|
2254
|
+
this._sc_touchCenterX = null;
|
2255
|
+
this._sc_touchCenterY = null;
|
2256
|
+
}
|
2257
|
+
|
2258
|
+
// Force recalculation of scrolling and scaling.
|
2259
|
+
this._sc_isTouchScrollingH = false;
|
2260
|
+
this._sc_isTouchScrollingHOnly = false;
|
2261
|
+
this._sc_isTouchScrollingV = false;
|
2262
|
+
this._sc_isTouchScrollingVOnly = false;
|
2263
|
+
this._sc_isTouchScaling = false;
|
2264
|
+
|
2265
|
+
// TODO: What happens when isEnabledInPane goes false while interacting? Statechart would help solve this.
|
2266
|
+
return true;
|
2267
|
+
},
|
2268
|
+
|
2269
|
+
/** @private @see SC.RootResponder.prototype.captureTouch */
|
2270
|
+
captureTouch: function (touch) {
|
2271
|
+
// Capture the touch and begin determination of actual scroll or not.
|
2272
|
+
if (this.get('delaysContentTouches')) {
|
2273
|
+
return true;
|
2274
|
+
|
2275
|
+
// Otherwise, suggest ourselves as a reasonable fallback responder. If none of our children capture
|
2276
|
+
// the touch or handle touchStart, we'll get another crack at it in touchStart.
|
2277
|
+
} else {
|
2278
|
+
touch.stackCandidateTouchResponder(this);
|
2279
|
+
|
2280
|
+
return false;
|
2281
|
+
}
|
2282
|
+
},
|
2283
|
+
|
2284
|
+
/** @private */
|
2285
|
+
mouseWheel: function (evt) {
|
2286
|
+
var handled = false,
|
2287
|
+
contentView = this.get('contentView');
|
2288
|
+
|
2289
|
+
// Ignore it if not enabled.
|
2290
|
+
if (contentView && this.get('isEnabledInPane')) {
|
2291
|
+
|
2292
|
+
var horizontalScrollOffset = this.get('horizontalScrollOffset'),
|
2293
|
+
minimumHorizontalScrollOffset = this.get('minimumHorizontalScrollOffset'),
|
2294
|
+
minimumVerticalScrollOffset = this.get('minimumVerticalScrollOffset'),
|
2295
|
+
maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset'),
|
2296
|
+
maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset'),
|
2297
|
+
verticalScrollOffset = this.get('verticalScrollOffset'),
|
2298
|
+
wheelDeltaX = evt.wheelDeltaX,
|
2299
|
+
wheelDeltaY = evt.wheelDeltaY;
|
2300
|
+
|
2301
|
+
// If we can't scroll in one direction, limit that direction.
|
2302
|
+
if (!this.get('canScrollHorizontal')) { // Don't allow inverted scrolling for now.
|
2303
|
+
wheelDeltaX = 0;
|
2304
|
+
}
|
2305
|
+
|
2306
|
+
if (!this.get('canScrollVertical')) { // Don't allow inverted scrolling for now.
|
2307
|
+
wheelDeltaY = 0;
|
2308
|
+
}
|
2309
|
+
|
2310
|
+
// Only attempt to scroll if we are allowed to scroll in the direction and have room to scroll
|
2311
|
+
// in the direction. Otherwise, ignore the event so that an outer ScrollView may capture it.
|
2312
|
+
handled = ((wheelDeltaX < 0 && horizontalScrollOffset > minimumHorizontalScrollOffset) ||
|
2313
|
+
(wheelDeltaX > 0 && horizontalScrollOffset < maximumHorizontalScrollOffset)) ||
|
2314
|
+
((wheelDeltaY < 0 && verticalScrollOffset > minimumVerticalScrollOffset) ||
|
2315
|
+
(wheelDeltaY > 0 && verticalScrollOffset < maximumVerticalScrollOffset));
|
2316
|
+
|
2317
|
+
if (handled) {
|
2318
|
+
this.scrollBy(wheelDeltaX, wheelDeltaY);
|
2319
|
+
}
|
2320
|
+
}
|
2321
|
+
|
2322
|
+
return handled;
|
2323
|
+
},
|
2324
|
+
|
2325
|
+
/** @private */
|
2326
|
+
touchesDragged: function (evt, touchesForView) {
|
2327
|
+
var avgTouch = evt.averagedTouchesForView(this),
|
2328
|
+
canScale = this.get('canScale'),
|
2329
|
+
canScrollHorizontal = this.get('canScrollHorizontal'),
|
2330
|
+
canScrollVertical = this.get('canScrollVertical'),
|
2331
|
+
scrollThreshold = this.get('scrollGestureThreshold'),
|
2332
|
+
scaleThreshold = this.get('scaleGestureThreshold'),
|
2333
|
+
scrollLockThreshold = this.get('scrollLockGestureThreshold'),
|
2334
|
+
horizontalScrollOffset,
|
2335
|
+
verticalScrollOffset;
|
2336
|
+
|
2337
|
+
|
2338
|
+
// Determine if we've moved enough to claim horizontal or vertical scrolling.
|
2339
|
+
if (!(this._sc_isTouchScrollingH && this._sc_isTouchScrollingV) &&
|
2340
|
+
!this._sc_isTouchScrollingHOnly && !this._sc_isTouchScrollingVOnly) {
|
2341
|
+
|
2342
|
+
if (canScrollHorizontal) {
|
2343
|
+
var totalAbsDeltaX = Math.abs(this._sc_gestureAnchorTotalX - avgTouch.x);
|
2344
|
+
|
2345
|
+
if (!this._sc_isTouchScrollingH) {
|
2346
|
+
this._sc_isTouchScrollingH = totalAbsDeltaX >= scrollThreshold;
|
2347
|
+
|
2348
|
+
// Determine if we've moved enough to lock scrolling to only this direction.
|
2349
|
+
} else {
|
2350
|
+
this._sc_isTouchScrollingHOnly = totalAbsDeltaX >= scrollLockThreshold;
|
2351
|
+
}
|
2352
|
+
}
|
2353
|
+
|
2354
|
+
if (canScrollVertical) {
|
2355
|
+
var totalAbsDeltaY = Math.abs(this._sc_gestureAnchorTotalY - avgTouch.y);
|
2356
|
+
|
2357
|
+
if (!this._sc_isTouchScrollingV) {
|
2358
|
+
this._sc_isTouchScrollingV = totalAbsDeltaY >= scrollThreshold;
|
2359
|
+
|
2360
|
+
// Determine if we've moved enough to lock scrolling to only this direction.
|
2361
|
+
} else {
|
2362
|
+
this._sc_isTouchScrollingVOnly = totalAbsDeltaY >= scrollLockThreshold;
|
2363
|
+
}
|
2364
|
+
}
|
2365
|
+
}
|
2366
|
+
|
2367
|
+
var touchDeltaX = this._sc_gestureAnchorX - avgTouch.x,
|
2368
|
+
absDeltaX = Math.abs(touchDeltaX);
|
2369
|
+
|
2370
|
+
// Adjust scroll.
|
2371
|
+
if (canScrollHorizontal && absDeltaX >= 1 && !this._sc_isTouchScrollingVOnly) {
|
2372
|
+
// Record the last velocity.
|
2373
|
+
this._sc_touchVelocityH = avgTouch.velocityX;
|
2374
|
+
|
2375
|
+
var minimumHorizontalScrollOffset = this.get('minimumHorizontalScrollOffset'),
|
2376
|
+
maximumHorizontalScrollOffset = this.get('maximumHorizontalScrollOffset');
|
2377
|
+
|
2378
|
+
horizontalScrollOffset = this._sc_gestureAnchorHOffset + touchDeltaX;
|
2379
|
+
|
2380
|
+
// Reset the anchor. Note: Do this before degrading the offset.
|
2381
|
+
this._sc_gestureAnchorX = avgTouch.x;
|
2382
|
+
this._sc_gestureAnchorHOffset = horizontalScrollOffset;
|
2383
|
+
|
2384
|
+
// Degrade the offset as we pass maximum.
|
2385
|
+
if (horizontalScrollOffset > maximumHorizontalScrollOffset) {
|
2386
|
+
horizontalScrollOffset = horizontalScrollOffset - this._sc_overDragSlip * (horizontalScrollOffset - maximumHorizontalScrollOffset);
|
2387
|
+
|
2388
|
+
// Degrade the offset as we pass minimum.
|
2389
|
+
} else if (horizontalScrollOffset < minimumHorizontalScrollOffset) {
|
2390
|
+
horizontalScrollOffset = horizontalScrollOffset + this._sc_overDragSlip * (minimumHorizontalScrollOffset - horizontalScrollOffset);
|
2391
|
+
}
|
2392
|
+
|
2393
|
+
// Update the scroll offset.
|
2394
|
+
this.set('horizontalScrollOffset', horizontalScrollOffset);
|
2395
|
+
}
|
2396
|
+
|
2397
|
+
var touchDeltaY = this._sc_gestureAnchorY - avgTouch.y,
|
2398
|
+
absDeltaY = Math.abs(touchDeltaY);
|
2399
|
+
|
2400
|
+
if (canScrollVertical && absDeltaY > 0 && !this._sc_isTouchScrollingHOnly) {
|
2401
|
+
// Record the last velocity.
|
2402
|
+
this._sc_touchVelocityV = avgTouch.velocityY;
|
2403
|
+
|
2404
|
+
var minimumVerticalScrollOffset = this.get('minimumVerticalScrollOffset'),
|
2405
|
+
maximumVerticalScrollOffset = this.get('maximumVerticalScrollOffset');
|
2406
|
+
|
2407
|
+
verticalScrollOffset = this._sc_gestureAnchorVOffset + touchDeltaY;
|
2408
|
+
|
2409
|
+
// Reset the anchor. Note: Do this before degrading the offset.
|
2410
|
+
this._sc_gestureAnchorY = avgTouch.y;
|
2411
|
+
this._sc_gestureAnchorVOffset = verticalScrollOffset;
|
2412
|
+
|
2413
|
+
// Degrade the offset as we pass maximum.
|
2414
|
+
if (verticalScrollOffset > maximumVerticalScrollOffset) {
|
2415
|
+
verticalScrollOffset = verticalScrollOffset - this._sc_overDragSlip * (verticalScrollOffset - maximumVerticalScrollOffset);
|
2416
|
+
|
2417
|
+
// Degrade the offset as we pass minimum.
|
2418
|
+
} else if (verticalScrollOffset < minimumVerticalScrollOffset) {
|
2419
|
+
verticalScrollOffset = verticalScrollOffset + this._sc_overDragSlip * (minimumVerticalScrollOffset - verticalScrollOffset);
|
2420
|
+
}
|
2421
|
+
|
2422
|
+
// Update the scroll offset.
|
2423
|
+
this.set('verticalScrollOffset', verticalScrollOffset);
|
2424
|
+
}
|
2425
|
+
|
2426
|
+
// Adjust scale.
|
2427
|
+
if (canScale) {
|
2428
|
+
|
2429
|
+
// Determine if we've moved enough to claim scaling.
|
2430
|
+
if (!this._sc_isTouchScaling) {
|
2431
|
+
var totalAbsDeltaD = Math.abs(this._sc_gestureAnchorTotalD - avgTouch.d);
|
2432
|
+
this._sc_isTouchScaling = !!avgTouch.d && totalAbsDeltaD > scaleThreshold;
|
2433
|
+
}
|
2434
|
+
|
2435
|
+
var touchDeltaD = this._sc_gestureAnchorD - avgTouch.d,
|
2436
|
+
absDeltaD = Math.abs(touchDeltaD);
|
2437
|
+
if (absDeltaD > 0) {
|
2438
|
+
// The percentage difference in touch distance.
|
2439
|
+
var scalePercentChange = avgTouch.d / this._sc_gestureAnchorD,
|
2440
|
+
scale = this._sc_gestureAnchorScale * scalePercentChange;
|
2441
|
+
|
2442
|
+
// Adjust the center of the zoom to the center of the gesture.
|
2443
|
+
horizontalScrollOffset = this._sc_horizontalScrollOffset;
|
2444
|
+
verticalScrollOffset = this._sc_verticalScrollOffset;
|
2445
|
+
|
2446
|
+
// Cache the current offset of the container view in the document. Calculated each time touch scaling begins.
|
2447
|
+
if (!this._sc_containerOffset) {
|
2448
|
+
var el = this.getPath('containerView.layer');
|
2449
|
+
|
2450
|
+
this._sc_containerOffset = SC.offset(el);
|
2451
|
+
this._sc_touchCenterX = avgTouch.x - this._sc_containerOffset.x;
|
2452
|
+
this._sc_touchCenterY = avgTouch.y - this._sc_containerOffset.y;
|
2453
|
+
}
|
2454
|
+
|
2455
|
+
// Compute the relative center of the scale gesture.
|
2456
|
+
this._sc_horizontalPct = (horizontalScrollOffset + this._sc_touchCenterX) / this._sc_contentWidth;
|
2457
|
+
this._sc_verticalPct = (verticalScrollOffset + this._sc_touchCenterY) / this._sc_contentHeight;
|
2458
|
+
|
2459
|
+
this.set('scale', scale);
|
2460
|
+
|
2461
|
+
// Reset the anchor.
|
2462
|
+
this._sc_gestureAnchorD = avgTouch.d;
|
2463
|
+
this._sc_gestureAnchorScale = scale;
|
2464
|
+
}
|
2465
|
+
}
|
2466
|
+
|
2467
|
+
// No longer pass the initial touch on to the content view if it was still about to.
|
2468
|
+
if (this._sc_passTouchToContentTimer && (this._sc_isTouchScrollingV || this._sc_isTouchScrollingH || this._sc_isTouchScaling)) {
|
2469
|
+
this._sc_passTouchToContentTimer.invalidate();
|
2470
|
+
this._sc_passTouchToContentTimer = null;
|
2471
|
+
}
|
2472
|
+
|
2473
|
+
// Note: If the content view has already accepted the initial touch, it will be sent a touchCancelled event.
|
2474
|
+
},
|
2475
|
+
|
2476
|
+
/** @private
|
2477
|
+
If we're in hand-holding mode and our content claims the touch, we will receive a touchCancelled
|
2478
|
+
event at its completion. We still need to do most of our touch-ending wrap up, for example to finish
|
2479
|
+
bouncing back from a previous gesture.
|
2480
|
+
*/
|
2481
|
+
touchCancelled: function (touch) {
|
2482
|
+
return this._sc_touchEnded(touch, true);
|
2483
|
+
},
|
2484
|
+
|
2485
|
+
/** @private
|
2486
|
+
If we are the touch's responder at its completion, we'll get a touchEnd event. If this is the
|
2487
|
+
gesture's last touch, we wrap up in spectacular fashion.
|
2488
|
+
*/
|
2489
|
+
touchEnd: function (touch) {
|
2490
|
+
return this._sc_touchEnded(touch, false);
|
2491
|
+
},
|
2492
|
+
|
2493
|
+
// /** @private */
|
2494
|
+
touchStart: function (touch) {
|
2495
|
+
var handled = false,
|
2496
|
+
contentView = this.get('contentView');
|
2497
|
+
|
2498
|
+
if (contentView && this.get('isEnabledInPane')) {
|
2499
|
+
var hasTouch = this.get('hasTouch');
|
2500
|
+
|
2501
|
+
// Additional touches can be used for pinching gestures.
|
2502
|
+
if (hasTouch) {
|
2503
|
+
|
2504
|
+
// If a new touch has appeared, force scrolling to recalculate.
|
2505
|
+
this._sc_isTouchScrollingV = this._sc_isTouchScrollingH = false;
|
2506
|
+
this._sc_isTouchScrollingHOnly = this._sc_isTouchScrollingHOnly = false;
|
2507
|
+
|
2508
|
+
// No longer pass the initial touch on to the content view if it was still about to.
|
2509
|
+
if (this._sc_passTouchToContentTimer) {
|
2510
|
+
this._sc_passTouchToContentTimer.invalidate();
|
2511
|
+
this._sc_passTouchToContentTimer = null;
|
2512
|
+
}
|
2513
|
+
|
2514
|
+
// The first touch is used to set up initial state.
|
2515
|
+
} else {
|
2516
|
+
// Cancel any active animation in place.
|
2517
|
+
this._sc_cancelAnimation();
|
2518
|
+
|
2519
|
+
// If we have captured the touch and are not yet scrolling, we may want to delay a moment to test for
|
2520
|
+
// scrolling and if not scrolling, we will pass the touch through to the content.
|
2521
|
+
// If configured to do so, delay 150ms to verify that the user is not scrolling before passing touches through to the content.
|
2522
|
+
if (this.get('delaysContentTouches')) {
|
2523
|
+
this._sc_passTouchToContentTimer = this.invokeLater(this._sc_beginTouchesInContent, 150, touch);
|
2524
|
+
} // Else do nothing.
|
2525
|
+
}
|
2526
|
+
|
2527
|
+
// Update the average distance to center of the touch, which is used to recognize pinch/zoom movement of the touch.
|
2528
|
+
var avgTouch = touch.averagedTouchesForView(this, true);
|
2529
|
+
|
2530
|
+
/* A note on these variables:
|
2531
|
+
|
2532
|
+
_sc_gestureAnchorX: the last x position (so that we don't update horizontal scroll if the change since last is 0)
|
2533
|
+
_sc_gestureAnchorTotalX: the initial x position (so that we can determine whether to take total control of touches and possibly lock the position)
|
2534
|
+
*/
|
2535
|
+
this._sc_gestureAnchorX = this._sc_gestureAnchorTotalX = avgTouch.x;
|
2536
|
+
this._sc_gestureAnchorY = this._sc_gestureAnchorTotalY = avgTouch.y;
|
2537
|
+
this._sc_gestureAnchorD = this._sc_gestureAnchorTotalD = avgTouch.d;
|
2538
|
+
this._sc_gestureAnchorScale = this.get('scale');
|
2539
|
+
this._sc_gestureAnchorHOffset = this.get('horizontalScrollOffset');
|
2540
|
+
this._sc_gestureAnchorVOffset = this.get('verticalScrollOffset');
|
2541
|
+
|
2542
|
+
handled = true;
|
2543
|
+
}
|
2544
|
+
|
2545
|
+
return handled;
|
2546
|
+
}
|
2547
|
+
|
2548
|
+
});
|
2549
|
+
|
2550
|
+
|
2551
|
+
SC.ScrollView.mixin(
|
2552
|
+
/** @scope SC.ScrollView */ {
|
2553
|
+
|
2554
|
+
/** @private Shared object used to avoid continually initializing/destroying objects. */
|
2555
|
+
_SC_CONTAINER_LAYOUT_MAP: null,
|
2556
|
+
|
2557
|
+
/** @private Shared object used to avoid continually initializing/destroying objects. */
|
2558
|
+
_SC_CONTENT_ADJUST_MAP: null
|
2559
|
+
|
2560
|
+
});
|