UNPKG

@progress/kendo-angular-dialog

Version:
336 lines (335 loc) 11.5 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Injectable, NgZone, EventEmitter } from "@angular/core"; import { Subscription } from 'rxjs'; import { tap, map, switchMap, takeUntil, take } from 'rxjs/operators'; import { isPresent, OFFSET_STYLES, preventDefault } from '../common/util'; import { scrollPosition, offset, getDocumentElement, positionWithScroll, getWindowViewPort } from '@progress/kendo-popup-common'; import * as i0 from "@angular/core"; /** * @hidden */ let newZIndex = 10002; /** * @hidden */ const DEFAULT_OPTIONS = { draggable: true, height: null, left: null, minHeight: 100, minWidth: 120, position: 'absolute', resizable: true, state: 'default', top: null, width: null }; /** * @hidden */ const createMoveStream = (el, ev) => mouseDown => { return el.kendoDrag .pipe(takeUntil(el.kendoRelease.pipe(tap(() => { ev.emit(); }))), map(({ pageX, pageY }) => ({ originalX: mouseDown.pageX, originalY: mouseDown.pageY, pageX, pageY }))); }; /** * @hidden */ export class DragResizeService { ngZone; close = new EventEmitter(); focus = new EventEmitter(); change = new EventEmitter(); stateChange = new EventEmitter(); dragStart = new EventEmitter(); dragEnd = new EventEmitter(); resizeStart = new EventEmitter(); resizeEnd = new EventEmitter(); options = Object.assign({}, DEFAULT_OPTIONS); restoreOptions; window; lastAction = null; subscriptions = new Subscription(); dragSubscription = new Subscription(); constructor(ngZone) { this.ngZone = ngZone; } ngOnDestroy() { if (this.subscriptions) { this.subscriptions.unsubscribe(); } if (this.dragSubscription) { this.dragSubscription.unsubscribe(); } } init(el) { const state = this.options.state; const options = this.options; this.window = el; if (state !== 'default') { this.restoreOptions = Object.assign({}, options); } if (state === 'minimized') { options.height = 0; options.minHeight = 0; } if (state === 'maximized') { options.position = 'fixed'; } } onDrag(el) { this.subscriptions.add(this.ngZone.runOutsideAngular(() => { let startPosition; let dragStarted; this.dragSubscription = el.kendoPress .pipe(tap((ev) => { if (!ev.isTouch) { preventDefault(ev); } this.focus.emit(); startPosition = this.currentPosition(); dragStarted = false; }), switchMap(createMoveStream(el, this.dragEnd))) .subscribe(({ pageX, pageY, originalX, originalY }) => { if (!dragStarted) { this.ensureWidth(); this.dragStart.emit(); dragStarted = true; } this.handleDrag({ originalX, originalY, pageX, pageY, startPosition }); }); })); } handleDrag({ originalX, originalY, pageX, pageY, startPosition }) { this.options.left = startPosition.x + pageX - originalX; this.options.top = startPosition.y + pageY - originalY; if (this.options.state === 'minimized' && isPresent(this.restoreOptions)) { this.restoreOptions.left = this.options.left; this.restoreOptions.top = this.options.top; } this.change.emit({ left: startPosition.x + pageX - originalX, top: startPosition.y + pageY - originalY }); } onResize(handle, direction) { this.subscriptions.add(this.ngZone.runOutsideAngular(() => { let startOffsetAndPosition; let resizeStarted = false; handle.kendoPress.pipe(tap((ev) => { preventDefault(ev); this.focus.emit(); startOffsetAndPosition = this.currentOffsetAndPosition(); resizeStarted = false; }), switchMap(createMoveStream(handle, this.resizeEnd))) .subscribe(({ pageX, pageY, originalX, originalY }) => { if (!resizeStarted) { this.resizeStart.emit(direction); resizeStarted = true; } const deltaX = pageX - originalX; const deltaY = pageY - originalY; this.handleResize(startOffsetAndPosition, direction, deltaX, deltaY); }); })); } handleResize(initial, dir, deltaX, deltaY) { const old = this.options; const ev = {}; if (dir.indexOf('e') >= 0) { const newWidth = initial.width + deltaX; if (newWidth !== old.width && newWidth >= old.minWidth) { ev.width = newWidth; } } if (dir.indexOf('n') >= 0) { const newHeight = initial.height - deltaY; const newTop = initial.y + deltaY; if (newHeight !== old.height && newHeight >= old.minHeight && newTop !== old.top) { ev.height = newHeight; ev.top = newTop; } } if (dir.indexOf('s') >= 0) { const newHeight = initial.height + deltaY; if (newHeight !== old.height && newHeight >= old.minHeight) { ev.height = newHeight; } } if (dir.indexOf('w') >= 0) { const newLeft = initial.x + deltaX; const newWidth = initial.width - deltaX; if (newWidth !== old.width && newWidth >= old.minWidth && newLeft !== old.left) { ev.width = newWidth; ev.left = newLeft; } } if (isPresent(ev.width) || isPresent(ev.height)) { OFFSET_STYLES.forEach((style) => { if (isPresent(ev[style])) { this.options[style] = ev[style]; } }); this.change.emit(ev); } } restoreAction() { this.lastAction = 'restore'; this.defaultState(); } defaultState() { if (isPresent(this.restoreOptions)) { this.options = Object.assign({}, this.restoreOptions); } this.options.state = 'default'; this.ngZone.onStable.pipe(take(1)).subscribe(() => { if (!isPresent(this.options.left) || !isPresent(this.options.top)) { this.center(); } }); this.stateChange.emit('default'); } storeOptions() { this.restoreOptions = Object.assign({}, this.options); } maximizeAction() { this.lastAction = 'maximize'; this.maximizeState(); } maximizeState() { this.storeOptions(); const wnd = this.windowViewPort; this.options = Object.assign({}, this.options, { height: wnd.height, left: 0, position: 'fixed', state: 'maximized', top: 0, width: wnd.width }); this.stateChange.emit('maximized'); } minimizeAction() { this.lastAction = 'minimize'; this.minimizeState(); } minimizeState() { this.storeOptions(); this.options = Object.assign({}, this.options, { height: null, minHeight: 0, state: 'minimized' }); this.stateChange.emit('minimized'); } /** * Handles manual changes of the 'state' property. * Required to distinguish them from action clicks. */ applyManualState() { const state = this.options.state; switch (state) { case 'default': this.clearHeight(); this.defaultState(); break; case 'maximized': this.clearHeight(); this.maximizeState(); break; case 'minimized': this.minimizeState(); break; default: break; } } closeAction() { this.close.emit(); } ensureWidth() { const windowOffset = offset(this.window.nativeElement); if (!isPresent(this.options.width)) { this.options.width = windowOffset.width; this.change.emit({ width: windowOffset.width }); } } clearHeight() { if (this.options.height === 0) { delete this.options.height; } if (this.options.minHeight === 0) { delete this.options.minHeight; } } center() { if (this.options.state === 'maximized') { return; } const scroll = scrollPosition(this.window.nativeElement); const wnd = this.windowViewPort; const wrapper = offset(this.window.nativeElement); const ev = {}; if (!isPresent(this.options.left)) { this.options.left = scroll.x + Math.max(0, (wnd.width - wrapper.width) / 2); ev.left = this.options.left; } if (!isPresent(this.options.top)) { this.options.top = scroll.y + Math.max(0, (wnd.height - wrapper.height) / 2); ev.top = this.options.top; } this.change.emit(ev); } currentOffsetAndPosition() { const o = this.options; const off = offset(this.window.nativeElement); return Object.assign({}, this.currentPosition(), { height: o.height ? o.height : off.height, width: o.width ? o.width : off.width }); } currentPosition() { const o = this.options; if (!o.top || !o.left) { this.setPosition(); } return { x: this.options.left, y: this.options.top }; } setPosition() { const wrapper = positionWithScroll(this.window.nativeElement, getDocumentElement(this.window.nativeElement)); this.options.left = wrapper.left; this.options.top = wrapper.top; } setRestoreOption(style, value) { if (isPresent(this.restoreOptions)) { this.restoreOptions[style] = value; } } get nextPossibleZIndex() { return newZIndex; } get nextZIndex() { return newZIndex++; } get windowViewPort() { return getWindowViewPort(this.window.nativeElement); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragResizeService, deps: [{ token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragResizeService }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragResizeService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.NgZone }]; } });