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/new/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/calendar/new/calendar-view-day-week.js
;(function(window) {
	var View = window.BXEventCalendarView;

	// Day view of the calendar
	function DayView()
	{
		View.apply(this, arguments);
		this.initConfig();
		this.preBuild();
	}
	DayView.prototype = Object.create(View.prototype);
	DayView.prototype.constructor = DayView;

	DayView.prototype.initConfig = function()
	{
		this.name = 'day';
		this.gridLineHeight = 60;
		this.slotHeight = 20;
		this.offHoursCollapsedHeight = 15;
		this.title = BX.message('EC_VIEW_DAY');
		this.entryWidthOffset = 2;
		this.lastEntryWidthOffset = 4;
		this.offsetForTimelineExpiredTime = 25;
		this.hotkey = 'D';

		this.contClassName = 'calendar-day-view';
		this.gridWrapClass = 'calendar-grid-wrap';
		if (BX.isAmPmMode())
		{
			this.gridWrapClass += ' is-am-pm-mode';
		}
		this.fullDayContClass = 'calendar-grid-day-full-days-events-holder';
		this.fullDayContHolderClass = 'calendar-grid-week-full-days-events-holder-grid';
		this.topEntryHolderClass = 'calendar-grid-day-events-holder';

		this.outerGridClass = 'calendar-grid-day-container';
		this.gridClass = 'calendar-grid-day';
		this.gridClassCurrent = 'calendar-grid-day-current';

		this.gridClassNext = 'calendar-grid-day-left-slide';
		this.gridClassPrevious = 'calendar-grid-day-right-slide';
		this.changeNextClass = 'calendar-change-day-left-slide';
		this.changePreviousClass = 'calendar-change-day-right-slide';

		this.gridRowClass = 'calendar-grid-day-row';
		this.gridCellClass = 'calendar-grid-day-cell';
		this.gridTimelinesClass = 'calendar-grid-day-time-lines';
		this.gridTimelineHourClass = 'calendar-grid-day-time-line-hour';
		this.gridTimelineHourLabelClass = 'calendar-grid-day-time-line-hour-label';
		this.gridTimelineHourLabelClassInner = 'calendar-grid-week-time-line-hour-label-inner';

		this.gridNowTimeClass = 'calendar-grid-day-time-line-hour-now';
		this.gridNowTimeLabelClass = 'calendar-grid-day-time-line-hour-label';
		this.gridNowTimeLineClass = 'calendar-grid-day-time-line-hour-now-line';
		this.gridNowTimeDotClass = 'calendar-grid-day-time-line-hour-now-dot';
		this.gridTimeTranslucentClass = 'calendar-grid-time-line-translucent';

		this.offHoursClass = 'calendar-grid-off-hours';
		this.offHoursCollapseClass = 'calendar-grid-off-hours-collapse';
		this.offHoursAnimateClass = 'calendar-grid-off-hours-animate';
		this.offHoursFastAnimateClass = 'calendar-grid-off-hours-fast-animate';

		this.dayCount = 1;
	};

	DayView.prototype.preBuild = function()
	{
		this.viewCont = BX.create('DIV', {props: {className: this.contClassName}, style: {display: 'none'}});
	};

	DayView.prototype.build = function()
	{
		this.titleCont = this.viewCont.appendChild(BX.create('DIV', {props: {className: 'calendar-grid-week-row-days-week'}}));

		this.fullDayEventsCont = this.viewCont.appendChild(BX.create('DIV', {props: {className: this.fullDayContClass}}));

		this.gridWrap = this.viewCont.appendChild(BX.create('DIV', {
			props: {className: this.gridWrapClass},
			style: {height: this.util.getViewHeight() + 'px'}
		}));
		this.checkTimelineScroll();
		this.outerGrid = this.gridWrap.appendChild(BX.create('DIV', {props: {className: this.outerGridClass}}));

		this.grid = this.outerGrid.appendChild(BX.create('DIV', {props: {className: this.gridClass + ' ' + this.gridClassCurrent}}));

		BX.bind(this.gridWrap, 'mousedown', BX.proxy(this.handleMousedown, this));
	};

	DayView.prototype.show = function()
	{
		View.prototype.show.apply(this, arguments);
		this.buildDaysGrid();

		this.showNavigationCalendar();
		BX.remove(this.calendar.additionalInfoOuter);

		this.loadEntries().then(entries => {
			this.entries = entries;
			this.displayEntries();
		});
	};

	DayView.prototype.hide = function()
	{
		View.prototype.hide.apply(this, arguments);
	};

	DayView.prototype.setFullDayHolderSize = function(size)
	{
		this.fullDayEventsCont.style.height = (size * (this.slotHeight + 1)) + 'px';
	};

	DayView.prototype.increaseViewRangeDate = function()
	{
		this.changeViewRangeDate(this.dayCount);
		this.highlightAll();
		this.setTitle();

		if (this.gridWrap)
		{
			this.gridWrap.style.overflowX = 'hidden';
		}

		var nextGrid = this.outerGrid.appendChild(BX.create('DIV', {props: {className: this.gridClass + ' ' + this.gridClassNext + ' ' + this.animateClass}}));
		BX.addClass(this.grid, this.animateClass);

		this.buildDaysGrid({grid: nextGrid});

		// Prepare entries while animatin goes
		this.preloadEntries();

		setTimeout(BX.delegate(function()
		{
			// Start CSS animation
			BX.addClass(this.outerGrid, this.changeNextClass);

			// Wait till the animation ends
			setTimeout(BX.delegate(function()
			{
				// Clear old grid, now it's hidden and use new as old one
				BX.removeClass(this.outerGrid, this.changeNextClass);
				BX.removeClass(nextGrid, this.gridClassNext);
				BX.addClass(nextGrid, this.gridClassCurrent);
				BX.remove(this.grid);
				this.grid = nextGrid;
				BX.removeClass(this.grid, this.animateClass);
				this.gridWrap.style.overflowX = '';

				// Display loaded entries for new view range
				this.loadEntries().then(entries => {
					this.entries = entries;
					this.displayEntries();
				});
			}, this), 400);
		}, this), 0);
	};

	DayView.prototype.decreaseViewRangeDate = function()
	{
		this.changeViewRangeDate(-this.dayCount);
		this.highlightAll();
		this.setTitle();

		this.gridWrap.style.overflowX = 'hidden';

		var previousGrid = this.outerGrid.appendChild(BX.create('DIV', {props: {className: this.gridClass + ' ' + this.gridClassPrevious + ' ' + this.animateClass}}));
		BX.addClass(this.grid, this.animateClass);
		this.buildDaysGrid({grid: previousGrid});

		setTimeout(BX.delegate(function()
		{
			// Start CSS animation
			BX.addClass(this.outerGrid, this.changePreviousClass);

			// Wait till the animation ends
			setTimeout(BX.delegate(function()
			{
				// Clear old grid, now it's hidden and use new as old one
				BX.removeClass(this.outerGrid, this.changePreviousClass);
				BX.removeClass(previousGrid, this.gridClassPrevious);
				BX.addClass(previousGrid, this.gridClassCurrent);
				BX.remove(this.grid);
				this.grid = previousGrid;
				BX.removeClass(this.grid, this.animateClass);
				this.gridWrap.style.overflowX = '';

				// Display loaded entries for new view range
				this.loadEntries().then(entries => {
					this.entries = entries;
					this.displayEntries();
				});
			}, this), 400);
		}, this), 0);
	};

	DayView.prototype.changeViewRangeDate = function(value)
	{
		var
			viewRangeDate = this.calendar.getViewRangeDate(),
			newDate = new Date(viewRangeDate.getTime());

		newDate.setDate(newDate.getDate() + value);

		this.calendar.setViewRangeDate(newDate);
		return newDate;
	};

	DayView.prototype.getViewRange = function()
	{
		var
			viewRangeDate = this.calendar.getViewRangeDate(),
			endDate = new Date(viewRangeDate.getTime());
		endDate.setDate(endDate.getDate() + this.dayCount);
		return {start: viewRangeDate, end: endDate};
	};

	DayView.prototype.getAdjustedDate = function(date, viewRange)
	{
		if (!date)
		{
			date = new Date();
		}

		if (viewRange && date.getTime() < viewRange.start.getTime())
		{
			date = new Date(viewRange.start.getTime());
		}

		if (viewRange && date.getTime() > viewRange.end.getTime())
		{
			date = new Date(viewRange.end.getTime());
		}

		var viewRangeDate = false;

		if (date && date.getTime)
		{
			date.setHours(0, 0, 0, 0);
			viewRangeDate = new Date(date.getTime());
		}

		return viewRangeDate;
	};

	DayView.prototype.adjustViewRangeToDate = function(date, animate)
	{
		var
			currentViewRangeDate = this.calendar.getViewRangeDate(),
			viewRangeDate = false;

		if (date && date.getTime)
		{
			date.setHours(0, 0, 0, 0);

			var diff = (date.getTime() - currentViewRangeDate.getTime()) / this.calendar.util.dayLength;
			if (diff === this.dayCount)
			{
				this.increaseViewRangeDate();
			}
			else if (diff === -this.dayCount)
			{
				this.decreaseViewRangeDate();
			}
			else
			{
				viewRangeDate = new Date(date.getTime());
				viewRangeDate.setHours(0, 0, 0, 0);
				this.calendar.setViewRangeDate(viewRangeDate);
				if (animate === false)
				{
					this.show();
				}
				else
				{
					this.fadeAnimation(this.getContainer(), 100, BX.delegate(function ()
					{
						this.show();
						this.getContainer().style.opacity = 0;
						this.showAnimation(this.getContainer(), 300)
					}, this));
				}
			}
		}

		return viewRangeDate;
	};

	DayView.prototype.buildDaysGrid = function(params)
	{
		if (!params)
			params = {};

		var
			i, dayCode,
			grid = params.grid || this.grid,
			viewRangeDate = this.calendar.getViewRangeDate(),
			date = new Date(viewRangeDate.getTime());

		var displayedRange = BX.clone(this.getViewRange(), true);

		if (this.dayCount > 1)
		{
			date = this.getAdjustedDate(date);
		}

		BX.cleanNode(grid);
		BX.cleanNode(this.fullDayEventsCont);

		this.holderTitle = this.fullDayEventsCont.appendChild(BX.create('DIV', {props: {className: 'calendar-grid-day-full-days-events-holder-title'}, text: BX.message('EC_VIEW_DAY')}));

		this.fullDayEventsHolderCont = this.fullDayEventsCont.appendChild(BX.create('DIV', {props: {className: this.fullDayContHolderClass}}));
		this.topEntryHolder = this.fullDayEventsCont.appendChild(BX.create('DIV', {props: {className: this.topEntryHolderClass}}));

		this.gridRow = grid.appendChild(BX.create('DIV', {
			props: {className: this.gridRowClass + ' ' + this.animateClass},
			style: {height: this.getDayGridHeight() + 'px'}
		}));

		this.dayIndex = {};
		this.days = [];

		if (this.titleCont)
		{
			BX.cleanNode(this.titleCont);
		}

		this.gridRowShadow = BX.create('DIV', {
			props: {className: 'calendar-grid-week-row-shadow'}
		});

		for (i = 0; i < this.dayCount; i++)
		{
			if (i === 0)
			{
				displayedRange.start = new Date(date.getTime());
				displayedRange.start.setHours(0, 0, 0, 0);
			}
			else if (i === this.dayCount - 1)
			{
				displayedRange.end = new Date(date.getTime());
				displayedRange.end.setHours(0, 0, 0, 0);
			}

			dayCode = this.util.getDayCode(date);

			this.fullDayEventsHolderCont.appendChild(BX.create('DIV', {
				attrs: {'data-bx-calendar-week-day': dayCode},
				props: {className: this.gridCellClass}
			}));

			this.buildDayCell({date: date, month: 'previous', grid: grid});

			if (this.dayCount > 1)
			{
				date.setDate(date.getDate() + 1);
			}

			this.gridRowShadow.appendChild(BX.create('DIV', {
				attrs: {'data-bx-calendar-timeline-day': dayCode},
				props: {className: 'calendar-grid-week-cell'},
				html: '<span class="calendar-grid-cell-inner"></span>'
			}));
		}

		// time lines
		this.timeLinesCont = this.gridRow.appendChild(BX.create('DIV', {props: {className: this.gridTimelinesClass}}));

		this.timelineEntryHolder = this.gridRow.appendChild(BX.create('DIV', {props: {className: this.topEntryHolderClass}}));

		this.timeLinesIndex = [];
		for (i = 0; i <= 24; i++) // Every hour
		{
			this.timeLinesIndex[i] = this.timeLinesCont.appendChild(BX.create('DIV', {
				props: {className: this.gridTimelineHourClass},
				html: '<div class="' + this.gridTimelineHourLabelClass + '">' + this.calendar.util.formatTime(i, 0, true) + '</div>',
				style: {top: ((i) * this.gridLineHeight) + 'px'}
			}));
		}

		this.gridRow.appendChild(this.gridRowShadow);

		setTimeout(BX.delegate(function()
		{
			if (!this.gridWrap.scrollTop && !this.isCollapsedOffHours)
			{
				var workTime = this.util.getWorkTime();
				this.gridWrap.scrollTop = workTime.start * this.gridLineHeight - 5;
			}
		}, this), 0);

		this.showOffHours();
		this.calendar.setDisplayedViewRange(displayedRange);

		// Show "now" red time line
		this.showNowTime();
	};

	DayView.prototype.buildDayCell = function(params)
	{
		var
			date = params.date,
			titleClassName = '',
			className = '',
			time = Math.round(date.getTime() / 1000) * 1000,
			day = date.getDay(),
			dayCode = this.util.getDayCode(date),
			weekDay = this.util.getWeekDayByInd(day);

		if (params.month === 'previous')
		{
			className += ' calendar-grid-previous-month-day';
		}
		else if (params.month === 'next')
		{
			className += ' calendar-grid-next-month-day';
		}
		if (this.util.isHoliday(date))
		{
			className += ' calendar-grid-holiday';
		}

		let todayClass = '';
		if (this.util.isToday(date))
		{
			titleClassName += ' calendar-grid-today';
			todayClass = 'calendar-grid-today';
		}

		if (this.titleCont && this.name === 'week')
		{
			this.titleCont.appendChild(BX.create('DIV', {
				props: {className: this.gridCellClass + titleClassName},
				html: '<span class="calendar-grid-cell-inner" data-bx-calendar-date="' + time + '">' +
				(BX.message('EC_WEEK_TITLE')
					.replace('#DAY_OF_WEEK#', BX.date.format('D', time / 1000))
					.replace('#DATE#', date.getDate())) +
				'</span>'
			}));
		}
		else if (this.titleCont)
		{
			this.titleCont.appendChild(BX.create('DIV', {
				props: {className: this.gridCellClass + titleClassName},
				html: '<span class="calendar-grid-cell-inner" data-bx-calendar-date="' + time + '">' +
				'<span class="calendar-day-of-week-day">' + BX.date.format('l', time / 1000) + '</span>' +
				'</span>'
			}));
		}

		this.days.push({
			date: new Date(date.getTime()),
			dayOffset: this.util.getWeekDayOffset(weekDay),
			node: this.gridRow.appendChild(BX.create('DIV', {
				attrs: {'data-bx-calendar-timeline-day': dayCode},
				props: {
					className: this.gridCellClass + className + ' a1' + ' ' + todayClass
				},
				html: '<span class="calendar-grid-cell-inner"></span>'
			})),
			dayCode: dayCode
		});
		this.dayIndex[this.days[this.days.length - 1].dayCode] = this.days.length - 1;

		this.calendar.dragDrop.registerTimelineDay(this.days[this.days.length - 1]);

	};

	DayView.prototype.setTitle = function()
	{
		var
			viewRangeDate = this.calendar.getViewRangeDate(),
			time = viewRangeDate.getTime() / 1000;

		View.prototype.setTitle.apply(this, [BX.date.format(BX.Calendar.Util.getLongDateFormat(), time)?.replaceAll('\\', '')]);
	};

	DayView.prototype.setDraggedEntry = function(entry)
	{
		this.draggedEntry = this.getRealEntry(entry);
		if (!this.draggedEntry)
		{
			return null;
		}
		for (const key in this.draggedEntry.parts)
		{
			this.draggedEntry.parts[key].params.wrapNode.style.transition = 'none';
			this.draggedEntry.parts[key].params.wrapNode.style.opacity = '0.3';
		}
	};

	DayView.prototype.setResizedEntry = function(entry)
	{
		if (!entry)
		{
			this.resizedEntry = null;
		}
		else
		{
			this.resizedEntry = this.entries.find(e => e.uid === entry.uid);
		}
	};

	DayView.prototype.loadEntries = function()
	{
		return new Promise((resolve) => {
			const viewRange = this.getViewRange();
			this.entryController.getList({
				showLoader: (this.entries && !this.entries.length),
				startDate: new Date(viewRange.start.getFullYear(), viewRange.start.getMonth(), 1),
				finishDate: new Date(viewRange.end.getFullYear(), viewRange.end.getMonth() + 1, 1),
				viewRange: viewRange,
			}).then((entries) => {
				resolve(entries);
			});
		});
	};

	DayView.prototype.displayEntries = function()
	{
		if (this.draggedEntry || this.resizedEntry)
		{
			return;
		}

		this.entries = this.getUndeletedEntries();

		this.partsStorage = [];
		this.timelinePartsStorage = [];

		// Clean holders
		BX.cleanNode(this.topEntryHolder);
		BX.cleanNode(this.timelineEntryHolder);
		this.fullDayEventsCont.style.height = '';

		// Clean days
		this.days.forEach(function(day)
		{
			day.slots = [];
			day.timelineMap = {};
			if (day.collapsedWrap && day.collapsedWrap.top)
			{
				day.collapsedWrap.top.destroy();
			}
			if (day.collapsedWrap && day.collapsedWrap.bottom)
			{
				day.collapsedWrap.bottom.destroy();
			}
			day.collapsedWrap = {top: null, bottom: null};

			day.entries = {
				topList: [],
				started: [],
				timeline: [],
				hidden: []
			};
		});

		let maxTopEntryCount = 0;
		if (this.entries && this.entries.length)
		{
			// Prepare for arrangement
			for (let i = 0; i < this.entries.length; i++)
			{
				const entry = this.entries[i];
				this.entriesIndex[entry.uid] = i;
				entry.cleanParts();
				let entryStarted = false;

				let part;
				for (let dayPos = this.dayIndex[entry.startDayCode]; dayPos < this.days.length; dayPos++)
				{
					const day = this.days[dayPos];
					if (!entry.isLongWithTime()
						&& day.dayCode === entry.startDayCode
						&& day.dayCode === entry.endDayCode && !entry.fullDay)
					{
						part = entry.startPart({
							from: day,
							to: day,
							daysCount: 0,
							fromTimeValue: this.util.getTimeValue(entry.from),
							toTimeValue: this.util.getTimeValue(entry.to)
						});

						day.entries.timeline.push({entry: entry, part: part});
						this.timelinePartsStorage.push({part: part, entry: entry});
						break;
					}
					else
					{
						if (day.dayCode === entry.startDayCode)
						{
							entryStarted = true;
							part = entry.startPart({from: day, daysCount: 0});
							day.entries.started.push({entry: entry, part: part});
						}

						if (entryStarted)
						{
							day.entries.topList.push({entry: entry, part: part});
							part.daysCount++;
							part.to = day;

							if (day.entries.topList.length > maxTopEntryCount)
								maxTopEntryCount = day.entries.topList.length;

							if (day.dayCode === entry.endDayCode ||
								day.dayOffset === this.dayCount - 1 /* for week view */||
								this.dayCount === 1 /*for day view */)
							{
								// here we know where part of event starts and ends
								this.partsStorage.push({part: part, entry: entry});

								// Event finished
								if (day.dayCode === entry.endDayCode)
								{
									break;
								}
							}
						}
					}
				}
			}
		}

		if (this.entries && this.entries.length)
		{
			this.displayTopEntries();
			this.displayTimelineEntries();

			this.SLOTS_COUNT = 10;

			this.arrangeTopEntries();
			this.arrangeTimelineEntries();
		}

		if (this.draggedEntry)
		{
			this.draggedEntry = this.entries.find(e => e.uid === this.draggedEntry.uid);
			for (const key in this.draggedEntry.parts)
			{
				this.draggedEntry.parts[key].params.wrapNode.style.transition = 'none';
				this.draggedEntry.parts[key].params.wrapNode.style.opacity = '0.3';
			}
		}

		this.setFullDayHolderSize(Math.min(Math.max(maxTopEntryCount, 1), this.SLOTS_COUNT));

		// Final arrangement on the grid
		for (const day of this.days)
		{
			// Here we check all entries in the day and if any of it
			// was hidden, we going to show 'show all' link
			if (day.entries.topList.length > 0)
			{
				let showHiddenLink = false;
				for(let i = 0; i < day.entries.topList.length; i++)
				{
					if (day.entries.topList[i].part.params.wrapNode.style.display === 'none')
					{
						showHiddenLink = true;
						break;
					}
				}

				if (showHiddenLink)
				{
					day.hiddenStorage = this.topEntryHolder.appendChild(BX.create('DIV', {
						props: {
							className: 'calendar-event-line-wrap calendar-event-more-btn-container'
						},
						attrs: {'data-bx-calendar-show-all-events': day.dayCode},
						style: {
							top: (parseInt(this.fullDayEventsCont.style.height) - 20) + 'px',
							left: this.dayCount === 1
								? '0' /*for day view */
								: 'calc((100% / ' + this.dayCount + ') * (' + (day.dayOffset + 1) + ' - 1) + 2px)',
							width: 'calc(100% / ' + this.dayCount + ' - 3px)'
						}
					}));

					day.hiddenStorageText = day.hiddenStorage.appendChild(BX.create('span', {props: {className: 'calendar-event-more-btn'}}));
					day.hiddenStorage.style.display = 'block';
					day.hiddenStorageText.innerHTML = BX.message('EC_SHOW_ALL') + ' ' + day.entries.topList.length;
				}
				else if (day.hiddenStorage)
				{
					day.hiddenStorage.style.display = 'none';
				}
			}
		}

		BX.addClass(this.grid, 'calendar-events-holder-show');
		BX.addClass(this.fullDayEventsCont, 'calendar-events-holder-show');

		this.checkTimelineScroll();
	};

	DayView.prototype.arrangeTopEntries = function()
	{
		var
			element, prevElement,
			i, j, dayPos, day, entry, entryPart, entryDisplayed;

		for (dayPos = 0; dayPos < this.days.length; dayPos++)
		{
			day = this.days[dayPos];

			if (day.entries.started.length > 0)
			{
				day.entries.started.sort(this.calendar.entryController.sort);

				for(i = 0; i < day.entries.started.length; i++)
				{
					element = day.entries.started[i];
					if (element)
					{
						entry = element.entry;
						entryPart = element.part;

						if (!entry.checkPartIsRegistered(entryPart))
							continue;

						entryDisplayed = false;

						for(j = 0; j < this.SLOTS_COUNT; j++)
						{
							if (day.slots[j] !== false)
							{
								this.occupySlot({slotIndex: j, startIndex: dayPos, endIndex: dayPos + entryPart.daysCount});
								entryDisplayed = true;

								entry.getWrap(entryPart.partIndex).style.top = (j * this.slotHeight) + 'px';
								break;
							}
						}

						if (!entryDisplayed)
						{
							prevElement = day.entries.started[i - 1];
							if (prevElement)
							{
								day.entries.hidden.push(prevElement);
								prevElement.entry.getWrap(prevElement.part.partIndex).style.display = 'none';
							}
							day.entries.hidden.push(element);
							entry.getWrap(entryPart.partIndex).style.display = 'none';
						}
					}

					if (day.hiddenStorage && day.entries.hidden.length > 0)
					{
						day.hiddenStorageText.innerHTML = BX.message('EC_SHOW_ALL') + ' (' + day.entries.topList.length + ')';
					}
				}
			}
		}
	};

	DayView.prototype.arrangeTimelineEntries = function()
	{
		var
			TIME_ACCURACY = 30, // in minutes
			MIN_BACK_ENTRY_OFFSET = 33,
			MIN_BACK_ENTRY_TIME_OFFSET = 20,
			MIN_TIME_WIDTH = 40,
			LAYER_LEFT_OFFSET = 6,
			LEFT_OFFSET = 2,
			lastCount, count, lastCode,
			entryIndex, i, dayPos, day,
			parallelPosition,
			startList,
			timeFrom, timeTo, l, layerIndex,
			backEntry,backEntryOffset,
			offsetWidthRate,
			backEntriesList,
			entry, entryPart;

		function occupyLayer(params)
		{
			var timeIndex, layerInfo;
			// Occupy Layer
			for (timeIndex = params.timeFrom; timeIndex < params.timeTo; timeIndex++)
			{
				if (!params.layers[timeIndex])
					params.layers[timeIndex] = [];

				layerInfo = params.day.layers[timeIndex][params.layerIndex] || {entries: [], start: []};
				layerInfo.entries.push(params.entryIndex);
				if (timeIndex == params.timeFrom)
				{
					layerInfo.start.push(params.entryIndex);
					params.entryPart.layerParallels = layerInfo.start.length;
				}

				params.day.layers[timeIndex][params.layerIndex] = layerInfo;
			}

			params.entryPart.layerIndex = params.layerIndex;
		}

		function isParallelEntries(timeFrom, layerIndex)
		{
			var layerTimeIndex = day.layers[timeFrom][layerIndex];
			return layerTimeIndex && layerTimeIndex.entries && layerTimeIndex.entries.length === layerTimeIndex.start.length;
		}

		function layerIsFree(layerTimeIndex)
		{
			return !layerTimeIndex;
		}

		function checkBackEntries(params)
		{
			var
				timeIndex,
				prevLayer, backEntryId,
				backEntriesList = [],
				backEntries = {};

			for (timeIndex = params.timeFrom; timeIndex < params.timeTo; timeIndex++)
			{
				if (params.layerIndex > 0 && params.day.layers[timeIndex][params.layerIndex - 1])
				{
					prevLayer = params.day.layers[timeIndex][params.layerIndex - 1].entries;
					if (prevLayer.length > 0)
					{
						backEntryId = prevLayer[prevLayer.length - 1];
						if (!backEntries[backEntryId])
						{
							backEntries[backEntryId] = true;
							backEntriesList.push(backEntryId);
						}
					}
				}
			}
			return backEntriesList;
		}

		function getTimeIndex(date, accuracy)
		{
			if (!accuracy)
				accuracy = TIME_ACCURACY;
			return date.getHours() * 60 + Math.floor(date.getMinutes() / accuracy) * accuracy;
		}

		for (dayPos = 0; dayPos < this.days.length; dayPos++)
		{
			day = this.days[dayPos];

			day.entries.timeline.sort(function(a, b)
			{
				if (a.part.fromTimeValue === b.part.fromTimeValue)
				{
					return (b.part.toTimeValue - b.part.fromTimeValue) - (a.part.toTimeValue - a.part.fromTimeValue);
				}

				return a.part.fromTimeValue - b.part.fromTimeValue;
			});

			lastCount = 0;
			lastCode = '';
			count = 0;
			l = 0;

			day.layers = [];
			for (entryIndex = 0; entryIndex < day.entries.timeline.length; entryIndex++)
			{
				entry = day.entries.timeline[entryIndex].entry;
				entryPart = day.entries.timeline[entryIndex].part;

				timeFrom = getTimeIndex(entry.from, 1);
				timeTo = getTimeIndex(entry.to, 1);
				if (timeFrom === timeTo)
					timeTo += 1;

				if (!day.layers)
					day.layers = [];

				layerIndex = 0;
				while (true)
				{
					// Empty time
					if (!day.layers[timeFrom]
						|| isParallelEntries(timeFrom, layerIndex)
						|| layerIsFree(day.layers[timeFrom][layerIndex])
					)
					{
						occupyLayer({
							day: day,
							timeFrom: timeFrom,
							timeTo: timeTo,
							layers: day.layers,
							entryIndex: entryIndex,
							layerIndex: layerIndex,
							entryPart: entryPart
						});
						break;
					}
					layerIndex++;
				}
			}

			for (entryIndex = 0; entryIndex < day.entries.timeline.length; entryIndex++)
			{
				if (day.entries.timeline[entryIndex])
				{
					entry = day.entries.timeline[entryIndex].entry;
					entryPart = day.entries.timeline[entryIndex].part;

					timeFrom = getTimeIndex(entry.from, 1);
					timeTo = getTimeIndex(entry.to, 1);
					if (timeFrom === timeTo)
						timeTo += 1;

					if (!entry.checkPartIsRegistered(entryPart)
						|| !day.layers[timeFrom]
						|| !day.layers[timeFrom][entryPart.layerIndex]
					)
					{
						continue;
					}

					startList = day.layers[timeFrom][entryPart.layerIndex].start;

					if (entryPart.params && entryPart.params.wrapNode)
					{
						entryPart.params.wrapNode.style.zIndex = timeFrom;
					}

					entryPart.absoluteLeftOffset = LEFT_OFFSET;
					if (entryPart.layerIndex > 0)
					{
						backEntriesList = checkBackEntries({
							day: day,
							entryIndex: entryIndex,
							layerIndex: entryPart.layerIndex,
							timeFrom: timeFrom,
							timeTo: timeTo
						});

						for (i = 0; i < backEntriesList.length; i++)
						{
							backEntry = day.entries.timeline[backEntriesList[i]];
							if (backEntry && backEntry.part && backEntry.part.params && entryPart.params.wrapNode)
							{
								backEntryOffset = parseInt(entryPart.params.wrapNode.style.top) - parseInt(backEntry.part.params.wrapNode.style.top);

								if (backEntryOffset > MIN_BACK_ENTRY_OFFSET)
								{
									entryPart.offsetFractionLeft = backEntry.part.offsetFractionWidth * 0.1;
								}
								else
								{
									entryPart.offsetFractionLeft = backEntry.part.offsetFractionWidth * 0.45;
								}

								entryPart.offsetFractionLeftTotal = backEntry.part.offsetFractionLeftTotal + entryPart.offsetFractionLeft;
								entryPart.offsetFractionWidth = 1 - entryPart.offsetFractionLeftTotal;

								if (this.dayCount > 1) // Weeks
								{
									entryPart.offsetLeftRate = entryPart.from.dayOffset + entryPart.offsetFractionLeftTotal;
								}
								else // One day
								{
									entryPart.offsetLeftRate = entryPart.offsetFractionLeftTotal;
								}

								entryPart.absoluteLeftOffset = (backEntry.absoluteLeftOffset || LEFT_OFFSET) + LAYER_LEFT_OFFSET;
								offsetWidthRate = 1 - entryPart.offsetFractionLeftTotal;

								if (backEntryOffset <= MIN_BACK_ENTRY_OFFSET)
								{
									if (backEntryOffset < MIN_BACK_ENTRY_TIME_OFFSET)
									{
										backEntry.part.params.timeNode.style.maxWidth = 'calc(' + ((1 - entryPart.offsetFractionWidth) * 100) + '% - 4px)';
										if (backEntry.part.params.timeNode.offsetWidth < MIN_TIME_WIDTH)
										{
											backEntry.part.params.timeNode.style.textOverflow = 'clip';
											backEntry.part.params.timeNode.style.maxWidth = MIN_TIME_WIDTH + 'px';
										}
									}

									//backEntry.part.params.nameNode.style.maxWidth = 'calc(' + ((1 - entryPart.offsetFractionWidth) * 100) + '% - 4px)';

									if (backEntry.part.params.nameNode.offsetWidth < MIN_TIME_WIDTH)
									{
										backEntry.part.params.nameNode.style.textOverflow = 'clip';
										backEntry.part.params.nameNode.style.maxWidth = 'calc(' + ((1 - entryPart.offsetFractionWidth) * 100) + '% + 5px)';
									}
								}
								else if (backEntry.part.params.nameNode)
								{
									backEntry.part.params.nameNode.style.whiteSpace = 'nowrap';
									backEntry.part.params.nameNode.style.display = 'block';
									backEntry.part.params.nameNode.style.textOverflow = 'ellipsis';
									backEntry.part.params.nameNode.style.lineHeight = '11px';
									backEntry.part.params.timeNode.style.lineHeight = '11px';
								}

								entryPart.params.wrapNode.style.left = 'calc((100% / ' + this.dayCount + ') * ' + entryPart.offsetLeftRate + ')';

								entryPart.params.wrapNode.style.width = 'calc(100% / (' + this.dayCount + ') * ' + entryPart.offsetFractionWidth + ' - ' + this.lastEntryWidthOffset + 'px)';

								BX.addClass(entryPart.params.wrapNode, 'calendar-bordered-block');
							}
						}
					}

					if (startList.length > 1)
					{
						parallelPosition = BX.util.array_search(entryIndex, day.layers[timeFrom][entryPart.layerIndex].start);

						var entryWidthOffset = this.entryWidthOffset;
						if (parallelPosition == day.layers[timeFrom][entryPart.layerIndex].start.length - 1)
						{
							entryWidthOffset = this.lastEntryWidthOffset;
							if (entryPart.absoluteLeftOffset > LEFT_OFFSET)
							{
								entryWidthOffset += (entryPart.absoluteLeftOffset / startList.length) + 1;
							}
						}

						entryPart.params.wrapNode.style.zIndex = parseInt(entryPart.params.wrapNode.style.zIndex) - parallelPosition;
						if (this.dayCount > 1) // Weeks
						{
							entryPart.params.wrapNode.style.width = 'calc(100% / (' + this.dayCount + ' * ' + startList.length + ') - ' + entryWidthOffset + 'px)';
							entryPart.params.wrapNode.style.left = 'calc((100% / ' + this.dayCount + ') * ' + entryPart.from.dayOffset + ' + 100% * ' + parallelPosition + '/ (' + this.dayCount + ' * ' + startList.length + ') + ' + entryPart.absoluteLeftOffset + 'px)';
						}
						else
						{
							entryPart.params.wrapNode.style.width = 'calc(100% / (' + this.dayCount + ' * ' + startList.length + ') - ' + entryWidthOffset + 'px)';

							entryPart.params.wrapNode.style.left = 'calc(100% * ' + parallelPosition + '/ ' + startList.length + ' + ' + entryPart.absoluteLeftOffset +'px)';
						}
					}
					if (entryPart.params && entryPart.params.wrapNode)
					{
						this.updateCompactness(entryPart.params.wrapNode);
					}
				}
			}
		}
	};

	DayView.prototype.fillTimelineMap = function(timelineMap, entry, entryIndex)
	{
		var
			i,
			from = entry.from.getHours() * 60 + entry.from.getMinutes(),
			to = entry.to.getHours() * 60 + entry.to.getMinutes();

		for (i = from; i < to; i++)
		{
			if (!timelineMap[i])
				timelineMap[i] = [];
			timelineMap[i].push(entryIndex);
		}
	};

	DayView.prototype.displayTopEntries = function()
	{
		// Display top parts (in the top section - full day or several days events)
		var i;
		for (i = 0; i < this.partsStorage.length; i++)
		{
			this.displayTopEntry(this.partsStorage[i]);
		}
	};

	DayView.prototype.displayTopEntry = function(params)
	{
		var
			res,
			entry = params.entry,
			from = params.part.from,
			daysCount = params.part.daysCount,
			partWrap, dotNode, innerNode, nameNode, timeNode, endTimeNode, innerContainer,
			entryClassName = 'calendar-event-line-wrap',
			deltaPartWidth = 0,
			startArrow, endArrow;

		if (entry.isFullDay())
		{
			entryClassName += ' calendar-event-line-fill';
		}
		else if (entry.isLongWithTime())
		{
			entryClassName += ' calendar-event-line-border';
		}
		if (entry.getCurrentStatus() === 'N')
		{
			entryClassName += ' calendar-event-line-refused';
		}
		if (entry.isInvited())
		{
			entryClassName += ' calendar-event-animate-counter-highlight';
		}

		let arrowColor = entry.color;
		if (entry.isFullDay())
		{
			arrowColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
		}
		else if (entry.isLongWithTime())
		{
			arrowColor = this.calendar.util.addOpacityToHex(entry.color, 0.5);
		}

		if (this.util.getDayCode(entry.from) !== this.util.getDayCode(from.date))
		{
			entryClassName += ' calendar-event-line-start-yesterday';
			deltaPartWidth += 8;
			startArrow = this.getArrow('left', arrowColor, entry.isFullDay());
		}

		if (this.util.getDayCode(entry.to) !== this.util.getDayCode(params.part.to.date))
		{
			entryClassName += ' calendar-event-line-finish-tomorrow';
			endArrow = this.getArrow('right', arrowColor, entry.isFullDay());
			deltaPartWidth += 12;
		}

		if (startArrow && !endArrow)
		{
			deltaPartWidth += 4;
		}

		if (deltaPartWidth === 0)
		{
			deltaPartWidth = 5;
		}

		partWrap = BX.create('DIV', {
			attrs: {'data-bx-calendar-entry': entry.uid},
			props: {className: entryClassName}, style: {
				top: 0,
				left: this.dayCount > 1 ? 'calc((100% / ' + this.dayCount + ') * (' + (from.dayOffset + 1) + ' - 1) + 2px)' : '2px',
				width: 'calc(' + daysCount + ' * 100% / ' + this.dayCount + ' - ' + deltaPartWidth + 'px)'
			}
		});

		if (startArrow)
		{
			partWrap.appendChild(startArrow);
			partWrap.style.left = '9px';
		}

		if (endArrow)
		{
			partWrap.appendChild(endArrow);
		}

		innerContainer = partWrap.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner-container'}}));
		innerNode = innerContainer.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner'}}));

		dotNode = innerNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-dot'}}));

		if (entry.isFullDay())
		{
			innerNode.style.maxWidth = 'calc(200% / ' + daysCount + ' - ' + this.lastEntryWidthOffset + 'px)';
		}
		else
		{
			partWrap.style.borderColor = entry.color;

			if (params.part.partIndex === entry.parts.length - 1)
			{
				if (daysCount > 1 && entry.parts.length > 1)
				{
					innerNode.style.width = 'calc(' + (daysCount - 1) + '00% / ' + daysCount + ' - ' + this.lastEntryWidthOffset + 'px)';
				}
			}

			partWrap.style.borderColor = entry.color;
			const startRangeDate = entry.calendar.displayedRange.start,
				endRangeDate = entry.calendar.displayedRange.end,
				eventStartAtRangeDates = this.util.getDayCode(entry.from) >= this.util.getDayCode(startRangeDate),
				eventEndAtRangeDates = this.util.getDayCode(entry.to) <= this.util.getDayCode(endRangeDate),
				formattedEventStartTime = this.calendar.util.formatTime(entry.from.getHours(), entry.from.getMinutes()),
				formattedEventEndTime = this.calendar.util.formatTime(entry.to.getHours(), entry.to.getMinutes());

			if (daysCount===1)
			{
				if (eventStartAtRangeDates)
				{
					timeNode = innerNode.appendChild(
						BX.create('SPAN', {
							props: {className: 'calendar-event-line-time'},
							text: formattedEventStartTime
						}));

					innerNode.style.width = 'calc(100% / ' + daysCount + ' - ' + this.lastEntryWidthOffset + 'px)';
				}
				else if (eventEndAtRangeDates)
				{
					timeNode = innerNode.appendChild(
						BX.create('SPAN', {
							props: {className: 'calendar-event-line-time'},
							text: BX.message('EC_JS_UNTIL_DATE').replace('#DATE#', formattedEventEndTime)
						})
					)
				}
			}
			else {
				if (eventEndAtRangeDates)
				{
					endTimeNode = innerNode.appendChild(
						BX.create('SPAN', {
							props: {className: 'calendar-event-line-expired-time'},
							text: formattedEventEndTime
						}));

					innerNode.style.width = 'calc(100% - ' + this.offsetForTimelineExpiredTime + 'px)';
				}

				if (eventStartAtRangeDates)
				{
					timeNode = innerNode.appendChild(
						BX.create('SPAN', {
							props: {className: 'calendar-event-line-time'},
							text: formattedEventStartTime
						}));

					innerNode.style.width = 'calc(100% / ' + daysCount + ' - ' + this.lastEntryWidthOffset + 'px)';
				}
			}
		}

		nameNode = innerNode.appendChild(BX.create('SPAN', {
			props: {className: 'calendar-event-line-text'},
			text: params.entry.name
		}));

		if (entry.isFullDay())
		{
			innerContainer.style.backgroundColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
			innerContainer.style.borderColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
		}
		else
		{
			if (entry.isLongWithTime())
			{
				innerContainer.style.borderColor = this.calendar.util.addOpacityToHex(entry.color, 0.5);
			}
			dotNode.style.backgroundColor = entry.color;
		}

		if (entry.isInvited() && this.isFirstVisibleRecursiveEntry(entry))
		{
			innerNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-invite-counter'}, text: '1'}));
		}

		(params.holder || this.topEntryHolder).appendChild(partWrap);

		res = {
			wrapNode: partWrap,
			nameNode: nameNode,
			innerNode: innerNode,
			innerContainer: innerContainer,
			timeNode: timeNode || false,
			endTimeNode: endTimeNode || false,
			dotNode: dotNode,
		};

		if (!params.popupMode)
		{
			params.entry.registerPartNode(params.part, res);
		}

		this.calendar.dragDrop.registerEntry(partWrap, params);

		return res;
	};

	DayView.prototype.displayTimelineEntries = function()
	{
		this.zIndexTimeline = 100;
		this.timelinePartsStorage.sort(function(a, b)
		{
			if (a.part.fromTimeValue === b.part.fromTimeValue)
			{
				return (b.part.toTimeValue - b.part.fromTimeValue)
					- (a.part.toTimeValue - a.part.fromTimeValue);
			}
			return a.part.fromTimeValue - b.part.fromTimeValue;
		});

		for (var i = 0; i < this.timelinePartsStorage.length; i++)
		{
			this.displayTimelineEntry(this.timelinePartsStorage[i]);
		}
	};

	DayView.prototype.displayTimelineEntry = function(params)
	{
		var
			res = false,
			top,
			wrapNode, innerNode, nameNode, timeNode, timeLabel,
			workTime = this.util.getWorkTime(),
			entry = params.entry,
			from = params.part.from,
			fromTimeValue = params.part.fromTimeValue,
			toTimeValue = params.part.toTimeValue,
			entryClassName = 'calendar-event-block-wrap';

		if (entry.hasEmailAttendees()
			|| entry.ownerIsEmailUser()
			|| entry.getCurrentStatus() === 'N'
			|| entry.isSharingEvent()
		)
		{
			entryClassName += ' calendar-event-wrap-icon';
		}

		if (entry.isExpired())
		{
			entryClassName += ' calendar-event-block-wrap-past';
		}

		if (entry.isSharingEvent())
		{
			entryClassName += ' calendar-event-block-wrap-sharing';
		}

		if (!this.isCollapsedOffHours
			|| (toTimeValue > workTime.start
				&& fromTimeValue < workTime.end))
		{
			if (this.isCollapsedOffHours)
			{
				fromTimeValue = Math.max(params.part.fromTimeValue, workTime.start);
				toTimeValue = Math.min(params.part.toTimeValue, workTime.end);

				top = ((fromTimeValue - workTime.start) * this.gridLineHeight + 1) + 'px';
			}
			else
			{
				top = (fromTimeValue * this.gridLineHeight + 1) + 'px';
			}

			wrapNode = BX.create('DIV', {
				attrs: {'data-bx-calendar-entry': entry.uid},
				props: {
					className: entryClassName
				},
				style: {
					top: top,
					height: ((toTimeValue - fromTimeValue) * this.gridLineHeight - 1) + 'px',
					left: this.dayCount > 1 ? 'calc((100% / ' + this.dayCount + ') * ' + from.dayOffset + ' + 2px)' : '2px',
					width: 'calc(100% / ' + this.dayCount + ' - ' + this.lastEntryWidthOffset + 'px)'
				}
			});

			innerNode = wrapNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-block-inner'}}));
			const titleNode = innerNode.appendChild(
				BX.create('SPAN',{
					props: {
						className: 'calendar-event-block-title',
					},
				})
			);

			if (entry.isInvited())
			{
				innerNode.className += ' calendar-event-animate-counter-highlight';
				if (this.isFirstVisibleRecursiveEntry(entry))
				{
					titleNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-invite-counter'}, text: '1'}));
				}
				else
				{
					titleNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-invite-counter-dot'}}));
				}
			}
			else if (entry.getCurrentStatus() === 'N')
			{
				titleNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-block-icon-refused'}}));
			}
			else if (this.shouldEntryLookLikeSharing(entry))
			{
				titleNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-block-icon-sharing'}}));
			}
			else if (entry.hasEmailAttendees() || entry.ownerIsEmailUser())
			{
				titleNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-block-icon-mail'}}));
			}

			if (this.shouldEntryLookLikeCollab(entry) && entry.getCurrentStatus() !== 'N')
			{
				const iconColor = entry.isExpired() ? '--gray' : '--white';
				titleNode.appendChild(BX.Tag.render`<span class="calendar-event-block-icon-collab ${iconColor}"></span>`);
			}

			nameNode = titleNode.appendChild(
				BX.create('SPAN',{
					props: {
						className: 'calendar-event-block-text'
					},
					text:  params.entry.name,
				})
			);

			if (!this.calendar.util.isDarkColor(entry.color))
			{
				BX.Dom.addClass(innerNode, 'calendar-event-text-dark');
			}

			timeNode = innerNode.appendChild(BX.create('SPAN', {
				props: {className: 'calendar-event-block-time'},
				html: this.calendar.util.formatTime(entry.from) + ' &ndash; ' + this.calendar.util.formatTime(entry.to)
			}));

			let collabNode;
			if (this.shouldEntryLookLikeCollab(entry) && entry.getCollabId())
			{
				const collab = this.calendar.collabManager.getById(entry.getCollabId());
				const isCurrentCollabCalendar = this.calendar.util.config.type === 'group'
					&& collab
					&& this.calendar.util.config.ownerId === collab.getId()
				;
				if (collab && !isCurrentCollabCalendar)
				{
					const prefixedTitle = BX.Loc.getMessage(
						'EC_VIEW_COLLAB_PREFIXED_NAME',
						{
							'#TITLE#': collab.getName(),
							'[collab_prefix]': '<span class="collab-prefix">',
							'[/collab_prefix]': '</span>',
						},
					);
					collabNode = BX.Tag.render`
						<span class="calendar-event-block-collab">
							<span class="calendar-event-block-collab-name">
								${prefixedTitle}
							</span>
						</span>
					`;
					innerNode.appendChild(collabNode);
				}
			}

			const innerNodeColor = this.shouldEntryLookLikeCollab(entry)
				? this.calendar.util.getCollabColor()
				: entry.color
			;
			innerNode.style.backgroundColor = innerNodeColor;

			let resizerNodeTop, resizerNodeBottom;
			if (this.calendar.util.type !== 'location' && this.calendar.entryController.canDo(entry, 'edit'))
			{
				resizerNodeTop = wrapNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-resizer calendar-event-resizer-top'}}));
				resizerNodeBottom = wrapNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-resizer calendar-event-resizer-bottom'}}));
			}

			this.timelineEntryHolder.appendChild(wrapNode);

			res = {
				wrapNode: wrapNode,
				nameNode: nameNode,
				innerNode: innerNode,
				timeNode: timeNode,
				collabNode: collabNode,
				blockBackgroundNode: innerNode,
				resizerNodeTop: resizerNodeTop,
				resizerNodeBottom: resizerNodeBottom,
			};

			params.part.offsetFractionRate = 1; //!!!!
			params.part.offsetFractionLeft = 0;
			params.part.offsetFractionWidth = 1;
			params.part.offsetFractionLeftTotal = 0;
			params.entry.registerPartNode(params.part, res);

			this.calendar.dragDrop.registerEntry(wrapNode, params);
		}
		else // event displayed on hidden timeline
		{
			this.addHiddenEntry(
				{
					position: fromTimeValue < workTime.end ? 'top' : 'bottom',
					entry: entry
				}
			);
		}

		return res;
	};

	DayView.prototype.addHiddenEntry = function(params)
	{
		this.getCollapsedWrap({
			position: params.position,
			dayCode: this.util.getDayCode(params.entry.from)
		}).addEntry(params.entry);
	};

	DayView.prototype.getCollapsedWrap = function(params)
	{
		if (this.dayIndex[params.dayCode] !== undefined && this.days[this.dayIndex[params.dayCode]])
		{
			var day = this.days[this.dayIndex[params.dayCode]];
			if (!day.collapsedWrap[params.position]
				|| !day.collapsedWrap[params.position].inited())
			{
				day.collapsedWrap[params.position] = new CollapsedTimeWrap({
					position: params.position,
					wrap: this.timelineEntryHolder,
					workTime: this.util.getWorkTime(),
					dayOffset: day.dayOffset,
					dayCount: this.dayCount,
					lastEntryWidthOffset: this.lastEntryWidthOffset,
					gridLineHeight: this.gridLineHeight,
					labelMessage: this.calendar.collapsedLabelMessage,
					clickHandler: (event) => {
						if (this.isCollapsedOffHours)
						{
							const entryWrap = event.target.closest('.calendar-event-block-wrap');
							const top = parseInt(entryWrap.style.top);
							if (top < 0)
							{
								this.switchOffHours(true, 'top');
							}
							else
							{
								this.switchOffHours(true, 'bottom');
							}
						}
					},
					mouseoverHandler: function(){
						BX.addClass(this.topOffHours, "calendar-grid-off-hours-hover");
						BX.addClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
					}.bind(this),
					mouseoutHandler: function(){
						BX.removeClass(this.topOffHours, "calendar-grid-off-hours-hover");
						BX.removeClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
					}.bind(this)
				});
			}

			return day.collapsedWrap[params.position];
		}
		return null;
	};

	DayView.prototype.displayTimelineCollapsedEntry = function(params)
	{
	};

	DayView.prototype.showNowTime = function()
	{
		this.nowTimeLabel = BX.create('DIV', { props: { className: this.gridNowTimeLabelClass } });

		this.nowTimeLine = BX.create('DIV', { props: { className: this.gridNowTimeLineClass } });
		this.nowTimeLine.append(this.nowTimeLabel);

		this.nowTimeCont = BX.create('DIV', { props: { className: this.gridNowTimeClass } });
		this.nowTimeCont.append(this.nowTimeLine);

		this.gridRow.append(this.nowTimeCont);

		if (this.nowTimeInterval)
		{
			clearInterval(this.nowTimeInterval);
		}

		this.updateNowTime();
		this.nowTimeInterval = setInterval(BX.proxy(this.updateNowTime, this), 15000);
	};

	DayView.prototype.hideNowTime = function()
	{
		if (!this.nowTimeCont)
		{
			return;
		}
		BX.cleanNode(this.nowTimeCont, 1);
		delete this.nowTimeCont;
		if (this.nowTimeInterval)
		{
			clearInterval(this.nowTimeInterval);
		}
	};

	DayView.prototype.resetNowTime = function()
	{
		this.hideNowTime();
		this.showNowTime();
	};

	DayView.prototype.hideOffHoursNowTime = function()
	{
		const workTime = this.util.getWorkTime();
		const timeValue = this.util.getTimeValue(new Date());
		if (timeValue < workTime.start || timeValue > workTime.end)
		{
			this.hideNowTime();
		}
	};

	DayView.prototype.getUserTime = function()
	{
		const userSettings = this.util.config.userSettings;
		const timeZone = userSettings.timezoneName;
		return new Date(new Date().toLocaleString("en-US", { timeZone }));
	};

	DayView.prototype.updateNowTime = function()
	{
		if (!this.nowTimeCont)
		{
			return;
		}

		const time = this.getUserTime();
		const timeValue = this.util.getTimeValue(time);

		const translucentLine = document.querySelector("." + this.gridTimeTranslucentClass);
		if (translucentLine)
		{
			BX.removeClass(translucentLine, this.gridTimeTranslucentClass);
		}

		const dayOffset = this.util.getWeekDayOffset(this.util.getWeekDayByInd(time.getDay()));
		const viewRange = this.getViewRange();
		if (time.getTime() > viewRange.start.getTime() && time.getTime() < viewRange.end.getTime())
		{
			if (this.dayCount > 1)
			{
				if (dayOffset === 0)
				{
					this.nowTimeLine.style.left = 0;
				}
				else
				{
					this.nowTimeLine.style.left = 'calc(' + dayOffset + ' * 100% / ' + this.dayCount + ' + 5px)';
				}
			}
		}
		else
		{
			this.hideNowTime();
			return;
		}

		let timeTextValue = this.calendar.util.formatTime(time.getHours(), time.getMinutes());
		if (BX.isAmPmMode())
		{
			timeTextValue = timeTextValue.replace(/(\sam|pm)/ig, "<small>$1<small>");
		}

		this.nowTimeLabel.innerHTML = timeTextValue;

		this.nowTimeCont.style.marginTop = '';
		this.nowTimeLine.classList.remove('calendar-hour-now-line-translucent');
		const workTime = this.util.getWorkTime();
		if (this.isCollapsedOffHours)
		{
			if (timeValue < workTime.start)
			{
				this.nowTimeCont.style.top = '-5px';
				this.nowTimeCont.style.marginTop = '23px';
				this.nowTimeLine.classList.add('calendar-hour-now-line-translucent');
			}
			else if (timeValue > workTime.end)
			{
				this.nowTimeCont.style.top = ((workTime.end - workTime.start) * this.gridLineHeight) + 4 + 'px';
				this.nowTimeCont.style.marginTop = '22px';
				this.nowTimeLine.classList.add('calendar-hour-now-line-translucent');
			}
			else
			{
				this.nowTimeCont.style.top = ((timeValue - workTime.start) * this.gridLineHeight  + this.timeLinesCont.offsetTop)  + 'px';
			}
		}
		else
		{
			this.nowTimeCont.style.top = (timeValue * this.gridLineHeight + this.timeLinesCont.offsetTop) + 'px';
		}

		if (this.isCollapsedOffHours && (dayOffset === 0 || this.dayCount === 1))
		{
			if (timeValue < workTime.start)
			{
				BX.addClass(this.topOffHoursLabel, this.gridTimeTranslucentClass);
			}
			if (timeValue > workTime.end)
			{
				BX.addClass(this.bottomOffHoursLabel, this.gridTimeTranslucentClass);
			}
		}
		else
		{
			BX.removeClass(this.topOffHoursLabel, this.gridTimeTranslucentClass);
			BX.removeClass(this.bottomOffHoursLabel, this.gridTimeTranslucentClass);
		}

		const nearestLineIndex = Math.round(timeValue);
		const nowTimeVisualOffsetPx = 10;
		if ((dayOffset === 0 || this.dayCount === 1)
			&& Math.abs((nearestLineIndex - timeValue) * this.gridLineHeight) < nowTimeVisualOffsetPx
			&& this.timeLinesIndex[nearestLineIndex]
		)
		{
			BX.addClass(this.timeLinesIndex[nearestLineIndex], this.gridTimeTranslucentClass);
		}
	};

	DayView.prototype.getPosByTime = function(time)
	{
		const startTime = this.getTimeByPos(0, 1);
		const startMinutes = startTime.h * 60 + startTime.m;
		const currentMinutes = time.h * 60 + time.m;

		let top = currentMinutes - startMinutes + 4;
		let t = this.getTimeByPos(top, 5);
		while (top >= 0 && t.h === time.h && t.m === time.m)
		{
			top--;
			t = this.getTimeByPos(top, 5);
		}
		return top + 1;
	};

	DayView.prototype.getTimeByPos = function(top, roundOff)
	{
		var
			workTime = this.util.getWorkTime(),
			timeFract = top / this.gridLineHeight,
			timeVal = this.util.getTimeByFraction(timeFract, roundOff || 10);

		if (this.isCollapsedOffHours)
		{
			timeVal.h += workTime.start;
		}
		return timeVal;
	};

	DayView.prototype.showOffHours = function()
	{
		var workTime = this.util.getWorkTime();
		this.topOffHours = this.timeLinesCont.appendChild(BX.create('DIV', {
			props: {className: this.offHoursClass + ' ' + this.offHoursAnimateClass},
			style: {
				top: 0,
				height: (workTime.start * this.gridLineHeight + 1) + 'px'
			}
		}));

		this.topOffHoursLabel = this.topOffHours.appendChild(BX.create('DIV', {
			props: {className: this.gridTimelineHourLabelClass},
			html: '<span>' + this.calendar.util.formatTime(0, 0, true) + "</span><span>" + this.calendar.util.formatTime(workTime.start, 0, true) + '</span>',
			events: {
				click: () => {
					this.switchOffHours(true, 'top');
				},
				mouseover: () => {
					BX.addClass(this.topOffHours, "calendar-grid-off-hours-hover");
				},
				mouseout: () => {
					BX.removeClass(this.topOffHours, "calendar-grid-off-hours-hover");
				}
			}
		}));
		this.timelineEntryHolder.addEventListener('mouseover', (e) => {
			if (e.target === this.timelineEntryHolder)
			{
				BX.addClass(this.topOffHours, "calendar-grid-off-hours-hover");
			}
		});
		this.timelineEntryHolder.addEventListener('mouseout', (e) => {
			if (e.target === this.timelineEntryHolder)
			{
				BX.removeClass(this.topOffHours, "calendar-grid-off-hours-hover");
			}
		});

		this.topOffHours.appendChild(BX.create('DIV', {
			props: {className: 'calendar-grid-off-hours-active'},
			events: {
				click: () => {
					this.switchOffHours(true, 'top');
				},
				mouseover: BX.proxy(function(){
					BX.addClass(this.topOffHours, "calendar-grid-off-hours-hover");
					BX.addClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				}, this),
				mouseout: BX.proxy(function(){
					BX.removeClass(this.topOffHours, "calendar-grid-off-hours-hover");
					BX.removeClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				}, this)
			}
		}));
		this.topOffHours.appendChild(BX.create('DIV', {
			props: {className: 'calendar-grid-off-hours-drag-down'},
			attrs: {'data-bx-calendar-off-time-drag': 'top'},
			events: {
				mousedown : BX.proxy(this.offHoursMousedown, this)
			}
		}));

		this.bottomOffHours = this.timeLinesCont.appendChild(BX.create('DIV', {
			props: {className: this.offHoursClass + ' ' + this.offHoursAnimateClass},
			style: {
				top: (workTime.end * this.gridLineHeight + 1) + 'px',
				height: ((24 - workTime.end) * this.gridLineHeight + 1) + 'px'
			}
		}));
		this.bottomOffHoursLabel = this.bottomOffHours.appendChild(BX.create('DIV', {
			props: {className: this.gridTimelineHourLabelClass},
			html: '<span>' + this.calendar.util.formatTime(workTime.end, 0, true) + "</span><span>" + this.calendar.util.formatTime(24, 0, true) + '</span>',
			events: {
				click: () => {
					this.switchOffHours(true, 'bottom');
				},
				mouseover: () => {
					BX.addClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				},
				mouseout: () => {
					BX.removeClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				}
			}
		}));

		this.bottomOffHours.appendChild(BX.create('DIV', {
			props: {className: 'calendar-grid-off-hours-active'},
			events: {
				click: () => {
					this.switchOffHours(true, 'bottom');
				},
				mouseover: BX.proxy(function(){
					BX.addClass(this.topOffHours, "calendar-grid-off-hours-hover");
					BX.addClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				}, this),
				mouseout: BX.proxy(function(){
					BX.removeClass(this.topOffHours, "calendar-grid-off-hours-hover");
					BX.removeClass(this.bottomOffHours, "calendar-grid-off-hours-hover");
				}, this)
			}
		}));
		this.bottomOffHours.appendChild(BX.create('DIV', {
			props: {className: 'calendar-grid-off-hours-drag-up'},
			attrs: {'data-bx-calendar-off-time-drag': 'bottom'},
			events: {
				mousedown : BX.proxy(this.offHoursMousedown, this)
			}
		}));

		BX.bind(this.topOffHours, 'click', BX.proxy(function(){if (this.isCollapsedOffHours){this.switchOffHours(true, 'top')}}, this));
		BX.bind(this.bottomOffHours, 'click', BX.proxy(function(){if (this.isCollapsedOffHours){this.switchOffHours(true, 'bottom')}}, this));

		if (this.isCollapsedOffHours)
		{
			this.gridRow.style.height = (this.gridLineHeight * (workTime.end - workTime.start)) + 30 + 'px';
			this.isCollapsedOffHours = !this.isCollapsedOffHours;
			this.switchOffHours(false);
			this.updateGridRowShadowHeight();
		}
		else
		{
			this.gridRow.style.height = (this.gridLineHeight * 24) + 40 + 'px';
			this.updateGridRowShadowHeight();
		}
	};

	DayView.prototype.offHoursMousedown = function(e)
	{
		var
			target = e.target || e.srcElement;

		this.lastWorkTime = false;
		this.lastTopCount = false;
		if (target && target.getAttribute)
		{
			this.lastWorkTime = BX.clone(this.util.getWorkTime());
			// Prevent double registration on eventhandlers
			BX.unbind(document, "mousemove", BX.proxy(this.offHoursMousemove, this));
			BX.unbind(document, "mouseup", BX.proxy(this.offHoursMouseup, this));

			BX.bind(document, "mousemove", BX.proxy(this.offHoursMousemove, this));
			BX.bind(document, "mouseup", BX.proxy(this.offHoursMouseup, this));

			BX.removeClass(this.topOffHours, this.offHoursAnimateClass);
			BX.removeClass(this.bottomOffHours, this.offHoursAnimateClass);
			BX.addClass(this.topOffHours, this.offHoursFastAnimateClass);
			BX.addClass(this.bottomOffHours, this.offHoursFastAnimateClass);

			if (target.getAttribute('data-bx-calendar-off-time-drag') == 'top')
			{
				this.offtimeTuneMode = 'top';
			}
			else
			{
				this.offtimeTuneMode = 'bottom';
			}

			this.offtimeTuneBaseZeroPos = BX.pos(this.timeLinesCont).top;
		}
	};

	DayView.prototype.offHoursMousemove = function(e)
	{
		if (this.offtimeTuneMode)
		{
			var
				mousePos = this.util.getMousePos(e),
				topPos = Math.max(Math.round((mousePos.y - this.offtimeTuneBaseZeroPos) / this.gridLineHeight), 0);

			if (this.lastTopCount !== topPos)
			{
				this.preventSwichOffHours = true;
				if (this.offtimeTuneMode == 'top')
				{
					topPos = Math.min(this.lastWorkTime.end - 1, topPos);
					this.topOffHours.style.height = (topPos * this.gridLineHeight + 1) + 'px';

					this.lastWorkTime.start = topPos;
				}
				else
				{
					topPos = Math.max(this.lastWorkTime.start + 1, topPos);
					this.bottomOffHours.style.top = topPos * this.gridLineHeight + 'px';
					this.bottomOffHours.style.height = ((24 - topPos) * this.gridLineHeight + 1) + 'px';

					this.lastWorkTime.end = topPos;
				}
				this.lastTopCount = topPos;
			}
		}
	};

	DayView.prototype.offHoursMouseup = function(event)
	{
		BX.unbind(document, "mousemove", BX.proxy(this.offHoursMousemove, this));
		BX.unbind(document, "mouseup", BX.proxy(this.offHoursMouseup, this));

		BX.addClass(this.topOffHours, this.offHoursAnimateClass);
		BX.addClass(this.bottomOffHours, this.offHoursAnimateClass);
		BX.removeClass(this.topOffHours, this.offHoursFastAnimateClass);
		BX.removeClass(this.bottomOffHours, this.offHoursFastAnimateClass);

		var workTime = this.util.setWorkTime(this.lastWorkTime);
		this.topOffHoursLabel.innerHTML = '<span>' + this.calendar.util.formatTime(0, 0, true) + "</span><span>" + this.calendar.util.formatTime(workTime.start, 0, true) + '</span>';
		this.bottomOffHoursLabel.innerHTML = '<span>' + this.calendar.util.formatTime(workTime.end, 0, true) + "</span><span>" + this.calendar.util.formatTime(24, 0, true) + '</span>';

		this.offtimeTuneMode = false;
		delete this.lastWorkTime;
		delete this.lastTopCount;

		this.isCollapsedOffHours = false;
		if (!this.preventSwichOffHours)
		{
			if (event.target.className === 'calendar-grid-off-hours-drag-up')
			{
				this.switchOffHours(true, 'bottom');
			}
			else
			{
				this.switchOffHours(true, 'top');
			}
		}
		this.preventSwichOffHours = false;
	};

	DayView.prototype.switchOffHours = function(animate, state)
	{
		if (this.denySwitch)
		{
			return;
		}
		this.denySwitch = true;
		this.removeOffHoursEntries();

		if (animate)
		{
			this.animateSwitchOffHours(state, this.isCollapsedOffHours);
		}
		else
		{
			this.setSwitchOffHours(this.isCollapsedOffHours);
		}

		this.isCollapsedOffHours = !this.isCollapsedOffHours;
	};

	DayView.prototype.setSwitchOffHours = function(isExpand)
	{
		BX.removeClass(this.bottomOffHours, this.offHoursAnimateClass);
		BX.removeClass(this.topOffHours, this.offHoursAnimateClass);
		BX.removeClass(this.timeLinesCont, this.offHoursAnimateClass);
		this.switchOffHoursProps(isExpand);

		if (isExpand)
		{
			this.showHourLines();
		}

		this.displayEntries();
		this.denySwitch = false;
		this.checkTimelineScroll();
	};

	DayView.prototype.animateSwitchOffHours = function(state, isExpandAnimation)
	{
		BX.addClass(this.bottomOffHours, this.offHoursAnimateClass);
		BX.addClass(this.topOffHours, this.offHoursAnimateClass);
		BX.addClass(this.timeLinesCont, this.offHoursAnimateClass);
		this.switchOffHoursProps(isExpandAnimation);
		this.hideOffHoursNowTime();

		let startCorrect, endCorrect;
		if (isExpandAnimation)
		{
			startCorrect = this.offHoursCollapsedHeight;
			endCorrect = 0;
		}
		else
		{
			startCorrect = 0;
			endCorrect = this.offHoursCollapsedHeight;
		}

		const correctingDiv = BX.create('DIV', {
			style: {
				position: 'absolute',
				width: 1 + 'px',
				height: startCorrect + 'px',
				top: (this.gridWrap.clientHeight + this.topOffHours.clientHeight) + 'px',
				transition: '400ms all ease'
			}
		});
		this.timelineEntryHolder.append(correctingDiv);

		correctingDiv.style.top = (this.gridWrap.clientHeight + this.topOffHours.clientHeight - endCorrect * 2) + 'px';
		correctingDiv.style.height = endCorrect + 'px';

		const savedTopOffHoursHeight = this.topOffHours.clientHeight;
		const savedScrollTop = this.gridWrap.scrollTop;
		const entryNodes = [...this.timelineEntryHolder.childNodes].filter(node => node !== correctingDiv);
		new BX.easing({
			duration: 400,
			start: {},
			finish: {},
			step: () => {
				let offset = this.topOffHours.clientHeight - correctingDiv.clientHeight;
				if (!isExpandAnimation)
				{
					offset -= savedTopOffHoursHeight;
				}

				this.gridWrap.scrollTop = savedScrollTop + offset;
				if (isExpandAnimation && state === 'top')
				{
					this.gridWrap.scrollTop = savedScrollTop;
				}

				this.timelineEntryHolder.style.transform = `translateY(${offset}px)`;

				if (this.nowTimeCont)
				{
					this.nowTimeCont.style.transform = `translateY(${offset}px)`;
				}

				this.cutEntryNodesByGrid(entryNodes, offset);
				this.checkTimelineScroll();
			},
			complete: () => {
				correctingDiv.remove();
				this.timelineEntryHolder.style.transform = 'none';
				this.resetNowTime();
				if (isExpandAnimation)
				{
					this.showHourLines();
				}
				this.displayEntries();
				this.denySwitch = false;
				this.checkTimelineScroll();
			}
		}).animate();
	};

	DayView.prototype.cutEntryNodesByGrid = function(entryNodes, offset)
	{
		for (const node of entryNodes)
		{
			const childTop = parseInt(node.offsetTop) + offset;
			const childBottom = childTop + node.offsetHeight;
			const gridBottom = parseInt(this.bottomOffHours.offsetTop) + this.bottomOffHours.offsetHeight - this.offHoursCollapsedHeight;
			if (childBottom > gridBottom)
			{
				const height = (node.offsetHeight - (childBottom - gridBottom));
				if (height > 0)
				{
					node.style.height = height + 'px';
				}
				else
				{
					node.remove();
				}
			}
			if (childTop < 0 && node.querySelector('.calendar-event-block-text'))
			{
				const height = (node.offsetHeight + childTop);
				node.style.top = (parseInt(node.style.top) - childTop) + 'px';
				if (height > 0)
				{
					node.style.height = height + 'px';
				}
				else
				{
					node.remove();
				}
			}
		}
	};

	DayView.prototype.switchOffHoursProps = function(isExpand)
	{
		const workTime = this.util.getWorkTime();
		if (isExpand)
		{
			this.toggleOffHoursClasses(this.offHoursCollapseClass, this.offHoursClass);
			this.setExpandedOffHoursHeight(workTime);
			this.displayOffHourLines(workTime);
			this.util.setUserOption('collapseOffHours', 'N');
		}
		else
		{
			this.toggleOffHoursClasses(this.offHoursClass, this.offHoursCollapseClass);
			this.setCollapsedOffHoursHeight(workTime);
			this.hideOffHourLines(workTime);
			this.util.setUserOption('collapseOffHours', 'Y');
		}
	};

	DayView.prototype.toggleOffHoursClasses = function(classBeforeAnimation, classAfterAnimation)
	{
		this.topOffHours.classList.add(classAfterAnimation);
		this.bottomOffHours.classList.add(classAfterAnimation);
		this.topOffHours.classList.remove(classBeforeAnimation);
		this.bottomOffHours.classList.remove(classBeforeAnimation);
	};

	DayView.prototype.setExpandedOffHoursHeight = function(workTime)
	{
		this.gridRow.style.height = (this.gridLineHeight * 24) + 40 + 'px';
		this.topOffHours.style.height = (this.gridLineHeight * workTime.start) + 1 + 'px';
		this.bottomOffHours.style.height = (this.gridLineHeight * (24 - workTime.end)) + 1 + 'px';
		this.bottomOffHours.style.top = (this.gridLineHeight * workTime.end) + 'px';
		this.updateGridRowShadowHeight();
	};

	DayView.prototype.setCollapsedOffHoursHeight = function(workTime)
	{
		this.gridRow.style.height = (this.gridLineHeight * (workTime.end - workTime.start)) + 30 + 'px';
		this.topOffHours.style.height = this.offHoursCollapsedHeight + 'px';
		this.bottomOffHours.style.height = this.offHoursCollapsedHeight + 'px';
		this.bottomOffHours.style.top = ((workTime.end - workTime.start) * this.gridLineHeight) + 9 + 'px';
		this.updateGridRowShadowHeight();
	};

	DayView.prototype.displayOffHourLines = function(workTime)
	{
		for (let i in this.timeLinesIndex)
		{
			if (this.timeLinesIndex.hasOwnProperty(i))
			{
				if (i < workTime.start || i > workTime.end)
				{
					this.timeLinesIndex[i].style.display = "block";
					this.timeLinesIndex[i].style.opacity = 1;
				}
				this.timeLinesIndex[i].style.top = (i * this.gridLineHeight) + 'px';
			}
		}
	};

	DayView.prototype.hideOffHourLines = function(workTime)
	{
		for (let i in this.timeLinesIndex)
		{
			if (this.timeLinesIndex.hasOwnProperty(i))
			{
				if (i <= workTime.start || i >= workTime.end)
				{
					this.timeLinesIndex[i].style.opacity = 0;
					this.timeLinesIndex[i].style.pointerEvents = 'none';
				}

				if (i >= workTime.end)
				{
					this.timeLinesIndex[i].style.top = ((workTime.end - workTime.start) * this.gridLineHeight) + 'px';
				}
				else
				{
					this.timeLinesIndex[i].style.top = ((i - workTime.start) * this.gridLineHeight) + 'px';
				}
			}
		}
	};

	DayView.prototype.showHourLines = function()
	{
		for (const i in this.timeLinesIndex)
		{
			if (this.timeLinesIndex.hasOwnProperty(i))
			{
				this.timeLinesIndex[i].style.opacity = '';
				this.timeLinesIndex[i].style.display = '';
			}
		}
	};

	DayView.prototype.removeOffHoursEntries = function()
	{
		const workTime = this.util.getWorkTime();
		for (const entry of this.entries)
		{
			if (!entry.fullDay
				&& (entry.from.getHours() >= workTime.end || entry.to.getHours() <= workTime.start)
				&& entry.parts[0] && entry.parts[0].params
			)
			{
				entry.parts[0].params.wrapNode.style.minHeight = 0 + 'px';
			}
		}
		this.days.forEach((day) =>
		{
			if (day.collapsedWrap && day.collapsedWrap.top)
			{
				day.collapsedWrap.top.destroy();
			}
			if (day.collapsedWrap && day.collapsedWrap.bottom)
			{
				day.collapsedWrap.bottom.destroy();
			}
		});
	};

	DayView.prototype.checkTimelineScroll = function()
	{
		if (!this.scrollbarWidth)
		{
			this.scrollbarWidth = this.util.getScrollbarWidth();
		}

		// Compensate padding in right title calendar-grid-week-full-days-events-holder
		const wrapOffsetRight = this.gridWrap.scrollHeight > this.gridWrap.offsetHeight ? this.scrollbarWidth : 0;
		if (this.titleCont)
		{
			this.titleCont.style.paddingRight = wrapOffsetRight + "px";
		}

		if(this.fullDayEventsHolderCont
			&& this.topEntryHolder
			&& parseInt(this.topEntryHolder.style.right) !== parseInt(wrapOffsetRight)
		)
		{
			this.gridWrap.style.width = '100%';
			this.topEntryHolder.style.right = wrapOffsetRight + "px";
			this.fullDayEventsHolderCont.style.paddingRight = wrapOffsetRight + "px";
			// new BX.easing({
			// 	duration: 100,
			// 	start: {width: wrapOffsetRight, paddingRight: 0},
			// 	finish: {width: 0, paddingRight: wrapOffsetRight},
			// 	transition: BX.easing.makeEaseOut(BX.easing.transitions.linear),
			// 	step: BX.delegate(function (state) {
			// 		this.gridWrap.style.width = 'calc(100% + ' + state.width + 'px)';
			// 		this.topEntryHolder.style.right = state.paddingRight + "px";
			// 		this.fullDayEventsHolderCont.style.paddingRight = state.paddingRight + "px";
			// 	}, this),
			// 	complete: function (){}
			// }).animate();
		}
	};

	DayView.prototype.getDayGridHeight = function()
	{
		return 756;
	};

	DayView.prototype.updateGridRowShadowHeight = function()
	{
		if (this.isCollapsedOffHours)
		{
			this.gridRowShadow.style.height = (parseInt(this.gridRow.style.height) - 38) + 'px';
			BX.removeClass(this.gridRowShadow, 'calendar-grid-week-row-shadow-off-hours');
		}
		else
		{
			this.gridRowShadow.style.height = (parseInt(this.gridRow.style.height) - 40) + 'px';
			BX.addClass(this.gridRowShadow, 'calendar-grid-week-row-shadow-off-hours');
		}
	};

	DayView.prototype.handleClick = function(params)
	{
		if (this.isActive())
		{
			if (!params)
				params = {};

			var dayCode, uid;
			if (params.specialTarget && (uid = params.specialTarget.getAttribute('data-bx-calendar-entry')))
			{
				this.handleEntryClick({
					uid: uid,
					specialTarget: params.specialTarget,
					target: params.target,
					e: params.e
				});
			}
			else if (params.specialTarget && (dayCode = params.specialTarget.getAttribute('data-bx-calendar-show-all-events')))
			{
				this.deselectEntry();
				if (this.dayIndex[dayCode] !== undefined && this.days[this.dayIndex[dayCode]])
				{
					this.showAllEventsInPopup({
						day: this.days[this.dayIndex[dayCode]],
						entrieList: this.days[this.dayIndex[dayCode]].entries.topList
					});
				}
			}
			else if (
				!this.calendar.util.readOnlyMode()
				&& this.entryController.canDo(true, 'add_event')
				&& (dayCode = params.specialTarget && params.specialTarget.getAttribute('data-bx-calendar-week-day'))
				&& !this.isCompactFormShown()
			)
			{
				this.deselectEntry();
				this.showCompactEditFormForNewEntry({
					entry: this.buildTopNewEntryWrap({
						dayFrom: this.days[this.dayIndex[dayCode]],
						holder: this.topEntryHolder
					})
				});
			}
		}
	};

	DayView.prototype.getEvents = function(day)
	{
		let items = this.name === 'week'
			? this.days[day.dayOffset]?.entries?.timeline
			: this.days[0].entries.timeline;
		items = items || [];
		const events = items.map(item => item.entry);
		return events.filter(event => {
			let isEventDeleted = false;
			if (event.parts[0].params)
			{
				isEventDeleted = event.parts[0].params.wrapNode.style.opacity === '0';
			}
			return event.accessibility !== 'free' && event !== this.draggedEntry && !isEventDeleted;
		});
	};

	DayView.prototype.correctDuration = function (entry)
	{
		let isToDateChange = false;
		let fromDate = new Date(entry.dayFrom.date.getTime());
		let toDate = new Date(entry.dayFrom.date.getTime());
		fromDate.setHours(entry.timeFrom.h, entry.timeFrom.m, 0, 0);
		toDate.setHours(entry.timeTo.h, entry.timeTo.m, 0, 0);

		const fromDateOrig = new Date(fromDate.getTime());
		const toDateOrig = new Date(toDate.getTime());
		let items =
			this.name === 'week'
				? this.days[entry.dayFrom.dayOffset]?.entries?.timeline
				: this.days[0].entries.timeline;
		items = items || [];

		for (var i = 0; i < items.length; i++)
		{
			if (items[i].entry.accessibility === 'free')
			{
				continue;
			}

			if (
				fromDate < items[i].entry.to
				&& fromDate >= items[i].entry.from
			)
			{
				fromDate = items[i].entry.to;
				if (!isToDateChange)
				{
					toDate.setHours(fromDate.getHours() + 1);
					toDate.setMinutes(fromDate.getMinutes())
				}
			}

			if (
				toDate > items[i].entry.from
				&& fromDate <= items[i].entry.from
			)
			{
				isToDateChange = true;
				toDate = items[i].entry.from;
			}
		}

		const shiftTimeMinutes = ((fromDate - fromDateOrig) / 60000);
		if (shiftTimeMinutes >= 30)
		{
			entry.timeFrom.h = fromDateOrig.getHours();
			entry.timeFrom.m = fromDateOrig.getMinutes();
			entry.timeTo.h = toDateOrig.getHours();
			entry.timeTo.m = toDateOrig.getMinutes();
		}
		else
		{
			entry.timeFrom.h = fromDate.getHours();
			entry.timeFrom.m = fromDate.getMinutes();
			entry.timeTo.h = toDate.getHours();
			entry.timeTo.m = toDate.getMinutes();
		}
	}

	DayView.prototype.correctEntryWrap = function(entry)
	{
		var fromTimeValue = entry.timeFrom.h + entry.timeFrom.m / 60;
		var toTimeValue = entry.timeTo.h + entry.timeTo.m / 60;
		entry.entryNode.style.height = ((toTimeValue - fromTimeValue) * this.gridLineHeight - 3) + 'px';

		var workTime = this.util.getWorkTime();

		if (this.isCollapsedOffHours)
		{
			fromTimeValue = Math.max(fromTimeValue, workTime.start);
			this.startMousePos = this.offtimeTuneBaseZeroPos + ((fromTimeValue - workTime.start) * this.gridLineHeight + 1);
		}
		else
		{
			this.startMousePos = this.offtimeTuneBaseZeroPos + (fromTimeValue * this.gridLineHeight + 1);
		}
	}

	DayView.prototype.getDayByCode = function(dayCode)
	{
		return this.days[this.dayIndex[dayCode]];
	}

	DayView.prototype.handleMousedown = function(e)
	{
		const isRightButton = e.which === 3;
		if (isRightButton || !this.isActive() || this.isCompactFormShown())
		{
			return;
		}

		var dayCode;
		var target = this.calendar.util.findTargetNode(e.target || e.srcElement);

		if ((this.calendar.util.type === 'location' || !this.calendar.util.readOnlyMode())
			&& this.entryController.canDo(true, 'add_event')
			&& (dayCode = target && target.getAttribute('data-bx-calendar-timeline-day')))
		{
			// Prevent double registration on eventhandlers
			BX.unbind(document, "mousemove", BX.proxy(this.handleMousemove, this));
			BX.unbind(document, "mouseup", BX.proxy(this.handleMouseup, this));
			BX.bind(document, "mousemove", BX.proxy(this.handleMousemove, this));
			BX.bind(document, "mouseup", BX.proxy(this.handleMouseup, this));
			BX.addCustomEvent(this.calendar, 'keyup', BX.proxy(this.checkKeyup, this));

			this.canMoveOnCreate = false;
			setTimeout(() => {
				this.canMoveOnCreate = true;
			}, 100);
			this.createEntryMode = true;
			this.offtimeTuneBaseZeroPos = BX.pos(this.timeLinesCont).top;
			this.startMousePos = Math.max(this.offtimeTuneBaseZeroPos + this.gridWrap.scrollTop, this.calendar.util.getMousePos(e).y);

			this.newEntry = this.buildTimelineNewEntryWrap({
				dayFrom: this.days[this.dayIndex[dayCode]],
				holder: this.timelineEntryHolder
			});

			this.newEntry.dayFrom = this.days[this.dayIndex[dayCode]];

			this.newEntry.timeFrom = this.getTimeByPos(this.startMousePos - this.offtimeTuneBaseZeroPos, 30, true);
			var workTime = this.util.getWorkTime();
			var fromTimeValue = this.newEntry.timeFrom.h + this.newEntry.timeFrom.m / 60;

			if (this.isCollapsedOffHours)
			{
				fromTimeValue = Math.max(fromTimeValue, workTime.start);
				this.startMousePos = this.offtimeTuneBaseZeroPos + ((fromTimeValue - workTime.start) * this.gridLineHeight + 1);
			}
			else
			{
				this.startMousePos = this.offtimeTuneBaseZeroPos + (fromTimeValue * this.gridLineHeight + 1);
			}

			if (this.newEntry.timeFrom.h === 23)
			{
				this.newEntry.timeTo = {h: 23, m: 59};
			}
			else
			{
				this.newEntry.timeTo = {
					h: this.newEntry.timeFrom.h + 1,
					m: this.newEntry.timeFrom.m
				};
			}

			this.correctDuration(this.newEntry);
			this.correctEntryWrap(this.newEntry);

			this.updateCompactness(this.newEntry.entryNode);

			this.newEntry.changeTimeCallback(this.newEntry.timeFrom, this.newEntry.timeTo);
			this.newEntry.entryNode.style.top = (this.startMousePos - BX.pos(this.outerGrid).top) + 'px';
		}
	};

	DayView.prototype.handleMousemove = function(e)
	{
		if (this.createEntryMode && this.canMoveOnCreate)
		{
			var offset = this.isCollapsedOffHours ? 9 : 20;
			var mousePos = this.calendar.util.getMousePos(e).y;
			var height = Math.min(
				Math.max(mousePos - this.startMousePos, 10),
				parseInt(this.gridRow.style.height) - parseInt(this.newEntry.entryNode.style.top) - offset
			);

			this.newEntry.entryNode.style.height = height + 'px';

			this.updateCompactness(this.newEntry.entryNode);

			this.newEntry.timeTo = this.getTimeByPos(height + this.startMousePos - this.offtimeTuneBaseZeroPos);
			this.newEntry.changeTimeCallback(this.newEntry.timeFrom, this.newEntry.timeTo);
		}
	};

	DayView.prototype.handleMouseup = function(e)
	{
		// BX.unbind(document, "mousemove", BX.proxy(this.offHoursMousemove, this));
		// BX.unbind(document, "mouseup", BX.proxy(this.offHoursMouseup, this));
		BX.removeCustomEvent(this.calendar, 'keyup', BX.proxy(this.checkKeyup, this));

		if (this.createEntryMode)
		{
			var
				fromDate = new Date(this.newEntry.dayFrom.date.getTime()),
				toDate = new Date(this.newEntry.dayFrom.date.getTime());
			fromDate.setHours(this.newEntry.timeFrom.h, this.newEntry.timeFrom.m, 0, 0);
			toDate.setHours(this.newEntry.timeTo.h, this.newEntry.timeTo.m, 0, 0);

			this.deselectEntry();
			this.showCompactEditFormForNewEntry({
				entry: this.newEntry,
				entryTime: {
					from: fromDate,
					to: toDate
				}
			});
			this.createEntryMode = false;
		}
	};

	DayView.prototype.checkKeyup = function(params)
	{
		var KEY_CODES = this.util.getKeyCodes();

		if (params.keyCode === KEY_CODES['escape'] && this.createEntryMode && this.newEntry)
		{
			BX.remove(this.newEntry.entryNode);
			this.createEntryMode = false;
			this.handleMouseup();
		}
	};

	DayView.prototype.isCompactFormShown = function()
	{
		const compactForm = BX.Calendar.EntryManager.getCompactViewForm(false);
		return compactForm && compactForm.isShown();
	};

	DayView.prototype.buildTopNewEntryWrap = function(params)
	{
		var
			_this = this,
			entryTime, entryName,
			partWrap, innerNode, innerContainer,
			entryClassName = 'calendar-event-line-wrap',
			deltaPartWidth = 0,
			from = params.dayFrom,
			timeNode, nameNode,
			daysCount = 1,
			sectionId = BX.Calendar.SectionManager.getNewEntrySectionId(),
			section = this.calendar.sectionManager.getSection(sectionId) || this.calendar.roomsManager.getRoom(sectionId),
			color = section.color;

		entryTime = this.entryController.getTimeForNewEntry(from.date);
		entryName = this.entryController.getDefaultEntryName();

		partWrap = params.holder.appendChild(BX.create('DIV', {
			props: {className: entryClassName}, style: {
				top: 0,
				left: this.dayCount > 1 ? 'calc((100% / ' + this.dayCount + ') * (' + (from.dayOffset + 1) + ' - 1) + 2px)' : '2px',
				width: 'calc(' + daysCount + ' * 100% / ' + this.dayCount + ' - ' + deltaPartWidth + 'px)'
			}
		}));

		innerContainer = partWrap.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner-container'}}));
		innerNode = innerContainer.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner'}}));
		innerNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-line-time'}, text: this.calendar.util.formatTime(entryTime.from.getHours(), entryTime.from.getMinutes())}));
		innerNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-line-text'}, text: entryName}));

		partWrap.style.backgroundColor = color;
		partWrap.style.borderColor = color;
		partWrap.style.opacity = 0;

		var entryClone = BX.adjust(this.fullDayEventsCont.appendChild(partWrap.cloneNode(true)), {
			props: {className: 'calendar-event-line-clone'},
			style: {
				width: (partWrap.offsetWidth - 4) + 'px',
				height: partWrap.offsetHeight + 'px',
				top : 3 + 'px',
				left : (partWrap.offsetLeft + 43)+ 'px',
				opacity: 1
			}
		});

		this.updateCompactness(entryClone);

		if (partWrap)
		{
			BX.remove(partWrap, true);
		}

		nameNode = entryClone.querySelector('.calendar-event-line-text');
		timeNode = entryClone.querySelector('.calendar-event-line-time');
		innerNode = entryClone.querySelector('.calendar-event-line-inner');

		var entry = {
			entryNode: entryClone,
			nameNode: nameNode,
			timeNode: timeNode,
			innerNode: innerNode,
			section: section,
			entryName: entryName,
			entryTime: entryTime,
			changeTimeCallback: function(from, to)
			{
				if (from.getHours && to.getHours)
				{
					timeNode.innerHTML = _this.calendar.util.formatTime(from.getHours(),from.getMinutes());
				}
				else
				{
					timeNode.innerHTML = _this.calendar.util.formatTime(from.h, from.m);
				}
			},
			changeNameCallback: function(name)
			{
				nameNode.innerHTML = BX.util.htmlspecialchars(name);
			}
		};

		this.selectEntryPart(entry, color, false);

		return entry;
	};


	DayView.prototype.buildTimelineNewEntryWrap = function(params)
	{
		var
			_this = this,
			entryTime, entryName,
			partWrap, innerNode,
			entryClassName = 'calendar-event-block-wrap',
			from = params.dayFrom,
			timeLabel, timeNode, nameNode, bindNode,
			sectionId = BX.Calendar.SectionManager.getNewEntrySectionId(),
			section = this.calendar.sectionManager.getSection(sectionId) || this.calendar.roomsManager.getRoom(sectionId),
			color = section.color;

		entryTime = this.entryController.getTimeForNewEntry(from.date);
		entryName = this.entryController.getDefaultEntryName();

		partWrap = params.holder.appendChild(BX.create('DIV', {
			props: {className: entryClassName},
			style: {
				height: this.gridLineHeight + 'px',
				minHeight: '20px',
				left: this.dayCount > 1 ? 'calc((100% / ' + this.dayCount + ') * ' + from.dayOffset + ' + 2px)' : '2px',
				width: 'calc(100% / ' + this.dayCount + ' - ' + this.lastEntryWidthOffset + 'px)'
			}
		}));
		innerNode = partWrap.appendChild(BX.create('DIV', {props: {className: 'calendar-event-block-inner'}}));
		timeLabel = this.calendar.util.formatTime(entryTime.from.getHours(), entryTime.from.getMinutes()) + ' &ndash; ' + this.calendar.util.formatTime(entryTime.to.getHours(), entryTime.to.getMinutes());
		innerNode.appendChild(BX.create('SPAN', {
			props: {className: 'calendar-event-block-text'},
			style: {color: '#fff'},
			text: entryName
		}));
		innerNode.appendChild(BX.create('SPAN', {
			props: {className: 'calendar-event-block-time'},
			style: {color: '#fff'},
			html: timeLabel
		}));
		innerNode.style.backgroundColor = color;

		var entryClone = BX.adjust(this.outerGrid.appendChild(partWrap.cloneNode(true)), {
			props: {className: 'calendar-event-line-clone calendar-event-block-wrap active'},
			style: {
				width: (partWrap.offsetWidth - 3) + 'px',
				height: partWrap.offsetHeight + 'px',
				left : (partWrap.offsetLeft + 42)+ 'px',
				opacity: 1
			}
		});

		if (partWrap)
		{
			BX.remove(partWrap, true);
		}

		nameNode = entryClone.querySelector('.calendar-event-block-text');
		timeNode = entryClone.querySelector('.calendar-event-block-time');
		innerNode = entryClone.querySelector('.calendar-event-block-inner');
		bindNode = entryClone.appendChild(BX.create('DIV', {props: {className: 'calendar-event-bind-node'}}));

		if (this.dayCount === 1)
			bindNode.style.right = '10%';
		else
			bindNode.style.left = '0';

		var entry = {
			entryNode: entryClone,
			innerNode: innerNode,
			section: section,
			entryName: entryName,
			bindNode: bindNode,
			blockBackgroundNode: innerNode,
			changeTimeCallback: function(from, to)
			{
				var timeLabel;
				if (from.getHours && to.getHours)
				{
					timeLabel = _this.calendar.util.formatTime(from.getHours(),from.getMinutes())
						+ ' &ndash; '
						+ _this.calendar.util.formatTime(to.getHours(), to.getMinutes());
				}
				else
				{
					timeLabel = _this.calendar.util.formatTime(from.h, from.m)
						+ ' &ndash; '
						+ _this.calendar.util.formatTime(to.h, to.m);
				}
				timeNode.innerHTML = timeLabel;
			},
			changeNameCallback: function(name)
			{
				nameNode.innerHTML = BX.util.htmlspecialchars(name);
			}
		};

		this.selectEntryPart(entry, color, false);

		return entry;
	};

	DayView.prototype.updateCompactness = function(entryNode)
	{
		const innerNode = entryNode.querySelector('.calendar-event-block-inner');
		const nameNode = entryNode.querySelector('.calendar-event-block-text');
		const timeNode = entryNode.querySelector('.calendar-event-block-time');
		if (!nameNode || !timeNode || !innerNode)
		{
			return;
		}
		// clear all compact levels
		BX.removeClass(entryNode, 'calendar-event-block-compact');
		BX.removeClass(entryNode, 'calendar-event-block-hide-collab');
		nameNode.style.overflow = 'visible';

		// add compactness level by level
		if (nameNode.offsetHeight + timeNode.offsetHeight > innerNode.offsetHeight - 10)
		{
			const lineHeight = parseInt(window.getComputedStyle(nameNode).lineHeight);
			const fitHeight = innerNode.offsetHeight - timeNode.offsetHeight - 10;
			const lineCount = Math.floor(fitHeight / lineHeight);

			if (lineCount <= 1)
			{
				BX.addClass(entryNode, 'calendar-event-block-compact');
			}
		}
		nameNode.style.overflow = '';

		const titleNode = entryNode.querySelector('.calendar-event-block-title');
		if (!titleNode)
		{
			return;
		}

		if (BX.hasClass(entryNode, 'calendar-event-block-compact'))
		{
			const titleWidth = titleNode.offsetWidth;
			const textWidth = [...titleNode.children].reduce((width, child) => {
				return width + child.offsetWidth + parseInt(getComputedStyle(child).marginRight);
			}, 0);

			if (textWidth < titleWidth)
			{
				titleNode.style.width = `${textWidth + 1}px`;
			}
		}

		const collabNode = entryNode.querySelector('.calendar-event-block-collab');
		if (!collabNode)
		{
			return;
		}

		if (nameNode.offsetHeight + timeNode.offsetHeight + collabNode.offsetHeight > innerNode.offsetHeight)
		{
			BX.addClass(entryNode, 'calendar-event-block-hide-collab');
		}

		if (nameNode.offsetHeight + timeNode.offsetHeight + collabNode.offsetHeight > innerNode.offsetHeight - 10)
		{
			const lineHeight = parseInt(window.getComputedStyle(nameNode).lineHeight);
			const fitHeight = innerNode.offsetHeight - timeNode.offsetHeight - collabNode.offsetHeight - 10;
			const lineCount = Math.floor(fitHeight / lineHeight);

			if (lineCount <= 1)
			{
				BX.addClass(entryNode, 'calendar-event-block-compact');
			}
		}
	}

	DayView.prototype.showCompactEditFormForNewEntry = function(params)
	{
		// Show simple add entry popup
		this.showCompactEditForm({
			entryNode: params.entry.entryNode,
			bindNode: params.entry.bindNode,
			section: params.entry.section,
			entryTime: params.entryTime || params.entry.entryTime,
			entryName: params.entry.entryName,
			changeTimeCallback: params.entry.changeTimeCallback,
			changeNameCallback: params.entry.changeNameCallback,
			closeCallback: BX.delegate(function()
			{
				BX.remove(params.entry.entryNode);
			}, this)
		});

		BX.Event.EventEmitter.unsubscribeAll('BX.Calendar.CompactEventForm:onChange');
		BX.Event.EventEmitter.subscribe('BX.Calendar.CompactEventForm:onChange', function(event)
		{
			if (event instanceof BX.Event.BaseEvent)
			{
				var data = event.getData();
				var dateTime = data.form.dateTimeControl.getValue();
				// var dayCode = this.util.getDayCode(dateTime.from);
				//
				// if (dayCode && this.dayIndex[dayCode] !== undefined && this.days[this.dayIndex[dayCode]])
				// {
				// 	var dayFrom = this.days[this.dayIndex[dayCode]];
				// 	partWrap.style.left = 'calc((100% / ' + this.dayCount + ') * (' + (dayFrom.dayOffset + 1) + ' - 1) + 2px)';
				//
				// 	BX.removeClass(this.entryHolders[dayFrom.holderIndex], 'shifted');
				// 	this.entryHolders[dayFrom.holderIndex].appendChild(partWrap);
				// 	var pos = BX.pos(partWrap);
				// 	if (entryClone)
				// 	{
				// 		BX.adjust(entryClone, {
				// 			style: {
				// 				width: (pos.width - 6) + 'px',
				// 				height: pos.height + 'px',
				// 				top : pos.top + 'px',
				// 				left : pos.left + 'px'
				// 			}
				// 		});
				// 	}
				// }
				//
				// var color = data.form.colorSelector.getValue();
				// if (entryClone)
				// {
				// 	entryClone.style.background = color;
				// 	entryClone.style.borderColor = color;
				// }
			}
		}.bind(this));


	};

	DayView.prototype.showAllEventsInPopup = function(params)
	{
		var
			entrieList = params.entrieList || params.day.entries.list,
			innerCont,
			popup;

		innerCont = BX.create('DIV', {
			props: {className: 'calendar-all-events-popup calendar-custom-scroll'},
			events: {click : BX.proxy(this.calendar.handleViewsClick, this.calendar)}
		});

		entrieList.sort(this.calendar.entryController.sort);

		var taskWrap, eventsWrap;
		entrieList.forEach(function(entryItem)
		{
			if (entryItem.entry)
			{
				if (entryItem.entry.isTask())
				{
					if (!taskWrap)
					{
						innerCont.appendChild(BX.create('DIV', {props: {className: 'calendar-event-title'}, text: BX.message('EC_ENTRIES_TASKS')}));
						taskWrap = innerCont.appendChild(BX.create('DIV', {props: {className: 'calendar-event-block'}}));
					}

					this.displayEntryPiece({
						dayInCell: params.day.date,
						entry: entryItem.entry,
						part: entryItem.part,
						holder: taskWrap,
						popupMode: true
					});
				}
				else
				{
					if (!eventsWrap)
					{
						innerCont.appendChild(BX.create('DIV', {props: {className: 'calendar-event-title'}, text: BX.message('EC_ENTRIES_EVENTS')}));
						eventsWrap = innerCont.appendChild(BX.create('DIV', {props: {className: 'calendar-event-block'}}));
					}

					this.displayEntryPiece({
						dayInCell: params.day.date,
						entry: entryItem.entry,
						part: entryItem.part,
						holder: eventsWrap,
						popupMode: true
					});
				}
			}
		}, this);


		popup = BX.PopupWindowManager.create(this.calendar.id + "-all-events-popup", params.day.hiddenStorageText,
			{
				autoHide: true,
				closeByEsc: true,
				offsetTop: -2,
				offsetLeft: -50,
				lightShadow: true,
				content: innerCont
			});

		popup.setAngle({offset: 118});
		popup.show(true);
		this.allEventsPopup = popup;

		BX.addCustomEvent(popup, 'onPopupClose', function()
		{
			popup.destroy();
		});
	};

	DayView.prototype.displayEntryPiece = function(params)
	{
		const entry = params.entry;
		let entryClassName = 'calendar-event-line-wrap';

		if (entry.isFullDay())
		{
			entryClassName += ' calendar-event-line-fill';
		}
		else if (entry.isLongWithTime())
		{
			entryClassName += ' calendar-event-line-border';
		}

		if (entry.getCurrentStatus() === 'N')
		{
			entryClassName += ' calendar-event-line-refused';
		}

		if (entry.isExpired())
		{
			entryClassName += ' calendar-event-line-past';
		}

		if (this.shouldEntryLookLikeSharing(entry))
		{
			entryClassName += ' calendar-event-line-wrap-sharing';
			entryClassName += ' calendar-event-wrap-icon';
		}
		else if (this.shouldEntryLookLikeCollab(entry))
		{
			entryClassName += ' calendar-event-line-wrap-collab';
			entryClassName += ' calendar-event-wrap-icon';
		}

		let arrowColor = entry.color;

		if (entry.isFullDay())
		{
			arrowColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
		}
		else if (entry.isLongWithTime())
		{
			arrowColor = this.calendar.util.addOpacityToHex(entry.color, 0.5);
		}

		let startArrow, endArrow, deltaPartWidth = 0;

		if (!params.popupMode && this.util.getDayCode(entry.from) !== this.util.getDayCode(from.date))
		{
			entryClassName += ' calendar-event-line-start-yesterday';
			deltaPartWidth += 8;
			startArrow = this.getArrow('left', arrowColor, entry.isFullDay());
		}

		if (!params.popupMode && this.util.getDayCode(entry.to) !== this.util.getDayCode(params.part.to.date))
		{
			entryClassName += ' calendar-event-line-finish-tomorrow';
			endArrow = this.getArrow('right', arrowColor, entry.isFullDay());
			deltaPartWidth += 12;
		}

		if (startArrow && !endArrow)
		{
			deltaPartWidth += 4;
		}

		deltaPartWidth = deltaPartWidth === 0 ? 5 : deltaPartWidth;

		const daysCount = params.part.daysCount, from = params.part.from;
		let partWrap = BX.create('DIV', {
			attrs: {'data-bx-calendar-entry': entry.uid},
			props: {className: entryClassName}, style: {
				top: 0,
				left: 'calc((100% / ' + this.dayCount + ') * (' + (from.dayOffset + 1) + ' - 1) + 2px)',
				width: 'calc(' + daysCount + ' * 100% / ' + this.dayCount + ' - ' + deltaPartWidth + 'px)'
			}
		});

		if (startArrow)
		{
			BX.Dom.addClass()
			partWrap.style.left = '9px';
		}

		if (endArrow)
		{
			partWrap.appendChild(endArrow);
		}

		let innerContainer = partWrap.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner-container'}})),
			innerNode = innerContainer.appendChild(BX.create('DIV', {props: {className: 'calendar-event-line-inner'}}));

		const day = this.days[this.dayIndex[entry.startDayCode]];
		const entriesInDay = [...day.entries.topList].sort((e1, e2) => {
			return (e1.entry.from.getTime() > e2.entry.from.getTime()) ? 1 : (e1.entry.from.getTime() < e2.entry.from.getTime()) ? -1 : 0;
		});
		const positionInDay = entriesInDay.findIndex(e => e.entry.uid === entry.uid);

		if (positionInDay >= this.slotsCount && entriesInDay.length > this.slotsCount)
		{
			entry.isHiddenInPopup = true;
		}

		let dotNode = BX.create('DIV', {props: {className: 'calendar-event-line-dot'}}), timeNode, endTimeNode;

		if (entry.isInvited())
		{
			partWrap.className += ' calendar-event-animate-counter-highlight';
			if (this.isFirstVisibleRecursiveEntry(entry))
			{
				innerNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-invite-counter'}, text: '1'}))
			}
			else
			{
				//temporarily removed recursive entries invitation indicators
				// innerNode.appendChild(BX.create('DIV', {props: {className: 'calendar-event-invite-counter-dot'}}))
				innerNode.appendChild(dotNode);
			}
		}
		else
		{
			innerNode.appendChild(dotNode);
		}

		if (entry.isSharingEvent())
		{
			innerNode.appendChild(BX.create('SPAN', {props: {className: 'calendar-event-block-icon-sharing'}}));
		}

		if (entry.isFullDay())
		{
			innerNode.style.maxWidth = 'calc(200% / ' + daysCount + ' - 3px)';
		}
		else if (entry.isLongWithTime())
		{
			innerNode.style.maxWidth = 'calc(200% / ' + daysCount + ' - 3px)';

			let dayInCell = params.dayInCell;
			if (params.popupMode && typeof dayInCell !== 'undefined')
			{
				switch (this.util.getDayCode(dayInCell))
				{
					case this.util.getDayCode(entry.from):
						timeNode = innerNode.appendChild(
							BX.create('SPAN', {
								props: {className: 'calendar-event-line-time'},
								text: this.calendar.util.formatTime(entry.from.getHours(), entry.from.getMinutes())
							}));
						break;
					case this.util.getDayCode(entry.to):
						let formattedDate = this.calendar.util.formatTime(entry.to.getHours(), entry.to.getMinutes());
						timeNode = innerNode.appendChild(
							BX.create('SPAN', {
								props: {className: 'calendar-event-line-time'},
								text: BX.message('EC_JS_UNTIL_DATE').replace('#DATE#', formattedDate)
							})
						)
						break;
				}

				innerNode.style.width = 'calc(100% / ' + daysCount + ' - 3px)';
			}
		}

		let nameNode = innerNode.appendChild(
			BX.create('SPAN', {
				props: {className: 'calendar-event-line-text'},
				text: params.entry.name
			})
		);

		if (entry.isFullDay())
		{
			innerContainer.style.backgroundColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
			innerContainer.style.borderColor = this.calendar.util.addOpacityToHex(entry.color, 0.3);
		}
		else
		{
			if (entry.isLongWithTime())
			{
				innerContainer.style.borderColor = this.calendar.util.addOpacityToHex(entry.color, 0.5);
			}
			dotNode.style.backgroundColor = entry.color;
		}

		let holder = params.holder || this.entryHolders[from.holderIndex];
		holder.appendChild(partWrap);

		if (entry.opacity !== undefined)
		{
			partWrap.style.opacity = entry.opacity;
		}

		let res = {
			wrapNode: partWrap,
			nameNode: nameNode,
			innerContainer: innerContainer,
			innerNode: innerNode,
			timeNode: timeNode || false,
			endTimeNode: endTimeNode || false,
			dotNode: dotNode
		};

		if (!params.popupMode)
		{
			params.entry.registerPartNode(params.part, res);
		}

		this.calendar.dragDrop.registerEntry(partWrap, params);

		return res;
	};

	// Week view of the calendar
	function WeekView()
	{
		View.apply(this, arguments);
		this.initConfig();
		this.preBuild();
	}
	WeekView.prototype = Object.create(DayView.prototype);
	WeekView.prototype.constructor = WeekView;

	WeekView.prototype.show = function()
	{
		View.prototype.show.apply(this, arguments);
		this.buildDaysGrid();

		if (this.calendar.navCalendar)
			this.calendar.navCalendar.hide();

		this.loadEntries().then(entries => {
			this.entries = entries;
			this.displayEntries();
		});
		this.calendar.initialViewShow = false;
	};

	WeekView.prototype.initConfig = function()
	{
		DayView.prototype.initConfig.apply(this, arguments);
		this.name = 'week';
		this.title = BX.message('EC_VIEW_WEEK');
		this.contClassName = 'calendar-week-view';
		this.hotkey = 'W';
		this.gridWrapClass = 'calendar-grid-wrap';
		if (BX.isAmPmMode())
		{
			this.gridWrapClass += ' is-am-pm-mode';
		}
		this.fullDayContClass = 'calendar-grid-week-full-days-events-holder';
		this.outerGridClass = 'calendar-grid-week-container';
		this.gridClass = 'calendar-grid-week';
		this.gridClassCurrent = 'calendar-grid-week-current';

		this.gridClassNext = 'calendar-grid-week-left-slide';
		this.gridClassPrevious = 'calendar-grid-week-right-slide';
		this.changeNextClass = 'calendar-change-week-left-slide';
		this.changePreviousClass = 'calendar-change-week-right-slide';

		this.gridRowClass = 'calendar-grid-week-row';
		this.gridCellClass = 'calendar-grid-week-cell';
		this.gridTimelinesClass = 'calendar-grid-week-time-lines';
		this.gridTimelineHourClass = 'calendar-grid-week-time-line-hour';
		this.gridTimelineHourLabelClass = 'calendar-grid-week-time-line-hour-label';
		this.topEntryHolderClass = 'calendar-grid-week-events-holder';

		this.gridNowTimeClass = 'calendar-grid-week-time-line-hour-now';
		this.gridNowTimeLabelClass = 'calendar-grid-week-time-line-hour-label';
		this.gridNowTimeLineClass = 'calendar-grid-week-time-line-hour-now-line';
		this.gridNowTimeDotClass = 'calendar-grid-week-time-line-hour-now-dot';

		this.dayCount = 7;
	};
	WeekView.prototype.setTitle = function()
	{
		var
			viewRangeDate = this.calendar.getViewRangeDate(),
			time = viewRangeDate.getTime(),
			dateTo = new Date(viewRangeDate.getTime() + this.dayCount * this.calendar.util.dayLength);

		if (viewRangeDate.getMonth() !== dateTo.getMonth())
		{
			View.prototype.setTitle.apply(this, [
				BX.date.format('f', time / 1000) + ' - ' + BX.date.format('f', dateTo.getTime() / 1000) + (this.util.showWeekNumber() ? ', #GRAY_START#' + BX.message('EC_DATE_WEEK_NUMBER').replace('#WEEK_NUMBER#', this.util.getWeekNumber(time)) + '#GRAY_END#' : '')
			]);
		}
		else
		{
			View.prototype.setTitle.apply(this, [
				BX.date.format('f', time / 1000) + (this.util.showWeekNumber() ? ', #GRAY_START#' + BX.message('EC_DATE_WEEK_NUMBER').replace('#WEEK_NUMBER#', this.util.getWeekNumber(time)) + '#GRAY_END#' : '')
			]);
		}
	};

	WeekView.prototype.getAdjustedDate = function(date, viewRange, adjustViewRange)
	{
		// TODO: add logic if we changed to the other date and than changing view
		if (!date)
		{
			date = new Date();
		}

		if (viewRange && date.getTime() < viewRange.start.getTime())
		{
			date = new Date(viewRange.start.getTime());
		}

		if (viewRange && date.getTime() > viewRange.end.getTime())
		{
			date = new Date(viewRange.end.getTime());
		}

		var weekstart = this.util.getWeekStart();

		while (this.util.getWeekDayByInd(date.getDay()) != weekstart)
		{
			date.setDate(date.getDate() - 1);
		}

		if (adjustViewRange)
		{
			viewRange.start.setDate(date.getTime());
			viewRange.end.setDate(date.getTime() + this.calendar.util.dayLength * this.dayCount);
		}

		return DayView.prototype.getAdjustedDate.apply(this, [date, viewRange]);
	};

	WeekView.prototype.adjustViewRangeToDate = function(date)
	{
		var weekstart = this.util.getWeekStart();
		while (this.util.getWeekDayByInd(date.getDay()) != weekstart)
		{
			date.setDate(date.getDate() - 1);
		}
		return DayView.prototype.adjustViewRangeToDate.apply(this, [date]);
	};

	if (window.BXEventCalendar)
	{
		window.BXEventCalendar.CalendarDayView = DayView;
		window.BXEventCalendar.CalendarWeekView = WeekView;
	}
	else
	{
		BX.addCustomEvent(window, "onBXEventCalendarInit", function()
		{
			window.BXEventCalendar.CalendarDayView = DayView;
			window.BXEventCalendar.CalendarWeekView = WeekView;
		});
	}


	function CollapsedTimeWrap(params)
	{
		this.position = params.position;
		this.outerWrap = params.wrap;
		this.workTime = params.workTime;
		this.dayOffset = params.dayOffset;
		this.dayCount = params.dayCount;
		this.lastEntryWidthOffset = params.lastEntryWidthOffset;
		this.gridLineHeight = params.gridLineHeight;
		this.labelMessage = params.labelMessage;

		this.clickHandler = params.clickHandler;
		this.mouseoutHandler = params.mouseoutHandler;
		this.mouseoverHandler = params.mouseoverHandler;

		this.isInited = false;
		this.entryCount = 0;
		this.create();
	}

	CollapsedTimeWrap.prototype =
	{
		create: function ()
		{
			this.wrap = this.outerWrap.appendChild(BX.create('DIV', {
				props: {
					className: 'calendar-event-block-wrap calendar-event-block-wrap-more'
				},
				style:
					{
						top: (this.position === 'bottom') ? ((this.workTime.end - this.workTime.start) * this.gridLineHeight) + 'px' : '-9px',
						left: this.dayCount > 1 ? 'calc((100% / ' + this.dayCount + ') * ' + this.dayOffset + ' + 2px)' : '2px',
						width: 'calc(100% / ' + this.dayCount + ' - ' + this.lastEntryWidthOffset + 'px)'
					}
			})).appendChild(BX.create('DIV', {
				props: {className: 'calendar-event-block-inner'},
				html: '<div class="calendar-event-block-background" style="background-color: #808080;"></div>'
			}));

			if (BX.type.isFunction(this.clickHandler))
			{
				BX.bind(this.wrap, 'click', this.clickHandler);
			}

			if (BX.type.isFunction(this.mouseoverHandler))
			{
				BX.bind(this.wrap, 'mouseover', this.mouseoverHandler);
			}

			if (BX.type.isFunction(this.mouseoutHandler))
			{
				BX.bind(this.wrap, 'mouseout', this.mouseoutHandler);
			}

			this.countContainer = this.wrap.appendChild(BX.create('span', {
				props: {
					className: 'calendar-event-block-text'
				},
				html: '<span class="calendar-event-block-text-subtitle">' + this.labelMessage + '</span>'
			})).appendChild(BX.create('span', {
				props: {
					className: 'calendar-event-block-text-total'
				}
			}));

			this.isInited = true;
		},

		inited: function()
		{
			return this.isInited && BX.isNodeInDom(this.wrap);
		},

		destroy: function()
		{
			BX.remove(this.wrap);
			this.isInited = false;
		},

		addEntry: function(entry)
		{
			this.entryCount++;
			this.countContainer.innerHTML = this.entryCount;
		}
	}
})(window);

Youez - 2016 - github.com/yon3zu
LinuXploit