403Webshell
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/cvetdv.ru/bitrix/js/im/v2/component/textarea/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/cvetdv.ru/bitrix/js/im/v2/component/textarea/src/textarea.js
import 'ui.icon-set.outline';
import { Extension, Type } from 'main.core';
import { BaseEvent, EventEmitter } from 'main.core.events';
import { BIcon, Outline as OutlineIcons } from 'ui.icon-set.api.vue';

import { EventType, LocalStorageKey, SoundType, TextareaPanelType as PanelType, Color } from 'im.v2.const';
import { Analytics } from 'im.v2.lib.analytics';
import { Logger } from 'im.v2.lib.logger';
import { DraftManager } from 'im.v2.lib.draft';
import { Utils } from 'im.v2.lib.utils';
import { Parser } from 'im.v2.lib.parser';
import { LocalStorageManager } from 'im.v2.lib.local-storage';
import { UploadingService, MultiUploadingService } from 'im.v2.provider.service.uploading';
import { SendingService } from 'im.v2.provider.service.sending';
import { MessageService } from 'im.v2.provider.service.message';
import { SoundNotificationManager } from 'im.v2.lib.sound-notification';
import { isSendMessageCombination, isNewLineCombination } from 'im.v2.lib.hotkey';
import { Textarea } from 'im.v2.lib.textarea';
import { ChannelManager } from 'im.v2.lib.channel';
import { InputAction } from 'im.v2.lib.input-action';

import { MentionManager, MentionManagerEvents } from './classes/mention-manager';
import { InputSenderService } from './classes/input-sender-service';
import { ResizeDirection, ResizeManager } from './classes/resize-manager';
import { AudioInput } from './components/audio-input/audio-input';
import { SmileSelector } from './components/smile-selector/smile-selector';
import { UploadMenu } from './components/upload-menu/upload-menu';
import { SendButton } from './components/send-button';
import { UploadPreviewPopup } from './components/upload-preview/upload-preview-popup';
import { MentionPopup } from './components/mention/mention-popup';
import { TextareaPanel } from './components/panel/panel';
import { AutoDeleteSelector } from './components/auto-delete-selector/auto-delete-selector';

import './css/textarea.css';

import type { JsonObject } from 'main.core';
import type { ImModelChat, ImModelMessage } from 'im.v2.model';
import type { InsertTextEvent, InsertMentionEvent } from 'im.v2.const';
import type { ForwardedEntityConfig, PanelContextWithMultipleIds } from 'im.v2.provider.service.sending';
import type { MultiUploadingResult } from 'im.v2.provider.service.uploading';

const MESSAGE_ACTION_PANELS = new Set([PanelType.edit, PanelType.reply, PanelType.forward, PanelType.forwardEntity]);
const TextareaHeight = {
	max: 400,
	min: 22,
};
const ICON_SIZE = 24;

// @vue/component
export const ChatTextarea = {
	components: {
		UploadMenu,
		SmileSelector,
		SendButton,
		UploadPreviewPopup,
		MentionPopup,
		TextareaPanel,
		AudioInput,
		AutoDeleteSelector,
		BIcon,
	},
	props: {
		dialogId: {
			type: String,
			default: '',
		},
		placeholder: {
			type: String,
			default: '',
		},
		withCreateMenu: {
			type: Boolean,
			default: true,
		},
		withMarket: {
			type: Boolean,
			default: true,
		},
		withEdit: {
			type: Boolean,
			default: true,
		},
		withUploadMenu: {
			type: Boolean,
			default: true,
		},
		withSmileSelector: {
			type: Boolean,
			default: true,
		},
		withAudioInput: {
			type: Boolean,
			default: true,
		},
		withAutoFocus: {
			type: Boolean,
			default: true,
		},
	},
	emits: ['mounted'],
	data(): JsonObject
	{
		return {
			text: '',
			textareaHeight: TextareaHeight.min,

			showMention: false,
			mentionQuery: '',

			showUploadPreviewPopup: false,
			previewPopupUploaderIds: [],
			previewPopupSourceFilesCount: 0,

			panelType: PanelType.none,
			panelContext: {
				messageId: 0,
			},
		};
	},
	computed:
	{
		OutlineIcons: () => OutlineIcons,
		ICON_SIZE: () => ICON_SIZE,
		dialog(): ImModelChat
		{
			return this.$store.getters['chats/get'](this.dialogId, true);
		},
		dialogInited(): boolean
		{
			return this.dialog.inited;
		},
		replyMode(): boolean
		{
			return this.panelType === PanelType.reply;
		},
		forwardMode(): boolean
		{
			return this.panelType === PanelType.forward;
		},
		forwardEntityMode(): boolean
		{
			return this.panelType === PanelType.forwardEntity;
		},
		editMode(): boolean
		{
			return this.panelType === PanelType.edit;
		},
		marketMode(): boolean
		{
			return this.panelType === PanelType.market;
		},
		isDisabled(): boolean
		{
			return this.text.trim() === '' && !this.editMode && !this.forwardMode && !this.forwardEntityMode;
		},
		textareaPlaceholder(): string
		{
			if (!this.placeholder)
			{
				return this.loc('IM_TEXTAREA_PLACEHOLDER_V3');
			}

			return this.placeholder;
		},
		textareaStyle(): Object
		{
			let height = `${this.textareaHeight}px`;
			if (this.textareaHeight === 'auto')
			{
				height = 'auto';
			}

			return {
				height,
				maxHeight: height,
			};
		},
		textareaMaxLength(): number
		{
			const settings = Extension.getSettings('im.v2.component.textarea');

			return settings.get('maxLength');
		},
		isChannelType(): boolean
		{
			return ChannelManager.isChannel(this.dialogId);
		},
		isEmptyText(): boolean
		{
			return this.text === '';
		},
		isAutoDeleteEnabled(): boolean
		{
			return this.$store.getters['chats/autoDelete/isEnabled'](this.dialog.chatId);
		},
		marketIconColor(): string
		{
			if (this.marketMode)
			{
				return Color.accentBlue;
			}

			return Color.gray40;
		},
	},
	watch:
	{
		text(newValue)
		{
			this.adjustTextareaHeight();
			this.getDraftManager().setDraftText(this.dialogId, newValue);

			if (Type.isStringFilled(newValue))
			{
				this.getInputActionService().startAction(InputAction.writing);
			}
		},
	},
	created()
	{
		this.initResizeManager();
		this.restoreTextareaHeight();
		void this.restorePanel();
		this.initSendingService();

		EventEmitter.subscribe(EventType.textarea.insertMention, this.onInsertMention);
		EventEmitter.subscribe(EventType.textarea.insertText, this.onInsertText);
		EventEmitter.subscribe(EventType.textarea.editMessage, this.onEditMessage);
		EventEmitter.subscribe(EventType.textarea.replyMessage, this.onReplyMessage);
		EventEmitter.subscribe(EventType.textarea.forwardEntity, this.onForwardEntity);
		EventEmitter.subscribe(EventType.textarea.sendMessage, this.onSendMessage);
		EventEmitter.subscribe(EventType.textarea.insertForward, this.onInsertForward);
		EventEmitter.subscribe(EventType.textarea.openUploadPreview, this.onOpenUploadPreview);

		EventEmitter.subscribe(EventType.dialog.onMessageDeleted, this.onMessageDeleted);
	},
	mounted()
	{
		void this.initMentionManager();

		if (this.withAutoFocus)
		{
			this.focus();
		}

		this.$emit('mounted');
	},
	beforeUnmount()
	{
		this.resizeManager.destroy();
		this.unbindUploadingService();
		EventEmitter.unsubscribe(EventType.textarea.insertMention, this.onInsertMention);
		EventEmitter.unsubscribe(EventType.textarea.insertText, this.onInsertText);
		EventEmitter.unsubscribe(EventType.textarea.editMessage, this.onEditMessage);
		EventEmitter.unsubscribe(EventType.textarea.replyMessage, this.onReplyMessage);
		EventEmitter.unsubscribe(EventType.textarea.forwardEntity, this.onForwardEntity);
		EventEmitter.unsubscribe(EventType.textarea.sendMessage, this.onSendMessage);
		EventEmitter.unsubscribe(EventType.textarea.insertForward, this.onInsertForward);
		EventEmitter.unsubscribe(EventType.textarea.openUploadPreview, this.onOpenUploadPreview);

		EventEmitter.unsubscribe(EventType.dialog.onMessageDeleted, this.onMessageDeleted);
	},
	methods:
	{
		sendMessage()
		{
			this.text = this.text.trim();
			if (this.isDisabled || !this.dialogInited)
			{
				return;
			}

			const text = this.mentionManager.replaceMentions(this.text);

			if (this.hasActiveMessageAction())
			{
				this.handlePanelAction(text);
				this.closePanel();
			}
			else
			{
				this.getSendingService().sendMessage({ text, dialogId: this.dialogId });
			}

			this.getInputActionService().stopAction(InputAction.writing);
			this.clear();
			this.getDraftManager().clearDraft(this.dialogId);
			SoundNotificationManager.getInstance().playOnce(SoundType.send);
			this.focus();
			EventEmitter.emit(EventType.textarea.onAfterSendMessage);
		},
		handlePanelAction(text: string)
		{
			if (this.editMode && text === '')
			{
				this.getMessageService().deleteMessages([this.panelContext.messageId]);
			}
			else if (this.editMode && text !== '')
			{
				this.getMessageService().editMessageText(this.panelContext.messageId, text);
			}
			else if (this.forwardMode)
			{
				void this.getSendingService().forwardMessages({
					text,
					dialogId: this.dialogId,
					forwardIds: this.panelContext.messagesIds,
				});
			}
			else if (this.forwardEntityMode)
			{
				console.error('sending forwarded entity message');
			}
			else if (this.replyMode)
			{
				this.getSendingService().sendMessage({
					text,
					dialogId: this.dialogId,
					replyId: this.panelContext.messageId,
				});
			}
		},
		clear()
		{
			this.text = '';
			this.mentionManager?.clearMentionReplacements();
		},
		hasActiveMessageAction(): boolean
		{
			return MESSAGE_ACTION_PANELS.has(this.panelType);
		},
		closePanel()
		{
			if (this.editMode)
			{
				this.clear();
			}
			this.panelType = PanelType.none;
			this.panelContext = {
				messageId: 0,
			};

			this.draftManager.setDraftPanel(this.dialogId, this.panelType, this.panelContext);
		},
		openEditPanel(messageId: number)
		{
			if (!this.withEdit)
			{
				return;
			}

			const message: ImModelMessage = this.$store.getters['messages/getById'](messageId);
			if (message.isDeleted)
			{
				return;
			}

			this.panelType = PanelType.edit;
			this.panelContext.messageId = messageId;

			const mentions = this.mentionManager.extractMentions(message.text);
			this.mentionManager.setMentionReplacements(mentions);

			this.text = Parser.prepareEdit(message);
			this.focus();

			this.draftManager.setDraftText(this.dialogId, this.text);
			this.draftManager.setDraftPanel(this.dialogId, this.panelType, this.panelContext);
			this.draftManager.setDraftMentions(this.dialogId, mentions);
		},
		openReplyPanel(messageId: number)
		{
			if (this.editMode)
			{
				this.clear();
			}
			this.panelType = PanelType.reply;
			this.panelContext.messageId = messageId;
			this.focus();

			this.draftManager.setDraftPanel(this.dialogId, this.panelType, this.panelContext);
		},
		openForwardPanel(messagesIds: number[])
		{
			this.panelType = PanelType.forward;
			this.panelContext.messageId = 0;
			this.panelContext.messagesIds = messagesIds;
			this.clear();
			this.focus();

			this.draftManager.setDraftPanel(this.dialogId, this.panelType, this.panelContext);
		},
		async openForwardEntityPanel(entityConfig: ForwardedEntityConfig)
		{
			this.panelType = PanelType.forwardEntity;
			this.panelContext.messageId = 0;
			this.panelContext.entityConfig = entityConfig;
			this.clear();
			this.focus();
		},
		toggleMarketPanel()
		{
			if (this.marketMode)
			{
				this.panelType = PanelType.none;

				return;
			}
			this.panelType = PanelType.market;
			this.panelContext.messageId = 0;
		},
		async adjustTextareaHeight()
		{
			this.textareaHeight = 'auto';

			await this.$nextTick();
			const newMaxPoint = Math.min(TextareaHeight.max, this.$refs.textarea.scrollHeight);
			if (this.resizedTextareaHeight)
			{
				this.textareaHeight = Math.max(newMaxPoint, this.resizedTextareaHeight);

				return;
			}

			this.textareaHeight = Math.max(newMaxPoint, TextareaHeight.min);
		},
		saveTextareaHeight()
		{
			const WRITE_TO_STORAGE_TIMEOUT = 200;
			clearTimeout(this.saveTextareaTimeout);
			this.saveTextareaTimeout = setTimeout(() => {
				LocalStorageManager.getInstance().set(LocalStorageKey.textareaHeight, this.resizedTextareaHeight);
			}, WRITE_TO_STORAGE_TIMEOUT);
		},
		restoreTextareaHeight()
		{
			const rawSavedHeight = LocalStorageManager.getInstance().get(LocalStorageKey.textareaHeight);
			const savedHeight = Number.parseInt(rawSavedHeight, 10);
			if (!savedHeight)
			{
				return;
			}

			this.resizedTextareaHeight = savedHeight;
			this.textareaHeight = savedHeight;
		},
		checkMessageExists(messageId: number): boolean
		{
			return this.$store.getters['messages/isExists'](messageId);
		},
		verifyPanelContext(panelContext: PanelContextWithMultipleIds): boolean
		{
			if (panelContext.messagesIds)
			{
				return panelContext.messagesIds.every((messageId) => this.checkMessageExists(messageId));
			}

			return this.checkMessageExists(panelContext.messageId);
		},
		async restorePanel()
		{
			const {
				text = '',
				panelType = PanelType.none,
				panelContext = {
					messageId: 0,
				},
			} = await this.getDraftManager().getDraft(this.dialogId);

			const noPanel = this.panelType === PanelType.none;

			if (!noPanel && !this.verifyPanelContext(panelContext))
			{
				return;
			}

			this.text = text;
			if (noPanel)
			{
				this.panelType = panelType;
			}
			this.panelContext = panelContext;
		},
		async onKeyDown(event: KeyboardEvent)
		{
			Analytics.getInstance().onTypeMessage(this.dialog);

			if (this.showMention)
			{
				this.mentionManager.onActiveMentionKeyDown(event);

				return;
			}

			const exitActionCombination = Utils.key.isCombination(event, 'Escape');
			if (this.hasActiveMessageAction() && exitActionCombination)
			{
				this.closePanel();

				return;
			}

			const sendMessageCombination = isSendMessageCombination(event);
			const newLineCombination = isNewLineCombination(event);
			if (sendMessageCombination && !newLineCombination)
			{
				event.preventDefault();
				this.sendMessage();

				return;
			}

			if (newLineCombination)
			{
				this.handleNewLine();

				return;
			}

			const tabCombination = Utils.key.isCombination(event, 'Tab');
			if (tabCombination)
			{
				this.handleTab(event);

				return;
			}

			const decorationCombination = Utils.key.isExactCombination(event, ['Ctrl+b', 'Ctrl+i', 'Ctrl+u', 'Ctrl+s']);
			if (decorationCombination)
			{
				event.preventDefault();
				this.text = Textarea.handleDecorationTag(this.$refs.textarea, event.code);

				return;
			}

			if (this.text === '' && Utils.key.isCombination(event, 'ArrowUp'))
			{
				this.handleLastOwnMessageEdit(event);

				return;
			}

			this.mentionManager.onKeyDown(event);
		},
		handleNewLine()
		{
			this.text = Textarea.addNewLine(this.$refs.textarea);
		},
		handleTab(event: KeyboardEvent)
		{
			event.preventDefault();
			if (event.shiftKey)
			{
				this.text = Textarea.removeTab(this.$refs.textarea);

				return;
			}
			this.text = Textarea.addTab(this.$refs.textarea);
		},
		handleLastOwnMessageEdit(event: KeyboardEvent)
		{
			event.preventDefault();
			const lastOwnMessageId = this.$store.getters['messages/getLastOwnMessageId'](this.dialog.chatId);
			const isForward = this.$store.getters['messages/isForward'](lastOwnMessageId);
			if (lastOwnMessageId && !isForward)
			{
				this.openEditPanel(lastOwnMessageId);
			}
		},
		onSendMessage(event: BaseEvent<{ text: string, dialogId: string }>)
		{
			const { text, dialogId } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}
			this.getSendingService().sendMessage({ text, dialogId: this.dialogId });
		},
		onResizeStart(event)
		{
			this.resizeManager.onResizeStart(event, this.textareaHeight);
		},
		async onFileSelect({ event, sendAsFile }: Event)
		{
			const multiUploadingService: MultiUploadingService = this.getMultiUploadingService();
			const multiUploadingResult: MultiUploadingResult = await multiUploadingService.uploadFromInput({
				event,
				sendAsFile,
				dialogId: this.dialogId,
				autoUpload: false,
			});

			this.showUploadPreviewPopup = true;
			this.previewPopupUploaderIds = multiUploadingResult.uploaderIds;
			this.previewPopupSourceFilesCount = multiUploadingResult.sourceFilesCount;
		},
		onDiskFileSelect({ files })
		{
			this.getUploadingService().uploadFileFromDisk(files, this.dialogId);
		},
		onInsertMention(event: BaseEvent<InsertMentionEvent>)
		{
			const { mentionText, mentionReplacement, dialogId, isMentionSymbol = true } = event.getData();
			let { textToReplace = '' } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}

			const mentions = this.mentionManager.addMentionReplacement(mentionText, mentionReplacement);
			this.draftManager.setDraftMentions(this.dialogId, mentions);

			const mentionSymbol = isMentionSymbol ? this.mentionManager.getMentionSymbol() : '';
			textToReplace = `${mentionSymbol}${textToReplace}`;
			this.text = Textarea.insertMention(this.$refs.textarea, {
				textToInsert: mentionText,
				textToReplace,
			});
			this.mentionManager.clearMentionSymbol();
		},
		onInsertText(event: BaseEvent<InsertTextEvent>)
		{
			const { dialogId } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}
			this.text = Textarea.insertText(this.$refs.textarea, event.getData());
		},
		onEditMessage(event: BaseEvent<{ messageId: number, dialogId: string }>)
		{
			const { messageId, dialogId } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}
			this.openEditPanel(messageId);
		},
		onReplyMessage(event: BaseEvent<{ messageId: number, dialogId: string }>)
		{
			const { messageId, dialogId } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}
			this.openReplyPanel(messageId);
		},
		onForwardEntity(event: BaseEvent<{ dialogId: string, entityConfig: ForwardedEntityConfig }>)
		{
			const { dialogId, entityConfig } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}
			this.openForwardEntityPanel(entityConfig);
		},
		onInsertForward(event: BaseEvent<{ messagesIds: number[], dialogId: string }>)
		{
			const { messagesIds, dialogId } = event.getData();
			if (this.dialogId !== dialogId)
			{
				return;
			}

			this.openForwardPanel(messagesIds);
		},
		async onPaste(clipboardEvent: ClipboardEvent)
		{
			if (!this.withUploadMenu)
			{
				return;
			}

			const multiUploadingService: MultiUploadingService = this.getMultiUploadingService();
			const multiUploadingResult: MultiUploadingResult = await multiUploadingService.uploadFromClipboard({
				clipboardEvent,
				dialogId: this.dialogId,
				imagesOnly: false,
				autoUpload: false,
			});

			if (!Type.isArrayFilled(multiUploadingResult.uploaderIds))
			{
				return;
			}

			this.showUploadPreviewPopup = true;
			this.previewPopupUploaderIds = multiUploadingResult.uploaderIds;
			this.previewPopupSourceFilesCount = multiUploadingResult.sourceFilesCount;
		},
		onOpenUploadPreview(event: BaseEvent)
		{
			const { multiUploadingResult } = event.getData();

			this.showUploadPreviewPopup = true;
			this.previewPopupUploaderIds = multiUploadingResult.uploaderIds;
			this.previewPopupSourceFilesCount = multiUploadingResult.sourceFilesCount;
		},
		onMarketIconClick()
		{
			this.toggleMarketPanel();
		},
		onMessageDeleted(event: BaseEvent<{ messageId: number }>)
		{
			const { messageId } = event.getData();

			if (this.panelContext.messageId === messageId)
			{
				this.closePanel();
			}

			if (this.panelContext.messagesIds && this.panelContext.messagesIds.includes(messageId))
			{
				this.closePanel();
			}
		},
		initResizeManager()
		{
			this.resizeManager = new ResizeManager({
				direction: ResizeDirection.up,
				maxHeight: TextareaHeight.max,
				minHeight: TextareaHeight.min,
			});

			this.resizeManager.subscribe(ResizeManager.events.onHeightChange, ({ data: { newHeight } }) => {
				Logger.warn('Textarea: Resize height change', newHeight);
				this.textareaHeight = newHeight;
			});
			this.resizeManager.subscribe(ResizeManager.events.onResizeStop, () => {
				Logger.warn('Textarea: Resize stop');
				this.resizedTextareaHeight = this.textareaHeight;
				this.saveTextareaHeight();
			});
		},
		initSendingService()
		{
			if (this.sendingService)
			{
				return;
			}

			this.sendingService = SendingService.getInstance();
		},
		async initMentionManager()
		{
			const {
				mentions = {},
			} = await this.getDraftManager().getDraft(this.dialogId);

			this.mentionManager = new MentionManager(this.$refs.textarea);
			this.mentionManager.setMentionReplacements(mentions);

			this.mentionManager.subscribe(MentionManagerEvents.showMentionPopup, (event) => {
				const { mentionQuery } = event.getData();
				this.showMentionPopup(mentionQuery);
			});

			this.mentionManager.subscribe(MentionManagerEvents.hideMentionPopup, () => {
				this.closeMentionPopup();
			});
		},
		getSendingService(): SendingService
		{
			return this.sendingService;
		},
		getInputActionService(): InputSenderService
		{
			if (!this.inputSenderService)
			{
				this.inputSenderService = new InputSenderService(this.dialogId);
			}

			return this.inputSenderService;
		},
		getDraftManager(): DraftManager
		{
			if (!this.draftManager)
			{
				this.draftManager = DraftManager.getInstance();
			}

			return this.draftManager;
		},
		getMessageService(): MessageService
		{
			if (!this.messageService)
			{
				this.messageService = new MessageService({ chatId: this.dialog.chatId });
			}

			return this.messageService;
		},
		getUploadingService(): UploadingService
		{
			if (!this.uploadingService)
			{
				this.initUploadingService();
			}

			return this.uploadingService;
		},
		initUploadingService()
		{
			this.uploadingService = UploadingService.getInstance();

			this.startFileUploadAction = () => {
				this.getInputActionService().startAction(InputAction.sendingFile);
			};

			this.stopFileUploadAction = () => {
				this.getInputActionService().stopAction(InputAction.sendingFile);
			};
			this.uploadingService.subscribe(UploadingService.event.uploadStart, this.startFileUploadAction);
			this.uploadingService.subscribe(UploadingService.event.uploadComplete, this.stopFileUploadAction);
			this.uploadingService.subscribe(UploadingService.event.uploadCancel, this.stopFileUploadAction);
			this.uploadingService.subscribe(UploadingService.event.uploadError, this.stopFileUploadAction);
		},
		unbindUploadingService()
		{
			if (!this.uploadingService)
			{
				return;
			}

			this.uploadingService.unsubscribe(UploadingService.event.uploadStart, this.startFileUploadAction);
			this.uploadingService.unsubscribe(UploadingService.event.uploadComplete, this.stopFileUploadAction);
			this.uploadingService.unsubscribe(UploadingService.event.uploadCancel, this.stopFileUploadAction);
			this.uploadingService.unsubscribe(UploadingService.event.uploadError, this.stopFileUploadAction);
		},
		getMultiUploadingService(): MultiUploadingService
		{
			if (!this.multiUploadingService)
			{
				this.multiUploadingService = new MultiUploadingService();
			}

			return this.multiUploadingService;
		},
		onSendFilesFromPreviewPopup(event)
		{
			this.text = '';
			const { text, uploaderIds } = event;
			const textWithMentions = this.mentionManager.replaceMentions(text);

			uploaderIds.forEach((uploaderId, index) => {
				this.getUploadingService().sendMessageWithFiles({
					uploaderId,
					text: index === 0 ? textWithMentions : '',
				});
			});

			this.focus();
		},
		closeMentionPopup()
		{
			this.showMention = false;
			this.mentionQuery = '';
			this.mentionManager.onMentionPopupClose();
		},
		showMentionPopup(mentionQuery: string)
		{
			this.mentionQuery = mentionQuery;
			this.showMention = true;
		},
		focus(): void
		{
			this.$refs.textarea?.focus({ preventScroll: true });
		},
		loc(phraseCode: string): string
		{
			return this.$Bitrix.Loc.getMessage(phraseCode);
		},
		onAudioInputStart()
		{
			if (this.isEmptyText)
			{
				return;
			}

			this.text += ' ';
		},
		onAudioInputResult(inputText: string)
		{
			this.text += inputText;
		},
	},
	template: `
		<div class="bx-im-send-panel__scope bx-im-send-panel__container --ui-context-content-light">
			<div class="bx-im-textarea__container">
				<div @mousedown="onResizeStart" class="bx-im-textarea__drag-handle"></div>
				<TextareaPanel
					:type="panelType"
					:context="panelContext"
					:dialogId="dialogId"
					@close="closePanel"
				/>
				<div class="bx-im-textarea__content" ref="textarea-content">
					<div class="bx-im-textarea__left">
						<UploadMenu
							v-if="withUploadMenu"
							:dialogId="dialogId" 
							@fileSelect="onFileSelect" 
							@diskFileSelect="onDiskFileSelect" 
						/>
						<textarea
							v-model="text"
							:style="textareaStyle"
							:placeholder="textareaPlaceholder"
							:maxlength="textareaMaxLength"
							@keydown="onKeyDown"
							@paste="onPaste"
							class="bx-im-textarea__element"
							ref="textarea"
							rows="1"
						></textarea>
						<AudioInput
							v-if="withAudioInput"
							@inputStart="onAudioInputStart"
							@inputResult="onAudioInputResult"
						/>
					</div>
					<div class="bx-im-textarea__right">
						<div class="bx-im-textarea__action-panel">
							<AutoDeleteSelector
								v-if="isAutoDeleteEnabled"
								:dialogId="dialogId"
							/>
							<BIcon
								v-if="withMarket"
								:name="OutlineIcons.APPS"
								:title="loc('IM_TEXTAREA_ICON_APPLICATION')"
								:size="ICON_SIZE"
								:color="marketIconColor"
								class="bx-im-textarea__icon"
								@click="onMarketIconClick"
							/>
							<SmileSelector 
								v-if="withSmileSelector" 
								:dialogId="dialogId" 
							/>
						</div>
					</div>
				</div>
			</div>
			<SendButton :dialogId="dialogId" :editMode="editMode" :isDisabled="isDisabled" @click="sendMessage" />
			<UploadPreviewPopup
				v-if="showUploadPreviewPopup"
				:dialogId="dialogId"
				:uploaderIds="previewPopupUploaderIds"
				:sourceFilesCount="previewPopupSourceFilesCount"
				:textareaValue="text"
				@close="showUploadPreviewPopup = false"
				@sendFiles="onSendFilesFromPreviewPopup"
			/>
			<MentionPopup 
				v-if="showMention" 
				:bindElement="$refs['textarea-content']"
				:dialogId="dialogId"
				:query="mentionQuery"
				@close="closeMentionPopup"
			/>
		</div>
	`,
};

Youez - 2016 - github.com/yon3zu
LinuXploit