sproutcore 1.6.0.1-java → 1.7.1.beta-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +21 -0
- data/Gemfile +5 -0
- data/Rakefile +26 -13
- data/VERSION.yml +2 -2
- data/lib/Buildfile +43 -4
- data/lib/buildtasks/build.rake +10 -0
- data/lib/buildtasks/helpers/file_rule.rb +22 -0
- data/lib/buildtasks/helpers/file_rule_list.rb +137 -0
- data/lib/buildtasks/manifest.rake +133 -122
- data/lib/frameworks/sproutcore/CHANGELOG.md +69 -2
- data/lib/frameworks/sproutcore/apps/tests/english.lproj/strings.js +1 -0
- data/lib/frameworks/sproutcore/frameworks/bootstrap/system/browser.js +28 -22
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/array.js +9 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controllers/controller.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/controls/button.js +18 -13
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/bind.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/ext/handlebars/collection.js +2 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/action_support.js +80 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/mixins/template_helpers/text_field_support.js +84 -116
- data/lib/frameworks/sproutcore/frameworks/core_foundation/panes/pane.js +8 -5
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/event.js +157 -157
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/platform.js +5 -3
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/root_responder.js +6 -6
- data/lib/frameworks/sproutcore/frameworks/core_foundation/system/sparse_array.js +10 -7
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/mixins/action_support.js +106 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/collection.js +18 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/template/handlebars.js +71 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/attribute_bindings_test.js +38 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/class_name_bindings_test.js +47 -0
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutChildViews.js +18 -18
- data/lib/frameworks/sproutcore/frameworks/core_foundation/tests/views/view/layoutStyle.js +42 -10
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view.js +158 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/keyboard.js +26 -1
- data/lib/frameworks/sproutcore/frameworks/core_foundation/views/view/layout_style.js +14 -8
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record.js +15 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/models/record_attribute.js +108 -108
- data/lib/frameworks/sproutcore/frameworks/datastore/system/query.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datastore/system/record_array.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/record/error_methods.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/models/single_attribute.js +26 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/query/builders.js +7 -0
- data/lib/frameworks/sproutcore/frameworks/datastore/tests/system/record_array/error_methods.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/system/datetime.js +4 -1
- data/lib/frameworks/sproutcore/frameworks/datetime/frameworks/core/tests/system/datetime.js +6 -0
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/menu.js +26 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/panes/picker.js +97 -96
- data/lib/frameworks/sproutcore/frameworks/desktop/system/drag.js +4 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/tests/panes/menu/ui.js +17 -4
- data/lib/frameworks/sproutcore/frameworks/desktop/views/collection.js +7 -7
- data/lib/frameworks/sproutcore/frameworks/desktop/views/menu_item.js +7 -5
- data/lib/frameworks/sproutcore/frameworks/desktop/views/scroll.js +12 -3
- data/lib/frameworks/sproutcore/frameworks/desktop/views/web.js +23 -14
- data/lib/frameworks/sproutcore/frameworks/experimental/Buildfile +5 -1
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/render_delegates/menu_scroller.js +28 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/tests/menu/scroll.js +235 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroll.js +363 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/menu/views/menu/scroller.js +250 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/desktop_scroller.js +92 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/native_scroll.js +25 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/scroll.js +33 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/render_delegates/touch_scroller.js +76 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/integration.js +50 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/methods.js +143 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/tests/scroll/ui.js +258 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroll.js +1164 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/core_scroller.js +332 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroll.js +236 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/desktop/scroller.js +347 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroll.js +15 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js +10 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js +804 -0
- data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroller.js +133 -0
- data/lib/frameworks/sproutcore/frameworks/foundation/resources/text_field.css +3 -3
- data/lib/frameworks/sproutcore/frameworks/foundation/validators/number.js +3 -1
- data/lib/frameworks/sproutcore/frameworks/foundation/views/text_field.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/media/views/audio.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/controls.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/media/views/media_slider.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/mini_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/simple_controls.js +2 -4
- data/lib/frameworks/sproutcore/frameworks/media/views/video.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/routing/system/routes.js +29 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/core.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/debug/test_suites/array/replace.js +1 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/private/property_chain.js +2 -1
- data/lib/frameworks/sproutcore/frameworks/runtime/system/binding.js +3 -3
- data/lib/frameworks/sproutcore/frameworks/runtime/system/index_set.js +2 -2
- data/lib/frameworks/sproutcore/frameworks/runtime/system/object.js +1 -1
- data/lib/frameworks/sproutcore/themes/ace/resources/collection/normal/list_item.css +2 -2
- data/lib/frameworks/sproutcore/themes/legacy_theme/english.lproj/segmented.css +1 -1
- data/lib/gen/app/templates/apps/@target_name@/Buildfile +3 -5
- data/lib/gen/app/templates/apps/@target_name@/resources/_theme.css +18 -0
- data/lib/gen/project/templates/@filename@/Buildfile +2 -2
- data/lib/sproutcore.rb +30 -5
- data/lib/sproutcore/builders.rb +1 -0
- data/lib/sproutcore/builders/chance_file.rb +9 -16
- data/lib/sproutcore/builders/html.rb +2 -1
- data/lib/sproutcore/builders/minify.rb +4 -35
- data/lib/sproutcore/builders/module.rb +38 -1
- data/lib/sproutcore/builders/split.rb +63 -0
- data/lib/sproutcore/builders/strings.rb +7 -1
- data/lib/sproutcore/helpers.rb +1 -1
- data/lib/sproutcore/helpers/css_split.rb +190 -0
- data/lib/sproutcore/helpers/entry_sorter.rb +2 -0
- data/lib/sproutcore/helpers/minifier.rb +40 -16
- data/lib/sproutcore/helpers/static_helper.rb +35 -17
- data/lib/sproutcore/models/manifest.rb +26 -0
- data/lib/sproutcore/models/target.rb +12 -1
- data/lib/sproutcore/rack.rb +1 -0
- data/lib/sproutcore/rack/proxy.rb +244 -225
- data/lib/sproutcore/rack/restrict_ip.rb +67 -0
- data/lib/sproutcore/rack/service.rb +8 -2
- data/lib/sproutcore/tools.rb +102 -46
- data/lib/sproutcore/tools/build.rb +91 -43
- data/lib/sproutcore/tools/gen.rb +2 -3
- data/lib/sproutcore/tools/manifest.rb +22 -16
- data/lib/sproutcore/tools/server.rb +21 -0
- data/spec/buildtasks/helpers/accept_list +22 -0
- data/spec/buildtasks/helpers/accept_list.rb +128 -0
- data/spec/buildtasks/helpers/list.json +11 -0
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_2x_spec.rb +1 -39
- data/spec/buildtasks/manifest/prepare_build_tasks/chance_spec.rb +0 -38
- data/spec/buildtasks/manifest/prepare_build_tasks/combine_spec.rb +4 -4
- data/spec/buildtasks/manifest/prepare_build_tasks/module_spec.rb +2 -2
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_indirect_spec.rb +7 -16
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_2x_spec.rb +7 -17
- data/spec/buildtasks/manifest/prepare_build_tasks/packed_spec.rb +11 -6
- data/spec/fixtures/builder_tests/Buildfile +2 -1
- data/spec/fixtures/builder_tests/apps/module_test/modules/required_module/core.js +0 -0
- data/spec/lib/builders/module_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/sproutcore.gemspec +4 -9
- data/vendor/chance/lib/chance.rb +25 -6
- data/vendor/chance/lib/chance/factory.rb +45 -0
- data/vendor/chance/lib/chance/instance.rb +173 -28
- data/vendor/chance/lib/chance/instance/data_url.rb +0 -29
- data/vendor/chance/lib/chance/instance/slicing.rb +57 -4
- data/vendor/chance/lib/chance/instance/spriting.rb +112 -21
- data/vendor/chance/lib/chance/parser.rb +80 -52
- data/vendor/sproutcore/SCCompiler.jar +0 -0
- data/vendor/sproutcore/lib/args4j-2.0.12.jar +0 -0
- data/vendor/sproutcore/lib/yuicompressor-2.4.2.jar +0 -0
- metadata +84 -25
@@ -0,0 +1,347 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2011 Strobe Inc. and contributors.
|
4
|
+
// Portions ©2008-2011 Apple Inc. All rights reserved.
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
|
+
// ==========================================================================
|
7
|
+
|
8
|
+
sc_require('views/core_scroller');
|
9
|
+
|
10
|
+
/** @class
|
11
|
+
Implements a custom desktop-like scroller view that handles
|
12
|
+
your basic scrollbar events:
|
13
|
+
|
14
|
+
- Arrow buttons for incremental scrolling in either direction.
|
15
|
+
- Clicking in the track to incrementally jump to a location.
|
16
|
+
- CTL+Click to jump immediately to a location.
|
17
|
+
- A draggable scroll thumb.
|
18
|
+
|
19
|
+
@extends SC.CoreScrollerView
|
20
|
+
@since SproutCore 1.6
|
21
|
+
*/
|
22
|
+
SC.DesktopScrollerView = SC.CoreScrollerView.extend(
|
23
|
+
/** @scope SC.DesktopScrollerView.prototype */{
|
24
|
+
|
25
|
+
/**
|
26
|
+
@type String
|
27
|
+
@default 'desktopScrollerRenderDelegate'
|
28
|
+
*/
|
29
|
+
renderDelegateName: 'desktopScrollerRenderDelegate',
|
30
|
+
|
31
|
+
// ..........................................................
|
32
|
+
// MOUSE EVENTS
|
33
|
+
//
|
34
|
+
|
35
|
+
/** @private
|
36
|
+
Returns the value for a position within the scroller's frame.
|
37
|
+
*/
|
38
|
+
valueForPosition: function (pos) {
|
39
|
+
return ((pos - (this.get('capLength') - this.get('capOverlap'))) /
|
40
|
+
(this.get('trackLength') - this.get('thumbLength'))) * this.get('maximum');
|
41
|
+
},
|
42
|
+
|
43
|
+
/** @private
|
44
|
+
Handles mouse down events and adjusts the value property depending where
|
45
|
+
the user clicked.
|
46
|
+
|
47
|
+
If the control is disabled, we ignore all mouse input.
|
48
|
+
|
49
|
+
If the user clicks the thumb, we note the position of the mouse event but
|
50
|
+
do not take further action until they begin to drag.
|
51
|
+
|
52
|
+
If the user clicks the track, we adjust the value a page at a time, unless
|
53
|
+
alt is pressed, in which case we scroll to that position.
|
54
|
+
|
55
|
+
If the user clicks the buttons, we adjust the value by a fixed amount, unless
|
56
|
+
alt is pressed, in which case we adjust by a page.
|
57
|
+
|
58
|
+
If the user clicks and holds on either the track or buttons, those actions
|
59
|
+
are repeated until they release the mouse button.
|
60
|
+
|
61
|
+
@param evt {SC.Event} the mousedown event
|
62
|
+
*/
|
63
|
+
mouseDown: function (evt) {
|
64
|
+
if (!this.get('isEnabled')) return NO;
|
65
|
+
|
66
|
+
var target = evt.target,
|
67
|
+
thumbPosition = this.get('thumbPosition'),
|
68
|
+
value, clickLocation, clickOffset,
|
69
|
+
scrollerLength = this.get('scrollerLength');
|
70
|
+
|
71
|
+
// Determine the subcontrol that was clicked
|
72
|
+
if (target.className.indexOf('thumb') >= 0) {
|
73
|
+
// Convert the mouseDown coordinates to the view's coordinates
|
74
|
+
clickLocation = this.convertFrameFromView({ x: evt.pageX,
|
75
|
+
y: evt.pageY });
|
76
|
+
|
77
|
+
clickLocation.x -= thumbPosition;
|
78
|
+
clickLocation.y -= thumbPosition;
|
79
|
+
|
80
|
+
// Store the starting state so we know how much to adjust the
|
81
|
+
// thumb when the user drags
|
82
|
+
this._thumbDragging = YES;
|
83
|
+
this._thumbOffset = clickLocation;
|
84
|
+
this._mouseDownLocation = { x: evt.pageX,
|
85
|
+
y: evt.pageY };
|
86
|
+
this._thumbPositionAtDragStart = this.get('thumbPosition');
|
87
|
+
this._valueAtDragStart = this.get("value");
|
88
|
+
|
89
|
+
// User clicked the up/left button; decrement the value by a fixed amount or page size
|
90
|
+
} else if (target.className.indexOf('button-top') >= 0) {
|
91
|
+
this.decrementProperty('value', 30);
|
92
|
+
this.makeButtonActive('.button-top');
|
93
|
+
|
94
|
+
// start a timer that will continue to fire until mouseUp is called
|
95
|
+
this.startMouseDownTimer('scrollUp');
|
96
|
+
this._isScrollingUp = YES;
|
97
|
+
|
98
|
+
// User clicked the down/right button; increment the value by a fixed amount
|
99
|
+
} else if (target.className.indexOf('button-bottom') >= 0) {
|
100
|
+
this.incrementProperty('value', 30);
|
101
|
+
this.makeButtonActive('.button-bottom');
|
102
|
+
|
103
|
+
// start a timer that will continue to fire until mouseUp is called
|
104
|
+
this.startMouseDownTimer('scrollDown');
|
105
|
+
this._isScrollingDown = YES;
|
106
|
+
|
107
|
+
// User clicked in the track
|
108
|
+
} else {
|
109
|
+
var scrollToClick = this.get("shouldScrollToClick"),
|
110
|
+
trackLength = this.get('trackLength'),
|
111
|
+
thumbLength = this.get('thumbLength'),
|
112
|
+
frame = this.convertFrameFromView({ x: evt.pageX, y: evt.pageY }),
|
113
|
+
mousePosition;
|
114
|
+
|
115
|
+
if (evt.altKey) scrollToClick = !scrollToClick;
|
116
|
+
|
117
|
+
switch (this.get('layoutDirection')) {
|
118
|
+
case SC.LAYOUT_VERTICAL:
|
119
|
+
this._mouseDownLocation = mousePosition = frame.y;
|
120
|
+
break;
|
121
|
+
case SC.LAYOUT_HORIZONTAL:
|
122
|
+
this._mouseDownLocation = mousePosition = frame.x;
|
123
|
+
break;
|
124
|
+
}
|
125
|
+
|
126
|
+
if (scrollToClick) {
|
127
|
+
this.set('value', this.valueForPosition(mousePosition - (thumbLength / 2)));
|
128
|
+
|
129
|
+
// and start a normal mouse down
|
130
|
+
thumbPosition = this.get('thumbPosition');
|
131
|
+
|
132
|
+
this._thumbDragging = YES;
|
133
|
+
this._thumbOffset = { x: frame.x - thumbPosition,
|
134
|
+
y: frame.y - thumbPosition };
|
135
|
+
this._mouseDownLocation = { x: evt.pageX,
|
136
|
+
y: evt.pageY };
|
137
|
+
this._thumbPositionAtDragStart = thumbPosition;
|
138
|
+
this._valueAtDragStart = this.get("value");
|
139
|
+
|
140
|
+
// Move the thumb up or down a page depending on whether the click
|
141
|
+
// was above or below the thumb
|
142
|
+
} else if (mousePosition < thumbPosition) {
|
143
|
+
this.decrementProperty('value', scrollerLength);
|
144
|
+
this.startMouseDownTimer('page');
|
145
|
+
|
146
|
+
} else {
|
147
|
+
this.incrementProperty('value', scrollerLength);
|
148
|
+
this.startMouseDownTimer('page');
|
149
|
+
}
|
150
|
+
}
|
151
|
+
|
152
|
+
return YES;
|
153
|
+
},
|
154
|
+
|
155
|
+
/** @private
|
156
|
+
When the user releases the mouse button, remove any active
|
157
|
+
state from the button controls, and cancel any outstanding
|
158
|
+
timers.
|
159
|
+
|
160
|
+
@param evt {SC.Event} the mousedown event
|
161
|
+
*/
|
162
|
+
mouseUp: function (evt) {
|
163
|
+
var active = this._scs_buttonActive,
|
164
|
+
ret = NO, timer;
|
165
|
+
|
166
|
+
// If we have an element that was set as active in mouseDown,
|
167
|
+
// remove its active state
|
168
|
+
if (active) {
|
169
|
+
active.removeClass('active');
|
170
|
+
ret = YES;
|
171
|
+
}
|
172
|
+
|
173
|
+
// Stop firing repeating events after mouseup
|
174
|
+
timer = this._mouseDownTimer;
|
175
|
+
if (timer) {
|
176
|
+
timer.invalidate();
|
177
|
+
this._mouseDownTimer = null;
|
178
|
+
}
|
179
|
+
|
180
|
+
this._thumbDragging = NO;
|
181
|
+
this._isScrollingDown = NO;
|
182
|
+
this._isScrollingUp = NO;
|
183
|
+
|
184
|
+
return ret;
|
185
|
+
},
|
186
|
+
|
187
|
+
/** @private
|
188
|
+
If the user began the drag on the thumb, we calculate the difference
|
189
|
+
between the mouse position at click and where it is now. We then
|
190
|
+
offset the thumb by that amount, within the bounds of the track.
|
191
|
+
|
192
|
+
If the user began scrolling up/down using the buttons, this will track
|
193
|
+
what component they are currently over, changing the scroll direction.
|
194
|
+
|
195
|
+
@param evt {SC.Event} the mousedragged event
|
196
|
+
*/
|
197
|
+
mouseDragged: function (evt) {
|
198
|
+
var value, length, delta, thumbPosition,
|
199
|
+
target = evt.target,
|
200
|
+
thumbPositionAtDragStart = this._thumbPositionAtDragStart,
|
201
|
+
isScrollingUp = this._isScrollingUp,
|
202
|
+
isScrollingDown = this._isScrollingDown,
|
203
|
+
active = this._scs_buttonActive,
|
204
|
+
timer;
|
205
|
+
|
206
|
+
// Only move the thumb if the user clicked on the thumb during mouseDown
|
207
|
+
if (this._thumbDragging) {
|
208
|
+
switch (this.get('layoutDirection')) {
|
209
|
+
case SC.LAYOUT_VERTICAL:
|
210
|
+
delta = (evt.pageY - this._mouseDownLocation.y);
|
211
|
+
break;
|
212
|
+
case SC.LAYOUT_HORIZONTAL:
|
213
|
+
delta = (evt.pageX - this._mouseDownLocation.x);
|
214
|
+
break;
|
215
|
+
}
|
216
|
+
|
217
|
+
thumbPosition = thumbPositionAtDragStart + delta;
|
218
|
+
length = this.get('trackLength') - this.get('thumbLength');
|
219
|
+
this.set('value', Math.round( (thumbPosition/length) * this.get('maximum')));
|
220
|
+
|
221
|
+
} else if (isScrollingUp || isScrollingDown) {
|
222
|
+
var nowScrollingUp = NO, nowScrollingDown = NO;
|
223
|
+
|
224
|
+
var topButtonRect = this.$('.button-top')[0].getBoundingClientRect();
|
225
|
+
var bottomButtonRect = this.$('.button-bottom')[0].getBoundingClientRect();
|
226
|
+
|
227
|
+
switch (this.get('layoutDirection')) {
|
228
|
+
case SC.LAYOUT_VERTICAL:
|
229
|
+
nowScrollingUp = (evt.clientY < topButtonRect.bottom);
|
230
|
+
break;
|
231
|
+
case SC.LAYOUT_HORIZONTAL:
|
232
|
+
nowScrollingUp = (evt.clientX < topButtonRect.right);
|
233
|
+
break;
|
234
|
+
}
|
235
|
+
nowScrollingDown = !nowScrollingUp;
|
236
|
+
|
237
|
+
if ((nowScrollingUp || nowScrollingDown) && nowScrollingUp !== isScrollingUp) {
|
238
|
+
// If we have an element that was set as active in mouseDown,
|
239
|
+
// remove its active state
|
240
|
+
if (active) active.removeClass('active');
|
241
|
+
|
242
|
+
// Stop firing repeating events after mouseup
|
243
|
+
this._mouseDownTimerAction = nowScrollingUp ? "scrollUp" : "scrollDown";
|
244
|
+
|
245
|
+
if (nowScrollingUp) {
|
246
|
+
this.makeButtonActive('.button-top');
|
247
|
+
} else if (nowScrollingDown) {
|
248
|
+
this.makeButtonActive('.button-bottom');
|
249
|
+
}
|
250
|
+
|
251
|
+
this._isScrollingUp = nowScrollingUp;
|
252
|
+
this._isScrollingDown = nowScrollingDown;
|
253
|
+
}
|
254
|
+
}
|
255
|
+
|
256
|
+
return YES;
|
257
|
+
},
|
258
|
+
|
259
|
+
mouseWheel: function (evt) {
|
260
|
+
var el = this.getPath('parentView.containerView.layer'),
|
261
|
+
rawEvent = evt.originalEvent;
|
262
|
+
|
263
|
+
if (el && rawEvent) {
|
264
|
+
try {
|
265
|
+
if (SC.typeOf(el.fireEvent) === SC.T_FUNCTION) { // IE
|
266
|
+
el.fireEvent(rawEvent.type, rawEvent);
|
267
|
+
} else { // W3C
|
268
|
+
el.dispatchEvent(rawEvent);
|
269
|
+
}
|
270
|
+
} catch (x) {
|
271
|
+
// Can't dispatch the event; give up.
|
272
|
+
}
|
273
|
+
}
|
274
|
+
},
|
275
|
+
|
276
|
+
/** @private
|
277
|
+
Starts a timer that fires after 300ms. This is called when the user
|
278
|
+
clicks a button or inside the track to move a page at a time. If they
|
279
|
+
continue holding the mouse button down, we want to repeat that action
|
280
|
+
after a small delay. This timer will be invalidated in mouseUp.
|
281
|
+
|
282
|
+
Specify "immediate" as YES if it should not wait.
|
283
|
+
*/
|
284
|
+
startMouseDownTimer: function (action, immediate) {
|
285
|
+
this._mouseDownTimerAction = action;
|
286
|
+
this._mouseDownTimer = SC.Timer.schedule({
|
287
|
+
target: this,
|
288
|
+
action: this.mouseDownTimerDidFire,
|
289
|
+
interval: immediate ? 0 : 300
|
290
|
+
});
|
291
|
+
},
|
292
|
+
|
293
|
+
/** @private
|
294
|
+
Called by the mousedown timer. This method determines the initial
|
295
|
+
user action and repeats it until the timer is invalidated in mouseUp.
|
296
|
+
*/
|
297
|
+
mouseDownTimerDidFire: function () {
|
298
|
+
var scrollerLength = this.get('scrollerLength'),
|
299
|
+
mouseLocation = SC.device.get('mouseLocation'),
|
300
|
+
thumbPosition = this.get('thumbPosition'),
|
301
|
+
thumbLength = this.get('thumbLength'),
|
302
|
+
timerInterval = 50;
|
303
|
+
|
304
|
+
switch (this.get('layoutDirection')) {
|
305
|
+
case SC.LAYOUT_VERTICAL:
|
306
|
+
mouseLocation = this.convertFrameFromView(mouseLocation).y;
|
307
|
+
break;
|
308
|
+
case SC.LAYOUT_HORIZONTAL:
|
309
|
+
mouseLocation = this.convertFrameFromView(mouseLocation).x;
|
310
|
+
break;
|
311
|
+
}
|
312
|
+
|
313
|
+
switch (this._mouseDownTimerAction) {
|
314
|
+
case 'scrollDown':
|
315
|
+
this.incrementProperty('value', 30);
|
316
|
+
break;
|
317
|
+
case 'scrollUp':
|
318
|
+
this.decrementProperty('value', 30);
|
319
|
+
break;
|
320
|
+
case 'page':
|
321
|
+
timerInterval = 150;
|
322
|
+
if (mouseLocation < thumbPosition) {
|
323
|
+
this.decrementProperty('value', scrollerLength);
|
324
|
+
} else if (mouseLocation > thumbPosition+thumbLength) {
|
325
|
+
this.incrementProperty('value', scrollerLength);
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
this._mouseDownTimer = SC.Timer.schedule({
|
330
|
+
target: this,
|
331
|
+
action: this.mouseDownTimerDidFire,
|
332
|
+
interval: timerInterval
|
333
|
+
});
|
334
|
+
},
|
335
|
+
|
336
|
+
/** @private
|
337
|
+
Given a selector, finds the corresponding DOM element and adds
|
338
|
+
the 'active' class name. Also stores the returned element so that
|
339
|
+
the 'active' class name can be removed during mouseup.
|
340
|
+
|
341
|
+
@param {String} the selector to find
|
342
|
+
*/
|
343
|
+
makeButtonActive: function (selector) {
|
344
|
+
this._scs_buttonActive = this.$(selector).addClass('active');
|
345
|
+
}
|
346
|
+
|
347
|
+
});
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2011 Strobe Inc. and contributors.
|
4
|
+
// License: Licensed under MIT license (see license.js)
|
5
|
+
// ==========================================================================
|
6
|
+
|
7
|
+
sc_require('views/desktop/scroll');
|
8
|
+
sc_require('views/touch/scroll');
|
9
|
+
|
10
|
+
SC.ScrollView = SC.platform.touch ? SC.TouchScrollView : SC.DesktopScrollView;
|
11
|
+
|
12
|
+
// Spoofed browsers should use TouchScrollView.
|
13
|
+
if (SC.browser && SC.platform && SC.browser.mobileSafari && !SC.platform.touch) {
|
14
|
+
SC.ScrollView = SC.TouchScrollView;
|
15
|
+
}
|
data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/scroller.js
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2011 Strobe Inc. and contributors.
|
4
|
+
// License: Licensed under MIT license (see license.js)
|
5
|
+
// ==========================================================================
|
6
|
+
|
7
|
+
sc_require('views/desktop/scroller');
|
8
|
+
|
9
|
+
// Legacy ScrollerView === DesktopScrollerView
|
10
|
+
SC.ScrollerView = SC.DesktopScrollerView;
|
data/lib/frameworks/sproutcore/frameworks/experimental/frameworks/scroll_view/views/touch/scroll.js
ADDED
@@ -0,0 +1,804 @@
|
|
1
|
+
// ==========================================================================
|
2
|
+
// Project: SproutCore - JavaScript Application Framework
|
3
|
+
// Copyright: ©2006-2011 Strobe Inc. and contributors.
|
4
|
+
// Portions ©2008-2011 Apple Inc. All rights reserved.
|
5
|
+
// License: Licensed under MIT license (see license.js)
|
6
|
+
// ==========================================================================
|
7
|
+
|
8
|
+
sc_require('views/core_scroll');
|
9
|
+
sc_require('views/touch/scroller');
|
10
|
+
|
11
|
+
/**
|
12
|
+
@static
|
13
|
+
@type Number
|
14
|
+
@default 0.95
|
15
|
+
*/
|
16
|
+
SC.NORMAL_SCROLL_DECELERATION = 0.95;
|
17
|
+
|
18
|
+
/**
|
19
|
+
@static
|
20
|
+
@type Number
|
21
|
+
@default 0.85
|
22
|
+
*/
|
23
|
+
SC.FAST_SCROLL_DECELERATION = 0.85;
|
24
|
+
|
25
|
+
|
26
|
+
/** @class
|
27
|
+
Implements touch events for a scroll view
|
28
|
+
|
29
|
+
Since the iPad doesn't allow native one-finger scrolling,
|
30
|
+
this has to do all of the work of implementing the solution
|
31
|
+
over again.
|
32
|
+
|
33
|
+
In addition to the one-finger scrolling, this view implements
|
34
|
+
edge-resistance.
|
35
|
+
|
36
|
+
Note that incremental rendering is done after the scrolling
|
37
|
+
has completely finished, which makes for a wait-and-see
|
38
|
+
experience.
|
39
|
+
|
40
|
+
@extends SC.CoreScrollerView
|
41
|
+
*/
|
42
|
+
SC.TouchScrollView = SC.CoreScrollView.extend(
|
43
|
+
/** @scope SC.TouchScrollView.prototype */{
|
44
|
+
|
45
|
+
/**
|
46
|
+
Use this to overlay the vertical scroller.
|
47
|
+
|
48
|
+
This ensures that the container frame will not resize to accomodate the
|
49
|
+
vertical scroller, hence overlaying the scroller on top of
|
50
|
+
the container.
|
51
|
+
|
52
|
+
@type Boolean
|
53
|
+
@default YES
|
54
|
+
*/
|
55
|
+
verticalOverlay: YES,
|
56
|
+
|
57
|
+
/**
|
58
|
+
Use this to overlay the horizontal scroller.
|
59
|
+
|
60
|
+
This ensures that the container frame will not resize to accomodate the
|
61
|
+
horizontal scroller, hence overlaying the scroller on top of
|
62
|
+
the container
|
63
|
+
|
64
|
+
@type Boolean
|
65
|
+
@default YES
|
66
|
+
*/
|
67
|
+
horizontalOverlay: YES,
|
68
|
+
|
69
|
+
/**
|
70
|
+
@type SC.CoreScrollerView
|
71
|
+
@default SC.TouchScrollerView
|
72
|
+
*/
|
73
|
+
horizontalScrollerView: SC.TouchScrollerView,
|
74
|
+
|
75
|
+
/**
|
76
|
+
@type SC.CoreScrollerView
|
77
|
+
@default SC.TouchScrollerView
|
78
|
+
*/
|
79
|
+
verticalScrollerView: SC.TouchScrollerView,
|
80
|
+
|
81
|
+
// ..........................................................
|
82
|
+
// TOUCH SUPPORT
|
83
|
+
//
|
84
|
+
|
85
|
+
/**
|
86
|
+
@type Boolean
|
87
|
+
@default YES
|
88
|
+
@readOnly
|
89
|
+
*/
|
90
|
+
acceptsMultitouch: YES,
|
91
|
+
|
92
|
+
/**
|
93
|
+
The scroll deceleration rate.
|
94
|
+
|
95
|
+
@type Number
|
96
|
+
@default SC.NORMAL_SCROLL_DECELERATION
|
97
|
+
*/
|
98
|
+
decelerationRate: SC.NORMAL_SCROLL_DECELERATION,
|
99
|
+
|
100
|
+
/**
|
101
|
+
If YES, bouncing will always be enabled in the horizontal direction, even if the content
|
102
|
+
is smaller or the same size as the view.
|
103
|
+
|
104
|
+
@type Boolean
|
105
|
+
@default NO
|
106
|
+
*/
|
107
|
+
alwaysBounceHorizontal: NO,
|
108
|
+
|
109
|
+
/**
|
110
|
+
If NO, bouncing will not be enabled in the vertical direction when the content is smaller
|
111
|
+
or the same size as the scroll view.
|
112
|
+
|
113
|
+
@type Boolean
|
114
|
+
@default YES
|
115
|
+
*/
|
116
|
+
alwaysBounceVertical: YES,
|
117
|
+
|
118
|
+
/**
|
119
|
+
Whether to delay touches from passing through to the content.
|
120
|
+
|
121
|
+
@type Boolean
|
122
|
+
@default YES
|
123
|
+
*/
|
124
|
+
delaysContentTouches: YES,
|
125
|
+
|
126
|
+
/** @private */
|
127
|
+
_applyCSSTransforms: function (layer) {
|
128
|
+
var transform = "";
|
129
|
+
this.updateScale(this._scale);
|
130
|
+
transform += 'translate3d('+ -this._scroll_horizontalScrollOffset +'px, '+ -Math.round(this._scroll_verticalScrollOffset)+'px,0) ';
|
131
|
+
transform += this._scale_css;
|
132
|
+
if (layer) {
|
133
|
+
layer.style.webkitTransform = transform;
|
134
|
+
layer.style.webkitTransformOrigin = "top left";
|
135
|
+
}
|
136
|
+
},
|
137
|
+
|
138
|
+
/** @private */
|
139
|
+
captureTouch: function (touch) {
|
140
|
+
return YES;
|
141
|
+
},
|
142
|
+
|
143
|
+
/** @private */
|
144
|
+
touchGeneration: 0,
|
145
|
+
|
146
|
+
/** @private */
|
147
|
+
touchStart: function (touch) {
|
148
|
+
var generation = ++this.touchGeneration;
|
149
|
+
if (!this.tracking && this.get("delaysContentTouches")) {
|
150
|
+
this.invokeLater(this.beginTouchesInContent, 150, generation);
|
151
|
+
} else if (!this.tracking) {
|
152
|
+
// NOTE: We still have to delay because we don't want to call touchStart
|
153
|
+
// while touchStart is itself being called...
|
154
|
+
this.invokeLater(this.beginTouchesInContent, 1, generation);
|
155
|
+
}
|
156
|
+
this.beginTouchTracking(touch, YES);
|
157
|
+
return YES;
|
158
|
+
},
|
159
|
+
|
160
|
+
/** @private */
|
161
|
+
beginTouchesInContent: function (gen) {
|
162
|
+
if (gen !== this.touchGeneration) return;
|
163
|
+
|
164
|
+
var touch = this.touch, itemView;
|
165
|
+
if (touch && this.tracking && !this.dragging && !touch.touch.scrollHasEnded) {
|
166
|
+
// try to capture the touch
|
167
|
+
touch.touch.captureTouch(this, YES);
|
168
|
+
|
169
|
+
if (!touch.touch.touchResponder) {
|
170
|
+
// if it DIDN'T WORK!!!!!
|
171
|
+
// then we need to take possession again.
|
172
|
+
touch.touch.makeTouchResponder(this);
|
173
|
+
// Otherwise, it did work, and if we had a pending scroll end, we must do it now
|
174
|
+
} else if (touch.needsScrollEnd) {
|
175
|
+
this._touchScrollDidEnd();
|
176
|
+
}
|
177
|
+
}
|
178
|
+
},
|
179
|
+
|
180
|
+
/** @private
|
181
|
+
This will notify anything that's incrementally rendering while
|
182
|
+
scrolling, instead of having unrendered views.
|
183
|
+
*/
|
184
|
+
_sctsv_setOffset: function (x, y) {
|
185
|
+
if (!SC.none(x)) {
|
186
|
+
this._scroll_horizontalScrollOffset = x;
|
187
|
+
}
|
188
|
+
|
189
|
+
if (!SC.none(y)) {
|
190
|
+
this._scroll_verticalScrollOffset = y;
|
191
|
+
}
|
192
|
+
},
|
193
|
+
|
194
|
+
/** @private
|
195
|
+
Initializes the start state of the gesture.
|
196
|
+
|
197
|
+
We keep information about the initial location of the touch so we can
|
198
|
+
disambiguate between a tap and a drag.
|
199
|
+
|
200
|
+
@param {Event} evt
|
201
|
+
*/
|
202
|
+
beginTouchTracking: function (touch, starting) {
|
203
|
+
var avg = touch.averagedTouchesForView(this, starting);
|
204
|
+
|
205
|
+
var verticalScrollOffset = this._scroll_verticalScrollOffset || 0,
|
206
|
+
horizontalScrollOffset = this._scroll_horizontalScrollOffset || 0,
|
207
|
+
startClipOffsetX = horizontalScrollOffset,
|
208
|
+
startClipOffsetY = verticalScrollOffset,
|
209
|
+
needsScrollEnd = NO;
|
210
|
+
|
211
|
+
this.willScroll(this);
|
212
|
+
|
213
|
+
if (this.touch && this.touch.timeout) {
|
214
|
+
// clear the timeout
|
215
|
+
clearTimeout(this.touch.timeout);
|
216
|
+
this.touch.timeout = null;
|
217
|
+
|
218
|
+
// get the scroll offsets
|
219
|
+
startClipOffsetX = this.touch.startClipOffset.x;
|
220
|
+
startClipOffsetY = this.touch.startClipOffset.y;
|
221
|
+
needsScrollEnd = YES;
|
222
|
+
}
|
223
|
+
|
224
|
+
// calculate container+content width/height
|
225
|
+
var view = this.get('contentView') ;
|
226
|
+
var contentWidth = view ? view.get('frame').width : 0,
|
227
|
+
contentHeight = view ? view.get('frame').height : 0;
|
228
|
+
|
229
|
+
if (view.calculatedWidth && view.calculatedWidth!==0) contentWidth = view.get('calculatedWidth');
|
230
|
+
if (view.calculatedHeight && view.calculatedHeight !==0) contentHeight = view.get('calculatedHeight');
|
231
|
+
|
232
|
+
var containerWidth = this.get('containerView').get('frame').width,
|
233
|
+
containerHeight = this.get('containerView').get('frame').height;
|
234
|
+
|
235
|
+
// calculate position in content
|
236
|
+
var globalFrame = this.convertFrameToView(this.get("frame"), null),
|
237
|
+
positionInContentX = (horizontalScrollOffset + (avg.x - globalFrame.x)) / this._scale,
|
238
|
+
positionInContentY = (verticalScrollOffset + (avg.y - globalFrame.y)) / this._scale;
|
239
|
+
|
240
|
+
this.touch = {
|
241
|
+
startTime: touch.timeStamp,
|
242
|
+
notCalculated: YES,
|
243
|
+
|
244
|
+
enableScrolling: {
|
245
|
+
x: contentWidth * this._scale > containerWidth || this.get("alwaysBounceHorizontal"),
|
246
|
+
y: contentHeight * this._scale > containerHeight || this.get("alwaysBounceVertical")
|
247
|
+
},
|
248
|
+
scrolling: { x: NO, y: NO },
|
249
|
+
|
250
|
+
enableBouncing: SC.platform.bounceOnScroll,
|
251
|
+
|
252
|
+
// offsets and velocities
|
253
|
+
startClipOffset: { x: startClipOffsetX, y: startClipOffsetY },
|
254
|
+
lastScrollOffset: { x: horizontalScrollOffset, y: verticalScrollOffset },
|
255
|
+
startTouchOffset: { x: avg.x, y: avg.y },
|
256
|
+
scrollVelocity: { x: 0, y: 0 },
|
257
|
+
|
258
|
+
startTouchOffsetInContent: { x: positionInContentX, y: positionInContentY },
|
259
|
+
|
260
|
+
containerSize: { width: containerWidth, height: containerHeight },
|
261
|
+
contentSize: { width: contentWidth, height: contentHeight },
|
262
|
+
|
263
|
+
startScale: this._scale,
|
264
|
+
startDistance: avg.d,
|
265
|
+
canScale: this.get("canScale") && SC.platform.pinchToZoom,
|
266
|
+
minimumScale: this.get("minimumScale"),
|
267
|
+
maximumScale: this.get("maximumScale"),
|
268
|
+
|
269
|
+
globalFrame: globalFrame,
|
270
|
+
|
271
|
+
// cache some things
|
272
|
+
layer: this.get("contentView").get('layer'),
|
273
|
+
|
274
|
+
// some constants
|
275
|
+
resistanceCoefficient: 0.998,
|
276
|
+
resistanceAsymptote: 320,
|
277
|
+
decelerationFromEdge: 0.05,
|
278
|
+
accelerationToEdge: 0.1,
|
279
|
+
|
280
|
+
// how much percent of the other drag direction you must drag to start dragging that direction too.
|
281
|
+
scrollTolerance: { x: 15, y: 15 },
|
282
|
+
scaleTolerance: 5,
|
283
|
+
secondaryScrollTolerance: 30,
|
284
|
+
scrollLock: 500,
|
285
|
+
|
286
|
+
decelerationRate: this.get("decelerationRate"),
|
287
|
+
|
288
|
+
// general status
|
289
|
+
lastEventTime: touch.timeStamp,
|
290
|
+
|
291
|
+
// the touch used
|
292
|
+
touch: (starting ? touch : (this.touch ? this.touch.touch : null)),
|
293
|
+
|
294
|
+
// needsScrollEnd will cause a scrollDidEnd even if this particular touch does not start a scroll.
|
295
|
+
// the reason for this is because we don't want to say we've stopped scrolling just because we got
|
296
|
+
// another touch, but simultaneously, we still need to send a touch end eventually.
|
297
|
+
// there are two cases in which this will be used:
|
298
|
+
//
|
299
|
+
// 1. If the touch was sent to content touches (in which case we will not be scrolling)
|
300
|
+
// 2. If the touch ends before scrolling starts (no scrolling then, either)
|
301
|
+
needsScrollEnd: needsScrollEnd
|
302
|
+
};
|
303
|
+
|
304
|
+
if (!this.tracking) {
|
305
|
+
this.tracking = YES;
|
306
|
+
this.dragging = NO;
|
307
|
+
}
|
308
|
+
},
|
309
|
+
|
310
|
+
/** @private */
|
311
|
+
_adjustForEdgeResistance: function (offset, minOffset, maxOffset, resistanceCoefficient, asymptote) {
|
312
|
+
var distanceFromEdge;
|
313
|
+
|
314
|
+
// find distance from edge
|
315
|
+
if (offset < minOffset) distanceFromEdge = offset - minOffset;
|
316
|
+
else if (offset > maxOffset) distanceFromEdge = maxOffset - offset;
|
317
|
+
else return offset;
|
318
|
+
|
319
|
+
// manipulate logarithmically
|
320
|
+
distanceFromEdge = Math.pow(resistanceCoefficient, Math.abs(distanceFromEdge)) * asymptote;
|
321
|
+
|
322
|
+
// adjust mathematically
|
323
|
+
if (offset < minOffset) distanceFromEdge = distanceFromEdge - asymptote;
|
324
|
+
else distanceFromEdge = -distanceFromEdge + asymptote;
|
325
|
+
|
326
|
+
// generate final value
|
327
|
+
return Math.min(Math.max(minOffset, offset), maxOffset) + distanceFromEdge;
|
328
|
+
},
|
329
|
+
|
330
|
+
/** @private */
|
331
|
+
touchesDragged: function (evt, touches) {
|
332
|
+
var avg = evt.averagedTouchesForView(this);
|
333
|
+
this.updateTouchScroll(avg.x, avg.y, avg.d, evt.timeStamp);
|
334
|
+
},
|
335
|
+
|
336
|
+
/** @private */
|
337
|
+
updateTouchScroll: function (touchX, touchY, distance, timeStamp) {
|
338
|
+
// get some vars
|
339
|
+
var touch = this.touch,
|
340
|
+
touchXInFrame = touchX - touch.globalFrame.x,
|
341
|
+
touchYInFrame = touchY - touch.globalFrame.y,
|
342
|
+
offsetY,
|
343
|
+
maxOffsetY,
|
344
|
+
offsetX,
|
345
|
+
maxOffsetX,
|
346
|
+
minOffsetX, minOffsetY;
|
347
|
+
|
348
|
+
// calculate new position in content
|
349
|
+
var positionInContentX = ((this._scroll_horizontalScrollOffset||0) + touchXInFrame) / this._scale,
|
350
|
+
positionInContentY = ((this._scroll_verticalScrollOffset||0) + touchYInFrame) / this._scale;
|
351
|
+
|
352
|
+
// calculate deltas
|
353
|
+
var deltaX = positionInContentX - touch.startTouchOffsetInContent.x,
|
354
|
+
deltaY = positionInContentY - touch.startTouchOffsetInContent.y;
|
355
|
+
|
356
|
+
var isDragging = touch.dragging;
|
357
|
+
if (!touch.scrolling.x && Math.abs(deltaX) > touch.scrollTolerance.x && touch.enableScrolling.x) {
|
358
|
+
// say we are scrolling
|
359
|
+
isDragging = YES;
|
360
|
+
touch.scrolling.x = YES;
|
361
|
+
touch.scrollTolerance.y = touch.secondaryScrollTolerance;
|
362
|
+
|
363
|
+
// reset position
|
364
|
+
touch.startTouchOffset.x = touchX;
|
365
|
+
deltaX = 0;
|
366
|
+
}
|
367
|
+
if (!touch.scrolling.y && Math.abs(deltaY) > touch.scrollTolerance.y && touch.enableScrolling.y) {
|
368
|
+
// say we are scrolling
|
369
|
+
isDragging = YES;
|
370
|
+
touch.scrolling.y = YES;
|
371
|
+
touch.scrollTolerance.x = touch.secondaryScrollTolerance;
|
372
|
+
|
373
|
+
// reset position
|
374
|
+
touch.startTouchOffset.y = touchY;
|
375
|
+
deltaY = 0;
|
376
|
+
}
|
377
|
+
|
378
|
+
// handle scroll start
|
379
|
+
if (isDragging && !touch.dragging) {
|
380
|
+
touch.dragging = YES;
|
381
|
+
this.dragging = YES;
|
382
|
+
this._touchScrollDidStart();
|
383
|
+
}
|
384
|
+
|
385
|
+
// calculate new offset
|
386
|
+
if (!touch.scrolling.x && !touch.scrolling.y && !touch.canScale) return;
|
387
|
+
if (touch.scrolling.x && !touch.scrolling.y) {
|
388
|
+
if (deltaX > touch.scrollLock && !touch.scrolling.y) touch.enableScrolling.y = NO;
|
389
|
+
}
|
390
|
+
if (touch.scrolling.y && !touch.scrolling.x) {
|
391
|
+
if (deltaY > touch.scrollLock && !touch.scrolling.x) touch.enableScrolling.x = NO;
|
392
|
+
}
|
393
|
+
|
394
|
+
// handle scaling through pinch gesture
|
395
|
+
if (touch.canScale) {
|
396
|
+
|
397
|
+
var startDistance = touch.startDistance, dd = distance - startDistance;
|
398
|
+
if (Math.abs(dd) > touch.scaleTolerance) {
|
399
|
+
touch.scrolling.y = YES; // if you scale, you can scroll.
|
400
|
+
touch.scrolling.x = YES;
|
401
|
+
|
402
|
+
// we want to say something that was the startDistance away from each other should now be
|
403
|
+
// distance away. So, if we are twice as far away as we started...
|
404
|
+
var scale = touch.startScale * (distance / Math.max(startDistance, 50));
|
405
|
+
|
406
|
+
var newScale = this._adjustForEdgeResistance(scale, touch.minimumScale, touch.maximumScale, touch.resistanceCoefficient, touch.resistanceAsymptote);
|
407
|
+
this.dragging = YES;
|
408
|
+
this._scale = newScale;
|
409
|
+
var newPositionInContentX = positionInContentX * this._scale,
|
410
|
+
newPositionInContentY = positionInContentY * this._scale;
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
// these do exactly what they sound like. So, this comment is just to
|
415
|
+
// block off the code a bit
|
416
|
+
// In english, these calculate the minimum X/Y offsets
|
417
|
+
minOffsetX = this.minimumScrollOffset(touch.contentSize.width * this._scale,
|
418
|
+
touch.containerSize.width, this.get("horizontalAlign"));
|
419
|
+
minOffsetY = this.minimumScrollOffset(touch.contentSize.height * this._scale,
|
420
|
+
touch.containerSize.height, this.get("verticalAlign"));
|
421
|
+
|
422
|
+
// and now, maximum...
|
423
|
+
maxOffsetX = this.maximumScrollOffset(touch.contentSize.width * this._scale,
|
424
|
+
touch.containerSize.width, this.get("horizontalAlign"));
|
425
|
+
maxOffsetY = this.maximumScrollOffset(touch.contentSize.height * this._scale,
|
426
|
+
touch.containerSize.height, this.get("verticalAlign"));
|
427
|
+
|
428
|
+
// So, the following is the completely written out algebra:
|
429
|
+
// (offsetY + touchYInFrame) / this._scale = touch.startTouchOffsetInContent.y
|
430
|
+
// offsetY + touchYInFrame = touch.startTouchOffsetInContent.y * this._scale;
|
431
|
+
// offsetY = touch.startTouchOffset * this._scale - touchYInFrame
|
432
|
+
|
433
|
+
// and the result applied:
|
434
|
+
offsetX = touch.startTouchOffsetInContent.x * this._scale - touchXInFrame;
|
435
|
+
offsetY = touch.startTouchOffsetInContent.y * this._scale - touchYInFrame;
|
436
|
+
|
437
|
+
|
438
|
+
// we need to adjust for edge resistance, or, if bouncing is disabled, just stop flat.
|
439
|
+
if (touch.enableBouncing) {
|
440
|
+
offsetX = this._adjustForEdgeResistance(offsetX, minOffsetX, maxOffsetX, touch.resistanceCoefficient, touch.resistanceAsymptote);
|
441
|
+
offsetY = this._adjustForEdgeResistance(offsetY, minOffsetY, maxOffsetY, touch.resistanceCoefficient, touch.resistanceAsymptote);
|
442
|
+
} else {
|
443
|
+
offsetX = Math.max(minOffsetX, Math.min(maxOffsetX, offsetX));
|
444
|
+
offsetY = Math.max(minOffsetY, Math.min(maxOffsetY, offsetY));
|
445
|
+
}
|
446
|
+
|
447
|
+
// and now, _if_ scrolling is enabled, set the new coordinates
|
448
|
+
if (touch.scrolling.x) this._sctsv_setOffset(offsetX, null);
|
449
|
+
if (touch.scrolling.y) this._sctsv_setOffset(null, offsetY);
|
450
|
+
|
451
|
+
// and apply the CSS transforms.
|
452
|
+
this._applyCSSTransforms(touch.layer);
|
453
|
+
this._touchScrollDidChange();
|
454
|
+
|
455
|
+
|
456
|
+
// prepare for momentum scrolling by calculating the momentum.
|
457
|
+
if ((timeStamp - touch.lastEventTime) >= 1 || touch.notCalculated) {
|
458
|
+
touch.notCalculated = NO;
|
459
|
+
var horizontalOffset = this._scroll_horizontalScrollOffset;
|
460
|
+
var verticalOffset = this._scroll_verticalScrollOffset;
|
461
|
+
|
462
|
+
touch.scrollVelocity.x = (horizontalOffset - touch.lastScrollOffset.x) /
|
463
|
+
Math.max(1, timeStamp - touch.lastEventTime); // in px per ms
|
464
|
+
touch.scrollVelocity.y = (verticalOffset - touch.lastScrollOffset.y) /
|
465
|
+
Math.max(1, timeStamp - touch.lastEventTime); // in px per ms
|
466
|
+
touch.lastScrollOffset.x = horizontalOffset;
|
467
|
+
touch.lastScrollOffset.y = verticalOffset;
|
468
|
+
touch.lastEventTime = timeStamp;
|
469
|
+
}
|
470
|
+
},
|
471
|
+
|
472
|
+
/** @private */
|
473
|
+
touchEnd: function (touch) {
|
474
|
+
var touchStatus = this.touch,
|
475
|
+
avg = touch.averagedTouchesForView(this);
|
476
|
+
|
477
|
+
touch.scrollHasEnded = YES;
|
478
|
+
if (avg.touchCount > 0) {
|
479
|
+
this.beginTouchTracking(touch, NO);
|
480
|
+
} else {
|
481
|
+
if (this.dragging) {
|
482
|
+
touchStatus.dragging = NO;
|
483
|
+
|
484
|
+
// reset last event time
|
485
|
+
touchStatus.lastEventTime = touch.timeStamp;
|
486
|
+
|
487
|
+
this.startDecelerationAnimation();
|
488
|
+
} else {
|
489
|
+
// well. The scrolling stopped. Let us tell everyone if there was a pending one that this non-drag op interrupted.
|
490
|
+
if (touchStatus.needsScrollEnd) this._touchScrollDidEnd();
|
491
|
+
|
492
|
+
// this part looks weird, but it is actually quite simple.
|
493
|
+
// First, we send the touch off for capture+starting again, but telling it to return to us
|
494
|
+
// if nothing is found or if it is released.
|
495
|
+
touch.captureTouch(this, YES);
|
496
|
+
|
497
|
+
// if we went anywhere, did anything, etc., call end()
|
498
|
+
if (touch.touchResponder && touch.touchResponder !== this) {
|
499
|
+
touch.end();
|
500
|
+
} else if (!touch.touchResponder || touch.touchResponder === this) {
|
501
|
+
// if it was released to us or stayed with us the whole time, or is for some
|
502
|
+
// wacky reason empty (in which case it is ours still). If so, and there is a next responder,
|
503
|
+
// relay to that.
|
504
|
+
|
505
|
+
if (touch.nextTouchResponder) touch.makeTouchResponder(touch.nextTouchResponder);
|
506
|
+
} else {
|
507
|
+
// in this case, the view that captured it and changed responder should have handled
|
508
|
+
// everything for us.
|
509
|
+
}
|
510
|
+
|
511
|
+
this.touch = null;
|
512
|
+
}
|
513
|
+
|
514
|
+
this.tracking = NO;
|
515
|
+
this.dragging = NO;
|
516
|
+
}
|
517
|
+
},
|
518
|
+
|
519
|
+
/** @private */
|
520
|
+
touchCancelled: function (touch) {
|
521
|
+
var touchStatus = this.touch,
|
522
|
+
avg = touch.averagedTouchesForView(this);
|
523
|
+
|
524
|
+
// if we are decelerating, we don't want to stop that. That would be bad. Because there's no point.
|
525
|
+
if (!this.touch || !this.touch.timeout) {
|
526
|
+
this.beginPropertyChanges();
|
527
|
+
this.set("scale", this._scale);
|
528
|
+
this.set("verticalScrollOffset", this._scroll_verticalScrollOffset);
|
529
|
+
this.set("horizontalScrollOffset", this._scroll_horizontalScrollOffset);
|
530
|
+
this.endPropertyChanges();
|
531
|
+
this.didScroll(this);
|
532
|
+
this.tracking = NO;
|
533
|
+
|
534
|
+
if (this.dragging) {
|
535
|
+
this._touchScrollDidEnd();
|
536
|
+
}
|
537
|
+
|
538
|
+
this.dragging = NO;
|
539
|
+
this.touch = null;
|
540
|
+
}
|
541
|
+
},
|
542
|
+
|
543
|
+
/** @private */
|
544
|
+
startDecelerationAnimation: function (evt) {
|
545
|
+
var touch = this.touch;
|
546
|
+
touch.decelerationVelocity = {
|
547
|
+
x: touch.scrollVelocity.x * 10,
|
548
|
+
y: touch.scrollVelocity.y * 10
|
549
|
+
};
|
550
|
+
|
551
|
+
this.decelerateAnimation();
|
552
|
+
},
|
553
|
+
|
554
|
+
/** @private
|
555
|
+
Does bounce calculations, adjusting velocity.
|
556
|
+
|
557
|
+
Bouncing is fun. Functions that handle it should have fun names,
|
558
|
+
don'tcha think?
|
559
|
+
|
560
|
+
P.S.: should this be named "bouncityBounce" instead?
|
561
|
+
*/
|
562
|
+
bouncyBounce: function (velocity, value, minValue, maxValue, de, ac, additionalAcceleration) {
|
563
|
+
// we have 4 possible paths. On a higher level, we have two leaf paths that can be applied
|
564
|
+
// for either of two super-paths.
|
565
|
+
//
|
566
|
+
// The first path is if we are decelerating past an edge: in this case, this function must
|
567
|
+
// must enhance that deceleration. In this case, our math boils down to taking the amount
|
568
|
+
// by which we are past the edge, multiplying it by our deceleration factor, and reducing
|
569
|
+
// velocity by that amount.
|
570
|
+
//
|
571
|
+
// The second path is if we are not decelerating, but are still past the edge. In this case,
|
572
|
+
// we must start acceleration back _to_ the edge. The math here takes the distance we are from
|
573
|
+
// the edge, multiplies by the acceleration factor, and then performs two additional things:
|
574
|
+
// First, it speeds up the acceleration artificially with additionalAcceleration; this will
|
575
|
+
// make the stop feel more sudden, as it will still have this additional acceleration when it reaches
|
576
|
+
// the edge. Second, it ensures the result does not go past the final value, so we don't end up
|
577
|
+
// bouncing back and forth all crazy-like.
|
578
|
+
if (value < minValue) {
|
579
|
+
if (velocity < 0) velocity = velocity + ((minValue - value) * de);
|
580
|
+
else {
|
581
|
+
velocity = Math.min((minValue-value) * ac + additionalAcceleration, minValue - value - 0.01);
|
582
|
+
}
|
583
|
+
} else if (value > maxValue) {
|
584
|
+
if (velocity > 0) velocity = velocity - ((value - maxValue) * de);
|
585
|
+
else {
|
586
|
+
velocity = -Math.min((value - maxValue) * ac + additionalAcceleration, value - maxValue - 0.01);
|
587
|
+
}
|
588
|
+
}
|
589
|
+
return velocity;
|
590
|
+
},
|
591
|
+
|
592
|
+
/** @private */
|
593
|
+
decelerateAnimation: function () {
|
594
|
+
// get a bunch of properties. They are named well, so not much explanation of what they are...
|
595
|
+
// However, note maxOffsetX/Y takes into account the scale;
|
596
|
+
// also, newX/Y adds in the current deceleration velocity (the deceleration velocity will
|
597
|
+
// be changed later in this function).
|
598
|
+
var touch = this.touch,
|
599
|
+
scale = this._scale,
|
600
|
+
minOffsetX = this.minimumScrollOffset(touch.contentSize.width * this._scale,
|
601
|
+
touch.containerSize.width, this.get("horizontalAlign")),
|
602
|
+
minOffsetY = this.minimumScrollOffset(touch.contentSize.height * this._scale,
|
603
|
+
touch.containerSize.height, this.get("verticalAlign")),
|
604
|
+
maxOffsetX = this.maximumScrollOffset(touch.contentSize.width * this._scale,
|
605
|
+
touch.containerSize.width, this.get("horizontalAlign")),
|
606
|
+
maxOffsetY = this.maximumScrollOffset(touch.contentSize.height * this._scale,
|
607
|
+
touch.containerSize.height, this.get("verticalAlign")),
|
608
|
+
|
609
|
+
now = Date.now(),
|
610
|
+
t = Math.max(now - touch.lastEventTime, 1),
|
611
|
+
|
612
|
+
newX = this._scroll_horizontalScrollOffset + touch.decelerationVelocity.x * (t / 10),
|
613
|
+
newY = this._scroll_verticalScrollOffset + touch.decelerationVelocity.y * (t / 10);
|
614
|
+
|
615
|
+
var de = touch.decelerationFromEdge, ac = touch.accelerationToEdge;
|
616
|
+
|
617
|
+
// under a few circumstances, we may want to force a valid X/Y position.
|
618
|
+
// For instance, if bouncing is disabled, or if position was okay before
|
619
|
+
// adjusting scale.
|
620
|
+
var forceValidXPosition = !touch.enableBouncing, forceValidYPosition = !touch.enableBouncing;
|
621
|
+
|
622
|
+
// determine if position was okay before adjusting scale (which we do, in
|
623
|
+
// a lovely, animated way, for the scaled out/in too far bounce-back).
|
624
|
+
// if the position was okay, then we are going to make sure that we keep the
|
625
|
+
// position okay when adjusting the scale.
|
626
|
+
//
|
627
|
+
// Position OKness, here, referring to if the position is valid (within
|
628
|
+
// minimum and maximum scroll offsets)
|
629
|
+
if (newX >= minOffsetX && newX <= maxOffsetX) forceValidXPosition = YES;
|
630
|
+
if (newY >= minOffsetY && newY <= maxOffsetY) forceValidYPosition = YES;
|
631
|
+
|
632
|
+
// We are going to change scale in a moment, but the position should stay the
|
633
|
+
// same, if possible (unless it would be more jarring, as described above, in
|
634
|
+
// the case of starting with a valid position and ending with an invalid one).
|
635
|
+
//
|
636
|
+
// Because we are changing the scale, we need to make the position scale-neutral.
|
637
|
+
// we'll make it non-scale-neutral after applying scale.
|
638
|
+
//
|
639
|
+
// Question: might it be better to save the center position instead, so scaling
|
640
|
+
// bounces back around the center of the screen?
|
641
|
+
newX /= this._scale;
|
642
|
+
newY /= this._scale;
|
643
|
+
|
644
|
+
// scale velocity (amount to change) starts out at 0 each time, because
|
645
|
+
// it is calculated by how far out of bounds it is, rather than by the
|
646
|
+
// previous such velocity.
|
647
|
+
var sv = 0;
|
648
|
+
|
649
|
+
// do said calculation; we'll use the same bouncyBounce method used for everything
|
650
|
+
// else, but our adjustor that gives a minimum amount to change by and (which, as we'll
|
651
|
+
// discuss, is to make the stop feel slightly more like a stop), we'll leave at 0
|
652
|
+
// (scale doesn't really need it as much; if you disagree, at least come up with
|
653
|
+
// numbers more appropriate for scale than the ones for X/Y)
|
654
|
+
sv = this.bouncyBounce(sv, scale, touch.minimumScale, touch.maximumScale, de, ac, 0);
|
655
|
+
|
656
|
+
// add the amount to scale. This is linear, rather than multiplicative. If you think
|
657
|
+
// it should be multiplicative (or however you say that), come up with a new formula.
|
658
|
+
this._scale = scale = scale + sv;
|
659
|
+
|
660
|
+
// now we can convert newX/Y back to scale-specific coordinates...
|
661
|
+
newX *= this._scale;
|
662
|
+
newY *= this._scale;
|
663
|
+
|
664
|
+
// It looks very weird if the content started in-bounds, but the scale animation
|
665
|
+
// made it not be in bounds; it causes the position to animate snapping back, and,
|
666
|
+
// well, it looks very weird. It is more proper to just make sure it stays in a valid
|
667
|
+
// position. So, we'll determine the new maximum/minimum offsets, and then, if it was
|
668
|
+
// originally a valid position, we'll adjust the new position to a valid position as well.
|
669
|
+
|
670
|
+
|
671
|
+
// determine new max offset
|
672
|
+
minOffsetX = this.minimumScrollOffset(touch.contentSize.width * this._scale,
|
673
|
+
touch.containerSize.width, this.get("horizontalAlign"));
|
674
|
+
minOffsetY = this.minimumScrollOffset(touch.contentSize.height * this._scale,
|
675
|
+
touch.containerSize.height, this.get("verticalAlign"));
|
676
|
+
maxOffsetX = this.maximumScrollOffset(touch.contentSize.width * this._scale,
|
677
|
+
touch.containerSize.width, this.get("horizontalAlign"));
|
678
|
+
maxOffsetY = this.maximumScrollOffset(touch.contentSize.height * this._scale,
|
679
|
+
touch.containerSize.height, this.get("verticalAlign"));
|
680
|
+
|
681
|
+
// see if scaling messed up the X position (but ignore if 'tweren't right to begin with).
|
682
|
+
if (forceValidXPosition && (newX < minOffsetX || newX > maxOffsetX)) {
|
683
|
+
// Correct the position
|
684
|
+
newX = Math.max(minOffsetX, Math.min(newX, maxOffsetX));
|
685
|
+
|
686
|
+
// also, make the velocity be ZERO; it is obviously not needed...
|
687
|
+
touch.decelerationVelocity.x = 0;
|
688
|
+
}
|
689
|
+
|
690
|
+
// now the y
|
691
|
+
if (forceValidYPosition && (newY < minOffsetY || newY > maxOffsetY)) {
|
692
|
+
// again, correct it...
|
693
|
+
newY = Math.max(minOffsetY, Math.min(newY, maxOffsetY));
|
694
|
+
|
695
|
+
// also, make the velocity be ZERO; it is obviously not needed...
|
696
|
+
touch.decelerationVelocity.y = 0;
|
697
|
+
}
|
698
|
+
|
699
|
+
|
700
|
+
// now that we are done modifying the position, we may update the actual scroll
|
701
|
+
this._sctsv_setOffset(newX, newY);
|
702
|
+
|
703
|
+
this._applyCSSTransforms(touch.layer); // <- Does what it sounds like.
|
704
|
+
|
705
|
+
this._touchScrollDidChange();
|
706
|
+
|
707
|
+
// Now we have to adjust the velocities. The velocities are simple x and y numbers that
|
708
|
+
// get added to the scroll X/Y positions each frame.
|
709
|
+
// The default decay rate is .950 per frame. To achieve some semblance of accuracy, we
|
710
|
+
// make it to the power of the elapsed number of frames. This is not fully accurate,
|
711
|
+
// as this is applying the elapsed time between this frame and the previous time to
|
712
|
+
// modify the velocity for the next frame. My mind goes blank when I try to figure out
|
713
|
+
// a way to fix this (given that we don't want to change the velocity on the first frame),
|
714
|
+
// and as it seems to work great as-is, I'm just leaving it.
|
715
|
+
var decay = touch.decelerationRate;
|
716
|
+
touch.decelerationVelocity.y *= Math.pow(decay, (t / 10));
|
717
|
+
touch.decelerationVelocity.x *= Math.pow(decay, (t / 10));
|
718
|
+
|
719
|
+
// We have a bouncyBounce method that adjusts the velocity for bounce. That is, if it is
|
720
|
+
// out of range and still going, it will slow it down. This step is decelerationFromEdge.
|
721
|
+
// If it is not moving (or has come to a stop from decelerating), but is still out of range,
|
722
|
+
// it will start it moving back into range (accelerationToEdge)
|
723
|
+
// we supply de and ac as these properties.
|
724
|
+
// The .3 artificially increases the acceleration by .3; this is actually to make the final
|
725
|
+
// stop a bit more abrupt.
|
726
|
+
touch.decelerationVelocity.x = this.bouncyBounce(touch.decelerationVelocity.x, newX, minOffsetX, maxOffsetX, de, ac, 0.3);
|
727
|
+
touch.decelerationVelocity.y = this.bouncyBounce(touch.decelerationVelocity.y, newY, minOffsetY, maxOffsetY, de, ac, 0.3);
|
728
|
+
|
729
|
+
// if we ain't got no velocity... then we must be finished, as there is no where else to go.
|
730
|
+
// to determine our velocity, we take the absolue value, and use that; if it is less than .01, we
|
731
|
+
// must be done. Note that we check scale's most recent velocity, calculated above using bouncyBounce,
|
732
|
+
// as well.
|
733
|
+
var absXVelocity = Math.abs(touch.decelerationVelocity.x);
|
734
|
+
var absYVelocity = Math.abs(touch.decelerationVelocity.y);
|
735
|
+
if (absYVelocity < 0.05 && absXVelocity < 0.05 && Math.abs(sv) < 0.05) {
|
736
|
+
// we can reset the timeout, as it will no longer be required, and we don't want to re-cancel it later.
|
737
|
+
touch.timeout = null;
|
738
|
+
this.touch = null;
|
739
|
+
|
740
|
+
// trigger scroll end
|
741
|
+
this._touchScrollDidEnd();
|
742
|
+
|
743
|
+
// set the scale, vertical, and horizontal offsets to what they technically already are,
|
744
|
+
// but don't know they are yet. This will finally update things like, say, the clipping frame.
|
745
|
+
this.beginPropertyChanges();
|
746
|
+
this.set("scale", this._scale);
|
747
|
+
this.set("verticalScrollOffset", this._scroll_verticalScrollOffset);
|
748
|
+
this.set("horizontalScrollOffset", this._scroll_horizontalScrollOffset);
|
749
|
+
this.endPropertyChanges();
|
750
|
+
this.didScroll(this);
|
751
|
+
|
752
|
+
return;
|
753
|
+
}
|
754
|
+
|
755
|
+
// We now set up the next round. We are doing this as raw as we possibly can, not touching the
|
756
|
+
// run loop at all. This speeds up performance drastically--keep in mind, we're on comparatively
|
757
|
+
// slow devices, here. So, we'll just make a closure, saving "this" into "self" and calling
|
758
|
+
// 10ms later (or however long it takes). Note also that we save both the last event time
|
759
|
+
// (so we may calculate elapsed time) and the timeout we are creating, so we may cancel it in future.
|
760
|
+
var self = this;
|
761
|
+
touch.lastEventTime = Date.now();
|
762
|
+
this.touch.timeout = setTimeout(function () {
|
763
|
+
SC.run(self.decelerateAnimation(), self);
|
764
|
+
}, 10);
|
765
|
+
},
|
766
|
+
|
767
|
+
adjustElementScroll: function () {
|
768
|
+
var content = this.get('contentView');
|
769
|
+
|
770
|
+
if (content) {
|
771
|
+
this._applyCSSTransforms(content.get('layer'));
|
772
|
+
}
|
773
|
+
return sc_super();
|
774
|
+
},
|
775
|
+
|
776
|
+
/** @private */
|
777
|
+
_touchScrollDidChange: function () {
|
778
|
+
var contentView = this.get('contentView'),
|
779
|
+
horizontalScrollOffset = this._scroll_horizontalScrollOffset,
|
780
|
+
verticalScrollOffset = this._scroll_verticalScrollOffset;
|
781
|
+
if (contentView.touchScrollDidChange) {
|
782
|
+
contentView.touchScrollDidChange(horizontalScrollOffset, verticalScrollOffset);
|
783
|
+
}
|
784
|
+
|
785
|
+
// tell scrollers
|
786
|
+
if (this.verticalScrollerView && this.verticalScrollerView.touchScrollDidChange) {
|
787
|
+
this.verticalScrollerView.touchScrollDidChange(verticalScrollOffset);
|
788
|
+
}
|
789
|
+
|
790
|
+
if (this.horizontalScrollerView && this.horizontalScrollerView.touchScrollDidChange) {
|
791
|
+
this.horizontalScrollerView.touchScrollDidChange(horizontalScrollOffset);
|
792
|
+
}
|
793
|
+
}
|
794
|
+
});
|
795
|
+
|
796
|
+
SC.TouchScrollView.prototype.mixin({
|
797
|
+
|
798
|
+
/** @private */
|
799
|
+
_touchScrollDidStart: SC.TouchScrollView.prototype._touchScrollDidChange,
|
800
|
+
|
801
|
+
/** @private */
|
802
|
+
_touchScrollDidEnd: SC.TouchScrollView.prototype._touchScrollDidChange
|
803
|
+
|
804
|
+
});
|