/*!
- * ui-grid - v3.0.7 - 2015-10-06
- * Copyright (c) 2015 ; License: MIT
+ * ui-grid - v3.1.0 - 2016-01-19
+ * Copyright (c) 2016 ; License: MIT
*/
(function () {
templateUrl: 'ui-grid/uiGridColumnMenu',
replace: true,
link: function ($scope, $elm, $attrs, uiGridCtrl) {
- var self = this;
-
uiGridColumnMenuService.initialize( $scope, uiGridCtrl );
$scope.defaultMenuItems = uiGridColumnMenuService.getDefaultMenuItems( $scope );
$scope.$broadcast('hide-menu', { originalEvent: event });
} else {
- self.shown = $scope.menuShown = true;
+ $scope.menuShown = true;
uiGridColumnMenuService.repositionMenu( $scope, column, colElementPosition, $elm, $columnElement );
$scope.colElement = $columnElement;
headerCell: i18nService.getSafeText('headerCell'),
sort: i18nService.getSafeText('sort')
};
+ $scope.isSortPriorityVisible = function() {
+ //show sort priority if column is sorted and there is at least one other sorted column
+ return $scope.col.sort.priority && $scope.grid.columns.some(function(element, index){
+ return element.sort.priority && element !== $scope.col;
+ });
+ };
$scope.getSortDirectionAriaLabel = function(){
var col = $scope.col;
//Trying to recreate this sort of thing but it was getting messy having it in the template.
//Sort direction {{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ? 'descending':'none')}}. {{col.sort.priority ? {{columnPriorityText}} {{col.sort.priority}} : ''}
var sortDirectionText = col.sort.direction === uiGridConstants.ASC ? $scope.i18n.sort.ascending : ( col.sort.direction === uiGridConstants.DESC ? $scope.i18n.sort.descending : $scope.i18n.sort.none);
var label = sortDirectionText;
- //Append the priority if it exists
- if (col.sort.priority) {
+
+ if ($scope.isSortPriorityVisible()) {
label = label + '. ' + $scope.i18n.headerCell.priority + ' ' + col.sort.priority;
}
return label;
}
contents.addClass(classAdded);
- var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
- $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
+ $timeout(function (){
+ var rightMostContainer = $scope.grid.renderContainers['right'] ? $scope.grid.renderContainers['right'] : $scope.grid.renderContainers['body'];
+ $scope.isLastCol = ( $scope.col === rightMostContainer.visibleColumnCache[ rightMostContainer.visibleColumnCache.length - 1 ] );
+ });
// Figure out whether this column is sortable or not
if (uiGridCtrl.grid.options.enableSorting && $scope.col.enableSorting) {
templateUrl: 'ui-grid/uiGridMenu',
replace: false,
link: function ($scope, $elm, $attrs, uiGridCtrl) {
- var self = this;
var menuMid;
var $animate;
+ var gridMenuMaxHeight;
+
+ $scope.dynamicStyles = '';
+
+ if (uiGridCtrl) {
+ // magic number of 30 because the grid menu displays somewhat below
+ // the top of the grid. It is approximately 30px.
+ gridMenuMaxHeight = uiGridCtrl.grid.gridHeight - 30;
+ $scope.dynamicStyles = [
+ '.grid' + uiGridCtrl.grid.id + ' .ui-grid-menu-mid {',
+ 'max-height: ' + gridMenuMaxHeight + 'px;',
+ '}'
+ ].join(' ');
+ }
$scope.i18n = {
close: i18nService.getSafeText('columnMenu.close')
};
// *** Show/Hide functions ******
- self.showMenu = $scope.showMenu = function(event, args) {
+ $scope.showMenu = function(event, args) {
if ( !$scope.shown ){
/*
};
- self.hideMenu = $scope.hideMenu = function(event, args) {
+ $scope.hideMenu = function(event, args) {
if ( $scope.shown ){
/*
* In order to animate cleanly we animate the addition of ng-hide, then use a $timeout to
deregFunctions.push( $scope.$parent.$watch($scope.uiGrid.data, dataWatchFunction) );
deregFunctions.push( $scope.$parent.$watch(function() {
if ( self.grid.appScope[$scope.uiGrid.data] ){
- return self.grid.appScope[$scope.uiGrid.data].length;
+ return self.grid.appScope[$scope.uiGrid.data].length;
} else {
return undefined;
- }
+ }
}, dataWatchFunction) );
} else {
deregFunctions.push( $scope.$parent.$watch(function() { return $scope.uiGrid.data; }, dataWatchFunction) );
}
deregFunctions.push( $scope.$parent.$watchCollection(function() { return $scope.uiGrid.columnDefs; }, columnDefsWatchFunction) );
}
-
+
function columnDefsWatchFunction(n, o) {
if (n && n !== o) {
}
}
+ var mostRecentData;
+
function dataWatchFunction(newData) {
// gridUtil.logDebug('dataWatch fired');
var promises = [];
-
+
if ( self.grid.options.fastWatch ){
if (angular.isString($scope.uiGrid.data)) {
newData = self.grid.appScope[$scope.uiGrid.data];
newData = $scope.uiGrid.data;
}
}
-
+
+ mostRecentData = newData;
+
if (newData) {
// columns length is greater than the number of row header columns, which don't count because they're created automatically
var hasColumns = self.grid.columns.length > (self.grid.rowHeaderColumns ? self.grid.rowHeaderColumns.length : 0);
}
$q.all(promises).then(function() {
- self.grid.modifyRows(newData)
+ // use most recent data, rather than the potentially outdated data passed into watcher handler
+ self.grid.modifyRows(mostRecentData)
.then(function () {
// if (self.viewport) {
self.grid.redrawInPlace(true);
grid.gridHeight = $scope.gridHeight = gridUtil.elementHeight($elm);
// If the grid isn't tall enough to fit a single row, it's kind of useless. Resize it to fit a minimum number of rows
- if (grid.gridHeight < grid.options.rowHeight && grid.options.enableMinHeightCheck) {
+ if (grid.gridHeight <= grid.options.rowHeight && grid.options.enableMinHeightCheck) {
autoAdjustHeight();
}
var contentHeight = grid.options.minRowsToShow * grid.options.rowHeight;
var headerHeight = grid.options.showHeader ? grid.options.headerRowHeight : 0;
var footerHeight = grid.calcFooterHeight();
-
+
var scrollbarHeight = 0;
if (grid.options.enableHorizontalScrollbar === uiGridConstants.scrollbars.ALWAYS) {
scrollbarHeight = gridUtil.getScrollbarWidth();
* @name handleWindowResize
* @methodOf ui.grid.class:Grid
* @description Triggered when the browser window resizes; automatically resizes the grid
+ * @returns {Promise} A resolved promise once the window resize has completed.
*/
Grid.prototype.handleWindowResize = function handleWindowResize($event) {
var self = this;
self.gridWidth = gridUtil.elementWidth(self.element);
self.gridHeight = gridUtil.elementHeight(self.element);
- self.queueRefresh();
+ return self.queueRefresh();
};
/**
//}
// This is the minimum amount of pixels we need to scroll vertical in order to see this row.
- var pixelsToSeeRow = ((seekRowIndex + 1) * self.options.rowHeight);
+ var pixelsToSeeRow = (seekRowIndex * self.options.rowHeight + self.headerHeight);
// Don't let the pixels required to see the row be less than zero
pixelsToSeeRow = (pixelsToSeeRow < 0) ? 0 : pixelsToSeeRow;
self.updateColumnDef(colDef, true);
- /**
- * @ngdoc function
- * @name hideColumn
- * @methodOf ui.grid.class:GridColumn
- * @description Hides the column by setting colDef.visible = false
- */
- GridColumn.prototype.hideColumn = function() {
- this.colDef.visible = false;
- };
-
self.aggregationValue = undefined;
// The footer cell registers to listen for the rowsRendered event, and calls this. Needed to be
};
}
+ /**
+ * @ngdoc function
+ * @name hideColumn
+ * @methodOf ui.grid.class:GridColumn
+ * @description Hides the column by setting colDef.visible = false
+ */
+ GridColumn.prototype.hideColumn = function() {
+ this.colDef.visible = false;
+ };
+
/**
* @ngdoc method
* @name footerCellClass
* @propertyOf ui.grid.class:GridOptions.columnDef
* @description footerCellClass can be a string specifying the class to append to a cell
- * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
+ * or it can be a function(grid, row, col, rowRenderIndex, colRenderIndex) that returns a class name
*
*/
self.footerCellClass = colDef.footerCellClass;
* @name cellClass
* @propertyOf ui.grid.class:GridOptions.columnDef
* @description cellClass can be a string specifying the class to append to a cell
- * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
+ * or it can be a function(grid, row, col, rowRenderIndex, colRenderIndex) that returns a class name
*
*/
self.cellClass = colDef.cellClass;
* @name headerCellClass
* @propertyOf ui.grid.class:GridOptions.columnDef
* @description headerCellClass can be a string specifying the class to append to a cell
- * or it can be a function(row,rowRenderIndex, col, colRenderIndex) that returns a class name
+ * or it can be a function(grid, row, col, rowRenderIndex, colRenderIndex) that returns a class name
*
*/
self.headerCellClass = colDef.headerCellClass;
}
});
}
+ };
- // Remove this column from the grid sorting, include inside build columns so has
- // access to self - all seems a bit dodgy but doesn't work otherwise so have left
- // as is
- GridColumn.prototype.unsort = function () {
- this.sort = {};
- self.grid.api.core.raise.sortChanged( self.grid, self.grid.getColumnSorting() );
- };
-
+ /**
+ * @ngdoc function
+ * @name unsort
+ * @methodOf ui.grid.class:GridColumn
+ * @description Removes column from the grid sorting
+ */
+ GridColumn.prototype.unsort = function () {
+ this.sort = {};
+ this.grid.api.core.raise.sortChanged( this.grid, this.grid.getColumnSorting() );
};
var strA = a.toString().toLowerCase(),
strB = b.toString().toLowerCase();
- return strA === strB ? 0 : (strA < strB ? -1 : 1);
+ return strA === strB ? 0 : strA.localeCompare(strB);
}
};
menu:{
text: 'Vælg kolonner:'
},
+ sort: {
+ ascending: 'Sorter stigende',
+ descending: 'Sorter faldende',
+ none: 'Sorter ingen',
+ remove: 'Fjern sortering'
+ },
column: {
hide: 'Skjul kolonne'
},
aggregation: {
- count: 'samlede rækker: ',
- sum: 'smalede: ',
+ count: 'antal rækker: ',
+ sum: 'sum: ',
avg: 'gns: ',
min: 'min: ',
max: 'max: '
angular.module('ui.grid').config(['$provide', function ($provide) {
$provide.decorator('i18nService', ['$delegate', function ($delegate) {
$delegate.add('de', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Filter für Spalte',
+ removeFilter: 'Filter löschen',
+ columnMenuButtonLabel: 'Spaltenmenü'
+ },
+ priority: 'Priorität:',
+ filterLabel: "Filter für Spalte: "
+ },
aggregate: {
label: 'Eintrag'
},
sort: {
ascending: 'aufsteigend sortieren',
descending: 'absteigend sortieren',
+ none: 'keine Sortierung',
remove: 'Sortierung zurücksetzen'
},
column: {
pinRight: 'Rechts anheften',
unpin: 'Lösen'
},
+ columnMenu: {
+ close: 'Schließen'
+ },
gridMenu: {
+ aria: {
+ buttonLabel: 'Tabellenmenü'
+ },
columns: 'Spalten:',
importerTitle: 'Datei importieren',
exporterAllAsCsv: 'Alle Daten als CSV exportieren',
exporterAllAsPdf: 'Alle Daten als PDF exportieren',
exporterVisibleAsPdf: 'sichtbare Daten als PDF exportieren',
exporterSelectedAsPdf: 'markierte Daten als CSV exportieren',
- clearAllFilters: 'Alle filter reinigen'
+ clearAllFilters: 'Alle Filter zurücksetzen'
},
importer: {
noHeaders: 'Es konnten keine Spaltennamen ermittelt werden. Sind in der Datei Spaltendefinitionen enthalten?',
jsonNotArray: 'Die importierte JSON-Datei muß ein Array enthalten. Breche Import ab.'
},
pagination: {
- sizes: 'Einträge pro Seite',
- totalItems: 'Einträge'
+ aria: {
+ pageToFirst: 'Zum Anfang',
+ pageBack: 'Seite zurück',
+ pageSelected: 'Ausgwählte Seite',
+ pageForward: 'Seite vor',
+ pageToLast: 'Zum Ende'
+ },
+ sizes: 'Einträge pro Seite',
+ totalItems: 'Einträge',
+ through: 'bis',
+ of: 'von'
},
grouping: {
group: 'Gruppieren',
aggregate_min: 'Agg: Min',
aggregate_avg: 'Agg: Avg',
aggregate_remove: 'Agg: Remove'
+ },
+ validate: {
+ error: 'Error:',
+ minLength: 'Value should be at least THRESHOLD characters long.',
+ maxLength: 'Value should be at most THRESHOLD characters long.',
+ required: 'A value is needed.'
}
});
return $delegate;
aggregate_min: 'Agg: Minimo',
aggregate_avg: 'Agg: Media',
aggregate_remove: 'Agg: Rimuovi'
+ },
+ validate: {
+ error: 'Errore:',
+ minLength: 'Lunghezza minima pari a THRESHOLD caratteri.',
+ maxLength: 'Lunghezza massima pari a THRESHOLD caratteri.',
+ required: 'Necessario inserire un valore.'
}
});
return $delegate;
(function () {
angular.module('ui.grid').config(['$provide', function($provide) {
$provide.decorator('i18nService', ['$delegate', function($delegate) {
+ $delegate.add('pl', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Filter dla kolumny',
+ removeFilter: 'Usuń filter',
+ columnMenuButtonLabel: 'Menu kolumny'
+ },
+ priority: 'Prioritet:',
+ filterLabel: "Filtr dla kolumny: "
+ },
+ aggregate: {
+ label: 'pozycji'
+ },
+ groupPanel: {
+ description: 'Przeciągnij nagłówek kolumny tutaj, aby pogrupować według niej.'
+ },
+ search: {
+ placeholder: 'Szukaj...',
+ showingItems: 'Widoczne pozycje:',
+ selectedItems: 'Zaznaczone pozycje:',
+ totalItems: 'Wszystkich pozycji:',
+ size: 'Rozmiar strony:',
+ first: 'Pierwsza strona',
+ next: 'Następna strona',
+ previous: 'Poprzednia strona',
+ last: 'Ostatnia strona'
+ },
+ menu: {
+ text: 'Wybierz kolumny:'
+ },
+ sort: {
+ ascending: 'Sortuj rosnąco',
+ descending: 'Sortuj malejąco',
+ none: 'Brak sortowania',
+ remove: 'Wyłącz sortowanie'
+ },
+ column: {
+ hide: 'Ukryj kolumne'
+ },
+ aggregation: {
+ count: 'Razem pozycji: ',
+ sum: 'Razem: ',
+ avg: 'Średnia: ',
+ min: 'Min: ',
+ max: 'Max: '
+ },
+ pinning: {
+ pinLeft: 'Przypnij do lewej',
+ pinRight: 'Przypnij do prawej',
+ unpin: 'Odepnij'
+ },
+ columnMenu: {
+ close: 'Zamknij'
+ },
+ gridMenu: {
+ aria: {
+ buttonLabel: 'Menu Grida'
+ },
+ columns: 'Kolumny:',
+ importerTitle: 'Importuj plik',
+ exporterAllAsCsv: 'Eksportuj wszystkie dane do csv',
+ exporterVisibleAsCsv: 'Eksportuj widoczne dane do csv',
+ exporterSelectedAsCsv: 'Eksportuj zaznaczone dane do csv',
+ exporterAllAsPdf: 'Eksportuj wszystkie dane do pdf',
+ exporterVisibleAsPdf: 'Eksportuj widoczne dane do pdf',
+ exporterSelectedAsPdf: 'Eksportuj zaznaczone dane do pdf',
+ clearAllFilters: 'Wyczyść filtry'
+ },
+ importer: {
+ noHeaders: 'Nie udało się wczytać nazw kolumn. Czy plik posiada nagłówek?',
+ noObjects: 'Nie udalo się wczytać pozycji. Czy plik zawiera dane??',
+ invalidCsv: 'Nie udało się przetworzyć pliku, jest to prawidlowy plik CSV??',
+ invalidJson: 'Nie udało się przetworzyć pliku, jest to prawidlowy plik Json?',
+ jsonNotArray: 'Importowany plik json musi zawierać tablicę, importowanie przerwane.'
+ },
+ pagination: {
+ aria: {
+ pageToFirst: 'Pierwsza strona',
+ pageBack: 'Poprzednia strona',
+ pageSelected: 'Wybrana strona',
+ pageForward: 'Następna strona',
+ pageToLast: 'Ostatnia strona'
+ },
+ sizes: 'pozycji na stronę',
+ totalItems: 'pozycji',
+ through: 'do',
+ of: 'z'
+ },
+ grouping: {
+ group: 'Grupuj',
+ ungroup: 'Rozgrupuj',
+ aggregate_count: 'Zbiorczo: Razem',
+ aggregate_sum: 'Zbiorczo: Suma',
+ aggregate_max: 'Zbiorczo: Max',
+ aggregate_min: 'Zbiorczo: Min',
+ aggregate_avg: 'Zbiorczo: Średnia',
+ aggregate_remove: 'Zbiorczo: Usuń'
+ }
+ });
+ return $delegate;
+ }]);
+ }]);
+})();
+
+(function () {
+ angular.module('ui.grid').config(['$provide', function($provide) {
+ $provide.decorator('i18nService', ['$delegate', function($delegate) {
$delegate.add('pt-br', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Filtro por coluna',
+ removeFilter: 'Remover filtro',
+ columnMenuButtonLabel: 'Menu coluna'
+ },
+ priority: 'Prioridade:',
+ filterLabel: "Filtro por coluna: "
+ },
aggregate: {
label: 'itens'
},
sort: {
ascending: 'Ordenar Ascendente',
descending: 'Ordenar Descendente',
+ none: 'Nenhuma Ordem',
remove: 'Remover Ordenação'
},
column: {
pinRight: 'Fixar Direita',
unpin: 'Desprender'
},
+ columnMenu: {
+ close: 'Fechar'
+ },
gridMenu: {
+ aria: {
+ buttonLabel: 'Menu Grid'
+ },
columns: 'Colunas:',
importerTitle: 'Importar arquivo',
exporterAllAsCsv: 'Exportar todos os dados como csv',
jsonNotArray: 'Arquivo json importado tem que conter um array. Abortando.'
},
pagination: {
+ aria: {
+ pageToFirst: 'Primeira página',
+ pageBack: 'Página anterior',
+ pageSelected: 'Página Selecionada',
+ pageForward: 'Proxima',
+ pageToLast: 'Anterior'
+ },
sizes: 'itens por página',
- totalItems: 'itens'
+ totalItems: 'itens',
+ through: 'através dos',
+ of: 'de'
},
grouping: {
group: 'Agrupar',
angular.module('ui.grid').config(['$provide', function($provide) {
$provide.decorator('i18nService', ['$delegate', function($delegate) {
$delegate.add('pt', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Filtro por coluna',
+ removeFilter: 'Remover filtro',
+ columnMenuButtonLabel: 'Menu coluna'
+ },
+ priority: 'Prioridade:',
+ filterLabel: "Filtro por coluna: "
+ },
aggregate: {
label: 'itens'
},
sort: {
ascending: 'Ordenar Ascendente',
descending: 'Ordenar Descendente',
+ none: 'Nenhuma Ordem',
remove: 'Remover Ordenação'
},
column: {
pinRight: 'Fixar Direita',
unpin: 'Desprender'
},
+ columnMenu: {
+ close: 'Fechar'
+ },
gridMenu: {
+ aria: {
+ buttonLabel: 'Menu Grid'
+ },
columns: 'Colunas:',
importerTitle: 'Importar ficheiro',
exporterAllAsCsv: 'Exportar todos os dados como csv',
jsonNotArray: 'Ficheiro json importado tem que conter um array. Interrompendo.'
},
pagination: {
+ aria: {
+ pageToFirst: 'Primeira página',
+ pageBack: 'Página anterior',
+ pageSelected: 'Página Selecionada',
+ pageForward: 'Próxima',
+ pageToLast: 'Anterior'
+ },
sizes: 'itens por página',
totalItems: 'itens',
+ through: 'através dos',
of: 'de'
},
grouping: {
(function () {
angular.module('ui.grid').config(['$provide', function($provide) {
$provide.decorator('i18nService', ['$delegate', function($delegate) {
+ $delegate.add('ro', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Filtru pentru coloana',
+ removeFilter: 'Sterge filtru',
+ columnMenuButtonLabel: 'Column Menu'
+ },
+ priority: 'Prioritate:',
+ filterLabel: "Filtru pentru coloana:"
+ },
+ aggregate: {
+ label: 'Elemente'
+ },
+ groupPanel: {
+ description: 'Trage un cap de coloana aici pentru a grupa elementele dupa coloana respectiva'
+ },
+ search: {
+ placeholder: 'Cauta...',
+ showingItems: 'Arata elementele:',
+ selectedItems: 'Elementele selectate:',
+ totalItems: 'Total elemente:',
+ size: 'Marime pagina:',
+ first: 'Prima pagina',
+ next: 'Pagina urmatoare',
+ previous: 'Pagina anterioara',
+ last: 'Ultima pagina'
+ },
+ menu: {
+ text: 'Alege coloane:'
+ },
+ sort: {
+ ascending: 'Ordoneaza crescator',
+ descending: 'Ordoneaza descrescator',
+ none: 'Fara ordonare',
+ remove: 'Sterge ordonarea'
+ },
+ column: {
+ hide: 'Ascunde coloana'
+ },
+ aggregation: {
+ count: 'total linii: ',
+ sum: 'total: ',
+ avg: 'medie: ',
+ min: 'min: ',
+ max: 'max: '
+ },
+ pinning: {
+ pinLeft: 'Pin la stanga',
+ pinRight: 'Pin la dreapta',
+ unpin: 'Sterge pinul'
+ },
+ columnMenu: {
+ close: 'Inchide'
+ },
+ gridMenu: {
+ aria: {
+ buttonLabel: 'Grid Menu'
+ },
+ columns: 'Coloane:',
+ importerTitle: 'Incarca fisier',
+ exporterAllAsCsv: 'Exporta toate datele ca csv',
+ exporterVisibleAsCsv: 'Exporta datele vizibile ca csv',
+ exporterSelectedAsCsv: 'Exporta datele selectate ca csv',
+ exporterAllAsPdf: 'Exporta toate datele ca pdf',
+ exporterVisibleAsPdf: 'Exporta datele vizibile ca pdf',
+ exporterSelectedAsPdf: 'Exporta datele selectate ca csv pdf',
+ clearAllFilters: 'Sterge toate filtrele'
+ },
+ importer: {
+ noHeaders: 'Numele coloanelor nu a putut fi incarcat, acest fisier are un header?',
+ noObjects: 'Datele nu au putut fi incarcate, exista date in fisier in afara numelor de coloane?',
+ invalidCsv: 'Fisierul nu a putut fi procesat, ati incarcat un CSV valid ?',
+ invalidJson: 'Fisierul nu a putut fi procesat, ati incarcat un Json valid?',
+ jsonNotArray: 'Json-ul incarcat trebuie sa contina un array, inchidere.'
+ },
+ pagination: {
+ aria: {
+ pageToFirst: 'Prima pagina',
+ pageBack: 'O pagina inapoi',
+ pageSelected: 'Pagina selectata',
+ pageForward: 'O pagina inainte',
+ pageToLast: 'Ultima pagina'
+ },
+ sizes: 'Elemente per pagina',
+ totalItems: 'elemente',
+ through: 'prin',
+ of: 'of'
+ },
+ grouping: {
+ group: 'Grupeaza',
+ ungroup: 'Opreste gruparea',
+ aggregate_count: 'Agg: Count',
+ aggregate_sum: 'Agg: Sum',
+ aggregate_max: 'Agg: Max',
+ aggregate_min: 'Agg: Min',
+ aggregate_avg: 'Agg: Avg',
+ aggregate_remove: 'Agg: Remove'
+ }
+ });
+ return $delegate;
+ }]);
+ }]);
+})();
+
+(function () {
+ angular.module('ui.grid').config(['$provide', function($provide) {
+ $provide.decorator('i18nService', ['$delegate', function($delegate) {
$delegate.add('ru', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Фильтр столбца',
+ removeFilter: 'Удалить фильтр',
+ columnMenuButtonLabel: 'Меню столбца'
+ },
+ priority: 'Приоритет:',
+ filterLabel: "Фильтр столбца: "
+ },
aggregate: {
label: 'элементы'
},
sort: {
ascending: 'По возрастанию',
descending: 'По убыванию',
+ none: 'Без сортировки',
remove: 'Убрать сортировку'
},
column: {
pinRight: 'Закрепить справа',
unpin: 'Открепить'
},
+ columnMenu: {
+ close: 'Закрыть'
+ },
gridMenu: {
+ aria: {
+ buttonLabel: 'Меню'
+ },
columns: 'Столбцы:',
- importerTitle: 'Import file',
+ importerTitle: 'Импортировать файл',
exporterAllAsCsv: 'Экспортировать всё в CSV',
exporterVisibleAsCsv: 'Экспортировать видимые данные в CSV',
exporterSelectedAsCsv: 'Экспортировать выбранные данные в CSV',
clearAllFilters: 'Очистите все фильтры'
},
importer: {
- noHeaders: 'Column names were unable to be derived, does the file have a header?',
- noObjects: 'Objects were not able to be derived, was there data in the file other than headers?',
- invalidCsv: 'File was unable to be processed, is it valid CSV?',
- invalidJson: 'File was unable to be processed, is it valid Json?',
- jsonNotArray: 'Imported json file must contain an array, aborting.'
+ noHeaders: 'Не удалось получить названия столбцов, есть ли в файле заголовок?',
+ noObjects: 'Не удалось получить данные, есть ли в файле строки кроме заголовка?',
+ invalidCsv: 'Не удалось обработать файл, это правильный CSV-файл?',
+ invalidJson: 'Не удалось обработать файл, это правильный JSON?',
+ jsonNotArray: 'Импортируемый JSON-файл должен содержать массив, операция отменена.'
+ },
+ pagination: {
+ aria: {
+ pageToFirst: 'Первая страница',
+ pageBack: 'Предыдущая страница',
+ pageSelected: 'Выбранная страница',
+ pageForward: 'Следующая страница',
+ pageToLast: 'Последняя страница'
+ },
+ sizes: 'строк на страницу',
+ totalItems: 'строк',
+ through: 'по',
+ of: 'из'
+ },
+ grouping: {
+ group: 'Группировать',
+ ungroup: 'Разгруппировать',
+ aggregate_count: 'Группировать: Count',
+ aggregate_sum: 'Для группы: Сумма',
+ aggregate_max: 'Для группы: Максимум',
+ aggregate_min: 'Для группы: Минимум',
+ aggregate_avg: 'Для группы: Среднее',
+ aggregate_remove: 'Для группы: Пусто'
}
});
return $delegate;
}]);
})();
+(function () {
+ angular.module('ui.grid').config(['$provide', function($provide) {
+ $provide.decorator('i18nService', ['$delegate', function($delegate) {
+ $delegate.add('tr', {
+ headerCell: {
+ aria: {
+ defaultFilterLabel: 'Sütun için filtre',
+ removeFilter: 'Filtreyi Kaldır',
+ columnMenuButtonLabel: 'Sütun Menüsü'
+ },
+ priority: 'Öncelik:',
+ filterLabel: "Sütun için filtre: "
+ },
+ aggregate: {
+ label: 'kayıtlar'
+ },
+ groupPanel: {
+ description: 'Sütuna göre gruplamak için sütun başlığını buraya sürükleyin ve bırakın.'
+ },
+ search: {
+ placeholder: 'Arama...',
+ showingItems: 'Gösterilen Kayıt:',
+ selectedItems: 'Seçili Kayıt:',
+ totalItems: 'Toplam Kayıt:',
+ size: 'Sayfa Boyutu:',
+ first: 'İlk Sayfa',
+ next: 'Sonraki Sayfa',
+ previous: 'Önceki Sayfa',
+ last: 'Son Sayfa'
+ },
+ menu: {
+ text: 'Sütunları Seç:'
+ },
+ sort: {
+ ascending: 'Artan Sırada Sırala',
+ descending: 'Azalan Sırada Sırala',
+ none: 'Sıralama Yapma',
+ remove: 'Sıralamayı Kaldır'
+ },
+ column: {
+ hide: 'Sütunu Gizle'
+ },
+ aggregation: {
+ count: 'toplam satır: ',
+ sum: 'toplam: ',
+ avg: 'ort: ',
+ min: 'min: ',
+ max: 'maks: '
+ },
+ pinning: {
+ pinLeft: 'Sola Sabitle',
+ pinRight: 'Sağa Sabitle',
+ unpin: 'Sabitlemeyi Kaldır'
+ },
+ columnMenu: {
+ close: 'Kapat'
+ },
+ gridMenu: {
+ aria: {
+ buttonLabel: 'Tablo Menü'
+ },
+ columns: 'Sütunlar:',
+ importerTitle: 'Dosya içeri aktar',
+ exporterAllAsCsv: 'Bütün veriyi CSV olarak dışarı aktar',
+ exporterVisibleAsCsv: 'Görünen veriyi CSV olarak dışarı aktar',
+ exporterSelectedAsCsv: 'Seçili veriyi CSV olarak dışarı aktar',
+ exporterAllAsPdf: 'Bütün veriyi PDF olarak dışarı aktar',
+ exporterVisibleAsPdf: 'Görünen veriyi PDF olarak dışarı aktar',
+ exporterSelectedAsPdf: 'Seçili veriyi PDF olarak dışarı aktar',
+ clearAllFilters: 'Bütün filtreleri kaldır'
+ },
+ importer: {
+ noHeaders: 'Sütun isimleri üretilemiyor, dosyanın bir başlığı var mı?',
+ noObjects: 'Nesneler üretilemiyor, dosyada başlıktan başka bir veri var mı?',
+ invalidCsv: 'Dosya işlenemedi, geçerli bir CSV dosyası mı?',
+ invalidJson: 'Dosya işlenemedi, geçerli bir Json dosyası mı?',
+ jsonNotArray: 'Alınan Json dosyasında bir dizi bulunmalıdır, işlem iptal ediliyor.'
+ },
+ pagination: {
+ aria: {
+ pageToFirst: 'İlk sayfaya',
+ pageBack: 'Geri git',
+ pageSelected: 'Seçili sayfa',
+ pageForward: 'İleri git',
+ pageToLast: 'Sona git'
+ },
+ sizes: 'Sayfadaki nesne sayısı',
+ totalItems: 'kayıtlar',
+ through: '', //note(fsw) : turkish dont have this preposition
+ of: '' //note(fsw) : turkish dont have this preposition
+ },
+ grouping: {
+ group: 'Grupla',
+ ungroup: 'Gruplama',
+ aggregate_count: 'Yekun: Sayı',
+ aggregate_sum: 'Yekun: Toplam',
+ aggregate_max: 'Yekun: Maks',
+ aggregate_min: 'Yekun: Min',
+ aggregate_avg: 'Yekun: Ort',
+ aggregate_remove: 'Yekun: Sil'
+ }
+ });
+ return $delegate;
+ }]);
+ }]);
+})();
/**
* @ngdoc overview
* @name ui.grid.i18n
if (grid.cellNav.lastRowCol === null || rowColSelectIndex === -1) {
var newRowCol = new GridRowColumn(row, col);
- grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
- grid.cellNav.lastRowCol = newRowCol;
+ if (grid.cellNav.lastRowCol === null || grid.cellNav.lastRowCol.row !== newRowCol.row || grid.cellNav.lastRowCol.col !== newRowCol.col){
+ grid.api.cellNav.raise.navigate(newRowCol, grid.cellNav.lastRowCol);
+ grid.cellNav.lastRowCol = newRowCol;
+ }
if (uiGridCtrl.grid.options.modifierKeysToMultiSelectCells && modifierDown) {
grid.cellNav.focusedCells.push(rowCol);
} else {
*/
module.directive('uiGridCell',
- ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService', '$rootScope',
- function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService, $rootScope) {
+ ['$compile', '$injector', '$timeout', 'uiGridConstants', 'uiGridEditConstants', 'gridUtil', '$parse', 'uiGridEditService', '$rootScope', '$q',
+ function ($compile, $injector, $timeout, uiGridConstants, uiGridEditConstants, gridUtil, $parse, uiGridEditService, $rootScope, $q) {
var touchstartTimeout = 500;
if ($injector.has('uiGridCellNavService')) {
var uiGridCellNavService = $injector.get('uiGridCellNavService');
*
*/
/**
+ * @ngdoc service
+ * @name editDropdownOptionsFunction
+ * @methodOf ui.grid.edit.api:ColumnDef
+ * @description a function returning an array of values in the format
+ * [ {id: xxx, value: xxx} ], which will be used to populate
+ * the edit dropdown. This can be used when the dropdown values are dependent on
+ * the backing row entity with some kind of algorithm.
+ * If this property is set then both editDropdownOptionsArray and
+ * editDropdownRowEntityOptionsArrayPath will be ignored.
+ * @param {object} rowEntity the options.data element that the returned array refers to
+ * @param {object} colDef the column that implements this dropdown
+ * @returns {object} an array of values in the format
+ * [ {id: xxx, value: xxx} ] used to populate the edit dropdown
+ * @example
+ * <pre>
+ * $scope.gridOptions = {
+ * columnDefs: [
+ * {name: 'status', editableCellTemplate: 'ui-grid/dropdownEditor',
+ * editDropdownOptionsFunction: function(rowEntity, colDef) {
+ * if (rowEntity.foo === 'bar') {
+ * return [{id: 'bar1', value: 'BAR 1'},
+ * {id: 'bar2', value: 'BAR 2'},
+ * {id: 'bar3', value: 'BAR 3'}];
+ * } else {
+ * return [{id: 'foo1', value: 'FOO 1'},
+ * {id: 'foo2', value: 'FOO 2'}];
+ * }
+ * },
+ * editDropdownIdLabel: 'code', editDropdownValueLabel: 'status' }
+ * ],
+ * </pre>
+ *
+ */
+ /**
* @ngdoc property
* @name editDropdownValueLabel
* @propertyOf ui.grid.edit.api:ColumnDef
}
html = html.replace('INPUT_TYPE', inputType);
- var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
- if (editDropdownRowEntityOptionsArrayPath) {
- $scope.editDropdownOptionsArray = resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
- }
- else {
- $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
+ // In order to fill dropdown options we use:
+ // - A function/promise or
+ // - An array inside of row entity if no function exists or
+ // - A single array for the whole column if none of the previous exists.
+ var editDropdownOptionsFunction = $scope.col.colDef.editDropdownOptionsFunction;
+ if (editDropdownOptionsFunction) {
+ $q.when(editDropdownOptionsFunction($scope.row.entity, $scope.col.colDef))
+ .then(function(result) {
+ $scope.editDropdownOptionsArray = result;
+ });
+ } else {
+ var editDropdownRowEntityOptionsArrayPath = $scope.col.colDef.editDropdownRowEntityOptionsArrayPath;
+ if (editDropdownRowEntityOptionsArrayPath) {
+ $scope.editDropdownOptionsArray = resolveObjectFromPath($scope.row.entity, editDropdownRowEntityOptionsArrayPath);
+ }
+ else {
+ $scope.editDropdownOptionsArray = $scope.col.colDef.editDropdownOptionsArray;
+ }
}
$scope.editDropdownIdLabel = $scope.col.colDef.editDropdownIdLabel ? $scope.col.colDef.editDropdownIdLabel : 'id';
$scope.editDropdownValueLabel = $scope.col.colDef.editDropdownValueLabel ? $scope.col.colDef.editDropdownValueLabel : 'value';
if (uiGridCtrl && uiGridCtrl.grid.api.cellNav) {
var viewPortKeyDownUnregister = uiGridCtrl.grid.api.cellNav.on.viewPortKeyPress($scope, function (evt, rowCol) {
if (uiGridEditService.isStartEditKey(evt)) {
- ngModel.$setViewValue(String.fromCharCode(evt.keyCode), evt);
+ ngModel.$setViewValue(String.fromCharCode( typeof evt.which === 'number' ? evt.which : evt.keyCode), evt);
ngModel.$render();
}
viewPortKeyDownUnregister();
*/
/**
* @ngdoc object
+ * @name ui.grid.expandable.api:GridRow
+ *
+ * @description Additional properties added to GridRow when using the expandable module
+ */
+ /**
+ * @ngdoc object
* @name ui.grid.expandable.api:GridOptions
*
* @description Options for configuring the expandable feature, these are available to be
toggleRowExpansion: function (grid, row) {
// trigger the "before change" event. Can change row height dynamically this way.
grid.api.expandable.raise.rowExpandedBeforeStateChanged(row);
+ /**
+ * @ngdoc object
+ * @name isExpanded
+ * @propertyOf ui.grid.expandable.api:GridRow
+ * @description Whether or not the row is currently expanded.
+ * @example
+ * <pre>
+ * $scope.api.expandable.on.rowExpandedStateChanged($scope, function (row) {
+ * if (row.isExpanded) {
+ * //...
+ * }
+ * });
+ * </pre>
+ */
row.isExpanded = !row.isExpanded;
if (angular.isUndefined(row.expandedRowHeight)){
row.expandedRowHeight = grid.options.expandableRowHeight;
*
* <div class="alert alert-success" role="alert"><strong>Stable</strong> This feature is stable. There should no longer be breaking api changes without a deprecation warning.</div>
*
- * This module provides the ability to exporter data from the grid.
+ * This module provides the ability to export data from the grid.
*
* Data can be exported in a range of formats, and all data, visible
* data, or selected rows can be exported, with all columns or visible
/**
* @ngdoc object
+ * @name exporterMenuVisibleData
+ * @porpertyOf ui.grid.exporter.api:GridOptions
+ * @description Add export visible data as cvs/pdf menu items to the ui-grid grid menu, if it's present. Defaults to true.
+ */
+ gridOptions.exporterMenuVisibleData = gridOptions.exporterMenuVisibleData !== undefined ? gridOptions.exporterMenuVisibleData : true;
+
+ /**
+ * @ngdoc object
+ * @name exporterMenuSelectedData
+ * @porpertyOf ui.grid.exporter.api:GridOptions
+ * @description Add export selected data as cvs/pdf menu items to the ui-grid grid menu, if it's present. Defaults to true.
+ */
+ gridOptions.exporterMenuSelectedData = gridOptions.exporterMenuSelectedData !== undefined ? gridOptions.exporterMenuSelectedData : true;
+
+ /**
+ * @ngdoc object
* @name exporterMenuCsv
* @propertyOf ui.grid.exporter.api:GridOptions
* @description Add csv export menu items to the ui-grid grid menu, if it's present. Defaults to true.
this.grid.api.exporter.csvExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
},
shown: function() {
- return this.grid.options.exporterMenuCsv;
+ return this.grid.options.exporterMenuCsv && this.grid.options.exporterMenuVisibleData;
},
order: 201
},
this.grid.api.exporter.csvExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
},
shown: function() {
- return this.grid.options.exporterMenuCsv &&
+ return this.grid.options.exporterMenuCsv && this.grid.options.exporterMenuSelectedData &&
( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 );
},
order: 202
this.grid.api.exporter.pdfExport( uiGridExporterConstants.VISIBLE, uiGridExporterConstants.VISIBLE );
},
shown: function() {
- return this.grid.options.exporterMenuPdf;
+ return this.grid.options.exporterMenuPdf && this.grid.options.exporterMenuVisibleData;
},
order: 204
},
this.grid.api.exporter.pdfExport( uiGridExporterConstants.SELECTED, uiGridExporterConstants.VISIBLE );
},
shown: function() {
- return this.grid.options.exporterMenuPdf &&
+ return this.grid.options.exporterMenuPdf && this.grid.options.exporterMenuSelectedData &&
( this.grid.api.selection && this.grid.api.selection.getSelectedRows().length > 0 );
},
order: 205
* @param {string} colTypes which columns to export, valid values are
* uiGridExporterConstants.ALL, uiGridExporterConstants.VISIBLE,
* uiGridExporterConstants.SELECTED
+ * @param {boolean} applyCellFilters whether or not to get the display value or the raw value of the data
*/
- getData: function (grid, rowTypes, colTypes) {
+ getData: function (grid, rowTypes, colTypes, applyCellFilters) {
var data = [];
var rows;
var columns;
if ( (gridCol.visible || colTypes === uiGridExporterConstants.ALL ) &&
gridCol.colDef.exporterSuppressExport !== true &&
grid.options.exporterSuppressColumns.indexOf( gridCol.name ) === -1 ){
- var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, grid.getCellValue( row, gridCol ) ) };
+ var cellValue = applyCellFilters ? grid.getCellDisplayValue( row, gridCol ) : grid.getCellValue( row, gridCol );
+ var extractedField = { value: grid.options.exporterFieldCallback( grid, row, gridCol, cellValue ) };
if ( gridCol.colDef.exporterPdfAlign ) {
extractedField.alignment = gridCol.colDef.exporterPdfAlign;
}
* @description Checks whether current browser is IE and returns it's version if it is
*/
isIE: function () {
- var match = navigator.userAgent.match(/(?:MSIE |Trident\/.*; rv:)(\d+)/);
- return match ? parseInt(match[1]) : false;
+ var match = navigator.userAgent.search(/(?:Edge|MSIE|Trident\/.*; rv:)/);
+ var isIE = false;
+
+ if (match !== -1) {
+ isIE = true;
+ }
+
+ return isIE;
},
var exportData = self.getData(grid, rowTypes, colTypes);
var docDefinition = self.prepareAsPdf(grid, exportColumnHeaders, exportData);
- if (self.isIE()) {
+ if (self.isIE() || navigator.appVersion.indexOf("Edge") !== -1) {
self.downloadPDF(grid.options.exporterPdfFilename, docDefinition);
} else {
pdfMake.createPdf(docDefinition).open();
var rawFile;
var ieVersion;
- ieVersion = this.isIE();
+ ieVersion = this.isIE(); // This is now a boolean value
var doc = pdfMake.createPdf(docDefinition);
var blob;
doc.getBuffer( function (buffer) {
blob = new Blob([buffer]);
- if (ieVersion && ieVersion < 10) {
+ // IE10+
+ if (navigator.msSaveBlob) {
+ return navigator.msSaveBlob(
+ blob, fileName
+ );
+ }
+
+ // Previously: && ieVersion < 10
+ // ieVersion now returns a boolean for the
+ // sake of sanity. We just check `msSaveBlob` first.
+ if (ieVersion) {
var frame = D.createElement('iframe');
document.body.appendChild(frame);
document.body.removeChild(frame);
return true;
}
-
- // IE10+
- if (navigator.msSaveBlob) {
- return navigator.msSaveBlob(
- blob, fileName
- );
- }
});
},
newDisplayValue = grid.options.groupingNullLabel;
}
+ var getKeyAsValueForCacheMap = function(key) {
+ if (angular.isObject(key)) {
+ return JSON.stringify(key);
+ } else {
+ return key;
+ }
+ };
+
var cacheItem = grid.grouping.oldGroupingHeaderCache;
for ( var i = 0; i < stateIndex; i++ ){
- if ( cacheItem && cacheItem[processingState[i].currentValue] ){
- cacheItem = cacheItem[processingState[i].currentValue].children;
+ if ( cacheItem && cacheItem[getKeyAsValueForCacheMap(processingState[i].currentValue)] ){
+ cacheItem = cacheItem[getKeyAsValueForCacheMap(processingState[i].currentValue)].children;
}
}
var headerRow;
- if ( cacheItem && cacheItem[newValue]){
- headerRow = cacheItem[newValue].row;
+ if ( cacheItem && cacheItem[getKeyAsValueForCacheMap(newValue)]){
+ headerRow = cacheItem[getKeyAsValueForCacheMap(newValue)].row;
headerRow.entity = {};
} else {
headerRow = new GridRow( {}, null, grid );
// add our new header row to the cache
cacheItem = grid.grouping.groupingHeaderCache;
for ( i = 0; i < stateIndex; i++ ){
- cacheItem = cacheItem[processingState[i].currentValue].children;
+ cacheItem = cacheItem[getKeyAsValueForCacheMap(processingState[i].currentValue)].children;
}
- cacheItem[newValue] = { row: headerRow, children: {} };
+ cacheItem[getKeyAsValueForCacheMap(newValue)] = { row: headerRow, children: {} };
},
});
},
redrawColumnAtPosition: function (grid, originalPosition, newPosition) {
+ if (originalPosition === newPosition) {
+ return;
+ }
var columns = grid.columns;
//Left of cloned element should be aligned to original header cell.
movingElm.addClass('movingColumn');
var movingElementStyles = {};
- var elmLeft;
- if (gridUtil.detectBrowser() === 'safari') {
- //Correction for Safari getBoundingClientRect,
- //which does not correctly compute when there is an horizontal scroll
- elmLeft = $elm[0].offsetLeft + $elm[0].offsetWidth - $elm[0].getBoundingClientRect().width;
- }
- else {
- elmLeft = $elm[0].getBoundingClientRect().left;
- }
- movingElementStyles.left = (elmLeft - gridLeft) + 'px';
+ movingElementStyles.left = $elm[0].offsetLeft + 'px';
var gridRight = $scope.grid.element[0].getBoundingClientRect().right;
var elmRight = $elm[0].getBoundingClientRect().right;
if (elmRight > gridRight) {
//Update css of moving column to adjust to new left value or fire scroll in case column has reached edge of grid
if ((currentElmLeft >= gridLeft || changeValue > 0) && (currentElmRight <= rightMoveLimit || changeValue < 0)) {
- movingElm.css({visibility: 'visible', 'left': newElementLeft + 'px'});
+ movingElm.css({visibility: 'visible', 'left': (movingElm[0].offsetLeft +
+ (newElementLeft < rightMoveLimit ? changeValue : (rightMoveLimit - currentElmLeft))) + 'px'});
}
else if (totalColumnWidth > Math.ceil(uiGridCtrl.grid.gridWidth)) {
changeValue *= 8;
* @ngdoc property
* @name enablePagination
* @propertyOf ui.grid.pagination.api:GridOptions
- * @description Enables pagination, defaults to true
+ * @description Enables pagination. Defaults to true.
*/
gridOptions.enablePagination = gridOptions.enablePagination !== false;
/**
* @ngdoc property
* @name enablePaginationControls
* @propertyOf ui.grid.pagination.api:GridOptions
- * @description Enables the paginator at the bottom of the grid. Turn this off, if you want to implement your
+ * @description Enables the paginator at the bottom of the grid. Turn this off if you want to implement your
* own controls outside the grid.
*/
gridOptions.enablePaginationControls = gridOptions.enablePaginationControls !== false;
* @name useExternalPagination
* @propertyOf ui.grid.pagination.api:GridOptions
* @description Disables client side pagination. When true, handle the paginationChanged event and set data
- * and totalItems, defaults to `false`
+ * and totalItems. Defaults to `false`
*/
gridOptions.useExternalPagination = gridOptions.useExternalPagination === true;
/**
* @ngdoc property
* @name totalItems
* @propertyOf ui.grid.pagination.api:GridOptions
- * @description Total number of items, set automatically when client side pagination, needs set by user
+ * @description Total number of items, set automatically when using client side pagination, but needs set by user
* for server side pagination
*/
if (gridUtil.isNullOrUndefined(gridOptions.totalItems)) {
var options = uiGridCtrl.grid.options;
uiGridCtrl.grid.renderContainers.body.registerViewportAdjuster(function (adjustment) {
- adjustment.height = adjustment.height - gridUtil.elementHeight($elm);
+ adjustment.height = adjustment.height - gridUtil.elementHeight($elm, "padding");
return adjustment;
});
},
/**
* @ngdoc function
+ * @name getSelectedCount
+ * @methodOf ui.grid.selection.api:PublicApi
+ * @description returns the number of rows selected
+ */
+ getSelectedCount: function () {
+ return grid.selection.selectedCount;
+ },
+ /**
+ * @ngdoc function
* @name setMultiSelect
* @methodOf ui.grid.selection.api:PublicApi
* @description Sets the current gridOption.multiSelect to true or false
* all transient information on the tree (children, childCount) and recalculate it
*
*/
- grid.treeBase.tree = {};
+ grid.treeBase.tree = [];
service.defaultGridOptions(grid.options);
}]);
})();
+(function () {
+ 'use strict';
+
+ /**
+ * @ngdoc overview
+ * @name ui.grid.validate
+ * @description
+ *
+ * # ui.grid.validate
+ *
+ * <div class="alert alert-warning" role="alert"><strong>Alpha</strong> This feature is in development. There will almost certainly be breaking api changes, or there are major outstanding bugs.</div>
+ *
+ * This module provides the ability to validate cells upon change.
+ *
+ * Design information:
+ * -------------------
+ *
+ * Validation is not based on angularjs validation, since it would work only when editing the field.
+ *
+ * Instead it adds custom properties to any field considered as invalid.
+ *
+ * <br/>
+ * <br/>
+ *
+ * <div doc-module-components="ui.grid.expandable"></div>
+ */
+
+ var module = angular.module('ui.grid.validate', ['ui.grid']);
+
+
+ /**
+ * @ngdoc service
+ * @name ui.grid.validate.service:uiGridValidateService
+ *
+ * @description Services for validation features
+ */
+ module.service('uiGridValidateService', ['$sce', '$q', '$http', 'i18nService', 'uiGridConstants', function ($sce, $q, $http, i18nService, uiGridConstants) {
+
+ var service = {
+
+ /**
+ * @ngdoc object
+ * @name validatorFactories
+ * @propertyOf ui.grid.validate.service:uiGridValidateService
+ * @description object containing all the factories used to validate data.<br/>
+ * These factories will be in the form <br/>
+ * ```
+ * {
+ * validatorFactory: function(argument) {
+ * return function(newValue, oldValue, rowEntity, colDef) {
+ * return true || false || promise
+ * }
+ * },
+ * messageFunction: function(argument) {
+ * return string
+ * }
+ * }
+ * ```
+ *
+ * Promises should return true or false as result according to the result of validation.
+ */
+ validatorFactories: {},
+
+
+ /**
+ * @ngdoc service
+ * @name setExternalFactoryFunction
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Adds a way to retrieve validators from an external service
+ * <p>Validators from this external service have a higher priority than default
+ * ones
+ * @param {function} externalFactoryFunction a function that accepts name and argument to pass to a
+ * validator factory and that returns an object with the same properties as
+ * you can see in {@link ui.grid.validate.service:uiGridValidateService#properties_validatorFactories validatorFactories}
+ */
+ setExternalFactoryFunction: function(externalFactoryFunction) {
+ service.externalFactoryFunction = externalFactoryFunction;
+ },
+
+ /**
+ * @ngdoc service
+ * @name clearExternalFactory
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Removes any link to external factory from this service
+ */
+ clearExternalFactory: function() {
+ delete service.externalFactoryFunction;
+ },
+
+ /**
+ * @ngdoc service
+ * @name getValidatorFromExternalFactory
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Retrieves a validator by executing a validatorFactory
+ * stored in an external service.
+ * @param {string} name the name of the validator to retrieve
+ * @param {object} argument an argument to pass to the validator factory
+ */
+ getValidatorFromExternalFactory: function(name, argument) {
+ return service.externalFactoryFunction(name, argument).validatorFactory(argument);
+ },
+
+ /**
+ * @ngdoc service
+ * @name getMessageFromExternalFactory
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Retrieves a message stored in an external service.
+ * @param {string} name the name of the validator
+ * @param {object} argument an argument to pass to the message function
+ */
+ getMessageFromExternalFactory: function(name, argument) {
+ return service.externalFactoryFunction(name, argument).messageFunction(argument);
+ },
+
+ /**
+ * @ngdoc service
+ * @name setValidator
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Adds a new validator to the service
+ * @param {string} name the name of the validator, must be unique
+ * @param {function} validatorFactory a factory that return a validatorFunction
+ * @param {function} messageFunction a function that return the error message
+ */
+ setValidator: function(name, validatorFactory, messageFunction) {
+ service.validatorFactories[name] = {
+ validatorFactory: validatorFactory,
+ messageFunction: messageFunction
+ };
+ },
+
+ /**
+ * @ngdoc service
+ * @name getValidator
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Returns a validator registered to the service
+ * or retrieved from the external factory
+ * @param {string} name the name of the validator to retrieve
+ * @param {object} argument an argument to pass to the validator factory
+ * @returns {object} the validator function
+ */
+ getValidator: function(name, argument) {
+ if (service.externalFactoryFunction) {
+ var validator = service.getValidatorFromExternalFactory(name, argument);
+ if (validator) {
+ return validator;
+ }
+ }
+ if (!service.validatorFactories[name]) {
+ throw ("Invalid validator name: " + name);
+ }
+ return service.validatorFactories[name].validatorFactory(argument);
+ },
+
+ /**
+ * @ngdoc service
+ * @name getMessage
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Returns the error message related to the validator
+ * @param {string} name the name of the validator
+ * @param {object} argument an argument to pass to the message function
+ * @returns {string} the error message related to the validator
+ */
+ getMessage: function(name, argument) {
+ if (service.externalFactoryFunction) {
+ var message = service.getMessageFromExternalFactory(name, argument);
+ if (message) {
+ return message;
+ }
+ }
+ return service.validatorFactories[name].messageFunction(argument);
+ },
+
+ /**
+ * @ngdoc service
+ * @name isInvalid
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Returns true if the cell (identified by rowEntity, colDef) is invalid
+ * @param {object} rowEntity the row entity of the cell
+ * @param {object} colDef the colDef of the cell
+ * @returns {boolean} true if the cell is invalid
+ */
+ isInvalid: function (rowEntity, colDef) {
+ return rowEntity['$$invalid'+colDef.name];
+ },
+
+ /**
+ * @ngdoc service
+ * @name setInvalid
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Makes the cell invalid by adding the proper field to the entity
+ * @param {object} rowEntity the row entity of the cell
+ * @param {object} colDef the colDef of the cell
+ */
+ setInvalid: function (rowEntity, colDef) {
+ rowEntity['$$invalid'+colDef.name] = true;
+ },
+
+ /**
+ * @ngdoc service
+ * @name setValid
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Makes the cell valid by removing the proper error field from the entity
+ * @param {object} rowEntity the row entity of the cell
+ * @param {object} colDef the colDef of the cell
+ */
+ setValid: function (rowEntity, colDef) {
+ delete rowEntity['$$invalid'+colDef.name];
+ },
+
+ /**
+ * @ngdoc service
+ * @name setError
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Adds the proper error to the entity errors field
+ * @param {object} rowEntity the row entity of the cell
+ * @param {object} colDef the colDef of the cell
+ * @param {string} validatorName the name of the validator that is failing
+ */
+ setError: function(rowEntity, colDef, validatorName) {
+ if (!rowEntity['$$errors'+colDef.name]) {
+ rowEntity['$$errors'+colDef.name] = {};
+ }
+ rowEntity['$$errors'+colDef.name][validatorName] = true;
+ },
+
+ /**
+ * @ngdoc service
+ * @name clearError
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Removes the proper error from the entity errors field
+ * @param {object} rowEntity the row entity of the cell
+ * @param {object} colDef the colDef of the cell
+ * @param {string} validatorName the name of the validator that is failing
+ */
+ clearError: function(rowEntity, colDef, validatorName) {
+ if (!rowEntity['$$errors'+colDef.name]) {
+ return;
+ }
+ if (validatorName in rowEntity['$$errors'+colDef.name]) {
+ delete rowEntity['$$errors'+colDef.name][validatorName];
+ }
+ },
+
+ /**
+ * @ngdoc function
+ * @name getErrorMessages
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description returns an array of i18n-ed error messages.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {array} An array of strings containing all the error messages for the cell
+ */
+ getErrorMessages: function(rowEntity, colDef) {
+ var errors = [];
+
+ if (!rowEntity['$$errors'+colDef.name] || Object.keys(rowEntity['$$errors'+colDef.name]).length === 0) {
+ return errors;
+ }
+
+ Object.keys(rowEntity['$$errors'+colDef.name]).sort().forEach(function(validatorName) {
+ errors.push(service.getMessage(validatorName, colDef.validators[validatorName]));
+ });
+
+ return errors;
+ },
+
+ /**
+ * @ngdoc function
+ * @name getFormattedErrors
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description returns the error i18n-ed and formatted in html to be shown inside the page.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {object} An object that can be used in a template (like a cellTemplate) to display the
+ * message inside the page (i.e. inside a div)
+ */
+ getFormattedErrors: function(rowEntity, colDef) {
+
+ var msgString = "";
+
+ var errors = service.getErrorMessages(rowEntity, colDef);
+
+ if (!errors.length) {
+ return;
+ }
+
+ errors.forEach(function(errorMsg) {
+ msgString += errorMsg + "<br/>";
+ });
+
+ return $sce.trustAsHtml('<p><b>' + i18nService.getSafeText('validate.error') + '</b></p>' + msgString );
+ },
+
+ /**
+ * @ngdoc function
+ * @name getTitleFormattedErrors
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description returns the error i18n-ed and formatted in javaScript to be shown inside an html
+ * title attribute.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {object} An object that can be used in a template (like a cellTemplate) to display the
+ * message inside an html title attribute
+ */
+ getTitleFormattedErrors: function(rowEntity, colDef) {
+
+ var newLine = "\n";
+
+ var msgString = "";
+
+ var errors = service.getErrorMessages(rowEntity, colDef);
+
+ if (!errors.length) {
+ return;
+ }
+
+ errors.forEach(function(errorMsg) {
+ msgString += errorMsg + newLine;
+ });
+
+ return $sce.trustAsHtml(i18nService.getSafeText('validate.error') + newLine + msgString);
+ },
+
+ /**
+ * @ngdoc function
+ * @name getTitleFormattedErrors
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description Executes all validators on a cell (identified by row entity and column definition) and sets or clears errors
+ * @param {object} rowEntity the row entity of the cell we want to run the validators on
+ * @param {object} colDef the column definition of the cell we want to run the validators on
+ * @param {object} newValue the value the user just entered
+ * @param {object} oldValue the value the field had before
+ */
+ runValidators: function(rowEntity, colDef, newValue, oldValue, grid) {
+
+ if (newValue === oldValue) {
+ // If the value has not changed we perform no validation
+ return;
+ }
+
+ if (typeof(colDef.name) === 'undefined' || !colDef.name) {
+ throw new Error('colDef.name is required to perform validation');
+ }
+
+ service.setValid(rowEntity, colDef);
+
+ var validateClosureFactory = function(rowEntity, colDef, validatorName) {
+ return function(value) {
+ if (!value) {
+ service.setInvalid(rowEntity, colDef);
+ service.setError(rowEntity, colDef, validatorName);
+ if (grid) {
+ grid.api.validate.raise.validationFailed(rowEntity, colDef, newValue, oldValue);
+ }
+ }
+ };
+ };
+
+ for (var validatorName in colDef.validators) {
+ service.clearError(rowEntity, colDef, validatorName);
+ var msg;
+ var validatorFunction = service.getValidator(validatorName, colDef.validators[validatorName]);
+ // We pass the arguments as oldValue, newValue so they are in the same order
+ // as ng-model validators (modelValue, viewValue)
+ $q.when(validatorFunction(oldValue, newValue, rowEntity, colDef))
+ .then(validateClosureFactory(rowEntity, colDef, validatorName)
+ );
+ }
+ },
+
+ /**
+ * @ngdoc function
+ * @name createDefaultValidators
+ * @methodOf ui.grid.validate.service:uiGridValidateService
+ * @description adds the basic validators to the list of service validators
+ */
+ createDefaultValidators: function() {
+ service.setValidator('minLength',
+ function (argument) {
+ return function (oldValue, newValue, rowEntity, colDef) {
+ if (newValue === undefined || newValue === null || newValue === '') {
+ return true;
+ }
+ return newValue.length >= argument;
+ };
+ },
+ function(argument) {
+ return i18nService.getSafeText('validate.minLength').replace('THRESHOLD', argument);
+ });
+
+ service.setValidator('maxLength',
+ function (argument) {
+ return function (oldValue, newValue, rowEntity, colDef) {
+ if (newValue === undefined || newValue === null || newValue === '') {
+ return true;
+ }
+ return newValue.length <= argument;
+ };
+ },
+ function(threshold) {
+ return i18nService.getSafeText('validate.maxLength').replace('THRESHOLD', threshold);
+ });
+
+ service.setValidator('required',
+ function (argument) {
+ return function (oldValue, newValue, rowEntity, colDef) {
+ if (argument) {
+ return !(newValue === undefined || newValue === null || newValue === '');
+ }
+ return true;
+ };
+ },
+ function(argument) {
+ return i18nService.getSafeText('validate.required');
+ });
+ },
+
+ initializeGrid: function (scope, grid) {
+ grid.validate = {
+
+ isInvalid: service.isInvalid,
+
+ getFormattedErrors: service.getFormattedErrors,
+
+ getTitleFormattedErrors: service.getTitleFormattedErrors,
+
+ runValidators: service.runValidators
+ };
+
+ /**
+ * @ngdoc object
+ * @name ui.grid.validate.api:PublicApi
+ *
+ * @description Public Api for validation feature
+ */
+ var publicApi = {
+ events: {
+ validate: {
+ /**
+ * @ngdoc event
+ * @name validationFailed
+ * @eventOf ui.grid.validate.api:PublicApi
+ * @description raised when one or more failure happened during validation
+ * <pre>
+ * gridApi.validate.on.validationFailed(scope, function(rowEntity, colDef, newValue, oldValue){...})
+ * </pre>
+ * @param {object} rowEntity the options.data element whose validation failed
+ * @param {object} colDef the column whose validation failed
+ * @param {object} newValue new value
+ * @param {object} oldValue old value
+ */
+ validationFailed: function (rowEntity, colDef, newValue, oldValue) {
+ }
+ }
+ },
+ methods: {
+ validate: {
+ /**
+ * @ngdoc function
+ * @name isInvalid
+ * @methodOf ui.grid.validate.api:PublicApi
+ * @description checks if a cell (identified by rowEntity, colDef) is invalid
+ * @param {object} rowEntity gridOptions.data[] array instance we want to check
+ * @param {object} colDef the column whose errors we want to check
+ * @returns {boolean} true if the cell value is not valid
+ */
+ isInvalid: function(rowEntity, colDef) {
+ return grid.validate.isInvalid(rowEntity, colDef);
+ },
+ /**
+ * @ngdoc function
+ * @name getErrorMessages
+ * @methodOf ui.grid.validate.api:PublicApi
+ * @description returns an array of i18n-ed error messages.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {array} An array of strings containing all the error messages for the cell
+ */
+ getErrorMessages: function (rowEntity, colDef) {
+ return grid.validate.getErrorMessages(rowEntity, colDef);
+ },
+ /**
+ * @ngdoc function
+ * @name getFormattedErrors
+ * @methodOf ui.grid.validate.api:PublicApi
+ * @description returns the error i18n-ed and formatted in html to be shown inside the page.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {object} An object that can be used in a template (like a cellTemplate) to display the
+ * message inside the page (i.e. inside a div)
+ */
+ getFormattedErrors: function (rowEntity, colDef) {
+ return grid.validate.getFormattedErrors(rowEntity, colDef);
+ },
+ /**
+ * @ngdoc function
+ * @name getTitleFormattedErrors
+ * @methodOf ui.grid.validate.api:PublicApi
+ * @description returns the error i18n-ed and formatted in javaScript to be shown inside an html
+ * title attribute.
+ * @param {object} rowEntity gridOptions.data[] array instance whose errors we are looking for
+ * @param {object} colDef the column whose errors we are looking for
+ * @returns {object} An object that can be used in a template (like a cellTemplate) to display the
+ * message inside an html title attribute
+ */
+ getTitleFormattedErrors: function (rowEntity, colDef) {
+ return grid.validate.getTitleFormattedErrors(rowEntity, colDef);
+ }
+ }
+ }
+ };
+
+ grid.api.registerEventsFromObject(publicApi.events);
+ grid.api.registerMethodsFromObject(publicApi.methods);
+
+ if (grid.edit) {
+ grid.api.edit.on.afterCellEdit(scope, function(rowEntity, colDef, newValue, oldValue) {
+ grid.validate.runValidators(rowEntity, colDef, newValue, oldValue, grid);
+ });
+ }
+
+ service.createDefaultValidators();
+ }
+
+ };
+
+ return service;
+ }]);
+
+
+ /**
+ * @ngdoc directive
+ * @name ui.grid.validate.directive:uiGridValidate
+ * @element div
+ * @restrict A
+ * @description Adds validating features to the ui-grid directive.
+ * @example
+ <example module="app">
+ <file name="app.js">
+ var app = angular.module('app', ['ui.grid', 'ui.grid.edit', 'ui.grid.validate']);
+
+ app.controller('MainCtrl', ['$scope', function ($scope) {
+ $scope.data = [
+ { name: 'Bob', title: 'CEO' },
+ { name: 'Frank', title: 'Lowly Developer' }
+ ];
+
+ $scope.columnDefs = [
+ {name: 'name', enableCellEdit: true, validators: {minLength: 3, maxLength: 9}, cellTemplate: 'ui-grid/cellTitleValidator'},
+ {name: 'title', enableCellEdit: true, validators: {required: true}, cellTemplate: 'ui-grid/cellTitleValidator'}
+ ];
+ }]);
+ </file>
+ <file name="index.html">
+ <div ng-controller="MainCtrl">
+ <div ui-grid="{ data: data, columnDefs: columnDefs }" ui-grid-edit ui-grid-validate></div>
+ </div>
+ </file>
+ </example>
+ */
+
+ module.directive('uiGridValidate', ['gridUtil', 'uiGridValidateService', function (gridUtil, uiGridValidateService) {
+ return {
+ priority: 0,
+ replace: true,
+ require: '^uiGrid',
+ scope: false,
+ compile: function () {
+ return {
+ pre: function ($scope, $elm, $attrs, uiGridCtrl) {
+ uiGridValidateService.initializeGrid($scope, uiGridCtrl.grid);
+ },
+ post: function ($scope, $elm, $attrs, uiGridCtrl) {
+ }
+ };
+ }
+ };
+ }]);
+})();
angular.module('ui.grid').run(['$templateCache', function($templateCache) {
'use strict';
$templateCache.put('ui-grid/uiGridHeaderCell',
- "<div role=\"columnheader\" ng-class=\"{ 'sortable': sortable }\" ui-grid-one-bind-aria-labelledby-grid=\"col.uid + '-header-text ' + col.uid + '-sortdir-text'\" aria-sort=\"{{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ? 'descending' : (!col.sort.direction ? 'none' : 'other'))}}\"><div role=\"button\" tabindex=\"0\" class=\"ui-grid-cell-contents ui-grid-header-cell-primary-focus\" col-index=\"renderIndex\" title=\"TOOLTIP\"><span class=\"ui-grid-header-cell-label\" ui-grid-one-bind-id-grid=\"col.uid + '-header-text'\">{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-one-bind-id-grid=\"col.uid + '-sortdir-text'\" ui-grid-visible=\"col.sort.direction\" aria-label=\"{{getSortDirectionAriaLabel()}}\"><i ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\" title=\"{{col.sort.priority ? i18n.headerCell.priority + ' ' + col.sort.priority : null}}\" aria-hidden=\"true\"></i> <sub class=\"ui-grid-sort-priority-number\">{{col.sort.priority}}</sub></span></div><div role=\"button\" tabindex=\"0\" ui-grid-one-bind-id-grid=\"col.uid + '-menu-button'\" class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\" ui-grid-one-bind-aria-label=\"i18n.headerCell.aria.columnMenuButtonLabel\" aria-haspopup=\"true\"><i class=\"ui-grid-icon-angle-down\" aria-hidden=\"true\"> </i></div><div ui-grid-filter></div></div>"
+ "<div role=\"columnheader\" ng-class=\"{ 'sortable': sortable }\" ui-grid-one-bind-aria-labelledby-grid=\"col.uid + '-header-text ' + col.uid + '-sortdir-text'\" aria-sort=\"{{col.sort.direction == asc ? 'ascending' : ( col.sort.direction == desc ? 'descending' : (!col.sort.direction ? 'none' : 'other'))}}\"><div role=\"button\" tabindex=\"0\" class=\"ui-grid-cell-contents ui-grid-header-cell-primary-focus\" col-index=\"renderIndex\" title=\"TOOLTIP\"><span class=\"ui-grid-header-cell-label\" ui-grid-one-bind-id-grid=\"col.uid + '-header-text'\">{{ col.displayName CUSTOM_FILTERS }}</span> <span ui-grid-one-bind-id-grid=\"col.uid + '-sortdir-text'\" ui-grid-visible=\"col.sort.direction\" aria-label=\"{{getSortDirectionAriaLabel()}}\"><i ng-class=\"{ 'ui-grid-icon-up-dir': col.sort.direction == asc, 'ui-grid-icon-down-dir': col.sort.direction == desc, 'ui-grid-icon-blank': !col.sort.direction }\" title=\"{{isSortPriorityVisible() ? i18n.headerCell.priority + ' ' + col.sort.priority : null}}\" aria-hidden=\"true\"></i> <sub ui-grid-visible=\"isSortPriorityVisible()\" class=\"ui-grid-sort-priority-number\">{{col.sort.priority}}</sub></span></div><div role=\"button\" tabindex=\"0\" ui-grid-one-bind-id-grid=\"col.uid + '-menu-button'\" class=\"ui-grid-column-menu-button\" ng-if=\"grid.options.enableColumnMenus && !col.isRowHeader && col.colDef.enableColumnMenu !== false\" ng-click=\"toggleMenu($event)\" ng-class=\"{'ui-grid-column-menu-button-last-col': isLastCol}\" ui-grid-one-bind-aria-label=\"i18n.headerCell.aria.columnMenuButtonLabel\" aria-haspopup=\"true\"><i class=\"ui-grid-icon-angle-down\" aria-hidden=\"true\"> </i></div><div ui-grid-filter></div></div>"
);
$templateCache.put('ui-grid/uiGridMenu',
- "<div class=\"ui-grid-menu\" ng-if=\"shown\"><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><button type=\"button\" ng-focus=\"focus=true\" ng-blur=\"focus=false\" class=\"ui-grid-menu-close-button\" ng-class=\"{'ui-grid-sr-only': (!focus)}\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"i18n.close\"></i></button><ul role=\"menu\" class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" role=\"menuitem\" ui-grid-menu-item ui-grid-one-bind-id=\"'menuitem-'+$index\" action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\" leave-open=\"item.leaveOpen\" screen-reader-only=\"item.screenReaderOnly\"></li></ul></div></div></div>"
+ "<div class=\"ui-grid-menu\" ng-if=\"shown\"><style ui-grid-style>{{dynamicStyles}}</style><div class=\"ui-grid-menu-mid\" ng-show=\"shownMid\"><div class=\"ui-grid-menu-inner\"><button type=\"button\" ng-focus=\"focus=true\" ng-blur=\"focus=false\" class=\"ui-grid-menu-close-button\" ng-class=\"{'ui-grid-sr-only': (!focus)}\"><i class=\"ui-grid-icon-cancel\" ui-grid-one-bind-aria-label=\"i18n.close\"></i></button><ul role=\"menu\" class=\"ui-grid-menu-items\"><li ng-repeat=\"item in menuItems\" role=\"menuitem\" ui-grid-menu-item ui-grid-one-bind-id=\"'menuitem-'+$index\" action=\"item.action\" name=\"item.title\" active=\"item.active\" icon=\"item.icon\" shown=\"item.shown\" context=\"item.context\" template-url=\"item.templateUrl\" leave-open=\"item.leaveOpen\" screen-reader-only=\"item.screenReaderOnly\"></li></ul></div></div></div>"
);
"<div class=\"ui-grid-tree-base-row-header-buttons\" ng-class=\"{'ui-grid-tree-base-header': row.treeLevel > -1 }\" ng-click=\"treeButtonClick(row, $event)\"><i ng-class=\"{'ui-grid-icon-minus-squared': ( ( grid.options.showTreeExpandNoChildren && row.treeLevel > -1 ) || ( row.treeNode.children && row.treeNode.children.length > 0 ) ) && row.treeNode.state === 'expanded', 'ui-grid-icon-plus-squared': ( ( grid.options.showTreeExpandNoChildren && row.treeLevel > -1 ) || ( row.treeNode.children && row.treeNode.children.length > 0 ) ) && row.treeNode.state === 'collapsed'}\" ng-style=\"{'padding-left': grid.options.treeIndent * row.treeLevel + 'px'}\"></i> </div>"
);
+
+ $templateCache.put('ui-grid/cellTitleValidator',
+ "<div class=\"ui-grid-cell-contents\" ng-class=\"{invalid:grid.validate.isInvalid(row.entity,col.colDef)}\" title=\"{{grid.validate.getTitleFormattedErrors(row.entity,col.colDef)}}\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
+ );
+
+
+ $templateCache.put('ui-grid/cellTooltipValidator',
+ "<div class=\"ui-grid-cell-contents\" ng-class=\"{invalid:grid.validate.isInvalid(row.entity,col.colDef)}\" tooltip-html-unsafe=\"{{grid.validate.getFormattedErrors(row.entity,col.colDef)}}\" tooltip-enable=\"grid.validate.isInvalid(row.entity,col.colDef)\" tooltip-append-to-body=\"true\" tooltip-placement=\"top\" title=\"TOOLTIP\">{{COL_FIELD CUSTOM_FILTERS}}</div>"
+ );
+
}]);