strong-arc
Version:
A visual suite for the StrongLoop API Platform
1,348 lines (1,278 loc) • 142 kB
JavaScript
/***********************************************
* 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: 09/02/2014 10:22
***********************************************/
(function(window, $) {
'use strict';
var EXCESS_ROWS = 6;
var SCROLL_THRESHOLD = 4;
var ASC = "asc";
var DESC = "desc";
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 = /<.+>/;
var FUNC_REGEXP = /(\([^)]*\))?$/;
var DOT_REGEXP = /\./g;
var APOS_REGEXP = /'/g;
var BRACKET_REGEXP = /^(.*)((?:\s*\[\s*\d+\s*\]\s*)|(?:\s*\[\s*"(?:[^"\\]|\\.)*"\s*\]\s*)|(?:\s*\[\s*'(?:[^'\\]|\\.)*'\s*\]\s*))(.*)$/;
window.ngGrid = {};
window.ngGrid.i18n = {};
var ngGridServices = angular.module('ngGrid.services', []);
var ngGridDirectives = angular.module('ngGrid.directives', []);
var ngGridFilters = angular.module('ngGrid.filters', []);
angular.module('ngGrid', ['ngGrid.services', 'ngGrid.directives', 'ngGrid.filters']);
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) {
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)) {
offset = -1;
}
else if (rowIndex !== items.length - 1 && (charCode === 40 || charCode === 13 && !evt.shiftKey || charCode === 9 && lastInRow)) {
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 ) {
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 ) {
"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];
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');
$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();
$testContainer.attr('style', '');
$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);
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();
grid.$viewport = grid.$root.find(".ngViewport");
grid.$canvas = grid.$viewport.find(".ngCanvas");
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() {
if(grid.$root) {
$(grid.$root.parent()).off('resize.nggrid');
grid.$root = null;
grid.$topPanel = null;
grid.$headerContainer = 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;
}
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();
grid.refreshDomSizes();
$scope.adjustScrollTop(scrollTop, true);
};
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) {
var rightPad = 0;
if ((i === cols.length - 1) && (sumWidth + col.width < grid.elementDims.rootMaxW)) {
rightPad = grid.elementDims.rootMaxW - sumWidth - col.width;
}
css += "." + gridId + " .col" + i + " { width: " + (col.width + rightPad) + "px; left: " + sumWidth + "px; height: " + rowHeight + "px }" +
"." + gridId + " .colt" + i + " { width: " + (col.width + rightPad) + "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;
domUtilityService.ScrollW = 17;
domUtilityService.LetterW = 10;
getWidths();
return domUtilityService;
}]);
angular.module('ngGrid.services').factory('$sortService', ['$parse', '$utilityService', function($parse, $utils) {
var sortService = {};
sortService.colSortFnCache = {};
sortService.isCustomSort = false;
sortService.guessSortFn = function(item) {
var itemType = typeof(item);
switch (itemType) {
case "number":
return sortService.sortNumber;
case "boolean":
return sortService.sortBool;
case "string":
return item.match(/^[-+]?[£$¤]?[\d,.]+%?$/) ? sortService.sortNumberStr : sortService.sortAlpha;
default:
if (Object.prototype.toString.call(item) === '[object Date]') {
return sortService.sortDate;
}
else {
return sortService.basicSort;
}
}
};
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;
}
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;
}
};
sortService.sortData = function(sortInfo, data ) {
if (!data || !sortInfo) {
return;
}
var l = sortInfo.fields.length,
order = sortInfo.fields,
col,
direction,
d = data.slice(0);
data.sort(function (itemA, itemB) {
var tem = 0,
indx = 0,
res,
sortFn;
while (tem === 0 && indx < l) {
col = sortInfo.columns[indx];
direction = sortInfo.directions[indx];
sortFn = sortService.getSortFn(col, d);
var propA = $utils.evalProperty(itemA, order[indx]);
var propB = $utils.evalProperty(itemB, order[indx]);
if (sortService.isCustomSort) {
res = sortFn(propA, propB);
tem = direction === ASC ? res : 0 - res;
} else {
if (propA == null || propB == null) {
if (propB == null && propA == null) {
tem = 0;
}
else if (propA == null) {
tem = 1;
}
else if (propB == null) {
tem = -1;
}
}
else {
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;
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 {
item = data[0];
if (!item) {
return sortFn;
}
sortFn = sortService.guessSortFn($parse('entity[\''+col.field.replace(DOT_REGEXP, '\'][\'')+'\']')({entity:item}));
if (sortFn) {
sortService.colSortFnCache[col.field] = sortFn;
} else {
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);
}
}
},
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, "");
return instanceType;
}
else {
return "";
}
},
init: function () {
function preEval(path) {
var m = BRACKET_REGEXP.exec(path);
if (m) {
return (m[1] ? preEval(m[1]) : m[1]) + m[2] + (m[3] ? preEval(m[3]) : m[3]);
} else {
path = path.replace(APOS_REGEXP, '\\\'');
var parts = path.split(DOT_REGEXP);
var preparsed = [parts.shift()];
angular.forEach(parts, function (part) {
preparsed.push(part.replace(FUNC_REGEXP, '\']$1'));
});
return preparsed.join('[\'');
}
}
this.preEval = preEval;
this.evalProperty = function (entity, path) {
return $parse(preEval('entity.' + path))({ entity: entity });
};
delete this.init;
return this;
}
}.init();
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;
self.enableCellEdit = colDef.enableCellEdit !== undefined ? colDef.enableCellEdit : (config.enableCellEdit || config.enableCellEditOnFocus);
self.cellEditableCondition = colDef.cellEditableCondition || config.cellEditableCondition || 'true';
self.headerRowHeight = config.headerRowHeight;
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;
}
var dir = self.sortDirection === ASC ? DESC : ASC;
self.sortDirection = dir;
config.sortCallback(self, evt);
return false;
};
self.gripClick = function() {
clicks++;
if (clicks === 1) {
timer = setTimeout(function() {
clicks = 0;
}, delay);
} else {
clearTimeout(timer);
config.resizeOnDataCallback(self);
clicks = 0;
}
};
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; });
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;
}
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) {
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) {
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;
self.colToMove = undefined;
self.groupToMove = undefined;
self.assignEvents = function() {
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){
evt.dataTransfer.setData('text', '');
};
self.dragOver = function(evt) {
evt.preventDefault();
};
self.setDraggables = function() {
if (!grid.config.jqueryUIDraggable) {
var columns = grid.$root.find('.ngHeaderSortColumn');
angular.forEach(columns, function(col){
if(col.className && col.className.indexOf("ngHeaderSortColumn") !== -1){
col.setAttribute('draggable', 'true');
if (col.addEventListener) {
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){
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);
if (groupItem[0].className !== 'ngRemoveGroup') {
var groupItemScope = angular.element(groupItem).scope();
if (groupItemScope) {
if (!grid.config.jqueryUIDraggable) {
groupItem.attr('draggable', 'true');
if(this.addEventListener){
this.addEventListener('dragstart', self.dragStart);
angular.element(this).on('$destroy', function() {
this.removeEventListener('dragstart', self.dragStart);
});
}
if (navigator.userAgent.indexOf("MSIE") !== -1){
groupItem.bind('selectstart', function () {
this.dragDrop();
return false;
});
groupItem.on('$destroy', function() {
groupItem.off('selectstart');
});
}
}
self.groupToMove = { header: groupItem, groupName: groupItemScope.group, index: groupItemScope.$index };
}
} else {
self.groupToMove = undefined;
}
};
self.onGroupDrop = function(event) {
event.stopPropagation();
var groupContainer;
var groupScope;
if (self.groupToMove) {
groupContainer = $(event.target).closest('.ngGroupElement');
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 (self.groupToMove.index !== groupScope.$index) {
$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');
if (groupContainer.context.className === 'ngGroupPanel' || groupContainer.context.className === 'ngGroupPanelDescription ng-binding') {
$scope.groupBy(self.colToMove.col);
} else {
groupScope = angular.element(groupContainer).scope();
if (groupScope) {
$scope.removeGroup(groupScope.$index);
}
}
}
self.colToMove = undefined;
}
if (!$scope.$$phase) {
$scope.$apply();
}
};
self.onHeaderMouseDown = function(event) {
var headerContainer = $(event.target).closest('.ngHeaderSortColumn');
var headerScope = angular.element(headerContainer).scope();
if (headerScope) {
self.colToMove = { header: headerContainer, col: headerScope.col };
}
};
self.onHeaderDrop = function(event) {
if (!self.colToMove || self.colToMove.col.pinned) {
return;
}
var headerContainer = $(event.target).closest('.ngHeaderSortColumn');
var headerScope = angular.element(headerContainer).scope();
if (headerScope) {
if (self.colToMove.col === headerScope.col || headerScope.col.pinned) {
return;
}
$scope.columns.splice(self.colToMove.col.index, 1);
$scope.columns.splice(headerScope.col.index, 0, self.colToMove.col);
grid.fixColumnIndexes();
self.colToMove = undefined;
domUtilityService.digest($scope);
}
};
self.assignGridEventHandlers = function() {
if (grid.config.tabIndex === -1) {
grid.$viewport.attr('tabIndex', domUtilityService.numberOfGrids);
domUtilityService.numberOfGrids++;
} else {
grid.$viewport.attr('tabIndex', grid.config.tabIndex);
}
var windowThrottle;
var windowResize = function(){
clearTimeout(windowThrottle);
windowThrottle = setTimeout(function() {
domUtilityService.RebuildGrid($scope,grid);
}, 100);
};
$(window).on('resize.nggrid', windowResize);
var parentThrottle;
var parentResize = function() {
clearTimeout(parentThrottle);
parentThrottle = setTimeout(function() {
domUtilityService.RebuildGrid($scope,grid);
}, 100);
};
$(grid.$root.parent()).on('resize.nggrid', parentResize);
$scope.$on('$destroy', function(){
$(window).off('resize.nggrid', windowResize);
});
};
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;
};
};
var ngGrid = function ($scope, options, sortService, domUtilityService, $filter, $templateCache, $utils, $timeout, $parse, $http, $q) {
var defaults = {
aggregateTemplate: undefined,
afterSelectionChange: function() {
},
beforeSelectionChange: function() {
return true;
},
checkboxCellTemplate: undefined,
checkboxHeaderTemplate: undefined,
columnDefs: undefined,
data: [],
dataUpdated: function() {
},
enableCellEdit: false,
enableCellEditOnFocus: false,
enableCellSelection: false,
enableColumnResize: false,
enableColumnReordering: false,
enableColumnHeavyVirt: false,
enablePaging: false,
enablePinning: false,
enableRowSelection: true,
enableSorting: true,
enableHighlighting: false,
excludeProperties: [],
filterOptions: {
filterText: "",
useExternalFilter: false
},
footerRowHeight: 55,
footerTemplate: undefined,
forceSyncScrolling: true,
groups: [],
groupsCollapsedByDefault: true,
headerRowHeight: 30,
headerRowTemplate: undefined,
jqueryUIDraggable: false,
jqueryUITheme: false,
keepLastSelected: true,
maintainColumnRatios: undefined,
menuTemplate: undefined,
multiSelect: true,
pagingOptions: {
pageSizes: [250, 500, 1000],
pageSize: 250,
currentPage: 1
},
pinSelectionCheckbox: false,
plugins: [],
primaryKey: undefined,
rowHeight: 30,
rowTemplate: undefined,
selectedItems: [],
selectionCheckboxColumnWidth: 25,
selectWithCheckboxOnly: false,
showColumnMenu: false,
showFilter: false,
showFooter: false,
showGroupPanel: false,
showSelectionCheckbox: false,
sortInfo: {fields: [], columns: [], directions: [] },
tabIndex: -1,
totalServerItems: 0,
useExternalSorting: false,
i18n: 'en',
virtualizationThreshold: 50,
noTabInterference: false
},
self = this;
self.maxCanvasHt = 0;
self.config = $.extend(defaults, window.ngGrid.config, options);
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;
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', 'checkboxHeaderTemplat