diff --git a/css/bwa.css b/css/bwa.css
index 8236559a..703def3e 100644
--- a/css/bwa.css
+++ b/css/bwa.css
@@ -134,3 +134,5 @@ img.AngularJS-large {
.modal-backdrop.fade.in {
display: block;
}
+
+.pagination a { cursor: pointer; }
diff --git a/index.html b/index.html
index 14a145a7..9c037b8a 100644
--- a/index.html
+++ b/index.html
@@ -38,7 +38,7 @@
$script('//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js', function() {
$script(['//ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js',
- 'js/bootstrap.min.js', 'js/bwa.js'], function() {
+ 'js/bootstrap.min.js', 'js/ui-bootstrap-custom-0.8.0.min.js', 'js/bwa.js'], function() {
$().dropdown();
angular.bootstrap(document, ['bwaApp']);
});
@@ -133,7 +133,15 @@
@@ -197,29 +205,16 @@
{{project.name}}
-
diff --git a/js/bwa.js b/js/bwa.js
index 64155adf..91f7e789 100644
--- a/js/bwa.js
+++ b/js/bwa.js
@@ -1,4 +1,4 @@
-var app = angular.module('bwaApp', []);
+var app = angular.module('bwaApp', ['ui.bootstrap']);
app.directive('bwaProject', function() {
return {
@@ -107,7 +107,7 @@ app.controller('BWAController', function ($scope, $http, $filter) {
$scope.error = "Cannot get data from the server";
});
- var num = 2;
+ var numCols = 2;
$scope.filteredProjects = [];
$scope.groupedProjects = [];
@@ -139,43 +139,50 @@ app.controller('BWAController', function ($scope, $http, $filter) {
$scope.filteredProjects = $filter('orderBy')($scope.filteredProjects, $scope.sortPrep);
}
- $scope.currentPage = 0;
+ //Pagination was born yesterday, knows nothing about zero
+ //Corrected with "currentPage-1" for the index in the view
+ //Seems hacky, but didn't want to modify the vendor paginator
+ $scope.currentPage = 1;
$scope.group();
};
// re-calculate groupedProjects in place
$scope.group = function () {
- $scope.groupedProjects.length = Math.ceil($scope.filteredProjects.length / num);
+ $scope.groupedProjects.length = Math.ceil($scope.filteredProjects.length / numCols);
for (var i = 0; i < $scope.filteredProjects.length; i++) {
- if (i % num === 0) {
- $scope.groupedProjects[Math.floor(i / num)] = [ $scope.filteredProjects[i] ];
+ if (i % numCols === 0) {
+ $scope.groupedProjects[Math.floor(i / numCols)] = [ $scope.filteredProjects[i] ];
} else {
- $scope.groupedProjects[Math.floor(i / num)].push($scope.filteredProjects[i]);
+ $scope.groupedProjects[Math.floor(i / numCols)].push($scope.filteredProjects[i]);
}
}
- if ($scope.filteredProjects.length % num !== 0) {
- $scope.groupedProjects[$scope.groupedProjects.length - 1].length = num - ($scope.filteredProjects.length % num);
+ if ($scope.filteredProjects.length % numCols !== 0) {
+ $scope.groupedProjects[$scope.groupedProjects.length - 1].length = numCols - ($scope.filteredProjects.length % numCols);
}
$scope.groupToPages();
};
- var itemsPerPage = 5;
+ var itemsPerCol = 5;
+ $scope.itemsPerPage = itemsPerCol*numCols;
$scope.pagedProjects = [];
- $scope.currentPage = 0;
+ //Pagination was born yesterday, knows nothing about zero
+ //Corrected with "currentPage-1" in the view
+ //Seems hacky, but didn't want to modify the vendor paginator
+ $scope.currentPage = 1;
// calc pages in place
$scope.groupToPages = function () {
$scope.pagedProjects = [];
for (var i = 0; i < $scope.groupedProjects.length; i++) {
- if (i % itemsPerPage === 0) {
- $scope.pagedProjects[Math.floor(i / itemsPerPage)] = [ $scope.groupedProjects[i] ];
+ if (i % itemsPerCol === 0) {
+ $scope.pagedProjects[Math.floor(i / itemsPerCol)] = [ $scope.groupedProjects[i] ];
} else {
- $scope.pagedProjects[Math.floor(i / itemsPerPage)].push($scope.groupedProjects[i]);
+ $scope.pagedProjects[Math.floor(i / itemsPerCol)].push($scope.groupedProjects[i]);
}
}
};
@@ -231,20 +238,4 @@ app.controller('BWAController', function ($scope, $http, $filter) {
return ret;
};
- $scope.prevPage = function () {
- if ($scope.currentPage > 0) {
- $scope.currentPage--;
- }
- };
-
- $scope.nextPage = function () {
- if ($scope.currentPage < $scope.pagedProjects.length - 1) {
- $scope.currentPage++;
- }
- };
-
- $scope.setPage = function () {
- $scope.currentPage = this.n;
- };
-
});
diff --git a/js/ui-bootstrap-custom-0.8.0.js b/js/ui-bootstrap-custom-0.8.0.js
new file mode 100644
index 00000000..10cb5c04
--- /dev/null
+++ b/js/ui-bootstrap-custom-0.8.0.js
@@ -0,0 +1,242 @@
+angular.module("ui.bootstrap", ["ui.bootstrap.pagination"]);
+angular.module('ui.bootstrap.pagination', [])
+
+.controller('PaginationController', ['$scope', '$attrs', '$parse', '$interpolate', function ($scope, $attrs, $parse, $interpolate) {
+ var self = this,
+ setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop;
+
+ 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.page === 1;
+ };
+ this.noNext = function() {
+ return this.page === $scope.totalPages;
+ };
+
+ this.isActive = function(page) {
+ return this.page === page;
+ };
+
+ this.calculateTotalPages = function() {
+ var totalPages = this.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / this.itemsPerPage);
+ return Math.max(totalPages || 0, 1);
+ };
+
+ 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;
+ if (this.page > 0 && this.page <= $scope.totalPages) {
+ $scope.pages = this.getPages(this.page, $scope.totalPages);
+ }
+ };
+
+ $scope.selectPage = function(page) {
+ if ( ! self.isActive(page) && page > 0 && page <= $scope.totalPages) {
+ $scope.page = page;
+ $scope.onSelectPage({ page: page });
+ }
+ };
+
+ $scope.$watch('page', function() {
+ self.render();
+ });
+
+ $scope.$watch('totalItems', function() {
+ $scope.totalPages = self.calculateTotalPages();
+ });
+
+ $scope.$watch('totalPages', function(value) {
+ setNumPages($scope.$parent, value); // Readonly variable
+
+ if ( self.page > value ) {
+ $scope.selectPage(value);
+ } else {
+ self.render();
+ }
+ });
+}])
+
+.constant('paginationConfig', {
+ itemsPerPage: 10,
+ boundaryLinks: false,
+ directionLinks: true,
+ firstText: 'First',
+ previousText: 'Previous',
+ nextText: 'Next',
+ lastText: 'Last',
+ rotate: true
+})
+
+.directive('pagination', ['$parse', 'paginationConfig', function($parse, config) {
+ return {
+ restrict: 'EA',
+ scope: {
+ page: '=',
+ totalItems: '=',
+ onSelectPage:' &'
+ },
+ controller: 'PaginationController',
+ templateUrl: 'template/pagination/pagination.html',
+ replace: true,
+ link: function(scope, element, attrs, paginationCtrl) {
+
+ // Setup configuration parameters
+ 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) {
+ return {
+ number: number,
+ text: text,
+ active: isActive,
+ disabled: isDisabled
+ };
+ }
+
+ paginationCtrl.getPages = function(currentPage, totalPages) {
+ var pages = [];
+
+ // Default page limits
+ 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(currentPage - Math.floor(maxSize/2), 1);
+ endPage = startPage + maxSize - 1;
+
+ // Adjust if limit is exceeded
+ if (endPage > totalPages) {
+ endPage = totalPages;
+ startPage = endPage - maxSize + 1;
+ }
+ } else {
+ // Visible pages are paginated with maxSize
+ startPage = ((Math.ceil(currentPage / maxSize) - 1) * maxSize) + 1;
+
+ // Adjust last page if limit is exceeded
+ 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);
+ pages.push(page);
+ }
+
+ // Add links to move between page sets
+ if ( isMaxSized && ! rotate ) {
+ if ( startPage > 1 ) {
+ var previousPageSet = makePage(startPage - 1, '...', false, false);
+ pages.unshift(previousPageSet);
+ }
+
+ if ( endPage < totalPages ) {
+ var nextPageSet = makePage(endPage + 1, '...', false, false);
+ pages.push(nextPageSet);
+ }
+ }
+
+ // Add previous & next links
+ if (directionLinks) {
+ var previousPage = makePage(currentPage - 1, previousText, false, paginationCtrl.noPrevious());
+ pages.unshift(previousPage);
+
+ 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());
+ pages.unshift(firstPage);
+
+ var lastPage = makePage(totalPages, lastText, false, paginationCtrl.noNext());
+ pages.push(lastPage);
+ }
+
+ return pages;
+ };
+ }
+ };
+}])
+
+.constant('pagerConfig', {
+ itemsPerPage: 10,
+ previousText: '« Previous',
+ nextText: 'Next »',
+ align: true
+})
+
+.directive('pager', ['pagerConfig', function(config) {
+ return {
+ restrict: 'EA',
+ scope: {
+ page: '=',
+ totalItems: '=',
+ onSelectPage:' &'
+ },
+ controller: 'PaginationController',
+ templateUrl: 'template/pagination/pager.html',
+ replace: true,
+ link: function(scope, element, attrs, paginationCtrl) {
+
+ // Setup configuration parameters
+ var previousText = paginationCtrl.getAttributeValue(attrs.previousText, config.previousText, true),
+ 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 {
+ number: number,
+ text: text,
+ disabled: isDisabled,
+ previous: ( align && isPrevious ),
+ next: ( align && isNext )
+ };
+ }
+
+ paginationCtrl.getPages = function(currentPage) {
+ return [
+ makePage(currentPage - 1, previousText, paginationCtrl.noPrevious(), true, false),
+ makePage(currentPage + 1, nextText, paginationCtrl.noNext(), false, true)
+ ];
+ };
+ }
+ };
+}]);
\ No newline at end of file
diff --git a/js/ui-bootstrap-custom-0.8.0.min.js b/js/ui-bootstrap-custom-0.8.0.min.js
new file mode 100644
index 00000000..269cfcb8
--- /dev/null
+++ b/js/ui-bootstrap-custom-0.8.0.min.js
@@ -0,0 +1 @@
+angular.module("ui.bootstrap",["ui.bootstrap.pagination"]);angular.module("ui.bootstrap.pagination",[]).controller("PaginationController",["$scope","$attrs","$parse","$interpolate",function(e,t,n,r){var i=this,s=t.numPages?n(t.numPages).assign:angular.noop;this.init=function(r){t.itemsPerPage?e.$parent.$watch(n(t.itemsPerPage),function(t){i.itemsPerPage=parseInt(t,10);e.totalPages=i.calculateTotalPages()}):this.itemsPerPage=r};this.noPrevious=function(){return this.page===1};this.noNext=function(){return this.page===e.totalPages};this.isActive=function(e){return this.page===e};this.calculateTotalPages=function(){var t=this.itemsPerPage<1?1:Math.ceil(e.totalItems/this.itemsPerPage);return Math.max(t||0,1)};this.getAttributeValue=function(t,n,i){return angular.isDefined(t)?i?r(t)(e.$parent):e.$parent.$eval(t):n};this.render=function(){this.page=parseInt(e.page,10)||1;this.page>0&&this.page<=e.totalPages&&(e.pages=this.getPages(this.page,e.totalPages))};e.selectPage=function(t){if(!i.isActive(t)&&t>0&&t<=e.totalPages){e.page=t;e.onSelectPage({page:t})}};e.$watch("page",function(){i.render()});e.$watch("totalItems",function(){e.totalPages=i.calculateTotalPages()});e.$watch("totalPages",function(t){s(e.$parent,t);i.page>t?e.selectPage(t):i.render()})}]).constant("paginationConfig",{itemsPerPage:10,boundaryLinks:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0}).directive("pagination",["$parse","paginationConfig",function(e,t){return{restrict:"EA",scope:{page:"=",totalItems:"=",onSelectPage:" &"},controller:"PaginationController",templateUrl:"template/pagination/pagination.html",replace:!0,link:function(n,r,i,s){function d(e,t,n,r){return{number:e,text:t,active:n,disabled:r}}var o,u=s.getAttributeValue(i.boundaryLinks,t.boundaryLinks),a=s.getAttributeValue(i.directionLinks,t.directionLinks),f=s.getAttributeValue(i.firstText,t.firstText,!0),l=s.getAttributeValue(i.previousText,t.previousText,!0),c=s.getAttributeValue(i.nextText,t.nextText,!0),h=s.getAttributeValue(i.lastText,t.lastText,!0),p=s.getAttributeValue(i.rotate,t.rotate);s.init(t.itemsPerPage);i.maxSize&&n.$parent.$watch(e(i.maxSize),function(e){o=parseInt(e,10);s.render()});s.getPages=function(e,t){var n=[],r=1,i=t,v=angular.isDefined(o)&&o
t){i=t;r=i-o+1}}else{r=(Math.ceil(e/o)-1)*o+1;i=Math.min(r+o-1,t)}for(var m=r;m<=i;m++){var g=d(m,m,s.isActive(m),!1);n.push(g)}if(v&&!p){if(r>1){var y=d(r-1,"...",!1,!1);n.unshift(y)}if(i