Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(paging): factor out common controller code
Browse files Browse the repository at this point in the history
- Create paging factory for creating common controller for the
  pagination and pager components
  • Loading branch information
wesleycho committed Nov 27, 2015
1 parent 8bfeda0 commit 46d4c45
Show file tree
Hide file tree
Showing 4 changed files with 447 additions and 175 deletions.
15 changes: 10 additions & 5 deletions src/pager/pager.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
angular.module('ui.bootstrap.pager', ['ui.bootstrap.pagination'])
angular.module('ui.bootstrap.pager', ['ui.bootstrap.paging'])

.controller('UibPagerController', ['$scope', '$attrs', 'uibPaging', 'uibPagerConfig', function($scope, $attrs, uibPaging, uibPagerConfig) {
$scope.align = angular.isDefined($attrs.align) ? $scope.$parent.$eval($attrs.align) : uibPagerConfig.align;

uibPaging.create(this, $scope, $attrs);
}])

.constant('uibPagerConfig', {
itemsPerPage: 10,
Expand All @@ -7,7 +13,7 @@ angular.module('ui.bootstrap.pager', ['ui.bootstrap.pagination'])
align: true
})

.directive('uibPager', ['uibPagerConfig', function(pagerConfig) {
.directive('uibPager', ['uibPagerConfig', function(uibPagerConfig) {
return {
scope: {
totalItems: '=',
Expand All @@ -16,7 +22,7 @@ angular.module('ui.bootstrap.pager', ['ui.bootstrap.pagination'])
ngDisabled: '='
},
require: ['uibPager', '?ngModel'],
controller: 'UibPaginationController',
controller: 'UibPagerController',
controllerAs: 'pager',
templateUrl: function(element, attrs) {
return attrs.templateUrl || 'uib/template/pager/pager.html';
Expand All @@ -29,8 +35,7 @@ angular.module('ui.bootstrap.pager', ['ui.bootstrap.pagination'])
return; // do nothing if no ng-model
}

scope.align = angular.isDefined(attrs.align) ? scope.$parent.$eval(attrs.align) : pagerConfig.align;
paginationCtrl.init(ngModelCtrl, pagerConfig);
paginationCtrl.init(ngModelCtrl, uibPagerConfig);
}
};
}]);
266 changes: 96 additions & 170 deletions src/pagination/pagination.js
Original file line number Diff line number Diff line change
@@ -1,80 +1,110 @@
angular.module('ui.bootstrap.pagination', [])
.controller('UibPaginationController', ['$scope', '$attrs', '$parse', function($scope, $attrs, $parse) {
var self = this,
ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl
setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;

this.init = function(ngModelCtrl_, config) {
ngModelCtrl = ngModelCtrl_;
this.config = config;

ngModelCtrl.$render = function() {
self.render();
angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging'])
.controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) {
var ctrl = this;
// Setup configuration parameters
var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize,
rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate,
forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses,
boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers;
$scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks;
$scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks;

uibPaging.create(this, $scope, $attrs);

if ($attrs.maxSize) {
$scope.$parent.$watch($parse($attrs.maxSize), function(value) {
maxSize = parseInt(value, 10);
ctrl.render();
});
}

// Create page object used in template
function makePage(number, text, isActive) {
return {
number: number,
text: text,
active: isActive
};
}

if ($attrs.itemsPerPage) {
$scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) {
self.itemsPerPage = parseInt(value, 10);
$scope.totalPages = self.calculateTotalPages();
updatePage();
});
} else {
this.itemsPerPage = config.itemsPerPage;
}
function getPages(currentPage, totalPages) {
var pages = [];

$scope.$watch('totalItems', function(newTotal, oldTotal) {
if (angular.isDefined(newTotal) || newTotal !== oldTotal) {
$scope.totalPages = self.calculateTotalPages();
updatePage();
}
});
};

this.calculateTotalPages = function() {
var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
return Math.max(totalPages || 0, 1);
};
// Default page limits
var startPage = 1, endPage = totalPages;
var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;

this.render = function() {
$scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1;
};
// recompute if maxSize
if (isMaxSized) {
if (rotate) {
// Current page is displayed in the middle of the visible ones
startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
endPage = startPage + maxSize - 1;

$scope.selectPage = function(page, evt) {
if (evt) {
evt.preventDefault();
}
// Adjust if limit is exceeded
if (endPage > totalPages) {
endPage = totalPages;
startPage = endPage - maxSize + 1;
}
} else {
// Visible pages are paginated with maxSize
startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;

var clickAllowed = !$scope.ngDisabled || !evt;
if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) {
if (evt && evt.target) {
evt.target.blur();
// Adjust last page if limit is exceeded
endPage = Math.min(startPage + maxSize - 1, totalPages);
}
ngModelCtrl.$setViewValue(page);
ngModelCtrl.$render();
}
};

$scope.getText = function(key) {
return $scope[key + 'Text'] || self.config[key + 'Text'];
};

$scope.noPrevious = function() {
return $scope.page === 1;
};

$scope.noNext = function() {
return $scope.page === $scope.totalPages;
};
// Add page number links
for (var number = startPage; number <= endPage; number++) {
var page = makePage(number, number, number === currentPage);
pages.push(page);
}

function updatePage() {
setNumPages($scope.$parent, $scope.totalPages); // Readonly variable
// Add links to move between page sets
if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
if (startPage > 1) {
if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
var previousPageSet = makePage(startPage - 1, '...', false);
pages.unshift(previousPageSet);
}
if (boundaryLinkNumbers) {
if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
var secondPageLink = makePage(2, '2', false);
pages.unshift(secondPageLink);
}
//add the first page
var firstPageLink = makePage(1, '1', false);
pages.unshift(firstPageLink);
}
}

if ($scope.page > $scope.totalPages) {
$scope.selectPage($scope.totalPages);
} else {
ngModelCtrl.$render();
if (endPage < totalPages) {
if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
var nextPageSet = makePage(endPage + 1, '...', false);
pages.push(nextPageSet);
}
if (boundaryLinkNumbers) {
if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
pages.push(secondToLastPageLink);
}
//add the last page
var lastPageLink = makePage(totalPages, totalPages, false);
pages.push(lastPageLink);
}
}
}
return pages;
}

var originalRender = this.render;
this.render = function() {
originalRender();
if ($scope.page > 0 && $scope.page <= $scope.totalPages) {
$scope.pages = getPages($scope.page, $scope.totalPages);
}
};
}])

