Your IP : 3.148.112.15


Current Path : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/ui/stamp/uploader/src/
Upload File :
Current File : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/ui/stamp/uploader/src/uploader.js

import {EventEmitter, BaseEvent} from 'main.core.events';
import {Type, Cache, Tag, Dom, Reflection, Loc, Event} from 'main.core';
import {Uploader as FileUploader, UploaderFile, FileEvent, UploaderEvent, Helpers} from 'ui.uploader.core';
import 'ui.dialogs.messagebox';
import {Layout} from 'ui.sidepanel.layout';
import {Button} from 'ui.buttons';
import Header from './header/header';
import UploadLayout from './upload-layout/upload-layout';
import Dropzone from './dropzone/dropzone';
import ActionPanel from './action-panel/action-panel';
import Status from './status/status';
import Preview from './preview/preview';
import Message from './message/message';
import FileSelect from './file-select/file-select';

import './css/style.css';

export type ContactItem = {
	id: number | string,
	label: string,
	href?: string,
};

export type UploaderOptions = {
	controller: {
		upload: string,
	},
	mode: $Values<Uploader.Mode>,
	contact: ContactItem,
	contactsList: Array<ContactItem>,
	events: {
		[key: string]: (event: BaseEvent) => void,
	},
};

/**
 * @namespace BX.UI.Stamp
 */
export class Uploader extends EventEmitter
{
	static Mode = {
		SLIDER: 'slider',
		INLINE: 'inline',
	};

	cache = new Cache.MemoryCache();

	constructor(options: UploaderOptions)
	{
		super();
		this.setEventNamespace('BX.UI.Stamp.Uploader');
		this.subscribeFromOptions(options.events);
		this.setOptions(options);

		this.cache.remember('fileUploader', () => {
			const dropzoneLayout = this.getDropzone().getLayout();
			const previewLayout = this.getPreview().getLayout();
			const fileSelectButtonLayout = this.getFileSelect().getLayout();

			Event.bind(previewLayout, 'click', (event: MouseEvent) => {
				if (this.getPreview().isCropEnabled())
				{
					event.stopImmediatePropagation();
				}
			});

			const acceptedFileTypes = ['image/png', 'image/jpeg'];

			return new FileUploader({
				controller: this.getOptions().controller?.upload,
				assignAsFile: true,
				browseElement: [
					dropzoneLayout,
					previewLayout,
					fileSelectButtonLayout,
					this.getHiddenInput(),
				],
				dropElement: [
					dropzoneLayout,
					previewLayout,
				],
				imagePreviewHeight: 556,
				imagePreviewWidth: 1000,
				autoUpload: false,
				acceptedFileTypes,
				events: {
					[UploaderEvent.FILE_ADD]: (event: BaseEvent) => {
						const {file, error} = event.getData();

						if (
							Type.isNil(error)
							&& Helpers.isValidFileType(file.getBinary(), acceptedFileTypes)
						)
						{
							this.getPreview().show(file.getClientPreview());
							this.setUploaderFile(file);

							if (this.getMode() === Uploader.Mode.SLIDER)
							{
								this.getSliderButtons().saveButton.setDisabled(false);
								this.getActionPanel().enable();
							}

							if (this.getMode() === Uploader.Mode.INLINE)
							{
								this.getInlineSaveButton().setDisabled(false);
								this.getActionPanel().enable();
							}

							this.setIsChanged(true);
						}
					},
					[UploaderEvent.FILE_UPLOAD_PROGRESS]: (event: BaseEvent) => {
						const {progress, file} = event.getData();

						this.getStatus().updateUploadStatus({
							percent: progress,
							size: (file.getSize() / 100) * progress,
						});
					},
					[UploaderEvent.FILE_ERROR]: function(event: BaseEvent) {
						const {error} = event.getData();
						Uploader.showAlert(error.getMessage());
					},
				},
			});
		});
	}

	static showAlert(...args)
	{
		const TopMessageBox = Reflection.getClass('top.BX.UI.Dialogs.MessageBox');
		if (!Type.isNil(TopMessageBox))
		{
			TopMessageBox.alert(...args);
		}
	}

	static showConfirm(options: {[key: string]: any})
	{
		const TopMessageBox = Reflection.getClass('top.BX.UI.Dialogs.MessageBox');
		const TopMessageBoxButtons = Reflection.getClass('top.BX.UI.Dialogs.MessageBoxButtons');
		if (!Type.isNil(TopMessageBox))
		{
			TopMessageBox.show({
				modal: true,
				buttons: TopMessageBoxButtons.OK_CANCEL,
				...options,
			});
		}
	}

	setIsChanged(value: boolean)
	{
		this.cache.set('isChanged', value);
	}

	isChanged(): boolean
	{
		return this.cache.get('isChanged', false);
	}

	static #delay(callback: () => void, delay: number)
	{
		const timeoutId = setTimeout(() => {
			callback();
			clearTimeout(timeoutId);
		}, delay);
	}

	getFileUploader(): FileUploader
	{
		return this.cache.get('fileUploader');
	}

	setUploaderFile(file: UploaderFile)
	{
		this.cache.set('uploaderFile', file);
	}

	getUploaderFile(): UploaderFile
	{
		return this.cache.get('uploaderFile', null);
	}

	setOptions(options: UploaderOptions)
	{
		this.cache.set('options', {...options});
	}

	getOptions(): UploaderOptions
	{
		return this.cache.get('options', {});
	}

	getMode(): $Values<Uploader.Mode>
	{
		const {mode} = this.getOptions();
		if (Object.values(Uploader.Mode).includes(mode))
		{
			return mode;
		}

		return Uploader.Mode.SLIDER;
	}

	getHeader(): Header
	{
		return this.cache.remember('header', () => {
			return new Header(this.getOptions());
		});
	}

	getPreview(): Preview
	{
		return this.cache.remember('preview', () => {
			return new Preview({});
		});
	}

	getFileSelect(): FileSelect
	{
		return this.cache.remember('fileSelect', () => {
			return new FileSelect({
				events: {
					onTakePhotoClick: () => {
						this.emit('onTakePhotoClick');
					},
					onSelectPhotoClick: () => {

					},
				},
			});
		});
	}

	getUploadLayout(): UploadLayout
	{
		return this.cache.remember('uploadLayout', () => {
			return new UploadLayout({
				children: [
					(() => {
						if (this.getMode() === Uploader.Mode.INLINE)
						{
							return this.getFileSelect();
						}

						return this.getDropzone();
					})(),
					this.getActionPanel(),
					this.getStatus(),
					this.getPreview(),
				],
			});
		});
	}

	getDropzone(): Dropzone
	{
		return this.cache.remember('dropzone', () => {
			return new Dropzone({});
		});
	}

	getActionPanel(): ActionPanel
	{
		return this.cache.remember('actionPanel', () => {
			return new ActionPanel({
				events: {
					onCropClick: this.onCropClick.bind(this),
					onApplyClick: this.onCropApplyClick.bind(this),
					onCancelClick: this.onCropCancelClick.bind(this),
				},
			});
		});
	}

	onCropApplyClick()
	{
		this.getPreview().applyCrop();
		this.getPreview().disableCrop();
		this.getActionPanel().hideCropActions();
		this.getInlineSaveButton().setDisabled(false);
		this.getActionPanel().enable();
	}

	onCropCancelClick()
	{
		this.getPreview().disableCrop();
		this.getActionPanel().hideCropActions();
		this.getInlineSaveButton().setDisabled(false);
		this.getActionPanel().enable();
	}

	onCropClick()
	{
		this.getPreview().enableCrop();
		this.getActionPanel().showCropAction();
		this.getInlineSaveButton().setDisabled(true);
		this.getActionPanel().enable();
	}

	getStatus(): Status
	{
		return this.cache.remember('status', () => {
			return new Status();
		});
	}

	getLayout(): HTMLDivElement
	{
		return this.cache.remember('layout', () => {
			const mode = this.getMode();
			return Tag.render`
				<div class="ui-stamp-uploader ui-stamp-uploader-mode-${mode}">
					${(() => {
						if (mode === Uploader.Mode.SLIDER)
						{
							return this.getMessage().getLayout();
						}

						return '';
					})()}
					${this.getHeader().getLayout()}
					${this.getUploadLayout().getLayout()}
					${(() => {
						if (mode === Uploader.Mode.INLINE)
						{
							return Tag.render`
								<div class="ui-stamp-uploader-footer">
									${this.getInlineSaveButton().render()}
								</div>
							`;
						}

						return '';
					})()}
					${this.getHiddenInput()}
				</div>
			`;
		});
	}

	getHiddenInput(): HTMLInputElement
	{
		return this.cache.remember('hiddenInput', () => {
			return Tag.render`
				<input type="file" name="STAMP_UPLOADER_INPUT" hidden>
			`;
		});
	}

	renderTo(target: HTMLElement)
	{
		if (Type.isDomNode(target))
		{
			Dom.append(this.getLayout(), target);
		}
	}

	upload(): Promise<UploaderFile>
	{
		return new Promise((resolve) => {
			this.getPreview().getFile().then((blob) => {
				this.getFileUploader().addFile(blob);
				const [resultFile] = this.getFileUploader().getFiles();

				resultFile.subscribeOnce(FileEvent.LOAD_COMPLETE, () => {
					this.getPreview().hide();
					const { controller } = this.getOptions();
					if (!controller)
					{
						resolve(resultFile);
						return;
					}

					this.getStatus().showUploadStatus({reset: true});
					resultFile.upload({
						onComplete: () => {
							resolve(resultFile);
						},
						onError: console.error,
					});
				});
			});
		});
	}

