UNPKG

@progress/kendo-angular-layout

Version:

Kendo UI for Angular Layout Package - a collection of components to create professional application layoyts

177 lines (176 loc) 8.11 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { DEFAULT_SCROLL_BEHAVIOR } from './constants'; import { Injectable, NgZone } from '@angular/core'; import { isDocumentAvailable } from '@progress/kendo-angular-common'; import { Subject } from 'rxjs'; import { getActiveTab, isTablistHorizontal } from './util'; import { LocalizationService } from '@progress/kendo-angular-l10n'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-l10n"; /** * @hidden */ export class ScrollService { ngZone; localization; owner; position = 0; scrollButtonActiveStateChange = new Subject(); get tablistElement() { return this.owner.tablist.nativeElement; } get tabstripSize() { const hostElement = this.owner.wrapper.nativeElement; const wrapperWidth = parseFloat(getComputedStyle(hostElement).width); const wrapperHeight = parseFloat(getComputedStyle(hostElement).height); return isTablistHorizontal(this.owner.tabPosition) ? wrapperWidth : wrapperHeight; } get tablistOverflowSize() { if (!isDocumentAvailable()) { return 0; } const isHorizontal = isTablistHorizontal(this.owner.tabPosition); const overflowSize = Math.floor(this.tablistElement[isHorizontal ? 'scrollWidth' : 'scrollHeight'] - this.tablistElement.getBoundingClientRect()[isHorizontal ? 'width' : 'height']); return overflowSize < 0 ? 0 : overflowSize; } get tabsOverflow() { return this.tablistOverflowSize > 0; } constructor(ngZone, localization) { this.ngZone = ngZone; this.localization = localization; } toggleScrollButtonsState() { const tabStrip = this.owner; if (!tabStrip.hasScrollButtons) { return; } const currentPrevButtonActive = !this.isDisabled('prev'); const currentNextButtonActive = !this.isDisabled('next'); const isHorizontal = isTablistHorizontal(this.owner.tabPosition); const rtlDelta = this.localization.rtl && isHorizontal ? -1 : 1; const calculatedPrevButtonActive = (this.position * rtlDelta) > 0 && this.tablistOverflowSize > 0; const calculatedNextButtonActive = (this.position * rtlDelta) < this.tablistOverflowSize && this.tablistOverflowSize > 0; if (calculatedPrevButtonActive !== currentPrevButtonActive) { this.ngZone.run(() => this.toggleButtonActiveState('prev', calculatedPrevButtonActive)); } if (calculatedNextButtonActive !== currentNextButtonActive) { this.ngZone.run(() => this.toggleButtonActiveState('next', calculatedNextButtonActive)); } } scrollToSelectedTab() { if (!this.tabsOverflow) { return; } const { index: activeIndex } = getActiveTab(this.owner.tabs); if (activeIndex === -1) { return; } this.position += this.getScrollOffset(activeIndex); if (isTablistHorizontal(this.owner.tabPosition)) { this.tablistElement.scrollLeft = this.position; } else { this.tablistElement.scrollTop = this.position; } this.toggleScrollButtonsState(); const tabStrip = this.owner; if (!tabStrip.hasScrollButtons) { return; } const isFirstTabActive = activeIndex === 0; const isLastTabActive = activeIndex === this.owner.tabs.length - 1; if (isFirstTabActive && !this.isDisabled('prev')) { this.ngZone.run(() => this.toggleButtonActiveState('prev', false)); } if (isLastTabActive && !this.isDisabled('next')) { this.ngZone.run(() => this.toggleButtonActiveState('next', false)); } } getScrollOffset(activeIndex) { if (!isDocumentAvailable()) { return 0; } const isHorizontal = isTablistHorizontal(this.owner.tabPosition); this.tablistElement[`scroll${isHorizontal ? 'Left' : 'Top'}`] = this.position; const activeTabRect = this.tablistElement.children[activeIndex].getBoundingClientRect(); const tablistRect = this.tablistElement.getBoundingClientRect(); const end = isHorizontal ? 'right' : 'bottom'; const start = isHorizontal ? 'left' : 'top'; const activeTabStart = activeTabRect[start]; const activeTabEnd = activeTabRect[end]; const tablistStart = tablistRect[start]; const tablistEnd = tablistRect[end]; const tabEndIsInVisibleRange = activeTabEnd <= tablistEnd; const tabStartIsInVisibleRange = activeTabStart >= tablistStart; const isWholeTabVisible = tabEndIsInVisibleRange && tabStartIsInVisibleRange; if (isWholeTabVisible) { return 0; } if (!tabEndIsInVisibleRange) { return activeTabEnd - tablistEnd; } if (!tabStartIsInVisibleRange) { return activeTabStart - tablistStart; } } onScroll(e) { this.position = isTablistHorizontal(this.owner.tabPosition) ? e.target.scrollLeft : e.target.scrollTop; this.toggleScrollButtonsState(); } scrollTabs(direction) { this.calculateListPosition(direction, this.owner.scrollable.buttonScrollSpeed); if (isTablistHorizontal(this.owner.tabPosition) && this.tablistElement) { this.tablistElement.scrollTo({ left: this.position, behavior: DEFAULT_SCROLL_BEHAVIOR }); } else { this.tablistElement.scrollTo({ top: this.position, behavior: DEFAULT_SCROLL_BEHAVIOR }); } this.toggleScrollButtonsState(); } calculateListPosition(direction, scrollSpeed) { const isHorizontal = isTablistHorizontal(this.owner.tabPosition); if (direction === 'prev') { if (this.localization.rtl && isHorizontal) { this.position = this.position + scrollSpeed >= 0 ? 0 : this.position + scrollSpeed; } else { this.position = this.position - scrollSpeed <= 0 ? 0 : this.position - scrollSpeed; } } else if (direction === 'next' && this.position < this.tablistOverflowSize) { if (this.position + scrollSpeed > this.tablistOverflowSize) { this.position = this.tablistOverflowSize; return; } if (this.localization.rtl && isHorizontal) { this.position -= scrollSpeed; } else { this.position += scrollSpeed; } } } restoreScrollPosition() { if (isTablistHorizontal(this.owner.tabPosition)) { this.tablistElement.scrollLeft = this.position; } else { this.tablistElement.scrollTop = this.position; } this.toggleScrollButtonsState(); } toggleButtonActiveState(buttonType, active) { this.scrollButtonActiveStateChange.next({ buttonType, active }); } isDisabled = (buttonType) => this.owner[`${buttonType}ScrollButton`]?.host.nativeElement.classList.contains('k-disabled'); static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ScrollService, deps: [{ token: i0.NgZone }, { token: i1.LocalizationService }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ScrollService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ScrollService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.NgZone }, { type: i1.LocalizationService }]; } });