From 4814c555dcb56276155d512def5f9ca8368fee46 Mon Sep 17 00:00:00 2001 From: IvanBisultanov Date: Mon, 28 Dec 2015 14:05:21 +0300 Subject: [PATCH] implement pagination --- demo/demo.css | 102 ++++++ demo/{app.js => demoApp.js} | 0 dist/dataGrid.css | 102 ++++++ dist/dataGrid.js | 420 ++++++++++++++++++++++++ dist/dataGrid.min.js | 1 + dist/pagination.js | 244 ++++++++++++++ dist/pagination.min.js | 1 + gulpfile.js | 143 ++++---- index.html | 33 +- package.json | 7 - src/css/dataGrid.scss | 122 +++++++ src/css/demo.scss | 36 +- src/html/gridPaginator.html | 6 - src/js/dataGrid.js | 18 +- src/js/demoApp.js | 35 ++ src/js/gridPaginator.html | 6 - src/js/pagination.js | 386 ++++++++++++++-------- src/js/paging.js | 85 ----- src/template/pagination/pagination.html | 12 +- 19 files changed, 1360 insertions(+), 399 deletions(-) create mode 100644 demo/demo.css rename demo/{app.js => demoApp.js} (100%) create mode 100644 dist/dataGrid.css create mode 100644 dist/dataGrid.js create mode 100644 dist/dataGrid.min.js create mode 100644 dist/pagination.js create mode 100644 dist/pagination.min.js create mode 100644 src/css/dataGrid.scss delete mode 100644 src/html/gridPaginator.html create mode 100644 src/js/demoApp.js delete mode 100644 src/js/gridPaginator.html delete mode 100644 src/js/paging.js diff --git a/demo/demo.css b/demo/demo.css new file mode 100644 index 0000000..a4e9252 --- /dev/null +++ b/demo/demo.css @@ -0,0 +1,102 @@ +:focus { + outline: none; } + +.pagination { + display: inline-block; + box-sizing: border-box; } + +.pagination > li { + display: inline-block; + vertical-align: middle; + width: auto; + height: 30px; + position: relative; + border-radius: 2px; + box-sizing: border-box; } + +.pagination a { + color: #444; + font-size: 16px; + padding: 0 10px; + line-height: 30px; + display: inline-block; + text-decoration: none; + box-sizing: border-box; } + .pagination a .md-ripple-container { + border-radius: 2px; } + +.pagination-prev a, +.pagination-next a, +.pagination-first a, +.pagination-last a { + padding: 3px 5px; } + +.pagination-prev svg, +.pagination-next svg, +.pagination-first svg, +.pagination-last svg { + width: 24px; + height: 24px; } + +.pagination-none-svg svg { + display: none !important; } + +.pagination-none-svg .pagination-prev a, +.pagination-none-svg .pagination-next a, +.pagination-none-svg .pagination-first a, +.pagination-none-svg .pagination-last a { + width: 30px; + text-align: center; + line-height: 24px; } + +.pagination-page { + transition: background .1s ease-out, color .1s ease-out; } + .pagination-page.active { + background: #106cc8; } + .pagination-page.active a { + color: #fff; } + +.pagination { + transition: background .1s ease-out, color .1s ease-out; } + .pagination .active { + background: #106cc8; } + .pagination .active a { + color: #fff; } + +.grid-data-table td { + border-bottom: 1px rgba(0, 0, 0, 0.12) solid; + padding: 12px; } + +.grid-data-table th { + padding: 0 12px; + border-bottom: 1px rgba(0, 0, 0, 0.12) solid; } + +th.sortable { + line-height: 24px; + padding-right: 31px; } + th.sortable svg { + height: 18px; + width: 18px; + margin: 0 4px; + transition: fill .25s,-webkit-transform .25s; + transition: fill .25s,transform .25s; + vertical-align: middle; + display: none !important; } + th.sortable.sort-descent { + padding-right: 0; } + th.sortable.sort-descent svg { + display: inline-block !important; } + th.sortable.sort-ascent { + padding-right: 0; } + th.sortable.sort-ascent svg { + display: inline-block !important; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.items-per-page .active { + background: #106cc8; } + .items-per-page .active a { + color: #fff; } + +.items-per-page a { + cursor: pointer; } diff --git a/demo/app.js b/demo/demoApp.js similarity index 100% rename from demo/app.js rename to demo/demoApp.js diff --git a/dist/dataGrid.css b/dist/dataGrid.css new file mode 100644 index 0000000..a4e9252 --- /dev/null +++ b/dist/dataGrid.css @@ -0,0 +1,102 @@ +:focus { + outline: none; } + +.pagination { + display: inline-block; + box-sizing: border-box; } + +.pagination > li { + display: inline-block; + vertical-align: middle; + width: auto; + height: 30px; + position: relative; + border-radius: 2px; + box-sizing: border-box; } + +.pagination a { + color: #444; + font-size: 16px; + padding: 0 10px; + line-height: 30px; + display: inline-block; + text-decoration: none; + box-sizing: border-box; } + .pagination a .md-ripple-container { + border-radius: 2px; } + +.pagination-prev a, +.pagination-next a, +.pagination-first a, +.pagination-last a { + padding: 3px 5px; } + +.pagination-prev svg, +.pagination-next svg, +.pagination-first svg, +.pagination-last svg { + width: 24px; + height: 24px; } + +.pagination-none-svg svg { + display: none !important; } + +.pagination-none-svg .pagination-prev a, +.pagination-none-svg .pagination-next a, +.pagination-none-svg .pagination-first a, +.pagination-none-svg .pagination-last a { + width: 30px; + text-align: center; + line-height: 24px; } + +.pagination-page { + transition: background .1s ease-out, color .1s ease-out; } + .pagination-page.active { + background: #106cc8; } + .pagination-page.active a { + color: #fff; } + +.pagination { + transition: background .1s ease-out, color .1s ease-out; } + .pagination .active { + background: #106cc8; } + .pagination .active a { + color: #fff; } + +.grid-data-table td { + border-bottom: 1px rgba(0, 0, 0, 0.12) solid; + padding: 12px; } + +.grid-data-table th { + padding: 0 12px; + border-bottom: 1px rgba(0, 0, 0, 0.12) solid; } + +th.sortable { + line-height: 24px; + padding-right: 31px; } + th.sortable svg { + height: 18px; + width: 18px; + margin: 0 4px; + transition: fill .25s,-webkit-transform .25s; + transition: fill .25s,transform .25s; + vertical-align: middle; + display: none !important; } + th.sortable.sort-descent { + padding-right: 0; } + th.sortable.sort-descent svg { + display: inline-block !important; } + th.sortable.sort-ascent { + padding-right: 0; } + th.sortable.sort-ascent svg { + display: inline-block !important; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); } + +.items-per-page .active { + background: #106cc8; } + .items-per-page .active a { + color: #fff; } + +.items-per-page a { + cursor: pointer; } diff --git a/dist/dataGrid.js b/dist/dataGrid.js new file mode 100644 index 0000000..5772568 --- /dev/null +++ b/dist/dataGrid.js @@ -0,0 +1,420 @@ +angular.module('dataGrid', []) + .filter('startFrom', function () { + return function (input, start) { + if (input) { + start = +start; + return input.slice(start); + } + return []; + } + }) + .controller('gridController', ['$scope', '$element', '$filter', '$location', 'filtersFactory', function ($scope, $element, $filter, $location, filtersFactory) { + // values by default + $scope._gridOptions = deepFind($scope, $element.attr('grid-options')); + $scope._gridActions = deepFind($scope, $element.attr('grid-actions')); + $scope.serverPagination = $element.attr('server-pagination') === 'true'; + $scope.getDataDelay = $element.attr('get-delay') || 350; + + if (!$scope._gridActions) { + $scope.$parent[$element.attr('grid-actions')] = {}; + $scope._gridActions = $scope.$parent[$element.attr('grid-actions')]; + } + + $scope.filtered = angular.copy($scope._gridOptions.data); + $scope.paginationOptions = $scope._gridOptions.pagination ? angular.copy($scope._gridOptions.pagination) : {}; + $scope.defaultsPaginationOptions = { + itemsPerPage: $scope.paginationOptions.itemsPerPage || 10, + currentPage: $scope.paginationOptions.currentPage || 1 + }; + $scope.paginationOptions = angular.copy($scope.defaultsPaginationOptions); + $scope.sortOptions = $scope._gridOptions.sort ? angular.copy($scope._gridOptions.sort) : {}; + $scope.customFilters = $scope._gridOptions.customFilters ? angular.copy($scope._gridOptions.customFilters) : {}; + $scope.urlSync = $scope._gridOptions.urlSync; + + $scope.$watch('_gridOptions.data', function (newValue) { + if (newValue && newValue.length) { + if ($scope.urlSync) { + parseUrl($location.path()); + } else { + applyFilters(); + } + } + }); + + $scope.sort = function (predicate) { + var direction = $scope.sortOptions.predicate === predicate && $scope.sortOptions.direction === 'desc' ? 'asc' : 'desc'; + $scope.sortOptions.predicate = predicate; + $scope.sortOptions.direction = direction; + $scope.paginationOptions.currentPage = 1; + $scope.reloadGrid(); + }; + + $scope.filter = function () { + $scope.paginationOptions.currentPage = 1; + $scope.reloadGrid(); + }; + + $scope.$on('$locationChangeSuccess', function () { + if ($scope.urlSync || $scope.serverPagination) { + if ($scope.serverPagination) { + clearTimeout($scope.getDataTimeout); + $scope.getDataTimeout = setTimeout(getData, $scope.getDataDelay); + } + parseUrl($location.path()); + } + }); + + $scope.reloadGrid = function () { + if ($scope.urlSync || $scope.serverPagination) { + changePath(); + } else { + applyFilters(); + } + }; + + $scope._gridActions.refresh = $scope.reloadGrid; + $scope._gridActions.filter = $scope.filter; + $scope._gridActions.sort = $scope.sort; + + function changePath() { + var path, needApplyFilters = false; + + path = 'page=' + $scope.paginationOptions.currentPage; + if ($scope.paginationOptions.itemsPerPage !== $scope.defaultsPaginationOptions.itemsPerPage) { + path += '&itemsPerPage=' + $scope.paginationOptions.itemsPerPage; + } + + if ($scope.sortOptions.predicate) { + path += '&sort=' + encodeURIComponent($scope.sortOptions.predicate + "-" + $scope.sortOptions.direction); + } + + //custom filters + $scope.filters.forEach(function (filter) { + var urlName = filter.model, + value = $scope[urlName]; + + if (filter.disableUrl) { + needApplyFilters = true; + return; + } + + if (value) { + var strValue; + if (value instanceof Date) { + if (isNaN(value.getTime())) { + return; + } + strValue = value.getFullYear() + '-'; + strValue += value.getMonth() < 9 ? '0' + (value.getMonth() + 1) + '-' : (value.getMonth() + 1) + '-'; + strValue += value.getDate() < 10 ? '0' + value.getDate() : value.getDate(); + value = strValue; + } + path += '&' + encodeURIComponent(urlName) + '=' + encodeURIComponent(value); + } + }); + + if (needApplyFilters) { + applyFilters(); + } + $location.path(path); + } + + function parseUrl() { + var url = $location.path().slice(1), + params = {}, + customParams = {}; + + $scope.params = params; + + url.split('&').forEach(function (urlParam) { + var param = urlParam.split('='); + params[param[0]] = param[1]; + if (param[0] !== 'page' && param[0] !== 'sort' && param[0] !== 'itemsPerPage') { + customParams[decodeURIComponent(param[0])] = decodeURIComponent(param[1]); + } + } + ); + + //custom filters + $scope.filters.forEach(function (filter) { + var urlName = filter.model, + value = customParams[urlName], + scope = $scope; + + if (filter.disableUrl) { + return; + } + + if (~filter.filterType.toLowerCase().indexOf('date') && value) { + scope[urlName] = new Date(value); + return; + } + + if (filter.filterType === 'select' && !value) { + value = ""; + } + + scope[urlName] = value; + }); + + if (!$scope.serverPagination) { + applyCustomFilters(); + } + + //pagination options + $scope.paginationOptions.itemsPerPage = $scope.defaultsPaginationOptions.itemsPerPage; + $scope.paginationOptions.currentPage = $scope.defaultsPaginationOptions.currentPage; + + if (params.itemsPerPage) { + $scope.paginationOptions.itemsPerPage = params.itemsPerPage; + } + + if (params.page) { + if (!$scope.serverPagination && ((params.page - 1) * $scope.paginationOptions.itemsPerPage > $scope.filtered.length)) { + $scope.paginationOptions.currentPage = 1; + } else { + $scope.paginationOptions.currentPage = params.page; + } + } + + //sort options + if (params.sort) { + var sort = params.sort.split('-'); + $scope.sortOptions.predicate = decodeURIComponent(sort[0]); + $scope.sortOptions.direction = decodeURIComponent(sort[1]); + } + if (!$scope.serverPagination) { + applyFilters(); + } + } + + function getData() { + var url = $location.path().slice(1); + $scope._gridOptions.getData('?' + url, function (data, totalItems) { + $scope.filtered = data; + $scope.paginationOptions.totalItems = totalItems; + }); + } + + function applyFilters() { + $scope.filtered = angular.copy($scope._gridOptions.data); + + applyCustomFilters(); + + //apply orderBy filter + $scope.filtered = $filter('orderBy')($scope.filtered, $scope.sortOptions.predicate, $scope.sortOptions.direction === 'desc'); + $scope.paginationOptions.totalItems = $scope.filtered.length; + } + + function applyCustomFilters() { + $scope.filters.forEach(function (filter) { + var predicate = filter.filterBy, + urlName = filter.model, + value = $scope[urlName], + type = filter.filterType; + if ($scope.customFilters[urlName]) { + $scope.filtered = $scope.customFilters[urlName]($scope.filtered, value, predicate); + } else if (value && type) { + var filterFunc = filtersFactory.getFilterByType(type); + if (filterFunc) { + $scope.filtered = filterFunc($scope.filtered, value, predicate); + } + } + }); + } + }]) + .directive('gridData', ['$compile', '$animate', function ($compile, $animate) { + return { + restrict: 'EA', + transclude: true, + replace: true, + controller: 'gridController', + link: function ($scope, $element, attrs, controller, $transclude) { + var sorting = [], + filters = [], + rows = [], + childScope = $scope.$new(), + directiveElement = $element.parent(), + gridId = attrs.id, + serverPagination = attrs.serverPagination === 'true'; + + $transclude($scope, function (clone) { + $animate.enter(clone, $element); + }); + + angular.forEach(angular.element(directiveElement[0].querySelectorAll('[sortable]')), function (sortable) { + var element = angular.element(sortable), + predicate = element.attr('sortable'); + sorting.push(element); + element.attr('ng-class', "{'sort-ascent' : sortOptions.predicate ==='" + + predicate + "' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '" + + predicate + "' && sortOptions.direction === 'desc'}"); + element.attr('ng-click', "sort('" + predicate + "')"); + $compile(element)(childScope); + }); + + angular.forEach(angular.element(document.querySelectorAll('[filter-by]')), function (filter) { + var element = angular.element(filter), + isInScope = directiveElement.find(element).length > 0, + predicate = element.attr('filter-by'), + filterType = element.attr('filter-type') || '', + urlName = element.attr('ng-model'), + disableUrl = element.attr('disable-url'); + + if (gridId && element.attr('grid-id') && gridId != element.attr('grid-id')) { + return; + } + + if (filterType === 'select') { + var options = generateOptions(deepFind($scope, $element.attr('grid-options') + '.data'), predicate); + $scope[urlName + 'Options'] = options; + } + + if (~filterType.indexOf('date') && !element.attr('ng-focus') + && !element.attr('ng-blur')) { + element.attr('ng-focus', "filter('{" + urlName + " : " + "this." + urlName + "}')"); + element.attr('ng-blur', "filter('{" + urlName + " : " + "this." + urlName + "}')"); + $compile(element)($scope); + } + if (!urlName) { + urlName = predicate; + element.attr('ng-model', predicate); + element.attr('ng-change', 'filter()'); + $compile(element)($scope); + } + + filters.push({ + model: urlName, + isInScope: isInScope, + filterBy: predicate, + filterType: filterType, + disableUrl: disableUrl + }); + }); + + angular.forEach(angular.element(directiveElement[0].querySelectorAll('[grid-item]')), function (row) { + var element = angular.element(row); + rows.push(element); + if (serverPagination) { + element.attr('ng-repeat', "item in filtered"); + } else { + element.attr('ng-repeat', "item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage"); + } + $compile(element)(childScope); + }); + + $scope.sorting = sorting; + $scope.rows = rows; + $scope.filters = filters; + + function generateOptions(values, predicate) { + var array = []; + values.forEach(function (item) { + if (!~array.indexOf(item[predicate])) { + array.push(item[predicate]); + } + }); + + return array.map(function (option) { + return {text: option, value: option}; + }); + } + } + } + }]) + .directive('gridItemPerPage', ['$compile', function ($compile) { + return { + replace: true, + template: '', + link: function (scope, element, attrs) { + if (attrs.gridItemPerPage) { + var values = attrs.gridItemPerPage.replace(/ /g, '').split(','); + values.forEach(function (value) { + if (Number(value)) { + value = Number(value); + } else { + return; + } + var li = angular.element('
  • '); + var button = angular.element('' + value + ''); + button.attr('ng-click', 'paginationOptions.itemsPerPage = ' + value + '; reloadGrid()'); + li.attr('ng-class', '{"active" : paginationOptions.itemsPerPage == ' + value + '}'); + li.append(button); + element.append(li); + element.append(' '); + $compile(li)(scope); + }); + } + } + } + }]) + .factory('filtersFactory', function () { + function selectFilter(items, value, predicate) { + return items.filter(function (item) { + return value && item[predicate] ? item[predicate] === value : true; + }); + } + + function textFilter(items, value, predicate) { + return items.filter(function (item) { + return value && item[predicate] ? ~item[predicate].toLowerCase().indexOf(value.toLowerCase()) : true; + }); + } + + function dateToFilter(items, value, predicate) { + value = new Date(value).getTime(); + return items.filter(function (item) { + return value && item[predicate] ? item[predicate] <= value + 86399999 : true; + }); + } + + function dateFromFilter(items, value, predicate) { + value = new Date(value).getTime(); + return items.filter(function (item) { + return value && item[predicate] ? item[predicate] >= value : true; + }); + } + + return { + getFilterByType: function (type) { + switch (type) { + case 'select' : + { + return selectFilter; + } + case 'text' : + { + return textFilter; + } + case 'dateTo': + { + return dateToFilter; + } + case 'dateFrom': + { + return dateFromFilter; + } + default : + { + return null; + } + } + } + } + }); + + +function deepFind(obj, path) { + var paths = path.split('.'), + current = obj, + i; + + for (i = 0; i < paths.length; ++i) { + if (current[paths[i]] == undefined) { + return undefined; + } else { + current = current[paths[i]]; + } + } + return current; +} \ No newline at end of file diff --git a/dist/dataGrid.min.js b/dist/dataGrid.min.js new file mode 100644 index 0000000..2c3351e --- /dev/null +++ b/dist/dataGrid.min.js @@ -0,0 +1 @@ +function deepFind(t,e){var i,n=e.split("."),r=t;for(i=0;it.filtered.length?t.paginationOptions.currentPage=1:t.paginationOptions.currentPage=i.page),i.sort){var a=i.sort.split("-");t.sortOptions.predicate=decodeURIComponent(a[0]),t.sortOptions.direction=decodeURIComponent(a[1])}t.serverPagination||l()}function s(){var e=n.path().slice(1);t._gridOptions.getData("?"+e,function(e,i){t.filtered=e,t.paginationOptions.totalItems=i})}function l(){t.filtered=angular.copy(t._gridOptions.data),c(),t.filtered=i("orderBy")(t.filtered,t.sortOptions.predicate,"desc"===t.sortOptions.direction),t.paginationOptions.totalItems=t.filtered.length}function c(){t.filters.forEach(function(e){var i=e.filterBy,n=e.model,a=t[n],o=e.filterType;if(t.customFilters[n])t.filtered=t.customFilters[n](t.filtered,a,i);else if(a&&o){var s=r.getFilterByType(o);s&&(t.filtered=s(t.filtered,a,i))}})}t._gridOptions=deepFind(t,e.attr("grid-options")),t._gridActions=deepFind(t,e.attr("grid-actions")),t.serverPagination="true"===e.attr("server-pagination"),t.getDataDelay=e.attr("get-delay")||350,t._gridActions||(t.$parent[e.attr("grid-actions")]={},t._gridActions=t.$parent[e.attr("grid-actions")]),t.filtered=angular.copy(t._gridOptions.data),t.paginationOptions=t._gridOptions.pagination?angular.copy(t._gridOptions.pagination):{},t.defaultsPaginationOptions={itemsPerPage:t.paginationOptions.itemsPerPage||10,currentPage:t.paginationOptions.currentPage||1},t.paginationOptions=angular.copy(t.defaultsPaginationOptions),t.sortOptions=t._gridOptions.sort?angular.copy(t._gridOptions.sort):{},t.customFilters=t._gridOptions.customFilters?angular.copy(t._gridOptions.customFilters):{},t.urlSync=t._gridOptions.urlSync,t.$watch("_gridOptions.data",function(e){e&&e.length&&(t.urlSync?o(n.path()):l())}),t.sort=function(e){var i=t.sortOptions.predicate===e&&"desc"===t.sortOptions.direction?"asc":"desc";t.sortOptions.predicate=e,t.sortOptions.direction=i,t.paginationOptions.currentPage=1,t.reloadGrid()},t.filter=function(){t.paginationOptions.currentPage=1,t.reloadGrid()},t.$on("$locationChangeSuccess",function(){(t.urlSync||t.serverPagination)&&(t.serverPagination&&(clearTimeout(t.getDataTimeout),t.getDataTimeout=setTimeout(s,t.getDataDelay)),o(n.path()))}),t.reloadGrid=function(){t.urlSync||t.serverPagination?a():l()},t._gridActions.refresh=t.reloadGrid,t._gridActions.filter=t.filter,t._gridActions.sort=t.sort}]).directive("gridData",["$compile","$animate",function(t,e){return{restrict:"EA",transclude:!0,replace:!0,controller:"gridController",link:function(i,n,r,a,o){function s(t,e){var i=[];return t.forEach(function(t){~i.indexOf(t[e])||i.push(t[e])}),i.map(function(t){return{text:t,value:t}})}var l=[],c=[],g=[],p=i.$new(),d=n.parent(),u=r.id,f="true"===r.serverPagination;o(i,function(t){e.enter(t,n)}),angular.forEach(angular.element(d[0].querySelectorAll("[sortable]")),function(e){var i=angular.element(e),n=i.attr("sortable");l.push(i),i.attr("ng-class","{'sort-ascent' : sortOptions.predicate ==='"+n+"' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '"+n+"' && sortOptions.direction === 'desc'}"),i.attr("ng-click","sort('"+n+"')"),t(i)(p)}),angular.forEach(angular.element(document.querySelectorAll("[filter-by]")),function(e){var r=angular.element(e),a=d.find(r).length>0,o=r.attr("filter-by"),l=r.attr("filter-type")||"",g=r.attr("ng-model"),p=r.attr("disable-url");if(!u||!r.attr("grid-id")||u==r.attr("grid-id")){if("select"===l){var f=s(deepFind(i,n.attr("grid-options")+".data"),o);i[g+"Options"]=f}!~l.indexOf("date")||r.attr("ng-focus")||r.attr("ng-blur")||(r.attr("ng-focus","filter('{"+g+" : this."+g+"}')"),r.attr("ng-blur","filter('{"+g+" : this."+g+"}')"),t(r)(i)),g||(g=o,r.attr("ng-model",o),r.attr("ng-change","filter()"),t(r)(i)),c.push({model:g,isInScope:a,filterBy:o,filterType:l,disableUrl:p})}}),angular.forEach(angular.element(d[0].querySelectorAll("[grid-item]")),function(e){var i=angular.element(e);g.push(i),f?i.attr("ng-repeat","item in filtered"):i.attr("ng-repeat","item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage"),t(i)(p)}),i.sorting=l,i.rows=g,i.filters=c}}}]).directive("gridItemPerPage",["$compile",function(t){return{replace:!0,template:'',link:function(e,i,n){if(n.gridItemPerPage){var r=n.gridItemPerPage.replace(/ /g,"").split(",");r.forEach(function(n){if(Number(n)){n=Number(n);var r=angular.element("
  • "),a=angular.element(""+n+"");a.attr("ng-click","paginationOptions.itemsPerPage = "+n+"; reloadGrid()"),r.attr("ng-class",'{"active" : paginationOptions.itemsPerPage == '+n+"}"),r.append(a),i.append(r),i.append(" "),t(r)(e)}})}}}}]).factory("filtersFactory",function(){function t(t,e,i){return t.filter(function(t){return e&&t[i]?t[i]===e:!0})}function e(t,e,i){return t.filter(function(t){return e&&t[i]?~t[i].toLowerCase().indexOf(e.toLowerCase()):!0})}function i(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return e&&t[i]?t[i]<=e+86399999:!0})}function n(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return e&&t[i]?t[i]>=e:!0})}return{getFilterByType:function(r){switch(r){case"select":return t;case"text":return e;case"dateTo":return i;case"dateFrom":return n;default:return null}}}}); \ No newline at end of file diff --git a/dist/pagination.js b/dist/pagination.js new file mode 100644 index 0000000..249c4b4 --- /dev/null +++ b/dist/pagination.js @@ -0,0 +1,244 @@ +angular.module('ui.bootstrap.paging', []) + /** + * Helper internal service for generating common controller code between the + * pager and pagination components + */ + .factory('uibPaging', ['$parse', function ($parse) { + return { + create: function (ctrl, $scope, $attrs) { + ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; + ctrl.ngModelCtrl = {$setViewValue: angular.noop}; // nullModelCtrl + + ctrl.init = function (ngModelCtrl, config) { + ctrl.ngModelCtrl = ngModelCtrl; + ctrl.config = config; + + ngModelCtrl.$render = function () { + ctrl.render(); + }; + + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function (value) { + ctrl.itemsPerPage = parseInt(value, 10); + $scope.totalPages = ctrl.calculateTotalPages(); + ctrl.updatePage(); + }); + } else { + ctrl.itemsPerPage = config.itemsPerPage; + } + + $scope.$watch('totalItems', function (newTotal, oldTotal) { + if (angular.isDefined(newTotal) || newTotal !== oldTotal) { + $scope.totalPages = ctrl.calculateTotalPages(); + ctrl.updatePage(); + } + }); + }; + + ctrl.calculateTotalPages = function () { + var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage); + return Math.max(totalPages || 0, 1); + }; + + ctrl.render = function () { + $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1; + }; + + $scope.selectPage = function (page, evt) { + if (evt) { + evt.preventDefault(); + } + + var clickAllowed = !$scope.ngDisabled || !evt; + if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) { + if (evt && evt.target) { + evt.target.blur(); + } + ctrl.ngModelCtrl.$setViewValue(page); + ctrl.ngModelCtrl.$render(); + } + }; + + $scope.getText = function (key) { + return $scope[key + 'Text'] || ctrl.config[key + 'Text']; + }; + + $scope.noPrevious = function () { + return $scope.page === 1; + }; + + $scope.noNext = function () { + return $scope.page === $scope.totalPages; + }; + + ctrl.updatePage = function () { + ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable + + if ($scope.page > $scope.totalPages) { + $scope.selectPage($scope.totalPages); + } else { + ctrl.ngModelCtrl.$render(); + } + }; + } + }; + }]); + +angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging']) + .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function ($scope, $attrs, $parse, uibPaging, uibPaginationConfig) { + var ctrl = this; + // Setup configuration parameters + var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize, + rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate, + forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses, + boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers; + $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks; + $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks; + + uibPaging.create(this, $scope, $attrs); + + if ($attrs.maxSize) { + $scope.$parent.$watch($parse($attrs.maxSize), function (value) { + maxSize = parseInt(value, 10); + ctrl.render(); + }); + } + + // Create page object used in template + function makePage(number, text, isActive) { + return { + number: number, + text: text, + active: isActive + }; + } + + function getPages(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, number === currentPage); + pages.push(page); + } + + // Add links to move between page sets + if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) { + if (startPage > 1) { + if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning + var previousPageSet = makePage(startPage - 1, '...', false); + pages.unshift(previousPageSet); + } + if (boundaryLinkNumbers) { + if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential + var secondPageLink = makePage(2, '2', false); + pages.unshift(secondPageLink); + } + //add the first page + var firstPageLink = makePage(1, '1', false); + pages.unshift(firstPageLink); + } + } + + if (endPage < totalPages) { + if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end + var nextPageSet = makePage(endPage + 1, '...', false); + pages.push(nextPageSet); + } + if (boundaryLinkNumbers) { + if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential + var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false); + pages.push(secondToLastPageLink); + } + //add the last page + var lastPageLink = makePage(totalPages, totalPages, false); + pages.push(lastPageLink); + } + } + } + return pages; + } + + var originalRender = this.render; + this.render = function () { + originalRender(); + if ($scope.page > 0 && $scope.page <= $scope.totalPages) { + $scope.pages = getPages($scope.page, $scope.totalPages); + } + }; + }]) + + .constant('uibPaginationConfig', { + itemsPerPage: 10, + boundaryLinks: false, + boundaryLinkNumbers: false, + directionLinks: true, + firstText: 'First', + previousText: 'Previous', + nextText: 'Next', + lastText: 'Last', + rotate: true, + forceEllipses: false + }) + + .directive('uibPagination', ['$parse', 'uibPaginationConfig', function ($parse, uibPaginationConfig) { + return { + scope: { + totalItems: '=', + firstText: '@', + previousText: '@', + nextText: '@', + lastText: '@', + ngDisabled: '=' + }, + require: ['uibPagination', '?ngModel'], + controller: 'UibPaginationController', + controllerAs: 'pagination', + templateUrl: function (element, attrs) { + return attrs.templateUrl || 'src/template/pagination/pagination.html'; + }, + replace: true, + link: function (scope, element, attrs, ctrls) { + var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if (!ngModelCtrl) { + return; // do nothing if no ng-model + } + + paginationCtrl.init(ngModelCtrl, uibPaginationConfig); + } + }; + }]) + + .run(['$templateCache', function ($templateCache) { + + $templateCache.put('src/template/pagination/pagination.html', + "" + ); + + }]); \ No newline at end of file diff --git a/dist/pagination.min.js b/dist/pagination.min.js new file mode 100644 index 0000000..a25c266 --- /dev/null +++ b/dist/pagination.min.js @@ -0,0 +1 @@ +angular.module("ui.bootstrap.paging",[]).factory("uibPaging",["$parse",function(e){return{create:function(a,t,n){a.setNumPages=n.numPages?e(n.numPages).assign:angular.noop,a.ngModelCtrl={$setViewValue:angular.noop},a.init=function(i,r){a.ngModelCtrl=i,a.config=r,i.$render=function(){a.render()},n.itemsPerPage?t.$parent.$watch(e(n.itemsPerPage),function(e){a.itemsPerPage=parseInt(e,10),t.totalPages=a.calculateTotalPages(),a.updatePage()}):a.itemsPerPage=r.itemsPerPage,t.$watch("totalItems",function(e,n){(angular.isDefined(e)||e!==n)&&(t.totalPages=a.calculateTotalPages(),a.updatePage())})},a.calculateTotalPages=function(){var e=a.itemsPerPage<1?1:Math.ceil(t.totalItems/a.itemsPerPage);return Math.max(e||0,1)},a.render=function(){t.page=parseInt(a.ngModelCtrl.$viewValue,10)||1},t.selectPage=function(e,n){n&&n.preventDefault();var i=!t.ngDisabled||!n;i&&t.page!==e&&e>0&&e<=t.totalPages&&(n&&n.target&&n.target.blur(),a.ngModelCtrl.$setViewValue(e),a.ngModelCtrl.$render())},t.getText=function(e){return t[e+"Text"]||a.config[e+"Text"]},t.noPrevious=function(){return 1===t.page},t.noNext=function(){return t.page===t.totalPages},a.updatePage=function(){a.setNumPages(t.$parent,t.totalPages),t.page>t.totalPages?t.selectPage(t.totalPages):a.ngModelCtrl.$render()}}}}]),angular.module("ui.bootstrap.pagination",["ui.bootstrap.paging"]).controller("UibPaginationController",["$scope","$attrs","$parse","uibPaging","uibPaginationConfig",function(e,a,t,n,i){function r(e,a,t){return{number:e,text:a,active:t}}function s(e,a){var t=[],n=1,i=a,s=angular.isDefined(o)&&a>o;s&&(g?(n=Math.max(e-Math.floor(o/2),1),i=n+o-1,i>a&&(i=a,n=i-o+1)):(n=(Math.ceil(e/o)-1)*o+1,i=Math.min(n+o-1,a)));for(var l=n;i>=l;l++){var p=r(l,l,l===e);t.push(p)}if(s&&o>0&&(!g||u||c)){if(n>1){if(!c||n>3){var f=r(n-1,"...",!1);t.unshift(f)}if(c){if(3===n){var d=r(2,"2",!1);t.unshift(d)}var P=r(1,"1",!1);t.unshift(P)}}if(a>i){if(!c||a-2>i){var b=r(i+1,"...",!1);t.push(b)}if(c){if(i===a-2){var v=r(a-1,a-1,!1);t.push(v)}var m=r(a,a,!1);t.push(m)}}}return t}var l=this,o=angular.isDefined(a.maxSize)?e.$parent.$eval(a.maxSize):i.maxSize,g=angular.isDefined(a.rotate)?e.$parent.$eval(a.rotate):i.rotate,u=angular.isDefined(a.forceEllipses)?e.$parent.$eval(a.forceEllipses):i.forceEllipses,c=angular.isDefined(a.boundaryLinkNumbers)?e.$parent.$eval(a.boundaryLinkNumbers):i.boundaryLinkNumbers;e.boundaryLinks=angular.isDefined(a.boundaryLinks)?e.$parent.$eval(a.boundaryLinks):i.boundaryLinks,e.directionLinks=angular.isDefined(a.directionLinks)?e.$parent.$eval(a.directionLinks):i.directionLinks,n.create(this,e,a),a.maxSize&&e.$parent.$watch(t(a.maxSize),function(e){o=parseInt(e,10),l.render()});var p=this.render;this.render=function(){p(),e.page>0&&e.page<=e.totalPages&&(e.pages=s(e.page,e.totalPages))}}]).constant("uibPaginationConfig",{itemsPerPage:10,boundaryLinks:!1,boundaryLinkNumbers:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0,forceEllipses:!1}).directive("uibPagination",["$parse","uibPaginationConfig",function(e,a){return{scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["uibPagination","?ngModel"],controller:"UibPaginationController",controllerAs:"pagination",templateUrl:function(e,a){return a.templateUrl||"src/template/pagination/pagination.html"},replace:!0,link:function(e,t,n,i){var r=i[0],s=i[1];s&&r.init(s,a)}}}]).run(["$templateCache",function(e){e.put("src/template/pagination/pagination.html","")}]); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 59440f8..a763b39 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,93 +1,74 @@ -'use strict'; - -var gulp = require('gulp'), - uglify = require('gulp-uglify'), - sourcemaps = require('gulp-sourcemaps'), - rename = require('gulp-rename'), - concat = require('gulp-concat'), - sass = require('gulp-sass'), - browserSync = require('browser-sync'), - rimraf = require('gulp-rimraf'), - addStream = require('add-stream'), - templateCache = require('gulp-angular-templatecache'); - -function browserSyncInit(baseDir) { - var server = { - baseDir: baseDir - }; - - browserSync.instance = browserSync.init({ - startPath: '/', - server: server, - open: false +(function () { + 'use strict'; + + var gulp = require('gulp'), + uglify = require('gulp-uglify'), + rename = require('gulp-rename'), + concat = require('gulp-concat'), + sass = require('gulp-sass'), + browserSync = require('browser-sync'), + rimraf = require('gulp-rimraf'); + + function browserSyncInit(baseDir) { + var server = { + baseDir: baseDir + }; + + browserSync.instance = browserSync.init({ + startPath: '/', + server: server, + open: false + }); + } + + gulp.task('js', function () { + gulp.src(['./src/**/*.js', '!./src/js/demoApp.js']) + .pipe(rename({dirname: ''})) + .pipe(gulp.dest('./dist')) + .pipe(uglify()) + .pipe(rename({ + suffix: ".min" + })) + .pipe(gulp.dest('./dist')); + gulp.src('./src/js/demoApp.js') + .pipe(gulp.dest('./demo')); }); -} - -gulp.task('js', function () { - gulp.src('./src/**/*.js') - .pipe(addStream.obj(prepareTemplates())) - .pipe(concat('index.js')) - .pipe(gulp.dest('./demo/js')); - - gulp.src(['./src/**/*.js', '!./src/js/app.js']) - .pipe(addStream.obj(prepareTemplates())) - .pipe(concat('datagrid.js')) - .pipe(gulp.dest('dist')) - .pipe(sourcemaps.init()) - .pipe(concat('app.js')) - .pipe(uglify()) - .pipe(rename('datagrid.min.js')) - .pipe(sourcemaps.write('./')) - .pipe(gulp.dest('dist')); - -}); + gulp.task('sass', function () { + gulp.src('./src/css/demo.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./demo')); + gulp.src('./src/css/dataGrid.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./dist')); + }); -gulp.task('sass', function () { - gulp.src('./src/**/*.scss') - .pipe(sass().on('error', sass.logError)) - .pipe(gulp.dest('./demo')); -}); + gulp.task('build', ['js', 'sass']); -gulp.task('html', function () { - gulp.src(['./src/**/*.html', '!./src/js/**/*.html']) - .pipe(gulp.dest('./demo')); -}); + gulp.task('watch', ['build'], function () { -gulp.task('build', ['js', 'sass', 'html']); + gulp.watch(['./src/**/*.js'], function (event) { + gulp.start('js'); + browserSync.reload(event.path); + }); -gulp.task('watch', ['build'], function () { - gulp.watch(['./src/**/*.html'], function (event) { - gulp.start('html'); - browserSync.reload(event.path); + gulp.watch(['./src/**/*.scss'], function (event) { + gulp.start('sass'); + browserSync.reload(event.path); + }); }); - gulp.watch(['./src/**/*.js'], function (event) { - gulp.start('js'); - browserSync.reload(event.path); + gulp.task('clean', function () { + return gulp.src(['demo'], {read: false}) + .pipe(rimraf()); }); - gulp.watch(['./src/**/*.scss'], function (event) { - gulp.start('sass'); - browserSync.reload(event.path); + gulp.task('full-clean', ['clean'], function () { + return gulp.src(['bower_components', 'node_modules'], {read: false}) + .pipe(rimraf()); }); -}); - -gulp.task('clean', function () { - return gulp.src(['demo'], {read: false}) - .pipe(rimraf()); -}); - -gulp.task('full-clean', ['clean'], function () { - return gulp.src(['bower_components', 'node_modules'], {read: false}) - .pipe(rimraf()); -}); -gulp.task('serve', ['watch'], function () { - browserSyncInit(['demo']); -}); - -function prepareTemplates() { - return gulp.src('./src/js/**/*.html') - .pipe(templateCache('templates.js', {module: 'dataGrid'})); -} \ No newline at end of file + gulp.task('serve', ['watch'], function () { + browserSyncInit(['demo']); + }); +})(); \ No newline at end of file diff --git a/index.html b/index.html index d5668f9..027ff5c 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ Flat JSON format for data tables +
    @@ -86,7 +87,14 @@

    Angular Data Grid

    -
    + @@ -134,10 +142,17 @@

    Angular Data Grid

    -
    - +
    +
    -
    +
    @@ -148,12 +163,10 @@

    Angular Data Grid

    - + - - - - - + + + \ No newline at end of file diff --git a/package.json b/package.json index 6d9fe55..e91cc83 100644 --- a/package.json +++ b/package.json @@ -6,19 +6,12 @@ "prebuild": "npm install" }, "dependencies": { - "add-stream": "^1.0.0", - "bower": "^1.6.5", "browser-sync": "^2.10.0", - "browser-sync-spa": "^1.0.3", "gulp": "^3.9.0", - "gulp-angular-templatecache": "^1.8.0", "gulp-concat": "^2.6.0", - "gulp-connect": "^2.2.0", - "gulp-csso": "^1.0.1", "gulp-rename": "^1.2.2", "gulp-rimraf": "*", "gulp-sass": "^2.1.0", - "gulp-sourcemaps": "^1.1.0", "gulp-uglify": "^1.4.2" } } diff --git a/src/css/dataGrid.scss b/src/css/dataGrid.scss new file mode 100644 index 0000000..50d2b5f --- /dev/null +++ b/src/css/dataGrid.scss @@ -0,0 +1,122 @@ +:focus { + outline: none; +} +.pagination { + display: inline-block; + box-sizing: border-box; +} +.pagination > li{ + display: inline-block; + vertical-align: middle; + width: auto; + height: 30px; + position: relative; + border-radius: 2px; + box-sizing: border-box; +} +.pagination a { + color: #444; + font-size: 16px; + padding: 0 10px; + line-height: 30px; + display: inline-block; + text-decoration: none; + box-sizing: border-box; + .md-ripple-container { + border-radius: 2px; + } +} +.pagination-prev, +.pagination-next, +.pagination-first, +.pagination-last { + a { + padding: 3px 5px; + } + svg { + width: 24px; + height: 24px; + } +} +.pagination-none-svg { + svg { + display: none !important; + } + .pagination-prev, + .pagination-next, + .pagination-first, + .pagination-last { + a { + width: 30px; + text-align: center; + line-height: 24px; + } + } +} +.pagination-page { + transition: background .1s ease-out, color .1s ease-out; + &.active { + background: rgb(16,108,200); + a { + color: #fff; + } + } +} +.pagination { + transition: background .1s ease-out, color .1s ease-out; + .active { + background: rgb(16,108,200); + a { + color: #fff; + } + } +} +.grid-data-table { + td { + border-bottom: 1px rgba(0,0,0,.12) solid; + padding: 12px; + } + th { + padding: 0 12px; + border-bottom: 1px rgba(0,0,0,.12) solid; + } +} +th.sortable { + line-height: 24px; + svg { + height: 18px; + width: 18px; + margin: 0 4px; + transition: fill .25s,-webkit-transform .25s; + transition: fill .25s,transform .25s; + vertical-align: middle; + display: none !important; + } + padding-right: 31px; + &.sort-descent { + padding-right: 0; + svg { + display: inline-block !important; + } + } + &.sort-ascent { + padding-right: 0; + svg { + display: inline-block !important; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + } +} + +.items-per-page { + .active { + background: rgb(16,108,200); + a { + color: #fff; + } + } + a { + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/css/demo.scss b/src/css/demo.scss index 9da63d7..3a09c2e 100644 --- a/src/css/demo.scss +++ b/src/css/demo.scss @@ -1,35 +1 @@ -.sortable { - &:after { - font-family: 'Material Icons'; - font-feature-settings: "liga" 1; - line-height: 1; - content: "compare_arrows"; - display: inline-block; - font-size: 18px; - transition: opacity 0.35s, -webkit-transform 0.25s; - transition: opacity 0.35s, transform 0.25s; - opacity: 0; - -webkit-transform: rotate(270deg) translateX(25%); - transform: rotate(270deg) translateY(15%); - } - - &:hover:after { - opacity: 1; - } - - &.sort-ascent:after { - opacity: 1; - content: "arrow_upward"; - vertical-align: top; - -webkit-transform: rotate(180deg); - transform: rotate(180deg); - } - - &.sort-descent:after { - opacity: 1; - content: "arrow_upward"; - vertical-align: bottom; - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } -} \ No newline at end of file +@import 'dataGrid'; \ No newline at end of file diff --git a/src/html/gridPaginator.html b/src/html/gridPaginator.html deleted file mode 100644 index 3e1b1d9..0000000 --- a/src/html/gridPaginator.html +++ /dev/null @@ -1,6 +0,0 @@ -
    -
    \ No newline at end of file diff --git a/src/js/dataGrid.js b/src/js/dataGrid.js index c32de0c..5772568 100644 --- a/src/js/dataGrid.js +++ b/src/js/dataGrid.js @@ -322,13 +322,6 @@ angular.module('dataGrid', []) } } }]) - .directive('gridPagination', function () { - return { - replace: true, - scope: true, - templateUrl: 'src/html/gridPaginator.html' - }; - }) .directive('gridItemPerPage', ['$compile', function ($compile) { return { replace: true, @@ -424,13 +417,4 @@ function deepFind(obj, path) { } } return current; -} - -angular.module('dataGrid').run(['$templateCache', function ($templateCache) { - 'use strict'; - - $templateCache.put('src/js/directives/modules/dataGrid/gridPaginator.html', - "
    paginationOptions.itemsPerPage\" total-items=\"paginationOptions.totalItems\" ng-model=\"paginationOptions.currentPage\" ng-change=\"reloadGrid()\" items-per-page=\"paginationOptions.itemsPerPage\">
    " - ); - -}]); \ No newline at end of file +} \ No newline at end of file diff --git a/src/js/demoApp.js b/src/js/demoApp.js new file mode 100644 index 0000000..38d2f9c --- /dev/null +++ b/src/js/demoApp.js @@ -0,0 +1,35 @@ +angular.module('myApp', ['dataGrid', 'ui.bootstrap.pagination']) + .controller('myAppController', ['$scope', 'myAppFactory', function ($scope, myAppFactory) { + + $scope.getData = function () { + myAppFactory.getData() + .success(function (response) { + $scope.gridOptions.data = response; + $scope.dataLoaded = true; + }).error(function () { + }); + }; + $scope.getData(); + + $scope.gridOptions = { + data: $scope.items, + urlSync: true + }; + + //$scope.items = [ + // {"firstName": "John", "lastName": "Doe"}, + // {"firstName": "Anna", "lastName": "Smith"}, + // {"firstName": "Peter", "lastName": "Jones"} + //]; + + + }]) + .factory('myAppFactory', function ($http) { + var root = 'http://jsonplaceholder.typicode.com'; + return { + getData: function () { + return $http.get(root + '/posts', {}); + } + } + }); + diff --git a/src/js/gridPaginator.html b/src/js/gridPaginator.html deleted file mode 100644 index f648c48..0000000 --- a/src/js/gridPaginator.html +++ /dev/null @@ -1,6 +0,0 @@ -
    -
    \ No newline at end of file diff --git a/src/js/pagination.js b/src/js/pagination.js index 96b52ef..249c4b4 100644 --- a/src/js/pagination.js +++ b/src/js/pagination.js @@ -1,150 +1,244 @@ +angular.module('ui.bootstrap.paging', []) + /** + * Helper internal service for generating common controller code between the + * pager and pagination components + */ + .factory('uibPaging', ['$parse', function ($parse) { + return { + create: function (ctrl, $scope, $attrs) { + ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; + ctrl.ngModelCtrl = {$setViewValue: angular.noop}; // nullModelCtrl + + ctrl.init = function (ngModelCtrl, config) { + ctrl.ngModelCtrl = ngModelCtrl; + ctrl.config = config; + + ngModelCtrl.$render = function () { + ctrl.render(); + }; + + if ($attrs.itemsPerPage) { + $scope.$parent.$watch($parse($attrs.itemsPerPage), function (value) { + ctrl.itemsPerPage = parseInt(value, 10); + $scope.totalPages = ctrl.calculateTotalPages(); + ctrl.updatePage(); + }); + } else { + ctrl.itemsPerPage = config.itemsPerPage; + } + + $scope.$watch('totalItems', function (newTotal, oldTotal) { + if (angular.isDefined(newTotal) || newTotal !== oldTotal) { + $scope.totalPages = ctrl.calculateTotalPages(); + ctrl.updatePage(); + } + }); + }; + + ctrl.calculateTotalPages = function () { + var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage); + return Math.max(totalPages || 0, 1); + }; + + ctrl.render = function () { + $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1; + }; + + $scope.selectPage = function (page, evt) { + if (evt) { + evt.preventDefault(); + } + + var clickAllowed = !$scope.ngDisabled || !evt; + if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) { + if (evt && evt.target) { + evt.target.blur(); + } + ctrl.ngModelCtrl.$setViewValue(page); + ctrl.ngModelCtrl.$render(); + } + }; + + $scope.getText = function (key) { + return $scope[key + 'Text'] || ctrl.config[key + 'Text']; + }; + + $scope.noPrevious = function () { + return $scope.page === 1; + }; + + $scope.noNext = function () { + return $scope.page === $scope.totalPages; + }; + + ctrl.updatePage = function () { + ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable + + if ($scope.page > $scope.totalPages) { + $scope.selectPage($scope.totalPages); + } else { + ctrl.ngModelCtrl.$render(); + } + }; + } + }; + }]); + angular.module('ui.bootstrap.pagination', ['ui.bootstrap.paging']) -.controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function($scope, $attrs, $parse, uibPaging, uibPaginationConfig) { - var ctrl = this; - // Setup configuration parameters - var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize, - rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate, - forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses, - boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers; - $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks; - $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks; - - uibPaging.create(this, $scope, $attrs); - - if ($attrs.maxSize) { - $scope.$parent.$watch($parse($attrs.maxSize), function(value) { - maxSize = parseInt(value, 10); - ctrl.render(); - }); - } - - // Create page object used in template - function makePage(number, text, isActive) { - return { - number: number, - text: text, - active: isActive - }; - } - - function getPages(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; + .controller('UibPaginationController', ['$scope', '$attrs', '$parse', 'uibPaging', 'uibPaginationConfig', function ($scope, $attrs, $parse, uibPaging, uibPaginationConfig) { + var ctrl = this; + // Setup configuration parameters + var maxSize = angular.isDefined($attrs.maxSize) ? $scope.$parent.$eval($attrs.maxSize) : uibPaginationConfig.maxSize, + rotate = angular.isDefined($attrs.rotate) ? $scope.$parent.$eval($attrs.rotate) : uibPaginationConfig.rotate, + forceEllipses = angular.isDefined($attrs.forceEllipses) ? $scope.$parent.$eval($attrs.forceEllipses) : uibPaginationConfig.forceEllipses, + boundaryLinkNumbers = angular.isDefined($attrs.boundaryLinkNumbers) ? $scope.$parent.$eval($attrs.boundaryLinkNumbers) : uibPaginationConfig.boundaryLinkNumbers; + $scope.boundaryLinks = angular.isDefined($attrs.boundaryLinks) ? $scope.$parent.$eval($attrs.boundaryLinks) : uibPaginationConfig.boundaryLinks; + $scope.directionLinks = angular.isDefined($attrs.directionLinks) ? $scope.$parent.$eval($attrs.directionLinks) : uibPaginationConfig.directionLinks; + + uibPaging.create(this, $scope, $attrs); + + if ($attrs.maxSize) { + $scope.$parent.$watch($parse($attrs.maxSize), function (value) { + maxSize = parseInt(value, 10); + ctrl.render(); + }); } - } 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, number === currentPage); - pages.push(page); - } - - // Add links to move between page sets - if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) { - if (startPage > 1) { - if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning - var previousPageSet = makePage(startPage - 1, '...', false); - pages.unshift(previousPageSet); - } - if (boundaryLinkNumbers) { - if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential - var secondPageLink = makePage(2, '2', false); - pages.unshift(secondPageLink); - } - //add the first page - var firstPageLink = makePage(1, '1', false); - pages.unshift(firstPageLink); + + // Create page object used in template + function makePage(number, text, isActive) { + return { + number: number, + text: text, + active: isActive + }; } - } - - if (endPage < totalPages) { - if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end - var nextPageSet = makePage(endPage + 1, '...', false); - pages.push(nextPageSet); - } - if (boundaryLinkNumbers) { - if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential - var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false); - pages.push(secondToLastPageLink); - } - //add the last page - var lastPageLink = makePage(totalPages, totalPages, false); - pages.push(lastPageLink); + + function getPages(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, number === currentPage); + pages.push(page); + } + + // Add links to move between page sets + if (isMaxSized && maxSize > 0 && (!rotate || forceEllipses || boundaryLinkNumbers)) { + if (startPage > 1) { + if (!boundaryLinkNumbers || startPage > 3) { //need ellipsis for all options unless range is too close to beginning + var previousPageSet = makePage(startPage - 1, '...', false); + pages.unshift(previousPageSet); + } + if (boundaryLinkNumbers) { + if (startPage === 3) { //need to replace ellipsis when the buttons would be sequential + var secondPageLink = makePage(2, '2', false); + pages.unshift(secondPageLink); + } + //add the first page + var firstPageLink = makePage(1, '1', false); + pages.unshift(firstPageLink); + } + } + + if (endPage < totalPages) { + if (!boundaryLinkNumbers || endPage < totalPages - 2) { //need ellipsis for all options unless range is too close to end + var nextPageSet = makePage(endPage + 1, '...', false); + pages.push(nextPageSet); + } + if (boundaryLinkNumbers) { + if (endPage === totalPages - 2) { //need to replace ellipsis when the buttons would be sequential + var secondToLastPageLink = makePage(totalPages - 1, totalPages - 1, false); + pages.push(secondToLastPageLink); + } + //add the last page + var lastPageLink = makePage(totalPages, totalPages, false); + pages.push(lastPageLink); + } + } + } + return pages; } - } - } - return pages; - } - - var originalRender = this.render; - this.render = function() { - originalRender(); - if ($scope.page > 0 && $scope.page <= $scope.totalPages) { - $scope.pages = getPages($scope.page, $scope.totalPages); - } - }; -}]) - -.constant('uibPaginationConfig', { - itemsPerPage: 10, - boundaryLinks: false, - boundaryLinkNumbers: false, - directionLinks: true, - firstText: 'First', - previousText: 'Previous', - nextText: 'Next', - lastText: 'Last', - rotate: true, - forceEllipses: false -}) - -.directive('uibPagination', ['$parse', 'uibPaginationConfig', function($parse, uibPaginationConfig) { - return { - scope: { - totalItems: '=', - firstText: '@', - previousText: '@', - nextText: '@', - lastText: '@', - ngDisabled:'=' - }, - require: ['uibPagination', '?ngModel'], - controller: 'UibPaginationController', - controllerAs: 'pagination', - templateUrl: function(element, attrs) { - return attrs.templateUrl || 'src/template/pagination/pagination.html'; - }, - replace: true, - link: function(scope, element, attrs, ctrls) { - var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; - - if (!ngModelCtrl) { - return; // do nothing if no ng-model - } - - paginationCtrl.init(ngModelCtrl, uibPaginationConfig); - } - }; -}]); + + var originalRender = this.render; + this.render = function () { + originalRender(); + if ($scope.page > 0 && $scope.page <= $scope.totalPages) { + $scope.pages = getPages($scope.page, $scope.totalPages); + } + }; + }]) + + .constant('uibPaginationConfig', { + itemsPerPage: 10, + boundaryLinks: false, + boundaryLinkNumbers: false, + directionLinks: true, + firstText: 'First', + previousText: 'Previous', + nextText: 'Next', + lastText: 'Last', + rotate: true, + forceEllipses: false + }) + + .directive('uibPagination', ['$parse', 'uibPaginationConfig', function ($parse, uibPaginationConfig) { + return { + scope: { + totalItems: '=', + firstText: '@', + previousText: '@', + nextText: '@', + lastText: '@', + ngDisabled: '=' + }, + require: ['uibPagination', '?ngModel'], + controller: 'UibPaginationController', + controllerAs: 'pagination', + templateUrl: function (element, attrs) { + return attrs.templateUrl || 'src/template/pagination/pagination.html'; + }, + replace: true, + link: function (scope, element, attrs, ctrls) { + var paginationCtrl = ctrls[0], ngModelCtrl = ctrls[1]; + + if (!ngModelCtrl) { + return; // do nothing if no ng-model + } + + paginationCtrl.init(ngModelCtrl, uibPaginationConfig); + } + }; + }]) + + .run(['$templateCache', function ($templateCache) { + + $templateCache.put('src/template/pagination/pagination.html', + "" + ); + + }]); \ No newline at end of file diff --git a/src/js/paging.js b/src/js/paging.js deleted file mode 100644 index 7adc5dd..0000000 --- a/src/js/paging.js +++ /dev/null @@ -1,85 +0,0 @@ -angular.module('ui.bootstrap.paging', []) -/** - * Helper internal service for generating common controller code between the - * pager and pagination components - */ -.factory('uibPaging', ['$parse', function($parse) { - return { - create: function(ctrl, $scope, $attrs) { - ctrl.setNumPages = $attrs.numPages ? $parse($attrs.numPages).assign : angular.noop; - ctrl.ngModelCtrl = { $setViewValue: angular.noop }; // nullModelCtrl - - ctrl.init = function(ngModelCtrl, config) { - ctrl.ngModelCtrl = ngModelCtrl; - ctrl.config = config; - - ngModelCtrl.$render = function() { - ctrl.render(); - }; - - if ($attrs.itemsPerPage) { - $scope.$parent.$watch($parse($attrs.itemsPerPage), function(value) { - ctrl.itemsPerPage = parseInt(value, 10); - $scope.totalPages = ctrl.calculateTotalPages(); - ctrl.updatePage(); - }); - } else { - ctrl.itemsPerPage = config.itemsPerPage; - } - - $scope.$watch('totalItems', function(newTotal, oldTotal) { - if (angular.isDefined(newTotal) || newTotal !== oldTotal) { - $scope.totalPages = ctrl.calculateTotalPages(); - ctrl.updatePage(); - } - }); - }; - - ctrl.calculateTotalPages = function() { - var totalPages = ctrl.itemsPerPage < 1 ? 1 : Math.ceil($scope.totalItems / ctrl.itemsPerPage); - return Math.max(totalPages || 0, 1); - }; - - ctrl.render = function() { - $scope.page = parseInt(ctrl.ngModelCtrl.$viewValue, 10) || 1; - }; - - $scope.selectPage = function(page, evt) { - if (evt) { - evt.preventDefault(); - } - - var clickAllowed = !$scope.ngDisabled || !evt; - if (clickAllowed && $scope.page !== page && page > 0 && page <= $scope.totalPages) { - if (evt && evt.target) { - evt.target.blur(); - } - ctrl.ngModelCtrl.$setViewValue(page); - ctrl.ngModelCtrl.$render(); - } - }; - - $scope.getText = function(key) { - return $scope[key + 'Text'] || ctrl.config[key + 'Text']; - }; - - $scope.noPrevious = function() { - return $scope.page === 1; - }; - - $scope.noNext = function() { - return $scope.page === $scope.totalPages; - }; - - ctrl.updatePage = function() { - ctrl.setNumPages($scope.$parent, $scope.totalPages); // Readonly variable - - if ($scope.page > $scope.totalPages) { - $scope.selectPage($scope.totalPages); - } else { - ctrl.ngModelCtrl.$render(); - } - }; - } - }; -}]); diff --git a/src/template/pagination/pagination.html b/src/template/pagination/pagination.html index f55a7b6..8c93196 100644 --- a/src/template/pagination/pagination.html +++ b/src/template/pagination/pagination.html @@ -1,7 +1,7 @@ -