	getMessage(): Message
	{
		return this.cache.remember('message', () => {
			return new Message();
		});
	}

	getInlineSaveButton(): Button
	{
		return this.cache.remember('inlineSaveButton', () => {
			const button = new Button({
				text: Loc.getMessage('UI_STAMP_UPLOADER_SAVE_BUTTON_LABEL'),
				color: Button.Color.PRIMARY,
				size: Button.Size.LARGE,
				round: true,
				onclick: () => {
					const saveButton = this.getInlineSaveButton();
					saveButton.setWaiting(true);

					this.upload()
						.then((uploaderFile) => {
							const { controller } = this.getOptions();
							if (!controller)
							{
								return this.emitAsync('onSaveAsync', {file: uploaderFile.toJSON()});
							}

							return Promise.all([
								new Promise((resolve) => {
									Uploader.#delay(() => {
										this.getPreview().show(uploaderFile.getClientPreview());
										this.getStatus().showPreparingStatus();
										resolve();
									}, 1000);
								}),
								this.emitAsync('onSaveAsync', {file: uploaderFile.toJSON()}),
							]);
						})
						.then(() => {
							this.getStatus().hide();

							Uploader.#delay(() => {
								saveButton.setWaiting(false);
								saveButton.setDisabled(true);
								this.getActionPanel().disable();
							}, 500);
						});
				},
			});

			button.setDisabled(true);
			this.getActionPanel().disable();

			return button;
		});
	}

	setSliderButtons(buttons: {saveButton: Button, cancelButton: Button})
	{
		this.cache.set('sliderButtons', buttons);
	}

	getSliderButtons(): {saveButton: Button, cancelButton: Button}
	{
		return this.cache.get('sliderButtons', {saveButton: null, cancelButton: null});
	}

	#setPreventConfirmShow(value: boolean)
	{
		this.cache.set('preventConfirmShow', value);
	}

	#isConfirmShowPrevented(): boolean
	{
		return this.cache.get('preventConfirmShow', false);
	}

	show()
	{
		const SidePanelInstance = Reflection.getClass('BX.SidePanel.Instance');
		if (Type.isNil(SidePanelInstance))
		{
			return;
		}

		this.getPreview().hide();
		this.getStatus().hide();
		this.getActionPanel().disable();

		SidePanelInstance.open('stampUploader', {
			width: 640,
			contentCallback: () => {
				return Layout.createContent({
					extensions: [
						'ui.stamp.uploader',
					],
					content: () => {
						return this.getLayout();
					},
					design: {
						section: false,
					},
					buttons: ({cancelButton, SaveButton}) => {
						const saveButton = new SaveButton({
							onclick: () => {
								saveButton.setWaiting(true);
								this.setIsChanged(false);
								this.#setPreventConfirmShow(true);

								this.upload()
									.then((uploaderFile) => {
										return Promise.all([
											new Promise((resolve) => {
												Uploader.#delay(() => {
													this.getPreview().show(uploaderFile.getClientPreview());
													this.getStatus().showPreparingStatus();
													resolve();
												}, 1000);
											}),
											this.emitAsync('onSaveAsync', {file: uploaderFile.toJSON()})
										]);
									})
									.then(() => {
										this.getStatus().hide();

										Uploader.#delay(() => {
											saveButton.setWaiting(false);
											saveButton.setDisabled(true);
											this.getActionPanel().disable();
											const topSlider = BX.SidePanel.Instance.getTopSlider();
											if (topSlider && topSlider.url === 'stampUploader')
											{
												topSlider.close();
											}
										}, 500);
									});
							}
						});

						saveButton.setDisabled(true);
						this.getActionPanel().disable();
						this.setSliderButtons({saveButton, cancelButton});

						return [
							saveButton,
							cancelButton,
						];
					},
				});
			},
			events: {
				onClose: (event) => {
					if (this.isChanged())
					{
						event.denyAction();
						if (!this.#isConfirmShowPrevented())
						{
							Uploader.showConfirm({
								message: Loc.getMessage('UI_STAMP_UPLOADER_SLIDER_CLOSE_CONFIRM'),
								onOk: (messageBox) => {
									this.setIsChanged(false);
									event.getSlider().close();
									messageBox.close();
								},
								okCaption: Loc.getMessage('UI_STAMP_UPLOADER_SLIDER_CLOSE_CONFIRM_CLOSE'),
								onCancel: (messageBox) => {
									messageBox.close();
								},
								cancelCaption: Loc.getMessage('UI_STAMP_UPLOADER_SLIDER_CLOSE_CONFIRM_CANCEL'),
							});
						}
						else
						{
							this.setIsChanged(false);
							event.getSlider().close();
						}
					}
				},
			},
		});
	}
}