UNPKG

@progress/kendo-angular-pager

Version:
1,001 lines (978 loc) 46.4 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Component, Input, EventEmitter, Output, HostBinding, ElementRef, Renderer2, NgZone, HostListener, ContentChildren, QueryList, Optional, SkipSelf, inject, ViewChild, ChangeDetectorRef } from '@angular/core'; import { PagerTemplateDirective } from "./pager-template.directive"; import { anyChanged, isChanged, isDocumentAvailable, Keys, normalizeNumpadKeys, replaceMessagePlaceholder, ResizeSensorComponent } from "@progress/kendo-angular-common"; import { PagerContextService } from "./pager-context.service"; import { Subscription } from "rxjs"; import { DEFAULT_PAGE_SIZE_VALUES, getStylingClasses, DEFAULT_SIZE, calculatePadding, createMeasurementSpan, copyComputedStyles, positionOffScreen, getAllFocusableChildren } from '../util'; import { L10N_PREFIX, LocalizationService } from '@progress/kendo-angular-l10n'; import { validatePackage } from '@progress/kendo-licensing'; import { packageMetadata } from '../package-metadata'; import { PagerNavigationService } from './navigation.service'; import { PagerNumericButtonsComponent } from './pager-numeric-buttons.component'; import { PagerInfoComponent } from './pager-info.component'; import { PagerPageSizesComponent } from './pager-page-sizes.component'; import { PagerNextButtonsComponent } from './pager-next-buttons.component'; import { PagerInputComponent } from './pager-input.component'; import { PagerPrevButtonsComponent } from './pager-prev-buttons.component'; import { NgIf, NgStyle, NgTemplateOutlet } from '@angular/common'; import { LocalizedMessagesDirective } from './localization/localized-messages.directive'; import { take } from 'rxjs/operators'; import * as i0 from "@angular/core"; import * as i1 from "./pager-context.service"; import * as i2 from "@progress/kendo-angular-l10n"; import * as i3 from "./navigation.service"; /** * Represents the Kendo UI Pager component for Angular. * Enables you to split a set of data into pages, providing a flexible and intuitive UI. * * @example * ```ts * @Component({ * selector: 'my-app', * template: ` * <kendo-pager * [total]="total" * [skip]="skip" * [pageSize]="pageSize" * (pageChange)="onPageChange($event)"> * </kendo-pager> * ` * }) * export class AppComponent { * public total = 200; * public skip = 0; * public pageSize = 10; * * public onPageChange(event: PageChangeEvent) { * this.skip = event.skip; * } * } * ``` * * @remarks * Supported children components are: * {@link PagerNumericButtonsComponent}, * {@link PagerInputComponent}, * {@link PagerPageSizesComponent}, * {@link PagerSpacerComponent}, * {@link PagerPrevButtonsComponent}, * {@link PagerNextButtonsComponent}, * {@link PagerInfoComponent}, * {@link CustomMessagesComponent} */ export class PagerComponent { pagerContext; element; localization; renderer; ngZone; cdr; navigationService; /** * Represents the collection of pager template directives. */ template; set numericButtons(buttons) { const newWidth = buttons ? buttons.nativeElement?.offsetWidth : 0; if (buttons && newWidth !== this.pagerDimensions.numericButtonsWidth) { this.pagerDimensions.numericButtonsWidth = newWidth; } } set pagerInput(input) { const newWidth = input ? input.nativeElement?.offsetWidth : 0; if (input && newWidth !== this.pagerDimensions.inputWidth) { this.pagerDimensions.inputWidth = newWidth; } } pagerInputComponent; set pageSizes(sizes) { const newWidth = sizes ? sizes.nativeElement?.offsetWidth : 0; if (sizes && newWidth !== this.pagerDimensions.pageSizesWidth) { this.pagerDimensions.pageSizesWidth = newWidth; } } pageSizesComponent; /** * @hidden */ externalTemplate; /** * Specifies the total number of data items in the collection. * * @default 0 */ total = 0; /** * Specifies the number of data items to skip. * * @default 0 */ skip = 0; /** * Specifies the number of data items per page. */ pageSize; /** * Specifies the maximum number of numeric buttons before the buttons are collapsed. * * @default 10 */ buttonCount = 10; /** * Determines whether to display information about the current page and the total number of records. * * @default true */ info = true; /** * Specifies the type of the Pager. * * @default 'numeric' */ type = 'numeric'; /** * Displays a dropdown for selecting the page size. * When set to `true`, the dropdown contains the default list of options - 5, 10, 20. * To customize the list of options, set `pageSizeValues` to an array of the desired values. * The array can contain numbers and [PageSizeItem]({% slug api_pager_pagesizeitem %}) objects. */ set pageSizeValues(value) { if (typeof value === 'boolean') { this._pageSizeValues = value ? DEFAULT_PAGE_SIZE_VALUES : []; } else { this._pageSizeValues = value; } } get pageSizeValues() { return this._pageSizeValues; } /** * Determines whether to display the **Previous** and **Next** buttons. * * @default true */ previousNext = true; /** * Determines whether users can use dedicated shortcuts to interact with the Pager ([see example]({% slug keyboard_navigation_pager %})). * By default, navigation is enabled. To disable it and make the Pager content accessible in the normal tab sequence, set the property to `false`. * @default true */ set navigable(value) { this._navigable = value; this.navigationService.isNavigable = value; } get navigable() { return this._navigable; } /** * Specifies the padding of all Pager elements. * * @default 'medium' */ set size(size) { const newSize = size ? size : DEFAULT_SIZE; this.handleClasses(newSize, 'size'); this._size = newSize; } get size() { return this._size; } /** * Determines whether the Pager responsive functionality is enabled ([see example](slug:responsive_pager)). * * @default true */ responsive = true; /** * Determines whether the Pager adaptiveness functionality is enabled ([see example](slug:adaptive_mode_pager)). * * @default 'auto' */ adaptiveMode = 'auto'; /** * Fires when the current page of the Pager changes ([see example](slug:overview_pager)). * You have to handle the event and page the data. */ pageChange = new EventEmitter(); /** * Fires when the page size of the Pager changes. * You have to handle the event and page the data. * If the event is prevented, the page size remains unchanged ([see example]({% slug pager_events %})). */ pageSizeChange = new EventEmitter(); /** * @hidden */ pagerInputVisibilityChange = new EventEmitter(); /** * @hidden */ pageTextVisibilityChange = new EventEmitter(); /** * @hidden */ itemsTextVisibilityChange = new EventEmitter(); pagerClass = true; get responsiveClass() { return this.responsive; } widgetRole = 'application'; roleDescription = 'pager'; keyShortcuts = 'Enter ArrowRight ArrowLeft'; get hostTabindex() { return this.navigable ? '0' : '-1'; } get dir() { return this.direction; } /** * @hidden */ focusHandler(ev) { const isInnerNavigationEnabled = ev.target !== this.element.nativeElement; this.navigationService.toggleInnerNavigation(isInnerNavigationEnabled); } get totalPages() { return Math.ceil((this.total || 0) / this.pageSize); } get currentPage() { return Math.floor((this.skip || 0) / this.pageSize) + 1; } get templateContext() { const context = this._templateContext; context.totalPages = this.totalPages; context.total = this.total; context.skip = this.skip; context.pageSize = this.pageSize; context.currentPage = this.currentPage; return context; } /** * @hidden */ get showPageText() { return this._showPageText; } set showPageText(value) { this._showPageText = value; this.pagerInputComponent && (this.pagerInputComponent.showPageText = value); this.pageTextVisibilityChange.emit(value); } /** * @hidden */ get showItemsText() { return this._showItemsText; } set showItemsText(value) { this._showItemsText = value; this.pageSizesComponent && (this.pageSizesComponent.showItemsText = value); this.itemsTextVisibilityChange.emit(value); } /** * @hidden */ get showInput() { return this._showInput; } set showInput(value) { this._showInput = value; this.pagerInputVisibilityChange.emit(value); } /** * @hidden */ initialized = false; subscriptions = new Subscription(); _templateContext = {}; _pageSizeValues = DEFAULT_PAGE_SIZE_VALUES; direction; isInnerNavigationEnabled = false; _navigable = true; _size = DEFAULT_SIZE; _showInput = true; _showPageText = true; _showItemsText = true; /** * Stores the measurements of various Pager elements. * These dimensions are used for responsive layout calculations. * @hidden */ pagerDimensions = { padding: 0, numericButtonsWidth: 0, inputWidth: 0, pageSizesWidth: 0, sizesTextWidth: 0, pageTextWidth: 0, infoTextWidth: 0, gapNumbersSizes: 0, gapSizesInfo: 0, width: 0 }; constructor(pagerContext, element, localization, renderer, ngZone, cdr, navigationService) { this.pagerContext = pagerContext; this.element = element; this.localization = localization; this.renderer = renderer; this.ngZone = ngZone; this.cdr = cdr; this.navigationService = navigationService; validatePackage(packageMetadata); this.direction = localization.rtl ? 'rtl' : 'ltr'; if (!navigationService) { this.navigationService = inject(PagerNavigationService); } if (!pagerContext) { this.pagerContext = inject(PagerContextService); } this.pagerContext.localization = localization; } ngOnInit() { this.subscriptions.add(this.pagerContext.pageChange.subscribe(this.changePage.bind(this))); this.subscriptions.add(this.pagerContext.pageSizeChange.subscribe(this.changePageSize.bind(this))); this.subscriptions.add(this.localization.changes.subscribe(({ rtl }) => { this.direction = rtl ? 'rtl' : 'ltr'; this.measureAllTextWidths(); this.responsive && this.resizeHandler(); })); this.subscriptions.add(this.navigationService.innerNavigationChange.subscribe(this.innerNavigationChange.bind(this))); if (this.navigable) { const wrapper = this.element.nativeElement; this.ngZone.runOutsideAngular(() => { this.subscriptions.add(this.renderer.listen(wrapper, 'keydown', this.keyDownHandler.bind(this))); }); } } /** * Gets the maximum number of items displayed on the current page. */ get maxItems() { return Math.min(this.currentPage * this.pageSize, this.total); } ngAfterViewInit() { this.renderer.setAttribute(this.element.nativeElement, 'aria-label', this.ariaLabel); this.subscriptions.add(this.template.changes.subscribe(() => { this.measureAllTextWidths(); this.responsive && this.resizeHandler(false); })); this.handleClasses(this.size, 'size'); this.measureAllTextWidths(); !this.numericButtons && (this.pagerDimensions.numericButtonsWidth = this.element.nativeElement.querySelector('.k-pager-numbers')?.offsetWidth ?? 0); !this.pagerInput && (this.pagerDimensions.inputWidth = this.element.nativeElement.querySelector('.k-pager-input')?.offsetWidth ?? 0); !this.pageSizes && (this.pagerDimensions.pageSizesWidth = this.element.nativeElement.querySelector('.k-pager-sizes')?.offsetWidth ?? 0); const padding = calculatePadding(this.element.nativeElement); this.pagerDimensions.padding = padding.padding; this.pagerDimensions.gapNumbersSizes = padding.gapNumbersSizes; this.pagerDimensions.gapSizesInfo = padding.gapSizesInfo; this.ngZone.onStable.pipe(take(1)).subscribe(() => { if (this.type !== 'input') { this.showInput = false; } }); if (!isDocumentAvailable()) { this.initialized = true; return; } this.responsive && this.resizeHandler(); setTimeout(() => { this.initialized = true; this.cdr.markForCheck(); }, 0); } ngOnChanges(changes) { if (anyChanged(["pageSize", "skip", "total"], changes, false)) { const previousButtonCount = Math.min(this.buttonCount, (changes['total']?.previousValue || this.total) / (changes['pageSize']?.previousValue || this.pageSize)); this.pagerContext.notifyChanges({ pageSize: this.pageSize, skip: this.skip, total: this.total }); this.pagerDimensions.numericButtonsWidth = (this.pagerDimensions.numericButtonsWidth * Math.min(this.buttonCount, this.total / this.pageSize)) / previousButtonCount; this.renderer.setAttribute(this.element.nativeElement, 'aria-label', this.ariaLabel); this.responsive && this.resizeHandler(false); } if (anyChanged(["pageSizeValues", "previousNext", "buttonCount"], changes, true)) { this.responsive && this.resizeHandler(false); } if (isChanged('responsive', changes, true)) { if (changes['responsive'].currentValue && !changes['responsive'].previousValue) { this.measureAllTextWidths(); this.resizeHandler(false); } if (!this.responsive) { this.showInput = this.type === 'input'; this.showElementsInOrder(this.element.nativeElement.offsetWidth, this.pagerDimensions.width); } } if (isChanged('type', changes, true)) { this.showNumericButtonsResponsive(); this.responsive && this.resizeHandler(false); } } ngOnDestroy() { this.subscriptions.unsubscribe(); } /** * @hidden */ changePage(event) { this.pageChange.emit(event); } /** * @hidden */ changePageSize(event) { this.pageSizeChange.emit(event); if (!event.isDefaultPrevented()) { if (event.newPageSize === 'all') { this.pageChange.emit({ skip: 0, take: this.total }); } else { this.pageChange.emit({ skip: 0, take: event.newPageSize }); } } } /** * @hidden */ onPageSizeChange(event) { this.pageSizeChange.emit(event); if (!event.isDefaultPrevented()) { this.pageChange.emit({ skip: this.skip, take: event.newPageSize }); } } /** * @hidden */ resizeHandler = (compareWidth = true) => { if (this.template?.first && !this.responsive) { return; } if (!isDocumentAvailable() || !this.element?.nativeElement) { this.initialized = true; return; } let pagerWidth = this.element.nativeElement.offsetWidth; if (pagerWidth <= 0) { return; } if (compareWidth && pagerWidth === this.pagerDimensions.width) { return; } else { this.pagerDimensions.width = pagerWidth; } this.ngZone.runOutsideAngular(() => { setTimeout(() => { if (this.template?.first && !this.responsive) { return; } const numericButtonsWrapperElement = this.element.nativeElement.querySelector('.k-pager-numbers-wrap'); const pagerInfoElement = this.element.nativeElement.querySelector('.k-pager-info'); const pagerPageSizes = this.element.nativeElement.querySelector('.k-pager-sizes'); let elementsWidths = numericButtonsWrapperElement?.offsetWidth + (pagerPageSizes?.offsetWidth || 0) + (pagerInfoElement?.offsetWidth > 0 ? Math.min(this.pagerDimensions.infoTextWidth) : 0); if (this.isElementVisible(pagerInfoElement)) { elementsWidths += this.pagerDimensions.gapSizesInfo; } pagerWidth -= this.pagerDimensions.padding; if (this.isElementVisible(pagerPageSizes)) { pagerWidth -= this.pagerDimensions.gapNumbersSizes; } if (Math.ceil(elementsWidths) <= pagerWidth) { this.showElementsInOrder(pagerWidth, elementsWidths); } else { this.hideElementsInOrder(pagerWidth, elementsWidths); } !this.initialized && this.ngZone.onStable.pipe(take(1)).subscribe(() => this.initialized = true); }); }); }; get ariaLabel() { const localizationMsg = this.localization.get('ariaLabel') || ''; return replaceMessagePlaceholder(replaceMessagePlaceholder(localizationMsg, 'currentPage', this.currentPage.toString()), 'totalPages', this.totalPages.toString()); } keyDownHandler(e) { const target = e.target; const wrapper = this.element.nativeElement; // on some keyboards arrow keys, PageUp/Down, and Home/End are mapped to Numpad keys const code = normalizeNumpadKeys(e); const isArrowLeftOrPageUp = code === Keys.ArrowLeft || code === Keys.PageUp; const isArrowRightOrPageDown = code === Keys.ArrowRight || code === Keys.PageDown; const isEnter = code === Keys.Enter || code === Keys.NumpadEnter; const isHome = code === Keys.Home; const isEnd = code === Keys.End; const isEsc = code === Keys.Escape; const isTab = code === Keys.Tab; const isFirstPage = this.currentPage === 1; const isLastPage = this.currentPage === this.totalPages; this.ngZone.run(() => { if (isHome) { if (e.target !== wrapper) { return; } e.preventDefault(); !isFirstPage && this.pagerContext.changePage(0); } else if (isEnd) { e.preventDefault(); if (e.target !== wrapper) { return; } !isLastPage && this.pagerContext.changePage(this.totalPages - 1); } else if (this.isInnerNavigationEnabled) { if (isEsc) { this.navigationService.toggleInnerNavigation(false); wrapper.focus(); } else if (isTab) { this.navigationService.keepFocusWithinComponent(wrapper, target, e); } } else { if (e.target !== wrapper) { return; } if (isArrowLeftOrPageUp) { e.preventDefault(); !isFirstPage && this.pagerContext.prevPage(); } else if (isArrowRightOrPageDown) { e.preventDefault(); !isLastPage && this.pagerContext.nextPage(); } else if (isEnter) { e.preventDefault(); let [firstFocusable] = this.navigationService.getFirstAndLastFocusable(wrapper); if (firstFocusable.getAttribute('aria-disabled') === 'true') { firstFocusable = Array.from(getAllFocusableChildren(wrapper)).find((el) => !el.getAttribute('aria-disabled')); const input = firstFocusable.querySelector('input'); if (input) { firstFocusable = input; } } this.navigationService.toggleInnerNavigation(true); firstFocusable?.focus(); } } }); } innerNavigationChange(value) { this.isInnerNavigationEnabled = value; } handleClasses(value, input) { const elem = this.element.nativeElement; const classes = getStylingClasses('pager', input, this[input], value); if (classes.toRemove) { this.renderer.removeClass(elem, classes.toRemove); } if (classes.toAdd) { this.renderer.addClass(elem, classes.toAdd); } } showElementsInOrder(availableWidth, currentWidth) { const el = this.element.nativeElement; const numericButtonsElement = el.querySelector('kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons'); const pagerInfoElement = el.querySelector('.k-pager-info'); const pagerPageSizes = el.querySelector('.k-pager-sizes'); const pagerSizesDropDown = el.querySelector('.k-pager-sizes .k-dropdownlist'); const checkOverflow = this.responsive; if (this.type === 'input' && this.isElementVisible(pagerInfoElement) || this.isElementVisible(numericButtonsElement)) { return; } if (this.showPageSizes && !this.isElementVisible(pagerPageSizes)) { const addDropDownWidth = currentWidth + this.pagerDimensions.pageSizesWidth + this.pagerDimensions.gapNumbersSizes - this.pagerDimensions.sizesTextWidth; if (checkOverflow && addDropDownWidth > availableWidth) return; this.ngZone.run(() => this.showItemsText = false); this.showElement(pagerPageSizes); currentWidth = addDropDownWidth; if (checkOverflow && currentWidth >= availableWidth) return; } if (this.showPageSizes && this.isElementVisible(pagerPageSizes) && !this.showItemsText) { const addPageSizesText = currentWidth - pagerSizesDropDown?.offsetWidth + this.pagerDimensions.pageSizesWidth; if (checkOverflow && addPageSizesText > availableWidth) return; this.ngZone.run(() => this.showItemsText = true); currentWidth = addPageSizesText; if (checkOverflow && currentWidth >= availableWidth) return; } if (!this.showPageText && (!this.showPageSizes || (this.isElementVisible(pagerPageSizes) && this.showItemsText))) { const addPageText = currentWidth + this.pagerDimensions.pageTextWidth; if (checkOverflow && addPageText > availableWidth) return; this.ngZone.run(() => this.showPageText = true); currentWidth = addPageText; if (checkOverflow && currentWidth >= availableWidth) return; } if (this.info && !this.isElementVisible(pagerInfoElement) && (!this.showPageSizes || (this.isElementVisible(pagerPageSizes) && this.showPageText))) { const addInfoText = currentWidth + this.pagerDimensions.infoTextWidth + this.pagerDimensions.gapSizesInfo; if (checkOverflow && addInfoText > availableWidth) return; this.ngZone.run(() => { this.showElement(pagerInfoElement); }); currentWidth = addInfoText; } if (this.type === 'numeric' && (!this.info || this.isElementVisible(pagerInfoElement))) { const addNumericButtons = currentWidth - this.pagerDimensions.inputWidth + this.pagerDimensions.numericButtonsWidth; if (checkOverflow && addNumericButtons > availableWidth) return; this.showElement(numericButtonsElement); this.ngZone.run(() => { this.showInput = false; this.cdr.markForCheck(); }); } } hideElementsInOrder(availableWidth, currentWidth) { const el = this.element.nativeElement; const numericButtonsElement = el.querySelector('kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons'); const pagerInfoElement = el.querySelector('.k-pager-info'); const pagerPageSizes = el.querySelector('.k-pager-sizes'); const pagerSizesDropDown = el.querySelector('.k-pager-sizes .k-dropdownlist'); if (this.isElementVisible(numericButtonsElement)) { this.hideElement(numericButtonsElement); this.ngZone.run(() => this.showInput = true); currentWidth += this.pagerDimensions.inputWidth - this.pagerDimensions.numericButtonsWidth; if (currentWidth <= availableWidth) return; } if (this.isElementVisible(pagerInfoElement)) { this.hideElement(pagerInfoElement); currentWidth -= (this.pagerDimensions.infoTextWidth + this.pagerDimensions.gapSizesInfo); if (currentWidth <= availableWidth) return; } if (this.showPageText) { this.ngZone.run(() => this.showPageText = false); currentWidth = currentWidth - this.pagerDimensions.pageTextWidth; if (currentWidth <= availableWidth) return; } if (this.showPageSizes && this.isElementVisible(pagerPageSizes) && this.showItemsText) { this.ngZone.run(() => this.showItemsText = false); currentWidth = currentWidth - this.pagerDimensions.pageSizesWidth + pagerSizesDropDown?.offsetWidth; if (currentWidth <= availableWidth) return; } this.hideElement(pagerPageSizes); } isElementVisible(element) { return element && !element?.classList.contains('k-hidden'); } hideElement(element) { if (element) { this.renderer.addClass(element, 'k-hidden'); } } showElement(element) { if (element) { this.renderer.removeClass(element, 'k-hidden'); } } measureAllTextWidths() { if (!isDocumentAvailable()) { return; } const el = this.element.nativeElement; const existingInfo = el.querySelector('.k-pager-info'); const existingInput = el.querySelector('.k-pager-input'); const existingSizes = el.querySelector('.k-pager-sizes'); // create a single measurement container const measureContainer = this.renderer.createElement('div'); positionOffScreen(this.renderer, measureContainer); this.renderer.appendChild(this.element.nativeElement, measureContainer); const infoSpan = createMeasurementSpan(this.renderer, measureContainer, 'k-pager-info'); const pageSpan = createMeasurementSpan(this.renderer, measureContainer, 'k-pager-input'); const sizesSpan = createMeasurementSpan(this.renderer, measureContainer, 'k-pager-sizes'); const infoText = `${this.currentPage} - ${this.maxItems} ${this.localization.get('of')} ${this.total} ${this.localization.get('items')}`; this.renderer.setProperty(infoSpan, 'textContent', infoText); this.renderer.setProperty(pageSpan, 'textContent', this.localization.get('page')); this.renderer.setProperty(sizesSpan, 'textContent', this.localization.get('itemsPerPage')); // copy computed styles if available if (existingInfo) copyComputedStyles(this.renderer, existingInfo, infoSpan); if (existingInput) copyComputedStyles(this.renderer, existingInput, pageSpan); if (existingSizes) copyComputedStyles(this.renderer, existingSizes, sizesSpan); // force a reflow to ensure measurements are accurate measureContainer.getBoundingClientRect(); this.pagerDimensions.infoTextWidth = infoSpan?.offsetWidth; if (this.pagerDimensions.inputWidth && this.pagerDimensions.pageTextWidth) { this.pagerDimensions.inputWidth = this.pagerDimensions.inputWidth - this.pagerDimensions.pageTextWidth + pageSpan.offsetWidth; } this.pagerDimensions.pageTextWidth = pageSpan?.offsetWidth; if (this.pagerDimensions.pageSizesWidth && this.pagerDimensions.sizesTextWidth) { this.pagerDimensions.pageSizesWidth = this.pagerDimensions.pageSizesWidth - this.pagerDimensions.sizesTextWidth + sizesSpan.offsetWidth; } this.pagerDimensions.sizesTextWidth = sizesSpan?.offsetWidth; this.renderer.removeChild(this.element.nativeElement, measureContainer); } showNumericButtonsResponsive() { if (!isDocumentAvailable() || !this.element?.nativeElement) { return; } const numericButtonsElement = this.element.nativeElement.querySelector('kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons'); const hasNumericButtons = this.numericButtons || numericButtonsElement; const hasInput = this.pagerInput || this.element.nativeElement.querySelector('.k-pager-input'); if (!this.responsive || (!hasNumericButtons && !hasInput)) { this.showInput = this.type === 'input'; return; } const pagerInfoElement = this.element.nativeElement.querySelector('.k-pager-info'); if (this.type === 'input' || !this.isElementVisible(pagerInfoElement)) { this.showInput = true; return; } if (this.isElementVisible(numericButtonsElement)) { this.showInput = false; return; } const pagerWidth = this.element.nativeElement?.offsetWidth; const numericButtonsWrapperElement = this.element.nativeElement.querySelector('.k-pager-numbers-wrap'); const elementsWidths = numericButtonsWrapperElement?.offsetWidth + this.pagerDimensions.pageSizesWidth + this.pagerDimensions.infoTextWidth + this.pagerDimensions.gapSizesInfo; const hasAvailableWidth = pagerWidth > elementsWidths - this.pagerDimensions.inputWidth + this.pagerDimensions.numericButtonsWidth; this.showInput = !hasAvailableWidth; } get showPageSizes() { if (typeof this.pageSizeValues === 'boolean') { return this.pageSizeValues; } return this.pageSizeValues?.length > 0; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PagerComponent, deps: [{ token: i1.PagerContextService, optional: true, skipSelf: true }, { token: i0.ElementRef }, { token: i2.LocalizationService }, { token: i0.Renderer2 }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: i3.PagerNavigationService, optional: true, skipSelf: true }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: PagerComponent, isStandalone: true, selector: "kendo-datapager, kendo-pager", inputs: { externalTemplate: "externalTemplate", total: "total", skip: "skip", pageSize: "pageSize", buttonCount: "buttonCount", info: "info", type: "type", pageSizeValues: "pageSizeValues", previousNext: "previousNext", navigable: "navigable", size: "size", responsive: "responsive", adaptiveMode: "adaptiveMode" }, outputs: { pageChange: "pageChange", pageSizeChange: "pageSizeChange", pagerInputVisibilityChange: "pagerInputVisibilityChange", pageTextVisibilityChange: "pageTextVisibilityChange", itemsTextVisibilityChange: "itemsTextVisibilityChange" }, host: { listeners: { "focusin": "focusHandler($event)" }, properties: { "class.k-pager": "this.pagerClass", "class.k-pager-responsive": "this.responsiveClass", "attr.role": "this.widgetRole", "attr.aria-roledescription": "this.roleDescription", "attr.aria-keyshortcuts": "this.keyShortcuts", "attr.tabindex": "this.hostTabindex", "attr.dir": "this.dir" } }, providers: [ LocalizationService, PagerContextService, PagerNavigationService, { provide: L10N_PREFIX, useValue: 'kendo.pager' } ], queries: [{ propertyName: "template", predicate: PagerTemplateDirective }], viewQueries: [{ propertyName: "numericButtons", first: true, predicate: PagerNumericButtonsComponent, descendants: true, read: ElementRef }, { propertyName: "pagerInput", first: true, predicate: PagerInputComponent, descendants: true, read: ElementRef }, { propertyName: "pagerInputComponent", first: true, predicate: PagerInputComponent, descendants: true }, { propertyName: "pageSizes", first: true, predicate: PagerPageSizesComponent, descendants: true, read: ElementRef }, { propertyName: "pageSizesComponent", first: true, predicate: PagerPageSizesComponent, descendants: true }], exportAs: ["kendoDataPager", "kendoPager"], usesOnChanges: true, ngImport: i0, template: ` <ng-container kendoPagerLocalizedMessages i18n-ariaLabel="kendo.pager.ariaLabel|The value of the aria-label attribute of the Pager" ariaLabel="{{ 'Page navigation, page {currentPage} of {totalPages}' }}" i18n-firstPage="kendo.pager.firstPage|The label for the first page button in the Pager" firstPage="Go to the first page" i18n-previousPage="kendo.pager.previousPage|The label for the previous page button in the Pager" previousPage="Go to the previous page" i18n-nextPage="kendo.pager.nextPage|The label for the next page button in the Pager" nextPage="Go to the next page" i18n-lastPage="kendo.pager.lastPage|The label for the last page button in the Pager" lastPage="Go to the last page" i18n-page="kendo.pager.page|The label before the current page number in the Pager" page="Page" i18n-of="kendo.pager.of|The label before the total pages number in the Pager" of="of" i18n-pageNumberInputTitle="kendo.pager.pageNumberInputTitle|The label for the pager input in the Pager" pageNumberInputTitle="Page Number" i18n-items="kendo.pager.items|The label after the total pages number in the Pager" items="items" i18n-itemsPerPage="kendo.pager.itemsPerPage|The label for the page size chooser in the Pager" itemsPerPage="items per page" i18n-selectPage="kendo.pager.selectPage|The text of the title and aria-label attributes applied to the page chooser in the Pager" selectPage="Select page" i18n-inputLabel="kendo.pager.inputLabel|The text of the aria-label attribute applied to the input element for entering the page number." inputLabel="Type a page number" > </ng-container> <ng-container *ngIf="template.first?.templateRef; else default" [ngTemplateOutlet]="template.first?.templateRef" [ngTemplateOutletContext]="templateContext"> </ng-container> <ng-template #default> <div class="k-pager-numbers-wrap" [ngStyle]="{opacity: initialized ? null : '0'}"> <kendo-pager-prev-buttons [size]="size" *ngIf="previousNext"></kendo-pager-prev-buttons> <kendo-pager-numeric-buttons [size]="size" *ngIf="type === 'numeric' && buttonCount > 0" [buttonCount]="buttonCount"> </kendo-pager-numeric-buttons> <kendo-pager-input [size]="size" *ngIf="showInput"></kendo-pager-input> <kendo-pager-next-buttons [size]="size" *ngIf="previousNext"></kendo-pager-next-buttons> </div> <kendo-pager-page-sizes *ngIf="_pageSizeValues.length" [ngStyle]="{opacity: initialized ? null : '0'}" [size]="size" [pageSizes]="_pageSizeValues" [adaptiveMode]="adaptiveMode"> </kendo-pager-page-sizes> <kendo-pager-info *ngIf="info" [ngStyle]="{opacity: initialized ? null : '0'}"> </kendo-pager-info> </ng-template> <kendo-resize-sensor *ngIf="responsive" (resize)="resizeHandler()"></kendo-resize-sensor> `, isInline: true, dependencies: [{ kind: "directive", type: LocalizedMessagesDirective, selector: "[kendoPagerLocalizedMessages]" }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PagerPrevButtonsComponent, selector: "kendo-datapager-prev-buttons, kendo-pager-prev-buttons", inputs: ["size"] }, { kind: "component", type: PagerNumericButtonsComponent, selector: "kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons", inputs: ["buttonCount", "size"] }, { kind: "component", type: PagerInputComponent, selector: "kendo-datapager-input, kendo-pager-input", inputs: ["showPageText", "size"] }, { kind: "component", type: PagerNextButtonsComponent, selector: "kendo-datapager-next-buttons, kendo-pager-next-buttons", inputs: ["size"] }, { kind: "component", type: PagerPageSizesComponent, selector: "kendo-datapager-page-sizes, kendo-pager-page-sizes", inputs: ["showItemsText", "pageSizes", "size", "adaptiveMode"] }, { kind: "component", type: PagerInfoComponent, selector: "kendo-datapager-info, kendo-pager-info" }, { kind: "component", type: ResizeSensorComponent, selector: "kendo-resize-sensor", inputs: ["rateLimit"], outputs: ["resize"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: PagerComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-datapager, kendo-pager', exportAs: 'kendoDataPager, kendoPager', providers: [ LocalizationService, PagerContextService, PagerNavigationService, { provide: L10N_PREFIX, useValue: 'kendo.pager' } ], template: ` <ng-container kendoPagerLocalizedMessages i18n-ariaLabel="kendo.pager.ariaLabel|The value of the aria-label attribute of the Pager" ariaLabel="{{ 'Page navigation, page {currentPage} of {totalPages}' }}" i18n-firstPage="kendo.pager.firstPage|The label for the first page button in the Pager" firstPage="Go to the first page" i18n-previousPage="kendo.pager.previousPage|The label for the previous page button in the Pager" previousPage="Go to the previous page" i18n-nextPage="kendo.pager.nextPage|The label for the next page button in the Pager" nextPage="Go to the next page" i18n-lastPage="kendo.pager.lastPage|The label for the last page button in the Pager" lastPage="Go to the last page" i18n-page="kendo.pager.page|The label before the current page number in the Pager" page="Page" i18n-of="kendo.pager.of|The label before the total pages number in the Pager" of="of" i18n-pageNumberInputTitle="kendo.pager.pageNumberInputTitle|The label for the pager input in the Pager" pageNumberInputTitle="Page Number" i18n-items="kendo.pager.items|The label after the total pages number in the Pager" items="items" i18n-itemsPerPage="kendo.pager.itemsPerPage|The label for the page size chooser in the Pager" itemsPerPage="items per page" i18n-selectPage="kendo.pager.selectPage|The text of the title and aria-label attributes applied to the page chooser in the Pager" selectPage="Select page" i18n-inputLabel="kendo.pager.inputLabel|The text of the aria-label attribute applied to the input element for entering the page number." inputLabel="Type a page number" > </ng-container> <ng-container *ngIf="template.first?.templateRef; else default" [ngTemplateOutlet]="template.first?.templateRef" [ngTemplateOutletContext]="templateContext"> </ng-container> <ng-template #default> <div class="k-pager-numbers-wrap" [ngStyle]="{opacity: initialized ? null : '0'}"> <kendo-pager-prev-buttons [size]="size" *ngIf="previousNext"></kendo-pager-prev-buttons> <kendo-pager-numeric-buttons [size]="size" *ngIf="type === 'numeric' && buttonCount > 0" [buttonCount]="buttonCount"> </kendo-pager-numeric-buttons> <kendo-pager-input [size]="size" *ngIf="showInput"></kendo-pager-input> <kendo-pager-next-buttons [size]="size" *ngIf="previousNext"></kendo-pager-next-buttons> </div> <kendo-pager-page-sizes *ngIf="_pageSizeValues.length" [ngStyle]="{opacity: initialized ? null : '0'}" [size]="size" [pageSizes]="_pageSizeValues" [adaptiveMode]="adaptiveMode"> </kendo-pager-page-sizes> <kendo-pager-info *ngIf="info" [ngStyle]="{opacity: initialized ? null : '0'}"> </kendo-pager-info> </ng-template> <kendo-resize-sensor *ngIf="responsive" (resize)="resizeHandler()"></kendo-resize-sensor> `, standalone: true, imports: [LocalizedMessagesDirective, NgIf, NgTemplateOutlet, PagerPrevButtonsComponent, PagerNumericButtonsComponent, PagerInputComponent, PagerNextButtonsComponent, PagerPageSizesComponent, PagerInfoComponent, ResizeSensorComponent, NgStyle] }] }], ctorParameters: function () { return [{ type: i1.PagerContextService, decorators: [{ type: Optional }, { type: SkipSelf }] }, { type: i0.ElementRef }, { type: i2.LocalizationService }, { type: i0.Renderer2 }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: i3.PagerNavigationService, decorators: [{ type: Optional }, { type: SkipSelf }] }]; }, propDecorators: { template: [{ type: ContentChildren, args: [PagerTemplateDirective] }], numericButtons: [{ type: ViewChild, args: [PagerNumericButtonsComponent, { read: ElementRef }] }], pagerInput: [{ type: ViewChild, args: [PagerInputComponent, { read: ElementRef }] }], pagerInputComponent: [{ type: ViewChild, args: [PagerInputComponent] }], pageSizes: [{ type: ViewChild, args: [PagerPageSizesComponent, { read: ElementRef }] }], pageSizesComponent: [{ type: ViewChild, args: [PagerPageSizesComponent] }], externalTemplate: [{ type: Input }], total: [{ type: Input }], skip: [{ type: Input }], pageSize: [{ type: Input }], buttonCount: [{ type: Input }], info: [{ type: Input }], type: [{ type: Input }], pageSizeValues: [{ type: Input }], previousNext: [{ type: Input }], navigable: [{ type: Input }], size: [{ type: Input }], responsive: [{ type: Input }], adaptiveMode: [{ type: Input }], pageChange: [{ type: Output }], pageSizeChange: [{ type: Output }], pagerInputVisibilityChange: [{ type: Output }], pageTextVisibilityChange: [{ type: Output }], itemsTextVisibilityChange: [{ type: Output }], pagerClass: [{ type: HostBinding, args: ['class.k-pager'] }], responsiveClass: [{ type: HostBinding, args: ['class.k-pager-responsive'] }], widgetRole: [{ type: HostBinding, args: ['attr.role'] }], roleDescription: [{ type: HostBinding, args: ['attr.aria-roledescription'] }], keyShortcuts: [{ type: HostBinding, args: ['attr.aria-keyshortcuts'] }], hostTabindex: [{ type: HostBinding, args: ['attr.tabindex'] }], dir: [{ type: HostBinding, args: ['attr.dir'] }], focusHandler: [{ type: HostListener, args: ['focusin', ['$event']] }] } });