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/rospirotorg.ru/bitrix/js/calendar/compacteventform/src/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/calendar/compacteventform/src/compacteventform.js
// @flow
import { Type, Tag, Loc, Dom, Event, Runtime } from 'main.core';
import { BaseEvent, EventEmitter } from 'main.core.events';
import { Util } from 'calendar.util';
import { MenuManager, Popup, PopupManager } from 'main.popup';
import {
	DateTimeControl,
	Location,
	Reminder,
	SectionSelector,
	UserPlannerSelector,
	ColorSelector,
	BusyUsersDialog,
} from 'calendar.controls';
import { Entry, EntryManager } from 'calendar.entry';
import { SectionManager } from 'calendar.sectionmanager';
import { sendData } from 'ui.analytics';
import { MessageBox } from 'ui.dialogs.messagebox';
import { RelationInterface } from 'calendar.entityrelation';

export class CompactEventForm extends EventEmitter
{
	static VIEW_MODE = 'view';
	static EDIT_MODE = 'edit';
	static USER_URL = '/company/personal/user/#USER_ID#/';
	STATE = { READY: 1, REQUEST: 2, ERROR: 3 };
	zIndex = 1200;
	Z_INDEX_OFFSET = -1000;
	userSettings = '';
	DOM = {};
	mode;
	displayed = false;
	sections = [];
	sectionIndex = {};
	trackingUsersList = [];
	checkDataBeforeCloseMode = true;
	CHECK_CHANGES_DELAY = 500;
	RELOAD_DATA_DELAY = 500;
	excludedUsers = [];

	constructor(options = {})
	{
		super();
		this.setEventNamespace('BX.Calendar.CompactEventForm');
		this.BX = Util.getBX();

		this.userId = parseInt(options.userId, 10) || Util.getCurrentUserId();
		this.type = options.type || 'user';
		this.isLocationCalendar = options.isLocationCalendar || false;
		this.calendarContext = options.calendarContext || null;
		this.ownerId = options.ownerId || this.userId;
		this.isCollabUser = Util.getCalendarContext().isCollabUser || false;

		this.checkForChangesDebounce = Runtime.debounce(this.checkForChanges, this.CHECK_CHANGES_DELAY, this);
		this.reloadEntryDataDebounce = Runtime.debounce(this.reloadEntryData, this.RELOAD_DATA_DELAY, this);
		this.checkOutsideClickClose = this.checkOutsideClickClose.bind(this);
		this.outsideMouseDownClose = this.outsideMouseDownClose.bind(this);
		this.keyHandler = this.handleKeyPress.bind(this);

		this.lastUsedSaveOptions = {};
	}

	show(mode = CompactEventForm.EDIT_MODE, params = {})
	{
		this.setParams(params);
		this.setMode(mode);

		this.state = this.STATE.READY;

		this.popupId = `compact-event-form-${Math.round(Math.random() * 100_000)}`;

		if (this.popup)
		{
			this.popup.destroy();
		}
		this.popup = this.getPopup(params);

		// Small hack to use transparent titlebar to drag&drop popup
		Dom.addClass(this.popup.titleBar, 'calendar-add-popup-titlebar');
		Dom.removeClass(this.popup.popupContainer, 'popup-window-with-titlebar');
		Dom.removeClass(this.popup.closeIcon, 'popup-window-titlebar-close-icon');
		Event.bind(document, 'mousedown', this.outsideMouseDownClose);
		Event.bind(document, 'mouseup', this.checkOutsideClickClose);
		Event.bind(document, 'keydown', this.keyHandler);
		Event.bind(this.popup.popupContainer, 'transitionend', () => {
			Dom.removeClass(this.popup.popupContainer, 'calendar-simple-view-popup-show');
		});

		// Fulfill previous deletions to avoid data inconsistency
		if (this.isEditMode())
		{
			EntryManager.doDelayedActions();
		}

		if (this.isViewMode() && !this.isLocationMode())
		{
			this.sendOpenViewCardAnalytics();
		}

		this.prepareData()
			.then(() => {
				if (this.isLocationMode())
				{
					this.setFormValuesLocation();
				}
				else
				{
					this.setFormValues();
				}

				this.popup.show();
				if (this.hasToOpenPlannerInDefault())
				{
					this.userPlannerSelector.showPlanner();
				}

				if (this.isTitleOverflowing())
				{
					this.DOM.titleInput.title = this.entry.name;
				}

				this.checkDataBeforeCloseMode = true;
				if (this.canDo('edit') && this.DOM.titleInput && mode === CompactEventForm.EDIT_MODE)
				{
					this.DOM.titleInput.focus();
					this.DOM.titleInput.select();
				}

				this.displayed = true;

				if (this.getMode() === CompactEventForm.VIEW_MODE)
				{
					Util.sendAnalyticLabel({ calendarAction: 'view_event', formType: 'compact' });
					this.popup.getButtons()[0].button.focus();
				}

				if (
					this.getMode() === CompactEventForm.EDIT_MODE
					&& !this.userPlannerSelector.isPlannerDisplayed()
				)
				{
					this.userPlannerSelector.checkBusyTime();
				}
			});
	}

	getPopup(params)
	{
		return new Popup(
			this.popupId,
			params.bindNode,
			{
				zIndex: this.zIndex + this.Z_INDEX_OFFSET,
				closeByEsc: true,
				offsetTop: 0,
				offsetLeft: 0,
				closeIcon: true,
				titleBar: true,
				draggable: true,
				resizable: false,
				lightShadow: true,
				className: 'calendar-simple-view-popup calendar-simple-view-popup-show',
				cacheable: false,
				content: this.isLocationMode()
					? this.getPopupContentLocation()
					: this.getPopupContentCalendar(),
				buttons: this.getButtons(),
				events: {
					onPopupClose: this.close.bind(this),
				},
			},
		);
	}

	isShown()
	{
		return this.displayed;
	}

	close(fromButton = true, fromPopup = false)
	{
		if (
			!fromButton
			&& !this.checkTopSlider()
		)
		{
			if (this.popup)
			{
				this.popup.destroyed = true;
				setTimeout(() => {
					this.popup.destroyed = false;
				}, 0);
			}

			return;
		}

		if (
			this.getMode() === CompactEventForm.EDIT_MODE
			&& this.formDataChanged()
			&& this.checkDataBeforeCloseMode
			&& !fromPopup
		)
		{
			if (this.checkTopSlider())
			{
				this.showConfirmClosePopup();
			}

			// Workaround to prevent form closing even if user don't want to and presses "cancel" in confirm
			if (this.popup)
			{
				this.popup.destroyed = true;
				setTimeout(() => {
					this.popup.destroyed = false;
				}, 0);
			}

			return;
		}

		this.displayed = false;
		this.emit('onClose');
		Event.unbind(document, 'mousedown', this.outsideMouseDownClose);
		Event.unbind(document, 'mouseup', this.checkOutsideClickClose);
		Event.unbind(document, 'keydown', this.keyHandler);

		if (this.userPlannerSelector)
		{
			this.userPlannerSelector.destroy();
		}

		if (this.popup)
		{
			this.popup.destroy();
		}

		if (Location)
		{
			Location.setCurrentCapacity(0);
		}
		Util.clearPlannerWatches();
		Util.closeAllPopups();
	}

	getPopupContentCalendar()
	{
		this.DOM.wrap = Tag.render`<div class="calendar-add-popup-wrap">
			${this.DOM.titleOuterWrap = Tag.render`
			<div class="calendar-field-container calendar-field-container-string-select">
				<div class="calendar-field-block">
					${this.getEntryCounter()}
					${this.getTitleControl()}
					${this.getTitleFade()}
					${this.getColorControl()}
				</div>
			</div>`}
			<div class="calendar-field-container calendar-field-container-choice">
				${this.getSectionControl('textselect')}
			</div>

			${this.getDateTimeControl()}
			${this.getUserPlannerSelector()}
			${this.getRelationControl()}

			<div class="calendar-field-container calendar-field-container-info">
				${this.getTypeInfoControl()}
				${this.getLocationControl()}
				${this.DOM.remindersOuterWrap = Tag.render`
				<div class="calendar-field-block">
					<div class="calendar-field-title">${Loc.getMessage('EC_REMIND_LABEL')}:</div>
					${this.createRemindersControl()}
				</div>`}
				${this.getRRuleInfoControl()}
			</div>
		</div>`;

		return this.DOM.wrap;
	}

	getPopupContentLocation()
	{
		this.DOM.wrap = Tag.render`<div class="calendar-add-popup-wrap">
			${this.DOM.titleOuterWrap = Tag.render`
			<div class="calendar-field-container calendar-field-container-string-select">
				<div class="calendar-field-block">
					${this.getTitleControlLocation()}
					${this.getTitleFade()}
					${this.getColorControlsLocationView()}
				</div>
			</div>`}
			<div class="calendar-field-container calendar-field-container-choice">
				${this.getSectionControl('location')}
			</div>
			${this.getDateTimeControl()}
			
		</div>`;
		if (this.entry.id !== this.entry.parentId)
		{
			this.DOM.wrap.appendChild(Tag.render`
				${this.getHostControl()}
			`);
		}

		return this.DOM.wrap;
	}

