PATH:
home
/
letacommog
/
crmleta
/
consumerportal
/
libraries
/
angularjs
/
directives
/
pagination
/** * dirPagination - AngularJS module for paginating (almost) anything. * * * Credits * ======= * * Daniel Tabuenca: https://groups.google.com/d/msg/angular/an9QpzqIYiM/r8v-3W1X5vcJ * for the idea on how to dynamically invoke the ng-repeat directive. * * I borrowed a couple of lines and a few attribute names from the AngularUI Bootstrap project: * https://github.com/angular-ui/bootstrap/blob/master/src/pagination/pagination.js * * Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk> */ (function() { /** * Config */ var moduleName = 'angularUtils.directives.dirPagination'; var templatePath = 'directives/pagination/dirPagination.tpl.html'; /** * Module */ var module; try { module = angular.module(moduleName); } catch(err) { // named module does not exist, so create one module = angular.module(moduleName, []); } module.directive('dirPaginate', ['$compile', '$parse', '$timeout', 'paginationService', function($compile, $parse, $timeout, paginationService) { return { terminal: true, multiElement: true, priority: 5000, // This setting is used in conjunction with the later call to $compile() to prevent infinite recursion of compilation compile: function dirPaginationCompileFn(tElement, tAttrs){ // Add ng-repeat to the dom element if (tElement[0].hasAttribute('dir-paginate-start') || tElement[0].hasAttribute('data-dir-paginate-start')) { // using multiElement mode (dir-paginate-start, dir-paginate-end) tAttrs.$set('ngRepeatStart', tAttrs.dirPaginate); tElement.eq(tElement.length - 1).attr('ng-repeat-end', true); } else { tAttrs.$set('ngRepeat', tAttrs.dirPaginate); } var expression = tAttrs.dirPaginate; // regex taken directly from https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L211 var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/); var filterPattern = /\|\s*itemsPerPage\s*:[^|]*/; if (match[2].match(filterPattern) === null) { throw 'pagination directive: the \'itemsPerPage\' filter must be set.'; } var itemsPerPageFilterRemoved = match[2].replace(filterPattern, ''); var collectionGetter = $parse(itemsPerPageFilterRemoved); return function dirPaginationLinkFn(scope, element, attrs){ var paginationId; var compiled = $compile(element, false, 5000); // we manually compile the element again, as we have now added ng-repeat. Priority less than 5000 prevents infinite recursion of compiling dirPaginate paginationId = attrs.paginationId || '__default'; paginationService.registerInstance(paginationId); var currentPageGetter; if (attrs.currentPage) { currentPageGetter = $parse(attrs.currentPage); } else { // if the current-page attribute was not set, we'll make our own var defaultCurrentPage = paginationId + '__currentPage'; scope[defaultCurrentPage] = 1; currentPageGetter = $parse(defaultCurrentPage); } paginationService.setCurrentPageParser(paginationId, currentPageGetter, scope); if (typeof attrs.totalItems !== 'undefined') { paginationService.setAsyncModeTrue(paginationId); scope.$watch(function() { return $parse(attrs.totalItems)(scope); }, function (result) { if (0 <= result) { paginationService.setCollectionLength(paginationId, result); } }); } else { scope.$watchCollection(function() { return collectionGetter(scope); }, function(collection) { if (collection) { paginationService.setCollectionLength(paginationId, collection.length); } }); } // Delegate to the link function returned by the new compilation of the ng-repeat compiled(scope); }; } }; }]); module.directive('dirPaginationControls', ['paginationService', function(paginationService) { var numberRegex = /^\d+$/; /** * Generate an array of page numbers (or the '...' string) which is used in an ng-repeat to generate the * links used in pagination * * @param currentPage * @param rowsPerPage * @param paginationRange * @param collectionLength * @returns {Array} */ function generatePagesArray(currentPage, collectionLength, rowsPerPage, paginationRange) { var pages = []; var totalPages = Math.ceil(collectionLength / rowsPerPage); var halfWay = Math.ceil(paginationRange / 2); var position; if (currentPage <= halfWay) { position = 'start'; } else if (totalPages - halfWay < currentPage) { position = 'end'; } else { position = 'middle'; } var ellipsesNeeded = paginationRange < totalPages; var i = 1; while (i <= totalPages && i <= paginationRange) { var pageNumber = calculatePageNumber(i, currentPage, paginationRange, totalPages); var openingEllipsesNeeded = (i === 2 && (position === 'middle' || position === 'end')); var closingEllipsesNeeded = (i === paginationRange - 1 && (position === 'middle' || position === 'start')); if (ellipsesNeeded && (openingEllipsesNeeded || closingEllipsesNeeded)) { pages.push('...'); } else { pages.push(pageNumber); } i ++; } return pages; } /** * Given the position in the sequence of pagination links [i], figure out what page number corresponds to that position. * * @param i * @param currentPage * @param paginationRange * @param totalPages * @returns {*} */ function calculatePageNumber(i, currentPage, paginationRange, totalPages) { var halfWay = Math.ceil(paginationRange/2); if (i === paginationRange) { return totalPages; } else if (i === 1) { return i; } else if (paginationRange < totalPages) { if (totalPages - halfWay < currentPage) { return totalPages - paginationRange + i; } else if (halfWay < currentPage) { return currentPage - halfWay + i; } else { return i; } } else { return i; } } return { restrict: 'AE', templateUrl: function(elem, attrs) { return attrs.templateUrl || templatePath; }, scope: { maxSize: '=?', onPageChange: '&?' }, link: function(scope, element, attrs) { var paginationId; paginationId = attrs.paginationId || '__default'; if (!scope.maxSize) { scope.maxSize = 9; } scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : true; scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : false; if (!paginationService.isRegistered(paginationId)) { var idMessage = (paginationId !== '__default') ? ' (id: ' + paginationId + ') ' : ' '; throw 'pagination directive: the pagination controls' + idMessage + 'cannot be used without the corresponding pagination directive.'; } var paginationRange = Math.max(scope.maxSize, 5); scope.pages = []; scope.pagination = { last: 1, current: 1 }; scope.$watch(function() { return (paginationService.getCollectionLength(paginationId) + 1) * paginationService.getItemsPerPage(paginationId); }, function(length) { if (0 < length) { generatePagination(); } }); scope.$watch(function() { return paginationService.getCurrentPage(paginationId); }, function(currentPage, previousPage) { if (currentPage != previousPage) { goToPage(currentPage); } }); scope.setCurrent = function(num) { if (isValidPageNumber(num)) { paginationService.setCurrentPage(paginationId, num); } }; function goToPage(num) { if (isValidPageNumber(num)) { scope.pages = generatePagesArray(num, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange); scope.pagination.current = num; // if a callback has been set, then call it with the page number as an argument if (scope.onPageChange) { scope.onPageChange({ newPageNumber : num }); } } } function generatePagination() { scope.pages = generatePagesArray(1, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange); scope.pagination.current = parseInt(paginationService.getCurrentPage(paginationId)); scope.pagination.last = scope.pages[scope.pages.length - 1]; if (scope.pagination.last < scope.pagination.current) { scope.setCurrent(scope.pagination.last); } } function isValidPageNumber(num) { return (numberRegex.test(num) && (0 < num && num <= scope.pagination.last)); } } }; }]); module.filter('itemsPerPage', ['paginationService', function(paginationService) { return function(collection, itemsPerPage, paginationId) { if (typeof (paginationId) === 'undefined') { paginationId = '__default'; } if (!paginationService.isRegistered(paginationId)) { throw 'pagination directive: the itemsPerPage id argument (id: ' + paginationId + ') does not match a registered pagination-id.'; } var end; var start; if (collection instanceof Array) { itemsPerPage = parseInt(itemsPerPage) || 9999999999; if (paginationService.isAsyncMode(paginationId)) { start = 0; } else { start = (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage; } end = start + itemsPerPage; paginationService.setItemsPerPage(paginationId, itemsPerPage); return collection.slice(start, end); } else { return collection; } }; }]); module.service('paginationService', function() { var instances = {}; var lastRegisteredInstance; this.registerInstance = function(instanceId) { if (typeof instances[instanceId] === 'undefined') { instances[instanceId] = { asyncMode: false }; lastRegisteredInstance = instanceId; } }; this.isRegistered = function(instanceId) { return (typeof instances[instanceId] !== 'undefined'); }; this.getLastInstanceId = function() { return lastRegisteredInstance; }; this.setCurrentPageParser = function(instanceId, val, scope) { instances[instanceId].currentPageParser = val; instances[instanceId].context = scope; }; this.setCurrentPage = function(instanceId, val) { instances[instanceId].currentPageParser.assign(instances[instanceId].context, val); }; this.getCurrentPage = function(instanceId) { return instances[instanceId].currentPageParser(instances[instanceId].context); }; this.setItemsPerPage = function(instanceId, val) { instances[instanceId].itemsPerPage = val; }; this.getItemsPerPage = function(instanceId) { return instances[instanceId].itemsPerPage; }; this.setCollectionLength = function(instanceId, val) { instances[instanceId].collectionLength = val; }; this.getCollectionLength = function(instanceId) { return instances[instanceId].collectionLength; }; this.setAsyncModeTrue = function(instanceId) { instances[instanceId].asyncMode = true; }; this.isAsyncMode = function(instanceId) { return instances[instanceId].asyncMode; }; }); })();
[+]
..
[-] dirPagination.tpl.html
[edit]
[-] README.md
[edit]
[-] dirPagination.spec.js
[edit]
[-] dirPagination.js
[edit]