From e55d90638117dd3c5c1ac37ba15af95f9fa567bb Mon Sep 17 00:00:00 2001 From: Tasos Bekos Date: Sat, 24 Aug 2013 01:45:05 +0300 Subject: [PATCH] feat(pagination): `total-items` & optional `items-per-page` API Closes #820. BREAKING CHANGE: API has undergone some changes in order to be easier to use. * `current-page` is replaced from `page`. * Number of pages is not defined by `num-pages`, but from `total-items` & `items-per-page` instead. If `items-per-page` is missing, default is 10. * `num-pages` still exists but is just readonly. Before: After: --- src/pagination/docs/demo.html | 18 +- src/pagination/docs/demo.js | 4 +- src/pagination/docs/readme.md | 18 +- src/pagination/pagination.js | 172 +++-- src/pagination/test/pager.spec.js | 257 +++---- src/pagination/test/pagination.spec.js | 889 +++++++++++-------------- 6 files changed, 670 insertions(+), 688 deletions(-) diff --git a/src/pagination/docs/demo.html b/src/pagination/docs/demo.html index e37e615cfa..16ff34371f 100644 --- a/src/pagination/docs/demo.html +++ b/src/pagination/docs/demo.html @@ -1,20 +1,22 @@

Default

- - - - + + + + The selected page no: {{currentPage}}

Pager

- +
-

Limit the maximimum visible page-buttons

- - +

Limit the maximimum visible buttons