	getButtons()
	{
		let buttons = [];
		if (this.isLocationMode())
		{
			buttons = this.getLocationModeButtons();
		}
		else if (this.isInvitedMode())
		{
			buttons = this.getInvitedButtons();
		}
		else if (this.isEditMode())
		{
			buttons = this.getEditModeButtons();
		}
		else if (this.isViewMode())
		{
			buttons = this.getViewModeButtons();
		}

		if (buttons.length > 3)
		{
			const firstTwoButtons = buttons.slice(0, 2);
			const menuButtons = buttons.slice(2);

			buttons = [...firstTwoButtons, this.getMoreButton(menuButtons)];
		}

		if (buttons.length > 2)
		{
			buttons[1].button.className = 'ui-btn ui-btn-light-border';
		}

		return buttons;
	}

	getLocationModeButtons()
	{
		// if (this.entry.id === this.entry.parentId)
		// {
		// 	return [
		// 		new BX.UI.Button({
		// 			className: 'ui-btn ui-btn-disabled',
		// 			text: Loc.getMessage('CALENDAR_UPDATE_PROGRESS'),
		// 		})
		// 	];
		// }

		const buttons = [this.getOpenParentButton()];

		if (this.canDo('release'))
		{
			buttons.push(this.getReleaseLocationButton());
		}

		return buttons;
	}

	getInvitedButtons()
	{
		return [this.getAcceptButton(), this.getDeclineButton(), this.getOpenButton(), ...this.getEditEventButtons()];
	}

	getEditModeButtons()
	{
		const buttons = [this.getSaveButton(), this.getCloseButton()];

		if (this.canDo('edit'))
		{
			buttons.push(this.getFullFormButton());
		}

		return buttons;
	}

	getViewModeButtons()
	{
		const buttons = [this.getOpenButton()];

		if (this.entry.isMeeting() && this.entry.getMeetingHost() !== this.userId)
		{
			if (this.entry.getCurrentStatus() === 'N')
			{
				buttons.push(this.getAcceptButtonWithoutBorder());
			}
			else if (this.entry.getCurrentStatus() === 'Y')
			{
				buttons.push(this.getDeclineButton());
			}
		}

		buttons.push(...this.getEditEventButtons());

		return buttons;
	}

	getEditEventButtons()
	{
		const buttons = [];
		if (!this.isNewEntry() && (this.entry.permissions?.edit || this.canDo('edit') || this.canDo('editLocation') || this.canDo('editAttendees')))
		{
			buttons.push(this.getEditButton());
		}

		if (
			this.isCollabUser
			&& !this.isNewEntry()
			&& (this.entry.permissions?.view_full || this.canDo('viewFull')))
		{
			buttons.push(this.getDownloadIcsButton());
		}

		if (!this.isNewEntry() && (this.entry.permissions?.edit || this.canDo('edit')))
		{
			buttons.push(this.getDeleteButton());
		}

		return buttons;
	}

	getOpenButton()
	{
		const className = this.entry.isInvited() ? 'ui-btn-link' : 'ui-btn-primary';
		const openButton = new BX.UI.Button({
			className: `ui-btn ${className}`,
			text: Loc.getMessage('CALENDAR_EVENT_DO_OPEN'),
			events: {
				click: () => {
					this.checkDataBeforeCloseMode = false;
					BX.Calendar.EntryManager.openViewSlider(this.entry.id, {
						entry: this.entry,
						calendarContext: this.calendarContext,
						type: this.type,
						ownerId: this.ownerId,
						userId: this.userId,
						from: this.entry.from,
						timezoneOffset: this.entry && this.entry.data ? this.entry.data.TZ_OFFSET_FROM : null,
					});
					this.close();
				},
			},
		});
		openButton.button.setAttribute('data-role', 'openButton');

		return openButton;
	}

