API Docs for:
Show:

File: packages/bricksui-thirdpart/lib/mixins/pageable.js

/*globals jQuery:true;Ember:true */
/**
 @module bricksui
 @submodule bricksui-thirdpart
 */
/**
 * Normalizes values to be used in a sort for natural sort
 * @private
 * @param  {Mixed} a
 * @param  {Mixed} b
 * @return {Array}
 */
var normalizeSortValues = function (a, b) {
    // Set unsupported types.  May need to be made into a whitelist instead
    var failTypes = ['function', 'object', 'array', 'date', 'regexp'];

    // Check if `b` can be normalized
    if (jQuery.inArray(jQuery.type(a), failTypes) !== -1) {
        throw new Error('Cannot normalize input `a`! ' + jQuery.type(a) + ' was passed!');
    }

    // Check if `b` can be normalized
    if (jQuery.inArray(jQuery.type(b), failTypes) !== -1) {
        throw new Error('Cannot normalize input `b`! ' + jQuery.type(b) + ' was passed!');
    }

    // Function that does the normalizing
    var norm = function (input) {
        // Some setup
        var ret,
            tests = {
                // Regex to detect if is number
                number: /^([0-9]+?)$/
            };

        // Figure out what the value is return the normalized version
        switch (jQuery.type(input)) {
            case 'string':
                if (tests.number.test(jQuery.trim(input))) {
                    return parseInt(input, 10);
                }
                return jQuery.trim(input).toLowerCase();
            case 'null':
                return '';
            case 'boolean':
                return input ? '0' : '1';
            default:
                return input;
        }
    };

    // Normalize variables
    a = norm(a);
    b = norm(b);

    // If types differ, set them both to strings
    if ((typeof a === 'string' && typeof b === 'number') || (typeof b === 'string' && typeof a === 'number')) {
        a = String(a);
        b = String(b);
    }

    // Return normalized values
    return [a, b];
};


/**
 静态数据处理扩展,用于分页处理
 @type {Ember.Mixin}
 @namespace BricksUI
 @class StaticPageable
 */
