UNPKG

@progress/kendo-angular-pager

Version:
1,270 lines (1,255 loc) 114 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import * as i0 from '@angular/core'; import { Directive, Input, forwardRef, Component, ChangeDetectionStrategy, ViewChild, HostBinding, Optional, ElementRef, EventEmitter, inject, SkipSelf, ContentChildren, Output, HostListener, NgModule } from '@angular/core'; import * as i1 from '@progress/kendo-angular-l10n'; import { ComponentMessages, LocalizationService, L10N_PREFIX } from '@progress/kendo-angular-l10n'; import { Subject, Subscription } from 'rxjs'; import { caretAltLeftIcon, caretAltToLeftIcon, caretAltRightIcon, caretAltToRightIcon } from '@progress/kendo-svg-icons'; import { isVisible, isDocumentAvailable, isFocusable, Keys, EventsOutsideAngularDirective, anyChanged, isChanged, replaceMessagePlaceholder, normalizeKeys, ResizeSensorComponent, isPresent, ResizeBatchService } from '@progress/kendo-angular-common'; import { ButtonComponent } from '@progress/kendo-angular-buttons'; import { DropDownListComponent } from '@progress/kendo-angular-dropdowns'; import { NumericTextBoxComponent } from '@progress/kendo-angular-inputs'; import { validatePackage } from '@progress/kendo-licensing'; import { NgTemplateOutlet, NgStyle } from '@angular/common'; import { take } from 'rxjs/operators'; import { IconsService } from '@progress/kendo-angular-icons'; import { PopupService } from '@progress/kendo-angular-popup'; /** * @hidden */ class PreventableEvent { prevented = false; /** * Prevents the default action for a specified event. * In this way, the source component suppresses the built-in behavior that follows the event. */ preventDefault() { this.prevented = true; } /** * If the event is prevented by any of its subscribers, returns `true`. * * @returns `true` if the default action was prevented. Otherwise, returns `false`. */ isDefaultPrevented() { return this.prevented; } } /** * Represents the arguments for the `pageSizeChange` event. The `pageSizeChange` event fires when you change the page size * from the UI. If you cancel the event, the change does not occur. */ class PageSizeChangeEvent extends PreventableEvent { /** * Gets the newly selected page size. */ newPageSize; /** * Constructs the event arguments for the `pageSizeChange` event. * @param newPageSize - The newly selected page size. * @hidden */ constructor(newPageSize) { super(); this.newPageSize = newPageSize; } } /** * @hidden */ class Messages extends ComponentMessages { /** * The label of the pager. Follows the pattern **Page navigation, page {currentPage} of {totalPages}** by default. * Тhe default label text when the current page is 1, and the total number of pages is 10 will be * **Page navigation, page 1 of 10**. * * The message consists of several parts - the current page number, the total number of pages, and a localizable string. * To allow for reordering its parts, the `ariaLabel` input accepts a string with placeholders for the current page * and total number of pages. The `{currentPage}` and `{totalPages}` placeholders will be replaced * internally with the respective actual values. */ ariaLabel; /** * The label for the **First page** button. */ firstPage; /** * The label for the **Last page** button. */ lastPage; /** * The label for the **Previous page** button. */ previousPage; /** * The label for the **Next page** button. */ nextPage; /** * The label displayed before the pager input. */ page; /** * The title attribute of the page number input element. */ pageNumberInputTitle; /** * The label displayed after the page-size selector. */ itemsPerPage; /** * The label before the total-page number. */ of; /** * The label after the total-page number. */ items; /** * The text of the title and aria-label attributes applied to the page chooser. */ selectPage; /** * The text of the aria-label attribute applied to the input element for entering the page number." */ inputLabel; static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, deps: null, target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: Messages, selector: "kendoPagerMessages", inputs: { ariaLabel: "ariaLabel", firstPage: "firstPage", lastPage: "lastPage", previousPage: "previousPage", nextPage: "nextPage", page: "page", pageNumberInputTitle: "pageNumberInputTitle", itemsPerPage: "itemsPerPage", of: "of", items: "items", selectPage: "selectPage", inputLabel: "inputLabel" }, usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: Messages, decorators: [{ type: Directive, args: [{ // eslint-disable-next-line @angular-eslint/directive-selector selector: 'kendoPagerMessages' }] }], propDecorators: { ariaLabel: [{ type: Input }], firstPage: [{ type: Input }], lastPage: [{ type: Input }], previousPage: [{ type: Input }], nextPage: [{ type: Input }], page: [{ type: Input }], pageNumberInputTitle: [{ type: Input }], itemsPerPage: [{ type: Input }], of: [{ type: Input }], items: [{ type: Input }], selectPage: [{ type: Input }], inputLabel: [{ type: Input }] } }); /** * Represents the Kendo UI Pager custom messages component for Angular. Use this component to override default component messages * ([see example]({% slug pager_globalization %}#toc-messages)). * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <kendo-pager-messages * previousNext="Previous/Next" * page="Page" * of="of"> * </kendo-pager-messages> * </kendo-pager> * ``` */ class CustomMessagesComponent extends Messages { service; constructor(service) { super(); this.service = service; } get override() { return true; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CustomMessagesComponent, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: CustomMessagesComponent, isStandalone: true, selector: "kendo-datapager-messages, kendo-pager-messages", providers: [ { provide: Messages, useExisting: forwardRef(() => CustomMessagesComponent) } ], usesInheritance: true, ngImport: i0, template: ``, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: CustomMessagesComponent, decorators: [{ type: Component, args: [{ providers: [ { provide: Messages, useExisting: forwardRef(() => CustomMessagesComponent) } ], selector: 'kendo-datapager-messages, kendo-pager-messages', template: ``, standalone: true }] }], ctorParameters: () => [{ type: i1.LocalizationService }] }); /** * @hidden */ class LocalizedMessagesDirective extends Messages { service; constructor(service) { super(); this.service = service; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocalizedMessagesDirective, deps: [{ token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: LocalizedMessagesDirective, isStandalone: true, selector: "[kendoPagerLocalizedMessages]", providers: [ { provide: Messages, useExisting: forwardRef(() => LocalizedMessagesDirective) } ], usesInheritance: true, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LocalizedMessagesDirective, decorators: [{ type: Directive, args: [{ providers: [ { provide: Messages, useExisting: forwardRef(() => LocalizedMessagesDirective) } ], selector: '[kendoPagerLocalizedMessages]', standalone: true }] }], ctorParameters: () => [{ type: i1.LocalizationService }] }); /** * @hidden */ class PagerContextService { total; skip; pageSize; isAllSelected = false; localization; changes = new Subject(); pageChange = new Subject(); pageSizeChange = new Subject(); get currentPage() { return this.skip / this.pageSize; } notifyChanges(changes) { this.total = changes.total; this.skip = changes.skip; this.pageSize = changes.pageSize; this.isAllSelected = changes.isAllSelected || false; this.changes.next(changes); } changePage(page) { this.pageChange.next({ skip: page * this.pageSize, take: this.pageSize }); } changePageSize(event) { this.pageSizeChange.next(event); } nextPage() { const nextPage = this.currentPage + 1; if (nextPage * this.pageSize < this.total) { this.changePage(nextPage); } } prevPage() { const prevPage = this.currentPage - 1; if (prevPage * this.pageSize >= 0) { this.changePage(prevPage); } } } /** * @hidden */ class PagerElementComponent { localization; pagerContext; cd; total; skip; pageSize; caretAltLeftIcon = caretAltLeftIcon; caretAltToLeftIcon = caretAltToLeftIcon; caretAltRightIcon = caretAltRightIcon; caretAltToRightIcon = caretAltToRightIcon; /** * @hidden * * @readonly * @type {number} * @memberOf PagerElementComponent */ get currentPage() { return Math.floor((this.skip || 0) / this.pageSize) + 1; } /** * @hidden * * @readonly * @type {number} * @memberOf PagerElementComponent */ get totalPages() { return Math.ceil((this.total || 0) / this.pageSize); } subscriptions; constructor(localization, pagerContext, cd) { this.localization = localization; this.pagerContext = pagerContext; this.cd = cd; this.total = pagerContext.total; this.skip = pagerContext.skip; this.pageSize = pagerContext.pageSize; } /** * @hidden * * @param {string} key * @returns {string} * * @memberOf PagerElementComponent */ textFor(key) { const isPagerLocalization = this.localization.prefix === 'kendo.pager'; return this.localization.get(isPagerLocalization ? key : `pager${key[0].toLocaleUpperCase()}${key.slice(1)}`); } /** * @hidden * * @param {number} page * * @memberOf PagerElementComponent */ changePage(page) { this.pagerContext.changePage(page); return false; } /** * @hidden * * @memberOf PagerElementComponent */ ngOnInit() { this.subscriptions = this.pagerContext.changes.subscribe(this.onChanges.bind(this)); this.subscriptions.add(this.localization.changes.subscribe(() => this.cd.markForCheck())); } ngOnDestroy() { if (this.subscriptions) { this.subscriptions.unsubscribe(); } } get prevArrowIcons() { return !this.localization.rtl ? ['caret-alt-to-left', 'caret-alt-left'] : ['caret-alt-to-right', 'caret-alt-right']; } get prevArrowSVGIcons() { return !this.localization.rtl ? [this.caretAltToLeftIcon, this.caretAltLeftIcon] : [this.caretAltToRightIcon, this.caretAltRightIcon]; } get nextArrowIcons() { return !this.localization.rtl ? ['caret-alt-right', 'caret-alt-to-right'] : ['caret-alt-left', 'caret-alt-to-left']; } get nextArrowSVGIcons() { return !this.localization.rtl ? [this.caretAltRightIcon, this.caretAltToRightIcon] : [this.caretAltLeftIcon, this.caretAltToLeftIcon]; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerElementComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerElementComponent, selector: "kendo-pager-element", ngImport: i0, template: ``, isInline: true }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerElementComponent, decorators: [{ type: Component, args: [{ selector: 'kendo-pager-element', template: `` }] }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: PagerContextService }, { type: i0.ChangeDetectorRef }] }); /** * @hidden */ const DEFAULT_PAGE_SIZE_VALUES = [5, 10, 20].map(n => ({ text: String(n), value: n })); /** * @hidden */ const focusableDirectiveSelector = '[kendoPagerFocusable]'; /** * @hidden */ const getAllFocusableChildren = (parent) => { return Array.from(parent.querySelectorAll(focusableDirectiveSelector))?.filter(isVisible); }; /** * @hidden */ const focusableSelector = [ 'a[href]:not([disabled]):not([aria-hidden="true"])', 'area[href]:not([disabled]):not([aria-hidden="true"])', 'input:not([disabled]):not([aria-hidden="true"])', 'select:not([disabled]):not([aria-hidden="true"])', 'textarea:not([disabled]):not([aria-hidden="true"])', 'button:not([aria-hidden="true"])', 'iframe:not([disabled])', 'object:not([disabled])', 'embed:not([disabled])', '*[tabindex]:not([disabled]):not([aria-hidden="true"])', '*[contenteditable]:not([disabled]):not([contenteditable="false"])' ].join(','); /** * @hidden */ const DEFAULT_SIZE = 'medium'; const SIZES = { small: 'sm', medium: 'md', large: 'lg' }; /** * @hidden * * Returns the styling classes to be added and removed */ const getStylingClasses = (componentType, stylingOption, previousValue, newValue) => { switch (stylingOption) { case 'size': return { toRemove: `k-${componentType}-${SIZES[previousValue]}`, toAdd: newValue !== 'none' ? `k-${componentType}-${SIZES[newValue]}` : '' }; default: break; } }; /** * @hidden */ const calculatePadding = (element) => { if (!element || !isDocumentAvailable()) { return { padding: 0, gapNumbersSizes: 0, gapSizesInfo: 0 }; } const computedStyle = window.getComputedStyle(element); const paddingLeft = parseInt(computedStyle.paddingLeft, 10) || 0; const paddingRight = parseInt(computedStyle.paddingRight, 10) || 0; const padding = (paddingLeft + paddingRight) * 1.2; // account for rounding errors const style = getComputedStyle(document.documentElement); const gapNumbersSizes = 2 * (parseFloat(style.getPropertyValue('--kendo-spacing-3\\.5') || '0.875rem') * (parseFloat(getComputedStyle(document.documentElement).fontSize) || 16)); // convert rem to px const gapSizesInfo = gapNumbersSizes; return { padding, gapNumbersSizes, gapSizesInfo }; }; /** * @hidden */ const calculateGap = (element) => { if (!element || !isDocumentAvailable()) { return 0; } const computedStyle = window.getComputedStyle(element); return parseFloat(computedStyle.gap) || 0; }; /** * @hidden */ const createMeasurementSpan = (renderer, container, className) => { const span = renderer.createElement('span'); renderer.appendChild(container, span); renderer.addClass(span, className); return span; }; /** * @hidden */ const copyComputedStyles = (renderer, source, destination) => { const computedStyle = getComputedStyle(source); const importantStyles = [ 'font-family', 'font-size', 'font-weight', 'font-style', 'letter-spacing', 'text-transform', 'white-space', 'word-spacing', 'padding-left', 'padding-right', 'margin-left', 'margin-right', 'border-left-width', 'border-right-width', 'box-sizing' ]; importantStyles.forEach(style => { renderer.setStyle(destination, style, computedStyle.getPropertyValue(style)); }); }; /** * * @hidden */ const positionOffScreen = (renderer, element) => { renderer.setStyle(element, 'position', 'absolute'); renderer.setStyle(element, 'visibility', 'hidden'); renderer.setStyle(element, 'left', '-9999px'); renderer.setStyle(element, 'top', '-9999px'); renderer.setStyle(element, 'display', 'flex'); }; /** * @hidden */ class PagerNavigationService { isNavigable = true; innerNavigationChange = new Subject(); toggleInnerNavigation(value) { this.innerNavigationChange.next(value); } keepFocusWithinComponent(wrapper, target, event) { const [firstFocusable, lastFocusable] = this.getFirstAndLastFocusable(wrapper); const tabAfterLastFocusable = !event.shiftKey && target === lastFocusable; const shiftTabAfterFirstFocusable = event.shiftKey && target === firstFocusable; if (tabAfterLastFocusable) { event.preventDefault(); firstFocusable.focus(); } if (shiftTabAfterFirstFocusable) { event.preventDefault(); lastFocusable.focus(); } } getFirstAndLastFocusable(wrapper) { const all = getAllFocusableChildren(wrapper); const firstFocusable = all.length > 0 ? all[0] : wrapper; const lastFocusable = all.length > 0 ? all[all.length - 1] : wrapper; return [ isFocusable(firstFocusable) ? firstFocusable : firstFocusable.querySelector(focusableSelector), isFocusable(lastFocusable) ? lastFocusable : lastFocusable.querySelector(focusableSelector) ]; } } /** * Represents the Kendo UI Pager focusable directive for Angular. Apply this directive to custom focusable elements in the [`kendoPagerTemplate`]({% slug api_pager_pagertemplatedirective %}) to include them in the built-in Pager keyboard navigation. * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <ng-template kendoPagerTemplate> * <button kendoPagerFocusable type="button">Custom Button</button> * </ng-template> * </kendo-pager> * ``` */ class PagerFocusableDirective { navigationService; element; renderer; subscriptions = new Subscription(); constructor(navigationService, element, renderer) { this.navigationService = navigationService; this.element = element; this.renderer = renderer; } ngOnInit() { if (!(this.nativeElement instanceof HTMLElement)) { return; } this.subscriptions.add(this.navigationService.innerNavigationChange.subscribe(this.innerNavigationChange.bind(this))); } ngOnDestroy() { this.subscriptions.unsubscribe(); } get nativeElement() { return this.element.nativeElement; } innerNavigationChange(value) { if (!this.navigationService.isNavigable) { return; } const index = value ? '0' : '-1'; if (this.nativeElement.matches(focusableSelector)) { this.renderer.setAttribute(this.nativeElement, 'tabindex', index); } const focusableElements = this.nativeElement.querySelectorAll(focusableSelector); focusableElements.forEach(el => { this.renderer.setAttribute(el, 'tabindex', index); }); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerFocusableDirective, deps: [{ token: PagerNavigationService }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: PagerFocusableDirective, isStandalone: true, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"], ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerFocusableDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoPagerFocusable]', exportAs: 'kendoPagerFocusable', standalone: true }] }], ctorParameters: () => [{ type: PagerNavigationService }, { type: i0.ElementRef }, { type: i0.Renderer2 }] }); // eslint-disable no-access-missing-member /** * Represents the Kendo UI Pager Previous Buttons component for Angular. Displays buttons for navigating to the first and to the previous page ([see example]({% slug pager_settings %})). * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <ng-template kendoPagerTemplate> * <kendo-pager-prev-buttons></kendo-pager-prev-buttons> * </ng-template> * </kendo-pager> * ``` */ class PagerPrevButtonsComponent extends PagerElementComponent { constructor(localization, pagerContext, cd) { super(localization, pagerContext, cd); } /** * Specifies the padding of the navigation buttons. * * @default 'medium' */ size = DEFAULT_SIZE; /** * @hidden * * @readonly * @type {boolean} * @memberOf PagerPrevButtonsComponent */ get disabled() { return this.currentPage === 1 || !this.total; } /** * @hidden */ onClick(isFirst = false) { if (this.disabled) { return false; } const targetPage = isFirst ? 0 : this.currentPage - 2; return this.currentPage !== 1 ? this.changePage(targetPage) : false; } onChanges({ total, skip, pageSize }) { this.total = total; this.skip = skip; this.pageSize = pageSize; this.cd.markForCheck(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPrevButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerPrevButtonsComponent, isStandalone: true, selector: "kendo-datapager-prev-buttons, kendo-pager-prev-buttons", inputs: { size: "size" }, usesInheritance: true, ngImport: i0, template: ` <button type="button" kendoButton kendoPagerFocusable class="k-pager-nav k-pager-first" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [icon]="prevArrowIcons[0]" [svgIcon]="prevArrowSVGIcons[0]" fillMode="flat" rounded="none" [size]="size" [title]="textFor('firstPage')" [attr.aria-label]="textFor('firstPage')" (click)="onClick(true)"> </button> <button type="button" kendoButton kendoPagerFocusable class="k-pager-nav" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [icon]="prevArrowIcons[1]" [svgIcon]="prevArrowSVGIcons[1]" fillMode="flat" rounded="none" [size]="size" [title]="textFor('previousPage')" [attr.aria-label]="textFor('previousPage')" (click)="onClick()"> </button> `, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPrevButtonsComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'kendo-datapager-prev-buttons, kendo-pager-prev-buttons', template: ` <button type="button" kendoButton kendoPagerFocusable class="k-pager-nav k-pager-first" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [icon]="prevArrowIcons[0]" [svgIcon]="prevArrowSVGIcons[0]" fillMode="flat" rounded="none" [size]="size" [title]="textFor('firstPage')" [attr.aria-label]="textFor('firstPage')" (click)="onClick(true)"> </button> <button type="button" kendoButton kendoPagerFocusable class="k-pager-nav" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [icon]="prevArrowIcons[1]" [svgIcon]="prevArrowSVGIcons[1]" fillMode="flat" rounded="none" [size]="size" [title]="textFor('previousPage')" [attr.aria-label]="textFor('previousPage')" (click)="onClick()"> </button> `, standalone: true, imports: [ButtonComponent, PagerFocusableDirective] }] }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: PagerContextService }, { type: i0.ChangeDetectorRef }], propDecorators: { size: [{ type: Input }] } }); /** * Represents the Kendo UI Pager Page Sizes component for Angular. Displays a drop-down list for the page size selection ([see example]({% slug pager_settings %})). * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <ng-template kendoPagerTemplate> * <kendo-pager-page-sizes [pageSizes]="[10, 20, 50]"></kendo-pager-page-sizes> * </ng-template> * </kendo-pager> * ``` */ class PagerPageSizesComponent extends PagerElementComponent { pagerContext; element; ngZone; dropDownList; _showItemsText = true; /** * Controls the visibility of the page text label. * @hidden */ get showItemsText() { return this._showItemsText; } set showItemsText(value) { this._showItemsText = value; this.cd.markForCheck(); } /** * Specifies the page sizes collection. You can include numbers and [`PageSizeItem`]({% slug api_pager_pagesizeitem %}) objects. * * @example * ```html * <kendo-pager [skip]="0" [pageSize]="10" [total]="100"> * <ng-template kendoPagerTemplate> * <kendo-pager-page-sizes [pageSizes]="[5, 10, 20, { text: 'All', value: 'all' }]"></kendo-pager-page-sizes> * </ng-template> * </kendo-pager> * ``` */ set pageSizes(pageSizes) { let normalizedItems = []; if (Array.isArray(pageSizes)) { pageSizes.forEach(item => { if (typeof item === 'number') { normalizedItems.push({ text: item.toString(), value: item }); } else { normalizedItems.push(item); } }); } else { normalizedItems = DEFAULT_PAGE_SIZE_VALUES; } if (this.pageSize && !normalizedItems.some(item => item.value === this.pageSize)) { normalizedItems = [{ text: this.pageSize.toString(), value: this.pageSize }, ...normalizedItems]; } this._pageSizes = normalizedItems; } /** * Specifies the padding of the DropDownList component. * * @default 'medium' */ size = DEFAULT_SIZE; /** * Specifies the adaptive mode of the internal `DropDownList` component. * * @default 'auto' */ adaptiveMode = 'auto'; /** * @hidden * * @readonly */ get classes() { return true; } _pageSizes = []; constructor(localization, cd, pagerContext, element, ngZone) { super(localization, pagerContext, cd); this.pagerContext = pagerContext; this.element = element; this.ngZone = ngZone; } ngAfterViewInit() { this.ngZone.runOutsideAngular(() => { this.element.nativeElement.addEventListener('keydown', this.keyDownHandler.bind(this), true); }); } ngOnDestroy() { this.element.nativeElement.removeEventListener('keydown', this.keyDownHandler); } /** * @hidden */ pageSizeChange(value, dropdownlist) { const event = new PageSizeChangeEvent(value); this.pagerContext.changePageSize(event); if (event.isDefaultPrevented()) { dropdownlist.writeValue(this.pageSize); } } onChanges({ total, skip, pageSize, isAllSelected }) { this.total = total; this.skip = skip; const normalizedPageSize = typeof pageSize === 'number' ? pageSize : this.total; this.pageSize = isAllSelected ? 'all' : normalizedPageSize; this.cd.markForCheck(); } keyDownHandler(ev) { if (ev.code === Keys.Escape && this.dropDownList.isOpen) { ev.stopPropagation(); this.dropDownList.toggle(false); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPageSizesComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: PagerContextService }, { token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PagerPageSizesComponent, isStandalone: true, selector: "kendo-datapager-page-sizes, kendo-pager-page-sizes", inputs: { showItemsText: "showItemsText", pageSizes: "pageSizes", size: "size", adaptiveMode: "adaptiveMode" }, host: { properties: { "class.k-pager-sizes": "this.classes" } }, viewQueries: [{ propertyName: "dropDownList", first: true, predicate: ["dropdownlist"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: ` <kendo-dropdownlist kendoPagerFocusable #dropdownlist [size]="size" [data]="_pageSizes" textField="text" valueField="value" [valuePrimitive]="true" [value]="pageSize" (valueChange)="pageSizeChange($event, dropdownlist)" [adaptiveMode]="adaptiveMode" [attr.aria-label]="textFor('itemsPerPage')"> </kendo-dropdownlist> @if (showItemsText) { {{ textFor('itemsPerPage') }} } `, isInline: true, dependencies: [{ kind: "component", type: DropDownListComponent, selector: "kendo-dropdownlist", inputs: ["customIconClass", "showStickyHeader", "icon", "svgIcon", "loading", "data", "value", "textField", "valueField", "adaptiveMode", "adaptiveTitle", "adaptiveSubtitle", "popupSettings", "listHeight", "defaultItem", "disabled", "itemDisabled", "readonly", "filterable", "virtual", "ignoreCase", "delay", "valuePrimitive", "tabindex", "tabIndex", "size", "rounded", "fillMode", "leftRightArrowsNavigation", "id"], outputs: ["valueChange", "filterChange", "selectionChange", "open", "opened", "close", "closed", "focus", "blur"], exportAs: ["kendoDropDownList"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerPageSizesComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'kendo-datapager-page-sizes, kendo-pager-page-sizes', template: ` <kendo-dropdownlist kendoPagerFocusable #dropdownlist [size]="size" [data]="_pageSizes" textField="text" valueField="value" [valuePrimitive]="true" [value]="pageSize" (valueChange)="pageSizeChange($event, dropdownlist)" [adaptiveMode]="adaptiveMode" [attr.aria-label]="textFor('itemsPerPage')"> </kendo-dropdownlist> @if (showItemsText) { {{ textFor('itemsPerPage') }} } `, standalone: true, imports: [DropDownListComponent, PagerFocusableDirective] }] }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: PagerContextService }, { type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { dropDownList: [{ type: ViewChild, args: ['dropdownlist', { static: true }] }], showItemsText: [{ type: Input }], pageSizes: [{ type: Input }], size: [{ type: Input }], adaptiveMode: [{ type: Input }], classes: [{ type: HostBinding, args: ["class.k-pager-sizes"] }] } }); /** * Represents the Kendo UI Pager template directive for Angular. * Use this directive to customize the Pager appearance. To define a Pager template, nest an `<ng-template>` tag with the `kendoPagerTemplate` directive inside `<kendo-pager>`. * * The template context provides the following fields: * * * `currentPage`&mdash;The index of the displayed page. * * `pageSize`&mdash;The value of the current `pageSize`. * * `skip`&mdash;The current skip value. * * `total`&mdash;The total number of records. * * `totalPages`&mdash;The total number of available pages. * * @example * ```html * <kendo-pager [skip]="0" [pageSize]="10" [total]="100"> * <ng-template kendoPagerTemplate let-currentPage="currentPage" let-pageSize="pageSize" let-skip="skip" let-total="total" let-totalPages="totalPages"> * <span>Page {{currentPage}} of {{totalPages}}</span> * <span>Items per page: {{pageSize}}</span> * </ng-template> * </kendo-pager> * ``` */ class PagerTemplateDirective { templateRef; constructor(templateRef) { this.templateRef = templateRef; } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerTemplateDirective, deps: [{ token: i0.TemplateRef, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: PagerTemplateDirective, isStandalone: true, selector: "[kendoDataPagerTemplate], [kendoPagerTemplate]", ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerTemplateDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoDataPagerTemplate], [kendoPagerTemplate]', standalone: true }] }], ctorParameters: () => [{ type: i0.TemplateRef, decorators: [{ type: Optional }] }] }); /** * Represents the Kendo UI Pager Numeric Buttons component for Angular. Displays numeric buttons to enable navigation between the pages. * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <ng-template kendoPagerTemplate> * <kendo-pager-numeric-buttons [buttonCount]="5"></kendo-pager-numeric-buttons> * </ng-template> * </kendo-pager> * ``` */ class PagerNumericButtonsComponent extends PagerElementComponent { pagerContext; renderer; selectElement; numbersElement; /** * Specifies the count of the displayed buttons. * * @type {number} * @memberOf PagerNumericButtonsComponent */ buttonCount; /** * Specifies the padding of the numeric buttons. * * @default 'medium' */ set size(size) { const newSize = size ? size : DEFAULT_SIZE; this.handleClasses(newSize, 'size'); this._size = newSize; } get size() { return this._size; } /** * @hidden * * @readonly * @type {number[]} * @memberOf PagerNumericButtonsComponent */ get buttons() { const result = []; for (let idx = this.start; idx <= this.end; idx++) { result.push(idx); } return result; } /** * @hidden */ get end() { return Math.min((this.start + this.buttonCount) - 1, this.totalPages); } /** * @hidden */ get start() { const page = this.currentPage; const buttonCount = this.buttonCount; if (page > buttonCount) { const reminder = (page % buttonCount); return (reminder === 0) ? (page - buttonCount) + 1 : (page - reminder) + 1; } return 1; } constructor(localization, cd, pagerContext, renderer) { super(localization, pagerContext, cd); this.pagerContext = pagerContext; this.renderer = renderer; } _size = DEFAULT_SIZE; ngAfterViewInit() { this.handleClasses(this.size, 'size'); } /** * @hidden */ pageLabel(num) { const pageText = this.textFor('page'); if (pageText) { return pageText + ' ' + num; } return num.toString(); } /** * @hidden */ onSelectChange(e) { const target = e.target; const valueAsNumber = Number(target.value); if (!Number.isNaN(valueAsNumber)) { this.changePage(valueAsNumber - 1); } else { if (target.value === 'previousButtons') { this.changePage(this.start - 2); } else { this.changePage(this.end); } } } onChanges({ total, skip, pageSize }) { this.total = total; this.skip = skip; this.pageSize = pageSize; this.cd.markForCheck(); } get pageChooserLabel() { return this.textFor('selectPage'); } handleClasses(value, input) { const elem = this.selectElement?.nativeElement; const classes = getStylingClasses('picker', input, this[input], value); if (!elem) { return; } if (classes.toRemove) { this.renderer.removeClass(elem, classes.toRemove); } if (classes.toAdd) { this.renderer.addClass(elem, classes.toAdd); } } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNumericButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: i0.ChangeDetectorRef }, { token: PagerContextService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.14", type: PagerNumericButtonsComponent, isStandalone: true, selector: "kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons", inputs: { buttonCount: "buttonCount", size: "size" }, viewQueries: [{ propertyName: "selectElement", first: true, predicate: ["select"], descendants: true, read: ElementRef }, { propertyName: "numbersElement", first: true, predicate: ["numbers"], descendants: true, read: ElementRef }], usesInheritance: true, ngImport: i0, template: ` <div class="k-pager-numbers" #numbers> @if (start > 1) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(start - 1)" [attr.title]="pageLabel(start - 1)" (click)="changePage(start - 2)">...</button> } @for (num of buttons; track num) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(num)" [attr.title]="pageLabel(num)" [attr.aria-current]="currentPage === num ? 'page' : undefined" [selected]="currentPage === num" (click)="currentPage === num ? false : changePage(num - 1)"> {{num}} </button> } @if (end < totalPages) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(end + 1)" [attr.title]="pageLabel(end + 1)" (click)="changePage(end)">...</button> } </div> `, isInline: true, dependencies: [{ kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }, { kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNumericButtonsComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'kendo-datapager-numeric-buttons, kendo-pager-numeric-buttons', template: ` <div class="k-pager-numbers" #numbers> @if (start > 1) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(start - 1)" [attr.title]="pageLabel(start - 1)" (click)="changePage(start - 2)">...</button> } @for (num of buttons; track num) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(num)" [attr.title]="pageLabel(num)" [attr.aria-current]="currentPage === num ? 'page' : undefined" [selected]="currentPage === num" (click)="currentPage === num ? false : changePage(num - 1)"> {{num}} </button> } @if (end < totalPages) { <button type="button" kendoPagerFocusable kendoButton [size]="size" fillMode="flat" themeColor="primary" rounded="none" [attr.aria-label]="pageLabel(end + 1)" [attr.title]="pageLabel(end + 1)" (click)="changePage(end)">...</button> } </div> `, standalone: true, imports: [PagerFocusableDirective, ButtonComponent] }] }], ctorParameters: () => [{ type: i1.LocalizationService }, { type: i0.ChangeDetectorRef }, { type: PagerContextService }, { type: i0.Renderer2 }], propDecorators: { selectElement: [{ type: ViewChild, args: ['select', { read: ElementRef }] }], numbersElement: [{ type: ViewChild, args: ['numbers', { read: ElementRef }] }], buttonCount: [{ type: Input }], size: [{ type: Input }] } }); // eslint-disable no-access-missing-member /** * Represents the Kendo UI Pager Next Buttons component for Angular. Displays buttons for navigating to the next and to the last page ([see example]({% slug pager_settings %})). * * @example * ```html * <kendo-pager [skip]="skip" [pageSize]="pageSize" [total]="total"> * <ng-template kendoPagerTemplate> * <kendo-pager-next-buttons></kendo-pager-next-buttons> * </ng-template> * </kendo-pager> * ``` */ class PagerNextButtonsComponent extends PagerElementComponent { /** * @hidden * * @readonly * @type {boolean} * @memberOf PagerNextButtonsComponent */ get disabled() { return this.currentPage === this.totalPages || !this.total; } /** * Specifies the padding of the navigation buttons. * * @default 'medium' */ size = DEFAULT_SIZE; constructor(localization, pagerContext, cd) { super(localization, pagerContext, cd); } /** * @hidden */ onClick(isLast = false) { if (this.disabled) { return false; } const targetPage = isLast ? this.totalPages - 1 : this.currentPage; return this.currentPage !== this.totalPages ? this.changePage(targetPage) : false; } onChanges({ total, skip, pageSize }) { this.total = total; this.skip = skip; this.pageSize = pageSize; this.cd.markForCheck(); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNextButtonsComponent, deps: [{ token: i1.LocalizationService }, { token: PagerContextService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.14", type: PagerNextButtonsComponent, isStandalone: true, selector: "kendo-datapager-next-buttons, kendo-pager-next-buttons", inputs: { size: "size" }, usesInheritance: true, ngImport: i0, template: ` <button kendoButton kendoPagerFocusable type="button" [size]="size" [icon]="nextArrowIcons[0]" [svgIcon]="nextArrowSVGIcons[0]" fillMode="flat" rounded="none" class="k-pager-nav" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [title]="textFor('nextPage')" [attr.aria-label]="textFor('nextPage')" (click)="onClick()"> </button> <button kendoButton kendoPagerFocusable type="button" [size]="size" [icon]="nextArrowIcons[1]" [svgIcon]="nextArrowSVGIcons[1]" fillMode="flat" rounded="none" class="k-pager-nav k-pager-last" [attr.aria-disabled]="disabled" [class.k-disabled]="disabled" [title]="textFor('lastPage')" [attr.aria-label]="textFor('lastPage')" (click)="onClick(true)"> </button> `, isInline: true, dependencies: [{ kind: "component", type: ButtonComponent, selector: "button[kendoButton]", inputs: ["arrowIcon", "toggleable", "togglable", "selected", "tabIndex", "imageUrl", "iconClass", "icon", "disabled", "size", "rounded", "fillMode", "themeColor", "svgIcon", "primary", "look"], outputs: ["selectedChange", "click"], exportAs: ["kendoButton"] }, { kind: "directive", type: PagerFocusableDirective, selector: "[kendoPagerFocusable]", exportAs: ["kendoPagerFocusable"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: PagerNextButtonsComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'kendo-datapager-