@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
897 lines • 54.1 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* Copyright © 2025 Progress Software Corporation. All rights reserved.
* Licensed under commercial license. See LICENSE.md in the project root for more information
*-------------------------------------------------------------------------------------------*/
import { ColumnInfoService } from './../../common/column-info.service';
import { Component, ChangeDetectorRef, HostBinding, Input, QueryList, ViewChildren, TemplateRef, NgZone } from '@angular/core';
import { Subscription, of, merge } from "rxjs";
import { filter, map, switchMap, tap, takeUntil } from 'rxjs/operators';
import { isColumnComponent } from '../../columns/column.component';
import { isColumnGroupComponent } from '../../columns/column-group.component';
import { isCheckboxColumn } from '../../columns/column-base';
import { DetailTemplateDirective } from '../details/detail-template.directive';
import { normalize } from '../../columns/sort-settings';
import { and, isNullOrEmptyString, isPresent, isTruthy, not, observe } from '../../utils';
import { columnsToRender, sortColumns, isInSpanColumn } from "../../columns/column-common";
import { SinglePopupService } from '../../common/single-popup.service';
import { hasFilterMenu, hasFilterRow } from '../../filtering/filterable';
import { IdService } from '../../common/id.service';
import { DraggableDirective, isDocumentAvailable, Keys, TemplateContextDirective } from '@progress/kendo-angular-common';
import { DropTargetDirective } from '../../dragdrop/drop-target.directive';
import { DraggableColumnDirective } from '../../dragdrop/draggable-column.directive';
import { DragHintService } from '../../dragdrop/drag-hint.service';
import { DropCueService } from '../../dragdrop/drop-cue.service';
import { ColumnReorderService } from '../../dragdrop/column-reorder.service';
import { position, isTargetBefore, offset } from '../../dragdrop/common';
import { SortService } from '../../common/sort.service';
import { hasItems } from '../../column-menu/utils';
import { closestInScope, isFocusable } from '../common/dom-queries';
import { FilterMenuComponent } from '../../filtering/menu/filter-menu.component';
import { ColumnMenuComponent } from '../../column-menu/column-menu.component';
import { sortAscSmallIcon, sortDescSmallIcon } from '@progress/kendo-svg-icons';
import { ContextService } from '../../common/provider.service';
import { ColumnReorderEvent } from '../../dragdrop/column-reorder-event';
import { ColumnsContainer } from '../../columns/columns-container';
import { NavigationService } from '../../navigation/navigation.service';
import { FilterRowComponent } from '../../filtering/filter-row.component';
import { ColumnHandleDirective } from '../../column-resizing/column-handle.directive';
import { FocusableDirective } from '../../navigation/focusable.directive';
import { SelectAllCheckboxDirective } from '../../selection/selectall-checkbox.directive';
import { LogicalCellDirective } from '../../navigation/logical-cell.directive';
import { LogicalRowDirective } from '../../navigation/logical-row.directive';
import { NgFor, NgIf, NgClass, NgStyle } from '@angular/common';
import { IconWrapperComponent } from '@progress/kendo-angular-icons';
import { CheckBoxComponent } from '@progress/kendo-angular-inputs';
import * as i0 from "@angular/core";
import * as i1 from "../../common/single-popup.service";
import * as i2 from "../../dragdrop/drag-hint.service";
import * as i3 from "../../dragdrop/drop-cue.service";
import * as i4 from "../../dragdrop/column-reorder.service";
import * as i5 from "../../common/id.service";
import * as i6 from "../../common/sort.service";
import * as i7 from "./../../common/column-info.service";
import * as i8 from "../../common/provider.service";
import * as i9 from "../../navigation/navigation.service";
const mergeObjects = (...args) => Object.assign.apply(null, [{}].concat(args));
const directions = initialDirection => initialDirection === "asc" ? ["asc", "desc"] : ["desc", "asc"];
/**
* @hidden
*/
const isRootLevel = ({ parent }) => !isTruthy(parent);
const ofColumnType = ({ draggable }) => ['column', 'columnGroup']
.indexOf(draggable.context.type) >= 0;
const notSameElement = ({ draggable, target }) => draggable.element.nativeElement !== target.element.nativeElement;
const inSameParent = (x, y) => x.parent === y.parent ||
(isInSpanColumn(y) && inSameParent(x, y.parent));
const sameParent = ({ draggable, target }) => inSameParent(draggable.context.column, target.context.column);
const lastNonLocked = ({ draggable }) => !isTruthy(draggable.context.column.locked) &&
isRootLevel(draggable.context.column) &&
draggable.context.lastColumn;
const notInSpanColumn = ({ draggable }) => !isInSpanColumn(draggable.context.column);
const reorderable = ({ draggable }) => draggable.context.column.reorderable;
const lockable = ({ draggable, target }) => draggable.context.column.lockable !== false ||
draggable.context.column.isLocked === target.context.column.isLocked;
const rules = and(ofColumnType, reorderable, notInSpanColumn, notSameElement, sameParent, not(lastNonLocked), lockable);
const modifierKeys = ['alt', 'ctrl', 'shift', 'meta'];
/**
* @hidden
*/
export class HeaderComponent {
popupService;
hint;
cue;
reorderService;
idService;
sortService;
columnInfoService;
cd;
contextService;
navigationService;
zone;
/**
* @hidden
*/
totalColumnLevels;
columns = [];
groups = [];
detailTemplate;
scrollable;
filterable;
sort = new Array();
filter;
sortable = false;
groupable = false;
lockedColumnsCount = 0;
resizable = false;
reorderable = false;
columnMenu = false;
columnMenuTemplate;
totalColumnsCount = 0;
totalColumns;
tabIndex;
size = 'medium';
sortedFields = {};
hostClass = true;
get sortableLabel() {
return this.contextService.localization.get('sortable');
}
get columnMenuSettings() {
return this.columnMenu;
}
dropTargets = new QueryList();
filterMenus;
columnMenus;
// Number of unlocked columns in the next table, if any
get unlockedColumnsCount() {
return this.totalColumnsCount - this.lockedColumnsCount - this.columns.length;
}
sortAscSmallIcon = sortAscSmallIcon;
sortDescSmallIcon = sortDescSmallIcon;
subscription = new Subscription();
targetSubscription;
stopSorting = false;
_leafColumns;
constructor(popupService, hint, cue, reorderService, idService, sortService, columnInfoService, cd, contextService, navigationService, zone) {
this.popupService = popupService;
this.hint = hint;
this.cue = cue;
this.reorderService = reorderService;
this.idService = idService;
this.sortService = sortService;
this.columnInfoService = columnInfoService;
this.cd = cd;
this.contextService = contextService;
this.navigationService = navigationService;
this.zone = zone;
}
sortColumn(descriptor) {
this.sortService.sort(descriptor);
}
getColumnComponent(column) {
return column;
}
onSortClick(column, event, link) {
if (this.stopSorting) {
this.stopSorting = false;
return;
}
const target = event.target;
if (column.headerTemplateRef && target !== link) {
const hasFocusableParent = Boolean(closestInScope(target, isFocusable, link));
if (hasFocusableParent) {
// Do not sort when clicking focusable template elements.
return;
}
}
const modifier = this.matchModifier(event);
const toggledColumn = this.toggleSort(column, modifier);
this.sortColumn(toggledColumn);
}
onHeaderKeydown(column, args) {
if (args.keyCode === Keys.ArrowDown && args.altKey && this.showFilterMenu) {
args.preventDefault();
args.stopImmediatePropagation();
const filterMenu = this.filterMenus.find(fm => fm.column === column);
filterMenu.toggle(filterMenu.anchor.nativeElement, filterMenu.template);
return;
}
if (args.keyCode === Keys.ArrowDown && args.altKey && this.showColumnMenu(column)) {
args.preventDefault();
args.stopImmediatePropagation();
const columnMenu = this.columnMenus.find(cm => cm.column === column);
columnMenu.toggle(null, columnMenu.anchor.nativeElement, columnMenu.template);
return;
}
const isCtrlOrMeta = args.ctrlKey || args.metaKey;
const isGroupingKeyShortcut = (args.keyCode === Keys.Enter || args.keyCode === Keys.Space) && isCtrlOrMeta;
if (isGroupingKeyShortcut && this.isGroupable(column)) {
args.preventDefault();
args.stopImmediatePropagation();
const isGroupedByField = this.groups.some(gr => gr.field === column.field);
if (isGroupedByField) {
this.groups = this.groups.filter(gr => gr.field !== column.field);
}
else {
this.groups.push({
field: column.field
});
}
this.contextService.grid.groupChange.emit(this.groups);
return;
}
const isLeftOrRightArrow = args.keyCode === Keys.ArrowLeft || args.keyCode === Keys.ArrowRight;
const isReorderingKeyShortcut = isLeftOrRightArrow && isCtrlOrMeta;
if (isReorderingKeyShortcut && this.isReorderable(column)) {
args.preventDefault();
const columnsCount = this.columnInfoService.leafNamedColumns.length;
const reorderDirection = args.keyCode === Keys.ArrowLeft ? -1 : 1;
const rtlMultiplier = this.contextService.localization.rtl ? -1 : 1;
const reorderDirectionOffset = reorderDirection * rtlMultiplier;
const newIndex = column.leafIndex + reorderDirectionOffset;
const normalizedNewIndex = Math.min(Math.max(0, newIndex), columnsCount - 1);
const gridInstance = this.contextService.grid;
gridInstance.reorderColumn(column, normalizedNewIndex, { before: reorderDirectionOffset < 0 });
gridInstance.columnReorder.emit(new ColumnReorderEvent({
column,
newIndex: normalizedNewIndex,
oldIndex: column.leafIndex
}));
return;
}
if (!this.sortable || args.defaultPrevented || column.sortable === false) {
return;
}
if (args.keyCode === Keys.Enter && isPresent(column.field)) {
const modifier = this.matchModifier(args);
this.sortService.sort(this.toggleSort(column, modifier));
}
}
showSortNumbering(column) {
const { showIndexes } = normalize(this.sortable);
return showIndexes
&& this.sort
&& this.sort.filter(({ dir }) => isPresent(dir)).length > 1
&& this.sortOrder(column.field) > 0;
}
sortOrder(field) {
return this.sort
.filter(({ dir }) => isPresent(dir))
.findIndex(x => x.field === field)
+ 1;
}
sortState(column) {
if (!this.isInteractive(column, 'sortable')) {
return;
}
const state = this.sortDescriptor(column.field);
if (state.dir === 'asc') {
return 'ascending';
}
if (state.dir === 'desc') {
return 'descending';
}
}
get isNavigable() {
return this.navigationService.tableEnabled;
}
/**
*
* @param column
* @param modifier - Indicates whether the client-defined `multiSortKey` modifier is met. Defaults to `true`.
* @returns - SortDescriptor[]
*/
toggleSort(column, modifier = true) {
const { allowUnsort, mode, initialDirection } = normalize(this.sortable, column.sortable);
const descriptor = this.toggleDirection(column.field, allowUnsort, initialDirection);
if (mode === 'single' || !modifier) {
return [descriptor];
}
return [...this.sort.filter(desc => desc.field !== column.field), descriptor];
}
/**
*
* Determines whether the modifier key (if any) passed
* with a click/keyboard event matches the user-defined multiSortKey.
*/
matchModifier(event) {
const { multiSortKey } = normalize(this.sortable);
if (multiSortKey === 'none') {
return modifierKeys.every(key => !event[`${key}Key`]);
}
return multiSortKey === 'ctrl'
? event.ctrlKey || event.metaKey
: event[`${multiSortKey}Key`];
}
ngAfterViewInit() {
this.subscription.add(observe(this.dropTargets)
.subscribe(this.attachTargets.bind(this)));
}
ngDoCheck() {
this._leafColumns = columnsToRender(this.columns || []).filter(x => !isColumnGroupComponent(x));
}
ngOnChanges(changes) {
const sortChange = changes.sort;
if (sortChange && !sortChange.isFirstChange()) {
sortChange.currentValue.forEach(change => {
this.sortedFields[change.field] = true;
});
}
}
ngOnInit() {
this.subscription.add(this.contextService.localization.changes
.subscribe(() => this.cd.markForCheck()));
}
ngOnDestroy() {
if (this.targetSubscription) {
this.targetSubscription.unsubscribe();
}
if (this.popupService) {
this.popupService.destroy();
}
this.subscription.unsubscribe();
}
selectAllCheckboxId() {
return this.idService.selectAllCheckboxId();
}
get selectAllCheckboxLabel() {
return this.contextService.localization.get('selectAllCheckboxLabel');
}
isFirstOnRow(column, index) {
const isTailing = (c) => c &&
(this.columnsForLevel(c.level).indexOf(c) > 0 || isTailing(c.parent));
return index === 0 && !this.groups.length && !this.detailTemplate && isTailing(column.parent);
}
logicalColumnIndex(column) {
const index = column.leafIndex;
if (isPresent(index)) {
return index + (isPresent(this.detailTemplate) ? 1 : 0);
}
return -1;
}
get showFilterMenu() {
return !this.columnMenu && hasFilterMenu(this.filterable);
}
get showFilterRow() {
return hasFilterRow(this.filterable);
}
showColumnMenu(column) {
return this.columnMenu && column.columnMenu &&
(this.columnMenuTemplate || column.columnMenuTemplates.length || hasItems(this.columnMenu, column));
}
isFilterable(column) {
return !isNullOrEmptyString(column.field) && column.filterable === true;
}
canDrop(draggable, target) {
isDocumentAvailable() && this.zone.runOutsideAngular(() => {
document.addEventListener('pointerup', () => {
this.stopSorting = true;
setTimeout(() => this.stopSorting = false);
}, {
once: true,
capture: true
});
});
return this.reorderable && rules({ draggable, target });
}
shouldActivate(column) {
const canReorder = this.isReorderable(column);
if (!canReorder && !isColumnComponent(column)) {
return false;
}
const groupable = this.isGroupable(column);
return groupable || canReorder;
}
isInteractive(column, prop) {
return !isNullOrEmptyString(column.field)
&& isTruthy(this[prop]) && isTruthy(column[prop]);
}
isCheckboxColumn(column) {
return isCheckboxColumn(column) && !column.templateRef;
}
addStickyStyles(column) {
const stickyStyles = this.columnInfoService.stickyColumnsStyles(column);
return { ...column.headerStyle, ...stickyStyles };
}
toggleDirection(field, allowUnsort, initialDirection) {
const descriptor = this.sortDescriptor(field);
const [first, second] = directions(initialDirection);
let dir = first;
if (descriptor.dir === first) {
dir = second;
}
else if (descriptor.dir === second && allowUnsort) {
dir = undefined;
}
return { dir, field };
}
columnsForLevel(level) {
const columns = this.columns ? this.columns.filter(column => column.level === level) : [];
return sortColumns(columnsToRender(columns));
}
isColumnGroupComponent(column) {
return isColumnGroupComponent(column);
}
sortDescriptor(field) {
return this.sort.find(item => item.field === field) || { field };
}
get columnLevels() {
return new Array((this.totalColumnLevels || 0) + 1);
}
get leafColumns() {
return this._leafColumns;
}
isReorderable(column) {
return this.reorderable && column.reorderable;
}
isGroupable(column) {
return this.groupable && isColumnComponent(column) && column.groupable !== false;
}
attachTargets() {
if (this.targetSubscription) {
this.targetSubscription.unsubscribe();
}
this.targetSubscription = new Subscription();
const enterStream = merge(...this.dropTargets.map(target => target.enter));
const leaveStream = merge(...this.dropTargets.map(target => target.leave));
const dropStream = merge(...this.dropTargets.map(target => target.drop));
this.targetSubscription.add(enterStream.pipe(tap(({ target, draggable }) => {
if (draggable.context.type === 'groupIndicator') {
return;
}
const targetLocked = isTruthy(target.context.column.isLocked);
const draggableLocked = isTruthy(draggable.context.column.isLocked);
if (this.lockedColumnsCount > 0 || targetLocked || draggableLocked) {
this.hint.toggleLock(targetLocked);
}
}), filter(({ draggable, target }) => this.canDrop(draggable, target)), switchMap(this.trackMove.bind(this, leaveStream, dropStream)), map((e) => mergeObjects(e, { before: this.calculateBefore(e), changeContainer: e.changeContainer })), map(this.normalizeTarget.bind(this)), tap(this.enter.bind(this)), switchMap((args) => dropStream.pipe(map(() => args), takeUntil(leaveStream.pipe(tap(this.leave.bind(this)))))))
.subscribe(this.drop.bind(this)));
}
normalizeTarget(e) {
let target = e.target;
const parent = target.context.column.parent;
if (parent && parent.isSpanColumn) {
const arr = this.dropTargets.toArray();
const firstSpan = arr.find(t => t.context.column.parent === parent);
const index = arr.indexOf(firstSpan);
const adjust = e.before ? 0 : parent.childColumns.length - 1;
target = arr[index + adjust];
}
return mergeObjects(e, { target });
}
trackMove(leaveStream, dropStream, e) {
const column = e.target.context.column;
const levelColumns = this.columnsForLevel(column.level);
const index = levelColumns.indexOf(column);
const isFirst = (column.locked ? index === levelColumns.length - 1 : index === 0);
const changed = e.draggable.context.column.isLocked !== column.isLocked;
if (changed && isFirst) {
return e.draggable.drag
.pipe(takeUntil(leaveStream), takeUntil(dropStream), map(({ mouseEvent }) => mergeObjects({ changeContainer: true }, e, { mouseEvent })));
}
return of(mergeObjects({ changeContainer: changed }, e));
}
calculateBefore({ draggable, target, mouseEvent, changeContainer = false }) {
const targetElement = target.element.nativeElement;
let before = false;
if (changeContainer) {
const { left } = offset(targetElement);
const halfWidth = targetElement.offsetWidth / 2;
const middle = left + halfWidth;
before = middle > mouseEvent.pageX;
if (this.contextService.localization.rtl) {
before = !before;
}
}
else {
before = isTargetBefore(draggable.element.nativeElement, targetElement);
}
return before;
}
enter({ target, before }) {
this.hint.enable();
if (this.contextService.localization.rtl) {
before = !before;
}
this.cue.position(position(target.element.nativeElement, before));
}
leave() {
this.hint.disable();
this.cue.hide();
}
drop({ draggable, target, before, changeContainer }) {
this.reorderService.reorder({
before,
changeContainer,
source: draggable.context.column,
target: target.context.column
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeaderComponent, deps: [{ token: i1.SinglePopupService }, { token: i2.DragHintService }, { token: i3.DropCueService }, { token: i4.ColumnReorderService }, { token: i5.IdService }, { token: i6.SortService }, { token: i7.ColumnInfoService }, { token: i0.ChangeDetectorRef }, { token: i8.ContextService }, { token: i9.NavigationService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HeaderComponent, isStandalone: true, selector: "[kendoGridHeader]", inputs: { totalColumnLevels: "totalColumnLevels", columns: "columns", groups: "groups", detailTemplate: "detailTemplate", scrollable: "scrollable", filterable: "filterable", sort: "sort", filter: "filter", sortable: "sortable", groupable: "groupable", lockedColumnsCount: "lockedColumnsCount", resizable: "resizable", reorderable: "reorderable", columnMenu: "columnMenu", columnMenuTemplate: "columnMenuTemplate", totalColumnsCount: "totalColumnsCount", totalColumns: "totalColumns", tabIndex: "tabIndex", size: "size" }, host: { properties: { "class.k-table-thead": "this.hostClass" } }, viewQueries: [{ propertyName: "dropTargets", predicate: DropTargetDirective, descendants: true }, { propertyName: "filterMenus", predicate: FilterMenuComponent, descendants: true }, { propertyName: "columnMenus", predicate: ColumnMenuComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: `
<tr *ngFor="let i of columnLevels; let levelIndex = index"
kendoGridLogicalRow
[logicalRowIndex]="levelIndex"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount"
[totalColumns]="totalColumns">
<th
class="k-group-cell k-header k-table-th"
role="presentation"
*ngFor="let g of groups">
</th>
<th class="k-hierarchy-cell k-header k-table-th"
role="presentation"
*ngIf="detailTemplate?.templateRef"
>
</th>
<ng-container *ngFor="let column of columnsForLevel(levelIndex); let columnIndex = index; let last = last;">
<th *ngIf="!isColumnGroupComponent(column)"
kendoGridLogicalCell
[logicalRowIndex]="levelIndex"
[logicalColIndex]="logicalColumnIndex(column)"
[headerLabelText]="column.title || getColumnComponent(column).field"
[colSpan]="column.colspan"
[rowSpan]="column.rowspan(totalColumnLevels)"
role="columnheader"
aria-selected="false"
[attr.aria-sort]="sortState(getColumnComponent(column))"
[class.k-sorted]="sortState(getColumnComponent(column))"
(keydown)="onHeaderKeydown(getColumnComponent(column), $event)"
kendoDropTarget
kendoDraggable
kendoDraggableColumn
[enableDrag]="shouldActivate(column)"
[context]="{
field: getColumnComponent(column).field,
type: 'column',
column: column,
hint: column.title || getColumnComponent(column).field,
lastColumn: last && columnIndex === 0
}"
class="k-header k-table-th"
[class.k-filterable]="(showFilterMenu && isFilterable(getColumnComponent(column))) || showColumnMenu(column)"
[class.k-first]="isFirstOnRow(getColumnComponent(column), columnIndex)"
[class.k-grid-header-sticky]="column.sticky"
[ngClass]="column.headerClass"
[ngStyle]="column.sticky ? addStickyStyles(column) : column.headerStyle"
[attr.rowspan]="column.rowspan(totalColumnLevels)"
[attr.colspan]="column.colspan"
[attr.aria-haspopup]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? 'dialog' : undefined"
[attr.aria-expanded]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? false : undefined"
[attr.aria-keyshortcuts]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? 'Alt + ArrowDown' : undefined">
<ng-container *ngIf="!isInteractive(getColumnComponent(column), 'sortable')">
<span class="k-cell-inner">
<span class="k-link" [class.!k-cursor-default]="!isInteractive(getColumnComponent(column), 'groupable') && !isInteractive(getColumnComponent(column), 'reorderable')">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: column.leafIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef">
<span class="k-column-title">{{column.displayTitle}}</span>
</ng-container>
</span>
<kendo-grid-filter-menu
*ngIf="showFilterMenu && isFilterable(getColumnComponent(column))"
[column]="getColumnComponent(column)"
[filter]="filter"
[tabIndex]="tabIndex">
</kendo-grid-filter-menu>
<kendo-grid-column-menu *ngIf="showColumnMenu(column)"
[standalone]="false"
[settings]="columnMenuSettings"
[column]="column"
[columnMenuTemplate]="columnMenuTemplate"
[sort]="sort"
[filter]="filter"
[sortable]="sortable"
[tabIndex]="tabIndex">
</kendo-grid-column-menu>
</span>
</ng-container>
<ng-container *ngIf="isInteractive(getColumnComponent(column), 'sortable')">
<span class="k-cell-inner">
<span #link class="k-link" (click)="onSortClick(getColumnComponent(column), $event, link)">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: column.leafIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef">
<span class="k-column-title">{{column.displayTitle}}</span>
</ng-container>
<span [class.k-sort-icon]="sortDescriptor(getColumnComponent(column).field).dir">
<kendo-icon-wrapper
*ngIf="sortDescriptor(getColumnComponent(column).field).dir"
role="note" [attr.aria-label]="sortableLabel"
name="sort-{{sortDescriptor(getColumnComponent(column).field).dir}}-small"
[svgIcon]="sortDescriptor(getColumnComponent(column).field).dir === 'asc' ? sortAscSmallIcon : sortDescSmallIcon"
></kendo-icon-wrapper>
</span>
<span *ngIf="showSortNumbering(getColumnComponent(column))" class="k-sort-order">{{sortOrder(getColumnComponent(column).field)}}</span>
</span>
<kendo-grid-filter-menu
*ngIf="showFilterMenu && isFilterable(getColumnComponent(column))"
[column]="getColumnComponent(column)"
[filter]="filter"
[tabIndex]="tabIndex">
</kendo-grid-filter-menu>
<kendo-grid-column-menu *ngIf="showColumnMenu(column)"
[standalone]="false"
[settings]="columnMenuSettings"
[column]="column"
[columnMenuTemplate]="columnMenuTemplate"
[sort]="sort"
[filter]="filter"
[sortable]="sortable"
[tabIndex]="tabIndex">
</kendo-grid-column-menu>
</span>
</ng-container>
<ng-container *ngIf="isCheckboxColumn(column) && !column.headerTemplateRef && $any(column).showSelectAll">
<kendo-checkbox
[attr.id]="selectAllCheckboxId()"
[inputAttributes]="{'aria-label': selectAllCheckboxLabel}"
kendoGridSelectAllCheckbox
kendoGridFocusable
></kendo-checkbox>
</ng-container>
<span kendoGridColumnHandle
kendoDraggable
class="k-column-resizer"
*ngIf="resizable"
[isLast]="last"
[column]="column"
[columns]="columns">
</span>
</th>
<th *ngIf="isColumnGroupComponent(column)"
kendoGridLogicalCell
[logicalRowIndex]="levelIndex"
[logicalColIndex]="logicalColumnIndex(column)"
[rowSpan]="column.rowspan(totalColumnLevels)"
[colSpan]="column.colspan"
[headerLabelText]="column.title || getColumnComponent(column).field"
kendoDropTarget
kendoDraggable
kendoDraggableColumn
[enableDrag]="shouldActivate(column)"
[context]="{
type: 'columnGroup',
column: column,
hint: column.title,
lastColumn: last && columnIndex === 0
}"
class="k-header k-table-th"
[class.k-first]="isFirstOnRow(getColumnComponent(column), columnIndex)"
[class.k-filterable]="showColumnMenu(column)"
[class.k-grid-content-sticky]="column.sticky"
[ngClass]="column.headerClass"
[ngStyle]="column.headerStyle"
[attr.aria-haspopup]="(isNavigable && showColumnMenu(column)) ? 'dialog' : undefined"
[attr.aria-expanded]="(isNavigable && showColumnMenu(column)) ? false : undefined"
[attr.aria-keyshortcuts]="isNavigable && showColumnMenu(column) ? 'Alt + ArrowDown' : undefined"
[attr.rowspan]="column.rowspan(totalColumnLevels)"
[attr.colspan]="column.colspan">
<span class="k-cell-inner">
<span class="k-link" [class.!k-cursor-default]="!isInteractive(getColumnComponent(column), 'reorderable')">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: lockedColumnsCount + columnIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef">
<span class="k-column-title">{{column.displayTitle}}</span>
</ng-container>
</span>
<kendo-grid-column-menu *ngIf="showColumnMenu(column)"
[standalone]="false"
[settings]="columnMenuSettings"
[column]="column"
[columnMenuTemplate]="columnMenuTemplate">
</kendo-grid-column-menu>
</span>
<span kendoGridColumnHandle
kendoDraggable
class="k-column-resizer"
*ngIf="resizable"
[isLast]="last"
[column]="column"
[columns]="columns">
</span>
</th>
</ng-container>
</tr>
<tr *ngIf="showFilterRow"
kendoGridFilterRow
[columns]="leafColumns"
[filter]="filter"
[groups]="groups"
[detailTemplate]="detailTemplate"
[lockedColumnsCount]="lockedColumnsCount"
kendoGridLogicalRow
[logicalRowIndex]="totalColumnLevels + 1"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount"
[totalColumns]="totalColumns"></tr>
`, isInline: true, dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: LogicalRowDirective, selector: "[kendoGridLogicalRow]", inputs: ["logicalRowIndex", "logicalSlaveRow", "logicalCellsCount", "logicalSlaveCellsCount", "dataRowIndex", "dataItem", "totalColumns"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: LogicalCellDirective, selector: "[kendoGridLogicalCell]", inputs: ["logicalColIndex", "logicalRowIndex", "logicalSlaveCell", "colIndex", "colSpan", "rowSpan", "groupItem", "dataRowIndex", "dataItem", "detailExpandCell", "headerLabelText"] }, { kind: "directive", type: DropTargetDirective, selector: "[kendoDropTarget]", inputs: ["context"], outputs: ["enter", "leave", "drop"] }, { kind: "directive", type: DraggableDirective, selector: "[kendoDraggable]", inputs: ["enableDrag"], outputs: ["kendoPress", "kendoDrag", "kendoRelease"] }, { kind: "directive", type: DraggableColumnDirective, selector: "[kendoDraggableColumn]", inputs: ["context", "enableDrag"], outputs: ["drag"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TemplateContextDirective, selector: "[templateContext]", inputs: ["templateContext"] }, { kind: "component", type: FilterMenuComponent, selector: "kendo-grid-filter-menu", inputs: ["column", "filter", "tabIndex"] }, { kind: "component", type: ColumnMenuComponent, selector: "kendo-grid-column-menu", inputs: ["standalone", "column", "settings", "sort", "filter", "sortable", "columnMenuTemplate", "tabIndex"] }, { kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "directive", type: SelectAllCheckboxDirective, selector: "[kendoGridSelectAllCheckbox]", inputs: ["state"], outputs: ["selectAllChange"] }, { kind: "directive", type: FocusableDirective, selector: "[kendoGridFocusable],\n [kendoGridEditCommand],\n [kendoGridRemoveCommand],\n [kendoGridSaveCommand],\n [kendoGridCancelCommand],\n [kendoGridSelectionCheckbox]\n ", inputs: ["kendoGridFocusable"] }, { kind: "directive", type: ColumnHandleDirective, selector: "[kendoGridColumnHandle]", inputs: ["isLast", "columns", "column"] }, { kind: "component", type: FilterRowComponent, selector: "[kendoGridFilterRow]", inputs: ["columns", "filter", "groups", "detailTemplate", "logicalRowIndex", "lockedColumnsCount"] }, { kind: "component", type: CheckBoxComponent, selector: "kendo-checkbox", inputs: ["checkedState", "rounded"], outputs: ["checkedStateChange"], exportAs: ["kendoCheckBox"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HeaderComponent, decorators: [{
type: Component,
args: [{
selector: '[kendoGridHeader]',
template: `
<tr *ngFor="let i of columnLevels; let levelIndex = index"
kendoGridLogicalRow
[logicalRowIndex]="levelIndex"
[logicalSlaveRow]="lockedColumnsCount > 0"
[logicalCellsCount]="columns.length"
[logicalSlaveCellsCount]="unlockedColumnsCount"
[totalColumns]="totalColumns">
<th
class="k-group-cell k-header k-table-th"
role="presentation"
*ngFor="let g of groups">
</th>
<th class="k-hierarchy-cell k-header k-table-th"
role="presentation"
*ngIf="detailTemplate?.templateRef"
>
</th>
<ng-container *ngFor="let column of columnsForLevel(levelIndex); let columnIndex = index; let last = last;">
<th *ngIf="!isColumnGroupComponent(column)"
kendoGridLogicalCell
[logicalRowIndex]="levelIndex"
[logicalColIndex]="logicalColumnIndex(column)"
[headerLabelText]="column.title || getColumnComponent(column).field"
[colSpan]="column.colspan"
[rowSpan]="column.rowspan(totalColumnLevels)"
role="columnheader"
aria-selected="false"
[attr.aria-sort]="sortState(getColumnComponent(column))"
[class.k-sorted]="sortState(getColumnComponent(column))"
(keydown)="onHeaderKeydown(getColumnComponent(column), $event)"
kendoDropTarget
kendoDraggable
kendoDraggableColumn
[enableDrag]="shouldActivate(column)"
[context]="{
field: getColumnComponent(column).field,
type: 'column',
column: column,
hint: column.title || getColumnComponent(column).field,
lastColumn: last && columnIndex === 0
}"
class="k-header k-table-th"
[class.k-filterable]="(showFilterMenu && isFilterable(getColumnComponent(column))) || showColumnMenu(column)"
[class.k-first]="isFirstOnRow(getColumnComponent(column), columnIndex)"
[class.k-grid-header-sticky]="column.sticky"
[ngClass]="column.headerClass"
[ngStyle]="column.sticky ? addStickyStyles(column) : column.headerStyle"
[attr.rowspan]="column.rowspan(totalColumnLevels)"
[attr.colspan]="column.colspan"
[attr.aria-haspopup]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? 'dialog' : undefined"
[attr.aria-expanded]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? false : undefined"
[attr.aria-keyshortcuts]="isNavigable && (showFilterMenu || showColumnMenu(column)) ? 'Alt + ArrowDown' : undefined">
<ng-container *ngIf="!isInteractive(getColumnComponent(column), 'sortable')">
<span class="k-cell-inner">
<span class="k-link" [class.!k-cursor-default]="!isInteractive(getColumnComponent(column), 'groupable') && !isInteractive(getColumnComponent(column), 'reorderable')">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: column.leafIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef">
<span class="k-column-title">{{column.displayTitle}}</span>
</ng-container>
</span>
<kendo-grid-filter-menu
*ngIf="showFilterMenu && isFilterable(getColumnComponent(column))"
[column]="getColumnComponent(column)"
[filter]="filter"
[tabIndex]="tabIndex">
</kendo-grid-filter-menu>
<kendo-grid-column-menu *ngIf="showColumnMenu(column)"
[standalone]="false"
[settings]="columnMenuSettings"
[column]="column"
[columnMenuTemplate]="columnMenuTemplate"
[sort]="sort"
[filter]="filter"
[sortable]="sortable"
[tabIndex]="tabIndex">
</kendo-grid-column-menu>
</span>
</ng-container>
<ng-container *ngIf="isInteractive(getColumnComponent(column), 'sortable')">
<span class="k-cell-inner">
<span #link class="k-link" (click)="onSortClick(getColumnComponent(column), $event, link)">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: column.leafIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef">
<span class="k-column-title">{{column.displayTitle}}</span>
</ng-container>
<span [class.k-sort-icon]="sortDescriptor(getColumnComponent(column).field).dir">
<kendo-icon-wrapper
*ngIf="sortDescriptor(getColumnComponent(column).field).dir"
role="note" [attr.aria-label]="sortableLabel"
name="sort-{{sortDescriptor(getColumnComponent(column).field).dir}}-small"
[svgIcon]="sortDescriptor(getColumnComponent(column).field).dir === 'asc' ? sortAscSmallIcon : sortDescSmallIcon"
></kendo-icon-wrapper>
</span>
<span *ngIf="showSortNumbering(getColumnComponent(column))" class="k-sort-order">{{sortOrder(getColumnComponent(column).field)}}</span>
</span>
<kendo-grid-filter-menu
*ngIf="showFilterMenu && isFilterable(getColumnComponent(column))"
[column]="getColumnComponent(column)"
[filter]="filter"
[tabIndex]="tabIndex">
</kendo-grid-filter-menu>
<kendo-grid-column-menu *ngIf="showColumnMenu(column)"
[standalone]="false"
[settings]="columnMenuSettings"
[column]="column"
[columnMenuTemplate]="columnMenuTemplate"
[sort]="sort"
[filter]="filter"
[sortable]="sortable"
[tabIndex]="tabIndex">
</kendo-grid-column-menu>
</span>
</ng-container>
<ng-container *ngIf="isCheckboxColumn(column) && !column.headerTemplateRef && $any(column).showSelectAll">
<kendo-checkbox
[attr.id]="selectAllCheckboxId()"
[inputAttributes]="{'aria-label': selectAllCheckboxLabel}"
kendoGridSelectAllCheckbox
kendoGridFocusable
></kendo-checkbox>
</ng-container>
<span kendoGridColumnHandle
kendoDraggable
class="k-column-resizer"
*ngIf="resizable"
[isLast]="last"
[column]="column"
[columns]="columns">
</span>
</th>
<th *ngIf="isColumnGroupComponent(column)"
kendoGridLogicalCell
[logicalRowIndex]="levelIndex"
[logicalColIndex]="logicalColumnIndex(column)"
[rowSpan]="column.rowspan(totalColumnLevels)"
[colSpan]="column.colspan"
[headerLabelText]="column.title || getColumnComponent(column).field"
kendoDropTarget
kendoDraggable
kendoDraggableColumn
[enableDrag]="shouldActivate(column)"
[context]="{
type: 'columnGroup',
column: column,
hint: column.title,
lastColumn: last && columnIndex === 0
}"
class="k-header k-table-th"
[class.k-first]="isFirstOnRow(getColumnComponent(column), columnIndex)"
[class.k-filterable]="showColumnMenu(column)"
[class.k-grid-content-sticky]="column.sticky"
[ngClass]="column.headerClass"
[ngStyle]="column.headerStyle"
[attr.aria-haspopup]="(isNavigable && showColumnMenu(column)) ? 'dialog' : undefined"
[attr.aria-expanded]="(isNavigable && showColumnMenu(column)) ? false : undefined"
[attr.aria-keyshortcuts]="isNavigable && showColumnMenu(column) ? 'Alt + ArrowDown' : undefined"
[attr.rowspan]="column.rowspan(totalColumnLevels)"
[attr.colspan]="column.colspan">
<span class="k-cell-inner">
<span class="k-link" [class.!k-cursor-default]="!isInteractive(getColumnComponent(column), 'reorderable')">
<ng-template
[templateContext]="{
templateRef: column.headerTemplateRef,
columnIndex: lockedColumnsCount + columnIndex,
column: column,
$implicit: column
}">
</ng-template>
<ng-container *ngIf="!column.headerTemplateRef