mirror of
https://github.com/syncthing/syncthing.git
synced 2024-11-18 03:18:57 -07:00
6e07742fe9
GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3108
654 lines
28 KiB
JavaScript
654 lines
28 KiB
JavaScript
/**
|
|
* 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>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
(function() {
|
|
|
|
/**
|
|
* Config
|
|
*/
|
|
var moduleName = 'angularUtils.directives.dirPagination';
|
|
var DEFAULT_ID = '__default';
|
|
|
|
/**
|
|
* Module
|
|
*/
|
|
angular.module(moduleName, [])
|
|
.directive('dirPaginate', ['$compile', '$parse', 'paginationService', dirPaginateDirective])
|
|
.directive('dirPaginateNoCompile', noCompileDirective)
|
|
.directive('dirPaginationControls', ['paginationService', 'paginationTemplate', dirPaginationControlsDirective])
|
|
.filter('itemsPerPage', ['paginationService', itemsPerPageFilter])
|
|
.service('paginationService', paginationService)
|
|
.provider('paginationTemplate', paginationTemplateProvider)
|
|
.run(['$templateCache',dirPaginationControlsTemplateInstaller]);
|
|
|
|
function dirPaginateDirective($compile, $parse, paginationService) {
|
|
|
|
return {
|
|
terminal: true,
|
|
multiElement: true,
|
|
priority: 100,
|
|
compile: dirPaginationCompileFn
|
|
};
|
|
|
|
function dirPaginationCompileFn(tElement, tAttrs){
|
|
|
|
var expression = tAttrs.dirPaginate;
|
|
// regex taken directly from https://github.com/angular/angular.js/blob/v1.4.x/src/ng/directive/ngRepeat.js#L339
|
|
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*$/);
|
|
|
|
var filterPattern = /\|\s*itemsPerPage\s*:\s*(.*\(\s*\w*\)|([^\)]*?(?=\s+as\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);
|
|
|
|
addNoCompileAttributes(tElement);
|
|
|
|
// If any value is specified for paginationId, we register the un-evaluated expression at this stage for the benefit of any
|
|
// dir-pagination-controls directives that may be looking for this ID.
|
|
var rawId = tAttrs.paginationId || DEFAULT_ID;
|
|
paginationService.registerInstance(rawId);
|
|
|
|
return function dirPaginationLinkFn(scope, element, attrs){
|
|
|
|
// Now that we have access to the `scope` we can interpolate any expression given in the paginationId attribute and
|
|
// potentially register a new ID if it evaluates to a different value than the rawId.
|
|
var paginationId = $parse(attrs.paginationId)(scope) || attrs.paginationId || DEFAULT_ID;
|
|
// In case rawId != paginationId we deregister using rawId for the sake of general cleanliness
|
|
// before registering using paginationId
|
|
paginationService.deregisterInstance(rawId);
|
|
paginationService.registerInstance(paginationId);
|
|
|
|
var repeatExpression = getRepeatExpression(expression, paginationId);
|
|
addNgRepeatToElement(element, attrs, repeatExpression);
|
|
|
|
removeTemporaryAttributes(element);
|
|
var compiled = $compile(element);
|
|
|
|
var currentPageGetter = makeCurrentPageGetterFn(scope, attrs, paginationId);
|
|
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 {
|
|
paginationService.setAsyncModeFalse(paginationId);
|
|
scope.$watchCollection(function() {
|
|
return collectionGetter(scope);
|
|
}, function(collection) {
|
|
if (collection) {
|
|
var collectionLength = (collection instanceof Array) ? collection.length : Object.keys(collection).length;
|
|
paginationService.setCollectionLength(paginationId, collectionLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Delegate to the link function returned by the new compilation of the ng-repeat
|
|
compiled(scope);
|
|
|
|
// When the scope is destroyed, we make sure to remove the reference to it in paginationService
|
|
// so that it can be properly garbage collected
|
|
scope.$on('$destroy', function destroyDirPagination() {
|
|
paginationService.deregisterInstance(paginationId);
|
|
});
|
|
};
|
|
}
|
|
|
|
/**
|
|
* If a pagination id has been specified, we need to check that it is present as the second argument passed to
|
|
* the itemsPerPage filter. If it is not there, we add it and return the modified expression.
|
|
*
|
|
* @param expression
|
|
* @param paginationId
|
|
* @returns {*}
|
|
*/
|
|
function getRepeatExpression(expression, paginationId) {
|
|
var repeatExpression,
|
|
idDefinedInFilter = !!expression.match(/(\|\s*itemsPerPage\s*:[^|]*:[^|]*)/);
|
|
|
|
if (paginationId !== DEFAULT_ID && !idDefinedInFilter) {
|
|
repeatExpression = expression.replace(/(\|\s*itemsPerPage\s*:\s*[^|\s]*)/, "$1 : '" + paginationId + "'");
|
|
} else {
|
|
repeatExpression = expression;
|
|
}
|
|
|
|
return repeatExpression;
|
|
}
|
|
|
|
/**
|
|
* Adds the ng-repeat directive to the element. In the case of multi-element (-start, -end) it adds the
|
|
* appropriate multi-element ng-repeat to the first and last element in the range.
|
|
* @param element
|
|
* @param attrs
|
|
* @param repeatExpression
|
|
*/
|
|
function addNgRepeatToElement(element, attrs, repeatExpression) {
|
|
if (element[0].hasAttribute('dir-paginate-start') || element[0].hasAttribute('data-dir-paginate-start')) {
|
|
// using multiElement mode (dir-paginate-start, dir-paginate-end)
|
|
attrs.$set('ngRepeatStart', repeatExpression);
|
|
element.eq(element.length - 1).attr('ng-repeat-end', true);
|
|
} else {
|
|
attrs.$set('ngRepeat', repeatExpression);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adds the dir-paginate-no-compile directive to each element in the tElement range.
|
|
* @param tElement
|
|
*/
|
|
function addNoCompileAttributes(tElement) {
|
|
angular.forEach(tElement, function(el) {
|
|
if (el.nodeType === 1) {
|
|
angular.element(el).attr('dir-paginate-no-compile', true);
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Removes the variations on dir-paginate (data-, -start, -end) and the dir-paginate-no-compile directives.
|
|
* @param element
|
|
*/
|
|
function removeTemporaryAttributes(element) {
|
|
angular.forEach(element, function(el) {
|
|
if (el.nodeType === 1) {
|
|
angular.element(el).removeAttr('dir-paginate-no-compile');
|
|
}
|
|
});
|
|
element.eq(0).removeAttr('dir-paginate-start').removeAttr('dir-paginate').removeAttr('data-dir-paginate-start').removeAttr('data-dir-paginate');
|
|
element.eq(element.length - 1).removeAttr('dir-paginate-end').removeAttr('data-dir-paginate-end');
|
|
}
|
|
|
|
/**
|
|
* Creates a getter function for the current-page attribute, using the expression provided or a default value if
|
|
* no current-page expression was specified.
|
|
*
|
|
* @param scope
|
|
* @param attrs
|
|
* @param paginationId
|
|
* @returns {*}
|
|
*/
|
|
function makeCurrentPageGetterFn(scope, attrs, paginationId) {
|
|
var currentPageGetter;
|
|
if (attrs.currentPage) {
|
|
currentPageGetter = $parse(attrs.currentPage);
|
|
} else {
|
|
// If the current-page attribute was not set, we'll make our own.
|
|
// Replace any non-alphanumeric characters which might confuse
|
|
// the $parse service and give unexpected results.
|
|
// See https://github.com/michaelbromley/angularUtils/issues/233
|
|
var defaultCurrentPage = (paginationId + '__currentPage').replace(/\W/g, '_');
|
|
scope[defaultCurrentPage] = 1;
|
|
currentPageGetter = $parse(defaultCurrentPage);
|
|
}
|
|
return currentPageGetter;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This is a helper directive that allows correct compilation when in multi-element mode (ie dir-paginate-start, dir-paginate-end).
|
|
* It is dynamically added to all elements in the dir-paginate compile function, and it prevents further compilation of
|
|
* any inner directives. It is then removed in the link function, and all inner directives are then manually compiled.
|
|
*/
|
|
function noCompileDirective() {
|
|
return {
|
|
priority: 5000,
|
|
terminal: true
|
|
};
|
|
}
|
|
|
|
function dirPaginationControlsTemplateInstaller($templateCache) {
|
|
$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)">«</a></li><li ng-if="directionLinks" ng-class="{ disabled : pagination.current == 1 }"><a href="" ng-click="setCurrent(pagination.current - 1)">‹</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)">›</a></li><li ng-if="boundaryLinks" ng-class="{ disabled : pagination.current == pagination.last }"><a href="" ng-click="setCurrent(pagination.last)">»</a></li></ul>');
|
|
}
|
|
|
|
function dirPaginationControlsDirective(paginationService, paginationTemplate) {
|
|
|
|
var numberRegex = /^\d+$/;
|
|
|
|
var DDO = {
|
|
restrict: 'AE',
|
|
scope: {
|
|
maxSize: '=?',
|
|
onPageChange: '&?',
|
|
paginationId: '=?',
|
|
autoHide: '=?'
|
|
},
|
|
link: dirPaginationControlsLinkFn
|
|
};
|
|
|
|
// We need to check the paginationTemplate service to see whether a template path or
|
|
// string has been specified, and add the `template` or `templateUrl` property to
|
|
// the DDO as appropriate. The order of priority to decide which template to use is
|
|
// (highest priority first):
|
|
// 1. paginationTemplate.getString()
|
|
// 2. attrs.templateUrl
|
|
// 3. paginationTemplate.getPath()
|
|
var templateString = paginationTemplate.getString();
|
|
if (templateString !== undefined) {
|
|
DDO.template = templateString;
|
|
} else {
|
|
DDO.templateUrl = function(elem, attrs) {
|
|
return attrs.templateUrl || paginationTemplate.getPath();
|
|
};
|
|
}
|
|
return DDO;
|
|
|
|
function dirPaginationControlsLinkFn(scope, element, attrs) {
|
|
|
|
// rawId is the un-interpolated value of the pagination-id attribute. This is only important when the corresponding dir-paginate directive has
|
|
// 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
|
|
// no corresponding dir-paginate directive and wrongly throwing an exception.
|
|
var rawId = attrs.paginationId || DEFAULT_ID;
|
|
var paginationId = scope.paginationId || attrs.paginationId || DEFAULT_ID;
|
|
|
|
if (!paginationService.isRegistered(paginationId) && !paginationService.isRegistered(rawId)) {
|
|
var idMessage = (paginationId !== DEFAULT_ID) ? ' (id: ' + paginationId + ') ' : ' ';
|
|
if (window.console) {
|
|
console.warn('Pagination directive: the pagination controls' + idMessage + 'cannot be used without the corresponding pagination directive, which was not found at link time.');
|
|
}
|
|
}
|
|
|
|
if (!scope.maxSize) { scope.maxSize = 9; }
|
|
scope.autoHide = scope.autoHide === undefined ? true : scope.autoHide;
|
|
scope.directionLinks = angular.isDefined(attrs.directionLinks) ? scope.$parent.$eval(attrs.directionLinks) : true;
|
|
scope.boundaryLinks = angular.isDefined(attrs.boundaryLinks) ? scope.$parent.$eval(attrs.boundaryLinks) : false;
|
|
|
|
var paginationRange = Math.max(scope.maxSize, 5);
|
|
scope.pages = [];
|
|
scope.pagination = {
|
|
last: 1,
|
|
current: 1
|
|
};
|
|
scope.range = {
|
|
lower: 1,
|
|
upper: 1,
|
|
total: 1
|
|
};
|
|
|
|
scope.$watch('maxSize', function(val) {
|
|
if (val) {
|
|
paginationRange = Math.max(scope.maxSize, 5);
|
|
generatePagination();
|
|
}
|
|
});
|
|
|
|
scope.$watch(function() {
|
|
if (paginationService.isRegistered(paginationId)) {
|
|
return (paginationService.getCollectionLength(paginationId) + 1) * paginationService.getItemsPerPage(paginationId);
|
|
}
|
|
}, function(length) {
|
|
if (0 < length) {
|
|
generatePagination();
|
|
}
|
|
});
|
|
|
|
scope.$watch(function() {
|
|
if (paginationService.isRegistered(paginationId)) {
|
|
return (paginationService.getItemsPerPage(paginationId));
|
|
}
|
|
}, function(current, previous) {
|
|
if (current != previous && typeof previous !== 'undefined') {
|
|
goToPage(scope.pagination.current);
|
|
}
|
|
});
|
|
|
|
scope.$watch(function() {
|
|
if (paginationService.isRegistered(paginationId)) {
|
|
return paginationService.getCurrentPage(paginationId);
|
|
}
|
|
}, function(currentPage, previousPage) {
|
|
if (currentPage != previousPage) {
|
|
goToPage(currentPage);
|
|
}
|
|
});
|
|
|
|
scope.setCurrent = function(num) {
|
|
if (paginationService.isRegistered(paginationId) && isValidPageNumber(num)) {
|
|
num = parseInt(num, 10);
|
|
paginationService.setCurrentPage(paginationId, num);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Custom "track by" function which allows for duplicate "..." entries on long lists,
|
|
* yet fixes the problem of wrongly-highlighted links which happens when using
|
|
* "track by $index" - see https://github.com/michaelbromley/angularUtils/issues/153
|
|
* @param id
|
|
* @param index
|
|
* @returns {string}
|
|
*/
|
|
scope.tracker = function(id, index) {
|
|
return id + '_' + index;
|
|
};
|
|
|
|
function goToPage(num) {
|
|
if (paginationService.isRegistered(paginationId) && isValidPageNumber(num)) {
|
|
var oldPageNumber = scope.pagination.current;
|
|
|
|
scope.pages = generatePagesArray(num, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
|
|
scope.pagination.current = num;
|
|
updateRangeValues();
|
|
|
|
// if a callback has been set, then call it with the page number as the first argument
|
|
// and the previous page number as a second argument
|
|
if (scope.onPageChange) {
|
|
scope.onPageChange({
|
|
newPageNumber : num,
|
|
oldPageNumber : oldPageNumber
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
function generatePagination() {
|
|
if (paginationService.isRegistered(paginationId)) {
|
|
var page = parseInt(paginationService.getCurrentPage(paginationId)) || 1;
|
|
scope.pages = generatePagesArray(page, paginationService.getCollectionLength(paginationId), paginationService.getItemsPerPage(paginationId), paginationRange);
|
|
scope.pagination.current = page;
|
|
scope.pagination.last = scope.pages[scope.pages.length - 1];
|
|
if (scope.pagination.last < scope.pagination.current) {
|
|
scope.setCurrent(scope.pagination.last);
|
|
} else {
|
|
updateRangeValues();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This function updates the values (lower, upper, total) of the `scope.range` object, which can be used in the pagination
|
|
* template to display the current page range, e.g. "showing 21 - 40 of 144 results";
|
|
*/
|
|
function updateRangeValues() {
|
|
if (paginationService.isRegistered(paginationId)) {
|
|
var currentPage = paginationService.getCurrentPage(paginationId),
|
|
itemsPerPage = paginationService.getItemsPerPage(paginationId),
|
|
totalItems = paginationService.getCollectionLength(paginationId);
|
|
|
|
scope.range.lower = (currentPage - 1) * itemsPerPage + 1;
|
|
scope.range.upper = Math.min(currentPage * itemsPerPage, totalItems);
|
|
scope.range.total = totalItems;
|
|
}
|
|
}
|
|
function isValidPageNumber(num) {
|
|
return (numberRegex.test(num) && (0 < num && num <= scope.pagination.last));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This filter slices the collection into pages based on the current page number and number of items per page.
|
|
* @param paginationService
|
|
* @returns {Function}
|
|
*/
|
|
function itemsPerPageFilter(paginationService) {
|
|
|
|
return function(collection, itemsPerPage, paginationId) {
|
|
if (typeof (paginationId) === 'undefined') {
|
|
paginationId = DEFAULT_ID;
|
|
}
|
|
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 (angular.isObject(collection)) {
|
|
itemsPerPage = parseInt(itemsPerPage) || 9999999999;
|
|
if (paginationService.isAsyncMode(paginationId)) {
|
|
start = 0;
|
|
} else {
|
|
start = (paginationService.getCurrentPage(paginationId) - 1) * itemsPerPage;
|
|
}
|
|
end = start + itemsPerPage;
|
|
paginationService.setItemsPerPage(paginationId, itemsPerPage);
|
|
|
|
if (collection instanceof Array) {
|
|
// the array just needs to be sliced
|
|
return collection.slice(start, end);
|
|
} else {
|
|
// in the case of an object, we need to get an array of keys, slice that, then map back to
|
|
// the original object.
|
|
var slicedObject = {};
|
|
angular.forEach(keys(collection).slice(start, end), function(key) {
|
|
slicedObject[key] = collection[key];
|
|
});
|
|
return slicedObject;
|
|
}
|
|
} else {
|
|
return collection;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Shim for the Object.keys() method which does not exist in IE < 9
|
|
* @param obj
|
|
* @returns {Array}
|
|
*/
|
|
function keys(obj) {
|
|
if (!Object.keys) {
|
|
var objKeys = [];
|
|
for (var i in obj) {
|
|
if (obj.hasOwnProperty(i)) {
|
|
objKeys.push(i);
|
|
}
|
|
}
|
|
return objKeys;
|
|
} else {
|
|
return Object.keys(obj);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This service allows the various parts of the module to communicate and stay in sync.
|
|
*/
|
|
function paginationService() {
|
|
|
|
var instances = {};
|
|
var lastRegisteredInstance;
|
|
|
|
this.registerInstance = function(instanceId) {
|
|
if (typeof instances[instanceId] === 'undefined') {
|
|
instances[instanceId] = {
|
|
asyncMode: false
|
|
};
|
|
lastRegisteredInstance = instanceId;
|
|
}
|
|
};
|
|
|
|
this.deregisterInstance = function(instanceId) {
|
|
delete instances[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) {
|
|
var parser = instances[instanceId].currentPageParser;
|
|
return parser ? parser(instances[instanceId].context) : 1;
|
|
};
|
|
|
|
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.setAsyncModeFalse = function(instanceId) {
|
|
instances[instanceId].asyncMode = false;
|
|
};
|
|
|
|
this.isAsyncMode = function(instanceId) {
|
|
return instances[instanceId].asyncMode;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* This provider allows global configuration of the template path used by the dir-pagination-controls directive.
|
|
*/
|
|
function paginationTemplateProvider() {
|
|
|
|
var templatePath = 'angularUtils.directives.dirPagination.template';
|
|
var templateString;
|
|
|
|
/**
|
|
* Set a templateUrl to be used by all instances of <dir-pagination-controls>
|
|
* @param {String} path
|
|
*/
|
|
this.setPath = function(path) {
|
|
templatePath = path;
|
|
};
|
|
|
|
/**
|
|
* Set a string of HTML to be used as a template by all instances
|
|
* of <dir-pagination-controls>. If both a path *and* a string have been set,
|
|
* the string takes precedence.
|
|
* @param {String} str
|
|
*/
|
|
this.setString = function(str) {
|
|
templateString = str;
|
|
};
|
|
|
|
this.$get = function() {
|
|
return {
|
|
getPath: function() {
|
|
return templatePath;
|
|
},
|
|
getString: function() {
|
|
return templateString;
|
|
}
|
|
};
|
|
};
|
|
}
|
|
})();
|