src/cm/media/js/lib/yui/yui_3.10.3/build/scrollview-base/scrollview-base-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 Yahoo! Inc. All rights reserved.
       
     4 Licensed under the BSD License.
       
     5 http://yuilibrary.com/license/
       
     6 */
       
     7 
       
     8 YUI.add('scrollview-base', function (Y, NAME) {
       
     9 
       
    10 /**
       
    11  * The scrollview-base module provides a basic ScrollView Widget, without scrollbar indicators
       
    12  *
       
    13  * @module scrollview
       
    14  * @submodule scrollview-base
       
    15  */
       
    16 
       
    17  // Local vars
       
    18 var getClassName = Y.ClassNameManager.getClassName,
       
    19     DOCUMENT = Y.config.doc,
       
    20     IE = Y.UA.ie,
       
    21     NATIVE_TRANSITIONS = Y.Transition.useNative,
       
    22     vendorPrefix = Y.Transition._VENDOR_PREFIX, // Todo: This is a private property, and alternative approaches should be investigated
       
    23     SCROLLVIEW = 'scrollview',
       
    24     CLASS_NAMES = {
       
    25         vertical: getClassName(SCROLLVIEW, 'vert'),
       
    26         horizontal: getClassName(SCROLLVIEW, 'horiz')
       
    27     },
       
    28     EV_SCROLL_END = 'scrollEnd',
       
    29     FLICK = 'flick',
       
    30     DRAG = 'drag',
       
    31     MOUSEWHEEL = 'mousewheel',
       
    32     UI = 'ui',
       
    33     TOP = 'top',
       
    34     LEFT = 'left',
       
    35     PX = 'px',
       
    36     AXIS = 'axis',
       
    37     SCROLL_Y = 'scrollY',
       
    38     SCROLL_X = 'scrollX',
       
    39     BOUNCE = 'bounce',
       
    40     DISABLED = 'disabled',
       
    41     DECELERATION = 'deceleration',
       
    42     DIM_X = 'x',
       
    43     DIM_Y = 'y',
       
    44     BOUNDING_BOX = 'boundingBox',
       
    45     CONTENT_BOX = 'contentBox',
       
    46     GESTURE_MOVE = 'gesturemove',
       
    47     START = 'start',
       
    48     END = 'end',
       
    49     EMPTY = '',
       
    50     ZERO = '0s',
       
    51     SNAP_DURATION = 'snapDuration',
       
    52     SNAP_EASING = 'snapEasing',
       
    53     EASING = 'easing',
       
    54     FRAME_DURATION = 'frameDuration',
       
    55     BOUNCE_RANGE = 'bounceRange',
       
    56     _constrain = function (val, min, max) {
       
    57         return Math.min(Math.max(val, min), max);
       
    58     };
       
    59 
       
    60 /**
       
    61  * ScrollView provides a scrollable widget, supporting flick gestures,
       
    62  * across both touch and mouse based devices.
       
    63  *
       
    64  * @class ScrollView
       
    65  * @param config {Object} Object literal with initial attribute values
       
    66  * @extends Widget
       
    67  * @constructor
       
    68  */
       
    69 function ScrollView() {
       
    70     ScrollView.superclass.constructor.apply(this, arguments);
       
    71 }
       
    72 
       
    73 Y.ScrollView = Y.extend(ScrollView, Y.Widget, {
       
    74 
       
    75     // *** Y.ScrollView prototype
       
    76 
       
    77     /**
       
    78      * Flag driving whether or not we should try and force H/W acceleration when transforming. Currently enabled by default for Webkit.
       
    79      * Used by the _transform method.
       
    80      *
       
    81      * @property _forceHWTransforms
       
    82      * @type boolean
       
    83      * @protected
       
    84      */
       
    85     _forceHWTransforms: Y.UA.webkit ? true : false,
       
    86 
       
    87     /**
       
    88      * <p>Used to control whether or not ScrollView's internal
       
    89      * gesturemovestart, gesturemove and gesturemoveend
       
    90      * event listeners should preventDefault. The value is an
       
    91      * object, with "start", "move" and "end" properties used to
       
    92      * specify which events should preventDefault and which shouldn't:</p>
       
    93      *
       
    94      * <pre>
       
    95      * {
       
    96      *    start: false,
       
    97      *    move: true,
       
    98      *    end: false
       
    99      * }
       
   100      * </pre>
       
   101      *
       
   102      * <p>The default values are set up in order to prevent panning,
       
   103      * on touch devices, while allowing click listeners on elements inside
       
   104      * the ScrollView to be notified as expected.</p>
       
   105      *
       
   106      * @property _prevent
       
   107      * @type Object
       
   108      * @protected
       
   109      */
       
   110     _prevent: {
       
   111         start: false,
       
   112         move: true,
       
   113         end: false
       
   114     },
       
   115 
       
   116     /**
       
   117      * Contains the distance (postive or negative) in pixels by which
       
   118      *  the scrollview was last scrolled. This is useful when setting up
       
   119      *  click listeners on the scrollview content, which on mouse based
       
   120      *  devices are always fired, even after a drag/flick.
       
   121      *
       
   122      * <p>Touch based devices don't currently fire a click event,
       
   123      *  if the finger has been moved (beyond a threshold) so this
       
   124      *  check isn't required, if working in a purely touch based environment</p>
       
   125      *
       
   126      * @property lastScrolledAmt
       
   127      * @type Number
       
   128      * @public
       
   129      * @default 0
       
   130      */
       
   131     lastScrolledAmt: 0,
       
   132 
       
   133     /**
       
   134      * Internal state, defines the minimum amount that the scrollview can be scrolled along the X axis
       
   135      *
       
   136      * @property _minScrollX
       
   137      * @type number
       
   138      * @protected
       
   139      */
       
   140     _minScrollX: null,
       
   141 
       
   142     /**
       
   143      * Internal state, defines the maximum amount that the scrollview can be scrolled along the X axis
       
   144      *
       
   145      * @property _maxScrollX
       
   146      * @type number
       
   147      * @protected
       
   148      */
       
   149     _maxScrollX: null,
       
   150 
       
   151     /**
       
   152      * Internal state, defines the minimum amount that the scrollview can be scrolled along the Y axis
       
   153      *
       
   154      * @property _minScrollY
       
   155      * @type number
       
   156      * @protected
       
   157      */
       
   158     _minScrollY: null,
       
   159 
       
   160     /**
       
   161      * Internal state, defines the maximum amount that the scrollview can be scrolled along the Y axis
       
   162      *
       
   163      * @property _maxScrollY
       
   164      * @type number
       
   165      * @protected
       
   166      */
       
   167     _maxScrollY: null,
       
   168     
       
   169     /**
       
   170      * Designated initializer
       
   171      *
       
   172      * @method initializer
       
   173      * @param {config} Configuration object for the plugin
       
   174      */
       
   175     initializer: function () {
       
   176         var sv = this;
       
   177 
       
   178         // Cache these values, since they aren't going to change.
       
   179         sv._bb = sv.get(BOUNDING_BOX);
       
   180         sv._cb = sv.get(CONTENT_BOX);
       
   181 
       
   182         // Cache some attributes
       
   183         sv._cAxis = sv.get(AXIS);
       
   184         sv._cBounce = sv.get(BOUNCE);
       
   185         sv._cBounceRange = sv.get(BOUNCE_RANGE);
       
   186         sv._cDeceleration = sv.get(DECELERATION);
       
   187         sv._cFrameDuration = sv.get(FRAME_DURATION);
       
   188     },
       
   189 
       
   190     /**
       
   191      * bindUI implementation
       
   192      *
       
   193      * Hooks up events for the widget
       
   194      * @method bindUI
       
   195      */
       
   196     bindUI: function () {
       
   197         var sv = this;
       
   198 
       
   199         // Bind interaction listers
       
   200         sv._bindFlick(sv.get(FLICK));
       
   201         sv._bindDrag(sv.get(DRAG));
       
   202         sv._bindMousewheel(true);
       
   203         
       
   204         // Bind change events
       
   205         sv._bindAttrs();
       
   206 
       
   207         // IE SELECT HACK. See if we can do this non-natively and in the gesture for a future release.
       
   208         if (IE) {
       
   209             sv._fixIESelect(sv._bb, sv._cb);
       
   210         }
       
   211 
       
   212         // Set any deprecated static properties
       
   213         if (ScrollView.SNAP_DURATION) {
       
   214             sv.set(SNAP_DURATION, ScrollView.SNAP_DURATION);
       
   215         }
       
   216 
       
   217         if (ScrollView.SNAP_EASING) {
       
   218             sv.set(SNAP_EASING, ScrollView.SNAP_EASING);
       
   219         }
       
   220 
       
   221         if (ScrollView.EASING) {
       
   222             sv.set(EASING, ScrollView.EASING);
       
   223         }
       
   224 
       
   225         if (ScrollView.FRAME_STEP) {
       
   226             sv.set(FRAME_DURATION, ScrollView.FRAME_STEP);
       
   227         }
       
   228 
       
   229         if (ScrollView.BOUNCE_RANGE) {
       
   230             sv.set(BOUNCE_RANGE, ScrollView.BOUNCE_RANGE);
       
   231         }
       
   232 
       
   233         // Recalculate dimension properties
       
   234         // TODO: This should be throttled.
       
   235         // Y.one(WINDOW).after('resize', sv._afterDimChange, sv);
       
   236     },
       
   237 
       
   238     /**
       
   239      * Bind event listeners
       
   240      *
       
   241      * @method _bindAttrs
       
   242      * @private
       
   243      */
       
   244     _bindAttrs: function () {
       
   245         var sv = this,
       
   246             scrollChangeHandler = sv._afterScrollChange,
       
   247             dimChangeHandler = sv._afterDimChange;
       
   248 
       
   249         // Bind any change event listeners
       
   250         sv.after({
       
   251             'scrollEnd': sv._afterScrollEnd,
       
   252             'disabledChange': sv._afterDisabledChange,
       
   253             'flickChange': sv._afterFlickChange,
       
   254             'dragChange': sv._afterDragChange,
       
   255             'axisChange': sv._afterAxisChange,
       
   256             'scrollYChange': scrollChangeHandler,
       
   257             'scrollXChange': scrollChangeHandler,
       
   258             'heightChange': dimChangeHandler,
       
   259             'widthChange': dimChangeHandler
       
   260         });
       
   261     },
       
   262 
       
   263     /**
       
   264      * Bind (or unbind) gesture move listeners required for drag support
       
   265      *
       
   266      * @method _bindDrag
       
   267      * @param drag {boolean} If true, the method binds listener to enable
       
   268      *  drag (gesturemovestart). If false, the method unbinds gesturemove
       
   269      *  listeners for drag support.
       
   270      * @private
       
   271      */
       
   272     _bindDrag: function (drag) {
       
   273         var sv = this,
       
   274             bb = sv._bb;
       
   275 
       
   276         // Unbind any previous 'drag' listeners
       
   277         bb.detach(DRAG + '|*');
       
   278 
       
   279         if (drag) {
       
   280             bb.on(DRAG + '|' + GESTURE_MOVE + START, Y.bind(sv._onGestureMoveStart, sv));
       
   281         }
       
   282     },
       
   283 
       
   284     /**
       
   285      * Bind (or unbind) flick listeners.
       
   286      *
       
   287      * @method _bindFlick
       
   288      * @param flick {Object|boolean} If truthy, the method binds listeners for
       
   289      *  flick support. If false, the method unbinds flick listeners.
       
   290      * @private
       
   291      */
       
   292     _bindFlick: function (flick) {
       
   293         var sv = this,
       
   294             bb = sv._bb;
       
   295 
       
   296         // Unbind any previous 'flick' listeners
       
   297         bb.detach(FLICK + '|*');
       
   298 
       
   299         if (flick) {
       
   300             bb.on(FLICK + '|' + FLICK, Y.bind(sv._flick, sv), flick);
       
   301 
       
   302             // Rebind Drag, becuase _onGestureMoveEnd always has to fire -after- _flick
       
   303             sv._bindDrag(sv.get(DRAG));
       
   304         }
       
   305     },
       
   306 
       
   307     /**
       
   308      * Bind (or unbind) mousewheel listeners.
       
   309      *
       
   310      * @method _bindMousewheel
       
   311      * @param mousewheel {Object|boolean} If truthy, the method binds listeners for
       
   312      *  mousewheel support. If false, the method unbinds mousewheel listeners.
       
   313      * @private
       
   314      */
       
   315     _bindMousewheel: function (mousewheel) {
       
   316         var sv = this,
       
   317             bb = sv._bb;
       
   318 
       
   319         // Unbind any previous 'mousewheel' listeners
       
   320         // TODO: This doesn't actually appear to work properly. Fix. #2532743
       
   321         bb.detach(MOUSEWHEEL + '|*');
       
   322 
       
   323         // Only enable for vertical scrollviews
       
   324         if (mousewheel) {
       
   325             // Bound to document, because that's where mousewheel events fire off of.
       
   326             Y.one(DOCUMENT).on(MOUSEWHEEL, Y.bind(sv._mousewheel, sv));
       
   327         }
       
   328     },
       
   329 
       
   330     /**
       
   331      * syncUI implementation.
       
   332      *
       
   333      * Update the scroll position, based on the current value of scrollX/scrollY.
       
   334      *
       
   335      * @method syncUI
       
   336      */
       
   337     syncUI: function () {
       
   338         var sv = this,
       
   339             scrollDims = sv._getScrollDims(),
       
   340             width = scrollDims.offsetWidth,
       
   341             height = scrollDims.offsetHeight,
       
   342             scrollWidth = scrollDims.scrollWidth,
       
   343             scrollHeight = scrollDims.scrollHeight;
       
   344 
       
   345         // If the axis is undefined, auto-calculate it
       
   346         if (sv._cAxis === undefined) {
       
   347             // This should only ever be run once (for now).
       
   348             // In the future SV might post-load axis changes
       
   349             sv._cAxis = {
       
   350                 x: (scrollWidth > width),
       
   351                 y: (scrollHeight > height)
       
   352             };
       
   353 
       
   354             sv._set(AXIS, sv._cAxis);
       
   355         }
       
   356         
       
   357         // get text direction on or inherited by scrollview node
       
   358         sv.rtl = (sv._cb.getComputedStyle('direction') === 'rtl');
       
   359 
       
   360         // Cache the disabled value
       
   361         sv._cDisabled = sv.get(DISABLED);
       
   362 
       
   363         // Run this to set initial values
       
   364         sv._uiDimensionsChange();
       
   365 
       
   366         // If we're out-of-bounds, snap back.
       
   367         if (sv._isOutOfBounds()) {
       
   368             sv._snapBack();
       
   369         }
       
   370     },
       
   371 
       
   372     /**
       
   373      * Utility method to obtain widget dimensions
       
   374      *
       
   375      * @method _getScrollDims
       
   376      * @return {Object} The offsetWidth, offsetHeight, scrollWidth and
       
   377      *  scrollHeight as an array: [offsetWidth, offsetHeight, scrollWidth,
       
   378      *  scrollHeight]
       
   379      * @private
       
   380      */
       
   381     _getScrollDims: function () {
       
   382         var sv = this,
       
   383             cb = sv._cb,
       
   384             bb = sv._bb,
       
   385             TRANS = ScrollView._TRANSITION,
       
   386             // Ideally using CSSMatrix - don't think we have it normalized yet though.
       
   387             // origX = (new WebKitCSSMatrix(cb.getComputedStyle("transform"))).e,
       
   388             // origY = (new WebKitCSSMatrix(cb.getComputedStyle("transform"))).f,
       
   389             origX = sv.get(SCROLL_X),
       
   390             origY = sv.get(SCROLL_Y),
       
   391             origHWTransform,
       
   392             dims;
       
   393 
       
   394         // TODO: Is this OK? Just in case it's called 'during' a transition.
       
   395         if (NATIVE_TRANSITIONS) {
       
   396             cb.setStyle(TRANS.DURATION, ZERO);
       
   397             cb.setStyle(TRANS.PROPERTY, EMPTY);
       
   398         }
       
   399 
       
   400         origHWTransform = sv._forceHWTransforms;
       
   401         sv._forceHWTransforms = false; // the z translation was causing issues with picking up accurate scrollWidths in Chrome/Mac.
       
   402 
       
   403         sv._moveTo(cb, 0, 0);
       
   404         dims = {
       
   405             'offsetWidth': bb.get('offsetWidth'),
       
   406             'offsetHeight': bb.get('offsetHeight'),
       
   407             'scrollWidth': bb.get('scrollWidth'),
       
   408             'scrollHeight': bb.get('scrollHeight')
       
   409         };
       
   410         sv._moveTo(cb, -(origX), -(origY));
       
   411 
       
   412         sv._forceHWTransforms = origHWTransform;
       
   413 
       
   414         return dims;
       
   415     },
       
   416 
       
   417     /**
       
   418      * This method gets invoked whenever the height or width attributes change,
       
   419      * allowing us to determine which scrolling axes need to be enabled.
       
   420      *
       
   421      * @method _uiDimensionsChange
       
   422      * @protected
       
   423      */
       
   424     _uiDimensionsChange: function () {
       
   425         var sv = this,
       
   426             bb = sv._bb,
       
   427             scrollDims = sv._getScrollDims(),
       
   428             width = scrollDims.offsetWidth,
       
   429             height = scrollDims.offsetHeight,
       
   430             scrollWidth = scrollDims.scrollWidth,
       
   431             scrollHeight = scrollDims.scrollHeight,
       
   432             rtl = sv.rtl,
       
   433             svAxis = sv._cAxis,
       
   434             minScrollX = (rtl ? Math.min(0, -(scrollWidth - width)) : 0),
       
   435             maxScrollX = (rtl ? 0 : Math.max(0, scrollWidth - width)),
       
   436             minScrollY = 0,
       
   437             maxScrollY = Math.max(0, scrollHeight - height);
       
   438             
       
   439         if (svAxis && svAxis.x) {
       
   440             bb.addClass(CLASS_NAMES.horizontal);
       
   441         }
       
   442 
       
   443         if (svAxis && svAxis.y) {
       
   444             bb.addClass(CLASS_NAMES.vertical);
       
   445         }
       
   446 
       
   447         sv._setBounds({
       
   448             minScrollX: minScrollX,
       
   449             maxScrollX: maxScrollX,
       
   450             minScrollY: minScrollY,
       
   451             maxScrollY: maxScrollY
       
   452         });
       
   453     },
       
   454 
       
   455     /**
       
   456      * Set the bounding dimensions of the ScrollView
       
   457      *
       
   458      * @method _setBounds
       
   459      * @protected
       
   460      * @param bounds {Object} [duration] ms of the scroll animation. (default is 0)
       
   461      *   @param {Number} [bounds.minScrollX] The minimum scroll X value
       
   462      *   @param {Number} [bounds.maxScrollX] The maximum scroll X value
       
   463      *   @param {Number} [bounds.minScrollY] The minimum scroll Y value
       
   464      *   @param {Number} [bounds.maxScrollY] The maximum scroll Y value
       
   465      */
       
   466     _setBounds: function (bounds) {
       
   467         var sv = this;
       
   468         
       
   469         // TODO: Do a check to log if the bounds are invalid
       
   470 
       
   471         sv._minScrollX = bounds.minScrollX;
       
   472         sv._maxScrollX = bounds.maxScrollX;
       
   473         sv._minScrollY = bounds.minScrollY;
       
   474         sv._maxScrollY = bounds.maxScrollY;
       
   475     },
       
   476 
       
   477     /**
       
   478      * Get the bounding dimensions of the ScrollView
       
   479      *
       
   480      * @method _getBounds
       
   481      * @protected
       
   482      */
       
   483     _getBounds: function () {
       
   484         var sv = this;
       
   485         
       
   486         return {
       
   487             minScrollX: sv._minScrollX,
       
   488             maxScrollX: sv._maxScrollX,
       
   489             minScrollY: sv._minScrollY,
       
   490             maxScrollY: sv._maxScrollY
       
   491         };
       
   492 
       
   493     },
       
   494 
       
   495     /**
       
   496      * Scroll the element to a given xy coordinate
       
   497      *
       
   498      * @method scrollTo
       
   499      * @param x {Number} The x-position to scroll to. (null for no movement)
       
   500      * @param y {Number} The y-position to scroll to. (null for no movement)
       
   501      * @param {Number} [duration] ms of the scroll animation. (default is 0)
       
   502      * @param {String} [easing] An easing equation if duration is set. (default is `easing` attribute)
       
   503      * @param {String} [node] The node to transform.  Setting this can be useful in
       
   504      *  dual-axis paginated instances. (default is the instance's contentBox)
       
   505      */
       
   506     scrollTo: function (x, y, duration, easing, node) {
       
   507         // Check to see if widget is disabled
       
   508         if (this._cDisabled) {
       
   509             return;
       
   510         }
       
   511 
       
   512         var sv = this,
       
   513             cb = sv._cb,
       
   514             TRANS = ScrollView._TRANSITION,
       
   515             callback = Y.bind(sv._onTransEnd, sv), // @Todo : cache this
       
   516             newX = 0,
       
   517             newY = 0,
       
   518             transition = {},
       
   519             transform;
       
   520 
       
   521         // default the optional arguments
       
   522         duration = duration || 0;
       
   523         easing = easing || sv.get(EASING); // @TODO: Cache this
       
   524         node = node || cb;
       
   525 
       
   526         if (x !== null) {
       
   527             sv.set(SCROLL_X, x, {src:UI});
       
   528             newX = -(x);
       
   529         }
       
   530 
       
   531         if (y !== null) {
       
   532             sv.set(SCROLL_Y, y, {src:UI});
       
   533             newY = -(y);
       
   534         }
       
   535 
       
   536         transform = sv._transform(newX, newY);
       
   537 
       
   538         if (NATIVE_TRANSITIONS) {
       
   539             // ANDROID WORKAROUND - try and stop existing transition, before kicking off new one.
       
   540             node.setStyle(TRANS.DURATION, ZERO).setStyle(TRANS.PROPERTY, EMPTY);
       
   541         }
       
   542 
       
   543         // Move
       
   544         if (duration === 0) {
       
   545             if (NATIVE_TRANSITIONS) {
       
   546                 node.setStyle('transform', transform);
       
   547             }
       
   548             else {
       
   549                 // TODO: If both set, batch them in the same update
       
   550                 // Update: Nope, setStyles() just loops through each property and applies it.
       
   551                 if (x !== null) {
       
   552                     node.setStyle(LEFT, newX + PX);
       
   553                 }
       
   554                 if (y !== null) {
       
   555                     node.setStyle(TOP, newY + PX);
       
   556                 }
       
   557             }
       
   558         }
       
   559 
       
   560         // Animate
       
   561         else {
       
   562             transition.easing = easing;
       
   563             transition.duration = duration / 1000;
       
   564 
       
   565             if (NATIVE_TRANSITIONS) {
       
   566                 transition.transform = transform;
       
   567             }
       
   568             else {
       
   569                 transition.left = newX + PX;
       
   570                 transition.top = newY + PX;
       
   571             }
       
   572 
       
   573             node.transition(transition, callback);
       
   574         }
       
   575     },
       
   576 
       
   577     /**
       
   578      * Utility method, to create the translate transform string with the
       
   579      * x, y translation amounts provided.
       
   580      *
       
   581      * @method _transform
       
   582      * @param {Number} x Number of pixels to translate along the x axis
       
   583      * @param {Number} y Number of pixels to translate along the y axis
       
   584      * @private
       
   585      */
       
   586     _transform: function (x, y) {
       
   587         // TODO: Would we be better off using a Matrix for this?
       
   588         var prop = 'translate(' + x + 'px, ' + y + 'px)';
       
   589 
       
   590         if (this._forceHWTransforms) {
       
   591             prop += ' translateZ(0)';
       
   592         }
       
   593 
       
   594         return prop;
       
   595     },
       
   596 
       
   597     /**
       
   598     * Utility method, to move the given element to the given xy position
       
   599     *
       
   600     * @method _moveTo
       
   601     * @param node {Node} The node to move
       
   602     * @param x {Number} The x-position to move to
       
   603     * @param y {Number} The y-position to move to
       
   604     * @private
       
   605     */
       
   606     _moveTo : function(node, x, y) {
       
   607         if (NATIVE_TRANSITIONS) {
       
   608             node.setStyle('transform', this._transform(x, y));
       
   609         } else {
       
   610             node.setStyle(LEFT, x + PX);
       
   611             node.setStyle(TOP, y + PX);
       
   612         }
       
   613     },
       
   614 
       
   615 
       
   616     /**
       
   617      * Content box transition callback
       
   618      *
       
   619      * @method _onTransEnd
       
   620      * @param {Event.Facade} e The event facade
       
   621      * @private
       
   622      */
       
   623     _onTransEnd: function () {
       
   624         var sv = this;
       
   625         
       
   626         // If for some reason we're OOB, snapback
       
   627         if (sv._isOutOfBounds()) {
       
   628             sv._snapBack();
       
   629         }
       
   630         else {
       
   631             /**
       
   632              * Notification event fired at the end of a scroll transition
       
   633              *
       
   634              * @event scrollEnd
       
   635              * @param e {EventFacade} The default event facade.
       
   636              */
       
   637             sv.fire(EV_SCROLL_END);
       
   638         }
       
   639     },
       
   640 
       
   641     /**
       
   642      * gesturemovestart event handler
       
   643      *
       
   644      * @method _onGestureMoveStart
       
   645      * @param e {Event.Facade} The gesturemovestart event facade
       
   646      * @private
       
   647      */
       
   648     _onGestureMoveStart: function (e) {
       
   649 
       
   650         if (this._cDisabled) {
       
   651             return false;
       
   652         }
       
   653 
       
   654         var sv = this,
       
   655             bb = sv._bb,
       
   656             currentX = sv.get(SCROLL_X),
       
   657             currentY = sv.get(SCROLL_Y),
       
   658             clientX = e.clientX,
       
   659             clientY = e.clientY;
       
   660 
       
   661         if (sv._prevent.start) {
       
   662             e.preventDefault();
       
   663         }
       
   664 
       
   665         // if a flick animation is in progress, cancel it
       
   666         if (sv._flickAnim) {
       
   667             sv._cancelFlick();
       
   668             sv._onTransEnd();
       
   669         }
       
   670 
       
   671         // Reset lastScrolledAmt
       
   672         sv.lastScrolledAmt = 0;
       
   673 
       
   674         // Stores data for this gesture cycle.  Cleaned up later
       
   675         sv._gesture = {
       
   676 
       
   677             // Will hold the axis value
       
   678             axis: null,
       
   679 
       
   680             // The current attribute values
       
   681             startX: currentX,
       
   682             startY: currentY,
       
   683 
       
   684             // The X/Y coordinates where the event began
       
   685             startClientX: clientX,
       
   686             startClientY: clientY,
       
   687 
       
   688             // The X/Y coordinates where the event will end
       
   689             endClientX: null,
       
   690             endClientY: null,
       
   691 
       
   692             // The current delta of the event
       
   693             deltaX: null,
       
   694             deltaY: null,
       
   695 
       
   696             // Will be populated for flicks
       
   697             flick: null,
       
   698 
       
   699             // Create some listeners for the rest of the gesture cycle
       
   700             onGestureMove: bb.on(DRAG + '|' + GESTURE_MOVE, Y.bind(sv._onGestureMove, sv)),
       
   701             
       
   702             // @TODO: Don't bind gestureMoveEnd if it's a Flick?
       
   703             onGestureMoveEnd: bb.on(DRAG + '|' + GESTURE_MOVE + END, Y.bind(sv._onGestureMoveEnd, sv))
       
   704         };
       
   705     },
       
   706 
       
   707     /**
       
   708      * gesturemove event handler
       
   709      *
       
   710      * @method _onGestureMove
       
   711      * @param e {Event.Facade} The gesturemove event facade
       
   712      * @private
       
   713      */
       
   714     _onGestureMove: function (e) {
       
   715         var sv = this,
       
   716             gesture = sv._gesture,
       
   717             svAxis = sv._cAxis,
       
   718             svAxisX = svAxis.x,
       
   719             svAxisY = svAxis.y,
       
   720             startX = gesture.startX,
       
   721             startY = gesture.startY,
       
   722             startClientX = gesture.startClientX,
       
   723             startClientY = gesture.startClientY,
       
   724             clientX = e.clientX,
       
   725             clientY = e.clientY;
       
   726 
       
   727         if (sv._prevent.move) {
       
   728             e.preventDefault();
       
   729         }
       
   730 
       
   731         gesture.deltaX = startClientX - clientX;
       
   732         gesture.deltaY = startClientY - clientY;
       
   733 
       
   734         // Determine if this is a vertical or horizontal movement
       
   735         // @TODO: This is crude, but it works.  Investigate more intelligent ways to detect intent
       
   736         if (gesture.axis === null) {
       
   737             gesture.axis = (Math.abs(gesture.deltaX) > Math.abs(gesture.deltaY)) ? DIM_X : DIM_Y;
       
   738         }
       
   739 
       
   740         // Move X or Y.  @TODO: Move both if dualaxis.
       
   741         if (gesture.axis === DIM_X && svAxisX) {
       
   742             sv.set(SCROLL_X, startX + gesture.deltaX);
       
   743         }
       
   744         else if (gesture.axis === DIM_Y && svAxisY) {
       
   745             sv.set(SCROLL_Y, startY + gesture.deltaY);
       
   746         }
       
   747     },
       
   748 
       
   749     /**
       
   750      * gesturemoveend event handler
       
   751      *
       
   752      * @method _onGestureMoveEnd
       
   753      * @param e {Event.Facade} The gesturemoveend event facade
       
   754      * @private
       
   755      */
       
   756     _onGestureMoveEnd: function (e) {
       
   757         var sv = this,
       
   758             gesture = sv._gesture,
       
   759             flick = gesture.flick,
       
   760             clientX = e.clientX,
       
   761             clientY = e.clientY,
       
   762             isOOB;
       
   763 
       
   764         if (sv._prevent.end) {
       
   765             e.preventDefault();
       
   766         }
       
   767 
       
   768         // Store the end X/Y coordinates
       
   769         gesture.endClientX = clientX;
       
   770         gesture.endClientY = clientY;
       
   771 
       
   772         // Cleanup the event handlers
       
   773         gesture.onGestureMove.detach();
       
   774         gesture.onGestureMoveEnd.detach();
       
   775 
       
   776         // If this wasn't a flick, wrap up the gesture cycle
       
   777         if (!flick) {
       
   778             // @TODO: Be more intelligent about this. Look at the Flick attribute to see
       
   779             // if it is safe to assume _flick did or didn't fire.
       
   780             // Then, the order _flick and _onGestureMoveEnd fire doesn't matter?
       
   781 
       
   782             // If there was movement (_onGestureMove fired)
       
   783             if (gesture.deltaX !== null && gesture.deltaY !== null) {
       
   784                 
       
   785                 isOOB = sv._isOutOfBounds();
       
   786                 
       
   787                 // If we're out-out-bounds, then snapback
       
   788                 if (isOOB) {
       
   789                     sv._snapBack();
       
   790                 }
       
   791 
       
   792                 // Inbounds
       
   793                 else {
       
   794                     // Fire scrollEnd unless this is a paginated instance and the gesture axis is the same as paginator's
       
   795                     // Not totally confident this is ideal to access a plugin's properties from a host, @TODO revisit
       
   796                     if (!sv.pages || (sv.pages && !sv.pages.get(AXIS)[gesture.axis])) {
       
   797                         sv._onTransEnd();
       
   798                     }
       
   799                 }
       
   800             }
       
   801         }
       
   802     },
       
   803 
       
   804     /**
       
   805      * Execute a flick at the end of a scroll action
       
   806      *
       
   807      * @method _flick
       
   808      * @param e {Event.Facade} The Flick event facade
       
   809      * @private
       
   810      */
       
   811     _flick: function (e) {
       
   812         if (this._cDisabled) {
       
   813             return false;
       
   814         }
       
   815 
       
   816         var sv = this,
       
   817             svAxis = sv._cAxis,
       
   818             flick = e.flick,
       
   819             flickAxis = flick.axis,
       
   820             flickVelocity = flick.velocity,
       
   821             axisAttr = flickAxis === DIM_X ? SCROLL_X : SCROLL_Y,
       
   822             startPosition = sv.get(axisAttr);
       
   823 
       
   824         // Sometimes flick is enabled, but drag is disabled
       
   825         if (sv._gesture) {
       
   826             sv._gesture.flick = flick;
       
   827         }
       
   828 
       
   829         // Prevent unneccesary firing of _flickFrame if we can't scroll on the flick axis
       
   830         if (svAxis[flickAxis]) {
       
   831             sv._flickFrame(flickVelocity, flickAxis, startPosition);
       
   832         }
       
   833     },
       
   834 
       
   835     /**
       
   836      * Execute a single frame in the flick animation
       
   837      *
       
   838      * @method _flickFrame
       
   839      * @param velocity {Number} The velocity of this animated frame
       
   840      * @param flickAxis {String} The axis on which to animate
       
   841      * @param startPosition {Number} The starting X/Y point to flick from
       
   842      * @protected
       
   843      */
       
   844     _flickFrame: function (velocity, flickAxis, startPosition) {
       
   845 
       
   846         var sv = this,
       
   847             axisAttr = flickAxis === DIM_X ? SCROLL_X : SCROLL_Y,
       
   848             bounds = sv._getBounds(),
       
   849 
       
   850             // Localize cached values
       
   851             bounce = sv._cBounce,
       
   852             bounceRange = sv._cBounceRange,
       
   853             deceleration = sv._cDeceleration,
       
   854             frameDuration = sv._cFrameDuration,
       
   855 
       
   856             // Calculate
       
   857             newVelocity = velocity * deceleration,
       
   858             newPosition = startPosition - (frameDuration * newVelocity),
       
   859 
       
   860             // Some convinience conditions
       
   861             min = flickAxis === DIM_X ? bounds.minScrollX : bounds.minScrollY,
       
   862             max = flickAxis === DIM_X ? bounds.maxScrollX : bounds.maxScrollY,
       
   863             belowMin       = (newPosition < min),
       
   864             belowMax       = (newPosition < max),
       
   865             aboveMin       = (newPosition > min),
       
   866             aboveMax       = (newPosition > max),
       
   867             belowMinRange  = (newPosition < (min - bounceRange)),
       
   868             withinMinRange = (belowMin && (newPosition > (min - bounceRange))),
       
   869             withinMaxRange = (aboveMax && (newPosition < (max + bounceRange))),
       
   870             aboveMaxRange  = (newPosition > (max + bounceRange)),
       
   871             tooSlow;
       
   872 
       
   873         // If we're within the range but outside min/max, dampen the velocity
       
   874         if (withinMinRange || withinMaxRange) {
       
   875             newVelocity *= bounce;
       
   876         }
       
   877 
       
   878         // Is the velocity too slow to bother?
       
   879         tooSlow = (Math.abs(newVelocity).toFixed(4) < 0.015);
       
   880 
       
   881         // If the velocity is too slow or we're outside the range
       
   882         if (tooSlow || belowMinRange || aboveMaxRange) {
       
   883             // Cancel and delete sv._flickAnim
       
   884             if (sv._flickAnim) {
       
   885                 sv._cancelFlick();
       
   886             }
       
   887 
       
   888             // If we're inside the scroll area, just end
       
   889             if (aboveMin && belowMax) {
       
   890                 sv._onTransEnd();
       
   891             }
       
   892 
       
   893             // We're outside the scroll area, so we need to snap back
       
   894             else {
       
   895                 sv._snapBack();
       
   896             }
       
   897         }
       
   898 
       
   899         // Otherwise, animate to the next frame
       
   900         else {
       
   901             // @TODO: maybe use requestAnimationFrame instead
       
   902             sv._flickAnim = Y.later(frameDuration, sv, '_flickFrame', [newVelocity, flickAxis, newPosition]);
       
   903             sv.set(axisAttr, newPosition);
       
   904         }
       
   905     },
       
   906 
       
   907     _cancelFlick: function () {
       
   908         var sv = this;
       
   909 
       
   910         if (sv._flickAnim) {
       
   911             // Cancel the flick (if it exists)
       
   912             sv._flickAnim.cancel();
       
   913 
       
   914             // Also delete it, otherwise _onGestureMoveStart will think we're still flicking
       
   915             delete sv._flickAnim;
       
   916         }
       
   917 
       
   918     },
       
   919 
       
   920     /**
       
   921      * Handle mousewheel events on the widget
       
   922      *
       
   923      * @method _mousewheel
       
   924      * @param e {Event.Facade} The mousewheel event facade
       
   925      * @private
       
   926      */
       
   927     _mousewheel: function (e) {
       
   928         var sv = this,
       
   929             scrollY = sv.get(SCROLL_Y),
       
   930             bounds = sv._getBounds(),
       
   931             bb = sv._bb,
       
   932             scrollOffset = 10, // 10px
       
   933             isForward = (e.wheelDelta > 0),
       
   934             scrollToY = scrollY - ((isForward ? 1 : -1) * scrollOffset);
       
   935 
       
   936         scrollToY = _constrain(scrollToY, bounds.minScrollY, bounds.maxScrollY);
       
   937 
       
   938         // Because Mousewheel events fire off 'document', every ScrollView widget will react
       
   939         // to any mousewheel anywhere on the page. This check will ensure that the mouse is currently
       
   940         // over this specific ScrollView.  Also, only allow mousewheel scrolling on Y-axis,
       
   941         // becuase otherwise the 'prevent' will block page scrolling.
       
   942         if (bb.contains(e.target) && sv._cAxis[DIM_Y]) {
       
   943 
       
   944             // Reset lastScrolledAmt
       
   945             sv.lastScrolledAmt = 0;
       
   946 
       
   947             // Jump to the new offset
       
   948             sv.set(SCROLL_Y, scrollToY);
       
   949 
       
   950             // if we have scrollbars plugin, update & set the flash timer on the scrollbar
       
   951             // @TODO: This probably shouldn't be in this module
       
   952             if (sv.scrollbars) {
       
   953                 // @TODO: The scrollbars should handle this themselves
       
   954                 sv.scrollbars._update();
       
   955                 sv.scrollbars.flash();
       
   956                 // or just this
       
   957                 // sv.scrollbars._hostDimensionsChange();
       
   958             }
       
   959 
       
   960             // Fire the 'scrollEnd' event
       
   961             sv._onTransEnd();
       
   962 
       
   963             // prevent browser default behavior on mouse scroll
       
   964             e.preventDefault();
       
   965         }
       
   966     },
       
   967 
       
   968     /**
       
   969      * Checks to see the current scrollX/scrollY position beyond the min/max boundary
       
   970      *
       
   971      * @method _isOutOfBounds
       
   972      * @param x {Number} [optional] The X position to check
       
   973      * @param y {Number} [optional] The Y position to check
       
   974      * @return {boolen} Whether the current X/Y position is out of bounds (true) or not (false)
       
   975      * @private
       
   976      */
       
   977     _isOutOfBounds: function (x, y) {
       
   978         var sv = this,
       
   979             svAxis = sv._cAxis,
       
   980             svAxisX = svAxis.x,
       
   981             svAxisY = svAxis.y,
       
   982             currentX = x || sv.get(SCROLL_X),
       
   983             currentY = y || sv.get(SCROLL_Y),
       
   984             bounds = sv._getBounds(),
       
   985             minX = bounds.minScrollX,
       
   986             minY = bounds.minScrollY,
       
   987             maxX = bounds.maxScrollX,
       
   988             maxY = bounds.maxScrollY;
       
   989 
       
   990         return (svAxisX && (currentX < minX || currentX > maxX)) || (svAxisY && (currentY < minY || currentY > maxY));
       
   991     },
       
   992 
       
   993     /**
       
   994      * Bounces back
       
   995      * @TODO: Should be more generalized and support both X and Y detection
       
   996      *
       
   997      * @method _snapBack
       
   998      * @private
       
   999      */
       
  1000     _snapBack: function () {
       
  1001         var sv = this,
       
  1002             currentX = sv.get(SCROLL_X),
       
  1003             currentY = sv.get(SCROLL_Y),
       
  1004             bounds = sv._getBounds(),
       
  1005             minX = bounds.minScrollX,
       
  1006             minY = bounds.minScrollY,
       
  1007             maxX = bounds.maxScrollX,
       
  1008             maxY = bounds.maxScrollY,
       
  1009             newY = _constrain(currentY, minY, maxY),
       
  1010             newX = _constrain(currentX, minX, maxX),
       
  1011             duration = sv.get(SNAP_DURATION),
       
  1012             easing = sv.get(SNAP_EASING);
       
  1013 
       
  1014         if (newX !== currentX) {
       
  1015             sv.set(SCROLL_X, newX, {duration:duration, easing:easing});
       
  1016         }
       
  1017         else if (newY !== currentY) {
       
  1018             sv.set(SCROLL_Y, newY, {duration:duration, easing:easing});
       
  1019         }
       
  1020         else {
       
  1021             sv._onTransEnd();
       
  1022         }
       
  1023     },
       
  1024 
       
  1025     /**
       
  1026      * After listener for changes to the scrollX or scrollY attribute
       
  1027      *
       
  1028      * @method _afterScrollChange
       
  1029      * @param e {Event.Facade} The event facade
       
  1030      * @protected
       
  1031      */
       
  1032     _afterScrollChange: function (e) {
       
  1033         if (e.src === ScrollView.UI_SRC) {
       
  1034             return false;
       
  1035         }
       
  1036 
       
  1037         var sv = this,
       
  1038             duration = e.duration,
       
  1039             easing = e.easing,
       
  1040             val = e.newVal,
       
  1041             scrollToArgs = [];
       
  1042 
       
  1043         // Set the scrolled value
       
  1044         sv.lastScrolledAmt = sv.lastScrolledAmt + (e.newVal - e.prevVal);
       
  1045 
       
  1046         // Generate the array of args to pass to scrollTo()
       
  1047         if (e.attrName === SCROLL_X) {
       
  1048             scrollToArgs.push(val);
       
  1049             scrollToArgs.push(sv.get(SCROLL_Y));
       
  1050         }
       
  1051         else {
       
  1052             scrollToArgs.push(sv.get(SCROLL_X));
       
  1053             scrollToArgs.push(val);
       
  1054         }
       
  1055 
       
  1056         scrollToArgs.push(duration);
       
  1057         scrollToArgs.push(easing);
       
  1058 
       
  1059         sv.scrollTo.apply(sv, scrollToArgs);
       
  1060     },
       
  1061 
       
  1062     /**
       
  1063      * After listener for changes to the flick attribute
       
  1064      *
       
  1065      * @method _afterFlickChange
       
  1066      * @param e {Event.Facade} The event facade
       
  1067      * @protected
       
  1068      */
       
  1069     _afterFlickChange: function (e) {
       
  1070         this._bindFlick(e.newVal);
       
  1071     },
       
  1072 
       
  1073     /**
       
  1074      * After listener for changes to the disabled attribute
       
  1075      *
       
  1076      * @method _afterDisabledChange
       
  1077      * @param e {Event.Facade} The event facade
       
  1078      * @protected
       
  1079      */
       
  1080     _afterDisabledChange: function (e) {
       
  1081         // Cache for performance - we check during move
       
  1082         this._cDisabled = e.newVal;
       
  1083     },
       
  1084 
       
  1085     /**
       
  1086      * After listener for the axis attribute
       
  1087      *
       
  1088      * @method _afterAxisChange
       
  1089      * @param e {Event.Facade} The event facade
       
  1090      * @protected
       
  1091      */
       
  1092     _afterAxisChange: function (e) {
       
  1093         this._cAxis = e.newVal;
       
  1094     },
       
  1095 
       
  1096     /**
       
  1097      * After listener for changes to the drag attribute
       
  1098      *
       
  1099      * @method _afterDragChange
       
  1100      * @param e {Event.Facade} The event facade
       
  1101      * @protected
       
  1102      */
       
  1103     _afterDragChange: function (e) {
       
  1104         this._bindDrag(e.newVal);
       
  1105     },
       
  1106 
       
  1107     /**
       
  1108      * After listener for the height or width attribute
       
  1109      *
       
  1110      * @method _afterDimChange
       
  1111      * @param e {Event.Facade} The event facade
       
  1112      * @protected
       
  1113      */
       
  1114     _afterDimChange: function () {
       
  1115         this._uiDimensionsChange();
       
  1116     },
       
  1117 
       
  1118     /**
       
  1119      * After listener for scrollEnd, for cleanup
       
  1120      *
       
  1121      * @method _afterScrollEnd
       
  1122      * @param e {Event.Facade} The event facade
       
  1123      * @protected
       
  1124      */
       
  1125     _afterScrollEnd: function () {
       
  1126         var sv = this;
       
  1127 
       
  1128         if (sv._flickAnim) {
       
  1129             sv._cancelFlick();
       
  1130         }
       
  1131 
       
  1132         // Ideally this should be removed, but doing so causing some JS errors with fast swiping
       
  1133         // because _gesture is being deleted after the previous one has been overwritten
       
  1134         // delete sv._gesture; // TODO: Move to sv.prevGesture?
       
  1135     },
       
  1136 
       
  1137     /**
       
  1138      * Setter for 'axis' attribute
       
  1139      *
       
  1140      * @method _axisSetter
       
  1141      * @param val {Mixed} A string ('x', 'y', 'xy') to specify which axis/axes to allow scrolling on
       
  1142      * @param name {String} The attribute name
       
  1143      * @return {Object} An object to specify scrollability on the x & y axes
       
  1144      *
       
  1145      * @protected
       
  1146      */
       
  1147     _axisSetter: function (val) {
       
  1148 
       
  1149         // Turn a string into an axis object
       
  1150         if (Y.Lang.isString(val)) {
       
  1151             return {
       
  1152                 x: val.match(/x/i) ? true : false,
       
  1153                 y: val.match(/y/i) ? true : false
       
  1154             };
       
  1155         }
       
  1156     },
       
  1157     
       
  1158     /**
       
  1159     * The scrollX, scrollY setter implementation
       
  1160     *
       
  1161     * @method _setScroll
       
  1162     * @private
       
  1163     * @param {Number} val
       
  1164     * @param {String} dim
       
  1165     *
       
  1166     * @return {Number} The value
       
  1167     */
       
  1168     _setScroll : function(val) {
       
  1169 
       
  1170         // Just ensure the widget is not disabled
       
  1171         if (this._cDisabled) {
       
  1172             val = Y.Attribute.INVALID_VALUE;
       
  1173         }
       
  1174 
       
  1175         return val;
       
  1176     },
       
  1177 
       
  1178     /**
       
  1179     * Setter for the scrollX attribute
       
  1180     *
       
  1181     * @method _setScrollX
       
  1182     * @param val {Number} The new scrollX value
       
  1183     * @return {Number} The normalized value
       
  1184     * @protected
       
  1185     */
       
  1186     _setScrollX: function(val) {
       
  1187         return this._setScroll(val, DIM_X);
       
  1188     },
       
  1189 
       
  1190     /**
       
  1191     * Setter for the scrollY ATTR
       
  1192     *
       
  1193     * @method _setScrollY
       
  1194     * @param val {Number} The new scrollY value
       
  1195     * @return {Number} The normalized value
       
  1196     * @protected
       
  1197     */
       
  1198     _setScrollY: function(val) {
       
  1199         return this._setScroll(val, DIM_Y);
       
  1200     }
       
  1201 
       
  1202     // End prototype properties
       
  1203 
       
  1204 }, {
       
  1205 
       
  1206     // Static properties
       
  1207 
       
  1208     /**
       
  1209      * The identity of the widget.
       
  1210      *
       
  1211      * @property NAME
       
  1212      * @type String
       
  1213      * @default 'scrollview'
       
  1214      * @readOnly
       
  1215      * @protected
       
  1216      * @static
       
  1217      */
       
  1218     NAME: 'scrollview',
       
  1219 
       
  1220     /**
       
  1221      * Static property used to define the default attribute configuration of
       
  1222      * the Widget.
       
  1223      *
       
  1224      * @property ATTRS
       
  1225      * @type {Object}
       
  1226      * @protected
       
  1227      * @static
       
  1228      */
       
  1229     ATTRS: {
       
  1230 
       
  1231         /**
       
  1232          * Specifies ability to scroll on x, y, or x and y axis/axes.
       
  1233          *
       
  1234          * @attribute axis
       
  1235          * @type String
       
  1236          */
       
  1237         axis: {
       
  1238             setter: '_axisSetter',
       
  1239             writeOnce: 'initOnly'
       
  1240         },
       
  1241 
       
  1242         /**
       
  1243          * The current scroll position in the x-axis
       
  1244          *
       
  1245          * @attribute scrollX
       
  1246          * @type Number
       
  1247          * @default 0
       
  1248          */
       
  1249         scrollX: {
       
  1250             value: 0,
       
  1251             setter: '_setScrollX'
       
  1252         },
       
  1253 
       
  1254         /**
       
  1255          * The current scroll position in the y-axis
       
  1256          *
       
  1257          * @attribute scrollY
       
  1258          * @type Number
       
  1259          * @default 0
       
  1260          */
       
  1261         scrollY: {
       
  1262             value: 0,
       
  1263             setter: '_setScrollY'
       
  1264         },
       
  1265 
       
  1266         /**
       
  1267          * Drag coefficent for inertial scrolling. The closer to 1 this
       
  1268          * value is, the less friction during scrolling.
       
  1269          *
       
  1270          * @attribute deceleration
       
  1271          * @default 0.93
       
  1272          */
       
  1273         deceleration: {
       
  1274             value: 0.93
       
  1275         },
       
  1276 
       
  1277         /**
       
  1278          * Drag coefficient for intertial scrolling at the upper
       
  1279          * and lower boundaries of the scrollview. Set to 0 to
       
  1280          * disable "rubber-banding".
       
  1281          *
       
  1282          * @attribute bounce
       
  1283          * @type Number
       
  1284          * @default 0.1
       
  1285          */
       
  1286         bounce: {
       
  1287             value: 0.1
       
  1288         },
       
  1289 
       
  1290         /**
       
  1291          * The minimum distance and/or velocity which define a flick. Can be set to false,
       
  1292          * to disable flick support (note: drag support is enabled/disabled separately)
       
  1293          *
       
  1294          * @attribute flick
       
  1295          * @type Object
       
  1296          * @default Object with properties minDistance = 10, minVelocity = 0.3.
       
  1297          */
       
  1298         flick: {
       
  1299             value: {
       
  1300                 minDistance: 10,
       
  1301                 minVelocity: 0.3
       
  1302             }
       
  1303         },
       
  1304 
       
  1305         /**
       
  1306          * Enable/Disable dragging the ScrollView content (note: flick support is enabled/disabled separately)
       
  1307          * @attribute drag
       
  1308          * @type boolean
       
  1309          * @default true
       
  1310          */
       
  1311         drag: {
       
  1312             value: true
       
  1313         },
       
  1314 
       
  1315         /**
       
  1316          * The default duration to use when animating the bounce snap back.
       
  1317          *
       
  1318          * @attribute snapDuration
       
  1319          * @type Number
       
  1320          * @default 400
       
  1321          */
       
  1322         snapDuration: {
       
  1323             value: 400
       
  1324         },
       
  1325 
       
  1326         /**
       
  1327          * The default easing to use when animating the bounce snap back.
       
  1328          *
       
  1329          * @attribute snapEasing
       
  1330          * @type String
       
  1331          * @default 'ease-out'
       
  1332          */
       
  1333         snapEasing: {
       
  1334             value: 'ease-out'
       
  1335         },
       
  1336 
       
  1337         /**
       
  1338          * The default easing used when animating the flick
       
  1339          *
       
  1340          * @attribute easing
       
  1341          * @type String
       
  1342          * @default 'cubic-bezier(0, 0.1, 0, 1.0)'
       
  1343          */
       
  1344         easing: {
       
  1345             value: 'cubic-bezier(0, 0.1, 0, 1.0)'
       
  1346         },
       
  1347 
       
  1348         /**
       
  1349          * The interval (ms) used when animating the flick for JS-timer animations
       
  1350          *
       
  1351          * @attribute frameDuration
       
  1352          * @type Number
       
  1353          * @default 15
       
  1354          */
       
  1355         frameDuration: {
       
  1356             value: 15
       
  1357         },
       
  1358 
       
  1359         /**
       
  1360          * The default bounce distance in pixels
       
  1361          *
       
  1362          * @attribute bounceRange
       
  1363          * @type Number
       
  1364          * @default 150
       
  1365          */
       
  1366         bounceRange: {
       
  1367             value: 150
       
  1368         }
       
  1369     },
       
  1370 
       
  1371     /**
       
  1372      * List of class names used in the scrollview's DOM
       
  1373      *
       
  1374      * @property CLASS_NAMES
       
  1375      * @type Object
       
  1376      * @static
       
  1377      */
       
  1378     CLASS_NAMES: CLASS_NAMES,
       
  1379 
       
  1380     /**
       
  1381      * Flag used to source property changes initiated from the DOM
       
  1382      *
       
  1383      * @property UI_SRC
       
  1384      * @type String
       
  1385      * @static
       
  1386      * @default 'ui'
       
  1387      */
       
  1388     UI_SRC: UI,
       
  1389 
       
  1390     /**
       
  1391      * Object map of style property names used to set transition properties.
       
  1392      * Defaults to the vendor prefix established by the Transition module.
       
  1393      * The configured property names are `_TRANSITION.DURATION` (e.g. "WebkitTransitionDuration") and
       
  1394      * `_TRANSITION.PROPERTY (e.g. "WebkitTransitionProperty").
       
  1395      *
       
  1396      * @property _TRANSITION
       
  1397      * @private
       
  1398      */
       
  1399     _TRANSITION: {
       
  1400         DURATION: (vendorPrefix ? vendorPrefix + 'TransitionDuration' : 'transitionDuration'),
       
  1401         PROPERTY: (vendorPrefix ? vendorPrefix + 'TransitionProperty' : 'transitionProperty')
       
  1402     },
       
  1403 
       
  1404     /**
       
  1405      * The default bounce distance in pixels
       
  1406      *
       
  1407      * @property BOUNCE_RANGE
       
  1408      * @type Number
       
  1409      * @static
       
  1410      * @default false
       
  1411      * @deprecated (in 3.7.0)
       
  1412      */
       
  1413     BOUNCE_RANGE: false,
       
  1414 
       
  1415     /**
       
  1416      * The interval (ms) used when animating the flick
       
  1417      *
       
  1418      * @property FRAME_STEP
       
  1419      * @type Number
       
  1420      * @static
       
  1421      * @default false
       
  1422      * @deprecated (in 3.7.0)
       
  1423      */
       
  1424     FRAME_STEP: false,
       
  1425 
       
  1426     /**
       
  1427      * The default easing used when animating the flick
       
  1428      *
       
  1429      * @property EASING
       
  1430      * @type String
       
  1431      * @static
       
  1432      * @default false
       
  1433      * @deprecated (in 3.7.0)
       
  1434      */
       
  1435     EASING: false,
       
  1436 
       
  1437     /**
       
  1438      * The default easing to use when animating the bounce snap back.
       
  1439      *
       
  1440      * @property SNAP_EASING
       
  1441      * @type String
       
  1442      * @static
       
  1443      * @default false
       
  1444      * @deprecated (in 3.7.0)
       
  1445      */
       
  1446     SNAP_EASING: false,
       
  1447 
       
  1448     /**
       
  1449      * The default duration to use when animating the bounce snap back.
       
  1450      *
       
  1451      * @property SNAP_DURATION
       
  1452      * @type Number
       
  1453      * @static
       
  1454      * @default false
       
  1455      * @deprecated (in 3.7.0)
       
  1456      */
       
  1457     SNAP_DURATION: false
       
  1458 
       
  1459     // End static properties
       
  1460 
       
  1461 });
       
  1462 
       
  1463 }, '3.10.3', {"requires": ["widget", "event-gestures", "event-mousewheel", "transition"], "skinnable": true});