Created
May 6, 2016 05:17
-
-
Save niaher/f01c5829862567fe66d640261dc97e6b to your computer and use it in GitHub Desktop.
"pagination" factory for angular
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
angular.module("paginator", []) | |
.service("base64", function() { | |
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; | |
function utf8Encode(string) { | |
string = string.replace(/\r\n/g, "\n"); | |
var utftext = ""; | |
for (var n = 0; n < string.length; n++) { | |
var c = string.charCodeAt(n); | |
if (c < 128) { | |
utftext += String.fromCharCode(c); | |
} else if ((c > 127) && (c < 2048)) { | |
utftext += String.fromCharCode((c >> 6) | 192); | |
utftext += String.fromCharCode((c & 63) | 128); | |
} else { | |
utftext += String.fromCharCode((c >> 12) | 224); | |
utftext += String.fromCharCode(((c >> 6) & 63) | 128); | |
utftext += String.fromCharCode((c & 63) | 128); | |
} | |
} | |
return utftext; | |
} | |
function utf8Decode(utftext) { | |
var string = "", i = 0, c, c2, c3; | |
while (i < utftext.length) { | |
c = utftext.charCodeAt(i); | |
if (c < 128) { | |
string += String.fromCharCode(c); | |
i++; | |
} else if ((c > 191) && (c < 224)) { | |
c2 = utftext.charCodeAt(i + 1); | |
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); | |
i += 2; | |
} else { | |
c2 = utftext.charCodeAt(i + 1); | |
c3 = utftext.charCodeAt(i + 2); | |
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); | |
i += 3; | |
} | |
} | |
return string; | |
} | |
this.encode = function(input) { | |
var output = ""; | |
var chr1, chr2, chr3, enc1, enc2, enc3, enc4; | |
var i = 0; | |
input = utf8Encode(input); | |
while (i < input.length) { | |
chr1 = input.charCodeAt(i++); | |
chr2 = input.charCodeAt(i++); | |
chr3 = input.charCodeAt(i++); | |
enc1 = chr1 >> 2; | |
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); | |
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); | |
enc4 = chr3 & 63; | |
if (isNaN(chr2)) { | |
enc3 = enc4 = 64; | |
} else if (isNaN(chr3)) { | |
enc4 = 64; | |
} | |
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4); | |
} | |
return output; | |
}; | |
this.decode = function(input) { | |
var output = ""; | |
var chr1, chr2, chr3; | |
var enc1, enc2, enc3, enc4; | |
var i = 0; | |
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); | |
while (i < input.length) { | |
enc1 = keyStr.indexOf(input.charAt(i++)); | |
enc2 = keyStr.indexOf(input.charAt(i++)); | |
enc3 = keyStr.indexOf(input.charAt(i++)); | |
enc4 = keyStr.indexOf(input.charAt(i++)); | |
chr1 = (enc1 << 2) | (enc2 >> 4); | |
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); | |
chr3 = ((enc3 & 3) << 6) | enc4; | |
output = output + String.fromCharCode(chr1); | |
if (enc3 !== 64) { | |
output = output + String.fromCharCode(chr2); | |
} | |
if (enc4 !== 64) { | |
output = output + String.fromCharCode(chr3); | |
} | |
} | |
return utf8Decode(output); | |
}; | |
}) | |
.factory("paginator", [ | |
"$location", "base64", "$rootScope", function($location, base64, $rootScope) { | |
function getRouteParameterStore(useLocation) { | |
if (useLocation || angular.isUndefined(useLocation)) { | |
return { | |
get: function(key) { | |
return $location.search()[key]; | |
}, | |
set: function(value) { | |
var current = $location.search(); | |
var newValue = angular.extend(current, value); | |
return $location.search(newValue); | |
} | |
}; | |
} else { | |
return { | |
value: {}, | |
get: function(key) { | |
return this.value[key]; | |
}, | |
set: function(value) { | |
return this.value = value; | |
} | |
}; | |
} | |
} | |
function parseParams(p) { | |
var d = base64.decode(p).replace(/\-/gi, "=").replace(/[\x00-\x1F\x7F-\x9F]/g, "") || "{}"; | |
return JSON.parse(d); | |
} | |
function removeEmtpyProperties(obj) { | |
var result = obj; | |
for (var propertyName in result) { | |
if (result.hasOwnProperty(propertyName)) { | |
var value = result[propertyName]; | |
if (angular.isUndefined(value) || value == null || value.length === 0) { | |
delete result[propertyName]; | |
} | |
} | |
} | |
return result; | |
} | |
function stringifyParams(params) { | |
var compressedParams = removeEmtpyProperties(params); | |
if (Object.keys(compressedParams).length === 0) { | |
return ""; | |
} | |
var s = JSON.stringify(compressedParams); | |
return base64.encode(s).replace(/=/gi, "-"); | |
} | |
function initFromRoute(paginator, routeParameters) { | |
paginator.currentPage = parseInt(routeParameters.get("p"), 10) || 1; | |
paginator.pageSize = parseInt(routeParameters.get("s"), 10) || options.pageSize || 10; | |
paginator.query = parseParams(routeParameters.get("q") || ""); | |
// Set the total items to make sure it fits the currentPage. This is needed to make | |
// sure that the pager renders correctly and doesn't reset currentPage to 1. | |
paginator.totalItems = paginator.currentPage * paginator.pageSize; | |
} | |
function Paginator(options) { | |
var self = this; | |
this.items = []; | |
this.currentPage = 1; | |
var routeParameters = getRouteParameterStore(options.useLocation); | |
initFromRoute(this, routeParameters); | |
var reading = false; | |
this.render = function(items, inlineCount) { | |
self.items = items; | |
self.totalItems = inlineCount; | |
reading = false; | |
}; | |
this.read = function(page) { | |
if (!reading) { | |
reading = true; | |
if (angular.isUndefined(page) || page == null) { | |
page = self.currentPage; | |
} | |
self.currentPage = page; | |
var pageSize = parseInt(self.pageSize, 10); | |
routeParameters.set({ p: page, s: self.pageSize, q: stringifyParams(self.query) }); | |
options.read(self.query, page, pageSize).then(function(data) { | |
self.render(data.results, data.inlineCount, page); | |
}); | |
} | |
}; | |
$rootScope.$on("$locationChangeSuccess", function () { | |
initFromRoute(self, routeParameters); | |
self.read(); | |
}); | |
return this; | |
} | |
Paginator.prototype.bindToScope = function($scope, property) { | |
var paginator = this; | |
$scope[property] = paginator; | |
var baseRender = this.render; | |
this.render = function(items, inlineCount, page) { | |
$scope.$evalAsync(function() { | |
baseRender(items, inlineCount, page); | |
}); | |
}; | |
$scope.$watch(property + ".currentPage", function(newValue, oldValue) { | |
if (newValue !== oldValue) { | |
paginator.read(newValue); | |
} | |
}); | |
$scope.$watch(property + ".pageSize", function(newValue, oldValue) { | |
if (newValue !== oldValue) { | |
paginator.read(1); | |
} | |
}); | |
return this; | |
}; | |
return function(options) { | |
return new Paginator(options); | |
}; | |
} | |
]); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment