Server IP : 80.87.202.40 / Your IP : 216.73.216.169 Web Server : Apache System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64 User : bitrix ( 600) PHP Version : 8.2.27 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/ui/text-editor/src/helpers/ |
Upload File : |
import { Type, Tag, Dom, Event } from 'main.core'; import { EventEmitter } from 'main.core.events'; import { type TextEditor } from '../text-editor'; function clamp(value: number, min: number, max: number): number { return Math.min(Math.max(value, min), max); } const Direction = { EAST: 1, SOUTH: 2, WEST: 4, NORTH: 8, }; import './figure-resizer.css'; export default class FigureResizer extends EventEmitter { #positioning = { currentHeight: 0, currentWidth: 0, direction: 0, isResizing: false, ratio: 0, startHeight: 0, startWidth: 0, startX: 0, startY: 0, }; #freeTransform: boolean = false; #onPointerDownHandler: Function = null; #onPointerMoveHandler: Function = null; #onPointerUpHandler: Function = null; #container: HTMLElement = null; #target: HTMLElement = null; #editor: TextEditor = null; #maxWidth: 'none' | number = 'none'; #maxHeight: 'none' | number = 'none'; #minWidth: number = 16; #minHeight: number = 16; constructor({ target, editor, originalWidth, originalHeight, minWidth, minHeight, maxWidth, maxHeight, events, freeTransform, }) { super(); this.setEventNamespace('BX.UI.TextEditor.FigureResizer'); this.#target = target; this.#editor = editor; this.#minWidth = Math.min( Math.max(this.#minWidth, Type.isNumber(minWidth) ? minWidth : this.#minWidth), Type.isNumber(originalWidth) ? originalWidth : Infinity, ); this.#minHeight = Math.min( Math.max(this.#minHeight, Type.isNumber(minHeight) ? minHeight : this.#minHeight), Type.isNumber(originalHeight) ? originalHeight : Infinity, ); this.#maxWidth = Type.isNumber(maxWidth) ? maxWidth : 'none'; this.#maxHeight = Type.isNumber(maxHeight) ? maxHeight : 'none'; this.#freeTransform = freeTransform === true; this.#onPointerDownHandler = this.#handlePointerDown.bind(this); this.#onPointerMoveHandler = this.#handlePointerMove.bind(this); this.#onPointerUpHandler = this.#handlePointerUp.bind(this); this.subscribeFromOptions(events); } show(): void { Dom.addClass(this.getContainer(), '--shown'); } hide(): void { Dom.removeClass(this.getContainer(), '--shown'); } getContainer(): HTMLElement { if (this.#container === null) { const freeTransform = Tag.render` <div class="ui-text-editor-figure-resizer-handle --north" data-direction="${Direction.NORTH}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --east" data-direction="${Direction.EAST}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --south" data-direction="${Direction.SOUTH}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --west" data-direction="${Direction.WEST}" onpointerdown="${this.#onPointerDownHandler}" ></div> `; this.#container = Tag.render` <div class="ui-text-editor-figure-resizer"> <div class="ui-text-editor-figure-resizer-handle --north-east" data-direction="${Direction.NORTH | Direction.EAST}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --south-east" data-direction="${Direction.SOUTH | Direction.EAST}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --south-west" data-direction="${Direction.SOUTH | Direction.WEST}" onpointerdown="${this.#onPointerDownHandler}" ></div> <div class="ui-text-editor-figure-resizer-handle --north-west" data-direction="${Direction.NORTH | Direction.WEST}" onpointerdown="${this.#onPointerDownHandler}" ></div> ${this.#freeTransform ? freeTransform : null} </div> `; } return this.#container; } getTarget(): HTMLElement { return this.#target; } setTarget(target: HTMLElement): void { this.#target = target; } getEditor(): TextEditor { return this.#editor; } isResizing(): boolean { return this.#positioning.isResizing; } #handlePointerDown(event: PointerEvent) { if (!this.getEditor().isEditable()) { return; } event.preventDefault(); const direction: number = Number(event.target.dataset.direction); const target = this.getTarget(); const { width, height } = target.getBoundingClientRect(); this.#positioning.startWidth = width; this.#positioning.startHeight = height; this.#positioning.ratio = width / height; this.#positioning.currentWidth = width; this.#positioning.currentHeight = height; this.#positioning.startX = event.clientX; this.#positioning.startY = event.clientY; this.#positioning.isResizing = true; this.#positioning.direction = direction; // setStartCursor(direction); this.emit('onResizeStart'); Dom.addClass(this.getContainer(), '--resizing'); Dom.style(target, { width: `${width}px`, height: `${height}px`, }); Event.bind(document, 'pointermove', this.#onPointerMoveHandler); Event.bind(document, 'pointerup', this.#onPointerUpHandler); } #handlePointerMove(event: PointerEvent) { const target = this.getTarget(); const isHorizontal = this.#positioning.direction & (Direction.EAST | Direction.WEST); const isVertical = this.#positioning.direction & (Direction.SOUTH | Direction.NORTH); if (this.#positioning.isResizing) { // Corner cursor if (isHorizontal && isVertical) { let diff = Math.floor(this.#positioning.startX - event.clientX); diff = this.#positioning.direction & Direction.EAST ? -diff : diff; const width = Math.round(clamp( this.#positioning.startWidth + diff, this.#minWidth, this.#getMaxContainerWidth(), )); const height = Math.ceil(width / this.#positioning.ratio); Dom.style(target, { width: `${width}px`, height: `${height}px`, }); this.emit('onResize', { width, height }); this.#positioning.currentHeight = height; this.#positioning.currentWidth = width; } else if (isVertical) { let diff = Math.floor(this.#positioning.startY - event.clientY); diff = this.#positioning.direction & Direction.SOUTH ? -diff : diff; const height = Math.round(Math.max( this.#positioning.startHeight + diff, this.#minHeight, // this.#getMaxContainerHeight(), )); Dom.style(target, 'height', `${height}px`); this.emit('onResize', { width: this.#positioning.currentWidth, height }); this.#positioning.currentHeight = height; } else { let diff = Math.floor(this.#positioning.startX - event.clientX); diff = this.#positioning.direction & Direction.EAST ? -diff : diff; const width = Math.round(clamp( this.#positioning.startWidth + diff, this.#minWidth, this.#getMaxContainerWidth(), )); Dom.style(target, 'width', `${width}px`); this.emit('onResize', { width, height: this.#positioning.currentHeight }); this.#positioning.currentWidth = width; } } } #handlePointerUp() { if (this.#positioning.isResizing) { setTimeout(() => { const width: number = this.#positioning.currentWidth; const height: number = this.#positioning.currentHeight; this.#positioning.startWidth = 0; this.#positioning.startHeight = 0; this.#positioning.ratio = 0; this.#positioning.startX = 0; this.#positioning.startY = 0; this.#positioning.currentWidth = 0; this.#positioning.currentHeight = 0; this.#positioning.isResizing = false; Dom.removeClass(this.getContainer(), '--resizing'); this.emit('onResizeEnd', { width, height }); // setEndCursor(); Event.unbind(document, 'pointermove', this.#onPointerMoveHandler); Event.unbind(document, 'pointerup', this.#onPointerUpHandler); }, 200); } } #getMaxContainerWidth(): number { const maxWidth = Type.isNumber(this.#maxWidth) ? this.#maxWidth : Infinity; const editorRootElement = this.getEditor().getRootElement(); if (editorRootElement !== null) { return Math.min(editorRootElement.getBoundingClientRect().width - 20, maxWidth); } return 100; } #getMaxContainerHeight(): number { if (Type.isNumber(this.#maxHeight)) { return this.#maxHeight; } const editorRootElement = this.getEditor().getRootElement(); if (editorRootElement !== null) { return editorRootElement.getBoundingClientRect().height - 20; } return 100; } }