OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * Implementation of a custom scrolling behavior. | 6 * Implementation of a custom scrolling behavior. |
7 * This behavior overrides native scrolling for an area. This area can be a | 7 * This behavior overrides native scrolling for an area. This area can be a |
8 * single defined part of a page, the entire page, or several different parts | 8 * single defined part of a page, the entire page, or several different parts |
9 * of a page. | 9 * of a page. |
10 * | 10 * |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 Scroller(Element scrollableElem, [this.verticalEnabled = false, | 137 Scroller(Element scrollableElem, [this.verticalEnabled = false, |
138 this.horizontalEnabled = false, | 138 this.horizontalEnabled = false, |
139 momentumEnabled = true, | 139 momentumEnabled = true, |
140 lookupContentSizeDelegate = null, | 140 lookupContentSizeDelegate = null, |
141 num defaultDecelerationFactor = 1, | 141 num defaultDecelerationFactor = 1, |
142 int scrollTechnique = null, bool capture = false]) | 142 int scrollTechnique = null, bool capture = false]) |
143 : _momentumEnabled = momentumEnabled, | 143 : _momentumEnabled = momentumEnabled, |
144 _lookupContentSizeDelegate = lookupContentSizeDelegate, | 144 _lookupContentSizeDelegate = lookupContentSizeDelegate, |
145 _element = scrollableElem, | 145 _element = scrollableElem, |
146 _frame = scrollableElem.parent, | 146 _frame = scrollableElem.parent, |
147 _scrollTechnique = scrollTechnique !== null | 147 _scrollTechnique = scrollTechnique != null |
148 ? scrollTechnique : ScrollerScrollTechnique.TRANSFORM_3D, | 148 ? scrollTechnique : ScrollerScrollTechnique.TRANSFORM_3D, |
149 _minPoint = new Coordinate(0, 0), | 149 _minPoint = new Coordinate(0, 0), |
150 _maxPoint = new Coordinate(0, 0), | 150 _maxPoint = new Coordinate(0, 0), |
151 _maxOffset = new Coordinate(0, 0), | 151 _maxOffset = new Coordinate(0, 0), |
152 _minOffset = new Coordinate(0, 0), | 152 _minOffset = new Coordinate(0, 0), |
153 _contentOffset = new Coordinate(0, 0) { | 153 _contentOffset = new Coordinate(0, 0) { |
154 _touchHandler = new TouchHandler(this, scrollableElem.parent); | 154 _touchHandler = new TouchHandler(this, scrollableElem.parent); |
155 _momentum = new Momentum(this, defaultDecelerationFactor); | 155 _momentum = new Momentum(this, defaultDecelerationFactor); |
156 | 156 |
157 Element parentElem = scrollableElem.parent; | 157 Element parentElem = scrollableElem.parent; |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 if (_scrollTechnique == ScrollerScrollTechnique.RELATIVE_POSITIONING) { | 233 if (_scrollTechnique == ScrollerScrollTechnique.RELATIVE_POSITIONING) { |
234 _element.computedStyle.then((CSSStyleDeclaration style) { | 234 _element.computedStyle.then((CSSStyleDeclaration style) { |
235 assert(style.position != "static"); | 235 assert(style.position != "static"); |
236 }); | 236 }); |
237 } | 237 } |
238 | 238 |
239 _initLayer(); | 239 _initLayer(); |
240 } | 240 } |
241 | 241 |
242 EventListenerList get onScrollerStart { | 242 EventListenerList get onScrollerStart { |
243 if (_onScrollerStart === null) { | 243 if (_onScrollerStart == null) { |
244 _onScrollerStart = new SimpleEventListenerList(); | 244 _onScrollerStart = new SimpleEventListenerList(); |
245 } | 245 } |
246 return _onScrollerStart; | 246 return _onScrollerStart; |
247 } | 247 } |
248 | 248 |
249 EventListenerList get onScrollerEnd { | 249 EventListenerList get onScrollerEnd { |
250 if (_onScrollerEnd === null) { | 250 if (_onScrollerEnd == null) { |
251 _onScrollerEnd = new SimpleEventListenerList(); | 251 _onScrollerEnd = new SimpleEventListenerList(); |
252 } | 252 } |
253 return _onScrollerEnd; | 253 return _onScrollerEnd; |
254 } | 254 } |
255 | 255 |
256 EventListenerList get onScrollerDragEnd { | 256 EventListenerList get onScrollerDragEnd { |
257 if (_onScrollerDragEnd === null) { | 257 if (_onScrollerDragEnd == null) { |
258 _onScrollerDragEnd = new SimpleEventListenerList(); | 258 _onScrollerDragEnd = new SimpleEventListenerList(); |
259 } | 259 } |
260 return _onScrollerDragEnd; | 260 return _onScrollerDragEnd; |
261 } | 261 } |
262 | 262 |
263 EventListenerList get onContentMoved { | 263 EventListenerList get onContentMoved { |
264 if (_onContentMoved === null) { | 264 if (_onContentMoved == null) { |
265 _onContentMoved = new SimpleEventListenerList(); | 265 _onContentMoved = new SimpleEventListenerList(); |
266 } | 266 } |
267 return _onContentMoved; | 267 return _onContentMoved; |
268 } | 268 } |
269 | 269 |
270 EventListenerList get onDecelStart { | 270 EventListenerList get onDecelStart { |
271 if (_onDecelStart === null) { | 271 if (_onDecelStart == null) { |
272 _onDecelStart = new SimpleEventListenerList(); | 272 _onDecelStart = new SimpleEventListenerList(); |
273 } | 273 } |
274 return _onDecelStart; | 274 return _onDecelStart; |
275 } | 275 } |
276 | 276 |
277 | 277 |
278 /** | 278 /** |
279 * Add a scroll listener. This allows other classes to subscribe to scroll | 279 * Add a scroll listener. This allows other classes to subscribe to scroll |
280 * notifications from this scroller. | 280 * notifications from this scroller. |
281 */ | 281 */ |
282 void addScrollListener(ScrollListener listener) { | 282 void addScrollListener(ScrollListener listener) { |
283 if (_scrollWatcher === null) { | 283 if (_scrollWatcher == null) { |
284 _scrollWatcher = new ScrollWatcher(this); | 284 _scrollWatcher = new ScrollWatcher(this); |
285 _scrollWatcher.initialize(); | 285 _scrollWatcher.initialize(); |
286 } | 286 } |
287 _scrollWatcher.addListener(listener); | 287 _scrollWatcher.addListener(listener); |
288 } | 288 } |
289 | 289 |
290 /** | 290 /** |
291 * Adjust the new calculated scroll position based on the minimum allowed | 291 * Adjust the new calculated scroll position based on the minimum allowed |
292 * position and returns the adjusted scroll value. | 292 * position and returns the adjusted scroll value. |
293 */ | 293 */ |
294 num _adjustValue(num newPosition, num minPosition, | 294 num _adjustValue(num newPosition, num minPosition, |
295 num maxPosition) { | 295 num maxPosition) { |
296 assert(minPosition <= maxPosition); | 296 assert(minPosition <= maxPosition); |
297 | 297 |
298 if (newPosition < minPosition) { | 298 if (newPosition < minPosition) { |
299 newPosition -= (newPosition - minPosition) / 2; | 299 newPosition -= (newPosition - minPosition) / 2; |
300 } else { | 300 } else { |
301 if (newPosition > maxPosition) { | 301 if (newPosition > maxPosition) { |
302 newPosition -= (newPosition - maxPosition) / 2; | 302 newPosition -= (newPosition - maxPosition) / 2; |
303 } | 303 } |
304 } | 304 } |
305 return newPosition; | 305 return newPosition; |
306 } | 306 } |
307 | 307 |
308 /** | 308 /** |
309 * Coordinate we would end up at if we did nothing. | 309 * Coordinate we would end up at if we did nothing. |
310 */ | 310 */ |
311 Coordinate get currentTarget { | 311 Coordinate get currentTarget { |
312 Coordinate end = _momentum.destination; | 312 Coordinate end = _momentum.destination; |
313 if (end === null) { | 313 if (end == null) { |
314 end = _contentOffset; | 314 end = _contentOffset; |
315 } | 315 } |
316 return end; | 316 return end; |
317 } | 317 } |
318 | 318 |
319 Coordinate get contentOffset => _contentOffset; | 319 Coordinate get contentOffset => _contentOffset; |
320 | 320 |
321 /** | 321 /** |
322 * Animate the position of the scroller to the specified [x], [y] coordinates | 322 * Animate the position of the scroller to the specified [x], [y] coordinates |
323 * by applying the throw gesture with the correct velocity to end at that | 323 * by applying the throw gesture with the correct velocity to end at that |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 Element getElement() => _element; | 385 Element getElement() => _element; |
386 Element getFrame() => _frame; | 386 Element getFrame() => _frame; |
387 num getHorizontalOffset() => _contentOffset.x; | 387 num getHorizontalOffset() => _contentOffset.x; |
388 | 388 |
389 /** | 389 /** |
390 * [x] Value to use as reference for percent measurement. If | 390 * [x] Value to use as reference for percent measurement. If |
391 * none is provided then the content's current x offset will be used. | 391 * none is provided then the content's current x offset will be used. |
392 * Returns the percent of the page scrolled horizontally. | 392 * Returns the percent of the page scrolled horizontally. |
393 */ | 393 */ |
394 num getHorizontalScrollPercent([num x = null]) { | 394 num getHorizontalScrollPercent([num x = null]) { |
395 x = x !== null ? x : _contentOffset.x; | 395 x = x != null ? x : _contentOffset.x; |
396 return (x - _minPoint.x) / (_maxPoint.x - _minPoint.x); | 396 return (x - _minPoint.x) / (_maxPoint.x - _minPoint.x); |
397 } | 397 } |
398 | 398 |
399 num getMaxPointY()=> _maxPoint.y; | 399 num getMaxPointY()=> _maxPoint.y; |
400 num getMinPointY() => _minPoint.y; | 400 num getMinPointY() => _minPoint.y; |
401 Momentum get momentum => _momentum; | 401 Momentum get momentum => _momentum; |
402 | 402 |
403 /** | 403 /** |
404 * Provide access to the touch handler that the scroller created to manage | 404 * Provide access to the touch handler that the scroller created to manage |
405 * touch events. | 405 * touch events. |
406 */ | 406 */ |
407 TouchHandler getTouchHandler() => _touchHandler; | 407 TouchHandler getTouchHandler() => _touchHandler; |
408 num getVerticalOffset() => _contentOffset.y; | 408 num getVerticalOffset() => _contentOffset.y; |
409 | 409 |
410 /** | 410 /** |
411 * [y] value is used as reference for percent measurement. If | 411 * [y] value is used as reference for percent measurement. If |
412 * none is provided then the content's current y offset will be used. | 412 * none is provided then the content's current y offset will be used. |
413 */ | 413 */ |
414 num getVerticalScrollPercent([num y = null]) { | 414 num getVerticalScrollPercent([num y = null]) { |
415 y = y !== null ? y : _contentOffset.y; | 415 y = y != null ? y : _contentOffset.y; |
416 return (y - _minPoint.y) / Math.max(1, _maxPoint.y - _minPoint.y); | 416 return (y - _minPoint.y) / Math.max(1, _maxPoint.y - _minPoint.y); |
417 } | 417 } |
418 | 418 |
419 /** | 419 /** |
420 * Initialize the dom elements necessary for the scrolling to work. | 420 * Initialize the dom elements necessary for the scrolling to work. |
421 */ | 421 */ |
422 void _initLayer() { | 422 void _initLayer() { |
423 // The scrollable node provided to Scroller must be a direct child | 423 // The scrollable node provided to Scroller must be a direct child |
424 // of the scrollable frame. | 424 // of the scrollable frame. |
425 // TODO(jacobr): Figure out why this is failing on dartium. | 425 // TODO(jacobr): Figure out why this is failing on dartium. |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
535 _minOffset.y = 0; | 535 _minOffset.y = 0; |
536 reconfigure(() => _setContentOffset(_maxPoint.x, _maxPoint.y)); | 536 reconfigure(() => _setContentOffset(_maxPoint.x, _maxPoint.y)); |
537 } | 537 } |
538 | 538 |
539 /** | 539 /** |
540 * Recalculate dimensions of the frame and the content. Adjust the minPoint | 540 * Recalculate dimensions of the frame and the content. Adjust the minPoint |
541 * and maxPoint allowed for scrolling. | 541 * and maxPoint allowed for scrolling. |
542 */ | 542 */ |
543 void _resize(Callback callback) { | 543 void _resize(Callback callback) { |
544 window.requestLayoutFrame(() { | 544 window.requestLayoutFrame(() { |
545 if (_lookupContentSizeDelegate !== null) { | 545 if (_lookupContentSizeDelegate != null) { |
546 _contentSize = _lookupContentSizeDelegate(); | 546 _contentSize = _lookupContentSizeDelegate(); |
547 } else { | 547 } else { |
548 _contentSize = new Size(_element.scrollWidth, _element.scrollHeight); | 548 _contentSize = new Size(_element.scrollWidth, _element.scrollHeight); |
549 } | 549 } |
550 | 550 |
551 _scrollSize = new Size(_frame.offsetWidth, | 551 _scrollSize = new Size(_frame.offsetWidth, |
552 _frame.offsetHeight); | 552 _frame.offsetHeight); |
553 Size adjusted = _getAdjustedContentSize(); | 553 Size adjusted = _getAdjustedContentSize(); |
554 _maxPoint = new Coordinate(-_maxOffset.x, -_maxOffset.y); | 554 _maxPoint = new Coordinate(-_maxOffset.x, -_maxOffset.y); |
555 _minPoint = new Coordinate( | 555 _minPoint = new Coordinate( |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 for (EventListener listener in _listeners) { | 713 for (EventListener listener in _listeners) { |
714 listener(evt); | 714 listener(evt); |
715 } | 715 } |
716 } | 716 } |
717 } | 717 } |
718 | 718 |
719 class ScrollerScrollTechnique { | 719 class ScrollerScrollTechnique { |
720 static const TRANSFORM_3D = 1; | 720 static const TRANSFORM_3D = 1; |
721 static const RELATIVE_POSITIONING = 2; | 721 static const RELATIVE_POSITIONING = 2; |
722 } | 722 } |
OLD | NEW |