	getEditButton()
	{
		return new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_DO_EDIT'),
			className: 'ui-btn ui-btn-link',
			events: {
				click: this.editEntryInSlider.bind(this),
			},
		});
	}

	getSaveButton()
	{
		const messageCode = this.isNewEntry() ? 'CALENDAR_EVENT_DO_ADD' : 'CALENDAR_EVENT_DO_SAVE';
		const saveButton = new BX.UI.Button({
			name: 'save',
			text: Loc.getMessage(messageCode),
			className: 'ui-btn ui-btn-primary',
			events: {
				click: () => {
					this.checkDataBeforeCloseMode = false;
					this.save();
				},
			},
		});
		saveButton.button.setAttribute('data-role', 'saveButton');

		return saveButton;
	}

	getDeleteButton()
	{
		return new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_DO_DELETE'),
			className: 'ui-btn ui-btn-link',
			events: {
				click: () => {
					EventEmitter.subscribeOnce('BX.Calendar.Entry:beforeDelete', () => {
						this.checkDataBeforeCloseMode = false;
						this.close();
					});

					EntryManager.deleteEntry(this.entry);

					if (!this.entry.wasEverRecursive())
					{
						this.close();
					}
				},
			},
		});
	}

	getCloseButton()
	{
		const closeButton = new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_DO_CANCEL'),
			className: 'ui-btn ui-btn-link',
			events: {
				click: () => {
					if (this.isNewEntry())
					{
						this.checkDataBeforeCloseMode = false;
						this.close();
					}
					else
					{
						this.setFormValues();

						if (this.userPlannerSelector)
						{
							this.userPlannerSelector.destroy();
						}

						this.setMode(CompactEventForm.VIEW_MODE);
						this.popup.setButtons(this.getButtons());
					}
				},
			},
		});
		closeButton.button.setAttribute('data-role', 'closeButton');

		return closeButton;
	}

	getFullFormButton()
	{
		const fullFormButton = new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_FULL_FORM'),
			className: 'ui-btn calendar-full-form-btn',
			events: {
				click: this.editEntryInSlider.bind(this),
			},
		});
		fullFormButton.button.setAttribute('data-role', 'fullForm');

		return fullFormButton;
	}

	getDownloadIcsButton(): BX.UI.Button
	{
		return new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_DO_DOWNLOAD_ICS'),
			className: 'ui-btn ui-btn-link',
			events: {
				click: () => EntryManager.downloadIcs(this.getCurrentEntry().id),
			},
		});
	}

	getAcceptButtonWithoutBorder()
	{
		return this.getAcceptButton(true);
	}

	getAcceptButton(withoutBorder = false)
	{
		const className = withoutBorder ? 'ui-btn-link' : 'ui-btn-primary';
		const acceptButton = new BX.UI.Button({
			className: `ui-btn ${className}`,
			text: Loc.getMessage('EC_DESIDE_BUT_Y'),
			events: {
				click: () => {
					if (!this.entry.isRecursive())
					{
						this.entry.setCurrentStatus('Y');
						this.setFormValues();
					}

					EntryManager.setMeetingStatus(this.entry, 'Y')
						.then(this.refreshMeetingStatus.bind(this));
				},
			},
		});
		acceptButton.button.setAttribute('data-role', 'accept');

		return acceptButton;
	}

	getDeclineButton()
	{
		const declineButton = new BX.UI.Button({
			className: 'ui-btn ui-btn-link',
			text: Loc.getMessage('EC_DESIDE_BUT_N'),
			events: {
				click: () => {
					EntryManager.setMeetingStatus(this.entry, 'N').then(() => {
						if (this.isShown())
						{
							this.close();
						}
					});
				},
			},
		});
		declineButton.button.setAttribute('data-role', 'decline');

		return declineButton;
	}

	getOpenParentButton()
	{
		const className = this.entry.isInvited() ? 'ui-btn-link' : 'ui-btn-primary';

		return new BX.UI.Button({
			className: `ui-btn ${className}`,
			text: Loc.getMessage('CALENDAR_EVENT_DO_OPEN_PARENT'),
			events: {
				click: () => {
					this.checkDataBeforeCloseMode = false;
					BX.Calendar.EntryManager.openViewSlider(
						this.entry.parentId,
						{
							userId: this.userId,
							from: this.entry.from,
							timezoneOffset: this.entry && this.entry.data ? this.entry.data.TZ_OFFSET_FROM : null,
						},
					);
					this.close();
				},
			},
		});
	}

	getReleaseLocationButton()
	{
		return new BX.UI.Button({
			name: 'release',
			text: Loc.getMessage('CALENDAR_EVENT_DO_RELEASE'),
			className: 'ui-btn ui-btn-light-border',
			events: {
				click: () => {
					this.checkDataBeforeCloseMode = false;
					this.releaseLocation();
				},
			},
		});
	}

	getMoreButton(buttons)
	{
		let buttonsMenu;

		const moreButton = new BX.UI.Button({
			text: Loc.getMessage('CALENDAR_EVENT_DO_MORE'),
			className: 'ui-btn ui-btn-light-border ui-btn-dropdown',
			events: {
				click: () => {
					buttonsMenu.show();
				},
			},
		});

		const buttonsItems = buttons.map((button) => {
			return {
				text: button.button.innerText,
				onclick: () => {
					button.button.click();
				},
			};
		});

		buttonsMenu = MenuManager.create({
			id: `calendar-compact-event-form-more${Date.now()}`,
			bindElement: moreButton.button,
			items: buttonsItems,
		});

		return moreButton;
	}

	freezePopup()
	{
		if (this.popup)
		{
			this.popup.buttons.forEach((button) => {
				if (button?.options?.name === 'save')
				{
					button.setClocking(true);
				}
				else
				{
					button.setDisabled(true);
				}
			});
		}
	}

	unfreezePopup()
	{
		if (this.popup)
		{
			this.popup.buttons.forEach((button) => {
				button.setClocking(false);
				button.setDisabled(false);
			});
		}
	}

	refreshMeetingStatus()
	{
		this.emit('doRefresh');
		this.popup.setButtons(this.getButtons());
		if (this.entry.isInvited())
		{
			Dom.removeClass(this.DOM.entryCounter, 'calendar-event-invite-counter-none');
		}
		else
		{
			Dom.addClass(this.DOM.entryCounter, 'calendar-event-invite-counter-none');
		}

		if (this.userPlannerSelector)
		{
			const isInvited = this.entry.isInvited();
			this.userPlannerSelector.setViewMode(isInvited);
			this.userPlannerSelector.displayAttendees(this.entry.getAttendees());
			this.locationSelector.setViewMode(isInvited);
			if (!isInvited)
			{
				if (this.isLocationCalendar)
				{
					this.locationSelector.setValue(this.locationSelector.default);
				}
				else
				{
					this.DOM.locationOuterWrap.style.display = '';
					this.locationSelector.setValue(this.entry.getLocation());
				}
			}
		}
	}

	hideLoader()
	{
		if (Type.isDomNode(this.DOM.loader))
		{
			Dom.remove(this.DOM.loader);
			this.DOM.loader = null;
		}
	}

	showInEditMode(params = {})
	{
		return this.show(CompactEventForm.EDIT_MODE, params);
	}

	showInViewMode(params = {})
	{
		return this.show(CompactEventForm.VIEW_MODE, params);
	}

	isLocationMode()
	{
		return this.isViewMode() && this.type === 'location';
	}

	isInvitedMode()
	{
		return this.entry.isInvited();
	}

	isEditMode()
	{
		return this.getMode() === CompactEventForm.EDIT_MODE;
	}

	isViewMode()
	{
		return this.getMode() === CompactEventForm.VIEW_MODE;
	}

	setMode(mode)
	{
		if (mode === 'edit' || mode === 'view')
		{
			this.mode = mode;
		}
	}

	getMode()
	{
		return this.mode;
	}

	checkForChanges()
	{
		if (
			!this.isNewEntry()
			&& this.getMode() === CompactEventForm.VIEW_MODE
			&& this.formDataChanged()
		)
		{
			this.setMode(CompactEventForm.EDIT_MODE);
			this.popup.setButtons(this.getButtons());
		}
		else if (
			!this.isNewEntry()
			&& this.getMode() === CompactEventForm.EDIT_MODE
			&& !this.formDataChanged()
		)
		{
			this.setMode(CompactEventForm.VIEW_MODE);
			this.popup.setButtons(this.getButtons());
		}
		this.emitOnChange();
	}

	updateEventNameInputTitle()
	{
		if (this.isTitleOverflowing())
		{
			this.DOM.titleInput.title = this.DOM.titleInput.value;
		}
		else
		{
			this.DOM.titleInput.title = '';
		}
	}

	isTitleOverflowing()
	{
		const el = this.DOM.titleInput;

		return el.clientWidth < el.scrollWidth || el.clientHeight < el.scrollHeight;
	}

	hasToOpenPlannerInDefault()
	{
		return this.userPlannerSelector
			&& (
				this.isLocationCalendar
				|| (
					this.userPlannerSelector.attendeesEntityList.length > 1
					&& this.getMode() !== CompactEventForm.VIEW_MODE
				)
			)
		;
	}

	checkLocationForm(event)
	{
		if (!this.isCollabUser && event && event instanceof BaseEvent)
		{
			const data = event.getData();
			const usersCount = data.usersCount;

			let locationCapacity = Location.getCurrentCapacity() || 0;

			if (this.locationSelector.value.type === undefined && locationCapacity)
			{
				locationCapacity = 0;
				Location.setCurrentCapacity(0);
			}

			if (locationCapacity < usersCount && locationCapacity !== 0)
			{
				this.locationSelector.addCapacityAlert();
			}
			else
			{
				this.locationSelector.removeCapacityAlert();
			}
		}
	}

	getFormDataChanges(excludes = [])
	{
		const entry = this.entry;
		const fields = [];

		// Name
		if (!excludes.includes('name') && entry.name !== this.DOM.titleInput.value)
		{
			fields.push('name');
		}

		// Location
		if (
			!excludes.includes('location')
			&& this.locationSelector.getTextLocation(Location.parseStringValue(entry.getLocation()))
			!==	this.locationSelector.getTextLocation(Location.parseStringValue(this.locationSelector.getTextValue()))
		)
		{
			fields.push('location');
		}

		// Date + time
		const dateTime = this.dateTimeControl.getValue();
		if (
			!excludes.includes('date&time')
			&&	(entry.isFullDay() !== dateTime.fullDay
				|| dateTime.from.toString() !== entry.from.toString()
				|| dateTime.to.toString() !== entry.to.toString()
			)
		)
		{
			fields.push('date&time');
		}

		// Notify
		if (
			!excludes.includes('notify')
			&& (!entry.isMeeting() || entry.getMeetingNotify()) !== this.userPlannerSelector.getInformValue()
		)
		{
			fields.push('notify');
		}

		// Section
		if (!excludes.includes('section') && parseInt(entry.sectionId) !== parseInt(this.sectionValue))
		{
			fields.push('section');
		}

		// Access codes
		if (
			!excludes.includes('codes')
			&& this.userPlannerSelector.getEntityList().map((item) => { return `${item.entityId}:${item.id}`;}).join('|')
			!==	entry.getAttendeesEntityList().map((item) => { return `${item.entityId}:${item.id}`;}).join('|')
		)
		{
			fields.push('codes');
		}

		return fields;
	}

	formDataChanged()
	{
		return this.getFormDataChanges().length > 0;
	}

	setParams(params = {})
	{
		this.userId = parseInt(params.userId, 10) || Util.getCurrentUserId();
		this.type = params.type || 'user';
		this.isLocationCalendar = params.isLocationCalendar || false;
		this.locationAccess = params.locationAccess || false;
		this.calendarContext = params.calendarContext || null;
		this.ownerId = params.ownerId ?? 0;
		if (this.type === 'user' && !this.ownerId)
		{
			this.ownerId = this.userId;
		}
		this.entry = EntryManager.getEntryInstance(params.entry, params.userIndex, {
			type: this.type,
			ownerId: this.ownerId,
		});
		this.sectionValue = null;
		this.analyticsSubSection = this.getFormAnalyticsContext();

		if (
			!this.entry.id
			&& Type.isPlainObject(params.entryTime)
			&& Type.isDate(params.entryTime.from)
			&& Type.isDate(params.entryTime.to)
		)
		{
			this.entry.setDateTimeValue(params.entryTime);
		}

		if (Type.isPlainObject(params.userSettings))
		{
			this.userSettings = params.userSettings;
		}

		this.locationFeatureEnabled = Boolean(params.locationFeatureEnabled);
		this.locationList = Type.isArray(params.locationList)
			? params.locationList.filter((locationItem) => {
				return locationItem.PERM.view_full;
			})
			: [];

		this.roomsManager = params.roomsManager || null;
		this.iblockMeetingRoomList = params.iblockMeetingRoomList || [];

		this.plannerFeatureEnabled = Boolean(params.plannerFeatureEnabled);

		this.setSections(params.sections, params.trackingUserList);
	}

	setSections(sections, trackingUsersList = [])
	{
		this.sections = sections;
		this.trackingUsersList = trackingUsersList || [];
		this.updateSectionIndex();

		if (this.entry.id)
		{
			const section = this.getCurrentSection();
			this.getSectionsForEditEvent(this.sections, section);
		}
	}

	prepareData(params = {})
	{
		return new Promise((resolve) => {
			const section = this.getCurrentSection();
			if (section && section.canDo)
			{
				resolve();
			}
			else
			{
				this.BX.ajax.runAction('calendar.api.calendarajax.getCompactFormData', {
					data: {
						entryId: this.entry.id,
						loadSectionId: this.entry.sectionId,
					},
				}).then((response) => {
					if (response && response.data && response.data.section)
					{
						// todo: refactor this part to new Section entities
						this.sections.push(new window.BXEventCalendar.Section(Util.getCalendarContext(), response.data.section));
						this.setSections(this.sections);
						resolve();
					}
				});
			}
		});
	}

	getEntryCounter()
	{
		if (!this.DOM.entryCounter)
		{
			this.DOM.entryCounter = Tag.render`
				<span class="calendar-event-invite-counter calendar-event-invite-counter-big">1</span>
			`;
		}

		if (this.entry.isInvited())
		{
			Dom.removeClass(this.DOM.entryCounter, 'calendar-event-invite-counter-none');
		}
		else
		{
			Dom.addClass(this.DOM.entryCounter, 'calendar-event-invite-counter-none');
		}

		return this.DOM.entryCounter;
	}

	getTitleControl()
	{
		this.DOM.titleInput = Tag.render`
			<input class="calendar-field calendar-field-string --text-overflow-none"
				value=""
				placeholder="${Loc.getMessage('EC_ENTRY_NAME')}"
				type="text"
			/>
		`;

		this.bindFade();

		Event.bind(this.DOM.titleInput, 'keyup', this.checkForChangesDebounce);
		Event.bind(this.DOM.titleInput, 'change', this.checkForChangesDebounce);
		Event.bind(this.DOM.titleInput, 'keyup', this.updateEventNameInputTitle.bind(this));
		Event.bind(this.DOM.titleInput, 'change', this.updateEventNameInputTitle.bind(this));

		return this.DOM.titleInput;
	}

	bindFade()
	{
		let isInputFocus = false;

		Event.bind(this.DOM.titleInput, 'focusout', () => {
			if (this.DOM.titleInput.scrollWidth > this.DOM.titleInput.offsetWidth)
			{
				this.getTitleFade().classList.add('--show');
			}
			else
			{
				this.getTitleFade().classList.remove('--show');
			}
			isInputFocus = false;
		});

		Event.bind(this.DOM.titleInput, 'focus', () => {
			this.getTitleFade().classList.remove('--show');
			isInputFocus = true;
		});

		Event.bind(this.DOM.titleInput, 'scroll', () => {
			if (
				this.DOM.titleInput.scrollWidth > this.DOM.titleInput.offsetWidth
				&& Math.ceil(this.DOM.titleInput.offsetWidth + this.DOM.titleInput.scrollLeft) < this.DOM.titleInput.scrollWidth
				&& !isInputFocus
			)
			{
				this.getTitleFade().classList.add('--show');
			}
			else
			{
				this.getTitleFade().classList.remove('--show');
			}
		});
	}

	getTitleFade()
	{
		if (!this.DOM.titleFade)
		{
			this.DOM.titleFade = Tag.render`
				<div class="calendar-field-title-fade"></div>	
			`;
		}

		return this.DOM.titleFade;
	}

	getTitleControlLocation()
	{
		this.DOM.titleInput = Tag.render`
			<input class="calendar-field calendar-field-string --text-overflow-none"
				value=""
				placeholder="${Loc.getMessage('EC_ENTRY_NAME')}"
				type="text"
				readonly
			/>
		`;

		this.bindFade();

		return this.DOM.titleInput;
	}

	getHostControl()
	{
		const userId = this.entry.data.CREATED_BY;
		const userUrl = CompactEventForm.USER_URL.replace('#USER_ID#', userId);
		const userAvatar = this.BX.Calendar.EntryManager.userIndex[userId]
			? this.BX.Calendar.EntryManager.userIndex[userId].AVATAR
			: ''
		;

		this.DOM.hostBar = Tag.render`
			<div class="calendar-slider-detail-option-without-border">
				<div class="calendar-slider-detail-option-block">
					<div class="calendar-field-value">
						${`${Loc.getMessage('EC_HOST')}: `}
					</div>
					<span class="calendar-field-location-host-img">
						<a href="${userUrl}">
							${this.renderAvatar(userAvatar)}
						</a>
					</span>
					<div class="calendar-slider-detail-option-value">
						<a href="${userUrl}" class="calendar-slider-sidebar-user-info-name calendar-slider-sidebar-user-info-name-padding">${BX.util.htmlspecialchars(this.entry.name)}</a>
					</div>
				</div>
			</div>
		`;

		return this.DOM.hostBar;
	}

	renderAvatar(src)
	{
		const avatarClassName = 'calendar-field-location-host-img-value';

		if (this.isAvatar(src))
		{
			return Tag.render`
				<img class="${avatarClassName}" src="${src}" alt="">
			`;
		}

		return Tag.render`
			<div class="ui-icon ui-icon-common-user ${avatarClassName}"><i></i></div>
		`;
	}

	isAvatar(src)
	{
		return Type.isStringFilled(src) && src !== '/bitrix/images/1.gif';
	}

	getColorControl()
	{
		this.DOM.colorSelect = Tag.render`<div class="calendar-field calendar-field-select calendar-field-tiny"></div>`;
		this.colorSelector = new ColorSelector({
			wrap: this.DOM.colorSelect,
			mode: 'selector',
		});

		this.colorSelector.subscribe('onChange', (event) => {
			if (event instanceof BaseEvent)
			{
				const color = event.getData().value;
				if (
					!this.isNewEntry()
					&& (this.canDo('edit') || this.entry.getCurrentStatus() !== false)
				)
				{
					this.BX.ajax.runAction('calendar.api.calendarajax.updateColor', {
						data: {
							entryId: this.entry.id,
							userId: this.userId,
							color,
						},
					});
					this.entry.data.COLOR = color;

					this.emit('doRefresh');
					this.emitOnChange();
				}
			}
		});

		return this.DOM.colorSelect;
	}

	getColorControlsLocationView()
	{
		this.DOM.colorSelect = Tag.render`<div class="calendar-field calendar-field-select calendar-colorpicker-readonly calendar-field-tiny"></div>`;
		this.colorSelector = new ColorSelector({
			wrap: this.DOM.colorSelect,
			mode: 'view',
		});

		return this.DOM.colorSelect;
	}

	getSectionControl(mode)
	{
		this.DOM.sectionSelectWrap = Tag.render`<div class="calendar-field-choice-calendar"></div>`;
		this.sectionSelector = new SectionSelector({
			outerWrap: this.DOM.sectionSelectWrap,
			defaultCalendarType: this.type,
			defaultOwnerId: this.ownerId,
			sectionList: Util.filterSectionsByContext(this.sections, {
				isCollabUser: this.isCollabUser,
				calendarType: this.type,
				calendarOwnerId: this.ownerId,
			}),
			sectionGroupList: SectionManager.getSectionGroupList({
				type: this.type,
				ownerId: this.ownerId,
				userId: this.userId,
				trackingUsersList: this.trackingUsersList,
				isCollabUser: this.isCollabUser,
				isCollabContext: this.getCurrentSection().isCollab(),
			}),
			mode,
			zIndex: this.zIndex,
			getCurrentSection: () => {
				const section = this.getCurrentSection();
				if (section)
				{
					return {
						id: section.id,
						name: section.name,
						color: section.color,
					};
				}

				return false;
			},
			selectCallback: (sectionValue) => {
				if (sectionValue)
				{
					if (this.colorSelector)
					{
						this.colorSelector.setValue(sectionValue.color);
					}
					this.sectionValue = sectionValue.id;
					this.checkForChangesDebounce();

					SectionManager.saveDefaultSectionId(this.sectionValue);
				}
			},
		});

		return this.DOM.sectionSelectWrap;
	}

	getDateTimeControl()
	{
		this.DOM.dateTimeWrap = Tag.render`<div class="calendar-field-container calendar-field-container-datetime"></div>`;

		this.dateTimeControl = new DateTimeControl(null, {
			showTimezone: false,
			outerWrap: this.DOM.dateTimeWrap,
			inlineEditMode: true,
		});

		this.dateTimeControl.subscribe('onSetValue', () => {
			this.excludedUsers = [];
		});

		this.dateTimeControl.subscribe('onChange', (event) => {
			if (event instanceof BaseEvent)
			{
				const value = event.getData().value;
				if (this.remindersControl)
				{
					this.remindersControl.setFullDayMode(value.fullDay);

					if (this.isNewEntry() && !this.remindersControl.wasChangedByUser())
					{
						const defaultReminders = EntryManager.getNewEntryReminders(
							value.fullDay ? 'fullDay' : 'withTime',
						);

						this.remindersControl.setValue(defaultReminders, false);
					}
				}

				if (this.userPlannerSelector)
				{
					if (!this.userPlannerSelector.isPlannerDisplayed())
					{
						this.userPlannerSelector.showPlanner();
						this.userPlannerSelector.refreshPlannerStateDebounce();
					}
					this.userPlannerSelector.setLocationValue(this.locationSelector.getTextValue());
					this.userPlannerSelector.setDateTime(value, true);
				}

				if (this.locationSelector)
				{
					this.locationSelector.checkLocationAccessibility(
						{
							from: event.getData().value.from,
							to: event.getData().value.to,
							fullDay: event.getData().value.fullDay,
							currentEventId: this.entry.parentId,
						},
					);
				}

				this.checkForChangesDebounce();
			}
		});

		return this.DOM.dateTimeWrap;
	}

	getUserPlannerSelector()
	{
		this.DOM.userPlannerSelectorOuterWrap = Tag.render`<div>
			<div class="calendar-field-container calendar-field-container-members">
				${this.DOM.userSelectorWrap = Tag.render`
				<div class="calendar-field-block">
					<div class="calendar-members-selected">
						<span class="calendar-attendees-label"></span>
						<span class="calendar-attendees-list"></span>
						<span class="calendar-members-more">${Loc.getMessage('EC_ATTENDEES_MORE')}</span>
						<span class="calendar-members-change-link">${Loc.getMessage('EC_SEC_SLIDER_CHANGE')}</span>
					</div>
				</div>`}
				<span class="calendar-videocall-wrap calendar-videocall-hidden"></span>
				${this.DOM.informWrap = Tag.render`
				<div class="calendar-field-container-inform">
					<span class="calendar-field-container-inform-text">${Loc.getMessage('EC_NOTIFY_OPTION')}</span>
				</div>`}
			</div>
			<div class="calendar-user-selector-wrap"></div>
			<div class="calendar-add-popup-planner-wrap calendar-add-popup-show-planner">
				${this.DOM.plannerOuterWrap = Tag.render`
				<div class="calendar-planner-wrapper" style="height: 0">
				</div>`}
			</div>
			${this.DOM.hideGuestsWrap = Tag.render`
			<div class="calendar-hide-members-container" style="display: none;">
				<div class="calendar-hide-members-container-inner">
					<div class="calendar-hide-members-icon-hidden"></div>
					<div class="calendar-hide-members-text">${Loc.getMessage('EC_HIDE_GUEST_NAMES')}</div>
					<span class="calendar-hide-members-helper" data-hint="${Loc.getMessage('EC_HIDE_GUEST_NAMES_HINT')}"></span>
				</div>
			</div>`}
		<div>`;

		this.userPlannerSelector = new UserPlannerSelector({
			plannerReadOnly: !this.canDo('editUserPlannerSelector'),
			outerWrap: this.DOM.userPlannerSelectorOuterWrap,
			wrap: this.DOM.userSelectorWrap,
			informWrap: this.DOM.informWrap,
			plannerOuterWrap: this.DOM.plannerOuterWrap,
			hideGuestsWrap: this.DOM.hideGuestsWrap,
			readOnlyMode: false,
			userId: this.userId,
			type: this.type,
			ownerId: this.ownerId,
			zIndex: this.zIndex + 10,
			plannerFeatureEnabled: this.plannerFeatureEnabled,
			isEditableSharingEvent: this.shouldShowFakeUserControl(),
			openEditFormCallback: () => {
				this.editEntryInSlider('userSelector');
			},
		});

		this.userPlannerSelector.subscribe('onDateChange', this.handlePlannerSelectorChanges.bind(this));
		this.userPlannerSelector.subscribe('onNotifyChange', this.checkForChangesDebounce);
		this.userPlannerSelector.subscribe('onUserCodesChange', this.checkForChangesDebounce);

		return this.DOM.userPlannerSelectorOuterWrap;
	}

	getRelationControl(): HTMLElement
	{
		this.DOM.relationWrap = null;
		if (this.entry?.data?.EVENT_TYPE === '#shared_crm#')
		{
			this.DOM.relationWrap = Tag.render`<div></div>`;
			this.relationControl = new RelationInterface({
				parentNode: this.DOM.relationWrap,
				eventId: this.entry.parentId,
			});
			Dom.append(this.relationControl.render(), this.DOM.relationWrap);
		}

		return this.DOM.relationWrap;
	}

	getLocationControl()
	{
		this.DOM.locationWrap = Tag.render`<div class="calendar-field-place"></div>`;

		this.locationSelector = new Location(
			{
				wrap: this.DOM.locationWrap,
				readOnly: !this.canDo('edit'),
				richLocationEnabled: this.locationFeatureEnabled,
				hideLocationLock: this.isCollabUser,
				locationList: this.locationList || [],
				roomsManager: this.roomsManager || null,
				locationAccess: this.locationAccess || false,
				iblockMeetingRoomList: this.iblockMeetingRoomList || [],
				inlineEditModeEnabled: !this.isLocationCalendar,
				onChangeCallback: () => {
					if (this.userPlannerSelector)
					{
						this.userPlannerSelector.setLocationValue(this.locationSelector.getTextValue());
						if (this.locationSelector.getValue().type !== undefined
							&& !this.userPlannerSelector.isPlannerDisplayed())
						{
							this.userPlannerSelector.showPlanner();
						}
						this.userPlannerSelector.refreshPlannerStateDebounce();
					}
					this.checkForChangesDebounce();
				},
			},
		);

		const locationName = this.locationSelector.getTextLocation(Location.parseStringValue(this.entry.getLocation()));
		this.DOM.editLocationInFullForm = Tag.render`
			<div class="calendar-field-place-link">
				<span class="calendar-text-link">
					${BX.util.htmlspecialchars(locationName) || Loc.getMessage('EC_REMIND1_ADD')}
				</span>
			</div>
		`;
		Event.bind(this.DOM.editLocationInFullForm, 'click', () => this.editEntryInSlider('location'));
		Dom.style(this.DOM.editLocationInFullForm, 'display', this.shouldShowFakeLocationControl() ? '' : 'none');

		this.DOM.locationOuterWrap = Tag.render`
			<div class="calendar-field-block">
				<div class="calendar-field-title calendar-field-title-align-top">${Loc.getMessage('EC_LOCATION_LABEL')}:</div>
				${this.DOM.locationWrap}
				${this.DOM.editLocationInFullForm}
			</div>
		`;

		if (this.userPlannerSelector)
		{
			this.userPlannerSelector.subscribe('onDisplayAttendees', this.checkLocationForm.bind(this));
			this.userPlannerSelector.planner?.subscribe('onDisplayAttendees', this.checkLocationForm.bind(this));
		}

		return this.DOM.locationOuterWrap;
	}

	createRemindersControl()
	{
		this.reminderValues = [];
		this.DOM.remindersWrap = Tag.render`<div class="calendar-text"></div>`;
		this.remindersControl = new Reminder({
			wrap: this.DOM.remindersWrap,
			zIndex: this.zIndex,
		});

		this.remindersControl.subscribe('onChange', (event) => {
			if (event instanceof BaseEvent)
			{
				this.reminderValues = event.getData().values;
				if (!this.isNewEntry()
					&& (this.canDo('edit')
						|| this.entry.getCurrentStatus() !== false))
				{
					this.BX.ajax.runAction('calendar.api.calendarajax.updateReminders', {
						data: {
							entryId: this.entry.id,
							userId: this.userId,
							reminders: this.reminderValues,
						},
					}).then((response) => {
						this.entry.data.REMIND = response.data.REMIND;
					});
				}
			}
		});

		return this.DOM.remindersWrap;
	}

	getTypeInfoControl()
	{
		this.DOM.typeInfoTitle = Tag.render`<div class="calendar-field-title"></div>`;
		this.DOM.typeInfoLink = Tag.render`<div class="calendar-field-link"></div>`;

		this.DOM.typeInfoWrap = Tag.render`
			<div class="calendar-field-block" style="display: none">
				${this.DOM.typeInfoTitle}
				${this.DOM.typeInfoLink}
			</div>
		`;

		return this.DOM.typeInfoWrap;
	}

	getRRuleInfoControl()
	{
		this.DOM.rruleInfo = Tag.render`<div class="calendar-text"></div>`;
		this.DOM.rruleInfoWrap = Tag.render`
			<div class="calendar-field-block" style="display: none">
				<div class="calendar-field-title">${Loc.getMessage('EC_REPEAT')}:</div>
				${this.DOM.rruleInfo}
			</div>
		`;

		return this.DOM.rruleInfoWrap;
	}

	getTimezoneInfoControl()
	{
		this.DOM.timezoneInfo = Tag.render`<div class="calendar-text"></div>`;
		this.DOM.timezoneInfoWrap = Tag.render`
			<div class="calendar-field-block" style="display: none">
				<div class="calendar-field-title">${Loc.getMessage('EC_TIMEZONE')}:</div>
				${this.DOM.timezoneInfo}
			</div>
		`;

		return this.DOM.timezoneInfoWrap;
	}

	isNewEntry()
	{
		return !this.entry.id;
	}

	canDo(action)
	{
		const section = this.getCurrentSection();

		if (action === 'edit' || action === 'delete')
		{
			if ((this.entry.isMeeting() && this.entry.id !== this.entry.parentId))
			{
				return false;
			}

			if (this.entry.isResourcebooking())
			{
				return false;
			}

			if (!this.isNewEntry() && this.isCollabUser && !this.entry?.permissions.edit)
			{
				return false;
			}

			return section.canDo('edit');
		}

		if (action === 'view')
		{
			if (this.entry.permissions && Type.isBoolean(this.entry.permissions.view_time))
			{
				return this.entry.permissions.view_time === true;
			}

			return section.canDo('view_time');
		}

		if (action === 'viewFull')
		{
			if (this.entry.permissions && Type.isBoolean(this.entry.permissions.view_full))
			{
				return this.entry.permissions.view_full === true;
			}

			return section.canDo('view_full');
		}

		if (action === 'release')
		{
			return section.canDo('access');
		}

		const isInvitedOrRejected = ['Q', 'N'].includes(this.entry.getCurrentStatus());
		if (action === 'editLocation')
		{
			const canEdit = this.entry.permissions?.edit === true;
			const canEditLocation = this.entry.permissions?.edit_location === true;

			return this.isNewEntry() || !isInvitedOrRejected && (canEdit || canEditLocation);
		}

		if (action === 'editAttendees')
		{
			const canEdit = this.entry.permissions?.edit === true;
			const canEditAttendees = this.entry.permissions?.edit_attendees === true;

			return this.isNewEntry() || !isInvitedOrRejected && (canEdit || canEditAttendees);
		}

		if (action === 'editUserPlannerSelector')
		{
			return this.isNewEntry() || this.entry.permissions?.edit === true;
		}

		return true;
	}

	setFormValues()
	{
		const entry = this.entry;
		const section = this.getCurrentSection();
		const readOnly = !this.canDo('edit');

		// Date time
		this.dateTimeControl.setValue({
			from: Util.adjustDateForTimezoneOffset(entry.from, entry.userTimezoneOffsetFrom, entry.fullDay),
			to: Util.adjustDateForTimezoneOffset(entry.to, entry.userTimezoneOffsetTo, entry.fullDay),
			fullDay: entry.fullDay,
			timezoneFrom: entry.getTimezoneFrom() || '',
			timezoneTo: entry.getTimezoneTo() || '',
			timezoneName: this.userSettings.timezoneName,
		});
		this.dateTimeControl.setInlineEditMode(this.isNewEntry() ? 'edit' : 'view');
		this.dateTimeControl.setViewMode(readOnly);

		// Title
		this.setEventNameInputValue(entry.getName());

		if (readOnly)
		{
			Dom.attr(this.DOM.titleInput, 'readonly', 'readonly');
		}

		// Color
		this.colorSelector.setValue(entry.getColor() || section.color, false);
		this.colorSelector.setViewMode(readOnly && this.entry.getCurrentStatus() === false);

		// Section
		this.sectionValue = this.getCurrentSectionId();
		this.sectionSelector.updateValue();
		if ((this.isSyncSection(section) || entry.isSharingEvent()) && entry.id)
		{
			this.sectionSelector.setViewMode(true);
		}
		else
		{
			this.sectionSelector.setViewMode(readOnly);
		}

		// Reminders
		this.remindersControl.setValue(entry.getReminders(), false);
		this.remindersControl.setViewMode(readOnly && this.entry.getCurrentStatus() === false);
		if (readOnly && this.entry.getCurrentStatus() === false)
		{
			this.DOM.remindersOuterWrap.style.display = 'none';
		}

		// Recurcion
		if (entry.isRecursive())
		{
			this.DOM.rruleInfoWrap.style = '';
			Dom.adjust(this.DOM.rruleInfo, { text: entry.getRRuleDescription() });
		}

		// Location
		const readOnlyLocation = !this.canDo('editLocation');
		let location = entry.getLocation();

		Dom.style(this.DOM.editLocationInFullForm, 'display', 'none');
		Dom.style(this.DOM.locationWrap, 'display', '');
		Dom.style(this.DOM.locationOuterWrap, 'display', '');

		if (this.shouldShowFakeLocationControl())
		{
			Dom.style(this.DOM.editLocationInFullForm, 'display', '');
			Dom.style(this.DOM.locationWrap, 'display', 'none');
		}
		else if (readOnlyLocation && !location)
		{
			Dom.style(this.DOM.locationOuterWrap, 'display', 'none');
		}
		else
		{
			this.locationSelector.setViewMode(readOnlyLocation);
			if (this.isLocationCalendar)
			{
				this.locationSelector.setValue(this.locationSelector.default);
				location = this.locationSelector.default;
			}
			else
			{
				this.DOM.locationOuterWrap.style.display = '';
				this.locationSelector.setValue(entry.getLocation());
			}
		}

		if (this.locationSelector)
		{
			this.locationSelector.checkLocationAccessibility(
				{
					from: this.dateTimeControl.getValue().from,
					to: this.dateTimeControl.getValue().to,
					fullDay: this.dateTimeControl.getValue().fullDay,
					currentEventId: this.entry.parentId,
				},
			);
		}

		// User Planner Selector
		if (
			this.userPlannerSelector
			&& (this.canDo('viewFull') || entry.getCurrentStatus() !== false)
		)
		{
			this.userPlannerSelector.setValue({
				attendeesEntityList: entry.getAttendeesEntityList(),
				location,
				attendees: entry.getAttendees(),
				notify: !entry.isMeeting() || entry.getMeetingNotify(),
				viewMode: this.getMode() === CompactEventForm.VIEW_MODE,
				entry,
				hideGuests: entry.getHideGuests(),
				attendeesUndeselectedItems: this.getUndeselectedItems(),
			});
			this.userPlannerSelector.setDateTime(this.dateTimeControl.getValue());
			const readOnlyUserPlanner = !this.canDo('editAttendees');
			if (readOnlyUserPlanner)
			{
				this.userPlannerSelector.setViewMode(readOnlyUserPlanner);
			}

			if (this.shouldShowFakeUserControl())
			{
				this.userPlannerSelector.setEditableSharingEventMode();
			}
		}
		else
		{
			Dom.remove(this.DOM.userPlannerSelectorOuterWrap);
		}

		if (!this.canDo('edit') && this.canDo('editAttendees'))
		{
			this.userPlannerSelector.setCanEditAttendeesMode();
		}

		let hideInfoContainer = true;
		this.DOM.infoContainer = this.DOM.wrap.querySelector('.calendar-field-container-info');
		for (let i = 0; i <= this.DOM.infoContainer.childNodes.length; i++)
		{
			if (
				Type.isElementNode(this.DOM.infoContainer.childNodes[i])
				&& this.DOM.infoContainer.childNodes[i].style.display !== 'none'
			)
			{
				hideInfoContainer = false;
			}
		}

		if (hideInfoContainer)
		{
			this.DOM.infoContainer.style.display = 'none';
		}
	}

	shouldShowFakeLocationControl()
	{
		if (this.entry.isSharingEvent())
		{
			return this.canDo('editLocation')
				&& (
					this.entry.permissions?.edit
					|| this.entry.permissions?.edit_location
					|| this.canDo('edit')
				)
			;
		}

		return this.canDo('editLocation') && !this.canDo('edit');
	}

	shouldShowFakeUserControl(): boolean
	{
		if (this.entry.isSharingEvent())
		{
			return this.canDo('editAttendees')
				&& (
					this.entry.permissions?.edit
					|| this.entry.permissions?.edit_attendees
					|| this.canDo('edit')
				)
			;
		}

		return this.canDo('editAttendees') && !this.canDo('edit');
	}

	setEventNameInputValue(name: string)
	{
		this.DOM.titleInput.value = name;
	}

	setFormValuesLocation()
	{
		const entry = this.entry;
		const section = this.getCurrentSection();
		const readOnly = true;

		// Date time
		this.dateTimeControl.setValue({
			from: Util.adjustDateForTimezoneOffset(entry.from, entry.userTimezoneOffsetFrom, entry.fullDay),
			to: Util.adjustDateForTimezoneOffset(entry.to, entry.userTimezoneOffsetTo, entry.fullDay),
			fullDay: entry.fullDay,
			timezoneFrom: entry.getTimezoneFrom() || '',
			timezoneTo: entry.getTimezoneTo() || '',
			timezoneName: this.userSettings.timezoneName,
		});
		this.dateTimeControl.setInlineEditMode(this.isNewEntry() ? 'edit' : 'view');
		this.dateTimeControl.setViewMode(readOnly);

		// Title
		let name = '';
		if (this.entry.id === this.entry.parentId)
		{
			name = Loc.getMessage('CALENDAR_UPDATE');
		}
		else
		{
			name = `${section.name}: ${BX.util.htmlspecialchars(entry.getName())}`;
		}
		this.setEventNameInputValue(name);

		// Color
		this.colorSelector.setValue(entry.getColor() || section.color, false);
		this.colorSelector.setViewMode(!readOnly);

		// Section
		this.sectionValue = this.getCurrentSectionId();
		this.sectionSelector.updateValue();
		this.sectionSelector.setViewMode(readOnly);
	}

	save(options = {}): boolean
	{
		if (this.state === this.STATE.REQUEST)
		{
			return false;
		}

		const entry = this.getCurrentEntry();
		options = Type.isPlainObject(options) ? options : {};

		if (
			!this.userSettings.sendFromEmail
			&& this.userPlannerSelector.hasExternalEmailUsers()
			&& !options.emailConfirmDialogShown
		)
		{
			EntryManager.showConfirmedEmailDialog({
				callback: (params) => {
					options.emailConfirmDialogShown = true;
					this.save(options);
				},
			});

			return false;
		}

		if (
			!this.isNewEntry()
			&& entry.isRecursive()
			&& !options.confirmed
			&& this.getFormDataChanges(['section', 'notify']).length > 0
		)
		{
			EntryManager.showConfirmEditDialog({
				callback: (params) => {
					options.recursionMode = (entry.isFirstInstance() && params.recursionMode === 'next')
						? 'all'
						: params.recursionMode;
					options.confirmed = true;
					this.lastUsedSaveOptions = options;
					this.save(options);
				},
			});

			return false;
		}

		if (
			!this.isNewEntry()
			&& entry.isMeeting()
			&& options.sendInvitesAgain === undefined
			&& this.getFormDataChanges().includes('date&time')
			&& entry.getAttendees().find((item) => {
				return item.STATUS === 'N';
			})
		)
		{
			EntryManager.showReInviteUsersDialog({
				callback: (params) => {
					options.sendInvitesAgain = params.sendInvitesAgain;
					this.lastUsedSaveOptions = options;
					this.save(options);
				},
			});

			return false;
		}

		if (
			!this.isNewEntry()
			&& entry.isRecursive()
			&& !options.confirmed
			&& this.getFormDataChanges().includes('section')
		)
		{
			options.recursionMode = entry.isFirstInstance() ? 'all' : 'next';
		}

		const dateTime = this.dateTimeControl.getValue();
		const data = {
			id: entry.id,
			section: this.sectionValue,
			name: this.DOM.titleInput.value,
			desc: entry.getDescription(),
			reminder: this.remindersControl.getSelectedValues(),
			date_from: dateTime.fromDate,
			date_to: dateTime.toDate,
			skip_time: dateTime.fullDay ? 'Y' : 'N',
			time_from: Util.formatTime(
				Util.adjustDateForTimezoneOffset(dateTime.from, -entry.userTimezoneOffsetFrom, dateTime.fullDay)
			),
			time_to: Util.formatTime(
				Util.adjustDateForTimezoneOffset(dateTime.to, -entry.userTimezoneOffsetTo, dateTime.fullDay)
			),
			location: this.locationSelector.getTextValue(),
			tz_from: entry.getTimezoneFrom(),
			tz_to: entry.getTimezoneTo(),
			meeting_notify: this.userPlannerSelector.getInformValue() ? 'Y' : 'N',
			meeting_host: entry.data.MEETING_HOST || '0',
			chat_id: entry.data.MEETING
				? entry.data.MEETING.CHAT_ID
				: 0,
			exclude_users: (this.excludedUsers || []).map((user) => user.ID).join(','),
			attendeesEntityList: this.userPlannerSelector.getEntityList(),
			sendInvitesAgain: options.sendInvitesAgain ? 'Y' : 'N',
			hide_guests: this.userPlannerSelector.hideGuests ? 'Y' : 'N',
			requestUid: BX.Calendar.Util.registerRequestId(),
			private_event: entry.isPrivate() ? 'Y' : 'N',
		};

		let checkCurrentUsersAccessibility = !entry.id || this.checkCurrentUsersAccessibility();
		if (
			!checkCurrentUsersAccessibility
			&& this.getFormDataChanges().includes('codes')
		)
		{
			const previousAttendeesList = entry.getAttendeesEntityList();
			const newAttendeesList = [];
			data.attendeesEntityList.forEach((entity) => {
				if (!previousAttendeesList.find((item) => {
					return entity.entityId === item.entityId
						&& parseInt(entity.id) === parseInt(item.id);
				}))
				{
					if (entity.entityId === 'user')
					{
						newAttendeesList.push(entity.id);
					}
					else
					{
						checkCurrentUsersAccessibility = true;
					}
				}
			});
			data.newAttendeesList = newAttendeesList;
		}
		data.checkCurrentUsersAccessibility = checkCurrentUsersAccessibility ? 'Y' : 'N';

		data.doCheckOccupancy = options.doCheckOccupancy === false ? 'N' : 'Y';

		if (entry.id && entry.isRecursive())
		{
			data.EVENT_RRULE = entry.data.RRULE;
		}

		if (options.recursionMode)
		{
			data.rec_edit_mode = options.recursionMode;
			data.current_date_from = Util.formatDate(entry.from);
		}

		if (this.getCurrentSection().color.toLowerCase() !== this.colorSelector.getValue().toLowerCase())
		{
			data.color = this.colorSelector.getValue();
		}

		if (this.analyticsSubSection)
		{
			data.analyticsSubSection = this.analyticsSubSection;
		}

		this.state = this.STATE.REQUEST;

		this.freezePopup();
		this.BX.ajax.runAction('calendar.api.calendarentryajax.editEntry', { data })
			.then(
				(response) => {
					if (this.isLocationCalendar && this.roomsManager)
					{
						this.roomsManager.unsetHiddenRoom(Location.parseStringValue(data.location).room_id);
					}

					if (this.excludedUsers)
					{
						this.excludedUsers = [];
					}

					// unset section from hidden
					const section = this.getCurrentSection();
					if (section && !section.isShown())
					{
						section.show();
					}

					this.unfreezePopup();
					this.state = this.STATE.READY;
					if (response.data.entryId)
					{
						if (entry.id)
						{
							EntryManager.showEditEntryNotification(response.data.entryId);
						}
						else
						{
							EntryManager.showNewEntryNotification(response.data.entryId);
						}
					}

					this.emit('onSave', new BaseEvent({
						data: {
							responseData: response.data,
							options,
						},
					}));
					this.close();

					if (Type.isArray(response.data.eventList)
						&& response.data.eventList.length > 0
						&& response.data.eventList[0].REMIND
					)
					{
						EntryManager.setNewEntryReminders(
							dateTime.fullDay ? 'fullDay' : 'withTime',
							response.data.eventList[0].REMIND,
						);
					}
				},
				(response) => {
					this.unfreezePopup();

					const errors = [];
					response.errors.forEach((error) => {
						if (
							error.code !== 'edit_entry_user_busy'
							&& error.code !== 'edit_entry_location_repeat_busy'
							&& error.code !== 'edit_entry_location_busy_recurrence'
						)
						{
							errors.push(error);
						}
						else if (error.code === 'edit_entry_location_repeat_busy')
						{
							this.showLocationRepeatBusyErrorPopup(error.message);
						}
					});

					response.errors = errors;

					if (response.data && Type.isPlainObject(response.data.busyUsersList))
					{
						this.handleBusyUsersError(response.data.busyUsersList);
					}

					if (response.errors && response.errors.length > 0)
					{
						this.showError(response.errors);
					}

					this.state = this.STATE.ERROR;
				},
			);

		return true;
	}

	showLocationRepeatBusyErrorPopup(message)
	{
		if (!this.DOM.locationRepeatBusyErrorPopup)
		{
			this.DOM.locationRepeatBusyErrorPopup = EntryManager.getLocationRepeatBusyErrorPopup({
				message,
				onYesCallback: () => {
					this.lastUsedSaveOptions.doCheckOccupancy = false;
					this.save(this.lastUsedSaveOptions);
					this.lastUsedSaveOptions = {};
					this.DOM.locationRepeatBusyErrorPopup.close();
				},
				onCancelCallback: () => {
					this.DOM.locationRepeatBusyErrorPopup.close();
				},
				onPopupCloseCallback: () => {
					delete this.DOM.locationRepeatBusyErrorPopup;
				},
			});

			this.DOM.locationRepeatBusyErrorPopup.show();
		}
	}

	handleBusyUsersError(busyUsers)
	{
		const users = [];

		for (const id in busyUsers)
		{
			if (busyUsers.hasOwnProperty(id))
			{
				users.push(busyUsers[id]);
			}
		}

		this.busyUsersDialog = new BusyUsersDialog();

		this.busyUsersDialog.subscribe('onContinueEditing', () => {
			this.excludedUsers = [];
		});

		this.busyUsersDialog.subscribe('onSaveWithout', () => {
			this.excludedUsers.push(...users);
			this.save();
		});

		this.busyUsersDialog.show({ users });
	}

	handleKeyPress(e)
	{
		if (
			this.getMode() === CompactEventForm.EDIT_MODE
			&& e.keyCode === Util.getKeyCode('enter')
			&& (e.ctrlKey || e.metaKey) && !e.altKey
			&& !this.isAdditionalPopupShown()
		)
		{
			if (this.busyUsersDialog && this.busyUsersDialog.isShown())
			{
				return;
			}

			this.checkDataBeforeCloseMode = false;
			this.locationSelector.selectContol.onChangeCallback();
			this.save();
		}
		else if (
			this.checkTopSlider()
			&& e.keyCode === Util.getKeyCode('escape')
			&& e.type === 'keyup'
			&& this.couldBeClosedByEsc()
		)
		{
			this.close();
		}
		else if (
			e.keyCode === Util.getKeyCode('delete')
			&& !this.isNewEntry()
			&& this.canDo('delete')
		)
		{
			const target = event.target || event.srcElement;
			const tagName = Type.isElementNode(target) ? target.tagName.toLowerCase() : null;
			if (tagName && !['input', 'textarea'].includes(tagName))
			{
				EventEmitter.subscribeOnce('BX.Calendar.Entry:beforeDelete', () => {
					this.checkDataBeforeCloseMode = false;
					this.close();
				});
				EntryManager.deleteEntry(this.entry);
			}
		}
		else if (
			e.keyCode === Util.getKeyCode('enter')
			&& this.DOM.confirmPopup
		)
		{
			this.close(true, true);
		}
	}

	isAdditionalPopupShown(): boolean
	{
		return this.DOM.locationRepeatBusyErrorPopup;
	}

	getCurrentEntry()
	{
		return this.entry;
	}

	getCurrentSection()
	{
		let section = false;
		const sectionId = this.getCurrentSectionId();

		if (
			sectionId
			&& this.sectionIndex[sectionId] !== undefined
			&& this.sections[this.sectionIndex[sectionId]] !== undefined)
		{
			section = this.sections[this.sectionIndex[sectionId]];
		}

		return section;
	}

	getCurrentSectionId()
	{
		let sectionId = 0;
		if (this.sectionValue)
		{
			sectionId = this.sectionValue;
		}
		else
		{
			const entry = this.getCurrentEntry();
			if (entry instanceof Entry)
			{
				sectionId = parseInt(entry.sectionId, 10);
			}

			// TODO: refactor - don't take first section
			if (!sectionId && this.sections[0])
			{
				sectionId = parseInt(this.sections[0].id, 10);
			}
		}

		return sectionId;
	}

	handlePlannerSelectorChanges(event)
	{
		if (event instanceof BaseEvent)
		{
			const dateTimeValue = this.dateTimeControl.getValue();
			dateTimeValue.from = event.getData().dateFrom;
			dateTimeValue.to = event.getData().dateTo;
			// Date time
			this.dateTimeControl.setValue(dateTimeValue);
			this.userPlannerSelector.setDateTime(this.dateTimeControl.getValue());

			if (this.locationSelector)
			{
				this.locationSelector.checkLocationAccessibility(
					{
						from: event.getData().dateFrom,
						to: event.getData().dateTo,
						fullDay: event.getData().fullDay,
						currentEventId: this.entry.parentId,
					},
				);
			}
			this.checkForChangesDebounce();
		}
	}

	editEntryInSlider(jumpToControl = false)
	{
		this.checkDataBeforeCloseMode = false;
		const dateTime = this.dateTimeControl.getValue();
		const calendarContext = Util.getCalendarContext();
		BX.Calendar.EntryManager.openEditSlider({
			calendarContext,
			entry: this.entry,
			type: this.type,
			isLocationCalendar: this.isLocationCalendar,
			locationAccess: this.locationAccess,
			roomsManager: this.roomsManager,
			locationCapacity: Location.getCurrentCapacity(), // for location component
			ownerId: this.ownerId,
			userId: this.userId,
			formDataValue: {
				section: this.sectionValue,
				name: this.DOM.titleInput.value,
				reminder: this.remindersControl.getSelectedRawValues(),
				color: this.colorSelector.getValue(),
				from: Util.adjustDateForTimezoneOffset(dateTime.from, -this.entry.userTimezoneOffsetFrom, dateTime.fullDay),
				to: Util.adjustDateForTimezoneOffset(dateTime.to, -this.entry.userTimezoneOffsetTo, dateTime.fullDay),
				fullDay: dateTime.fullDay,
				location: this.locationSelector.getTextValue(),
				meetingNotify: this.userPlannerSelector.getInformValue() ? 'Y' : 'N',
				hideGuests: this.userPlannerSelector.hideGuests ? 'Y' : 'N',
				attendeesEntityList: this.userPlannerSelector.getEntityList(),
			},
			jumpToControl,
		});
		this.close();
	}

	outsideMouseDownClose(event)
	{
		const target = event.target || event.srcElement;
		this.outsideMouseDown = !target.closest('div.popup-window');
	}

	checkTopSlider()
	{
		return !Util.getBX().SidePanel.Instance.getTopSlider();
	}

	checkOutsideClickClose(event)
	{
		const target = event.target || event.srcElement;
		this.outsideMouseUp = !target.closest('div.popup-window');
		if (this.couldBeClosedByEsc()
			&& this.outsideMouseDown
			&& this.outsideMouseUp
			&& (this.getMode() === CompactEventForm.VIEW_MODE
				|| !this.formDataChanged()
				|| this.isNewEntry())
		)
		{
			setTimeout(() => {
				this.close(false);
			}, 0);
		}
	}

	couldBeClosedByEsc()
	{
		return !PopupManager._popups.find((popup) => {
			return popup && popup.getId() !== this.popupId && popup.isShown();
		});
	}

	emitOnChange()
	{
		this.emit('onChange', new BaseEvent({
			data: {
				form: this,
				entry: this.entry,
			},
		}));
	}

	showError(errorList)
	{
		let errorText = '';

		if (Type.isArray(errorList))
		{
			errorList.forEach((error) => {
				errorText += `${error.message}\n`;
			});
		}

		if (errorText !== '')
		{
			alert(errorText);
		}
	}

	reloadEntryData()
	{
		if (this.isShown()
			&& !this.isNewEntry()
			&& this.getMode() === CompactEventForm.VIEW_MODE)
		{
			const calendar = Util.getCalendarContext();
			if (calendar)
			{
				const entry = EntryManager.getEntryInstance(
					calendar.getView().getEntryById(this.entry.getUniqueId()),
				);

				if (entry && entry.getUniqueId())
				{
					this.entry = entry;
					if (this.isLocationMode())
					{
						this.setFormValuesLocation();
					}
					else
					{
						this.setFormValues();
					}
				}
			}
		}
	}

	checkCurrentUsersAccessibility()
	{
		return this.getFormDataChanges().includes('date&time');
	}

	handlePull(params)
	{
		if (
			this.userPlannerSelector
			&& this.userPlannerSelector?.planner?.isShown()
		)
		{
			const userIdList = Type.isArray(params?.fields?.ATTENDEES) ? params.fields.ATTENDEES : [];
			const eventOwner = params?.fields?.CAL_TYPE === 'user'
				? parseInt(params?.fields?.OWNER_ID)
				: parseInt(params?.fields?.CREATED_BY);
			if (!userIdList.includes(eventOwner))
			{
				userIdList.push(eventOwner);
			}
			this.userPlannerSelector.clearAccessibilityData(userIdList);

			this.userPlannerSelector.refreshPlannerStateDebounce();
		}

		const entry = this.getCurrentEntry();
		if (
			!this.isNewEntry()
			&& entry
			&& entry.parentId === parseInt(params?.fields?.PARENT_ID)
		)
		{
			if (params.command === 'delete_event'
				&& entry.getType() === params?.fields?.CAL_TYPE)
			{
				this.close();
			}
			else
			{
				const onEntryListReloadHandler = () => {
					this.reloadEntryDataDebounce();
					BX.Event.EventEmitter.unsubscribe('BX.Calendar:onEntryListReload', onEntryListReloadHandler);
				};
				BX.Event.EventEmitter.subscribe('BX.Calendar:onEntryListReload', onEntryListReloadHandler);
			}
		}
	}

	isSyncSection(section)
	{
		return section.isGoogle()
			|| section.isIcloud()
			|| section.isOffice365()
			|| section.isCalDav()
			|| section.hasConnection()
		;
	}

	getSectionsForEditEvent(sections, currentSection)
	{
		const result = [];
		const currentType = currentSection.type;
		result.push(currentSection);

		sections.forEach((section) => {
			if (!this.isSyncSection(section) && section.type === currentType)
			{
				result.push(section);
			}
		});

		this.sections = result;
		this.updateSectionIndex();
	}

	releaseLocation(options = {})
	{
		const entry = this.getCurrentEntry();

		if (entry.id && entry.isRecursive()
			&& !options.confirmed
		)
		{
			EntryManager.showConfirmEditDialog({
				callback: (params) => {
					options.confirmed = true;
					this.releaseLocation({
						recursionMode: params.recursionMode,
						confirmed: true,
					});
				},
			});

			return false;
		}

		if (!options.recursionMode)
		{
			options.recursionMode = '';
		}

		this.state = this.STATE.REQUEST;

		this.freezePopup();

		this.BX.ajax.runAction('calendar.api.locationajax.cancelBooking', {
			data: {
				parent_event_id: entry.parentId,
				recursion_mode: options.recursionMode,
				section_id: entry.sectionId,
				current_event_date_from: entry.data.DATE_FROM,
				current_event_date_to: entry.data.DATE_TO,
				owner_id: entry.data.CREATED_BY,
			},
		})
			.then(
				(response) => {
					this.unfreezePopup();
					this.state = this.STATE.READY;
					EntryManager.showReleaseLocationNotification();
					this.calendarContext.reloadDebounce();
					this.close();
				},
				(response) => {
					this.unfreezePopup();
					this.state = this.STATE.ERROR;
					this.close();
				},
			);

		return true;
	}

	showConfirmClosePopup()
	{
		this.DOM.confirmPopup = new MessageBox({
			message: this.getConfirmContent(),
			minHeight: 120,
			minWidth: 350,
			maxWidth: 350,
			buttons: BX.UI.Dialogs.MessageBoxButtons.OK_CANCEL,
			onOk: () => {
				this.DOM.confirmPopup.close();
				this.close(true, true);
			},
			onCancel: () => {
				this.DOM.confirmPopup.close();
			},
			okCaption: Loc.getMessage('EC_SEC_SLIDER_CLOSE'),
			popupOptions: {
				events: {
					onPopupClose: () => {
						delete this.DOM.confirmPopup;
					},
				},
				closeByEsc: true,
				padding: 0,
				contentPadding: 0,
				animation: 'fading-slide',
			},
		});

		this.DOM.confirmPopup.show();
	}

	getConfirmContent()
	{
		return Tag.render`
			<div class="calendar-list-slider-messagebox-text">${`${Loc.getMessage('EC_LEAVE_EVENT_CONFIRM_QUESTION')
			}<br>${Loc.getMessage('EC_LEAVE_EVENT_CONFIRM_DESC')}`}</div>
		`;
	}

	getUndeselectedItems()
	{
		if (this.canDo('edit'))
		{
			return [];
		}

		return [['user', this.entry.data.MEETING_HOST || 0], ['user', this.entry.getOwnerId()]];
	}

	sendOpenViewCardAnalytics()
	{
		sendData({
			tool: 'im',
			category: 'events',
			event: 'view_card',
			c_section: 'card_compact',
			p5: `eventId_${this.entry.data.PARENT_ID}`,
		});
	}

	updateSectionIndex()
	{
		this.sectionIndex = {};
		if (Type.isArray(this.sections))
		{
			this.sections.forEach((value, ind) => {
				const id = parseInt(value.ID || value.id, 10);
				if (id > 0)
				{
					this.sectionIndex[id] = ind;
				}
			});
		}
	}

	getFormAnalyticsContext()
	{
		if (this.type === 'group')
		{
			return 'calendar_collab';
		}

		return 'calendar_personal';
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit