scrollview-base-debug.js revision 6448ea60e198da82d2ea7fc33d1f1ecf3c3c8b74
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * The scrollview-base module provides a basic ScrollView Widget, without scrollbar indicators
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @module scrollview-base
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * ScrollView provides a scrollable widget, supporting flick gestures, across both touch and mouse based devices.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @class ScrollView
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @namespace
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param config {Object} Object literal with initial attribute values
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @extends Widget
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @constructor
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync ScrollView.superclass.constructor.apply(this, arguments);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // Y.ScrollView prototype
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Designated initializer
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method initializer
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync initializer: function() {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Notification event fired at the end of a scroll transition
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @event scrollEnd
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param e {EventFacade} The default event facade.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Notification event fired at the end of a flick gesture (the flick animation may still be in progress)
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @event flick
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param e {EventFacade} The default event facade.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // Cache - they're write once, and not going to change
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Override the contentBox sizing method, since the contentBox height
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * should not be that of the boundingBox.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _uiSizeCB
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @protected
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync _uiSizeCB: function() {},
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Content box transition callback
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _transitionEnded
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param {Event.Facade} e The event facade
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync _transitionEnded: function(e) {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * bindUI implementation
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Hooks up events for the widget
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method bindUI
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync bindUI: function() {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync bb.on('gesturemovestart', Y.bind(this._onGestureMoveStart, this));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // IE SELECT HACK. See if we can do this non-natively and in the gesture for a future release.
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._nativeBody = Y.Node.getDOMNode(Y.one("body", cb.get("ownerDocument")));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._selectstart = this._nativeBody.onselectstart;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._nativeBody.onselectstart = this._iePreventSelect;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._cbDoc.once(MOUSE_UP, this._ieRestoreSelect, this);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // TODO: Fires way to often when using non-native transitions, due to property change
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync cb.on('DOMSubtreeModified', Y.bind(this._uiDimensionsChange, this));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * syncUI implementation
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Update the scroll position, based on the current value of scrollY
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method bindUI
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync syncUI: function() {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this.scrollTo(this.get(SCROLL_X), this.get(SCROLL_Y));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Scroll the element to a given y coordinate
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method scrollTo
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param x {Number} The x-position to scroll to
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param y {Number} The y-position to scroll to
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param duration {Number} Duration, in ms, of the scroll animation (default is 0)
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param easing {String} An easing equation if duration is set
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync xSet = (x !== null),
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync ySet = (y !== null),
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // ANDROID WORKAROUND - try and stop existing transition, before kicking off new one.
f65e6cba3e74ffd3dc9e6053828dcc82b367e8devboxsync cb.setStyle(ScrollView._TRANSITION_DURATION, ZERO);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync cb.setStyle(ScrollView._TRANSITION_PROPERTY, EMPTY);
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // Causes bounce back from 0,0 instead of current translation for bottom/right edge animation
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync // cb.setStyle("WebkitTransform", cb.getComputedStyle("WebkitTransform"));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync transition.transform = 'translate3D('+ xMove +'px,'+ yMove +'px, 0px)';
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync Y.log("Transition: duration, easing:" + [transition.duration, transition.easing], "scrollview");
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync callback = this._transEndCallback = Y.bind(this._transitionEnded, this);
35396ee506ef68dd1c161f1ef2c3c0b68a146ff2vboxsync cb.setStyle('transform', 'translate3D('+ xMove +'px,'+ yMove +'px, 0px)');
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Native onselectstart handle to prevent selection in IE
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _iePreventSelect
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync _iePreventSelect : function() {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync return false;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Restores native onselectstart handle, backed up to prevent selection in IE
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _ieRestoreSelect
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync _ieRestoreSelect : function() {
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._nativeBody.onselectstart = this._selectstart;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * gesturemovestart event handler
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _onGestureMoveStart
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync * @param e {Event.Facade} The gesturemovestart event facade
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync this._moveEvt = bb.on('gesturemove', Y.bind(this._onGestureMove, this));
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync this._moveEndEvt = bb.on('gesturemoveend', Y.bind(this._onGestureMoveEnd, this));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._moveStartClientY = this._moveEndClientY = e.clientY;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._moveStartClientX = this._moveEndClientX = e.clientX;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Internal state, defines whether or not the scrollview is currently being dragged
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @property _isDragging
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @type boolean
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @protected
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._isDragging = false;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Internal state, defines whether or not the scrollview is currently animating a flick
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @property _flicking
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync * @type boolean
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @protected
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._flicking = false;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * Internal state, defines whether or not the scrollview needs to snap to a boundary edge
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @property _snapToEdge
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @type boolean
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @protected
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this._snapToEdge = false;
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * gesturemove event handler
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _onGestureMove
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param e {Event.Facade} The gesturemove event facade
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync _onGestureMove: function(e) {
1222ff94540f6426532c1f1714f0717fdcf92e46vboxsync this.set(SCROLL_Y, -(e.clientY - this._moveStartY));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync this.set(SCROLL_X, -(e.clientX - this._moveStartX));
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * gestureend event handler
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @method _onGestureMoveEnd
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync * @param e {Event.Facade} The gesturemoveend event facade
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync startPoint = this._scrollsVertical ? this._moveStartClientY : this._moveStartClientX,
7a61a5714b9a39ac3bd59e52b0843ef498350a35vboxsync endPoint = this._scrollsVertical ? this._moveEndClientY : this._moveEndClientX,
this._scrolledHalfway = false;
this._snapToEdge = false;
this._isDragging = false;
* Contains the distance (postive or negative) in pixels by which the scrollview was last scrolled. This is useful when
* setting up click listeners on the scrollview content, which on mouse based devices are always fired, even after a
* <p>Touch based devices don't currently fire a click event, if the finger has been moved (beyond a threshold) so this check isn't required,
this._scrolledHalfway = true;
* Internal state, defines whether or not the scrollview has been scrolled in the forward (distance > 0), or backward (distance < 0) direction
this._scrolledHalfway = true;
this._snapToEdge = true;
this._snapToEdge = true;
this._snapToEdge = true;
this._snapToEdge = true;
if(this._snapToEdge) {
onGestureMoveEnd: true
_afterScrollYChange : function(e) {
_afterScrollXChange : function(e) {
_afterHeightChange: function() {
this._uiDimensionsChange();
_afterWidthChange: function() {
this._uiDimensionsChange();
_uiDimensionsChange: function() {
this._scrollsVertical = true;
this._scrollsHorizontal = true;
_flick: function(e) {
this._flicking = true;
this._pastYEdge = false;
this._pastXEdge = false;
this._flickFrame();
_flickFrame: function() {
var newY,
maxY,
minY,
newX,
maxX,
minX,
if(scrollsVertical) {
if(scrollsHorizontal) {
this._flicking = false;
if(scrollsVertical) {
this._snapToEdge = true;
this._snapToEdge = true;
if(scrollsHorizontal) {
this._snapToEdge = true;
this._snapToEdge = true;
if (scrollsVertical) {
this._pastYEdge = true;
if (scrollsHorizontal) {
this._pastXEdge = true;
if (!this._flickTimer) {
if(this._flickTimer) {
this._flickTimer = null;
if(fireEvent) {
return val;
ATTRS: {
scrollY: {
scrollX: {
deceleration: {
bounce: {
flick: {
value: {
* Style property name to use to set transition duration. Currently Webkit specific (WebkitTransitionDuration)