@progress/kendo-angular-grid
Version:
Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.
219 lines (218 loc) • 9.19 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 { Directive, ElementRef, HostBinding, Inject, Input, NgZone, Optional, Renderer2 } from '@angular/core';
import { FocusGroup } from './focus-group';
import { FocusRoot } from './focus-root';
import { NavigationService } from './navigation.service';
import { ColumnInfoService } from '../common/column-info.service';
import { IdService } from '../common/id.service';
import { CELL_CONTEXT } from '../rendering/common/cell-context';
import * as i0 from "@angular/core";
import * as i1 from "./focus-group";
import * as i2 from "../common/column-info.service";
import * as i3 from "../common/id.service";
import * as i4 from "./navigation.service";
let id = 0;
function nextId() {
return id++;
}
/**
* @hidden
*/
export class LogicalCellDirective {
focusGroup;
element;
columnInfoService;
idService;
navigationService;
renderer;
zone;
cellContext;
logicalColIndex;
logicalRowIndex;
logicalSlaveCell = false;
colIndex;
colSpan = 1;
rowSpan = 1;
groupItem;
dataRowIndex = -1;
dataItem;
detailExpandCell = false;
headerLabelText;
uid = nextId();
get id() {
if (!this.logicalSlaveCell && this.columnInfoService.isLocked) {
return this.idService.cellId(this.logicalRowIndex, this.logicalColIndex);
}
}
get cellRowspan() {
return String(this.rowSpan);
}
get rowspanClass() {
return this.dataRowIndex > -1 && this.rowSpan > 1;
}
get ariaColIndex() {
if (this.logicalSlaveCell || this.logicalColIndex === -1) {
return undefined;
}
return this.logicalColIndex + 1;
}
navigationChange;
constructor(focusGroup, element, columnInfoService, idService, navigationService, renderer, zone, cellContext) {
this.focusGroup = focusGroup;
this.element = element;
this.columnInfoService = columnInfoService;
this.idService = idService;
this.navigationService = navigationService;
this.renderer = renderer;
this.zone = zone;
this.cellContext = cellContext;
}
ngOnInit() {
if (!this.navigationService.tableEnabled) {
return;
}
this.navigationChange = this.navigationService.changes.subscribe((e) => this.onNavigationChange(e));
}
ngDoCheck() {
if (!this.navigationService.tableEnabled || this.logicalColIndex === -1) {
return;
}
if (this.cellContext) {
this.cellContext.focusGroup = this.focusGroup;
}
this.registerNoChanges();
}
ngOnChanges(changes) {
if (!this.navigationService.tableEnabled) {
return;
}
const keys = Object.keys(changes);
if ((keys.length === 1 && keys[0] === 'groupItem') || this.logicalColIndex === -1) {
// Ignore groupItem changes as the reference is not stable
return;
}
const indexChange = changes['logicalColIndex'];
const rowIndexChange = changes['logicalRowIndex'];
const index = indexChange && !indexChange.isFirstChange() ? indexChange.previousValue : this.logicalColIndex;
const rowIndex = rowIndexChange && !rowIndexChange.isFirstChange() ? rowIndexChange.previousValue : this.logicalRowIndex;
this.navigationService.unregisterCell(index, rowIndex, this);
this.registerChanges();
this.updateElement();
}
ngOnDestroy() {
if (this.navigationChange) {
this.navigationChange.unsubscribe();
}
this.navigationService.unregisterCell(this.logicalColIndex, this.logicalRowIndex, this);
}
onNavigationChange(e) {
const active = this.logicalColIndex === e.colIndex && this.logicalRowIndex === e.rowIndex;
const wasActive = this.logicalColIndex === e.prevColIndex && this.logicalRowIndex === e.prevRowIndex;
if (active || wasActive) {
this.updateElement();
}
}
updateElement() {
const el = this.element.nativeElement;
this.renderer.setAttribute(el, 'tabIndex', this.isFocusable() && !this.logicalSlaveCell ? '0' : '-1');
if (this.isFocused()) {
if (this.focusGroup.isNavigable()) {
this.focusGroup.focus();
}
else {
if (!this.logicalSlaveCell && this.navigationService.autoFocusCell(this.logicalColIndex, this.logicalColIndex + this.colSpan - 1)) {
this.microtask(() => this.isFocused() && el.focus());
}
this.renderer.addClass(el, 'k-focus');
}
if (this.headerLabelText) {
el.removeAttribute('aria-label');
}
}
else {
this.renderer.removeClass(el, 'k-focus');
if (this.headerLabelText) {
el.setAttribute('aria-label', this.headerLabelText);
}
}
}
microtask(callback) {
this.zone.runOutsideAngular(() => Promise.resolve(null).then(callback));
}
registerChanges() {
if (!this.logicalSlaveCell) {
this.navigationService.registerCell(this);
}
}
registerNoChanges() {
if (!this.logicalSlaveCell) {
this.navigationService.registerCellOnCurrentRow(this);
}
}
isFocusable() {
return this.navigationService.isCellFocusable(this);
}
isFocused() {
return this.navigationService.isCellFocused(this);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LogicalCellDirective, deps: [{ token: i1.FocusGroup }, { token: i0.ElementRef }, { token: i2.ColumnInfoService }, { token: i3.IdService }, { token: i4.NavigationService }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: CELL_CONTEXT, optional: true }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: LogicalCellDirective, isStandalone: true, selector: "[kendoGridLogicalCell]", inputs: { logicalColIndex: "logicalColIndex", logicalRowIndex: "logicalRowIndex", logicalSlaveCell: "logicalSlaveCell", colIndex: "colIndex", colSpan: "colSpan", rowSpan: "rowSpan", groupItem: "groupItem", dataRowIndex: "dataRowIndex", dataItem: "dataItem", detailExpandCell: "detailExpandCell", headerLabelText: "headerLabelText" }, host: { properties: { "attr.id": "this.id", "attr.rowspan": "this.cellRowspan", "class.k-table-td-row-span": "this.rowspanClass", "attr.aria-colindex": "this.ariaColIndex" } }, providers: [{
provide: FocusGroup,
deps: [FocusRoot],
useClass: FocusGroup
}], usesOnChanges: true, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: LogicalCellDirective, decorators: [{
type: Directive,
args: [{
providers: [{
provide: FocusGroup,
deps: [FocusRoot],
useClass: FocusGroup
}],
selector: '[kendoGridLogicalCell]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i1.FocusGroup }, { type: i0.ElementRef }, { type: i2.ColumnInfoService }, { type: i3.IdService }, { type: i4.NavigationService }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: undefined, decorators: [{
type: Optional
}, {
type: Inject,
args: [CELL_CONTEXT]
}] }]; }, propDecorators: { logicalColIndex: [{
type: Input
}], logicalRowIndex: [{
type: Input
}], logicalSlaveCell: [{
type: Input
}], colIndex: [{
type: Input
}], colSpan: [{
type: Input
}], rowSpan: [{
type: Input
}], groupItem: [{
type: Input
}], dataRowIndex: [{
type: Input
}], dataItem: [{
type: Input
}], detailExpandCell: [{
type: Input
}], headerLabelText: [{
type: Input
}], id: [{
type: HostBinding,
args: ['attr.id']
}], cellRowspan: [{
type: HostBinding,
args: ['attr.rowspan']
}], rowspanClass: [{
type: HostBinding,
args: ['class.k-table-td-row-span']
}], ariaColIndex: [{
type: HostBinding,
args: ['attr.aria-colindex']
}] } });