UNPKG

@progress/kendo-angular-grid

Version:

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

150 lines (149 loc) 5.9 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { PopupService } from '@progress/kendo-angular-popup'; import { Injectable, Renderer2, NgZone } from '@angular/core'; import { isPresent } from '../utils'; import { PreventableEvent } from './preventable-event'; import { Subject, Subscription } from 'rxjs'; import { ScrollSyncService } from '../scrolling/scroll-sync.service'; import { isDocumentAvailable } from '@progress/kendo-angular-common'; import { ContextService } from './provider.service'; import { skip } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-popup"; import * as i2 from "../scrolling/scroll-sync.service"; import * as i3 from "./provider.service"; const contains = (node, predicate) => { while (node) { if (predicate(node)) { return true; } node = node.parentNode; } return false; }; /** * Arguments for the `close` event of the filter and column-menu popup. */ export class PopupCloseEvent extends PreventableEvent { /** * The original DOM event that causes the popup to close. */ originalEvent; constructor(e) { super(); this.originalEvent = e; } } const DEFAULT_POPUP_CLASS = 'k-grid-filter-popup'; /** * The service that is used for the popups of the filter and column menus * ([see example]({% slug filter_menu %}#toc-filter-menu-with-popup)). */ export class SinglePopupService { popupService; renderer; ngZone; ctx; /** * Fires when the filter or column menus are about to close because the user clicked outside their popups. * Used to prevent the popup from closing. */ onClose = new Subject(); removeClick; pointerEventsSub = new Subscription(); popupRef; scrollSubscription; canClosePopup = true; /** * @hidden */ constructor(popupService, renderer, ngZone, scrollSyncService, ctx) { this.popupService = popupService; this.renderer = renderer; this.ngZone = ngZone; this.ctx = ctx; this.scrollSubscription = scrollSyncService.changes.pipe(skip(1)).subscribe(() => this.destroy()); } /** * @hidden */ open(anchor, template, popupRef, popupClass = DEFAULT_POPUP_CLASS) { const toggle = isPresent(popupRef) && this.popupRef === popupRef; this.destroy(); if (!toggle) { const direction = this.ctx.localization.rtl ? 'right' : 'left'; this.popupRef = this.popupService.open({ anchorAlign: { vertical: 'bottom', horizontal: direction }, popupAlign: { vertical: 'top', horizontal: direction }, anchor: anchor, popupClass: popupClass, content: template, positionMode: "absolute" }); this.renderer.setAttribute(this.popupRef.popupElement, 'dir', this.ctx.localization.rtl ? 'rtl' : 'ltr'); this.attachClose(anchor); } const popupEl = this.popupRef?.popupElement; if (popupEl) { this.attachMouseListeners(popupEl); } return this.popupRef; } /** * @hidden */ destroy() { if (this.popupRef) { this.detachClose(); this.pointerEventsSub.unsubscribe(); this.pointerEventsSub = null; this.popupRef.close(); this.popupRef = null; } } ngOnDestroy() { this.destroy(); this.scrollSubscription.unsubscribe(); } detachClose() { if (this.removeClick) { this.removeClick(); } } attachClose(skipElement) { if (!isDocumentAvailable()) { return; } this.detachClose(); this.ngZone.runOutsideAngular(() => this.removeClick = this.renderer.listen('document', 'click', (e) => { if (!contains(e.target, x => this.popupRef.popupElement === x || x === skipElement)) { const args = new PopupCloseEvent(e); this.onClose.next(args); if (!args.isDefaultPrevented() && this.canClosePopup) { this.destroy(); } this.canClosePopup = true; } })); } attachMouseListeners(el) { this.pointerEventsSub = new Subscription(); this.ngZone.runOutsideAngular(() => { this.pointerEventsSub.add(this.renderer.listen(el, 'pointerdown', (e) => { e.stopImmediatePropagation(); this.canClosePopup = false; })); this.pointerEventsSub.add(this.renderer.listen(el, 'pointerup', () => { this.canClosePopup = true; })); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SinglePopupService, deps: [{ token: i1.PopupService }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i2.ScrollSyncService }, { token: i3.ContextService }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SinglePopupService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SinglePopupService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.PopupService }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i2.ScrollSyncService }, { type: i3.ContextService }]; } });