You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sirona.apache.org by ol...@apache.org on 2014/08/22 09:06:30 UTC
svn commit: r1619686 [2/3] - in /incubator/sirona/trunk/server/reporting:
reporting-api/src/main/java/org/apache/sirona/reporting/web/counters/
reporting-ui/src/main/webapp/css/ reporting-ui/src/main/webapp/js/
reporting-ui/src/main/webapp/js/app/contr...
Added: incubator/sirona/trunk/server/reporting/reporting-ui/src/main/webapp/js/ng-grid-2.0.12.debug.js
URL: http://svn.apache.org/viewvc/incubator/sirona/trunk/server/reporting/reporting-ui/src/main/webapp/js/ng-grid-2.0.12.debug.js?rev=1619686&view=auto
==============================================================================
--- incubator/sirona/trunk/server/reporting/reporting-ui/src/main/webapp/js/ng-grid-2.0.12.debug.js (added)
+++ incubator/sirona/trunk/server/reporting/reporting-ui/src/main/webapp/js/ng-grid-2.0.12.debug.js Fri Aug 22 07:06:30 2014
@@ -0,0 +1,4031 @@
+/***********************************************
+* ng-grid JavaScript Library
+* Authors: https://github.com/angular-ui/ng-grid/blob/master/README.md
+* License: MIT (http://www.opensource.org/licenses/mit-license.php)
+* Compiled At: 08/04/2014 16:09
+***********************************************/
+(function(window, $) {
+'use strict';
+// the # of rows we want to add to the top and bottom of the rendered grid rows
+var EXCESS_ROWS = 6;
+var SCROLL_THRESHOLD = 4;
+var ASC = "asc";
+// constant for sorting direction
+var DESC = "desc";
+// constant for sorting direction
+var NG_FIELD = '_ng_field_';
+var NG_DEPTH = '_ng_depth_';
+var NG_HIDDEN = '_ng_hidden_';
+var NG_COLUMN = '_ng_column_';
+var CUSTOM_FILTERS = /CUSTOM_FILTERS/g;
+var COL_FIELD = /COL_FIELD/g;
+var DISPLAY_CELL_TEMPLATE = /DISPLAY_CELL_TEMPLATE/g;
+var EDITABLE_CELL_TEMPLATE = /EDITABLE_CELL_TEMPLATE/g;
+var CELL_EDITABLE_CONDITION = /CELL_EDITABLE_CONDITION/g;
+var TEMPLATE_REGEXP = /<.+>/;
+window.ngGrid = {};
+window.ngGrid.i18n = {};
+
+// Declare app level module which depends on filters, and services
+var ngGridServices = angular.module('ngGrid.services', []);
+var ngGridDirectives = angular.module('ngGrid.directives', []);
+var ngGridFilters = angular.module('ngGrid.filters', []);
+// initialization of services into the main module
+angular.module('ngGrid', ['ngGrid.services', 'ngGrid.directives', 'ngGrid.filters']);
+//set event binding on the grid so we can select using the up/down keys
+var ngMoveSelectionHandler = function($scope, elm, evt, grid) {
+ if ($scope.selectionProvider.selectedItems === undefined) {
+ return true;
+ }
+
+ var charCode = evt.which || evt.keyCode,
+ newColumnIndex,
+ lastInRow = false,
+ firstInRow = false,
+ rowIndex = $scope.selectionProvider.lastClickedRow === undefined ? 1 : $scope.selectionProvider.lastClickedRow.rowIndex,
+ visibleCols = $scope.columns.filter(function(c) {
+ return c.visible && c.width > 0;
+ }),
+ pinnedCols = $scope.columns.filter(function(c) { return c.pinned; });
+
+ if ($scope.col) {
+ newColumnIndex = visibleCols.indexOf($scope.col);
+ }
+
+ if (charCode !== 37 && charCode !== 38 && charCode !== 39 && charCode !== 40 && (grid.config.noTabInterference || charCode !== 9) && charCode !== 13) {
+ return true;
+ }
+
+ if ($scope.enableCellSelection) {
+ if (charCode === 9) { //tab key
+ evt.preventDefault();
+ }
+
+ var focusedOnFirstColumn = $scope.showSelectionCheckbox ? newColumnIndex === 1 : newColumnIndex === 0;
+ var focusedOnFirstVisibleColumns = newColumnIndex === 1 || newColumnIndex === 0;
+ var focusedOnLastVisibleColumns = newColumnIndex === (visibleCols.length - 1) || newColumnIndex === (visibleCols.length - 2);
+ var focusedOnLastColumn = visibleCols.indexOf($scope.col) === (visibleCols.length - 1);
+ var focusedOnLastPinnedColumn = pinnedCols.indexOf($scope.col) === (pinnedCols.length - 1);
+
+ if (charCode === 37 || charCode === 9 && evt.shiftKey) {
+ var scrollTo = 0;
+
+ if (!focusedOnFirstColumn) {
+ newColumnIndex -= 1;
+ }
+
+ if (focusedOnFirstVisibleColumns) {
+ if (focusedOnFirstColumn && charCode === 9 && evt.shiftKey){
+ scrollTo = grid.$canvas.width();
+ newColumnIndex = visibleCols.length - 1;
+ firstInRow = true;
+ }
+ else {
+ scrollTo = grid.$viewport.scrollLeft() - $scope.col.width;
+ }
+ }
+ else if (pinnedCols.length > 0) {
+ scrollTo = grid.$viewport.scrollLeft() - visibleCols[newColumnIndex].width;
+ }
+
+ grid.$viewport.scrollLeft(scrollTo);
+
+ }
+ else if (charCode === 39 || charCode === 9 && !evt.shiftKey) {
+ if (focusedOnLastVisibleColumns) {
+ if (focusedOnLastColumn && charCode === 9 && !evt.shiftKey) {
+ grid.$viewport.scrollLeft(0);
+ newColumnIndex = $scope.showSelectionCheckbox ? 1 : 0;
+ lastInRow = true;
+ }
+ else {
+ grid.$viewport.scrollLeft(grid.$viewport.scrollLeft() + $scope.col.width);
+ }
+ }
+ else if (focusedOnLastPinnedColumn) {
+ grid.$viewport.scrollLeft(0);
+ }
+
+ if (!focusedOnLastColumn) {
+ newColumnIndex += 1;
+ }
+ }
+ }
+
+ var items;
+ if ($scope.configGroups.length > 0) {
+ items = grid.rowFactory.parsedData.filter(function (row) {
+ return !row.isAggRow;
+ });
+ }
+ else {
+ items = grid.filteredRows;
+ }
+
+ var offset = 0;
+ if (rowIndex !== 0 && (charCode === 38 || charCode === 13 && evt.shiftKey || charCode === 9 && evt.shiftKey && firstInRow)) { //arrow key up or shift enter or tab key and first item in row
+ offset = -1;
+ }
+ else if (rowIndex !== items.length - 1 && (charCode === 40 || charCode === 13 && !evt.shiftKey || charCode === 9 && lastInRow)) {//arrow key down, enter, or tab key and last item in row?
+ offset = 1;
+ }
+
+ if (offset) {
+ var r = items[rowIndex + offset];
+ if (r.beforeSelectionChange(r, evt)) {
+ r.continueSelection(evt);
+ $scope.$emit('ngGridEventDigestGridParent');
+
+ if ($scope.selectionProvider.lastClickedRow.renderedRowIndex >= $scope.renderedRows.length - EXCESS_ROWS - 2) {
+ grid.$viewport.scrollTop(grid.$viewport.scrollTop() + $scope.rowHeight);
+ }
+ else if ($scope.selectionProvider.lastClickedRow.renderedRowIndex <= EXCESS_ROWS + 2) {
+ grid.$viewport.scrollTop(grid.$viewport.scrollTop() - $scope.rowHeight);
+ }
+ }
+ }
+
+ if ($scope.enableCellSelection) {
+ setTimeout(function(){
+ $scope.domAccessProvider.focusCellElement($scope, $scope.renderedColumns.indexOf(visibleCols[newColumnIndex]));
+ }, 3);
+ }
+
+ return false;
+};
+
+if (!String.prototype.trim) {
+ String.prototype.trim = function() {
+ return this.replace(/^\s+|\s+$/g, '');
+ };
+}
+if (!Array.prototype.indexOf) {
+ Array.prototype.indexOf = function(elt /*, from*/) {
+ var len = this.length >>> 0;
+ var from = Number(arguments[1]) || 0;
+ from = (from < 0) ? Math.ceil(from) : Math.floor(from);
+ if (from < 0) {
+ from += len;
+ }
+ for (; from < len; from++) {
+ if (from in this && this[from] === elt) {
+ return from;
+ }
+ }
+ return -1;
+ };
+}
+if (!Array.prototype.filter) {
+ Array.prototype.filter = function(fun /*, thisp */) {
+ "use strict";
+ var t = Object(this);
+ var len = t.length >>> 0;
+ if (typeof fun !== "function") {
+ throw new TypeError();
+ }
+ var res = [];
+ var thisp = arguments[1];
+ for (var i = 0; i < len; i++) {
+ if (i in t) {
+ var val = t[i]; // in case fun mutates this
+ if (fun.call(thisp, val, i, t)) {
+ res.push(val);
+ }
+ }
+ }
+ return res;
+ };
+}
+ngGridFilters.filter('checkmark', function() {
+ return function(input) {
+ return input ? '\u2714' : '\u2718';
+ };
+});
+ngGridFilters.filter('ngColumns', function() {
+ return function(input) {
+ return input.filter(function(col) {
+ return !col.isAggCol;
+ });
+ };
+});
+angular.module('ngGrid.services').factory('$domUtilityService',['$utilityService', '$window', function($utils, $window) {
+ var domUtilityService = {};
+ var regexCache = {};
+ var getWidths = function() {
+ var $testContainer = $('<div></div>');
+ $testContainer.appendTo('body');
+ // 1. Run all the following measurements on startup!
+ //measure Scroll Bars
+ $testContainer.height(100).width(100).css("position", "absolute").css("overflow", "scroll");
+ $testContainer.append('<div style="height: 400px; width: 400px;"></div>');
+ domUtilityService.ScrollH = ($testContainer.height() - $testContainer[0].clientHeight);
+ domUtilityService.ScrollW = ($testContainer.width() - $testContainer[0].clientWidth);
+ $testContainer.empty();
+ //clear styles
+ $testContainer.attr('style', '');
+ //measure letter sizes using a pretty typical font size and fat font-family
+ $testContainer.append('<span style="font-family: Verdana, Helvetica, Sans-Serif; font-size: 14px;"><strong>M</strong></span>');
+ domUtilityService.LetterW = $testContainer.children().first().width();
+ $testContainer.remove();
+ };
+ domUtilityService.eventStorage = {};
+ domUtilityService.AssignGridContainers = function($scope, rootEl, grid) {
+ grid.$root = $(rootEl);
+ //Headers
+ grid.$topPanel = grid.$root.find(".ngTopPanel");
+ grid.$groupPanel = grid.$root.find(".ngGroupPanel");
+ grid.$headerContainer = grid.$topPanel.find(".ngHeaderContainer");
+ $scope.$headerContainer = grid.$headerContainer;
+
+ grid.$headerScroller = grid.$topPanel.find(".ngHeaderScroller");
+ grid.$headers = grid.$headerScroller.children();
+ //Viewport
+ grid.$viewport = grid.$root.find(".ngViewport");
+ //Canvas
+ grid.$canvas = grid.$viewport.find(".ngCanvas");
+ //Footers
+ grid.$footerPanel = grid.$root.find(".ngFooterPanel");
+
+ var scopeDereg = $scope.$watch(function () {
+ return grid.$viewport.scrollLeft();
+ }, function (newLeft) {
+ return grid.$headerContainer.scrollLeft(newLeft);
+ });
+
+ $scope.$on('$destroy', function() {
+ // Remove all references to DOM elements, otherwise we get memory leaks
+ if(grid.$root) {
+ $(grid.$root.parent()).off('resize.nggrid');
+
+ grid.$root = null;
+ grid.$topPanel = null;
+ // grid.$groupPanel = null;
+ grid.$headerContainer = null;
+ // grid.$headerScroller = null;
+ grid.$headers = null;
+ grid.$canvas = null;
+ grid.$footerPanel = null;
+ }
+
+ scopeDereg();
+ });
+
+ domUtilityService.UpdateGridLayout($scope, grid);
+ };
+ domUtilityService.getRealWidth = function (obj) {
+ var width = 0;
+ var props = { visibility: "hidden", display: "block" };
+ var hiddenParents = obj.parents().andSelf().not(':visible');
+ $.swap(hiddenParents[0], props, function () {
+ width = obj.outerWidth();
+ });
+ return width;
+ };
+ domUtilityService.UpdateGridLayout = function($scope, grid) {
+ if (!grid.$root){
+ return;
+ }
+ //catch this so we can return the viewer to their original scroll after the resize!
+ var scrollTop = grid.$viewport.scrollTop();
+ grid.elementDims.rootMaxW = grid.$root.width();
+ if (grid.$root.is(':hidden')) {
+ grid.elementDims.rootMaxW = domUtilityService.getRealWidth(grid.$root);
+ }
+ grid.elementDims.rootMaxH = grid.$root.height();
+ //check to see if anything has changed
+ grid.refreshDomSizes();
+ $scope.adjustScrollTop(scrollTop, true); //ensure that the user stays scrolled where they were
+ };
+ domUtilityService.numberOfGrids = 0;
+ domUtilityService.setStyleText = function(grid, css) {
+ var style = grid.styleSheet,
+ gridId = grid.gridId,
+ doc = $window.document;
+
+ if (!style) {
+ style = doc.getElementById(gridId);
+ }
+ if (!style) {
+ style = doc.createElement('style');
+ style.type = 'text/css';
+ style.id = gridId;
+ (doc.head || doc.getElementsByTagName('head')[0]).appendChild(style);
+ }
+
+ if (style.styleSheet && !style.sheet) {
+ style.styleSheet.cssText = css;
+ } else {
+ style.innerHTML = css;
+ }
+ grid.styleSheet = style;
+ grid.styleText = css;
+ };
+ domUtilityService.BuildStyles = function($scope, grid, digest) {
+ var rowHeight = grid.config.rowHeight,
+ gridId = grid.gridId,
+ css,
+ cols = $scope.columns,
+ sumWidth = 0;
+
+ var trw = $scope.totalRowWidth();
+ css = "." + gridId + " .ngCanvas { width: " + trw + "px; }" +
+ "." + gridId + " .ngRow { width: " + trw + "px; }" +
+ "." + gridId + " .ngCanvas { width: " + trw + "px; }" +
+ "." + gridId + " .ngHeaderScroller { width: " + (trw + domUtilityService.ScrollH) + "px}";
+
+ for (var i = 0; i < cols.length; i++) {
+ var col = cols[i];
+ if (col.visible !== false) {
+ css += "." + gridId + " .col" + i + " { width: " + col.width + "px; left: " + sumWidth + "px; height: " + rowHeight + "px }" +
+ "." + gridId + " .colt" + i + " { width: " + col.width + "px; }";
+ sumWidth += col.width;
+ }
+ }
+ domUtilityService.setStyleText(grid, css);
+
+ $scope.adjustScrollLeft(grid.$viewport.scrollLeft());
+ if (digest) {
+ domUtilityService.digest($scope);
+ }
+ };
+ domUtilityService.setColLeft = function(col, colLeft, grid) {
+ if (grid.styleText) {
+ var regex = regexCache[col.index];
+ if (!regex) {
+ regex = regexCache[col.index] = new RegExp(".col" + col.index + " { width: [0-9]+px; left: [0-9]+px");
+ }
+ var css = grid.styleText.replace(regex, ".col" + col.index + " { width: " + col.width + "px; left: " + colLeft + "px");
+ domUtilityService.setStyleText(grid, css);
+ }
+ };
+ domUtilityService.setColLeft.immediate = 1;
+ domUtilityService.RebuildGrid = function($scope, grid){
+ domUtilityService.UpdateGridLayout($scope, grid);
+ if (grid.config.maintainColumnRatios == null || grid.config.maintainColumnRatios) {
+ grid.configureColumnWidths();
+ }
+ $scope.adjustScrollLeft(grid.$viewport.scrollLeft());
+ domUtilityService.BuildStyles($scope, grid, true);
+ };
+
+ domUtilityService.digest = function($scope) {
+ if (!$scope.$root.$$phase) {
+ $scope.$digest();
+ }
+ };
+ domUtilityService.ScrollH = 17; // default in IE, Chrome, & most browsers
+ domUtilityService.ScrollW = 17; // default in IE, Chrome, & most browsers
+ domUtilityService.LetterW = 10;
+ getWidths();
+ return domUtilityService;
+}]);
+angular.module('ngGrid.services').factory('$sortService', ['$parse', function($parse) {
+ var sortService = {};
+ sortService.colSortFnCache = {}; // cache of sorting functions. Once we create them, we don't want to keep re-doing it
+ sortService.isCustomSort = false; // track if we're using an internal sort or a user provided sort
+ // this takes an piece of data from the cell and tries to determine its type and what sorting
+ // function to use for it
+ // @item - the cell data
+ sortService.guessSortFn = function(item) {
+ var itemType = typeof(item);
+ //check for numbers and booleans
+ switch (itemType) {
+ case "number":
+ return sortService.sortNumber;
+ case "boolean":
+ return sortService.sortBool;
+ case "string":
+ // if number string return number string sort fn. else return the str
+ return item.match(/^[-+]?[£$¤]?[\d,.]+%?$/) ? sortService.sortNumberStr : sortService.sortAlpha;
+ default:
+ //check if the item is a valid Date
+ if (Object.prototype.toString.call(item) === '[object Date]') {
+ return sortService.sortDate;
+ }
+ else {
+ //finally just sort the basic sort...
+ return sortService.basicSort;
+ }
+ }
+ };
+ //#region Sorting Functions
+ sortService.basicSort = function(a, b) {
+ if (a === b) {
+ return 0;
+ }
+ if (a < b) {
+ return -1;
+ }
+ return 1;
+ };
+ sortService.sortNumber = function(a, b) {
+ return a - b;
+ };
+ sortService.sortNumberStr = function(a, b) {
+ var numA, numB, badA = false, badB = false;
+ numA = parseFloat(a.replace(/[^0-9.-]/g, ''));
+ if (isNaN(numA)) {
+ badA = true;
+ }
+ numB = parseFloat(b.replace(/[^0-9.-]/g, ''));
+ if (isNaN(numB)) {
+ badB = true;
+ }
+ // we want bad ones to get pushed to the bottom... which effectively is "greater than"
+ if (badA && badB) {
+ return 0;
+ }
+ if (badA) {
+ return 1;
+ }
+ if (badB) {
+ return -1;
+ }
+ return numA - numB;
+ };
+ sortService.sortAlpha = function(a, b) {
+ var strA = a.toLowerCase(),
+ strB = b.toLowerCase();
+ return strA === strB ? 0 : (strA < strB ? -1 : 1);
+ };
+ sortService.sortDate = function(a, b) {
+ var timeA = a.getTime(),
+ timeB = b.getTime();
+ return timeA === timeB ? 0 : (timeA < timeB ? -1 : 1);
+ };
+ sortService.sortBool = function(a, b) {
+ if (a && b) {
+ return 0;
+ }
+ if (!a && !b) {
+ return 0;
+ } else {
+ return a ? 1 : -1;
+ }
+ };
+ //#endregion
+ // the core sorting logic trigger
+ sortService.sortData = function(sortInfo, data /*datasource*/) {
+ // first make sure we are even supposed to do work
+ if (!data || !sortInfo) {
+ return;
+ }
+ var l = sortInfo.fields.length,
+ order = sortInfo.fields,
+ col,
+ direction,
+ // IE9 HACK.... omg, I can't reference data array within the sort fn below. has to be a separate reference....!!!!
+ d = data.slice(0);
+ //now actually sort the data
+ data.sort(function (itemA, itemB) {
+ var tem = 0,
+ indx = 0,
+ res,
+ sortFn;
+ while (tem === 0 && indx < l) {
+ // grab the metadata for the rest of the logic
+ col = sortInfo.columns[indx];
+ direction = sortInfo.directions[indx];
+ sortFn = sortService.getSortFn(col, d);
+
+ var propA = $parse(order[indx])(itemA);
+ var propB = $parse(order[indx])(itemB);
+ // if user provides custom sort, we want them to have full control of the sort
+ if (sortService.isCustomSort) {
+ res = sortFn(propA, propB);
+ tem = direction === ASC ? res : 0 - res;
+ } else {
+ // we want to allow zero values to be evaluated in the sort function
+ if (propA == null || propB == null) {
+ // we want to force nulls and such to the bottom when we sort... which effectively is "greater than"
+ if (propB == null && propA == null) {
+ tem = 0;
+ }
+ else if (propA == null) {
+ tem = 1;
+ }
+ else if (propB == null) {
+ tem = -1;
+ }
+ }
+ else {
+ // this will keep nulls at the bottom regardless of ordering
+ res = sortFn(propA, propB);
+ tem = direction === ASC ? res : 0 - res;
+ }
+ }
+ indx++;
+ }
+ return tem;
+ });
+ };
+ sortService.Sort = function(sortInfo, data) {
+ if (sortService.isSorting) {
+ return;
+ }
+ sortService.isSorting = true;
+ sortService.sortData(sortInfo, data);
+ sortService.isSorting = false;
+ };
+ sortService.getSortFn = function(col, data) {
+ var sortFn, item;
+ //see if we already figured out what to use to sort the column
+ if (sortService.colSortFnCache[col.field]) {
+ sortFn = sortService.colSortFnCache[col.field];
+ }
+ else if (col.sortingAlgorithm !== undefined) {
+ sortFn = col.sortingAlgorithm;
+ sortService.colSortFnCache[col.field] = col.sortingAlgorithm;
+ sortService.isCustomSort = true;
+ }
+ else { // try and guess what sort function to use
+ item = data[0];
+ if (!item) {
+ return sortFn;
+ }
+ sortFn = sortService.guessSortFn($parse(col.field)(item));
+ //cache it
+ if (sortFn) {
+ sortService.colSortFnCache[col.field] = sortFn;
+ } else {
+ // we assign the alpha sort because anything that is null/undefined will never get passed to
+ // the actual sorting function. It will get caught in our null check and returned to be sorted
+ // down to the bottom
+ sortFn = sortService.sortAlpha;
+ }
+ }
+ return sortFn;
+ };
+ return sortService;
+}]);
+
+angular.module('ngGrid.services').factory('$utilityService', ['$parse', function ($parse) {
+ var funcNameRegex = /function (.{1,})\(/;
+ var utils = {
+ visualLength: function(node) {
+ var elem = document.getElementById('testDataLength');
+ if (!elem) {
+ elem = document.createElement('SPAN');
+ elem.id = "testDataLength";
+ elem.style.visibility = "hidden";
+ document.body.appendChild(elem);
+ }
+ var $node = $(node);
+ $(elem).css({'font': $node.css('font'),
+ 'font-size': $node.css('font-size'),
+ 'font-family': $node.css('font-family')});
+ elem.innerHTML = $node.text();
+ var width = elem.offsetWidth;
+ document.body.removeChild(elem);
+ return width;
+ },
+ forIn: function(obj, action) {
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ action(obj[prop], prop);
+ }
+ }
+ },
+ evalProperty: function (entity, path) {
+ return $parse("entity." + path)({ entity: entity });
+ },
+ endsWith: function(str, suffix) {
+ if (!str || !suffix || typeof str !== "string") {
+ return false;
+ }
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ },
+ isNullOrUndefined: function(obj) {
+ if (obj === undefined || obj === null) {
+ return true;
+ }
+ return false;
+ },
+ getElementsByClassName: function(cl) {
+ if (document.getElementsByClassName) {
+ return document.getElementsByClassName(cl);
+ }
+ else {
+ var retnode = [];
+ var myclass = new RegExp('\\b' + cl + '\\b');
+ var elem = document.getElementsByTagName('*');
+ for (var i = 0; i < elem.length; i++) {
+ var classes = elem[i].className;
+ if (myclass.test(classes)) {
+ retnode.push(elem[i]);
+ }
+ }
+ return retnode;
+ }
+ },
+ newId: (function() {
+ var seedId = new Date().getTime();
+ return function() {
+ return seedId += 1;
+ };
+ })(),
+ seti18n: function($scope, language) {
+ var $langPack = window.ngGrid.i18n[language];
+ for (var label in $langPack) {
+ $scope.i18n[label] = $langPack[label];
+ }
+ },
+ getInstanceType: function (o) {
+ var results = (funcNameRegex).exec(o.constructor.toString());
+ if (results && results.length > 1) {
+ var instanceType = results[1].replace(/^\s+|\s+$/g, ""); // Trim surrounding whitespace; IE appears to add a space at the end
+ return instanceType;
+ }
+ else {
+ return "";
+ }
+ }
+ };
+
+ return utils;
+}]);
+
+var ngAggregate = function (aggEntity, rowFactory, rowHeight, groupInitState) {
+ this.rowIndex = 0;
+ this.offsetTop = this.rowIndex * rowHeight;
+ this.entity = aggEntity;
+ this.label = aggEntity.gLabel;
+ this.field = aggEntity.gField;
+ this.depth = aggEntity.gDepth;
+ this.parent = aggEntity.parent;
+ this.children = aggEntity.children;
+ this.aggChildren = aggEntity.aggChildren;
+ this.aggIndex = aggEntity.aggIndex;
+ this.collapsed = groupInitState;
+ this.groupInitState = groupInitState;
+ this.rowFactory = rowFactory;
+ this.rowHeight = rowHeight;
+ this.isAggRow = true;
+ this.offsetLeft = aggEntity.gDepth * 25;
+ this.aggLabelFilter = aggEntity.aggLabelFilter;
+};
+
+ngAggregate.prototype.toggleExpand = function () {
+ this.collapsed = this.collapsed ? false : true;
+ if (this.orig) {
+ this.orig.collapsed = this.collapsed;
+ }
+ this.notifyChildren();
+};
+ngAggregate.prototype.setExpand = function (state) {
+ this.collapsed = state;
+ if (this.orig) {
+ this.orig.collapsed = state;
+ }
+ this.notifyChildren();
+};
+ngAggregate.prototype.notifyChildren = function () {
+ var longest = Math.max(this.rowFactory.aggCache.length, this.children.length);
+ for (var i = 0; i < longest; i++) {
+ if (this.aggChildren[i]) {
+ this.aggChildren[i].entity[NG_HIDDEN] = this.collapsed;
+ if (this.collapsed) {
+ this.aggChildren[i].setExpand(this.collapsed);
+ }
+ }
+ if (this.children[i]) {
+ this.children[i][NG_HIDDEN] = this.collapsed;
+ }
+ if (i > this.aggIndex && this.rowFactory.aggCache[i]) {
+ var agg = this.rowFactory.aggCache[i];
+ var offset = (30 * this.children.length);
+ agg.offsetTop = this.collapsed ? agg.offsetTop - offset : agg.offsetTop + offset;
+ }
+ }
+ this.rowFactory.renderedChange();
+};
+ngAggregate.prototype.aggClass = function () {
+ return this.collapsed ? "ngAggArrowCollapsed" : "ngAggArrowExpanded";
+};
+ngAggregate.prototype.totalChildren = function () {
+ if (this.aggChildren.length > 0) {
+ var i = 0;
+ var recurse = function (cur) {
+ if (cur.aggChildren.length > 0) {
+ angular.forEach(cur.aggChildren, function (a) {
+ recurse(a);
+ });
+ } else {
+ i += cur.children.length;
+ }
+ };
+ recurse(this);
+ return i;
+ } else {
+ return this.children.length;
+ }
+};
+ngAggregate.prototype.copy = function () {
+ var ret = new ngAggregate(this.entity, this.rowFactory, this.rowHeight, this.groupInitState);
+ ret.orig = this;
+ return ret;
+};
+
+var ngColumn = function (config, $scope, grid, domUtilityService, $templateCache, $utils) {
+ var self = this,
+ colDef = config.colDef,
+ delay = 500,
+ clicks = 0,
+ timer = null;
+ self.colDef = config.colDef;
+ self.width = colDef.width;
+ self.groupIndex = 0;
+ self.isGroupedBy = false;
+ self.minWidth = !colDef.minWidth ? 50 : colDef.minWidth;
+ self.maxWidth = !colDef.maxWidth ? 9000 : colDef.maxWidth;
+
+ // TODO: Use the column's definition for enabling cell editing
+ // self.enableCellEdit = config.enableCellEdit || colDef.enableCellEdit;
+ self.enableCellEdit = colDef.enableCellEdit !== undefined ? colDef.enableCellEdit : (config.enableCellEdit || config.enableCellEditOnFocus);
+
+ self.cellEditableCondition = colDef.cellEditableCondition || config.cellEditableCondition || 'true';
+
+ self.headerRowHeight = config.headerRowHeight;
+
+ // Use colDef.displayName as long as it's not undefined, otherwise default to the field name
+ self.displayName = (colDef.displayName === undefined) ? colDef.field : colDef.displayName;
+
+ self.index = config.index;
+ self.isAggCol = config.isAggCol;
+ self.cellClass = colDef.cellClass;
+ self.sortPriority = undefined;
+ self.cellFilter = colDef.cellFilter ? colDef.cellFilter : "";
+ self.field = colDef.field;
+ self.aggLabelFilter = colDef.aggLabelFilter || colDef.cellFilter;
+ self.visible = $utils.isNullOrUndefined(colDef.visible) || colDef.visible;
+ self.sortable = false;
+ self.resizable = false;
+ self.pinnable = false;
+ self.pinned = (config.enablePinning && colDef.pinned);
+ self.originalIndex = config.originalIndex == null ? self.index : config.originalIndex;
+ self.groupable = $utils.isNullOrUndefined(colDef.groupable) || colDef.groupable;
+ if (config.enableSort) {
+ self.sortable = $utils.isNullOrUndefined(colDef.sortable) || colDef.sortable;
+ }
+ if (config.enableResize) {
+ self.resizable = $utils.isNullOrUndefined(colDef.resizable) || colDef.resizable;
+ }
+ if (config.enablePinning) {
+ self.pinnable = $utils.isNullOrUndefined(colDef.pinnable) || colDef.pinnable;
+ }
+ self.sortDirection = undefined;
+ self.sortingAlgorithm = colDef.sortFn;
+ self.headerClass = colDef.headerClass;
+ self.cursor = self.sortable ? 'pointer' : 'default';
+ self.headerCellTemplate = colDef.headerCellTemplate || $templateCache.get('headerCellTemplate.html');
+ self.cellTemplate = colDef.cellTemplate || $templateCache.get('cellTemplate.html').replace(CUSTOM_FILTERS, self.cellFilter ? "|" + self.cellFilter : "");
+ if(self.enableCellEdit) {
+ self.cellEditTemplate = colDef.cellEditTemplate || $templateCache.get('cellEditTemplate.html');
+ self.editableCellTemplate = colDef.editableCellTemplate || $templateCache.get('editableCellTemplate.html');
+ }
+ if (colDef.cellTemplate && !TEMPLATE_REGEXP.test(colDef.cellTemplate)) {
+ self.cellTemplate = $templateCache.get(colDef.cellTemplate) || $.ajax({
+ type: "GET",
+ url: colDef.cellTemplate,
+ async: false
+ }).responseText;
+ }
+ if (self.enableCellEdit && colDef.editableCellTemplate && !TEMPLATE_REGEXP.test(colDef.editableCellTemplate)) {
+ self.editableCellTemplate = $templateCache.get(colDef.editableCellTemplate) || $.ajax({
+ type: "GET",
+ url: colDef.editableCellTemplate,
+ async: false
+ }).responseText;
+ }
+ if (colDef.headerCellTemplate && !TEMPLATE_REGEXP.test(colDef.headerCellTemplate)) {
+ self.headerCellTemplate = $templateCache.get(colDef.headerCellTemplate) || $.ajax({
+ type: "GET",
+ url: colDef.headerCellTemplate,
+ async: false
+ }).responseText;
+ }
+ self.colIndex = function () {
+ var classes = self.pinned ? "pinned " : "";
+ classes += "col" + self.index + " colt" + self.index;
+ if (self.cellClass) {
+ classes += " " + self.cellClass;
+ }
+ return classes;
+ };
+ self.groupedByClass = function() {
+ return self.isGroupedBy ? "ngGroupedByIcon" : "ngGroupIcon";
+ };
+ self.toggleVisible = function() {
+ self.visible = !self.visible;
+ };
+ self.showSortButtonUp = function() {
+ return self.sortable ? self.sortDirection === DESC : self.sortable;
+ };
+ self.showSortButtonDown = function() {
+ return self.sortable ? self.sortDirection === ASC : self.sortable;
+ };
+ self.noSortVisible = function() {
+ return !self.sortDirection;
+ };
+ self.sort = function(evt) {
+ if (!self.sortable) {
+ return true; // column sorting is disabled, do nothing
+ }
+ var dir = self.sortDirection === ASC ? DESC : ASC;
+ self.sortDirection = dir;
+ config.sortCallback(self, evt);
+ return false;
+ };
+ self.gripClick = function() {
+ clicks++; //count clicks
+ if (clicks === 1) {
+ timer = setTimeout(function() {
+ //Here you can add a single click action.
+ clicks = 0; //after action performed, reset counter
+ }, delay);
+ } else {
+ clearTimeout(timer); //prevent single-click action
+ config.resizeOnDataCallback(self); //perform double-click action
+ clicks = 0; //after action performed, reset counter
+ }
+ };
+ self.gripOnMouseDown = function(event) {
+ $scope.isColumnResizing = true;
+ if (event.ctrlKey && !self.pinned) {
+ self.toggleVisible();
+ domUtilityService.BuildStyles($scope, grid);
+ return true;
+ }
+ event.target.parentElement.style.cursor = 'col-resize';
+ self.startMousePosition = event.clientX;
+ self.origWidth = self.width;
+ $(document).mousemove(self.onMouseMove);
+ $(document).mouseup(self.gripOnMouseUp);
+ return false;
+ };
+ self.onMouseMove = function(event) {
+ var diff = event.clientX - self.startMousePosition;
+ var newWidth = diff + self.origWidth;
+ self.width = (newWidth < self.minWidth ? self.minWidth : (newWidth > self.maxWidth ? self.maxWidth : newWidth));
+ $scope.hasUserChangedGridColumnWidths = true;
+ domUtilityService.BuildStyles($scope, grid);
+ return false;
+ };
+ self.gripOnMouseUp = function (event) {
+ $(document).off('mousemove', self.onMouseMove);
+ $(document).off('mouseup', self.gripOnMouseUp);
+ event.target.parentElement.style.cursor = 'default';
+ domUtilityService.digest($scope);
+ $scope.isColumnResizing = false;
+ return false;
+ };
+ self.copy = function() {
+ var ret = new ngColumn(config, $scope, grid, domUtilityService, $templateCache, $utils);
+ ret.isClone = true;
+ ret.orig = self;
+ return ret;
+ };
+ self.setVars = function (fromCol) {
+ self.orig = fromCol;
+ self.width = fromCol.width;
+ self.groupIndex = fromCol.groupIndex;
+ self.isGroupedBy = fromCol.isGroupedBy;
+ self.displayName = fromCol.displayName;
+ self.index = fromCol.index;
+ self.isAggCol = fromCol.isAggCol;
+ self.cellClass = fromCol.cellClass;
+ self.cellFilter = fromCol.cellFilter;
+ self.field = fromCol.field;
+ self.aggLabelFilter = fromCol.aggLabelFilter;
+ self.visible = fromCol.visible;
+ self.sortable = fromCol.sortable;
+ self.resizable = fromCol.resizable;
+ self.pinnable = fromCol.pinnable;
+ self.pinned = fromCol.pinned;
+ self.originalIndex = fromCol.originalIndex;
+ self.sortDirection = fromCol.sortDirection;
+ self.sortingAlgorithm = fromCol.sortingAlgorithm;
+ self.headerClass = fromCol.headerClass;
+ self.headerCellTemplate = fromCol.headerCellTemplate;
+ self.cellTemplate = fromCol.cellTemplate;
+ self.cellEditTemplate = fromCol.cellEditTemplate;
+ };
+};
+
+var ngDimension = function (options) {
+ this.outerHeight = null;
+ this.outerWidth = null;
+ $.extend(this, options);
+};
+var ngDomAccessProvider = function (grid) {
+ this.previousColumn = null;
+ this.grid = grid;
+
+};
+
+ngDomAccessProvider.prototype.changeUserSelect = function (elm, value) {
+ elm.css({
+ '-webkit-touch-callout': value,
+ '-webkit-user-select': value,
+ '-khtml-user-select': value,
+ '-moz-user-select': value === 'none' ? '-moz-none' : value,
+ '-ms-user-select': value,
+ 'user-select': value
+ });
+};
+ngDomAccessProvider.prototype.focusCellElement = function ($scope, index) {
+ if ($scope.selectionProvider.lastClickedRow) {
+ var columnIndex = index !== undefined ? index : this.previousColumn;
+ var elm = $scope.selectionProvider.lastClickedRow.clone ? $scope.selectionProvider.lastClickedRow.clone.elm : $scope.selectionProvider.lastClickedRow.elm;
+ if (columnIndex !== undefined && elm) {
+ var columns = angular.element(elm[0].children).filter(function () { return this.nodeType !== 8; }); //Remove html comments for IE8
+ var i = Math.max(Math.min($scope.renderedColumns.length - 1, columnIndex), 0);
+ if (this.grid.config.showSelectionCheckbox && angular.element(columns[i]).scope() && angular.element(columns[i]).scope().col.index === 0) {
+ i = 1; //don't want to focus on checkbox
+ }
+ if (columns[i]) {
+ columns[i].children[1].children[0].focus();
+ }
+ this.previousColumn = columnIndex;
+ }
+ }
+};
+ngDomAccessProvider.prototype.selectionHandlers = function ($scope, elm) {
+ var doingKeyDown = false;
+ var self = this;
+
+ function keydown (evt) {
+ if (evt.keyCode === 16) { //shift key
+ self.changeUserSelect(elm, 'none', evt);
+ return true;
+ } else if (!doingKeyDown) {
+ doingKeyDown = true;
+ var ret = ngMoveSelectionHandler($scope, elm, evt, self.grid);
+ doingKeyDown = false;
+ return ret;
+ }
+ return true;
+ }
+
+ elm.bind('keydown', keydown);
+
+ function keyup (evt) {
+ if (evt.keyCode === 16) { //shift key
+ self.changeUserSelect(elm, 'text', evt);
+ }
+ return true;
+ }
+
+ elm.bind('keyup', keyup);
+
+ elm.on('$destroy', function() {
+ elm.off('keydown', keydown);
+ elm.off('keyup', keyup);
+ });
+};
+var ngEventProvider = function (grid, $scope, domUtilityService, $timeout) {
+ var self = this;
+ // The init method gets called during the ng-grid directive execution.
+ self.colToMove = undefined;
+ self.groupToMove = undefined;
+ self.assignEvents = function() {
+ // Here we set the onmousedown event handler to the header container.
+ if (grid.config.jqueryUIDraggable && !grid.config.enablePinning) {
+ grid.$groupPanel.droppable({
+ addClasses: false,
+ drop: function(event) {
+ self.onGroupDrop(event);
+ }
+ });
+
+ grid.$groupPanel.on('$destroy', function() {
+ grid.$groupPanel = null;
+ });
+ } else {
+ grid.$groupPanel.on('mousedown', self.onGroupMouseDown).on('dragover', self.dragOver).on('drop', self.onGroupDrop);
+ grid.$topPanel.on('mousedown', '.ngHeaderScroller', self.onHeaderMouseDown).on('dragover', '.ngHeaderScroller', self.dragOver);
+
+ grid.$groupPanel.on('$destroy', function() {
+ if (grid.$groupPanel){
+ grid.$groupPanel.off('mousedown');
+ }
+
+ grid.$groupPanel = null;
+ });
+
+ if (grid.config.enableColumnReordering) {
+ grid.$topPanel.on('drop', '.ngHeaderScroller', self.onHeaderDrop);
+ }
+
+ grid.$topPanel.on('$destroy', function() {
+ if (grid.$topPanel){
+ grid.$topPanel.off('mousedown');
+ }
+
+ if (grid.config.enableColumnReordering && grid.$topPanel) {
+ grid.$topPanel.off('drop');
+ }
+
+ grid.$topPanel = null;
+ });
+ }
+
+ $scope.$on('$destroy', $scope.$watch('renderedColumns', function() {
+ $timeout(self.setDraggables);
+ }));
+ };
+ self.dragStart = function(evt){
+ //FireFox requires there to be dataTransfer if you want to drag and drop.
+ evt.dataTransfer.setData('text', ''); //cannot be empty string
+ };
+ self.dragOver = function(evt) {
+ evt.preventDefault();
+ };
+ //For JQueryUI
+ self.setDraggables = function() {
+ if (!grid.config.jqueryUIDraggable) {
+ //Fix for FireFox. Instead of using jQuery on('dragstart', function) on find, we have to use addEventListeners for each column.
+ var columns = grid.$root.find('.ngHeaderSortColumn'); //have to iterate if using addEventListener
+ angular.forEach(columns, function(col){
+ if(col.className && col.className.indexOf("ngHeaderSortColumn") !== -1){
+ col.setAttribute('draggable', 'true');
+ //jQuery 'on' function doesn't have dataTransfer as part of event in handler unless added to event props, which is not recommended
+ //See more here: http://api.jquery.com/category/events/event-object/
+ if (col.addEventListener) { //IE8 doesn't have drag drop or event listeners
+ col.addEventListener('dragstart', self.dragStart);
+
+ angular.element(col).on('$destroy', function() {
+ angular.element(col).off('dragstart', self.dragStart);
+ col.removeEventListener('dragstart', self.dragStart);
+ });
+ }
+ }
+ });
+ if (navigator.userAgent.indexOf("MSIE") !== -1){
+ //call native IE dragDrop() to start dragging
+ var sortColumn = grid.$root.find('.ngHeaderSortColumn');
+ sortColumn.bind('selectstart', function () {
+ this.dragDrop();
+ return false;
+ });
+ angular.element(sortColumn).on('$destroy', function() {
+ sortColumn.off('selectstart');
+ });
+ }
+ } else {
+ if (grid.$root) {
+ grid.$root.find('.ngHeaderSortColumn').draggable({
+ helper: 'clone',
+ appendTo: 'body',
+ stack: 'div',
+ addClasses: false,
+ start: function(event) {
+ self.onHeaderMouseDown(event);
+ }
+ }).droppable({
+ drop: function(event) {
+ self.onHeaderDrop(event);
+ }
+ });
+ }
+ }
+ };
+ self.onGroupMouseDown = function(event) {
+ var groupItem = $(event.target);
+ // Get the scope from the header container
+ if (groupItem[0].className !== 'ngRemoveGroup') {
+ var groupItemScope = angular.element(groupItem).scope();
+ if (groupItemScope) {
+ // set draggable events
+ if (!grid.config.jqueryUIDraggable) {
+ groupItem.attr('draggable', 'true');
+ if(this.addEventListener){//IE8 doesn't have drag drop or event listeners
+ this.addEventListener('dragstart', self.dragStart);
+
+ angular.element(this).on('$destroy', function() {
+ this.removeEventListener('dragstart', self.dragStart);
+ });
+ }
+ if (navigator.userAgent.indexOf("MSIE") !== -1){
+ //call native IE dragDrop() to start dragging
+ groupItem.bind('selectstart', function () {
+ this.dragDrop();
+ return false;
+ });
+
+ groupItem.on('$destroy', function() {
+ groupItem.off('selectstart');
+ });
+ }
+ }
+ // Save the column for later.
+ self.groupToMove = { header: groupItem, groupName: groupItemScope.group, index: groupItemScope.$index };
+ }
+ } else {
+ self.groupToMove = undefined;
+ }
+ };
+ self.onGroupDrop = function(event) {
+ event.stopPropagation();
+ // clear out the colToMove object
+ var groupContainer;
+ var groupScope;
+ if (self.groupToMove) {
+ // Get the closest header to where we dropped
+ groupContainer = $(event.target).closest('.ngGroupElement'); // Get the scope from the header.
+ if (groupContainer.context.className === 'ngGroupPanel') {
+ $scope.configGroups.splice(self.groupToMove.index, 1);
+ $scope.configGroups.push(self.groupToMove.groupName);
+ } else {
+ groupScope = angular.element(groupContainer).scope();
+ if (groupScope) {
+ // If we have the same column, do nothing.
+ if (self.groupToMove.index !== groupScope.$index) {
+ // Splice the columns
+ $scope.configGroups.splice(self.groupToMove.index, 1);
+ $scope.configGroups.splice(groupScope.$index, 0, self.groupToMove.groupName);
+ }
+ }
+ }
+ self.groupToMove = undefined;
+ grid.fixGroupIndexes();
+ } else if (self.colToMove) {
+ if ($scope.configGroups.indexOf(self.colToMove.col) === -1) {
+ groupContainer = $(event.target).closest('.ngGroupElement'); // Get the scope from the header.
+ if (groupContainer.context.className === 'ngGroupPanel' || groupContainer.context.className === 'ngGroupPanelDescription ng-binding') {
+ $scope.groupBy(self.colToMove.col);
+ } else {
+ groupScope = angular.element(groupContainer).scope();
+ if (groupScope) {
+ // Splice the columns
+ $scope.removeGroup(groupScope.$index);
+ }
+ }
+ }
+ self.colToMove = undefined;
+ }
+ if (!$scope.$$phase) {
+ $scope.$apply();
+ }
+ };
+ //Header functions
+ self.onHeaderMouseDown = function(event) {
+ // Get the closest header container from where we clicked.
+ var headerContainer = $(event.target).closest('.ngHeaderSortColumn');
+ // Get the scope from the header container
+ var headerScope = angular.element(headerContainer).scope();
+ if (headerScope) {
+ // Save the column for later.
+ self.colToMove = { header: headerContainer, col: headerScope.col };
+ }
+ };
+ self.onHeaderDrop = function(event) {
+ if (!self.colToMove || self.colToMove.col.pinned) {
+ return;
+ }
+ // Get the closest header to where we dropped
+ var headerContainer = $(event.target).closest('.ngHeaderSortColumn');
+ // Get the scope from the header.
+ var headerScope = angular.element(headerContainer).scope();
+ if (headerScope) {
+ // If we have the same column or the target column is pinned, do nothing.
+ if (self.colToMove.col === headerScope.col || headerScope.col.pinned) {
+ return;
+ }
+ // Splice the columns
+ $scope.columns.splice(self.colToMove.col.index, 1);
+ $scope.columns.splice(headerScope.col.index, 0, self.colToMove.col);
+ grid.fixColumnIndexes();
+ // clear out the colToMove object
+ self.colToMove = undefined;
+ domUtilityService.digest($scope);
+ }
+ };
+
+ self.assignGridEventHandlers = function() {
+ //Chrome and firefox both need a tab index so the grid can recieve focus.
+ //need to give the grid a tabindex if it doesn't already have one so
+ //we'll just give it a tab index of the corresponding gridcache index
+ //that way we'll get the same result every time it is run.
+ //configurable within the options.
+ if (grid.config.tabIndex === -1) {
+ grid.$viewport.attr('tabIndex', domUtilityService.numberOfGrids);
+ domUtilityService.numberOfGrids++;
+ } else {
+ grid.$viewport.attr('tabIndex', grid.config.tabIndex);
+ }
+ // resize on window resize
+ var windowThrottle;
+ var windowResize = function(){
+ clearTimeout(windowThrottle);
+ windowThrottle = setTimeout(function() {
+ //in function for IE8 compatibility
+ domUtilityService.RebuildGrid($scope,grid);
+ }, 100);
+ };
+ $(window).on('resize.nggrid', windowResize);
+ // resize on parent resize as well.
+ var parentThrottle;
+ var parentResize = function() {
+ clearTimeout(parentThrottle);
+ parentThrottle = setTimeout(function() {
+ //in function for IE8 compatibility
+ domUtilityService.RebuildGrid($scope,grid);
+ }, 100);
+ };
+ $(grid.$root.parent()).on('resize.nggrid', parentResize);
+
+ $scope.$on('$destroy', function(){
+ $(window).off('resize.nggrid', windowResize);
+ // $(grid.$root.parent()).off('resize.nggrid', parentResize);
+ });
+ };
+ // In this example we want to assign grid events.
+ self.assignGridEventHandlers();
+ self.assignEvents();
+};
+
+var ngFooter = function ($scope, grid) {
+ $scope.maxRows = function () {
+ var ret = Math.max($scope.totalServerItems, grid.data.length);
+ return ret;
+ };
+
+ $scope.$on('$destroy', $scope.$watch('totalServerItems',function(n,o){
+ $scope.currentMaxPages = $scope.maxPages();
+ }));
+
+ $scope.multiSelect = (grid.config.enableRowSelection && grid.config.multiSelect);
+ $scope.selectedItemCount = grid.selectedItemCount;
+
+ $scope.maxPages = function () {
+ if($scope.maxRows() === 0) {
+ return 1;
+ }
+ return Math.ceil($scope.maxRows() / $scope.pagingOptions.pageSize);
+ };
+
+ $scope.pageForward = function() {
+ var page = $scope.pagingOptions.currentPage;
+ if ($scope.totalServerItems > 0) {
+ $scope.pagingOptions.currentPage = Math.min(page + 1, $scope.maxPages());
+ } else {
+ $scope.pagingOptions.currentPage++;
+ }
+ };
+
+ $scope.pageBackward = function() {
+ var page = $scope.pagingOptions.currentPage;
+ $scope.pagingOptions.currentPage = Math.max(page - 1, 1);
+ };
+
+ $scope.pageToFirst = function() {
+ $scope.pagingOptions.currentPage = 1;
+ };
+
+ $scope.pageToLast = function() {
+ var maxPages = $scope.maxPages();
+ $scope.pagingOptions.currentPage = maxPages;
+ };
+
+ $scope.cantPageForward = function() {
+ var curPage = $scope.pagingOptions.currentPage;
+ var maxPages = $scope.maxPages();
+ if ($scope.totalServerItems > 0) {
+ return curPage >= maxPages;
+ } else {
+ return grid.data.length < 1;
+ }
+
+ };
+ $scope.cantPageToLast = function() {
+ if ($scope.totalServerItems > 0) {
+ return $scope.cantPageForward();
+ } else {
+ return true;
+ }
+ };
+
+ $scope.cantPageBackward = function() {
+ var curPage = $scope.pagingOptions.currentPage;
+ return curPage <= 1;
+ };
+};
+/// <reference path="footer.js" />
+/// <reference path="../services/SortService.js" />
+/// <reference path="../../lib/jquery-1.8.2.min" />
+var ngGrid = function ($scope, options, sortService, domUtilityService, $filter, $templateCache, $utils, $timeout, $parse, $http, $q) {
+ var defaults = {
+ //Define an aggregate template to customize the rows when grouped. See github wiki for more details.
+ aggregateTemplate: undefined,
+
+ //Callback for when you want to validate something after selection.
+ afterSelectionChange: function() {
+ },
+
+ /* Callback if you want to inspect something before selection,
+ return false if you want to cancel the selection. return true otherwise.
+ If you need to wait for an async call to proceed with selection you can
+ use rowItem.changeSelection(event) method after returning false initially.
+ Note: when shift+ Selecting multiple items in the grid this will only get called
+ once and the rowItem will be an array of items that are queued to be selected. */
+ beforeSelectionChange: function() {
+ return true;
+ },
+
+ //checkbox templates.
+ checkboxCellTemplate: undefined,
+ checkboxHeaderTemplate: undefined,
+
+ //definitions of columns as an array [], if not defines columns are auto-generated. See github wiki for more details.
+ columnDefs: undefined,
+
+ //*Data being displayed in the grid. Each item in the array is mapped to a row being displayed.
+ data: [],
+
+ //Data updated callback, fires every time the data is modified from outside the grid.
+ dataUpdated: function() {
+ },
+
+ //Enables cell editing.
+ enableCellEdit: false,
+
+ //Enables cell editing on focus
+ enableCellEditOnFocus: false,
+
+ //Enables cell selection.
+ enableCellSelection: false,
+
+ //Enable or disable resizing of columns
+ enableColumnResize: false,
+
+ //Enable or disable reordering of columns
+ enableColumnReordering: false,
+
+ //Enable or disable HEAVY column virtualization. This turns off selection checkboxes and column pinning and is designed for spreadsheet-like data.
+ enableColumnHeavyVirt: false,
+
+ //Enables the server-side paging feature
+ enablePaging: false,
+
+ //Enable column pinning
+ enablePinning: false,
+
+ //To be able to have selectable rows in grid.
+ enableRowSelection: true,
+
+ //Enables or disables sorting in grid.
+ enableSorting: true,
+
+ //Enables or disables text highlighting in grid by adding the "unselectable" class (See CSS file)
+ enableHighlighting: false,
+
+ // string list of properties to exclude when auto-generating columns.
+ excludeProperties: [],
+
+ /* filterOptions -
+ filterText: The text bound to the built-in search box.
+ useExternalFilter: Bypass internal filtering if you want to roll your own filtering mechanism but want to use builtin search box.
+ */
+ filterOptions: {
+ filterText: "",
+ useExternalFilter: false
+ },
+
+ //Defining the height of the footer in pixels.
+ footerRowHeight: 55,
+
+ // the template for the column menu and filter, including the button.
+ footerTemplate: undefined,
+
+ // Enables a trade off between refreshing the contents of the grid continuously while scrolling (behaviour when true)
+ // and keeping the scroll bar button responsive at the expense of refreshing grid contents (behaviour when false)
+ forceSyncScrolling: true,
+
+ //Initial fields to group data by. Array of field names, not displayName.
+ groups: [],
+
+ // set the initial state of aggreagate grouping. "true" means they will be collapsed when grouping changes, "false" means they will be expanded by default.
+ groupsCollapsedByDefault: true,
+
+ //The height of the header row in pixels.
+ headerRowHeight: 30,
+
+ //Define a header row template for further customization. See github wiki for more details.
+ headerRowTemplate: undefined,
+
+ /*Enables the use of jquery UI reaggable/droppable plugin. requires jqueryUI to work if enabled.
+ Useful if you want drag + drop but your users insist on crappy browsers. */
+ jqueryUIDraggable: false,
+
+ //Enable the use jqueryUIThemes
+ jqueryUITheme: false,
+
+ //Prevent unselections when in single selection mode.
+ keepLastSelected: true,
+
+ /*Maintains the column widths while resizing.
+ Defaults to true when using *'s or undefined widths. Can be ovverriden by setting to false.*/
+ maintainColumnRatios: undefined,
+
+ // the template for the column menu and filter, including the button.
+ menuTemplate: undefined,
+
+ //Set this to false if you only want one item selected at a time
+ multiSelect: true,
+
+ // pagingOptions -
+ pagingOptions: {
+ // pageSizes: list of available page sizes.
+ pageSizes: [250, 500, 1000],
+ //pageSize: currently selected page size.
+ pageSize: 250,
+ //currentPage: the uhm... current page.
+ currentPage: 1
+ },
+
+ //the selection checkbox is pinned to the left side of the viewport or not.
+ pinSelectionCheckbox: false,
+
+ //Array of plugin functions to register in ng-grid
+ plugins: [],
+
+ //User defined unique ID field that allows for better handling of selections and for server-side paging
+ primaryKey: undefined,
+
+ //Row height of rows in grid.
+ rowHeight: 30,
+
+ //Define a row template to customize output. See github wiki for more details.
+ rowTemplate: undefined,
+
+ //all of the items selected in the grid. In single select mode there will only be one item in the array.
+ selectedItems: [],
+
+ //Width of row selection checkbox column
+ selectionCheckboxColumnWidth: 25,
+
+ //Disable row selections by clicking on the row and only when the checkbox is clicked.
+ selectWithCheckboxOnly: false,
+
+ /*Enables menu to choose which columns to display and group by.
+ If both showColumnMenu and showFilter are false the menu button will not display.*/
+ showColumnMenu: false,
+
+ /*Enables display of the filterbox in the column menu.
+ If both showColumnMenu and showFilter are false the menu button will not display.*/
+ showFilter: false,
+
+ //Show or hide the footer alltogether the footer is enabled by default
+ showFooter: false,
+
+ //Show the dropzone for drag and drop grouping
+ showGroupPanel: false,
+
+ //Row selection check boxes appear as the first column.
+ showSelectionCheckbox: false,
+
+ /*Define a sortInfo object to specify a default sorting state.
+ You can also observe this variable to utilize server-side sorting (see useExternalSorting).
+ Syntax is sortinfo: { fields: ['fieldName1',' fieldName2'], direction: 'ASC'/'asc' || 'desc'/'DESC'}*/
+ sortInfo: {fields: [], columns: [], directions: [] },
+
+ //Set the tab index of the Vieport.
+ tabIndex: -1,
+
+ //totalServerItems: Total items are on the server.
+ totalServerItems: 0,
+
+ /*Prevents the internal sorting from executing.
+ The sortInfo object will be updated with the sorting information so you can handle sorting (see sortInfo)*/
+ useExternalSorting: false,
+
+ /*i18n language support. choose from the installed or included languages, en, fr, sp, etc...*/
+ i18n: 'en',
+
+ //the threshold in rows to force virtualization on
+ virtualizationThreshold: 50,
+
+ // Don't handle tabs, so they can be used to navigate between controls.
+ noTabInterference: false
+ },
+ self = this;
+ self.maxCanvasHt = 0;
+ //self vars
+ self.config = $.extend(defaults, window.ngGrid.config, options);
+
+ // override conflicting settings
+ self.config.showSelectionCheckbox = (self.config.showSelectionCheckbox && self.config.enableColumnHeavyVirt === false);
+ self.config.enablePinning = (self.config.enablePinning && self.config.enableColumnHeavyVirt === false);
+ self.config.selectWithCheckboxOnly = (self.config.selectWithCheckboxOnly && self.config.showSelectionCheckbox !== false);
+ self.config.pinSelectionCheckbox = self.config.enablePinning;
+
+ if (typeof options.columnDefs === "string") {
+ self.config.columnDefs = $scope.$eval(options.columnDefs);
+ }
+ self.rowCache = [];
+ self.rowMap = [];
+ self.gridId = "ng" + $utils.newId();
+ self.$root = null; //this is the root element that is passed in with the binding handler
+ self.$groupPanel = null;
+ self.$topPanel = null;
+ self.$headerContainer = null;
+ self.$headerScroller = null;
+ self.$headers = null;
+ self.$viewport = null;
+ self.$canvas = null;
+ self.rootDim = self.config.gridDim;
+ self.data = [];
+ self.lateBindColumns = false;
+ self.filteredRows = [];
+
+ self.initTemplates = function() {
+ var templates = ['rowTemplate', 'aggregateTemplate', 'headerRowTemplate', 'checkboxCellTemplate', 'checkboxHeaderTemplate', 'menuTemplate', 'footerTemplate'];
+
+ var promises = [];
+ angular.forEach(templates, function(template) {
+ promises.push( self.getTemplate(template) );
+ });
+
+ return $q.all(promises);
+ };
+
+ //Templates
+ // test templates for urls and get the tempaltes via synchronous ajax calls
+ self.getTemplate = function (key) {
+ var t = self.config[key];
+ var uKey = self.gridId + key + ".html";
+ var p = $q.defer();
+ if (t && !TEMPLATE_REGEXP.test(t)) {
+ $http.get(t, {
+ cache: $templateCache
+ })
+ .success(function(data){
+ $templateCache.put(uKey, data);
+ p.resolve();
+ })
+ .error(function(err){
+ p.reject("Could not load template: " + t);
+ });
+ } else if (t) {
+ $templateCache.put(uKey, t);
+ p.resolve();
+ } else {
+ var dKey = key + ".html";
+ $templateCache.put(uKey, $templateCache.get(dKey));
+ p.resolve();
+ }
+
+ return p.promise;
+ };
+
+ if (typeof self.config.data === "object") {
+ self.data = self.config.data; // we cannot watch for updates if you don't pass the string name
+ }
+ self.calcMaxCanvasHeight = function() {
+ var calculatedHeight;
+ if(self.config.groups.length > 0){
+ calculatedHeight = self.rowFactory.parsedData.filter(function(e) {
+ return !e[NG_HIDDEN];
+ }).length * self.config.rowHeight;
+ } else {
+ calculatedHeight = self.filteredRows.length * self.config.rowHeight;
+ }
+ return calculatedHeight;
+ };
+ self.elementDims = {
+ scrollW: 0,
+ scrollH: 0,
+ rowIndexCellW: self.config.selectionCheckboxColumnWidth,
+ rowSelectedCellW: self.config.selectionCheckboxColumnWidth,
+ rootMaxW: 0,
+ rootMaxH: 0
+ };
+ //self funcs
+ self.setRenderedRows = function (newRows) {
+ $scope.renderedRows.length = newRows.length;
+ for (var i = 0; i < newRows.length; i++) {
+ if (!$scope.renderedRows[i] || (newRows[i].isAggRow || $scope.renderedRows[i].isAggRow)) {
+ $scope.renderedRows[i] = newRows[i].copy();
+ $scope.renderedRows[i].collapsed = newRows[i].collapsed;
+ if (!newRows[i].isAggRow) {
+ $scope.renderedRows[i].setVars(newRows[i]);
+ }
+ } else {
+ $scope.renderedRows[i].setVars(newRows[i]);
+ }
+ $scope.renderedRows[i].rowIndex = newRows[i].rowIndex;
+ $scope.renderedRows[i].offsetTop = newRows[i].offsetTop;
+ $scope.renderedRows[i].selected = newRows[i].selected;
+ newRows[i].renderedRowIndex = i;
+ }
+ self.refreshDomSizes();
+ $scope.$emit('ngGridEventRows', newRows);
+ };
+ self.minRowsToRender = function() {
+ var viewportH = $scope.viewportDimHeight() || 1;
+ return Math.floor(viewportH / self.config.rowHeight);
+ };
+ self.refreshDomSizes = function() {
+ var dim = new ngDimension();
+ dim.outerWidth = self.elementDims.rootMaxW;
+ dim.outerHeight = self.elementDims.rootMaxH;
+ self.rootDim = dim;
+ self.maxCanvasHt = self.calcMaxCanvasHeight();
+ };
+ self.buildColumnDefsFromData = function () {
+ self.config.columnDefs = [];
+ var item = self.data[0];
+ if (!item) {
+ self.lateBoundColumns = true;
+ return;
+ }
+ $utils.forIn(item, function (prop, propName) {
+ if (self.config.excludeProperties.indexOf(propName) === -1) {
+ self.config.columnDefs.push({
+ field: propName
+ });
+ }
+ });
+ };
+ self.buildColumns = function() {
+ var columnDefs = self.config.columnDefs,
+ cols = [];
+ if (!columnDefs) {
+ self.buildColumnDefsFromData();
+ columnDefs = self.config.columnDefs;
+ }
+ if (self.config.showSelectionCheckbox) {
+ cols.push(new ngColumn({
+ colDef: {
+ field: '\u2714',
+ width: self.elementDims.rowSelectedCellW,
+ sortable: false,
+ resizable: false,
+ groupable: false,
+ headerCellTemplate: $templateCache.get($scope.gridId + 'checkboxHeaderTemplate.html'),
+ cellTemplate: $templateCache.get($scope.gridId + 'checkboxCellTemplate.html'),
+ pinned: self.config.pinSelectionCheckbox
+ },
+ index: 0,
+ headerRowHeight: self.config.headerRowHeight,
+ sortCallback: self.sortData,
+ resizeOnDataCallback: self.resizeOnData,
+ enableResize: self.config.enableColumnResize,
+ enableSort: self.config.enableSorting,
+ enablePinning: self.config.enablePinning
+ }, $scope, self, domUtilityService, $templateCache, $utils));
+ }
+ if (columnDefs.length > 0) {
+ var checkboxOffset = self.config.showSelectionCheckbox ? 1 : 0;
+ var groupOffset = $scope.configGroups.length;
+ $scope.configGroups.length = 0;
+ angular.forEach(columnDefs, function(colDef, i) {
+ i += checkboxOffset;
+ var column = new ngColumn({
+ colDef: colDef,
+ index: i + groupOffset,
+ originalIndex: i,
+ headerRowHeight: self.config.headerRowHeight,
+ sortCallback: self.sortData,
+ resizeOnDataCallback: self.resizeOnData,
+ enableResize: self.config.enableColumnResize,
+ enableSort: self.config.enableSorting,
+ enablePinning: self.config.enablePinning,
+ enableCellEdit: self.config.enableCellEdit || self.config.enableCellEditOnFocus,
+ cellEditableCondition: self.config.cellEditableCondition
+ }, $scope, self, domUtilityService, $templateCache, $utils);
+ var indx = self.config.groups.indexOf(colDef.field);
+ if (indx !== -1) {
+ column.isGroupedBy = true;
+ $scope.configGroups.splice(indx, 0, column);
+ column.groupIndex = $scope.configGroups.length;
+ }
+ cols.push(column);
+ });
+ $scope.columns = cols;
+ if (self.config.groups.length > 0) {
+ self.rowFactory.getGrouping(self.config.groups);
+ }
+ }
+ };
+ self.configureColumnWidths = function() {
+ var asterisksArray = [],
+ percentArray = [],
+ asteriskNum = 0,
+ totalWidth = 0;
+
+ // When rearranging columns, their index in $scope.columns will no longer match the original column order from columnDefs causing
+ // their width config to be out of sync. We can use "originalIndex" on the ngColumns to get hold of the correct setup from columnDefs, but to
+ // avoid O(n) lookups in $scope.columns per column we setup a map.
+ var indexMap = {};
+ // Build a map of columnDefs column indices -> ngColumn indices (via the "originalIndex" property on ngColumns).
+ angular.forEach($scope.columns, function(ngCol, i) {
+ // Disregard columns created by grouping (the grouping columns don't match a column from columnDefs)
+ if (!$utils.isNullOrUndefined(ngCol.originalIndex)) {
+ var origIndex = ngCol.originalIndex;
+ if (self.config.showSelectionCheckbox) {
+ //if visible, takes up 25 pixels
+ if(ngCol.originalIndex === 0 && ngCol.visible){
+ totalWidth += self.config.selectionCheckboxColumnWidth;
+ }
+ // The originalIndex will be offset 1 when including the selection column
+ origIndex--;
+ }
+ indexMap[origIndex] = i;
+ } else if (ngCol.isAggCol && ngCol.visible){ // aggregate columns are 25px in length.
+ totalWidth+=25;
+ }
+ });
+
+ angular.forEach(self.config.columnDefs, function(colDef, i) {
+ // Get the ngColumn that matches the current column from columnDefs
+ var ngColumn = $scope.columns[indexMap[i]];
+
+ colDef.index = i;
+
+ var isPercent = false, t;
+ //if width is not defined, set it to a single star
+ if ($utils.isNullOrUndefined(colDef.width)) {
+ colDef.width = "*";
+ } else { // get column width
+ isPercent = isNaN(colDef.width) ? $utils.endsWith(colDef.width, "%") : false;
+ t = isPercent ? colDef.width : parseInt(colDef.width, 10);
+ }
+
+ // has bug for resize event causing NaN for all column width after another http.get
+ // if (isNaN(t) && !$scope.hasUserChangedGridColumnWidths) {
+ // check if it is a number
+ if (isNaN(t)) {
+ t = colDef.width;
+ // figure out if the width is defined or if we need to calculate it
+ if (t === 'auto') { // set it for now until we have data and subscribe when it changes so we can set the width.
+ ngColumn.width = ngColumn.minWidth;
+ totalWidth += ngColumn.width;
+ var temp = ngColumn;
+
+ $scope.$on('$destroy', $scope.$on("ngGridEventData", function () {
+ self.resizeOnData(temp);
+ }));
+
+ return;
+ } else if (t.indexOf("*") !== -1) { // we need to save it until the end to do the calulations on the remaining width.
+ if (ngColumn.visible !== false) {
+ asteriskNum += t.length;
+ }
+ asterisksArray.push(colDef);
+ return;
+ } else if (isPercent) { // If the width is a percentage, save it until the very last.
+ percentArray.push(colDef);
+ return;
+ } else { // we can't parse the width so lets throw an error.
+ throw "unable to parse column width, use percentage (\"10%\",\"20%\", etc...) or \"*\" to use remaining width of grid";
+ }
+ } else if (ngColumn.visible !== false) {
+ totalWidth += ngColumn.width = parseInt(ngColumn.width, 10);
+ }
+ });
+
+ // Now we check if we saved any percentage columns for calculating last
+ if (percentArray.length > 0) {
+ //If they specificy for maintain column ratios to be false in grid config, then it will remain false. If not specifiied or true, will be true.
+ self.config.maintainColumnRatios = self.config.maintainColumnRatios !== false;
+ // If any columns with % widths have been hidden, then let other % based columns use their width
+ var percentWidth = 0; // The total % value for all columns setting their width using % (will e.g. be 40 for 2 columns with 20% each)
+ var hiddenPercent = 0; // The total % value for all columns setting their width using %, but which have been hidden
+ angular.forEach(percentArray, function(colDef) {
+ // Get the ngColumn that matches the current column from columnDefs
+ var ngColumn = $scope.columns[indexMap[colDef.index]];
+ var percent = parseFloat(colDef.width) / 100;
+ percentWidth += percent;
+
+ if (!ngColumn.visible) {
+ hiddenPercent += percent;
+ }
+ });
+ var percentWidthUsed = percentWidth - hiddenPercent;
+
+ // do the math
+ angular.forEach(percentArray, function(colDef) {
+ // Get the ngColumn that matches the current column from columnDefs
+ var ngColumn = $scope.columns[indexMap[colDef.index]];
+
+ // Calc the % relative to the amount of % reserved for the visible columns (that use % based widths)
+ var percent = parseFloat(colDef.width) / 100;
+ if (hiddenPercent > 0) {
+ percent = percent / percentWidthUsed;
+ }
+ else {
+ percent = percent / percentWidth;
+ }
+
+ var pixelsForPercentBasedWidth = self.rootDim.outerWidth * percentWidth;
+ ngColumn.width = pixelsForPercentBasedWidth * percent;
+ totalWidth += ngColumn.width;
+ });
+ }
+
+ // check if we saved any asterisk columns for calculating later
+ if (asterisksArray.length > 0) {
+ //If they specificy for maintain column ratios to be false in grid config, then it will remain false. If not specifiied or true, will be true.
+ self.config.maintainColumnRatios = self.config.maintainColumnRatios !== false;
+ // get the remaining width
+ var remainingWidth = self.rootDim.outerWidth - totalWidth;
+ // are we overflowing vertically?
+ if (self.maxCanvasHt > $scope.viewportDimHeight()) {
+ //compensate for scrollbar
+ remainingWidth -= domUtilityService.ScrollW;
+ }
+ // calculate the weight of each asterisk rounded down
+ var asteriskVal = Math.floor(remainingWidth / asteriskNum);
+
+ // set the width of each column based on the number of stars
+ angular.forEach(asterisksArray, function(colDef, i) {
+ // Get the ngColumn that matches the current column from columnDefs
+ var ngColumn = $scope.columns[indexMap[colDef.index]];
+ ngColumn.width = asteriskVal * colDef.width.length;
+ if (ngColumn.width < ngColumn.minWidth) {
+ ngColumn.width = ngColumn.minWidth;
+ }
+ if (ngColumn.visible !== false) {
+ totalWidth += ngColumn.width;
+ }
+
+ var isLast = (i === (asterisksArray.length - 1));
+ //if last asterisk and doesn't fill width of grid, add the difference
+ if(isLast && totalWidth < self.rootDim.outerWidth){
+ var gridWidthDifference = self.rootDim.outerWidth - totalWidth;
+ if(self.maxCanvasHt > $scope.viewportDimHeight()){
+ gridWidthDifference -= domUtilityService.ScrollW;
+ }
+ ngColumn.width += gridWidthDifference;
+ }
+ });
+ }
+ };
+ self.init = function() {
+ return self.initTemplates().then(function(){
+ //factories and services
+ $scope.selectionProvider = new ngSelectionProvider(self, $scope, $parse);
+ $scope.domAccessProvider = new ngDomAccessProvider(self);
+ self.rowFactory = new ngRowFactory(self, $scope, domUtilityService, $templateCache, $utils);
+ self.searchProvider = new ngSearchProvider($scope, self, $filter, $utils);
+ self.styleProvider = new ngStyleProvider($scope, self);
+ $scope.$on('$destroy', $scope.$watch('configGroups', function(a) {
+ var tempArr = [];
+ angular.forEach(a, function(item) {
+ tempArr.push(item.field || item);
+ });
+ self.config.groups = tempArr;
+ self.rowFactory.filteredRowsChanged();
+ $scope.$emit('ngGridEventGroups', a);
+ }, true));
+ $scope.$on('$destroy', $scope.$watch('columns', function (a) {
+ if(!$scope.isColumnResizing){
+ domUtilityService.RebuildGrid($scope, self);
+ }
+ $scope.$emit('ngGridEventColumns', a);
+ }, true));
+ $scope.$on('$destroy', $scope.$watch(function() {
+ return options.i18n;
+ }, function(newLang) {
+ $utils.seti18n($scope, newLang);
+ }));
+ self.maxCanvasHt = self.calcMaxCanvasHeight();
+
+ if (self.config.sortInfo.fields && self.config.sortInfo.fields.length > 0) {
+ $scope.$on('$destroy', $scope.$watch(function() {
+ return self.config.sortInfo;
+ }, function(sortInfo){
+ if (!sortService.isSorting) {
+ self.sortColumnsInit();
+ $scope.$emit('ngGridEventSorted', self.config.sortInfo);
+ }
+ }, true));
+ }
+ });
+
+ // var p = $q.defer();
+ // p.resolve();
+ // return p.promise;
+ };
+
+ self.resizeOnData = function(col) {
+ // we calculate the longest data.
+ var longest = col.minWidth;
+ var arr = $utils.getElementsByClassName('col' + col.index);
+ angular.forEach(arr, function(elem, index) {
+ var i;
+ if (index === 0) {
+ var kgHeaderText = $(elem).find('.ngHeaderText');
+ i = $utils.visualLength(kgHeaderText) + 10; // +10 some margin
+ } else {
+ var ngCellText = $(elem).find('.ngCellText');
+ i = $utils.visualLength(ngCellText) + 10; // +10 some margin
+ }
+ if (i > longest) {
+ longest = i;
+ }
+ });
+ col.width = col.longest = Math.min(col.maxWidth, longest + 7); // + 7 px to make it look decent.
+ domUtilityService.BuildStyles($scope, self, true);
+ };
+ self.lastSortedColumns = [];
+ self.sortData = function(col, evt) {
+ if (evt && evt.shiftKey && self.config.sortInfo) {
+ var indx = self.config.sortInfo.columns.indexOf(col);
+ if (indx === -1) {
+ if (self.config.sortInfo.columns.length === 1) {
+ self.config.sortInfo.columns[0].sortPriority = 1;
+ }
+ self.config.sortInfo.columns.push(col);
+ col.sortPriority = self.config.sortInfo.columns.length;
+ self.config.sortInfo.fields.push(col.field);
+ self.config.sortInfo.directions.push(col.sortDirection);
+ self.lastSortedColumns.push(col);
+ } else {
+ self.config.sortInfo.directions[indx] = col.sortDirection;
+ }
+ $scope.$emit('ngGridEventSorted', self.config.sortInfo);
+ } else if (!self.config.useExternalSorting || (self.config.useExternalSorting && self.config.sortInfo )) {
+ var isArr = $.isArray(col);
+ self.config.sortInfo.columns.length = 0;
+ self.config.sortInfo.fields.length = 0;
+ self.config.sortInfo.directions.length = 0;
+ var push = function (c) {
+ self.config.sortInfo.columns.push(c);
+ self.config.sortInfo.fields.push(c.field);
+ self.config.sortInfo.directions.push(c.sortDirection);
+ self.lastSortedColumns.push(c);
+ };
+ if (isArr) {
+ angular.forEach(col, function (c, i) {
+ c.sortPriority = i + 1;
+ push(c);
+ });
+ } else {
+ self.clearSortingData(col);
+ col.sortPriority = undefined;
+ push(col);
+ }
+
+ self.sortActual();
+ self.searchProvider.evalFilter();
+ $scope.$emit('ngGridEventSorted', self.config.sortInfo);
+ }
+ };
+ self.sortColumnsInit = function() {
+ if (self.config.sortInfo.columns) {
+ self.config.sortInfo.columns.length = 0;
+ } else {
+ self.config.sortInfo.columns = [];
+ }
+
+ var cols = [];
+ angular.forEach($scope.columns, function(c) {
+ var i = self.config.sortInfo.fields.indexOf(c.field);
+ if (i !== -1) {
+ c.sortDirection = self.config.sortInfo.directions[i] || 'asc';
+ cols[i] = c;
+ }
+ });
+
+ if(cols.length === 1){
+ self.sortData(cols[0]);
+ }else{
+ self.sortData(cols);
+ }
+ };
+ self.sortActual = function() {
+ if (!self.config.useExternalSorting) {
+ var tempData = self.data.slice(0);
+ angular.forEach(tempData, function(item, i) {
+ var e = self.rowMap[i];
+ if (e !== undefined) {
+ var v = self.rowCache[e];
+ if (v !== undefined) {
+ item.preSortSelected = v.selected;
+ item.preSortIndex = i;
+ }
+ }
+ });
+ sortService.Sort(self.config.sortInfo, tempData);
+ angular.forEach(tempData, function(item, i) {
+ self.rowCache[i].entity = item;
+ self.rowCache[i].selected = item.preSortSelected;
+ self.rowMap[item.preSortIndex] = i;
+ delete item.preSortSelected;
+ delete item.preSortIndex;
+ });
+ }
+ };
+
+ self.clearSortingData = function (col) {
+ if (!col) {
+ angular.forEach(self.lastSortedColumns, function (c) {
+ c.sortDirection = "";
+ c.sortPriority = null;
+ });
+ self.lastSortedColumns = [];
+ } else {
+ angular.forEach(self.lastSortedColumns, function (c) {
+ if (col.index !== c.index) {
+ c.sortDirection = "";
+ c.sortPriority = null;
+ }
+ });
+ self.lastSortedColumns[0] = col;
+ self.lastSortedColumns.length = 1;
+ }
+ };
+ self.fixColumnIndexes = function() {
+ //fix column indexes
+ for (var i = 0; i < $scope.columns.length; i++) {
+ $scope.columns[i].index = i;
+ }
+ };
+ self.fixGroupIndexes = function() {
+ angular.forEach($scope.configGroups, function(item, i) {
+ item.groupIndex = i + 1;
+ });
+ };
+ //$scope vars
+ $scope.elementsNeedMeasuring = true;
+ $scope.columns = [];
+ $scope.renderedRows = [];
+ $scope.renderedColumns = [];
+ $scope.headerRow = null;
+ $scope.rowHeight = self.config.rowHeight;
+ $scope.jqueryUITheme = self.config.jqueryUITheme;
+ $scope.showSelectionCheckbox = self.config.showSelectionCheckbox;
+ $scope.enableCellSelection = self.config.enableCellSelection;
+ $scope.enableCellEditOnFocus = self.config.enableCellEditOnFocus;
+ $scope.footer = null;
+ $scope.selectedItems = self.config.selectedItems;
+ $scope.multiSelect = self.config.multiSelect;
+ $scope.showFooter = self.config.showFooter;
+ $scope.footerRowHeight = $scope.showFooter ? self.config.footerRowHeight : 0;
+ $scope.showColumnMenu = self.config.showColumnMenu;
+ $scope.forceSyncScrolling = self.config.forceSyncScrolling;
+ $scope.showMenu = false;
+ $scope.configGroups = [];
+ $scope.gridId = self.gridId;
+ //Paging
+ $scope.enablePaging = self.config.enablePaging;
+ $scope.pagingOptions = self.config.pagingOptions;
+
+ //i18n support
+ $scope.i18n = {};
+ $utils.seti18n($scope, self.config.i18n);
+ $scope.adjustScrollLeft = function (scrollLeft) {
+ var colwidths = 0,
+ totalLeft = 0,
+ x = $scope.columns.length,
+ newCols = [],
+ dcv = !self.config.enableColumnHeavyVirt;
+ var r = 0;
+ var addCol = function (c) {
+ if (dcv) {
+ newCols.push(c);
+ } else {
+ if (!$scope.renderedColumns[r]) {
+ $scope.renderedColumns[r] = c.copy();
+ } else {
+ $scope.renderedColumns[r].setVars(c);
+ }
+ }
+ r++;
+ };
+ for (var i = 0; i < x; i++) {
+ var col = $scope.columns[i];
+ if (col.visible !== false) {
+ var w = col.width + colwidths;
+ if (col.pinned) {
+ addCol(col);
+ var newLeft = i > 0 ? (scrollLeft + totalLeft) : scrollLeft;
+ domUtilityService.setColLeft(col, newLeft, self);
+ totalLeft += col.width;
+ } else {
+ if (w >= scrollLeft) {
+ if (colwidths <= scrollLeft + self.rootDim.outerWidth) {
+ addCol(col);
+ }
+ }
+ }
+ colwidths += col.width;
+ }
+ }
+ if (dcv) {
+ $scope.renderedColumns = newCols;
+ }
+ };
+ self.prevScrollTop = 0;
+ self.prevScrollIndex = 0;
+ $scope.adjustScrollTop = function(scrollTop, force) {
+ if (self.prevScrollTop === scrollTop && !force) {
+ return;
+ }
+ if (scrollTop > 0 && self.$viewport[0].scrollHeight - scrollTop <= self.$viewport.outerHeight()) {
+ $scope.$emit('ngGridEventScroll');
+ }
+ var rowIndex = Math.floor(scrollTop / self.config.rowHeight);
+ var newRange;
+ if (self.filteredRows.length > self.config.virtualizationThreshold) {
+ // Have we hit the threshold going down?
+ if (self.prevScrollTop < scrollTop && rowIndex < self.prevScrollIndex + SCROLL_THRESHOLD) {
+ return;
+ }
+ //Have we hit the threshold going up?
+ if (self.prevScrollTop > scrollTop && rowIndex > self.prevScrollIndex - SCROLL_THRESHOLD) {
+ return;
+ }
+ newRange = new ngRange(Math.max(0, rowIndex - EXCESS_ROWS), rowIndex + self.minRowsToRender() + EXCESS_ROWS);
+ } else {
+ var maxLen = $scope.configGroups.length > 0 ? self.rowFactory.parsedData.length : self.filteredRows.length;
+ newRange = new ngRange(0, Math.max(maxLen, self.minRowsToRender() + EXCESS_ROWS));
+ }
+ self.prevScrollTop = scrollTop;
+ self.rowFactory.UpdateViewableRange(newRange);
[... 1885 lines stripped ...]