972 lines
38 KiB
JavaScript
Executable File
972 lines
38 KiB
JavaScript
Executable File
(function(angular, factory) {
|
|
'use strict';
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
define(['angular'], function(angular) {
|
|
return factory(angular);
|
|
});
|
|
} else {
|
|
return factory(angular);
|
|
}
|
|
}(angular || null, function(angular) {
|
|
'use strict';
|
|
/**
|
|
* ngTable: Table + Angular JS
|
|
*
|
|
* @author Vitalii Savchuk <esvit666@gmail.com>
|
|
* @url https://github.com/esvit/ng-table/
|
|
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc module
|
|
* @name ngTable
|
|
* @description ngTable: Table + Angular JS
|
|
* @example
|
|
<doc:example>
|
|
<doc:source>
|
|
<script>
|
|
var app = angular.module('myApp', ['ngTable']);
|
|
app.controller('MyCtrl', function($scope) {
|
|
$scope.users = [
|
|
{name: "Moroni", age: 50},
|
|
{name: "Tiancum", age: 43},
|
|
{name: "Jacob", age: 27},
|
|
{name: "Nephi", age: 29},
|
|
{name: "Enos", age: 34}
|
|
];
|
|
});
|
|
</script>
|
|
<table ng-table class="table">
|
|
<tr ng-repeat="user in users">
|
|
<td data-title="'Name'">{{user.name}}</td>
|
|
<td data-title="'Age'">{{user.age}}</td>
|
|
</tr>
|
|
</table>
|
|
</doc:source>
|
|
</doc:example>
|
|
*/
|
|
var app = angular.module('ngTable', []);
|
|
/**
|
|
* ngTable: Table + Angular JS
|
|
*
|
|
* @author Vitalii Savchuk <esvit666@gmail.com>
|
|
* @url https://github.com/esvit/ng-table/
|
|
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc value
|
|
* @name ngTable.value:ngTableDefaultParams
|
|
* @description Default Parameters for ngTable
|
|
*/
|
|
app.value('ngTableDefaults', {
|
|
params: {},
|
|
settings: {}
|
|
});
|
|
|
|
/**
|
|
* @ngdoc service
|
|
* @name ngTable.factory:NgTableParams
|
|
* @description Parameters manager for ngTable
|
|
*/
|
|
|
|
app.factory('NgTableParams', ['$q', '$log', 'ngTableDefaults', function($q, $log, ngTableDefaults) {
|
|
var isNumber = function(n) {
|
|
return !isNaN(parseFloat(n)) && isFinite(n);
|
|
};
|
|
var NgTableParams = function(baseParameters, baseSettings) {
|
|
var self = this,
|
|
log = function() {
|
|
if (settings.debugMode && $log.debug) {
|
|
$log.debug.apply(this, arguments);
|
|
}
|
|
};
|
|
|
|
this.data = [];
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#parameters
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Set new parameters or get current parameters
|
|
*
|
|
* @param {string} newParameters New parameters
|
|
* @param {string} parseParamsFromUrl Flag if parse parameters like in url
|
|
* @returns {Object} Current parameters or `this`
|
|
*/
|
|
this.parameters = function(newParameters, parseParamsFromUrl) {
|
|
parseParamsFromUrl = parseParamsFromUrl || false;
|
|
if (angular.isDefined(newParameters)) {
|
|
for (var key in newParameters) {
|
|
var value = newParameters[key];
|
|
if (parseParamsFromUrl && key.indexOf('[') >= 0) {
|
|
var keys = key.split(/\[(.*)\]/).reverse()
|
|
var lastKey = '';
|
|
for (var i = 0, len = keys.length; i < len; i++) {
|
|
var name = keys[i];
|
|
if (name !== '') {
|
|
var v = value;
|
|
value = {};
|
|
value[lastKey = name] = (isNumber(v) ? parseFloat(v) : v);
|
|
}
|
|
}
|
|
if (lastKey === 'sorting') {
|
|
params[lastKey] = {};
|
|
}
|
|
params[lastKey] = angular.extend(params[lastKey] || {}, value[lastKey]);
|
|
} else {
|
|
params[key] = (isNumber(newParameters[key]) ? parseFloat(newParameters[key]) : newParameters[key]);
|
|
}
|
|
}
|
|
log('ngTable: set parameters', params);
|
|
return this;
|
|
}
|
|
return params;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#settings
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Set new settings for table
|
|
*
|
|
* @param {string} newSettings New settings or undefined
|
|
* @returns {Object} Current settings or `this`
|
|
*/
|
|
this.settings = function(newSettings) {
|
|
if (angular.isDefined(newSettings)) {
|
|
if (angular.isArray(newSettings.data)) {
|
|
//auto-set the total from passed in data
|
|
newSettings.total = newSettings.data.length;
|
|
}
|
|
settings = angular.extend(settings, newSettings);
|
|
log('ngTable: set settings', settings);
|
|
return this;
|
|
}
|
|
return settings;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#page
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description If parameter page not set return current page else set current page
|
|
*
|
|
* @param {string} page Page number
|
|
* @returns {Object|Number} Current page or `this`
|
|
*/
|
|
this.page = function(page) {
|
|
return angular.isDefined(page) ? this.parameters({
|
|
'page': page
|
|
}) : params.page;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#total
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description If parameter total not set return current quantity else set quantity
|
|
*
|
|
* @param {string} total Total quantity of items
|
|
* @returns {Object|Number} Current page or `this`
|
|
*/
|
|
this.total = function(total) {
|
|
return angular.isDefined(total) ? this.settings({
|
|
'total': total
|
|
}) : settings.total;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#count
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description If parameter count not set return current count per page else set count per page
|
|
*
|
|
* @param {string} count Count per number
|
|
* @returns {Object|Number} Count per page or `this`
|
|
*/
|
|
this.count = function(count) {
|
|
// reset to first page because can be blank page
|
|
return angular.isDefined(count) ? this.parameters({
|
|
'count': count,
|
|
'page': 1
|
|
}) : params.count;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#filter
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description If parameter page not set return current filter else set current filter
|
|
*
|
|
* @param {string} filter New filter
|
|
* @returns {Object} Current filter or `this`
|
|
*/
|
|
this.filter = function(filter) {
|
|
return angular.isDefined(filter) ? this.parameters({
|
|
'filter': filter,
|
|
'page': 1
|
|
}) : params.filter;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#sorting
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description If 'sorting' parameter is not set, return current sorting. Otherwise set current sorting.
|
|
*
|
|
* @param {string} sorting New sorting
|
|
* @returns {Object} Current sorting or `this`
|
|
*/
|
|
this.sorting = function(sorting) {
|
|
if (arguments.length == 2) {
|
|
var sortArray = {};
|
|
sortArray[sorting] = arguments[1];
|
|
this.parameters({
|
|
'sorting': sortArray
|
|
});
|
|
return this;
|
|
}
|
|
return angular.isDefined(sorting) ? this.parameters({
|
|
'sorting': sorting
|
|
}) : params.sorting;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#isSortBy
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Checks sort field
|
|
*
|
|
* @param {string} field Field name
|
|
* @param {string} direction Direction of sorting 'asc' or 'desc'
|
|
* @returns {Array} Return true if field sorted by direction
|
|
*/
|
|
this.isSortBy = function(field, direction) {
|
|
return angular.isDefined(params.sorting[field]) && angular.equals(params.sorting[field], direction);
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#orderBy
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Return object of sorting parameters for angular filter
|
|
*
|
|
* @returns {Array} Array like: [ '-name', '+age' ]
|
|
*/
|
|
this.orderBy = function() {
|
|
var sorting = [];
|
|
for (var column in params.sorting) {
|
|
sorting.push((params.sorting[column] === "asc" ? "+" : "-") + column);
|
|
}
|
|
return sorting;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#getData
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Called when updated some of parameters for get new data
|
|
*
|
|
* @param {Object} $defer promise object
|
|
* @param {Object} params New parameters
|
|
*/
|
|
this.getData = function($defer, params) {
|
|
if (angular.isArray(this.data) && angular.isObject(params)) {
|
|
$defer.resolve(this.data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
|
|
} else {
|
|
$defer.resolve([]);
|
|
}
|
|
return $defer.promise;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#getGroups
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Return groups for table grouping
|
|
*/
|
|
this.getGroups = function($defer, column) {
|
|
var defer = $q.defer();
|
|
|
|
defer.promise.then(function(data) {
|
|
var groups = {};
|
|
angular.forEach(data, function(item) {
|
|
var groupName = angular.isFunction(column) ? column(item) : item[column];
|
|
|
|
groups[groupName] = groups[groupName] || {
|
|
data: []
|
|
};
|
|
groups[groupName]['value'] = groupName;
|
|
groups[groupName].data.push(item);
|
|
});
|
|
var result = [];
|
|
for (var i in groups) {
|
|
result.push(groups[i]);
|
|
}
|
|
log('ngTable: refresh groups', result);
|
|
$defer.resolve(result);
|
|
});
|
|
return this.getData(defer, self);
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#generatePagesArray
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Generate array of pages
|
|
*
|
|
* @param {boolean} currentPage which page must be active
|
|
* @param {boolean} totalItems Total quantity of items
|
|
* @param {boolean} pageSize Quantity of items on page
|
|
* @returns {Array} Array of pages
|
|
*/
|
|
this.generatePagesArray = function(currentPage, totalItems, pageSize) {
|
|
var maxBlocks, maxPage, maxPivotPages, minPage, numPages, pages;
|
|
maxBlocks = 11;
|
|
pages = [];
|
|
numPages = Math.ceil(totalItems / pageSize);
|
|
if (numPages > 1) {
|
|
pages.push({
|
|
type: 'prev',
|
|
number: Math.max(1, currentPage - 1),
|
|
active: currentPage > 1
|
|
});
|
|
pages.push({
|
|
type: 'first',
|
|
number: 1,
|
|
active: currentPage > 1,
|
|
current: currentPage === 1
|
|
});
|
|
maxPivotPages = Math.round((maxBlocks - 5) / 2);
|
|
minPage = Math.max(2, currentPage - maxPivotPages);
|
|
maxPage = Math.min(numPages - 1, currentPage + maxPivotPages * 2 - (currentPage - minPage));
|
|
minPage = Math.max(2, minPage - (maxPivotPages * 2 - (maxPage - minPage)));
|
|
var i = minPage;
|
|
while (i <= maxPage) {
|
|
if ((i === minPage && i !== 2) || (i === maxPage && i !== numPages - 1)) {
|
|
pages.push({
|
|
type: 'more',
|
|
active: false
|
|
});
|
|
} else {
|
|
pages.push({
|
|
type: 'page',
|
|
number: i,
|
|
active: currentPage !== i,
|
|
current: currentPage === i
|
|
});
|
|
}
|
|
i++;
|
|
}
|
|
pages.push({
|
|
type: 'last',
|
|
number: numPages,
|
|
active: currentPage !== numPages,
|
|
current: currentPage === numPages
|
|
});
|
|
pages.push({
|
|
type: 'next',
|
|
number: Math.min(numPages, currentPage + 1),
|
|
active: currentPage < numPages
|
|
});
|
|
}
|
|
return pages;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#url
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Return groups for table grouping
|
|
*
|
|
* @param {boolean} asString flag indicates return array of string or object
|
|
* @returns {Array} If asString = true will be return array of url string parameters else key-value object
|
|
*/
|
|
this.url = function(asString) {
|
|
asString = asString || false;
|
|
var pairs = (asString ? [] : {});
|
|
for (var key in params) {
|
|
if (params.hasOwnProperty(key)) {
|
|
var item = params[key],
|
|
name = encodeURIComponent(key);
|
|
if (typeof item === "object") {
|
|
for (var subkey in item) {
|
|
if (!angular.isUndefined(item[subkey]) && item[subkey] !== "") {
|
|
var pname = name + "[" + encodeURIComponent(subkey) + "]";
|
|
if (asString) {
|
|
pairs.push(pname + "=" + item[subkey]);
|
|
} else {
|
|
pairs[pname] = item[subkey];
|
|
}
|
|
}
|
|
}
|
|
} else if (!angular.isFunction(item) && !angular.isUndefined(item) && item !== "") {
|
|
if (asString) {
|
|
pairs.push(name + "=" + encodeURIComponent(item));
|
|
} else {
|
|
pairs[name] = encodeURIComponent(item);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return pairs;
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:NgTableParams#reload
|
|
* @methodOf ngTable.factory:NgTableParams
|
|
* @description Reload table data
|
|
*/
|
|
this.reload = function() {
|
|
var $defer = $q.defer(),
|
|
self = this,
|
|
pData = null;
|
|
|
|
if (!settings.$scope) {
|
|
return;
|
|
}
|
|
|
|
settings.$loading = true;
|
|
if (settings.groupBy) {
|
|
pData = settings.getGroups($defer, settings.groupBy, this);
|
|
} else {
|
|
pData = settings.getData($defer, this);
|
|
}
|
|
log('ngTable: reload data');
|
|
|
|
if (!pData) {
|
|
// If getData resolved the $defer, and didn't promise us data,
|
|
// create a promise from the $defer. We need to return a promise.
|
|
pData = $defer.promise;
|
|
}
|
|
return pData.then(function(data) {
|
|
settings.$loading = false;
|
|
log('ngTable: current scope', settings.$scope);
|
|
if (settings.groupBy) {
|
|
self.data = data;
|
|
if (settings.$scope) settings.$scope.$groups = data;
|
|
} else {
|
|
self.data = data;
|
|
if (settings.$scope) settings.$scope.$data = data;
|
|
}
|
|
if (settings.$scope) settings.$scope.pages = self.generatePagesArray(self.page(), self.total(), self.count());
|
|
settings.$scope.$emit('ngTableAfterReloadData');
|
|
return data;
|
|
});
|
|
};
|
|
|
|
this.reloadPages = function() {
|
|
var self = this;
|
|
settings.$scope.pages = self.generatePagesArray(self.page(), self.total(), self.count());
|
|
};
|
|
|
|
var params = this.$params = {
|
|
page: 1,
|
|
count: 1,
|
|
filter: {},
|
|
sorting: {},
|
|
group: {},
|
|
groupBy: null
|
|
};
|
|
angular.extend(params, ngTableDefaults.params);
|
|
|
|
var settings = {
|
|
$scope: null, // set by ngTable controller
|
|
$loading: false,
|
|
data: null, //allows data to be set when table is initialized
|
|
total: 0,
|
|
defaultSort: 'desc',
|
|
filterDelay: 750,
|
|
counts: [10, 25, 50, 100],
|
|
sortingIndicator: 'span',
|
|
getGroups: this.getGroups,
|
|
getData: this.getData
|
|
};
|
|
angular.extend(settings, ngTableDefaults.settings);
|
|
|
|
this.settings(baseSettings);
|
|
this.parameters(baseParameters, true);
|
|
return this;
|
|
};
|
|
return NgTableParams;
|
|
}]);
|
|
|
|
/**
|
|
* @ngdoc service
|
|
* @name ngTable.factory:ngTableParams
|
|
* @description Backwards compatible shim for lowercase 'n' in NgTableParams
|
|
*/
|
|
app.factory('ngTableParams', ['NgTableParams', function(NgTableParams) {
|
|
return NgTableParams;
|
|
}]);
|
|
|
|
/**
|
|
* ngTable: Table + Angular JS
|
|
*
|
|
* @author Vitalii Savchuk <esvit666@gmail.com>
|
|
* @url https://github.com/esvit/ng-table/
|
|
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc object
|
|
* @name ngTable.directive:ngTable.ngTableController
|
|
*
|
|
* @description
|
|
* Each {@link ngTable.directive:ngTable ngTable} directive creates an instance of `ngTableController`
|
|
*/
|
|
app.controller('ngTableController', ['$scope', 'NgTableParams', '$timeout', '$parse', '$compile', '$attrs', '$element',
|
|
'ngTableColumn',
|
|
function($scope, NgTableParams, $timeout, $parse, $compile, $attrs, $element, ngTableColumn) {
|
|
var isFirstTimeLoad = true;
|
|
$scope.$filterRow = {};
|
|
$scope.$loading = false;
|
|
|
|
// until such times as the directive uses an isolated scope, we need to ensure that the check for
|
|
// the params field only consults the "own properties" of the $scope. This is to avoid seeing the params
|
|
// field on a $scope higher up in the prototype chain
|
|
if (!$scope.hasOwnProperty("params")) {
|
|
$scope.params = new NgTableParams();
|
|
$scope.params.isNullInstance = true;
|
|
}
|
|
$scope.params.settings().$scope = $scope;
|
|
|
|
var delayFilter = (function() {
|
|
var timer = 0;
|
|
return function(callback, ms) {
|
|
$timeout.cancel(timer);
|
|
timer = $timeout(callback, ms);
|
|
};
|
|
})();
|
|
|
|
function resetPage() {
|
|
$scope.params.$params.page = 1;
|
|
}
|
|
|
|
$scope.$watch('params.$params', function(newParams, oldParams) {
|
|
|
|
if (newParams === oldParams) {
|
|
return;
|
|
}
|
|
|
|
$scope.params.settings().$scope = $scope;
|
|
|
|
if (!angular.equals(newParams.filter, oldParams.filter)) {
|
|
var maybeResetPage = isFirstTimeLoad ? angular.noop : resetPage;
|
|
delayFilter(function() {
|
|
maybeResetPage();
|
|
$scope.params.reload();
|
|
}, $scope.params.settings().filterDelay);
|
|
} else {
|
|
$scope.params.reload();
|
|
}
|
|
|
|
if (!$scope.params.isNullInstance) {
|
|
isFirstTimeLoad = false;
|
|
}
|
|
|
|
}, true);
|
|
|
|
this.compileDirectiveTemplates = function () {
|
|
if (!$element.hasClass('ng-table')) {
|
|
$scope.templates = {
|
|
header: ($attrs.templateHeader ? $attrs.templateHeader : 'ng-table/header.html'),
|
|
pagination: ($attrs.templatePagination ? $attrs.templatePagination : 'ng-table/pager.html')
|
|
};
|
|
$element.addClass('ng-table');
|
|
var headerTemplate = null;
|
|
if ($element.find('> thead').length === 0) {
|
|
headerTemplate = angular.element(document.createElement('thead')).attr('ng-include', 'templates.header');
|
|
$element.prepend(headerTemplate);
|
|
}
|
|
var paginationTemplate = angular.element(document.createElement('div')).attr({
|
|
'ng-table-pagination': 'params',
|
|
'template-url': 'templates.pagination'
|
|
});
|
|
$element.after(paginationTemplate);
|
|
if (headerTemplate) {
|
|
$compile(headerTemplate)($scope);
|
|
}
|
|
$compile(paginationTemplate)($scope);
|
|
}
|
|
};
|
|
|
|
this.loadFilterData = function ($columns) {
|
|
angular.forEach($columns, function ($column) {
|
|
var def;
|
|
def = $column.filterData($scope, {
|
|
$column: $column
|
|
});
|
|
if (!def) {
|
|
delete $column.filterData;
|
|
return;
|
|
}
|
|
|
|
// if we're working with a deferred object, let's wait for the promise
|
|
if ((angular.isObject(def) && angular.isObject(def.promise))) {
|
|
delete $column.filterData;
|
|
return def.promise.then(function(data) {
|
|
// our deferred can eventually return arrays, functions and objects
|
|
if (!angular.isArray(data) && !angular.isFunction(data) && !angular.isObject(data)) {
|
|
// if none of the above was found - we just want an empty array
|
|
data = [];
|
|
} else if (angular.isArray(data)) {
|
|
data.unshift({
|
|
title: '-',
|
|
id: ''
|
|
});
|
|
}
|
|
$column.data = data;
|
|
});
|
|
}
|
|
// otherwise, we just return what the user gave us. It could be a function, array, object, whatever
|
|
else {
|
|
return $column.data = def;
|
|
}
|
|
});
|
|
};
|
|
|
|
this.buildColumns = function (columns) {
|
|
return columns.map(function(col){
|
|
return ngTableColumn.buildColumn(col, $scope)
|
|
})
|
|
};
|
|
|
|
this.setupBindingsToInternalScope = function(tableParamsExpr){
|
|
|
|
// note: this we're setting up watches to simulate angular's isolated scope bindings
|
|
|
|
// note: is REALLY important to watch for a change to the ngTableParams *reference* rather than
|
|
// $watch for value equivalence. This is because ngTableParams references the current page of data as
|
|
// a field and it's important not to watch this
|
|
var tableParamsGetter = $parse(tableParamsExpr);
|
|
$scope.$watch(tableParamsGetter, (function (params) {
|
|
if (angular.isUndefined(params)) {
|
|
return;
|
|
}
|
|
$scope.paramsModel = tableParamsGetter;
|
|
$scope.params = params;
|
|
}), false);
|
|
|
|
if ($attrs.showFilter) {
|
|
$scope.$parent.$watch($attrs.showFilter, function(value) {
|
|
$scope.show_filter = value;
|
|
});
|
|
}
|
|
if ($attrs.disableFilter) {
|
|
$scope.$parent.$watch($attrs.disableFilter, function(value) {
|
|
$scope.$filterRow.disabled = value;
|
|
});
|
|
}
|
|
};
|
|
|
|
$scope.sortBy = function($column, event) {
|
|
var parsedSortable = $column.sortable && $column.sortable();
|
|
if (!parsedSortable) {
|
|
return;
|
|
}
|
|
var defaultSort = $scope.params.settings().defaultSort;
|
|
var inverseSort = (defaultSort === 'asc' ? 'desc' : 'asc');
|
|
var sorting = $scope.params.sorting() && $scope.params.sorting()[parsedSortable] && ($scope.params.sorting()[parsedSortable] === defaultSort);
|
|
var sortingParams = (event.ctrlKey || event.metaKey) ? $scope.params.sorting() : {};
|
|
sortingParams[parsedSortable] = (sorting ? inverseSort : defaultSort);
|
|
$scope.params.parameters({
|
|
sorting: sortingParams
|
|
});
|
|
};
|
|
}]);
|
|
|
|
|
|
/**
|
|
* @ngdoc service
|
|
* @name ngTable.factory:ngTableColumn
|
|
*
|
|
* @description
|
|
* Service to construct a $column definition used by {@link ngTable.directive:ngTable ngTable} directive
|
|
*/
|
|
app.factory('ngTableColumn', [function () {
|
|
|
|
var defaults = {
|
|
'class': function(){ return ''; },
|
|
filter: function(){ return false; },
|
|
filterData: angular.noop,
|
|
headerTemplateURL: function(){ return false; },
|
|
headerTitle: function(){ return ' '; },
|
|
sortable: function(){ return false; },
|
|
show: function(){ return true; },
|
|
title: function(){ return ' '; },
|
|
titleAlt: function(){ return ''; }
|
|
};
|
|
|
|
/**
|
|
* @ngdoc method
|
|
* @name ngTable.factory:ngTableColumn#buildColumn
|
|
* @methodOf ngTable.factory:ngTableColumn
|
|
* @description Creates a $column for use within a header template
|
|
*
|
|
* @param {Object} column an existing $column or simple column data object
|
|
* @param {Scope} defaultScope the $scope to supply to the $column getter methods when not supplied by caller
|
|
* @returns {Object} a $column object
|
|
*/
|
|
function buildColumn(column, defaultScope){
|
|
// note: we're not modifying the original column object. This helps to avoid unintended side affects
|
|
var extendedCol = Object.create(column);
|
|
for (var prop in defaults) {
|
|
if (extendedCol[prop] === undefined) {
|
|
extendedCol[prop] = defaults[prop];
|
|
}
|
|
if(!angular.isFunction(extendedCol[prop])){
|
|
// wrap raw field values with "getter" functions
|
|
// - this is to ensure consistency with how ngTable.compile builds columns
|
|
// - note that the original column object is being "proxied"; this is important
|
|
// as it ensure that any changes to the original object will be returned by the "getter"
|
|
(function(prop1){
|
|
extendedCol[prop1] = function(){
|
|
return column[prop1];
|
|
};
|
|
})(prop);
|
|
}
|
|
(function(prop1){
|
|
// satisfy the arguments expected by the function returned by parsedAttribute in the ngTable directive
|
|
var getterFn = extendedCol[prop1];
|
|
extendedCol[prop1] = function(){
|
|
if (arguments.length === 0){
|
|
return getterFn.call(column, defaultScope);
|
|
} else {
|
|
return getterFn.apply(column, arguments);
|
|
}
|
|
};
|
|
})(prop);
|
|
}
|
|
return extendedCol;
|
|
}
|
|
|
|
return {
|
|
buildColumn: buildColumn
|
|
};
|
|
}]);
|
|
|
|
/**
|
|
* ngTable: Table + Angular JS
|
|
*
|
|
* @author Vitalii Savchuk <esvit666@gmail.com>
|
|
* @url https://github.com/esvit/ng-table/
|
|
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ngTable.directive:ngTable
|
|
* @restrict A
|
|
*
|
|
* @description
|
|
* Directive that instantiates {@link ngTable.directive:ngTable.ngTableController ngTableController}.
|
|
*/
|
|
app.directive('ngTable', ['$q', '$parse',
|
|
function($q, $parse) {
|
|
'use strict';
|
|
|
|
return {
|
|
restrict: 'A',
|
|
priority: 1001,
|
|
scope: true,
|
|
controller: 'ngTableController',
|
|
compile: function(element) {
|
|
var columns = [],
|
|
i = 0,
|
|
row = null;
|
|
|
|
// IE 8 fix :not(.ng-table-group) selector
|
|
angular.forEach(angular.element(element.find('tr')), function(tr) {
|
|
tr = angular.element(tr);
|
|
if (!tr.hasClass('ng-table-group') && !row) {
|
|
row = tr;
|
|
}
|
|
});
|
|
if (!row) {
|
|
return;
|
|
}
|
|
angular.forEach(row.find('td'), function(item) {
|
|
var el = angular.element(item);
|
|
if (el.attr('ignore-cell') && 'true' === el.attr('ignore-cell')) {
|
|
return;
|
|
}
|
|
|
|
var getAttrValue = function(attr){
|
|
return el.attr('x-data-' + attr) || el.attr('data-' + attr) || el.attr(attr);
|
|
};
|
|
|
|
var parsedAttribute = function(attr) {
|
|
var expr = getAttrValue(attr);
|
|
if (!expr){
|
|
return undefined;
|
|
}
|
|
return function(scope, locals) {
|
|
return $parse(expr)(scope, angular.extend(locals || {}, {
|
|
$columns: columns
|
|
}));
|
|
};
|
|
};
|
|
|
|
var titleExpr = getAttrValue('title-alt') || getAttrValue('title');
|
|
if (titleExpr){
|
|
el.attr('data-title-text', '{{' + titleExpr + '}}'); // this used in responsive table
|
|
}
|
|
// NOTE TO MAINTAINERS: if you add extra fields to a $column be sure to extend ngTableColumn with
|
|
// a corresponding "safe" default
|
|
columns.push({
|
|
id: i++,
|
|
title: parsedAttribute('title'),
|
|
titleAlt: parsedAttribute('title-alt'),
|
|
headerTitle: parsedAttribute('header-title'),
|
|
sortable: parsedAttribute('sortable'),
|
|
'class': parsedAttribute('header-class'),
|
|
filter: parsedAttribute('filter'),
|
|
headerTemplateURL: parsedAttribute('header'),
|
|
filterData: parsedAttribute('filter-data'),
|
|
show: (el.attr("ng-show") ? function (scope) {
|
|
return $parse(el.attr("ng-show"))(scope);
|
|
} : undefined)
|
|
});
|
|
});
|
|
return function(scope, element, attrs, controller) {
|
|
scope.$columns = columns = controller.buildColumns(columns);
|
|
|
|
controller.setupBindingsToInternalScope(attrs.ngTable);
|
|
controller.loadFilterData(columns);
|
|
controller.compileDirectiveTemplates();
|
|
};
|
|
}
|
|
}
|
|
}
|
|
]);
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ngTable.directive:ngTableDynamic
|
|
* @restrict A
|
|
*
|
|
* @description
|
|
* A dynamic version of the {@link ngTable.directive:ngTable ngTable} directive that accepts a dynamic list of columns
|
|
* definitions to render
|
|
*/
|
|
app.directive('ngTableDynamic', ['$parse', function ($parse){
|
|
|
|
function parseDirectiveExpression(attr) {
|
|
if (!attr || attr.indexOf(" with ") > -1) {
|
|
var parts = attr.split(/\s+with\s+/);
|
|
return {
|
|
tableParams: parts[0],
|
|
columns: parts[1]
|
|
};
|
|
} else {
|
|
throw new Error('Parse error (expected example: ng-table-dynamic=\'tableParams with cols\')');
|
|
}
|
|
}
|
|
|
|
return {
|
|
restrict: 'A',
|
|
priority: 1001,
|
|
scope: true,
|
|
controller: 'ngTableController',
|
|
compile: function(tElement) {
|
|
var row;
|
|
|
|
// IE 8 fix :not(.ng-table-group) selector
|
|
angular.forEach(angular.element(tElement.find('tr')), function(tr) {
|
|
tr = angular.element(tr);
|
|
if (!tr.hasClass('ng-table-group') && !row) {
|
|
row = tr;
|
|
}
|
|
});
|
|
if (!row) {
|
|
return;
|
|
}
|
|
|
|
angular.forEach(row.find('td'), function(item) {
|
|
var el = angular.element(item);
|
|
var getAttrValue = function(attr){
|
|
return el.attr('x-data-' + attr) || el.attr('data-' + attr) || el.attr(attr);
|
|
};
|
|
|
|
// this used in responsive table
|
|
var titleExpr = getAttrValue('title');
|
|
if (!titleExpr){
|
|
el.attr('data-title-text', '{{$columns[$index].titleAlt(this) || $columns[$index].title(this)}}');
|
|
}
|
|
var showExpr = el.attr('ng-show');
|
|
if (!showExpr){
|
|
el.attr('ng-show', '$columns[$index].show(this)');
|
|
}
|
|
});
|
|
|
|
return function(scope, element, attrs, controller) {
|
|
var expr = parseDirectiveExpression(attrs.ngTableDynamic);
|
|
var columns = $parse(expr.columns)(scope) || [];
|
|
scope.$columns = controller.buildColumns(columns);
|
|
|
|
controller.setupBindingsToInternalScope(expr.tableParams);
|
|
controller.loadFilterData(scope.$columns);
|
|
controller.compileDirectiveTemplates();
|
|
};
|
|
}
|
|
};
|
|
}]);
|
|
|
|
/**
|
|
* ngTable: Table + Angular JS
|
|
*
|
|
* @author Vitalii Savchuk <esvit666@gmail.com>
|
|
* @url https://github.com/esvit/ng-table/
|
|
* @license New BSD License <http://creativecommons.org/licenses/BSD/>
|
|
*/
|
|
|
|
/**
|
|
* @ngdoc directive
|
|
* @name ngTable.directive:ngTablePagination
|
|
* @restrict A
|
|
*/
|
|
app.directive('ngTablePagination', ['$compile',
|
|
function($compile) {
|
|
'use strict';
|
|
|
|
return {
|
|
restrict: 'A',
|
|
scope: {
|
|
'params': '=ngTablePagination',
|
|
'templateUrl': '='
|
|
},
|
|
replace: false,
|
|
link: function(scope, element, attrs) {
|
|
|
|
scope.params.settings().$scope.$on('ngTableAfterReloadData', function() {
|
|
scope.pages = scope.params.generatePagesArray(scope.params.page(), scope.params.total(), scope.params.count());
|
|
}, true);
|
|
|
|
scope.$watch('templateUrl', function(templateUrl) {
|
|
if (angular.isUndefined(templateUrl)) {
|
|
return;
|
|
}
|
|
var template = angular.element(document.createElement('div'))
|
|
template.attr({
|
|
'ng-include': 'templateUrl'
|
|
});
|
|
element.append(template);
|
|
$compile(template)(scope);
|
|
});
|
|
}
|
|
};
|
|
}
|
|
]);
|
|
angular.module('ngTable').run(['$templateCache', function ($templateCache) {
|
|
$templateCache.put('ng-table/filters/select-multiple.html', '<select ng-options="data.id as data.title for data in $column.data" ng-disabled="$filterRow.disabled" multiple ng-multiple="true" ng-model="params.filter()[name]" ng-show="filter==\'select-multiple\'" class="filter filter-select-multiple form-control" name="{{name}}"> </select>');
|
|
$templateCache.put('ng-table/filters/select.html', '<select ng-options="data.id as data.title for data in $column.data" ng-disabled="$filterRow.disabled" ng-model="params.filter()[name]" ng-show="filter==\'select\'" class="filter filter-select form-control" name="{{name}}"> </select>');
|
|
$templateCache.put('ng-table/filters/text.html', '<input type="text" name="{{name}}" ng-disabled="$filterRow.disabled" ng-model="params.filter()[name]" ng-if="filter==\'text\'" class="input-filter form-control"/>');
|
|
$templateCache.put('ng-table/header.html', '<tr> <th title="{{$column.headerTitle(this)}}" ng-repeat="$column in $columns" ng-class="{ \'sortable\': $column.sortable(this), \'sort-asc\': params.sorting()[$column.sortable(this)]==\'asc\', \'sort-desc\': params.sorting()[$column.sortable(this)]==\'desc\' }" ng-click="sortBy($column, $event)" ng-show="$column.show(this)" ng-init="template=$column.headerTemplateURL(this)" class="header {{$column.class(this)}}"> <div ng-if="!template" ng-show="!template" class="ng-table-header" ng-class="{\'sort-indicator\': params.settings().sortingIndicator==\'div\'}"> <span ng-bind="$column.title(this)" ng-class="{\'sort-indicator\': params.settings().sortingIndicator==\'span\'}"></span> </div> <div ng-if="template" ng-show="template" ng-include="template"></div> </th> </tr> <tr ng-show="show_filter" class="ng-table-filters"> <th data-title-text="{{$column.titleAlt(this) || $column.title(this)}}" ng-repeat="$column in $columns" ng-show="$column.show(this)" class="filter"> <div ng-repeat="(name, filter) in $column.filter(this)"> <div ng-if="filter.indexOf(\'/\') !==-1" ng-include="filter"></div> <div ng-if="filter.indexOf(\'/\')===-1" ng-include="\'ng-table/filters/\' + filter + \'.html\'"></div> </div> </th> </tr> ');
|
|
$templateCache.put('ng-table/pager.html', '<div class="ng-cloak ng-table-pager" ng-if="params.data.length"> <div ng-if="params.settings().counts.length" class="ng-table-counts btn-group pull-right"> <button ng-repeat="count in params.settings().counts" type="button" ng-class="{\'active\':params.count()==count}" ng-click="params.count(count)" class="btn btn-default"> <span ng-bind="count"></span> </button> </div> <ul class="pagination ng-table-pagination"> <li ng-class="{\'disabled\': !page.active && !page.current, \'active\': page.current}" ng-repeat="page in pages" ng-switch="page.type"> <a ng-switch-when="prev" ng-click="params.page(page.number)" href="">«</a> <a ng-switch-when="first" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="page" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="more" ng-click="params.page(page.number)" href="">…</a> <a ng-switch-when="last" ng-click="params.page(page.number)" href=""><span ng-bind="page.number"></span></a> <a ng-switch-when="next" ng-click="params.page(page.number)" href="">»</a> </li> </ul> </div> ');
|
|
}]);
|
|
return app;
|
|
})); |