var StaticPageable = Ember.Mixin.create({
    /**
     * 当前页码
     * @property currentPage
     * @type {Number}
     */
    currentPage: 1,

    /**
     * 每页显示条数
     * @property perPage
     * @type {Number}
     */
    perPage: 100,

    /**
     * 排序字段
     * @property sortBy
     * @type {String}
     */
    sortBy: null,

    /**
     * 排序方向
     * @property sortDirection
     * @type {String}
     */
    sortDirection: 'ascending',


    /**
     * 静态数据本地数据存放的集合
     * @property data
     * @type {Array}
     */
    data: [],

    /**
     * Used for the collection view for which items to show
     *
     * @return {Array}
     */
    content: function () {
        // Get the starting and ending point of the array to slice
        var start = (this.get('currentPage') - 1) * this.get('perPage'),
            end = start + this.get('perPage');

        return this.get('data').slice(start, end);
    }.property('currentPage', 'perPage', 'data.@each'),

    /**
     * 总页数
     * @property totalPages
     * @return int Total Number of Pages
     */
    totalPages: function () {
        return Math.ceil(this.get('data.length') / this.get('perPage'));
    }.property('data.@each', 'perPage'),

    actions: {
        /**
         * 后一页
         * @method nextPage
         */
        nextPage: function () {
            // Make sure you can go forward first
            if (this.get('currentPage') === this.get('totalPages'))
                return null; // NOOP

            // Set the current page to the next page
            this.set('currentPage', this.get('currentPage') + 1);
        },

        /**
         * 前一页
         * @method prevPage
         */
        prevPage: function () {
            // Make sure you can go backwards first
            if (this.get('currentPage') === 1)
                return null; // NOOP

            // Set the current page to the previous page
            this.set('currentPage', this.get('currentPage') - 1);
        },
        /**
         * 第一页
         * @method firstPage
         */
        firstPage: function () {
            this.set('currentPage', 1);
        },
        /**
         * 尾页
         * @method lastPage
         */
        lastPage: function () {
            this.set('currentPage', this.get('totalPages'));
        }
    },

    /**
     * Sorts the data by a property
     * @param  {String} property
     * @param  {String} direction
     * @return {Void}
     */
    sortByProperty: function (property, direction) {
        var data = this.get('data').slice();

        // Set up sort direction
        if (direction === undefined) {
            if (this.get('sortBy') === property && this.get('sortDirection') === 'ascending')
                direction = 'descending';
            else
                direction = 'ascending';
        }

        // Custom sort to sort alphanumerically
        data.sort(function (a, b) {
            // Normalize values to make sort natural
            var normalizedValues = normalizeSortValues(a.get(property), b.get(property)),
                va = normalizedValues[0],
                vb = normalizedValues[1];

            // Do the sorting
            if (va === vb)
                return 0;
            else {
                // Reverse if necessary
                if (direction === 'ascending')
                    return va > vb ? 1 : -1;
                else
                    return va < vb ? 1 : -1;
            }
        });

        // Now that sort is complete, set the controller
        this.set('sortBy', property);

        // Assign sort direction
        this.set('sortDirection', direction);

        // Assign the data
        this.set('data', data);

        // Reset the current page to 1
        this.set('currentPage', 1);
    }
});
/**
 基于Ember-Data的数据处理扩展,用于分页处理
 分页扩展,用于增强控制器的功能,使控制器具备分页管理功能
 * `modelName`  必须配置,当前分页组件所要请求的模型名称
 * `query` 要传入到后台的查询参数,是一个计算属性,需要返回`Object`
 ```javascript
 App.ApplicationController = Ember.ArrayController.extend(BricksUI.DynamicPageable,{
    perPage: 5,
    modelName:"user",
    firstName:"xx",
    selectedPageSize:5,
    pageSizes: [
       5,10,15,20
    ],
    query:function(){
        return {
            firstName:this.get('firstName'),
            limit:this.get('selectedPageSize')
        }
    }.property("firstName","city").volatile()
});
 ```
 `BricksUI.DynamicPageable` 用于扩展控制器的分页功能
 `BricksUI.BuPagination` 用于分页组件视图的呈现,并且将`action`委托给控制器

 @namespace BricksUI
 @type {Ember.Mixin}
 @class DynamicPageable
 */
