Paginator.js 6.72 KB
define(function(require) {
    'use strict';
    var _ = require('underscore');
    var Backbone = require('backbone');
    var Util = require('./Util');

    var Paginator = Backbone.Model.extend({
        defaults: function defaults() {
            return {
                hasNext: false,
                hasNextJump: undefined,
                hasPrevious: false,
                hasPreviousJump: undefined,
                leadingPageCount: 4,
                nextJumpPage: undefined,
                nextPage: undefined,
                pages: [],
                pageJump: 5,
                previousJumpPage: undefined,
                previousPage: undefined,
                totalPages: 0,
                trailingPageCount: 5,
            };
        },
        initialize: function(data, options) {
            var buildPages = _.bind(function buildPages() {
                var source = this.get('source');
                if (!source) {
                    return;
                }
                var currentPage = parseInt(source.get('currentPage'));
                var pageSize = parseInt(source.get('pageSize'));
                var totalCount = parseInt(source.get('totalCount'));
                if (!totalCount) {
                    return;
                }
                var pages = [];
                var totalPages = Math.floor((totalCount + pageSize - 1) / pageSize);
                if (currentPage < 0) {
                    source.set('currentPage', 1);
                    return;
                } else if (currentPage > totalPages) {
                    source.set('currentPage', totalPages);
                    return;
                }
                function addPage(self, i) {
                    pages.push({
                        current: i === currentPage,
                        jump: _.bind(function() {
                            this.get('source').set('currentPage', i);
                            return true;
                        }, self),
                        number: i,
                    });
                }
                var startAt = currentPage - this.get('leadingPageCount'), endAt = currentPage + this.get('trailingPageCount');
                if (startAt < 1) {
                    endAt += (1 - startAt);
                }
                if (endAt > totalPages) {
                    startAt -= endAt - totalPages - 1;
                    endAt = totalPages + 1;
                }
                if (startAt < 1) {
                    startAt = 1;
                }

                for (var i = startAt; i < endAt; i++) {
                    addPage(this, i);
                }
                var hasPrevious = currentPage > 1;
                var hasNext = currentPage < totalPages;
                var pageJump = this.get('pageJump');
                var nextJumpPage, previousJumpPage, hasNextJump, hasPreviousJump;
                if (pageJump) {
                    nextJumpPage = currentPage + pageJump;
                    previousJumpPage = currentPage - pageJump;
                    hasNextJump = nextJumpPage < totalPages;
                    hasPreviousJump = previousJumpPage > 0;
                } else {
                    hasNextJump = false;
                    hasPreviousJump = false;
                }
                this.set({
                    hasNext: hasNext,
                    hasNextJump: hasNextJump,
                    hasPrevious: hasPrevious,
                    hasPreviousJump: hasPreviousJump,
                    nextJumpPage: hasNextJump ? nextJumpPage : undefined,
                    nextPage: hasNext ? currentPage + 1 : undefined,
                    pages: pages,
                    previousJumpPage: hasNextJump ? previousJumpPage : undefined,
                    previousPage: hasPrevious ? currentPage - 1 : undefined,
                    totalPages: totalPages,
                });
            }, this);
            this.on('change:leadingPageCount change:trailingPageCount', buildPages);
            var installActions = _.bind(function installActions(eventName, nextName, actNextName, hasNextName, previousName, actPreviousName, hasPreviousName, pageCount) {
                this.on(eventName, function() {
                    var hasNext = this.get(hasNextName);
                    var hasPrevious = this.get(hasPreviousName);
                    var next, previous;
                    if (hasNext) {
                        next = _.bind(function(e) {
                            Util.preventDefault(e);
                            var source = this.get('source');
                            source.set('currentPage', source.get('currentPage') + pageCount);
                            return false;
                        }, this);
                    } else {
                        next = Util.eventFalse;
                    }
                    if (hasPrevious) {
                        previous = _.bind(function(e) {
                            Util.preventDefault(e);
                            var source = this.get('source');
                            source.set('currentPage', source.get('currentPage') - pageCount);
                            return false;
                        }, this);
                    } else {
                        previous = Util.eventFalse;
                    }
                    this.set(nextName, next);
                    this.set(previousName, previous);
                }, this);
                this[actNextName] = _.bind(function() {
                    return this.get(nextName)();
                }, this);
                this[actPreviousName] = _.bind(function() {
                    return this.get(previousName)();
                }, this);
                this.trigger(eventName.split(' ')[0]);
            }, this);
            this.on('change:pageJump', function() {
                var pageJump = this.get('pageJump');
                installActions('change:hasNextJump change:hasPreviousJump', 'nextJump', 'actNextJump', 'hasNextJump', 'previousJump', 'actPreviousJump', 'hasPreviousJump', pageJump);
            }, this);
            installActions('change:hasNext change:hasPrevious', 'next', 'actNext', 'hasNext', 'previous', 'actPrevious', 'hasPrevious', 1);
            this.on('change:source', function() {
                var oldSource = this.previous('source');
                if (oldSource) {
                    this.stopListening(oldSource);
                }
                this.listenTo(this.get('source'), 'change:pageSize change:currentPage change:totalCount', buildPages);
            });
            var r = Paginator.__super__.initialize.apply(this, arguments);
            buildPages();
            this.trigger('change:pageJump');
            this.trigger('change:source');
            return r;
        }
    });
    return Paginator;
});