+ + + +
Page: {{bigCurrentPage}} / {{numPages}}
diff --git a/src/pagination/docs/demo.js b/src/pagination/docs/demo.js index 7ae5ef6769..889e50e1e1 100644 --- a/src/pagination/docs/demo.js +++ b/src/pagination/docs/demo.js @@ -1,5 +1,5 @@ var PaginationDemoCtrl = function ($scope) { - $scope.noOfPages = 7; + $scope.totalItems = 64; $scope.currentPage = 4; $scope.maxSize = 5; @@ -7,6 +7,6 @@ var PaginationDemoCtrl = function ($scope) { $scope.currentPage = pageNo; }; - $scope.bigNoOfPages = 18; + $scope.bigTotalItems = 175; $scope.bigCurrentPage = 1; }; diff --git a/src/pagination/docs/readme.md b/src/pagination/docs/readme.md index 8394e5bb8d..f184895e51 100644 --- a/src/pagination/docs/readme.md +++ b/src/pagination/docs/readme.md @@ -5,18 +5,26 @@ A lightweight pagination directive that is focused on ... providing pagination & Settings can be provided as attributes in the `` or globally configured through the `paginationConfig`. - * `num-pages` + * `page` : - Number of total pages. + Current page number. First page is 1. - * `current-page` + * `total-items` : - Current page number. + Total number of items in all pages. + + * `items-per-page` + _(Defaults: 10)_ : + Maximum number of items per page. A value less than one indicates all items on one page. * `max-size` _(Defaults: null)_ : Limit number for pagination size. + * `num-pages` readonly + : + Total number of pages to display. + * `rotate` _(Defaults: true)_ : Whether to keep current page in the middle of the visible ones. @@ -52,7 +60,7 @@ Settings can be provided as attributes in the `` or globally configu ### Pager Settings ### Settings can be provided as attributes in the `` or globally configured through the `pagerConfig`. -For `num-pages`, `current-page` and `on-select-page (page)` see pagination settings. Other settings are: +For `page`, `total-items`, `items-per-page`, `num-pages` and `on-select-page (page)` see pagination settings. Other settings are: * `align` _(Default: true)_ : diff --git a/src/pagination/pagination.js b/src/pagination/pagination.js index f4becfcd2c..538a1b421e 100644 --- a/src/pagination/pagination.js +++ b/src/pagination/pagination.js @@ -1,43 +1,73 @@ angular.module('ui.bootstrap.pagination', []) -.controller('PaginationController', ['$scope', '$interpolate', function ($scope, $interpolate) { +.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) { + var self = this; - this.currentPage = 1; + this.init = function(defaultItemsPerPage) { + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { + self.itemsPerPage = parseInt(value, 10); + $scope.totalPages = self.calculateTotalPages(); + }); + } else { + this.itemsPerPage = defaultItemsPerPage; + } + }; this.noPrevious = function() { - return this.currentPage === 1; + return this.page === 1; }; this.noNext = function() { - return this.currentPage === $scope.numPages; + return this.page === $scope.totalPages; }; this.isActive = function(page) { - return this.currentPage === page; + return this.page === page; }; - this.reset = function() { - $scope.pages = []; - this.currentPage = parseInt($scope.currentPage, 10); + this.calculateTotalPages = function() { + return this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage); + }; - if ( this.currentPage > $scope.numPages ) { - $scope.selectPage($scope.numPages); - } + this.getAttributeValue = function(attribute, defaultValue, interpolate) { + return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue; + }; + + this.render = function() { + this.page = parseInt($scope.page, 10) || 1; + $scope.pages = this.getPages(this.page, $scope.totalPages); }; - var self = this; $scope.selectPage = function(page) { - if ( ! self.isActive(page) && page > 0 && page <= $scope.numPages) { - $scope.currentPage = page; + if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) { + $scope.page = page; $scope.onSelectPage({ page: page }); } }; - this.getAttributeValue = function(attribute, defaultValue, interpolate) { - return angular.isDefined(attribute) ? (interpolate ? $interpolate(attribute)($scope.$parent) : $scope.$parent.$eval(attribute)) : defaultValue; - }; + $scope.$watch('totalItems', function() { + $scope.totalPages = self.calculateTotalPages(); + }); + + $scope.$watch('totalPages', function(value) { + if ( $attrs.numPages ) { + $scope.numPages = value; // Readonly variable + } + + if ( self.page > value ) { + $scope.selectPage(value); + } else { + self.render(); + } + }); + + $scope.$watch('page', function() { + self.render(); + }); }]) .constant('paginationConfig', { + itemsPerPage: 10, boundaryLinks: false, directionLinks: true, firstText: 'First', @@ -47,14 +77,14 @@ angular.module('ui.bootstrap.pagination', []) rotate: true }) -.directive('pagination', ['paginationConfig', function(config) { +.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) { return { restrict: 'EA', scope: { - numPages: '=', - currentPage: '=', - maxSize: '=', - onSelectPage: '&' + page: '=', + totalItems: '=', + onSelectPage:' &', + numPages: '=' }, controller: 'PaginationController', templateUrl: 'template/pagination/pagination.html', @@ -62,13 +92,23 @@ angular.module('ui.bootstrap.pagination', []) link: function(scope, element, attrs, paginationCtrl) { // Setup configuration parameters - var boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ), - directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ), - firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true), - previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), - nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), - lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true), - rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate); + var maxSize, + boundaryLinks = paginationCtrl.getAttributeValue(attrs.boundaryLinks, config.boundaryLinks ), + directionLinks = paginationCtrl.getAttributeValue(attrs.directionLinks, config.directionLinks ), + firstText = paginationCtrl.getAttributeValue(attrs.firstText, config.firstText, true), + previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true), + nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), + lastText = paginationCtrl.getAttributeValue(attrs.lastText, config.lastText, true), + rotate = paginationCtrl.getAttributeValue(attrs.rotate, config.rotate); + + paginationCtrl.init(config.itemsPerPage); + + 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, isDisabled) { @@ -80,76 +120,79 @@ angular.module('ui.bootstrap.pagination', []) }; } - scope.$watch('numPages + currentPage + maxSize', function() { - paginationCtrl.reset(); + paginationCtrl.getPages = function(currentPage, totalPages) { + var pages = []; // Default page limits - var startPage = 1, endPage = scope.numPages; - var isMaxSized = ( angular.isDefined(scope.maxSize) && scope.maxSize < scope.numPages ); + 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(paginationCtrl.currentPage - Math.floor(scope.maxSize/2), 1); - endPage = startPage + scope.maxSize - 1; + startPage = Math.max(currentPage - Math.floor(maxSize/2), 1); + endPage = startPage + maxSize - 1; // Adjust if limit is exceeded - if (endPage > scope.numPages) { - endPage = scope.numPages; - startPage = endPage - scope.maxSize + 1; + if (endPage > totalPages) { + endPage = totalPages; + startPage = endPage - maxSize + 1; } } else { // Visible pages are paginated with maxSize - startPage = ((Math.ceil(paginationCtrl.currentPage / scope.maxSize) - 1) * scope.maxSize) + 1; + startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1; // Adjust last page if limit is exceeded - endPage = Math.min(startPage + scope.maxSize - 1, scope.numPages); + endPage = Math.min(startPage + maxSize - 1, totalPages); } } // Add page number links for (var number = startPage; number <= endPage; number++) { var page = makePage(number, number, paginationCtrl.isActive(number), false); - scope.pages.push(page); + pages.push(page); } // Add links to move between page sets if ( isMaxSized && ! rotate ) { if ( startPage > 1 ) { var previousPageSet = makePage(startPage - 1, '...', false, false); - scope.pages.unshift(previousPageSet); + pages.unshift(previousPageSet); } - if ( endPage < scope.numPages ) { + if ( endPage < totalPages ) { var nextPageSet = makePage(endPage + 1, '...', false, false); - scope.pages.push(nextPageSet); + pages.push(nextPageSet); } } // Add previous & next links if (directionLinks) { - var previousPage = makePage(paginationCtrl.currentPage - 1, previousText, false, paginationCtrl.noPrevious()); - scope.pages.unshift(previousPage); + var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious()); + pages.unshift(previousPage); - var nextPage = makePage(paginationCtrl.currentPage + 1, nextText, false, paginationCtrl.noNext()); - scope.pages.push(nextPage); + var nextPage = makePage(currentPage + 1, nextText, false, paginationCtrl.noNext()); + pages.push(nextPage); } // Add first & last links if (boundaryLinks) { var firstPage = makePage(1, firstText, false, paginationCtrl.noPrevious()); - scope.pages.unshift(firstPage); + pages.unshift(firstPage); - var lastPage = makePage(scope.numPages, lastText, false, paginationCtrl.noNext()); - scope.pages.push(lastPage); + var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext()); + pages.push(lastPage); } - }); + + return pages; + }; } }; }]) .constant('pagerConfig', { + itemsPerPage: 10, previousText: '« Previous', nextText: 'Next »', align: true @@ -159,9 +202,10 @@ angular.module('ui.bootstrap.pagination', []) return { restrict: 'EA', scope: { - numPages: '=', - currentPage: '=', - onSelectPage: '&' + page: '=', + totalItems: '=', + onSelectPage:' &', + numPages: '=' }, controller: 'PaginationController', templateUrl: 'template/pagination/pager.html', @@ -173,6 +217,8 @@ angular.module('ui.bootstrap.pagination', []) nextText = paginationCtrl.getAttributeValue(attrs.nextText, config.nextText, true), align = paginationCtrl.getAttributeValue(attrs.align, config.align); + paginationCtrl.init(config.itemsPerPage); + // Create page object used in template function makePage(number, text, isDisabled, isPrevious, isNext) { return { @@ -184,16 +230,12 @@ angular.module('ui.bootstrap.pagination', []) }; } - scope.$watch('numPages + currentPage', function() { - paginationCtrl.reset(); - - // Add previous & next links - var previousPage = makePage(paginationCtrl.currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false); - scope.pages.unshift(previousPage); - - var nextPage = makePage(paginationCtrl.currentPage + 1, nextText, paginationCtrl.noNext(), false, true); - scope.pages.push(nextPage); - }); + paginationCtrl.getPages = function(currentPage) { + return [ + makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false), + makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true) + ]; + }; } }; }]); diff --git a/src/pagination/test/pager.spec.js b/src/pagination/test/pager.spec.js index 91874d6e8c..d03dc12564 100644 --- a/src/pagination/test/pager.spec.js +++ b/src/pagination/test/pager.spec.js @@ -1,193 +1,202 @@ -describe('pager directive with default configuration', function () { - var $rootScope, element; +describe('pager directive', function () { + var $compile, $rootScope, element; beforeEach(module('ui.bootstrap.pagination')); beforeEach(module('template/pagination/pager.html')); beforeEach(inject(function(_$compile_, _$rootScope_) { $compile = _$compile_; $rootScope = _$rootScope_; - $rootScope.numPages = 5; + $rootScope.total = 47; // 5 pages $rootScope.currentPage = 3; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$digest(); })); + function getPaginationBarSize() { + return element.find('li').length; + } + + function getPaginationEl(index) { + return element.find('li').eq(index); + } + + function clickPaginationEl(index) { + getPaginationEl(index).find('a').click(); + } + + function updateCurrentPage(value) { + $rootScope.currentPage = value; + $rootScope.$digest(); + } + it('has a "pager" css class', function() { expect(element.hasClass('pager')).toBe(true); }); it('contains 2 li elements', function() { - expect(element.find('li').length).toBe(2); - expect(element.find('li').eq(0).text()).toBe('« Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next »'); + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0).text()).toBe('« Previous'); + expect(getPaginationEl(-1).text()).toBe('Next »'); }); it('aligns previous & next page', function() { - expect(element.find('li').eq(0).hasClass('previous')).toBe(true); - expect(element.find('li').eq(0).hasClass('next')).toBe(false); + expect(getPaginationEl(0)).toHaveClass('previous'); + expect(getPaginationEl(0)).not.toHaveClass('next'); - expect(element.find('li').eq(-1).hasClass('previous')).toBe(false); - expect(element.find('li').eq(-1).hasClass('next')).toBe(true); + expect(getPaginationEl(-1)).not.toHaveClass('previous'); + expect(getPaginationEl(-1)).toHaveClass('next'); }); - it('disables the "previous" link if current-page is 1', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - expect(element.find('li').eq(0).hasClass('disabled')).toBe(true); + it('disables the "previous" link if current page is 1', function() { + updateCurrentPage(1); + expect(getPaginationEl(0)).toHaveClass('disabled'); }); - it('disables the "next" link if current-page is num-pages', function() { - $rootScope.currentPage = 5; - $rootScope.$digest(); - expect(element.find('li').eq(-1).hasClass('disabled')).toBe(true); + it('disables the "next" link if current page is num-pages', function() { + updateCurrentPage(5); + expect(getPaginationEl(-1)).toHaveClass('disabled'); }); it('changes currentPage if the "previous" link is clicked', function() { - var previous = element.find('li').eq(0).find('a').eq(0); - previous.click(); - $rootScope.$digest(); + clickPaginationEl(0); expect($rootScope.currentPage).toBe(2); }); it('changes currentPage if the "next" link is clicked', function() { - var next = element.find('li').eq(-1).find('a').eq(0); - next.click(); - $rootScope.$digest(); + clickPaginationEl(-1); expect($rootScope.currentPage).toBe(4); }); it('does not change the current page on "previous" click if already at first page', function() { - var previous = element.find('li').eq(0).find('a').eq(0); - $rootScope.currentPage = 1; - $rootScope.$digest(); - previous.click(); - $rootScope.$digest(); + updateCurrentPage(1); + clickPaginationEl(0); expect($rootScope.currentPage).toBe(1); }); it('does not change the current page on "next" click if already at last page', function() { - var next = element.find('li').eq(-1).find('a').eq(0); - $rootScope.currentPage = 5; - $rootScope.$digest(); - next.click(); - $rootScope.$digest(); + updateCurrentPage(5); + clickPaginationEl(-1); expect($rootScope.currentPage).toBe(5); }); - it('executes the onSelectPage expression when the current page changes', function() { + it('executes the `on-select-page` expression when an element is clicked', function() { $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - var next = element.find('li').eq(-1).find('a').eq(0); - next.click(); + element = $compile('')($rootScope); $rootScope.$digest(); + + clickPaginationEl(-1); expect($rootScope.selectPageHandler).toHaveBeenCalledWith(4); }); - it('does not changes the number of items when numPages changes', function() { - $rootScope.numPages = 8; + it('does not changes the number of pages when `total-items` changes', function() { + $rootScope.total = 73; // 8 pages $rootScope.$digest(); - expect(element.find('li').length).toBe(2); - expect(element.find('li').eq(0).text()).toBe('« Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next »'); - }); - it('sets the current page to the last page if the numPages is changed to less than the current page', function() { - $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - $rootScope.numPages = 2; - $rootScope.$digest(); - expect(element.find('li').length).toBe(2); - expect($rootScope.currentPage).toBe(2); - expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0).text()).toBe('« Previous'); + expect(getPaginationEl(-1).text()).toBe('Next »'); }); - describe('when `current-page` is not a number', function () { - it('handles string', function() { - $rootScope.currentPage = '1'; + describe('`items-per-page`', function () { + beforeEach(inject(function() { + $rootScope.perpage = 5; + element = $compile('')($rootScope); $rootScope.$digest(); - expect(element.find('li').eq(0).hasClass('disabled')).toBe(true); + })); - $rootScope.currentPage = '05'; + it('does not change the number of pages', function() { + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0).text()).toBe('« Previous'); + expect(getPaginationEl(-1).text()).toBe('Next »'); + }); + + it('selects the last page when it is too big', function() { + $rootScope.perpage = 30; $rootScope.$digest(); - expect(element.find('li').eq(-1).hasClass('disabled')).toBe(true); + + expect($rootScope.currentPage).toBe(2); + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0)).not.toHaveClass('disabled'); + expect(getPaginationEl(1)).toHaveClass('disabled'); }); }); -}); -describe('setting pagerConfig', function() { - var $rootScope, element; - var originalConfig = {}; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pager.html')); - beforeEach(inject(function(_$compile_, _$rootScope_, pagerConfig) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - angular.extend(originalConfig, pagerConfig); - pagerConfig.previousText = 'PR'; - pagerConfig.nextText = 'NE'; - pagerConfig.align = false; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - afterEach(inject(function(pagerConfig) { - // return it to the original state - angular.extend(pagerConfig, originalConfig); - })); + describe('when `page` is not a number', function () { + it('handles string', function() { + updateCurrentPage('1'); + expect(getPaginationEl(0)).toHaveClass('disabled'); - it('contains 2 li elements', function() { - expect(element.find('li').length).toBe(2); + updateCurrentPage('05'); + expect(getPaginationEl(-1)).toHaveClass('disabled'); + }); }); - it('should change paging text', function () { - expect(element.find('li').eq(0).text()).toBe('PR'); - expect(element.find('li').eq(-1).text()).toBe('NE'); - }); + describe('`num-pages`', function () { + beforeEach(inject(function() { + $rootScope.numpg = null; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('should not align previous & next page link', function () { - expect(element.find('li').eq(0).hasClass('previous')).toBe(false); - expect(element.find('li').eq(-1).hasClass('next')).toBe(false); + it('equals to total number of pages', function() { + expect($rootScope.numpg).toBe(5); + }); }); -}); - -describe('pager bypass configuration from attributes', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pager.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + describe('setting `pagerConfig`', function() { + var originalConfig = {}; + beforeEach(inject(function(pagerConfig) { + angular.extend(originalConfig, pagerConfig); + pagerConfig.previousText = 'PR'; + pagerConfig.nextText = 'NE'; + pagerConfig.align = false; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + afterEach(inject(function(pagerConfig) { + // return it to the original state + angular.extend(pagerConfig, originalConfig); + })); + + it('should change paging text', function () { + expect(getPaginationEl(0).text()).toBe('PR'); + expect(getPaginationEl(-1).text()).toBe('NE'); + }); - it('contains 2 li elements', function() { - expect(element.find('li').length).toBe(2); + it('should not align previous & next page link', function () { + expect(getPaginationEl(0)).not.toHaveClass('previous'); + expect(getPaginationEl(-1)).not.toHaveClass('next'); + }); }); - it('should change paging text from attributes', function () { - expect(element.find('li').eq(0).text()).toBe('<'); - expect(element.find('li').eq(-1).text()).toBe('>'); - }); + describe('override configuration from attributes', function () { + beforeEach(inject(function() { + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('should not align previous & next page link', function () { - expect(element.find('li').eq(0).hasClass('previous')).toBe(false); - expect(element.find('li').eq(-1).hasClass('next')).toBe(false); - }); + it('contains 2 li elements', function() { + expect(getPaginationBarSize()).toBe(2); + }); - it('changes "previous" & "next" text from interpolated attributes', function() { - $rootScope.previousText = '<<'; - $rootScope.nextText = '>>'; - element = $compile('')($rootScope); - $rootScope.$digest(); + it('should change paging text from attributes', function () { + expect(getPaginationEl(0).text()).toBe('<'); + expect(getPaginationEl(-1).text()).toBe('>'); + }); + + it('should not align previous & next page link', function () { + expect(getPaginationEl(0)).not.toHaveClass('previous'); + expect(getPaginationEl(-1)).not.toHaveClass('next'); + }); - expect(element.find('li').eq(0).text()).toBe('<<'); - expect(element.find('li').eq(-1).text()).toBe('>>'); + it('changes "previous" & "next" text from interpolated attributes', function() { + $rootScope.previousText = '<<'; + $rootScope.nextText = '>>'; + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect(getPaginationEl(0).text()).toBe('<<'); + expect(getPaginationEl(-1).text()).toBe('>>'); + }); }); -}); \ No newline at end of file +}); diff --git a/src/pagination/test/pagination.spec.js b/src/pagination/test/pagination.spec.js index 764cf2f5ac..e67218874e 100644 --- a/src/pagination/test/pagination.spec.js +++ b/src/pagination/test/pagination.spec.js @@ -1,613 +1,534 @@ -describe('pagination directive with default configuration', function () { - var $rootScope, element; +describe('pagination directive', function () { + var $compile, $rootScope, element; beforeEach(module('ui.bootstrap.pagination')); beforeEach(module('template/pagination/pagination.html')); beforeEach(inject(function(_$compile_, _$rootScope_) { $compile = _$compile_; $rootScope = _$rootScope_; - $rootScope.numPages = 5; + $rootScope.total = 47; // 5 pages $rootScope.currentPage = 3; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$digest(); })); + function getPaginationBarSize() { + return element.find('li').length; + } + + function getPaginationEl(index) { + return element.find('li').eq(index); + } + + function clickPaginationEl(index) { + getPaginationEl(index).find('a').click(); + } + + function updateCurrentPage(value) { + $rootScope.currentPage = value; + $rootScope.$digest(); + } + it('has a "pagination" css class', function() { expect(element.hasClass('pagination')).toBe(true); }); it('contains one ul and num-pages + 2 li elements', function() { expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(7); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next'); + expect(getPaginationBarSize()).toBe(7); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); }); it('has the number of the page as text in each page item', function() { - var lis = element.find('li'); - for(var i=1; i<=$rootScope.numPages;i++) { - expect(lis.eq(i).text()).toEqual(''+i); + for (var i = 1; i <= 5; i++) { + expect(getPaginationEl(i).text()).toEqual(''+i); } }); - it('sets the current-page to be active', function() { - var currentPageItem = element.find('li').eq($rootScope.currentPage); - expect(currentPageItem.hasClass('active')).toBe(true); + it('sets the current page to be active', function() { + expect(getPaginationEl($rootScope.currentPage).hasClass('active')).toBe(true); }); - it('disables the "previous" link if current-page is 1', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - var previousPageItem = element.find('li').eq(0); - expect(previousPageItem.hasClass('disabled')).toBe(true); + it('disables the "previous" link if current page is 1', function() { + updateCurrentPage(1); + expect(getPaginationEl(0).hasClass('disabled')).toBe(true); }); - it('disables the "next" link if current-page is num-pages', function() { - $rootScope.currentPage = 5; - $rootScope.$digest(); - var nextPageItem = element.find('li').eq(-1); - expect(nextPageItem.hasClass('disabled')).toBe(true); + it('disables the "next" link if current page is last', function() { + updateCurrentPage(5); + expect(getPaginationEl(-1).hasClass('disabled')).toBe(true); }); it('changes currentPage if a page link is clicked', function() { - var page2 = element.find('li').eq(2).find('a'); - page2.click(); - $rootScope.$digest(); + clickPaginationEl(2); expect($rootScope.currentPage).toBe(2); }); it('changes currentPage if the "previous" link is clicked', function() { - var previous = element.find('li').eq(0).find('a').eq(0); - previous.click(); - $rootScope.$digest(); + clickPaginationEl(0); expect($rootScope.currentPage).toBe(2); }); it('changes currentPage if the "next" link is clicked', function() { - var next = element.find('li').eq(-1).find('a').eq(0); - next.click(); - $rootScope.$digest(); + clickPaginationEl(-1); expect($rootScope.currentPage).toBe(4); }); it('does not change the current page on "previous" click if already at first page', function() { - var previous = element.find('li').eq(0).find('a').eq(0); - $rootScope.currentPage = 1; - $rootScope.$digest(); - previous.click(); - $rootScope.$digest(); + updateCurrentPage(1); + clickPaginationEl(0); expect($rootScope.currentPage).toBe(1); }); it('does not change the current page on "next" click if already at last page', function() { - var next = element.find('li').eq(-1).find('a').eq(0); - $rootScope.currentPage = 5; - $rootScope.$digest(); - next.click(); - $rootScope.$digest(); + updateCurrentPage(5); + clickPaginationEl(-1); expect($rootScope.currentPage).toBe(5); }); - it('executes the onSelectPage expression when the current page changes', function() { - $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); + it('changes the number of pages when `total-items` changes', function() { + $rootScope.total = 78; // 8 pages $rootScope.$digest(); - var page2 = element.find('li').eq(2).find('a').eq(0); - page2.click(); - $rootScope.$digest(); - expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); - }); - it('changes the number of items when numPages changes', function() { - $rootScope.numPages = 8; - $rootScope.$digest(); - expect(element.find('li').length).toBe(10); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next'); + expect(getPaginationBarSize()).toBe(10); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); }); - it('sets the current page to the last page if the numPages is changed to less than the current page', function() { - $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - $rootScope.numPages = 2; - $rootScope.$digest(); - expect(element.find('li').length).toBe(4); - expect($rootScope.currentPage).toBe(2); - expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); - }); + describe('`items-per-page`', function () { + beforeEach(inject(function() { + $rootScope.perpage = 5; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - describe('when `current-page` is not a number', function () { - it('handles string', function() { - $rootScope.currentPage = '2'; + it('changes the number of pages', function() { + expect(getPaginationBarSize()).toBe(12); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); + + it('changes the number of pages when changes', function() { + $rootScope.perpage = 20; $rootScope.$digest(); - expect(element.find('li').eq(2).hasClass('active')).toBe(true); - $rootScope.currentPage = '04'; + expect(getPaginationBarSize()).toBe(5); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); + + it('selects the last page when current page is too big', function() { + $rootScope.perpage = 30; $rootScope.$digest(); - expect(element.find('li').eq(4).hasClass('active')).toBe(true); + + expect($rootScope.currentPage).toBe(2); + expect(getPaginationBarSize()).toBe(4); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); }); - }); -}); -describe('pagination directive with max size option', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 10; - $rootScope.currentPage = 3; - $rootScope.maxSize = 5; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - - it('contains one ul and maxsize + 2 li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe($rootScope.maxSize + 2); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next'); - }); + it('displays a single page when it is negative', function() { + $rootScope.perpage = -1; + $rootScope.$digest(); - it('shows the page number even if it can\'t be shown in the middle', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - var currentPageItem = element.find('li').eq(1); - expect(currentPageItem.hasClass('active')).toBe(true); - - $rootScope.currentPage = 10; - $rootScope.$digest(); - currentPageItem = element.find('li').eq(-2); - expect(currentPageItem.hasClass('active')).toBe(true); - }); - - it('shows the page number in middle after the next link is clicked', function() { - $rootScope.currentPage = 6; - $rootScope.$digest(); - var next = element.find('li').eq(-1).find('a').eq(0); - next.click(); - expect($rootScope.currentPage).toBe(7); - var currentPageItem = element.find('li').eq(3); - expect(currentPageItem.hasClass('active')).toBe(true); - expect(parseInt(currentPageItem.text(), 10)).toBe($rootScope.currentPage); - }); - - it('shows the page number in middle after the prev link is clicked', function() { - $rootScope.currentPage = 7; - $rootScope.$digest(); - var prev = element.find('li').eq(0).find('a').eq(0); - prev.click(); - expect($rootScope.currentPage).toBe(6); - var currentPageItem = element.find('li').eq(3); - expect(currentPageItem.hasClass('active')).toBe(true); - expect(parseInt(currentPageItem.text(), 10)).toBe($rootScope.currentPage); + expect(getPaginationBarSize()).toBe(3); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(1).text()).toBe('1'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); }); - - it('changes pagination bar size when max-size value changed', function() { - $rootScope.maxSize = 7; - $rootScope.$digest(); - expect(element.find('li').length).toBe(9); - }); - it('sets the pagination bar size to num-pages, if max-size is greater than num-pages ', function() { - $rootScope.maxSize = 15; - $rootScope.$digest(); - expect(element.find('li').length).toBe(12); - }); + describe('executes `on-select-page` expression', function () { + beforeEach(inject(function() { + $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('should not change value of max-size expression, if max-size is greater than num-pages ', function() { - $rootScope.maxSize = 15; - $rootScope.$digest(); - expect($rootScope.maxSize).toBe(15); + it('when an element is clicked', function() { + clickPaginationEl(2); + expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); + }); }); - it('should not display page numbers, if max-size is zero', function() { - $rootScope.maxSize = 0; - $rootScope.$digest(); - expect(element.find('li').length).toBe(2); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next'); + describe('when `page` is not a number', function () { + it('handles string', function() { + updateCurrentPage('2'); + expect(getPaginationEl(2)).toHaveClass('active'); + + updateCurrentPage('04'); + expect(getPaginationEl(4)).toHaveClass('active'); + }); }); -}); + describe('with `max-size` option', function () { + beforeEach(inject(function() { + $rootScope.total = 98; // 10 pages + $rootScope.currentPage = 3; + $rootScope.maxSize = 5; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); -describe('pagination directive with max size option & no rotate', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 12; - $rootScope.currentPage = 7; - $rootScope.maxSize = 5; - $rootScope.rotate = false; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + it('contains maxsize + 2 li elements', function() { + expect(getPaginationBarSize()).toBe($rootScope.maxSize + 2); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); - it('contains one ul and maxsize + 4 elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe($rootScope.maxSize + 4); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(1).text()).toBe('...'); - expect(element.find('li').eq(2).text()).toBe('6'); - expect(element.find('li').eq(-3).text()).toBe('10'); - expect(element.find('li').eq(-2).text()).toBe('...'); - expect(element.find('li').eq(-1).text()).toBe('Next'); - }); + it('shows the page number even if it can\'t be shown in the middle', function() { + updateCurrentPage(1); + expect(getPaginationEl(1)).toHaveClass('active'); - it('shows only the next ellipsis element on first page set', function() { - $rootScope.currentPage = 3; - $rootScope.$digest(); - expect(element.find('li').eq(1).text()).toBe('1'); - expect(element.find('li').eq(-3).text()).toBe('5'); - expect(element.find('li').eq(-2).text()).toBe('...'); - }); + updateCurrentPage(10); + expect(getPaginationEl(-2)).toHaveClass('active'); + }); - it('shows only the previous ellipsis element on last page set', function() { - $rootScope.currentPage = 12; - $rootScope.$digest(); - expect(element.find('li').length).toBe(5); - expect(element.find('li').eq(1).text()).toBe('...'); - expect(element.find('li').eq(2).text()).toBe('11'); - expect(element.find('li').eq(-2).text()).toBe('12'); - }); + it('shows the page number in middle after the next link is clicked', function() { + updateCurrentPage(6); + clickPaginationEl(-1); - it('moves to the previous set when first ellipsis is clicked', function() { - var prev = element.find('li').eq(1).find('a').eq(0); - expect(prev.text()).toBe('...'); + expect($rootScope.currentPage).toBe(7); + expect(getPaginationEl(3)).toHaveClass('active'); + expect(getPaginationEl(3).text()).toBe(''+$rootScope.currentPage); + }); - prev.click(); - expect($rootScope.currentPage).toBe(5); - var currentPageItem = element.find('li').eq(-3); - expect(currentPageItem.hasClass('active')).toBe(true); - }); + it('shows the page number in middle after the prev link is clicked', function() { + updateCurrentPage(7); + clickPaginationEl(0); - it('moves to the next set when last ellipsis is clicked', function() { - var next = element.find('li').eq(-2).find('a').eq(0); - expect(next.text()).toBe('...'); + expect($rootScope.currentPage).toBe(6); + expect(getPaginationEl(3)).toHaveClass('active'); + expect(getPaginationEl(3).text()).toBe(''+$rootScope.currentPage); + }); - next.click(); - expect($rootScope.currentPage).toBe(11); - var currentPageItem = element.find('li').eq(2); - expect(currentPageItem.hasClass('active')).toBe(true); - }); + it('changes pagination bar size when max-size value changed', function() { + $rootScope.maxSize = 7; + $rootScope.$digest(); + expect(getPaginationBarSize()).toBe(9); + }); - it('should not display page numbers, if max-size is zero', function() { - $rootScope.maxSize = 0; - $rootScope.$digest(); - expect(element.find('li').length).toBe(2); - expect(element.find('li').eq(0).text()).toBe('Previous'); - expect(element.find('li').eq(-1).text()).toBe('Next'); - }); -}); + it('sets the pagination bar size to num-pages, if max-size is greater than num-pages ', function() { + $rootScope.maxSize = 15; + $rootScope.$digest(); + expect(getPaginationBarSize()).toBe(12); + }); -describe('pagination directive with added first & last links', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + it('should not change value of max-size expression, if max-size is greater than num-pages ', function() { + $rootScope.maxSize = 15; + $rootScope.$digest(); + expect($rootScope.maxSize).toBe(15); + }); - it('contains one ul and num-pages + 4 li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(9); - expect(element.find('li').eq(0).text()).toBe('First'); - expect(element.find('li').eq(1).text()).toBe('Previous'); - expect(element.find('li').eq(-2).text()).toBe('Next'); - expect(element.find('li').eq(-1).text()).toBe('Last'); + it('should not display page numbers, if max-size is zero', function() { + $rootScope.maxSize = 0; + $rootScope.$digest(); + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); }); - it('has first and last li visible & with borders', function() { - var firstLiEl = element.find('li').eq(0); - var lastLiEl = element.find('li').eq(-1); + describe('with `max-size` option & no `rotate`', function () { + beforeEach(inject(function() { + $rootScope.total = 115; // 12 pages + $rootScope.currentPage = 7; + $rootScope.maxSize = 5; + $rootScope.rotate = false; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + + it('contains one ul and maxsize + 4 elements', function() { + expect(element.find('ul').length).toBe(1); + expect(getPaginationBarSize()).toBe($rootScope.maxSize + 4); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(1).text()).toBe('...'); + expect(getPaginationEl(2).text()).toBe('6'); + expect(getPaginationEl(-3).text()).toBe('10'); + expect(getPaginationEl(-2).text()).toBe('...'); + expect(getPaginationEl(-1).text()).toBe('Next'); + }); - expect(firstLiEl.text()).toBe('First'); - expect(firstLiEl.css('display')).not.toBe('none'); - expect(lastLiEl.text()).toBe('Last'); - expect(lastLiEl.css('display')).not.toBe('none'); - }); + it('shows only the next ellipsis element on first page set', function() { + updateCurrentPage(3); + expect(getPaginationEl(1).text()).toBe('1'); + expect(getPaginationEl(-3).text()).toBe('5'); + expect(getPaginationEl(-2).text()).toBe('...'); + }); + it('shows only the previous ellipsis element on last page set', function() { + updateCurrentPage(12); + expect(getPaginationBarSize()).toBe(5); + expect(getPaginationEl(1).text()).toBe('...'); + expect(getPaginationEl(2).text()).toBe('11'); + expect(getPaginationEl(-2).text()).toBe('12'); + }); - it('disables the "first" & "previous" link if current-page is 1', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - expect(element.find('li').eq(0).hasClass('disabled')).toBe(true); - expect(element.find('li').eq(1).hasClass('disabled')).toBe(true); - }); + it('moves to the previous set when first ellipsis is clicked', function() { + expect(getPaginationEl(1).text()).toBe('...'); - it('disables the "last" & "next" link if current-page is num-pages', function() { - $rootScope.currentPage = 5; - $rootScope.$digest(); - expect(element.find('li').eq(-2).hasClass('disabled')).toBe(true); - expect(element.find('li').eq(-1).hasClass('disabled')).toBe(true); - }); + clickPaginationEl(1); - it('changes currentPage if the "first" link is clicked', function() { - var first = element.find('li').eq(0).find('a').eq(0); - first.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe(1); - }); + expect($rootScope.currentPage).toBe(5); + expect(getPaginationEl(-3)).toHaveClass('active'); + }); - it('changes currentPage if the "last" link is clicked', function() { - var last = element.find('li').eq(-1).find('a').eq(0); - last.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe($rootScope.numPages); - }); + it('moves to the next set when last ellipsis is clicked', function() { + expect(getPaginationEl(-2).text()).toBe('...'); - it('does not change the current page on "first" click if already at first page', function() { - var first = element.find('li').eq(0).find('a').eq(0); - $rootScope.currentPage = 1; - $rootScope.$digest(); - first.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe(1); - }); + clickPaginationEl(-2); - it('does not change the current page on "last" click if already at last page', function() { - var last = element.find('li').eq(-1).find('a').eq(0); - $rootScope.currentPage = $rootScope.numPages; - $rootScope.$digest(); - last.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe($rootScope.numPages); - }); + expect($rootScope.currentPage).toBe(11); + expect(getPaginationEl(2)).toHaveClass('active'); + }); - it('changes "first" & "last" text from attributes', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + it('should not display page numbers, if max-size is zero', function() { + $rootScope.maxSize = 0; + $rootScope.$digest(); - expect(element.find('li').eq(0).text()).toBe('<<<'); - expect(element.find('li').eq(-1).text()).toBe('>>>'); + expect(getPaginationBarSize()).toBe(2); + expect(getPaginationEl(0).text()).toBe('Previous'); + expect(getPaginationEl(1).text()).toBe('Next'); + }); }); - it('changes "previous" & "next" text from attributes', function() { - element = $compile('')($rootScope); - $rootScope.$digest(); + describe('pagination directive with `boundary-links`', function () { + beforeEach(inject(function() { + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + + it('contains one ul and num-pages + 4 li elements', function() { + expect(element.find('ul').length).toBe(1); + expect(getPaginationBarSize()).toBe(9); + expect(getPaginationEl(0).text()).toBe('First'); + expect(getPaginationEl(1).text()).toBe('Previous'); + expect(getPaginationEl(-2).text()).toBe('Next'); + expect(getPaginationEl(-1).text()).toBe('Last'); + }); - expect(element.find('li').eq(1).text()).toBe('<<'); - expect(element.find('li').eq(-2).text()).toBe('>>'); - }); + it('has first and last li elements visible', function() { + expect(getPaginationEl(0).css('display')).not.toBe('none'); + expect(getPaginationEl(-1).css('display')).not.toBe('none'); + }); - it('changes "first" & "last" text from interpolated attributes', function() { - $rootScope.myfirstText = '<<<'; - $rootScope.mylastText = '>>>'; - element = $compile('')($rootScope); - $rootScope.$digest(); - expect(element.find('li').eq(0).text()).toBe('<<<'); - expect(element.find('li').eq(-1).text()).toBe('>>>'); - }); + it('disables the "first" & "previous" link if current page is 1', function() { + updateCurrentPage(1); - it('changes "previous" & "next" text from interpolated attributes', function() { - $rootScope.previousText = '<<'; - $rootScope.nextText = '>>'; - element = $compile('')($rootScope); - $rootScope.$digest(); + expect(getPaginationEl(0)).toHaveClass('disabled'); + expect(getPaginationEl(1)).toHaveClass('disabled'); + }); - expect(element.find('li').eq(1).text()).toBe('<<'); - expect(element.find('li').eq(-2).text()).toBe('>>'); - }); + it('disables the "last" & "next" link if current page is num-pages', function() { + updateCurrentPage(5); -}); + expect(getPaginationEl(-2)).toHaveClass('disabled'); + expect(getPaginationEl(-1)).toHaveClass('disabled'); + }); -describe('pagination directive with just number links', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + it('changes currentPage if the "first" link is clicked', function() { + clickPaginationEl(0); + expect($rootScope.currentPage).toBe(1); + }); - it('has a "pagination" css class', function() { - expect(element.hasClass('pagination')).toBe(true); - }); + it('changes currentPage if the "last" link is clicked', function() { + clickPaginationEl(-1); + expect($rootScope.currentPage).toBe(5); + }); - it('contains one ul and num-pages li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(5); - expect(element.find('li').eq(0).text()).toBe('1'); - expect(element.find('li').eq(-1).text()).toBe(''+$rootScope.numPages); - }); + it('does not change the current page on "first" click if already at first page', function() { + updateCurrentPage(1); + clickPaginationEl(0); + expect($rootScope.currentPage).toBe(1); + }); - it('has the number of the page as text in each page item', function() { - var lis = element.find('li'); - for(var i=0; i<$rootScope.numPages;i++) { - expect(lis.eq(i).text()).toEqual(''+(i+1)); - } - }); + it('does not change the current page on "last" click if already at last page', function() { + updateCurrentPage(5); + clickPaginationEl(-1); + expect($rootScope.currentPage).toBe(5); + }); - it('sets the current-page to be active', function() { - var currentPageItem = element.find('li').eq($rootScope.currentPage-1); - expect(currentPageItem.hasClass('active')).toBe(true); - }); + it('changes "first" & "last" text from attributes', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - it('does not disable the "1" link if current-page is 1', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - var onePageItem = element.find('li').eq(0); - expect(onePageItem.hasClass('disabled')).toBe(false); - expect(onePageItem.hasClass('active')).toBe(true); - }); + expect(getPaginationEl(0).text()).toBe('<<<'); + expect(getPaginationEl(-1).text()).toBe('>>>'); + }); - it('does not disable the "numPages" link if current-page is num-pages', function() { - $rootScope.currentPage = 5; - $rootScope.$digest(); - var lastPageItem = element.find('li').eq(-1); - expect(lastPageItem.hasClass('disabled')).toBe(false); - expect(lastPageItem.hasClass('active')).toBe(true); - }); + it('changes "previous" & "next" text from attributes', function() { + element = $compile('')($rootScope); + $rootScope.$digest(); - it('changes currentPage if a page link is clicked', function() { - var page2 = element.find('li').eq(1).find('a'); - page2.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe(2); - }); + expect(getPaginationEl(1).text()).toBe('<<'); + expect(getPaginationEl(-2).text()).toBe('>>'); + }); - it('executes the onSelectPage expression when the current page changes', function() { - $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - var page2 = element.find('li').eq(1).find('a').eq(0); - page2.click(); - $rootScope.$digest(); - expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); - }); + it('changes "first" & "last" text from interpolated attributes', function() { + $rootScope.myfirstText = '<<<'; + $rootScope.mylastText = '>>>'; + element = $compile('')($rootScope); + $rootScope.$digest(); - it('changes the number of items when numPages changes', function() { - $rootScope.numPages = 8; - $rootScope.$digest(); - expect(element.find('li').length).toBe(8); - expect(element.find('li').eq(0).text()).toBe('1'); - expect(element.find('li').eq(-1).text()).toBe(''+$rootScope.numPages); - }); + expect(getPaginationEl(0).text()).toBe('<<<'); + expect(getPaginationEl(-1).text()).toBe('>>>'); + }); - it('sets the current page to the last page if the numPages is changed to less than the current page', function() { - $rootScope.selectPageHandler = jasmine.createSpy('selectPageHandler'); - element = $compile('')($rootScope); - $rootScope.$digest(); - $rootScope.numPages = 2; - $rootScope.$digest(); - expect(element.find('li').length).toBe(2); - expect($rootScope.currentPage).toBe(2); - expect($rootScope.selectPageHandler).toHaveBeenCalledWith(2); + it('changes "previous" & "next" text from interpolated attributes', function() { + $rootScope.previousText = '<<'; + $rootScope.nextText = '>>'; + element = $compile('')($rootScope); + $rootScope.$digest(); + + expect(getPaginationEl(1).text()).toBe('<<'); + expect(getPaginationEl(-2).text()).toBe('>>'); + }); }); -}); -describe('setting paginationConfig', function() { - var $rootScope, element; - var originalConfig = {}; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_, paginationConfig) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - angular.extend(originalConfig, paginationConfig); - paginationConfig.boundaryLinks = true; - paginationConfig.directionLinks = true; - paginationConfig.firstText = 'FI'; - paginationConfig.previousText = 'PR'; - paginationConfig.nextText = 'NE'; - paginationConfig.lastText = 'LA'; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); - afterEach(inject(function(paginationConfig) { - // return it to the original state - angular.extend(paginationConfig, originalConfig); - })); + describe('pagination directive with just number links', function () { + beforeEach(inject(function() { + element = $compile('')($rootScope); + $rootScope.$digest(); + })); - it('should change paging text', function () { - expect(element.find('li').eq(0).text()).toBe('FI'); - expect(element.find('li').eq(1).text()).toBe('PR'); - expect(element.find('li').eq(-2).text()).toBe('NE'); - expect(element.find('li').eq(-1).text()).toBe('LA'); - }); + it('contains one ul and num-pages li elements', function() { + expect(getPaginationBarSize()).toBe(5); + expect(getPaginationEl(0).text()).toBe('1'); + expect(getPaginationEl(-1).text()).toBe('5'); + }); - it('contains one ul and num-pages + 4 li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(9); - }); + it('has the number of the page as text in each page item', function() { + for(var i = 0; i < 5; i++) { + expect(getPaginationEl(i).text()).toEqual(''+(i+1)); + } + }); -}); + it('sets the current page to be active', function() { + expect(getPaginationEl(2)).toHaveClass('active'); + }); + it('does not disable the "1" link if current page is 1', function() { + updateCurrentPage(1); -describe('pagination directive with first, last & number links', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - $rootScope.directions = false; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + expect(getPaginationEl(0)).not.toHaveClass('disabled'); + expect(getPaginationEl(0)).toHaveClass('active'); + }); - it('contains one ul and num-pages + 2 li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(7); - expect(element.find('li').eq(0).text()).toBe('First'); - expect(element.find('li').eq(1).text()).toBe('1'); - expect(element.find('li').eq(-2).text()).toBe(''+$rootScope.numPages); - expect(element.find('li').eq(-1).text()).toBe('Last'); - }); + it('does not disable the "last" link if current page is last page', function() { + updateCurrentPage(5); - it('disables the "first" & activates "1" link if current-page is 1', function() { - $rootScope.currentPage = 1; - $rootScope.$digest(); - expect(element.find('li').eq(0).hasClass('disabled')).toBe(true); - expect(element.find('li').eq(1).hasClass('disabled')).toBe(false); - expect(element.find('li').eq(1).hasClass('active')).toBe(true); - }); + expect(getPaginationEl(-1)).not.toHaveClass('disabled'); + expect(getPaginationEl(-1)).toHaveClass('active'); + }); - it('disables the "last" & "next" link if current-page is num-pages', function() { - $rootScope.currentPage = 5; - $rootScope.$digest(); - expect(element.find('li').eq(-2).hasClass('disabled')).toBe(false); - expect(element.find('li').eq(-2).hasClass('active')).toBe(true); - expect(element.find('li').eq(-1).hasClass('disabled')).toBe(true); - }); + it('changes currentPage if a page link is clicked', function() { + clickPaginationEl(1); + expect($rootScope.currentPage).toBe(2); + }); - it('changes currentPage if the "first" link is clicked', function() { - var first = element.find('li').eq(0).find('a').eq(0); - first.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe(1); + it('changes the number of items when total items changes', function() { + $rootScope.total = 73; // 8 pages + $rootScope.$digest(); + + expect(getPaginationBarSize()).toBe(8); + expect(getPaginationEl(0).text()).toBe('1'); + expect(getPaginationEl(-1).text()).toBe('8'); + }); }); - it('changes currentPage if the "last" link is clicked', function() { - var last = element.find('li').eq(-1).find('a').eq(0); - last.click(); - $rootScope.$digest(); - expect($rootScope.currentPage).toBe($rootScope.numPages); + describe('with just boundary & number links', function () { + beforeEach(inject(function() { + $rootScope.directions = false; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + + it('contains number of pages + 2 li elements', function() { + expect(getPaginationBarSize()).toBe(7); + expect(getPaginationEl(0).text()).toBe('First'); + expect(getPaginationEl(1).text()).toBe('1'); + expect(getPaginationEl(-2).text()).toBe('5'); + expect(getPaginationEl(-1).text()).toBe('Last'); + }); + + it('disables the "first" & activates "1" link if current page is 1', function() { + updateCurrentPage(1); + + expect(getPaginationEl(0)).toHaveClass('disabled'); + expect(getPaginationEl(1)).not.toHaveClass('disabled'); + expect(getPaginationEl(1)).toHaveClass('active'); + }); + + it('disables the "last" & "next" link if current page is num-pages', function() { + updateCurrentPage(5); + + expect(getPaginationEl(-2)).toHaveClass('active'); + expect(getPaginationEl(-2)).not.toHaveClass('disabled'); + expect(getPaginationEl(-1)).toHaveClass('disabled'); + }); }); -}); + describe('`num-pages`', function () { + beforeEach(inject(function() { + $rootScope.numpg = null; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); -describe('pagination bypass configuration from attributes', function () { - var $rootScope, element; - beforeEach(module('ui.bootstrap.pagination')); - beforeEach(module('template/pagination/pagination.html')); - beforeEach(inject(function(_$compile_, _$rootScope_) { - $compile = _$compile_; - $rootScope = _$rootScope_; - $rootScope.numPages = 5; - $rootScope.currentPage = 3; - element = $compile('')($rootScope); - $rootScope.$digest(); - })); + it('equals to total number of pages', function() { + expect($rootScope.numpg).toBe(5); + }); + }); - it('contains one ul and num-pages + 4 li elements', function() { - expect(element.find('ul').length).toBe(1); - expect(element.find('li').length).toBe(9); + describe('setting `paginationConfig`', function() { + var originalConfig = {}; + beforeEach(inject(function(paginationConfig) { + angular.extend(originalConfig, paginationConfig); + paginationConfig.itemsPerPage = 5; + paginationConfig.boundaryLinks = true; + paginationConfig.directionLinks = true; + paginationConfig.firstText = 'FI'; + paginationConfig.previousText = 'PR'; + paginationConfig.nextText = 'NE'; + paginationConfig.lastText = 'LA'; + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + afterEach(inject(function(paginationConfig) { + // return it to the original stat + angular.extend(paginationConfig, originalConfig); + })); + + it('should change paging text', function () { + expect(getPaginationEl(0).text()).toBe('FI'); + expect(getPaginationEl(1).text()).toBe('PR'); + expect(getPaginationEl(-2).text()).toBe('NE'); + expect(getPaginationEl(-1).text()).toBe('LA'); + }); + + it('contains number of pages + 4 li elements', function() { + expect(getPaginationBarSize()).toBe(14); + }); }); - it('should change paging text from attribute', function () { - expect(element.find('li').eq(0).text()).toBe('<<'); - expect(element.find('li').eq(1).text()).toBe('<'); - expect(element.find('li').eq(-2).text()).toBe('>'); - expect(element.find('li').eq(-1).text()).toBe('>>'); + describe('override configuration from attributes', function () { + beforeEach(inject(function() { + element = $compile('')($rootScope); + $rootScope.$digest(); + })); + + it('contains number of pages + 4 li elements', function() { + expect(getPaginationBarSize()).toBe(9); + }); + + it('should change paging text from attribute', function () { + expect(getPaginationEl(0).text()).toBe('<<'); + expect(getPaginationEl(1).text()).toBe('<'); + expect(getPaginationEl(-2).text()).toBe('>'); + expect(getPaginationEl(-1).text()).toBe('>>'); + }); }); });