var DynamicPageable = Ember.Mixin.create({
    /**
     * 当前页码
     * @property currentPage
     * @type {Number}
     */
    currentPage: 1,

    /**
     * 每页显示多少条
     * @property perPage
     * @type {Number}
     */
    perPage: 10,

    /**
     * 排序字段
     * @property sortBy
     * @type {String}
     */
    sortBy: null,

    /**
     * 排序方向,升序或者降序
     * @property sortDirection
     * @type {String}
     * @default ascending
     */
    sortDirection: 'ascending',

    init: function () {
        Ember.assert("the modelName must provided !", this.get('modelName'));
        this.paramNames = Ember.$.extend(this.paramNames || {}, this.defaultParamNames);
        this._super.apply(this, arguments);
        this.send("firstPage");
    },
    /**
     * @private
     * @returns {null}
     */
    getParams: function () {
        return this.paramNames;
    },
    /**
     *  查询参数,可覆盖`defaultParamNames`
     *  @property paramNames
     *  @type {Object}
     *  @default null
     */
    paramNames: null,

    /**
     *  默认的查询参数
     *  @property defaultParamNames
     *  @type {Object}
     *  @default {
     *      start: 'start',
     *      limit: 'limit',
     *      sort: 'sort',
     *      dir: 'dir'
     *  }
     */
    defaultParamNames: {
        start: 'start',
        limit: 'limit',
        sort: 'sort',
        dir: 'dir'
    },
    /**
     * 数据加载中
     * @property loading
     * @type {Boolean}
     * @default false
     */
    loading: false,
    /**
     * 用户的自定以查询参数
     * @property query
     * @type {Object}
     * @default null
     */
    query: null,
    /**
     * @private
     */
    cursor: 0,
    /**
     * @private
     */
    doLoad: function (start) {
        if (!this.get('store')) {
            return [];
        }
        var o = {}, pn = this.getParams(), that = this;
        o[pn.start] = start;
        o[pn.limit] = this.get('perPage');
        o[pn.sort] = this.get("sortBy");
        o[pn.dir] = this.get("sortDirection");

        Ember.$.extend(o, this.get('query'));

        if (this.get('loading')) {
            return false;
        }
        console.log(o);
        var loadingPromise = this.store.find(this.get('modelName'), o).then(function (models) {
            var perPage = o.limit,
                len = models.get('length');
            Ember.assert("server return models length is " + models.get('length') + " but the config perPage is " + perPage, len === perPage);
            that.set("content", models);
            that.set("cursor", start);
            Ember.propertyDidChange(that, "totalPages");
            that.set("loading", false);
        });
        this.set("loading", true);
        return loadingPromise;
    },


    /**
     * 总页数
     * @property totalPages
     */
    totalPages: function () {
        return Math.ceil(this.getTotalCount() / this.get('perPage'));
    }.property('perPage'),

    actions: {
        /**
         * 下一页
         * @method nextPage
         */
        nextPage: function () {
            // Make sure you can go forward first
            if (this.get('currentPage') === this.get('totalPages'))
                return null; // NOOP

            // Set the current page to the next page
            var promise = this.doLoad(this.cursor + this.get('perPage'));
            if (promise.then) {
                var that = this;
                promise.then(function () {
                    that.set('currentPage', that.get('currentPage') + 1);
                });
            }
        },

        /**
         * 上一页
         * @method prevPage
         */
        prevPage: function () {
            // Make sure you can go backwards first
            if (this.get('currentPage') === 1)
                return null; // NOOP

            // Set the current page to the previous page

            var promise = this.doLoad(Math.max(0, this.cursor - this.get('perPage')));
            if (promise.then) {
                var that = this;
                promise.then(function () {
                    that.set('currentPage', that.get('currentPage') - 1);
                });
            }
        },
        /**
         * 首页
         * @method firstPage
         */
        firstPage: function () {
            this.set("currentPage", 1);
            this.doLoad(0);
        },
        /**
         * 尾页
         * @method lastPage
         */
        lastPage: function () {
            var total = this./**/getTotalCount(),
                extra = total % this.get('perPage');

            this.set("currentPage", this.get('totalPages'));
            this.doLoad(extra ? (total - extra) : total - this.get('perPage'));
        }
    },
    /**
     * 总条数
     * @method getTotalCount
     * @returns {*|number}
     */
    getTotalCount: function () {
        var meta = this.store.metadataFor(this.get('modelName'));
        return meta.total || 0;
    },
    /**
     * 根据属性名称排序
     * @method sortByProperty
     */
    sortByProperty: function (property, direction) {
        var data = this.get('content').slice();

        // Set up sort direction
        if (direction === undefined) {
            if (this.get('sortBy') === property && this.get('sortDirection') === 'ascending')
                direction = 'descending';
            else
                direction = 'ascending';
        }

        // Custom sort to sort alphanumerically
        data.sort(function (a, b) {
            // Normalize values to make sort natural
            var normalizedValues = normalizeSortValues(a.get(property), b.get(property)),
                va = normalizedValues[0],
                vb = normalizedValues[1];

            // Do the sorting
            if (va === vb)
                return 0;
            else {
                // Reverse if necessary
                if (direction === 'ascending')
                    return va > vb ? 1 : -1;
                else
                    return va < vb ? 1 : -1;
            }
        });

        // Now that sort is complete, set the controller
        this.set('sortBy', property);

        // Assign sort direction
        this.set('sortDirection', direction);

        // Assign the data
        this.set('content', data);

        // Reset the current page to 1
        //this.set('currentPage', 1);
        this.send("firstPage");
    }
});

export {
    StaticPageable,
    DynamicPageable
    };