API Docs for: 0.0.1
Show:

File: js/zui-scrollsnapper.js

/**
 * ZUI ScrollSnapper is a scrollView plugin to replace YUI3 ScrollViewPaginator plugin.
 * It provides same interface and namespace, and better user interaction.
 *
 * @module gallery-zui-scrollsnapper
 */

/**
 * ScrollSnapper is a ScrollView plugin to replace YUI3 ScrollViewPaginator.
 *
 * @class ScrollSnapper
 * @namespace zui 
 * @extends Plugin.Base
 * @constructor
 */
var ScrollSnapper = function () {
        ScrollSnapper.superclass.constructor.apply(this, arguments);
    };

ScrollSnapper.NAME = 'pluginScrollSnapper';
ScrollSnapper.NS = 'pages';
ScrollSnapper.ATTRS = {
    /**
     * The active page number for a paged scrollview in micro seconds
     *
     * @attribute snapDuration
     * @type {Number}
     * @default 500
     */
    snapDuration: {
        value: 500,
        validator: Y.Lang.isNumber
    },

    /**
     * CSS selector for a page inside the scrollview. The scrollview
     * will snap to the closest page.
     *
     * @attribute selector
     * @type {String}
     */
    selector: {
        value: null
    },

    /**
     * The active page number for a paged scrollview
     *
     * @attribute index
     * @type {Number}
     * @default 0
     */
    index: {
        value: 0,
        lazyAdd: false,
        setter: function (val) {
            var T = this.get('total'),
                V = Math.max(Math.floor(val), 0);

            if (T && (V >= T)) {
                V = T - 1;
            }

            if (this._pages) {
                this.scrollTo(V, this.get('snapDuration'), 'ease-out');
            }

            return V;
        }
    },

    /**
     * The total number of pages
     *
     * @attribute total
     * @type {Number}
     * @default 0
     */
    total: {
        value: 0
    }
};

Y.namespace('zui').ScrollSnapper = Y.extend(ScrollSnapper, Y.Plugin.Base, {
    initializer: function () {
        this._host = this.get('host');
        this._vertical = this._host._scrollsVertical;
        this._snapAttr = this._vertical ? 'offsetTop' : 'offsetLeft';
        this._snapRange = this._vertical ? 'offsetHeight' : 'offsetWidth';
        this._snapSource = this._vertical ? 'scrollY' : 'scrollX';
        this.afterHostMethod('_uiDimensionsChange', this._updateSnap);
        this.afterHostEvent('render', this._updatePages);
        this.afterHostEvent('scrollEnd', this._scrollEnded);
        this._updatePages();
    },

    /**
     * Update current page positions when scrollView width/height changed
     *
     * @method _updateSnap
     * @protected
     */
    _updateSnap: function () {
        this.scrollTo(this.get('index'));
    },

    /**
     * Update page positions
     *
     * @method _updatePages
     * @protected
     */
    _updatePages: function () {
        var cb = this._host.get('contentBox'),
            S = this.get('selector');

        this._pages = S ? cb.all(S) : cb.get('children');
        this.set('total', this._pages.size());
    },

    /**
     * internal scrollEnd event handler
     *
     * @method _scrollEnded
     * @protected
     */
    _scrollEnded: function (E) {
        var fl = this._host._flicking;

        Y.later(fl ? this.get('snapDuration') : 1, this, function () {
            if (fl) {
                this._host._currentVelocity = 0;
            }
            if (this._host.get(this._snapSource) == this._lastSnap) {
                return;
            }
            this.snapTo(this.snapIndex());
        });
    },

    /**
     * Snap to a page, same as set('index', page)
     *
     * @method snapTo
     * @param page {Number} page index, start from 0
     */
    snapTo: function (page) {
        this.set('index', page);
    },

    /**
     * Scroll to a given page in the scrollview
     *
     * @method scrollTo
     * @param page {Number} page index, start from 0
     * @param duration {Number} The number of ms the animation should last
     * @param easing {String} The timing function to use in the animation
     */
    scrollTo: function (page, duration, easing) {
        var V = Math.max(Math.floor(page), 0),
            T = Math.max(duration, 0),
            O = this._pages.item(V),
            D = O ? O.get(this._snapAttr) : 0,
            C = this._host.get(this._snapSource);

        if (C === D) {
            return;
        }

        this._lastSnap = D;

        if (this._vertical) {
            this._host.scrollTo(null, D, T, easing);
        } else {
            this._host.scrollTo(D, null, T, easing);
        }
    },

    /**
     * Scroll to the next page in the scrollview, with animation
     *
     * @method next
     */
    next: function () {
        var index = this.get('index');
        if(index < this.get('total') - 1) {
            this.set('index', index + 1);
        }
    },

    /**
     * Scroll to the previous page in the scrollview, with animation
     *
     * @method prev
     */
    prev: function () {
        var index = this.get('index');
        if(index > 0) {
            this.set('index', index - 1);
        }
    },

    /**
     * Get nearest page index
     *
     * @method snapIndex
     */
    snapIndex: function () {
        var A = this._snapAttr,
            R = this._snapRange,
            C = this._host.get(this._snapSource), // + this._range,
            I, O,
            pages = this._pages,
            T = pages.size();

        for (I=0;I<T;I++) {
            O = pages.item(I);
            if (C < O.get(A) + O.get(R) / 2) {
                return I;
            }
        }
        return null;
    }
});