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