Your IP : 216.73.216.86


Current Path : /var/www/homesaver/www/bitrix/js/ui/text-editor/src/plugins/file/video/
Upload File :
Current File : /var/www/homesaver/www/bitrix/js/ui/text-editor/src/plugins/file/video/file-video-component.js

import type { JsonObject } from 'main.core';
import { Dom, Tag, Type } from 'main.core';
import { type BaseCache, MemoryCache } from 'main.core.cache';
import type { BaseEvent } from 'main.core.events';
import { $getNodeByKey } from 'ui.lexical.core';
import type { EditorConfig } from 'ui.lexical.core';

import DecoratorComponent from '../../../decorator-component';
import { calcImageSize } from '../../../helpers/calc-image-size';
import FigureResizer from '../../../helpers/figure-resizer';
import type { DecoratorComponentOptions } from '../../../types/decorator-component-options';
import { $isFileVideoNode, FileVideoNode } from './file-video-node';

export class FileVideoComponent extends DecoratorComponent
{
	#refs: BaseCache<HTMLElement> = new MemoryCache();
	#figureResizer: FigureResizer = null;

	constructor(options: DecoratorComponentOptions)
	{
		super(options);

		this.#figureResizer = new FigureResizer({
			target: this.#getVideo(),
			editor: this.getEditor(),
			minWidth: 120,
			minHeight: 120,
			events: {
				onResize: this.#handleResize.bind(this),
				onResizeEnd: this.#handleResizeEnd.bind(this),
			},
		});

		this.getNodeSelection().onSelect((selected: boolean) => {
			if (selected || this.#figureResizer.isResizing())
			{
				Dom.addClass(this.#getContainer(), '--selected');
				this.#figureResizer.show();
			}
			else
			{
				Dom.removeClass(this.#getContainer(), '--selected');
				this.#figureResizer.hide();
			}

			this.#setDraggable(selected);
		});

		this.update(this.getOptions());
		this.#render();
	}

	#render()
	{
		Dom.append(this.#getContainer(), this.getTarget());
	}

	#getContainer(): HTMLElement
	{
		return this.#refs.remember('container', () => {
			return Tag.render`
				<div class="ui-text-editor-video-component">
					<div class="ui-text-editor-video-object-container">${this.#getVideo()}</div>
					${this.#figureResizer.getContainer()}
				</div>
			`;
		});
	}

	#getVideo(): HTMLIFrameElement | HTMLVideoElement
	{
		return this.#refs.remember('video', () => {
			const video: HTMLVideoElement = Dom.create({
				tag: 'video',
				attrs: {
					controls: true,
					preload: 'metadata',
					playsinline: true,
					src: this.getOption('src'),
				},
				events: {
					loadedmetadata: (event: Event) => {
						this.getEditor().update(() => {
							const node: FileVideoNode = $getNodeByKey(this.getNodeKey());
							if ($isFileVideoNode(node) && node.getWidth() === 0)
							{
								const [width, height] = calcImageSize(
									event.target.videoWidth,
									event.target.videoHeight,
									600,
									600,
								);

								node.setWidthAndHeight(width, height);
							}
						});
					},
				},
			});

			const config: EditorConfig = this.getOption('config', {});
			if (config?.theme?.video?.object)
			{
				video.className = config.theme.video.object;
			}

			return video;
		});
	}

	#handleResize(event: BaseEvent): void
	{
		this.update(event.getData());
	}

	#handleResizeEnd(event: BaseEvent): void
	{
		this.setSelected(true);

		this.getEditor().update(() => {
			const node: FileVideoNode = $getNodeByKey(this.getNodeKey());
			if ($isFileVideoNode(node))
			{
				const { width, height } = event.getData();
				node.setWidthAndHeight(width, height);
			}
		});
	}

	#setDraggable(draggable: boolean): void
	{
		Dom.attr(this.#getContainer(), { draggable });
		if (draggable)
		{
			Dom.addClass(this.#getContainer(), '--draggable');
		}
		else
		{
			Dom.removeClass(this.#getContainer(), '--draggable');
		}
	}

	update(options: JsonObject): void
	{
		const width = Type.isNumber(options.width) && options.width > 0 ? options.width : null;
		const height = Type.isNumber(options.height) && options.height > 0 ? options.height : null;
		const aspectRatio = width > 0 && height > 0 ? `${width} / ${height}` : 'auto';

		Dom.adjust(this.#getVideo(), {
			attrs: {
				width,
				height: null,
			},
			style: {
				width,
				height: 'auto',
				aspectRatio,
			},
		});
	}
}