angular-dirPagination.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /**
  2. * dirPagination - AngularJS module for paginating (almost) anything.
  3. *
  4. *
  5. * Credits
  6. * =======
  7. *
  8. * Daniel Tabuenca: https://groups.google.com/d/msg/angular/an9QpzqIYiM/r8v-3W1X5vcJ
  9. * for the idea on how to dynamically invoke the ng-repeat directive.
  10. *
  11. * I borrowed a couple of lines and a few attribute names from the AngularUI Bootstrap project:
  12. * https://github.com/angular-ui/bootstrap/blob/master/src/pagination/pagination.js
  13. *
  14. * Copyright 2014 Michael Bromley <michael@michaelbromley.co.uk>
  15. *
  16. * Permission is hereby granted, free of charge, to any person obtaining a copy
  17. * of this software and associated documentation files (the "Software"), to deal
  18. * in the Software without restriction, including without limitation the rights
  19. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  20. * copies of the Software, and to permit persons to whom the Software is
  21. * furnished to do so, subject to the following conditions:
  22. *
  23. * The above copyright notice and this permission notice shall be included in
  24. * all copies or substantial portions of the Software.
  25. *
  26. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  27. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  29. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  30. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  31. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  32. * THE SOFTWARE.
  33. *
  34. */
  35. (function() {
  36. /**
  37. * Config
  38. */
  39. var moduleName = 'angularUtils.directives.dirPagination';
  40. var DEFAULT_ID = '__default';
  41. /**
  42. * Module
  43. */
  44. angular.module(moduleName, [])
  45. .directive('dirPaginate', ['$compile', '$parse', 'paginationService', dirPaginateDirective])
  46. .directive('dirPaginateNoCompile', noCompileDirective)
  47. .directive('dirPaginationControls', ['paginationService', 'paginationTemplate', dirPaginationControlsDirective])
  48. .filter('itemsPerPage', ['paginationService', itemsPerPageFilter])
  49. .service('paginationService', paginationService)
  50. .provider('paginationTemplate', paginationTemplateProvider)
  51. .run(['$templateCache',dirPaginationControlsTemplateInstaller]);
  52. function dirPaginateDirective($compile, $parse, paginationService) {
  53. return {
  54. terminal: true,
  55. multiElement: true,
  56. priority: 100,
  57. compile: dirPaginationCompileFn
  58. };
  59. function dirPaginationCompileFn(tElement, tAttrs){
  60. var expression = tAttrs.dirPaginate;
  61. // regex taken directly from https://github.com/angular/angular.js/blob/v1.4.x/src/ng/directive/ngRepeat.js#L339
  62. var match = expression.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
  63. var filterPattern = /\|\s*itemsPerPage\s*:\s*(.*\(\s*\w*\)|([^\)]*?(?=\s+as\s+))|[^\)]*)/;
  64. if (match[2].match(filterPattern) === null) {
  65. throw 'pagination directive: the \'itemsPerPage\' filter must be set.';
  66. }
  67. var itemsPerPageFilterRemoved = match[2].replace(filterPattern, '');
  68. var collectionGetter = $parse(itemsPerPageFilterRemoved);
  69. addNoCompileAttributes(tElement);
  70. // If any value is specified for paginationId, we register the un-evaluated expression at this stage for the benefit of any
  71. // dir-pagination-controls directives that may be looking for this ID.
  72. var rawId = tAttrs.paginationId || DEFAULT_ID;
  73. paginationService.registerInstance(rawId);
  74. return function dirPaginationLinkFn(scope, element, attrs){
  75. // Now that we have access to the `scope` we can interpolate any expression given in the paginationId attribute and
  76. // potentially register a new ID if it evaluates to a different value than the rawId.
  77. var paginationId = $parse(attrs.paginationId)(scope) || attrs.paginationId || DEFAULT_ID;
  78. // In case rawId != paginationId we deregister using rawId for the sake of general cleanliness
  79. // before registering using paginationId
  80. paginationService.deregisterInstance(rawId);
  81. paginationService.registerInstance(paginationId);
  82. var repeatExpression = getRepeatExpression(expression, paginationId);
  83. addNgRepeatToElement(element, attrs, repeatExpression);
  84. removeTemporaryAttributes(element);
  85. var compiled = $compile(element);
  86. var currentPageGetter = makeCurrentPageGetterFn(scope, attrs, paginationId);
  87. paginationService.setCurrentPageParser(paginationId, currentPageGetter, scope);
  88. if (typeof attrs.totalItems !== 'undefined') {
  89. paginationService.setAsyncModeTrue(paginationId);
  90. scope.$watch(function() {
  91. return $parse(attrs.totalItems)(scope);
  92. }, function (result) {
  93. if (0 <= result) {
  94. paginationService.setCollectionLength(paginationId, result);
  95. }
  96. });
  97. } else {
  98. paginationService.setAsyncModeFalse(paginationId);
  99. scope.$watchCollection(function() {
  100. return collectionGetter(scope);
  101. }, function(collection) {
  102. if (collection) {
  103. var collectionLength = (collection instanceof Array) ? collection.length : Object.keys(collection).length;
  104. paginationService.setCollectionLength(paginationId, collectionLength);
  105. }
  106. });
  107. }
  108. // Delegate to the link function returned by the new compilation of the ng-repeat
  109. compiled(scope);
  110. // When the scope is destroyed, we make sure to remove the reference to it in paginationService
  111. // so that it can be properly garbage collected
  112. scope.$on('$destroy', function destroyDirPagination() {
  113. paginationService.deregisterInstance(paginationId);
  114. });
  115. };
  116. }
  117. /**
  118. * If a pagination id has been specified, we need to check that it is present as the second argument passed to
  119. * the itemsPerPage filter. If it is not there, we add it and return the modified expression.
  120. *
  121. * @param expression
  122. * @param paginationId
  123. * @returns {*}
  124. */
  125. function getRepeatExpression(expression, paginationId) {
  126. var repeatExpression,
  127. idDefinedInFilter = !!expression.match(/(\|\s*itemsPerPage\s*:[^|]*:[^|]*)/);
  128. if (paginationId !== DEFAULT_ID && !idDefinedInFilter) {
  129. repeatExpression = expression.replace(/(\|\s*itemsPerPage\s*:\s*[^|\s]*)/, "$1 : '" + paginationId + "'");
  130. } else {
  131. repeatExpression = expression;
  132. }
  133. return repeatExpression;
  134. }
  135. /**
  136. * Adds the ng-repeat directive to the element. In the case of multi-element (-start, -end) it adds the
  137. * appropriate multi-element ng-repeat to the first and last element in the range.
  138. * @param element
  139. * @param attrs
  140. * @param repeatExpression
  141. */
  142. function addNgRepeatToElement(element, attrs, repeatExpression) {
  143. if (element[0].hasAttribute('dir-paginate-start') || element[0].hasAttribute('data-dir-paginate-start')) {
  144. // using multiElement mode (dir-paginate-start, dir-paginate-end)
  145. attrs.$set('ngRepeatStart', repeatExpression);
  146. element.eq(element.length - 1).attr('ng-repeat-end', true);
  147. } else {
  148. attrs.$set('ngRepeat', repeatExpression);
  149. }
  150. }
  151. /**
  152. * Adds the dir-paginate-no-compile directive to each element in the tElement range.
  153. * @param tElement
  154. */
  155. function addNoCompileAttributes(tElement) {
  156. angular.forEach(tElement, function(el) {
  157. if (el.nodeType === 1) {
  158. angular.element(el).attr('dir-paginate-no-compile', true);
  159. }
  160. });
  161. }
  162. /**
  163. * Removes the variations on dir-paginate (data-, -start, -end) and the dir-paginate-no-compile directives.
  164. * @param element
  165. */
  166. function removeTemporaryAttributes(element) {
  167. angular.forEach(element, function(el) {
  168. if (el.nodeType === 1) {
  169. angular.element(el).removeAttr('dir-paginate-no-compile');
  170. }
  171. });
  172. element.eq(0).removeAttr('dir-paginate-start').removeAttr('dir-paginate').removeAttr('data-dir-paginate-start').removeAttr('data-dir-paginate');
  173. element.eq(element.length - 1).removeAttr('dir-paginate-end').removeAttr('data-dir-paginate-end');
  174. }
  175. /**
  176. * Creates a getter function for the current-page attribute, using the expression provided or a default value if
  177. * no current-page expression was specified.
  178. *
  179. * @param scope
  180. * @param attrs
  181. * @param paginationId
  182. * @returns {*}
  183. */
  184. function makeCurrentPageGetterFn(scope, attrs, paginationId) {
  185. var currentPageGetter;
  186. if (attrs.currentPage) {
  187. currentPageGetter = $parse(attrs.currentPage);
  188. } else {
  189. // If the current-page attribute was not set, we'll make our own.
  190. // Replace any non-alphanumeric characters which might confuse
  191. // the $parse service and give unexpected results.
  192. // See https://github.com/michaelbromley/angularUtils/issues/233
  193. var defaultCurrentPage = (paginationId + '__currentPage').replace(/\W/g, '_');
  194. scope[defaultCurrentPage] = 1;
  195. currentPageGetter = $parse(defaultCurrentPage);
  196. }
  197. return currentPageGetter;
  198. }
  199. }
  200. /**
  201. * This is a helper directive that allows correct compilation when in multi-element mode (ie dir-paginate-start, dir-paginate-end).
  202. * It is dynamically added to all elements in the dir-paginate compile function, and it prevents further compilation of
  203. * any inner directives. It is then removed in the link function, and all inner directives are then manually compiled.
  204. */
  205. function noCompileDirective() {
  206. return {
  207. priority: 5000,
  208. terminal: true
  209. };
  210. }
  211. function dirPaginationControlsTemplateInstaller($templateCache) {
  212. $templateCache.put('angularUtils.directives.dirPagination.template', '<ul class="pagination" ng-if="1 < pages.length || !autoHide"><li ng-if="boundaryLinks" ng-class="{ disabled : pagination.current == 1 }"><a href="" ng-click="setCurrent(1)">&laquo;</a></li><li ng-if="directionLinks" ng-class="{ disabled : pagination.current == 1 }"><a href="" ng-click="setCurrent(pagination.current - 1)">&lsaquo;</a></li><li ng-repeat="pageNumber in pages track by tracker(pageNumber, $index)" ng-class="{ active : pagination.current == pageNumber, disabled : pageNumber == \'...\' || ( ! autoHide && pages.length === 1 ) }"><a href="" ng-click="setCurrent(pageNumber)">{{ pageNumber }}</a></li><li ng-if="directionLinks" ng-class="{ disabled : pagination.current == pagination.last }"><a href="" ng-click="setCurrent(pagination.current + 1)">&rsaquo;</a></li><li ng-if="boundaryLinks" ng-class="{ disabled : pagination.current == pagination.last }"><a href="" ng-click="setCurrent(pagination.last)">&raquo;</a></li></ul>');
  213. }
  214. function dirPaginationControlsDirective(paginationService, paginationTemplate) {
  215. var numberRegex = /^\d+$/;
  216. var DDO = {
  217. restrict: 'AE',
  218. scope: {
  219. maxSize: '=?',
  220. onPageChange: '&?',
  221. paginationId: '=?',
  222. autoHide: '=?'
  223. },
  224. link: dirPaginationControlsLinkFn
  225. };
  226. // We need to check the paginationTemplate service to see whether a template path or
  227. // string has been specified, and add the `template` or `templateUrl` property to
  228. // the DDO as appropriate. The order of priority to decide which template to use is
  229. // (highest priority first):
  230. // 1. paginationTemplate.getString()
  231. // 2. attrs.templateUrl
  232. // 3. paginationTemplate.getPath()
  233. var templateString = paginationTemplate.getString();
  234. if (templateString !== undefined) {
  235. DDO.template = templateString;
  236. } else {
  237. DDO.templateUrl = function(elem, attrs) {
  238. return attrs.templateUrl || paginationTemplate.getPath();
  239. };
  240. }
  241. return DDO;
  242. function dirPaginationControlsLinkFn(scope, element, attrs) {
  243. // rawId is the un-interpolated value of the pagination-id attribute. This is only important when the corresponding dir-paginate directive has
  244. // not yet been linked (e.g. if it is inside an ng-if block), and in that case it prevents this controls directive from assuming that there is
  245. // no corresponding dir-paginate directive and wrongly throwing an exception.
  246. var rawId = attrs.paginationId || DEFAULT_ID;
  247. var paginationId = scope.paginationId || attrs.paginationId || DEFAULT_ID;
  248. if (!paginationService.isRegistered(paginationId) && !paginationService.isRegistered(rawId)) {
  249. var idMessage = (paginationId !== DEFAULT_ID) ? ' (id: ' + paginationId + ') ' : ' ';
  250. if (window.console) {
  251. console.warn('Pagination directive: the pagination controls' + idMessage + 'cannot be used without the corresponding pagination directive, which was not found at link time.');
  252. }
  253. }
  254. if (!scope.maxSize) { scope.maxSize = 9; }
  255. scope.autoHide = scope.autoHide === undefined ? true : scope.autoHide;
  256. scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : true;
  257. scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : false;
  258. var paginationRange = Math.max(scope.maxSize, 5);
  259. scope.pages = [];
  260. scope.pagination = {
  261. last: 1,
  262. current: 1
  263. };
  264. scope.range = {
  265. lower: 1,
  266. upper: 1,
  267. total: 1
  268. };
  269. scope.$watch('maxSize', function(val) {
  270. if (val) {
  271. paginationRange = Math.max(scope.maxSize, 5);
  272. generatePagination();
  273. }
  274. });
  275. scope.$watch(function() {
  276. if (paginationService.isRegistered(paginationId)) {
  277. return (paginationService.getCollectionLength(paginationId) + 1) * paginationService.getItemsPerPage(paginationId);
  278. }
  279. }, function(length) {
  280. if (0 < length) {
  281. generatePagination();
  282. }
  283. });
  284. scope.$watch(function() {
  285. if (paginationService.isRegistered(paginationId)) {
  286. return (paginationService.getItemsPerPage(paginationId));
  287. }
  288. }, function(current, previous) {
  289. if (current != previous && typeof previous !== 'undefined') {
  290. goToPage(scope.pagination.current);
  291. }
  292. });
  293. scope.$watch(function() {
  294. if (paginationService.isRegistered(paginationId)) {
  295. return paginationService.getCurrentPage(paginationId);
  296. }
  297. }, function(currentPage, previousPage) {
  298. if (currentPage != previousPage) {
  299. goToPage(currentPage);
  300. }
  301. });
  302. scope.setCurrent = function(num) {
  303. if (paginationService.isRegistered(paginationId) && isValidPageNumber(num)) {
  304. num = parseInt(num, 10);
  305. paginationService.setCurrentPage(paginationId, num);
  306. }
  307. };
  308. /**
  309. * Custom "track by" function which allows for duplicate "..." entries on long lists,
  310. * yet fixes the problem of wrongly-highlighted links which happens when using
  311. * "track by $index" - see https://github.com/michaelbromley/angularUtils/issues/153
  312. * @param id
  313. * @param index
  314. * @returns {string}
  315. */
  316. scope.tracker = function(id, index) {
  317. return id + '_' + index;
  318. };
  319. function goToPage(num) {
  320. if (paginationService.isRegistered(paginationId) && isValidPageNumber(num)) {
  321. var oldPageNumber = scope.pagination.current;
  322. scope.pages = generatePagesArray(num, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
  323. scope.pagination.current = num;
  324. updateRangeValues();
  325. // if a callback has been set, then call it with the page number as the first argument
  326. // and the previous page number as a second argument
  327. if (scope.onPageChange) {
  328. scope.onPageChange({
  329. newPageNumber : num,
  330. oldPageNumber : oldPageNumber
  331. });
  332. }
  333. }
  334. }
  335. function generatePagination() {
  336. if (paginationService.isRegistered(paginationId)) {
  337. var page = parseInt(paginationService.getCurrentPage(paginationId)) || 1;
  338. scope.pages = generatePagesArray(page, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
  339. scope.pagination.current = page;
  340. scope.pagination.last = scope.pages[scope.pages.length - 1];
  341. if (scope.pagination.last < scope.pagination.current) {
  342. scope.setCurrent(scope.pagination.last);
  343. } else {
  344. updateRangeValues();
  345. }
  346. }
  347. }
  348. /**
  349. * This function updates the values (lower, upper, total) of the `scope.range` object, which can be used in the pagination
  350. * template to display the current page range, e.g. "showing 21 - 40 of 144 results";
  351. */
  352. function updateRangeValues() {
  353. if (paginationService.isRegistered(paginationId)) {
  354. var currentPage = paginationService.getCurrentPage(paginationId),
  355. itemsPerPage = paginationService.getItemsPerPage(paginationId),
  356. totalItems = paginationService.getCollectionLength(paginationId);
  357. scope.range.lower = (currentPage - 1) * itemsPerPage + 1;
  358. scope.range.upper = Math.min(currentPage * itemsPerPage, totalItems);
  359. scope.range.total = totalItems;
  360. }
  361. }
  362. function isValidPageNumber(num) {
  363. return (numberRegex.test(num) && (0 < num && num <= scope.pagination.last));
  364. }
  365. }
  366. /**
  367. * Generate an array of page numbers (or the '...' string) which is used in an ng-repeat to generate the
  368. * links used in pagination
  369. *
  370. * @param currentPage
  371. * @param rowsPerPage
  372. * @param paginationRange
  373. * @param collectionLength
  374. * @returns {Array}
  375. */
  376. function generatePagesArray(currentPage, collectionLength, rowsPerPage, paginationRange) {
  377. var pages = [];
  378. var totalPages = Math.ceil(collectionLength / rowsPerPage);
  379. var halfWay = Math.ceil(paginationRange / 2);
  380. var position;
  381. if (currentPage <= halfWay) {
  382. position = 'start';
  383. } else if (totalPages - halfWay < currentPage) {
  384. position = 'end';
  385. } else {
  386. position = 'middle';
  387. }
  388. var ellipsesNeeded = paginationRange < totalPages;
  389. var i = 1;
  390. while (i <= totalPages && i <= paginationRange) {
  391. var pageNumber = calculatePageNumber(i, currentPage, paginationRange, totalPages);
  392. var openingEllipsesNeeded = (i === 2 && (position === 'middle' || position === 'end'));
  393. var closingEllipsesNeeded = (i === paginationRange - 1 && (position === 'middle' || position === 'start'));
  394. if (ellipsesNeeded && (openingEllipsesNeeded || closingEllipsesNeeded)) {
  395. pages.push('...');
  396. } else {
  397. pages.push(pageNumber);
  398. }
  399. i ++;
  400. }
  401. return pages;
  402. }
  403. /**
  404. * Given the position in the sequence of pagination links [i], figure out what page number corresponds to that position.
  405. *
  406. * @param i
  407. * @param currentPage
  408. * @param paginationRange
  409. * @param totalPages
  410. * @returns {*}
  411. */
  412. function calculatePageNumber(i, currentPage, paginationRange, totalPages) {
  413. var halfWay = Math.ceil(paginationRange/2);
  414. if (i === paginationRange) {
  415. return totalPages;
  416. } else if (i === 1) {
  417. return i;
  418. } else if (paginationRange < totalPages) {
  419. if (totalPages - halfWay < currentPage) {
  420. return totalPages - paginationRange + i;
  421. } else if (halfWay < currentPage) {
  422. return currentPage - halfWay + i;
  423. } else {
  424. return i;
  425. }
  426. } else {
  427. return i;
  428. }
  429. }
  430. }
  431. /**
  432. * This filter slices the collection into pages based on the current page number and number of items per page.
  433. * @param paginationService
  434. * @returns {Function}
  435. */
  436. function itemsPerPageFilter(paginationService) {
  437. return function(collection, itemsPerPage, paginationId) {
  438. if (typeof (paginationId) === 'undefined') {
  439. paginationId = DEFAULT_ID;
  440. }
  441. if (!paginationService.isRegistered(paginationId)) {
  442. throw 'pagination directive: the itemsPerPage id argument (id: ' + paginationId + ') does not match a registered pagination-id.';
  443. }
  444. var end;
  445. var start;
  446. if (angular.isObject(collection)) {
  447. itemsPerPage = parseInt(itemsPerPage) || 9999999999;
  448. if (paginationService.isAsyncMode(paginationId)) {
  449. start = 0;
  450. } else {
  451. start = (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage;
  452. }
  453. end = start + itemsPerPage;
  454. paginationService.setItemsPerPage(paginationId, itemsPerPage);
  455. if (collection instanceof Array) {
  456. // the array just needs to be sliced
  457. return collection.slice(start, end);
  458. } else {
  459. // in the case of an object, we need to get an array of keys, slice that, then map back to
  460. // the original object.
  461. var slicedObject = {};
  462. angular.forEach(keys(collection).slice(start, end), function(key) {
  463. slicedObject[key] = collection[key];
  464. });
  465. return slicedObject;
  466. }
  467. } else {
  468. return collection;
  469. }
  470. };
  471. }
  472. /**
  473. * Shim for the Object.keys() method which does not exist in IE < 9
  474. * @param obj
  475. * @returns {Array}
  476. */
  477. function keys(obj) {
  478. if (!Object.keys) {
  479. var objKeys = [];
  480. for (var i in obj) {
  481. if (obj.hasOwnProperty(i)) {
  482. objKeys.push(i);
  483. }
  484. }
  485. return objKeys;
  486. } else {
  487. return Object.keys(obj);
  488. }
  489. }
  490. /**
  491. * This service allows the various parts of the module to communicate and stay in sync.
  492. */
  493. function paginationService() {
  494. var instances = {};
  495. var lastRegisteredInstance;
  496. this.registerInstance = function(instanceId) {
  497. if (typeof instances[instanceId] === 'undefined') {
  498. instances[instanceId] = {
  499. asyncMode: false
  500. };
  501. lastRegisteredInstance = instanceId;
  502. }
  503. };
  504. this.deregisterInstance = function(instanceId) {
  505. delete instances[instanceId];
  506. };
  507. this.isRegistered = function(instanceId) {
  508. return (typeof instances[instanceId] !== 'undefined');
  509. };
  510. this.getLastInstanceId = function() {
  511. return lastRegisteredInstance;
  512. };
  513. this.setCurrentPageParser = function(instanceId, val, scope) {
  514. instances[instanceId].currentPageParser = val;
  515. instances[instanceId].context = scope;
  516. };
  517. this.setCurrentPage = function(instanceId, val) {
  518. instances[instanceId].currentPageParser.assign(instances[instanceId].context, val);
  519. };
  520. this.getCurrentPage = function(instanceId) {
  521. var parser = instances[instanceId].currentPageParser;
  522. return parser ? parser(instances[instanceId].context) : 1;
  523. };
  524. this.setItemsPerPage = function(instanceId, val) {
  525. instances[instanceId].itemsPerPage = val;
  526. };
  527. this.getItemsPerPage = function(instanceId) {
  528. return instances[instanceId].itemsPerPage;
  529. };
  530. this.setCollectionLength = function(instanceId, val) {
  531. instances[instanceId].collectionLength = val;
  532. };
  533. this.getCollectionLength = function(instanceId) {
  534. return instances[instanceId].collectionLength;
  535. };
  536. this.setAsyncModeTrue = function(instanceId) {
  537. instances[instanceId].asyncMode = true;
  538. };
  539. this.setAsyncModeFalse = function(instanceId) {
  540. instances[instanceId].asyncMode = false;
  541. };
  542. this.isAsyncMode = function(instanceId) {
  543. return instances[instanceId].asyncMode;
  544. };
  545. }
  546. /**
  547. * This provider allows global configuration of the template path used by the dir-pagination-controls directive.
  548. */
  549. function paginationTemplateProvider() {
  550. var templatePath = 'angularUtils.directives.dirPagination.template';
  551. var templateString;
  552. /**
  553. * Set a templateUrl to be used by all instances of <dir-pagination-controls>
  554. * @param {String} path
  555. */
  556. this.setPath = function(path) {
  557. templatePath = path;
  558. };
  559. /**
  560. * Set a string of HTML to be used as a template by all instances
  561. * of <dir-pagination-controls>. If both a path *and* a string have been set,
  562. * the string takes precedence.
  563. * @param {String} str
  564. */
  565. this.setString = function(str) {
  566. templateString = str;
  567. };
  568. this.$get = function() {
  569. return {
  570. getPath: function() {
  571. return templatePath;
  572. },
  573. getString: function() {
  574. return templateString;
  575. }
  576. };
  577. };
  578. }
  579. })();