UNPKG

@progress/kendo-angular-grid

Version:

Kendo UI Grid for Angular - high performance data grid with paging, filtering, virtualization, CRUD, and more.

203 lines (202 loc) 9.55 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { NavigationService } from './../../navigation/navigation.service'; import { ChangeDetectorRef, Component, ElementRef, Input, Optional, Renderer2, TemplateRef, ViewChild } from '@angular/core'; import { FilterService } from "../filter.service"; import { ColumnComponent } from '../../columns/column.component'; import { SinglePopupService } from '../../common/single-popup.service'; import { filtersByField } from '../base-filter-cell.component'; import { replaceMessagePlaceholder } from '../../utils'; import { filterIcon } from '@progress/kendo-svg-icons'; import { ContextService } from '../../common/provider.service'; import { IdService } from '../../common/id.service'; import { FilterMenuContainerComponent } from './filter-menu-container.component'; import { IconWrapperComponent } from '@progress/kendo-angular-icons'; import * as i0 from "@angular/core"; import * as i1 from "../filter.service"; import * as i2 from "../../common/single-popup.service"; import * as i3 from "../../common/provider.service"; import * as i4 from "./../../navigation/navigation.service"; import * as i5 from "../../common/id.service"; let id = 0; const getId = (gridId) => `${gridId}-filter-menu-${id++}`; /** * @hidden */ export class FilterMenuComponent { filterService; popupService; ctx; navigationService; renderer; cdr; idService; filterIcon = filterIcon; /** * The column with which the filter is associated. * @type {ColumnComponent} */ column; /** * The current root filter. * @type {CompositeFilterDescriptor} */ filter; anchor; template; tabIndex = '-1'; popupRef; popupSubs; constructor(filterService, popupService, ctx, navigationService, renderer, cdr, idService) { this.filterService = filterService; this.popupService = popupService; this.ctx = ctx; this.navigationService = navigationService; this.renderer = renderer; this.cdr = cdr; this.idService = idService; } ngOnDestroy() { this.cleanUp(); } get hasFilters() { return filtersByField(this.filter, (this.column || {}).field).length > 0; } /** * @hidden */ get filterLabel() { const localizationMsg = this.ctx.localization.get('filterMenuTitle') || ''; const columnName = this.column.title || this.column.field; return replaceMessagePlaceholder(localizationMsg, 'columnName', columnName); } /** * @hidden */ get isNavigable() { return this.navigationService.tableEnabled; } toggle(anchor, template) { this.popupRef = this.popupService.open(anchor, template, this.popupRef); // Needed as changes to 'popupRef' are not reflected // automatically when the Popup is closed by clicking outside the anchor const ariaRoot = this.isNavigable ? anchor.closest('.k-table-th') : anchor; if (this.popupRef) { this.popupSubs?.unsubscribe(); this.popupSubs = this.popupRef.popup.instance.anchorViewportLeave.subscribe(() => { this.close(); this.updateAria(ariaRoot); }); this.popupSubs.add(() => this.popupRef.popup.instance.close.subscribe(() => { this.popupRef = null; this.updateAria(ariaRoot); })); const popupAriaElement = this.popupRef.popupElement.querySelector('.k-grid-filter-popup'); if (popupAriaElement) { const popupId = getId(this.idService?.gridId()); this.renderer.setAttribute(popupAriaElement, 'id', popupId); this.renderer.setAttribute(popupAriaElement, 'role', 'dialog'); this.renderer.setAttribute(popupAriaElement, 'aria-label', this.filterLabel); ariaRoot && this.renderer.setAttribute(ariaRoot, 'aria-controls', popupId); ariaRoot && this.renderer.setAttribute(ariaRoot, 'aria-expanded', 'true'); } } else { this.focusRoot(); } return false; } close() { this.cleanUp(); this.focusRoot(); } updateAria(ariaRoot) { ariaRoot && this.renderer.removeAttribute(ariaRoot, 'aria-controls'); ariaRoot && this.renderer.setAttribute(ariaRoot, 'aria-expanded', 'false'); } cleanUp() { this.popupService.destroy(); this.popupRef = null; this.popupSubs?.unsubscribe(); this.popupSubs = null; this.cdr.markForCheck(); } focusRoot() { this.isNavigable ? this.navigationService.focusCell(0, this.column.leafIndex) : this.anchor.nativeElement.focus(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterMenuComponent, deps: [{ token: i1.FilterService }, { token: i2.SinglePopupService }, { token: i3.ContextService }, { token: i4.NavigationService }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i5.IdService, optional: true }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: FilterMenuComponent, isStandalone: true, selector: "kendo-grid-filter-menu", inputs: { column: "column", filter: "filter", tabIndex: "tabIndex" }, viewQueries: [{ propertyName: "anchor", first: true, predicate: ["anchor"], descendants: true, static: true }, { propertyName: "template", first: true, predicate: ["template"], descendants: true, read: TemplateRef, static: true }], ngImport: i0, template: ` <a #anchor class="k-grid-filter-menu k-grid-header-menu" [class.k-active]="hasFilters" [tabindex]="tabIndex" (click)="toggle(anchor, template)" (keydown.enter)="$event.stopImmediatePropagation()" href="#" [attr.title]="filterLabel" [attr.aria-haspopup]="isNavigable ? undefined : 'dialog'" [attr.aria-expanded]="isNavigable ? undefined : false"> <kendo-icon-wrapper name="filter" [svgIcon]="filterIcon"></kendo-icon-wrapper> </a> <ng-template #template> <kendo-grid-filter-menu-container [column]="column" [filter]="filter" (close)="close()" (keydown.escape)="close()" (keydown.enter)="$event.stopImmediatePropagation()"> </kendo-grid-filter-menu-container> </ng-template> `, isInline: true, dependencies: [{ kind: "component", type: IconWrapperComponent, selector: "kendo-icon-wrapper", inputs: ["name", "svgIcon", "innerCssClass", "customFontClass", "size"], exportAs: ["kendoIconWrapper"] }, { kind: "component", type: FilterMenuContainerComponent, selector: "kendo-grid-filter-menu-container", inputs: ["column", "isLast", "isExpanded", "menuTabbingService", "filter", "actionsClass"], outputs: ["close"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FilterMenuComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-grid-filter-menu', template: ` <a #anchor class="k-grid-filter-menu k-grid-header-menu" [class.k-active]="hasFilters" [tabindex]="tabIndex" (click)="toggle(anchor, template)" (keydown.enter)="$event.stopImmediatePropagation()" href="#" [attr.title]="filterLabel" [attr.aria-haspopup]="isNavigable ? undefined : 'dialog'" [attr.aria-expanded]="isNavigable ? undefined : false"> <kendo-icon-wrapper name="filter" [svgIcon]="filterIcon"></kendo-icon-wrapper> </a> <ng-template #template> <kendo-grid-filter-menu-container [column]="column" [filter]="filter" (close)="close()" (keydown.escape)="close()" (keydown.enter)="$event.stopImmediatePropagation()"> </kendo-grid-filter-menu-container> </ng-template> `, standalone: true, imports: [IconWrapperComponent, FilterMenuContainerComponent] }] }], ctorParameters: function () { return [{ type: i1.FilterService }, { type: i2.SinglePopupService }, { type: i3.ContextService }, { type: i4.NavigationService }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i5.IdService, decorators: [{ type: Optional }] }]; }, propDecorators: { column: [{ type: Input }], filter: [{ type: Input }], anchor: [{ type: ViewChild, args: ['anchor', { static: true }] }], template: [{ type: ViewChild, args: ['template', { static: true, read: TemplateRef }] }], tabIndex: [{ type: Input }] } });