.constant('uibPaginationConfig', {
Expand All @@ -90,9 +120,8 @@ angular.module('ui.bootstrap.pagination', [])
forceEllipses: false
})

.directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, paginationConfig) {
.directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) {
return {
restrict: 'EA',
scope: {
totalItems: '=',
firstText: '@',
Expand All @@ -115,110 +144,7 @@ angular.module('ui.bootstrap.pagination', [])
return; // do nothing if no ng-model
}

// Setup configuration parameters
var maxSize = angular.isDefined(attrs.maxSize) ? scope.$parent.$eval(attrs.maxSize) : paginationConfig.maxSize,
rotate = angular.isDefined(attrs.rotate) ? scope.$parent.$eval(attrs.rotate) : paginationConfig.rotate,
forceEllipses = angular.isDefined(attrs.forceEllipses) ? scope.$parent.$eval(attrs.forceEllipses) : paginationConfig.forceEllipses,
boundaryLinkNumbers = angular.isDefined(attrs.boundaryLinkNumbers) ? scope.$parent.$eval(attrs.boundaryLinkNumbers) : paginationConfig.boundaryLinkNumbers;
scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : paginationConfig.boundaryLinks;
scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : paginationConfig.directionLinks;

paginationCtrl.init(ngModelCtrl, paginationConfig);

if (attrs.maxSize) {
scope.$parent.$watch($parse(attrs.maxSize), function(value) {
maxSize = parseInt(value, 10);
paginationCtrl.render();
});
}

// Create page object used in template
function makePage(number, text, isActive) {
return {
number: number,
text: text,
active: isActive
};
}

function getPages(currentPage, totalPages) {
var pages = [];

// Default page limits
var startPage = 1, endPage = totalPages;
var isMaxSized = angular.isDefined(maxSize) && maxSize < totalPages;

// recompute if maxSize
if (isMaxSized) {
if (rotate) {
// Current page is displayed in the middle of the visible ones
startPage = Math.max(currentPage - Math.floor(maxSize / 2), 1);
endPage = startPage + maxSize - 1;

// Adjust if limit is exceeded
if (endPage > totalPages) {
endPage = totalPages;
startPage = endPage - maxSize + 1;
}
} else {
// Visible pages are paginated with maxSize
startPage = (Math.ceil(currentPage / maxSize) - 1) * maxSize + 1;

// Adjust last page if limit is exceeded
endPage = Math.min(startPage + maxSize - 1, totalPages);
}
}

// Add page number links
for (var number = startPage; number <= endPage; number++) {
var page = makePage(number, number, number === currentPage);
pages.push(page);
}

// Add links to move between page sets
if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) {
if (startPage > 1) {
if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning
var previousPageSet = makePage(startPage - 1, '...', false);
pages.unshift(previousPageSet);
}
if (boundaryLinkNumbers) {
if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential
var secondPageLink = makePage(2, '2', false);
pages.unshift(secondPageLink);
}
//add the first page
var firstPageLink = makePage(1, '1', false);
pages.unshift(firstPageLink);
}
}

if (endPage < totalPages) {
if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end
var nextPageSet = makePage(endPage + 1, '...', false);
pages.push(nextPageSet);
}
if (boundaryLinkNumbers) {
if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential
var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false);
pages.push(secondToLastPageLink);
}
//add the last page
var lastPageLink = makePage(totalPages, totalPages, false);
pages.push(lastPageLink);
}
}
}
return pages;
}

var originalRender = paginationCtrl.render;
paginationCtrl.render = function() {
originalRender();
if (scope.page > 0 && scope.page <= scope.totalPages) {
scope.pages = getPages(scope.page, scope.totalPages);
}
};
paginationCtrl.init(ngModelCtrl, uibPaginationConfig);
}
};
}]);
Loading

0 comments on commit 46d4c45

Please sign in to comment.