From c1e4bb76c214b95d098fe5533947b2a8bba04192 Mon Sep 17 00:00:00 2001 From: Wesley Cho Date: Fri, 27 Nov 2015 04:10:28 -0800 Subject: [PATCH] feat(paging): factor out common controller code - Create paging factory for creating common controller for the pagination and pager components --- src/pager/pager.js | 15 +- src/pagination/pagination.js | 266 +++++++++++++---------------------- src/paging/paging.js | 85 +++++++++++ 3 files changed, 191 insertions(+), 175 deletions(-) create mode 100644 src/paging/paging.js diff --git a/src/pager/pager.js b/src/pager/pager.js index 3fdccb4d1d..5d871e1ddd 100644 --- a/src/pager/pager.js +++ b/src/pager/pager.js @@ -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, @@ -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: '=', @@ -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'; @@ -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); } }; }]); diff --git a/src/pagination/pagination.js b/src/pagination/pagination.js index d483c9a564..c67e370429 100644 --- a/src/pagination/pagination.js +++ b/src/pagination/pagination.js @@ -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', { @@ -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: '@', @@ -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); } }; }]); diff --git a/src/paging/paging.js b/src/paging/paging.js new file mode 100644 index 0000000000..d8ae9574ad --- /dev/null +++ b/src/paging/paging.js @@ -0,0 +1,85 @@ +angular.module('ui.bootstrap.paging', []) +/** + * Helper internal service for generating common controller code between the + * pager and pagination components + */ +.factory('uibPaging', ['$parse', function($parse) { + return { + create: function(ctrl, $scope, $attrs) { + var ngModelCtrl = { $setViewValue: angular.noop }, // nullModelCtrl + setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; + + ctrl.init = function(ngModelCtrl_, config) { + ngModelCtrl = ngModelCtrl_; + ctrl.config = config; + + ngModelCtrl.$render = function() { + ctrl.render(); + }; + + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { + ctrl.itemsPerPage = parseInt(value, 10); + $scope.totalPages = ctrl.calculateTotalPages(); + updatePage(); + }); + } else { + ctrl.itemsPerPage = config.itemsPerPage; + } + + $scope.$watch('totalItems', function(newTotal, oldTotal) { + if (angular.isDefined(newTotal) || newTotal !== oldTotal) { + $scope.totalPages = ctrl.calculateTotalPages(); + updatePage(); + } + }); + }; + + ctrl.calculateTotalPages = function() { + var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage); + return Math.max(totalPages || 0, 1); + }; + + ctrl.render = function() { + $scope.page = parseInt(ngModelCtrl.$viewValue, 10) || 1; + }; + + $scope.selectPage = function(page, evt) { + if (evt) { + evt.preventDefault(); + } + + var clickAllowed = !$scope.ngDisabled || !evt; + if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) { + if (evt && evt.target) { + evt.target.blur(); + } + ngModelCtrl.$setViewValue(page); + ngModelCtrl.$render(); + } + }; + + $scope.getText = function(key) { + return $scope[key + 'Text'] || ctrl.config[key + 'Text']; + }; + + $scope.noPrevious = function() { + return $scope.page === 1; + }; + + $scope.noNext = function() { + return $scope.page === $scope.totalPages; + }; + + function updatePage() { + setNumPages($scope.$parent, $scope.totalPages); // Readonly variable + + if ($scope.page > $scope.totalPages) { + $scope.selectPage($scope.totalPages); + } else { + ngModelCtrl.$render(); + } + } + } + }; +}]);