UNPKG

strong-arc

Version:

A visual suite for the StrongLoop API Platform

1,348 lines (1,278 loc) 142 kB
/*********************************************** * 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