Your IP : 3.147.46.174


Current Path : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/main/rating/src/
Upload File :
Current File : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/main/rating/src/render.js

import { Type, Loc, Dom, Runtime, pos, GetWindowSize } from 'main.core';
import { EventEmitter } from 'main.core.events'
import {Lottie} from 'ui.lottie';

import { RatingManager } from './manager';
import { RatingLike } from './like';
import { ListPopup } from './listpopup';
import likeAnimatedEmojiData from '../animations/em_01.json';
import laughAnimatedEmojiData from '../animations/em_02.json';
import wonderAnimatedEmojiData from '../animations/em_03.json';
import cryAnimatedEmojiData from '../animations/em_04.json';
import angryAnimatedEmojiData from '../animations/em_05.json';
import facepalmAnimatedEmojiData from '../animations/em_06.json';
import kissAnimatedEmojiData from '../animations/em_07.json';

export class RatingRender
{
	static reactionsList = [ 'like', 'kiss', 'laugh', 'wonder', 'cry', 'angry', 'facepalm' ];
	static reactionsAnimationData = {
		like: likeAnimatedEmojiData,
		kiss: kissAnimatedEmojiData,
		laugh: laughAnimatedEmojiData,
		wonder: wonderAnimatedEmojiData,
		cry: cryAnimatedEmojiData,
		angry: angryAnimatedEmojiData,
		facepalm: facepalmAnimatedEmojiData,
	}
	static popupCurrentReaction = false;
	static popupPagesList = [];
	static popupSizeInitialized = false;
	static blockShowPopup = false;
	static blockShowPopupTimeout = false;
	static afterClickBlockShowPopup = false;
	static afterClickHandler = null;
	static touchStartPosition = null;
	static touchCurrentPosition = {
		x: null,
		y: null,
	};
	static currentReactionNodeHover = null;

	static touchMoveDeltaY = null;
	static touchScrollTop = 0;

	static hasMobileTouchMoved = null;
	static mobileOverlay = null;

	static reactionsPopup = null;
	static reactionsPopupAnimation = null;
	static reactionsPopupAnimation2 = null;
	static reactionsPopupLikeId = null;
	static reactionsPopupMouseOutHandler = null;
	static reactionsPopupOpacityState = 0;
	static reactionsPopupTouchStartIn = null;
	static reactionsPopupPositionY = null;
	static blockTouchEndByScroll = false;

	static reactionsPopupMobileTouchEndHandler = this.reactionsPopupMobileTouchEnd.bind(this);
	static reactionsPopupMobileTouchMoveHandler = this.reactionsPopupMobileTouchMove.bind(this);
	static reactionsPopupMobileHideHandler = this.reactionsPopupMobileHide.bind(this);

	static getTopUsersText(params)
	{
		const currentUserId = Number(Loc.getMessage('USER_ID'));
		const you = (!Type.isUndefined(params.you) ? !!params.you : false);
		const topList = (!Type.isUndefined(params.top) && Type.isArray(params.top) ? params.top : []);
		const more = (!Type.isUndefined(params.more) ? Number(params.more) : 0);
		let result = '';

		if (
			topList.length <= 0
			&& !you
			&& (
				RatingManager.mobile
				|| more <= 0
			)
		)
		{
			return result;
		}

		if (RatingManager.mobile)
		{
			if (you)
			{
				topList.push({
					ID: currentUserId,
					NAME_FORMATTED: Loc.getMessage('RATING_LIKE_TOP_TEXT3_YOU'),
					WEIGHT: 1,
				});
			}

			result = Loc.getMessage(`RATING_LIKE_TOP_TEXT3_${(topList.length > 1 ? '2' : '1')}`)
				.replace('#OVERFLOW_START#', RatingManager.mobile ? '<span class="feed-post-emoji-text-item-overflow">' : '')
				.replace('#OVERFLOW_END#', RatingManager.mobile ? '</span>' : '');
		}
		else
		{
			result = Loc.getMessage(`RATING_LIKE_TOP_TEXT2_${(you ? 'YOU_' : '')}${(topList.length)}${(more > 0 ? '_MORE' : '')}`)
				.replace('#OVERFLOW_START#', RatingManager.mobile ? '<span class="feed-post-emoji-text-item-overflow">' : '')
				.replace('#OVERFLOW_END#', RatingManager.mobile ? '</span>' : '')
				.replace('#MORE_START#', RatingManager.mobile ? '<span class="feed-post-emoji-text-item-more">' : '&nbsp;')
				.replace('#MORE_END#', RatingManager.mobile ? '</span>' : '');
		}

		if (RatingManager.mobile)
		{
			topList.sort((a, b) => {
				if (parseInt(a.ID) === currentUserId)
				{
					return -1;
				}

				if (parseInt(b.ID) === currentUserId)
				{
					return 1;
				}

				if (parseFloat(a.WEIGHT) === parseFloat(b.WEIGHT))
				{
					return 0;
				}

				return (parseFloat(a.WEIGHT) > parseFloat(b.WEIGHT) ? -1 : 1);
			});

			const userNameList = topList.map((item) => {
				return item.NAME_FORMATTED;
			});

			let userNameBegin = '';
			let userNameEnd = '';

			if (userNameList.length === 1)
			{
				userNameBegin = userNameList.pop();
				userNameEnd = '';
			}
			else
			{
				userNameBegin = userNameList.slice(0, userNameList.length - 1)
					.join(Loc.getMessage('RATING_LIKE_TOP_TEXT3_USERLIST_SEPARATOR').replace(/#USERNAME#/g, ''));
				userNameEnd = userNameList[userNameList.length - 1];
			}

			result = result.replace('#USER_LIST_BEGIN#', userNameBegin)
				.replace('#USER_LIST_END#', userNameEnd);
		}
		else
		{
			topList.forEach((item, i) => {

				result = result.replace(
					`#USER_${(Number(i) + 1)}#`,
					`<span class="feed-post-emoji-text-item">${item.NAME_FORMATTED}</span>`
				);
			});

			result = result.replace('#USERS_MORE#', '<span class="feed-post-emoji-text-item">' + more + '</span>');
		}

		return result;
	}

	static getUserReaction(params)
	{
		return (
			Type.isDomNode(params.userReactionNode)
				? params.userReactionNode.getAttribute('data-value')
				: ''
		);
	}

	static setReaction(params)
	{
		if (
			Type.isUndefined(params.rating)
			|| !Type.isStringFilled(params.likeId)
		)
		{
			return;
		}

		const action = (Type.isStringFilled(params.action) ? params.action : 'add');
		if (!['add', 'cancel', 'change'].includes(action))
		{
			return;
		}

		const likeId = params.likeId;
		const rating = params.rating;
		const userReaction = (Type.isStringFilled(params.userReaction) ? params.userReaction : Loc.getMessage('RATING_LIKE_REACTION_DEFAULT'));
		const userReactionOld = (Type.isStringFilled(params.userReactionOld) ? params.userReactionOld : Loc.getMessage('RATING_LIKE_REACTION_DEFAULT'));
		if (
			action === 'change'
			&& userReaction === userReactionOld
		)
		{
			return;
		}

		const totalCount = (!Type.isUndefined(params.totalCount) ? Number(params.totalCount) : null);
		const currentUserId = Number(Loc.getMessage('USER_ID'));
		const userId = (!Type.isUndefined(params.userId) ? Number(params.userId) : currentUserId);

		const userReactionNode = this.getNode(rating.userReactionNode);
		const reactionsNode = this.getNode(rating.reactionsNode);
		const topPanel = this.getNode(rating.topPanel);
		const topPanelContainer = this.getNode(rating.topPanelContainer);
		const topUsersText = this.getNode(rating.topUsersText);
		const countText = this.getNode(rating.countText);
		const buttonText = this.getNode(rating.buttonText);

		if (
			userId === currentUserId // not pull
			&& userReactionNode
		)
		{
			userReactionNode.setAttribute('data-value', [ 'add', 'change' ].includes(action) ? userReaction : '');
		}

		let i = 0;
		let elements = [];
		let elementsNew = [];

		if (
			totalCount !== null
			&& topPanel
			&& topUsersText
			&& reactionsNode
		)
		{
			if (totalCount > 0)
			{
				topPanelContainer.classList.add('feed-post-emoji-top-panel-container-active');

				if (!topPanel.classList.contains('feed-post-emoji-container-toggle'))
				{
					topPanel.classList.add('feed-post-emoji-container-toggle');
					topUsersText.classList.add('feed-post-emoji-move-to-right');
					reactionsNode.classList.add('feed-post-emoji-icon-box-show');
				}
			}
			else if (totalCount <= 0)
			{
				topPanelContainer.classList.remove('feed-post-emoji-top-panel-container-active');

				if (topPanel.classList.contains('feed-post-emoji-container-toggle'))
				{
					topPanel.classList.remove('feed-post-emoji-container-toggle');
					topUsersText.classList.remove('feed-post-emoji-move-to-right');
					reactionsNode.classList.remove('feed-post-emoji-icon-box-show');
				}
			}
		}

		if (
			totalCount !== null
			&& countText
		)
		{
			if (
				totalCount <= 0
				&& !countText.classList.contains('feed-post-emoji-text-counter-invisible')
			)
			{
				countText.classList.add('feed-post-emoji-text-counter-invisible');
			}
			else if (
				totalCount > 0
				&& countText.classList.contains('feed-post-emoji-text-counter-invisible')
			)
			{
				countText.classList.remove('feed-post-emoji-text-counter-invisible');
			}
		}

		if (reactionsNode)
		{
			const reactionsContainer = reactionsNode.querySelector('.feed-post-emoji-icon-container');
			elements = reactionsNode.querySelectorAll('.feed-post-emoji-icon-item');

			if (reactionsContainer)
			{
				let found = false;
				let newValue = false;

				elements.forEach((element) => {

					const reactionValue = element.getAttribute('data-reaction');
					const reactionCount = Number(element.getAttribute('data-value'));

					if (reactionValue === userReaction)
					{
						found = true;
						if (action === 'cancel')
						{
							newValue = (reactionCount > 0 ? reactionCount - 1 : 0);
						}
						else if ([ 'add', 'change' ].includes(action))
						{
							newValue = reactionCount + 1;
						}

						if (newValue > 0 && newValue > reactionCount)
						{
							elementsNew.push({
								reaction: reactionValue,
								count: newValue,
								animate: {
									type: 'pop',
								},
							});
						}
						else if (newValue > 0)
						{
							elementsNew.push({
								reaction: reactionValue,
								count: reactionCount,
								animate: false,
							});
						}
					}
					else if (
						action === 'change'
						&& reactionValue === userReactionOld
					)
					{
						newValue = (reactionCount > 0 ? reactionCount - 1 : 0);

						if (newValue > 0)
						{
							elementsNew.push({
								reaction: reactionValue,
								count: newValue,
								animate: false,
							});
						}
					}
					else
					{
						elementsNew.push({
							reaction: reactionValue,
							count: reactionCount,
							animate: false,
						});
					}
				});

				if (
					['add', 'change'].includes(action)
					&& !found
				)
				{
					elementsNew.push({
						reaction: userReaction,
						count: 1,
						animate: true,
					});
				}

				Dom.clean(reactionsContainer);

				if (topPanel)
				{
					if (elementsNew.length > 0)
					{
						topPanel.classList.add('feed-post-emoji-container-nonempty');
					}
					else
					{
						topPanel.classList.remove('feed-post-emoji-container-nonempty');
					}

					if (RatingManager.mobile)
					{
						const commentNode = topPanel.closest('.post-comment-block');
						if (commentNode)
						{
							if (elementsNew.length > 0)
							{
								commentNode.classList.add('comment-block-rating-nonempty');
							}
							else
							{
								commentNode.classList.remove('comment-block-rating-nonempty');
							}
						}
					}
				}

				this.drawReactions({
					likeId: likeId,
					container: reactionsContainer,
					data: elementsNew,
				});
			}
		}

		if (
			userId === currentUserId
			&& buttonText
		)
		{
			if ([ 'add', 'change' ].includes(action))
			{
				buttonText.innerHTML = Loc.getMessage(`RATING_LIKE_EMOTION_${userReaction.toUpperCase()}_CALC`);
				if (RatingManager.mobile)
				{
					buttonText.parentElement.className = '';
					buttonText.parentElement.classList.add(
						'bx-ilike-left-wrap',
						'bx-you-like-button',
						`bx-you-like-button-${userReaction.toLowerCase()}`
					);
				}
			}
			else
			{
				buttonText.innerHTML = Loc.getMessage('RATING_LIKE_EMOTION_LIKE_CALC');
				if (RatingManager.mobile)
				{
					buttonText.parentElement.className = 'bx-ilike-left-wrap';
				}
			}
		}
	}

	static drawReactions(params)
	{
		const container = (Type.isDomNode(params.container) ? params.container : null);
		const data = (Type.isArray(params.data) ? params.data : []);
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '')
		if (
			!container
			|| !Type.isStringFilled(likeId)
		)
		{
			return;
		}

		const reactionEvents = (
			RatingManager.mobile
				? {}
				: {
					click: this.resultReactionClick.bind(this),
					mouseenter: this.resultReactionMouseEnter.bind(this),
					mouseleave: this.resultReactionMouseLeave.bind(this),
				}
		);

		Dom.clean(container);

		const reactionsData = {};

		data.forEach((element, i) => {

			const classList = [
				'feed-post-emoji-icon-item',
				`feed-post-emoji-icon-item-${(i+1)}`,
			];

			if (element?.animate)
			{
				if (element.animate?.type === 'pop')
				{
					classList.push('feed-post-emoji-animation-pop');
				}
				else if (i >= 1)
				{
					classList.push('feed-post-emoji-icon-animate');
				}
				else if (data.length == 1)
				{
					classList.push('feed-post-emoji-animation-pop');
				}
			}

			const emojiContainer = Dom.create('div', {
				props: {
					id: `bx-ilike-result-reaction-${element.reaction}-${likeId}`,
					className: classList.join(' '),
				},
				attrs: {
					'data-reaction': element.reaction,
					'data-value': element.count,
					'data-like-id': likeId,
					title: Loc.getMessage(`RATING_LIKE_EMOTION_${element.reaction.toUpperCase()}_CALC`),
				},
				events: reactionEvents,
			});

			const animation = Lottie.loadAnimation({
				animationData: this.reactionsAnimationData[element.reaction],
				container: emojiContainer,
				loop: false,
				autoplay: false,
				renderer: 'svg',
				rendererSettings: {
					viewBoxOnly: true,
				}
			});

			if (Boolean(element.animate))
			{
				setTimeout(() => {
					animation.play();
				}, 200);
			}

			container.appendChild(emojiContainer);

			reactionsData[element.reaction] = element.count;
		});

		container.setAttribute('data-reactions-data', JSON.stringify(reactionsData));
	}

	static showReactionsPopup(params)
	{
		const bindElement = this.getNode(params.bindElement);
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');

		if (
			!bindElement
			|| !Type.isStringFilled(likeId)
		)
		{
			return false;
		}

		this.reactionsPopupLikeId = likeId;

		if (this.reactionsPopup === null)
		{
			const reactionsNodesList = [];

			this.reactionsList.forEach((currentEmotion, index) => {

				const emojiItem = Dom.create('div', {
					props: {
						className: `feed-post-emoji-icon-item`,
					},
					attrs: {
						'data-reaction': currentEmotion,
						title: Loc.getMessage(`RATING_LIKE_EMOTION_${currentEmotion.toUpperCase()}_CALC`),
					},
				});

				Lottie.loadAnimation({
					renderer: 'svg',
					container: emojiItem,
					animationData: this.reactionsAnimationData[currentEmotion],
				});

				reactionsNodesList.push(emojiItem);
			});

			this.reactionsPopup = Dom.create('div', {
				props: {
					className: `feed-post-emoji-popup-container ${(RatingManager.mobile ? '--mobile' : '')}`,
				},
				children: [
					Dom.create('div', {
						props: {
							className: 'feed-post-emoji-icon-inner',
						},
						children: reactionsNodesList,
					})
				],
			});

			this.reactionsPopup.addEventListener((RatingManager.mobile ? 'touchend' : 'click'), (e) => {

				const reactionNode = (
					(e.target.classList.contains('feed-post-emoji-icon-item'))
						? e.target
						: e.target.closest('.feed-post-emoji-icon-item')
				);

				if (reactionNode)
				{
					RatingLike.ClickVote(
						e,
						this.reactionsPopupLikeId,
						reactionNode.getAttribute('data-reaction'),
						true
					);
				}

				e.preventDefault();
			});

			Dom.append(this.reactionsPopup, document.body);
		}
		else if (this.reactionsPopup.classList.contains('feed-post-emoji-popup-invisible'))
		{
			this.reactionsPopup.classList.remove('feed-post-emoji-popup-invisible');
		}
		else if (
			RatingManager.mobile
			&& this.reactionsPopup.classList.contains('feed-post-emoji-popup-invisible-final-mobile')
		)
		{
			this.reactionsPopup.classList.remove('feed-post-emoji-popup-invisible-final-mobile');
		}
		else
		{
			return;
		}

		this.reactionsPopupMouseOutHandler = this.getReactionsPopupMouseOutHandler(likeId);

		const bindElementPosition = pos(bindElement);

		if (
			bindElement.closest('.feed-com-informers-bottom')
			&& bindElement.closest('.iframe-comments-cont, .task-iframe-popup')
		)
		{
			bindElementPosition.left += 100;
		}

		const inverted = ((bindElementPosition.top - GetWindowSize().scrollTop) < 80);
		const deltaY = (inverted ? 15 : -45);

		if (inverted)
		{
			this.reactionsPopup.classList.add('feed-post-emoji-popup-inverted');
		}
		else
		{
			this.reactionsPopup.classList.remove('feed-post-emoji-popup-inverted');
		}

		const likeInstance = RatingLike.getInstance(likeId);

		if (RatingManager.mobile)
		{
			this.touchMoveDeltaY = (inverted ? 60 : -45);
			Dom.adjust(this.reactionsPopup, {
				style: {
					left: '12px',
					top: ((inverted ? (bindElementPosition.top - 23) : (bindElementPosition.top - 28)) + deltaY) + 'px',
					width: '330px',
					borderRadius: '61px',
				},
			});

			this.reactionsPopup.classList.remove('feed-post-emoji-popup-invisible-final');
			this.reactionsPopup.classList.add('feed-post-emoji-popup-active-final');
			this.reactionsPopup.classList.add('feed-post-emoji-popup-active-final-item');
			likeInstance.box.classList.add('feed-post-emoji-control-active');
			this.reactionsPopupMobileDisableScroll();
		}
		else
		{
			this.reactionsPopupAnimation = new BX.easing({
				duration: 300,
				start: {
					width: 100,
					left: (bindElementPosition.left + (bindElementPosition.width / 2) - 50),
					top: ((inverted ? bindElementPosition.top - 30 : bindElementPosition.top + 30 ) + deltaY),
					borderRadius: 0,
					opacity: 0,
				},
				finish: {
					width: 300,
					left: (bindElementPosition.left + (bindElementPosition.width / 2) - 133),
					top: (bindElementPosition.top + deltaY - 5),
					borderRadius: 50,
					opacity: 100,
				},
				transition : BX.easing.makeEaseInOut(BX.easing.transitions.cubic),
				step: (state) => {
					if (!this.reactionsPopup)
					{
						this.reactionsPopupAnimation.stop();
						return;
					}
					this.reactionsPopup.style.width = `${state.width}px`;
					this.reactionsPopup.style.left = `${state.left}px`;
					this.reactionsPopup.style.top = `${state.top}px`;
					this.reactionsPopup.style.borderRadius = `${state.borderRadius}px`;
					this.reactionsPopup.style.opacity = state.opacity / 100;
					this.reactionsPopupOpacityState = state.opacity;
				},
				complete: () => {
					if (!this.reactionsPopup)
					{
						return;
					}
					this.reactionsPopup.style.opacity = '';
					this.reactionsPopup.classList.add('feed-post-emoji-popup-active-final');
					likeInstance.box.classList.add('feed-post-emoji-control-active');
					if (Type.isFunction(params.onComplete))
					{
						params.onComplete();
					}
				},
			});
			this.reactionsPopupAnimation.animate();

			setTimeout(() => {

				if (!this.reactionsPopup)
				{
					return;
				}

				const reactions = this.reactionsPopup.querySelectorAll('.feed-post-emoji-icon-item');

				this.reactionsPopupAnimation2 = new BX.easing({
					duration: 140,
					start: {
						opacity: 0,
					},
					finish: {
						opacity: 100
					},
					transition : BX.easing.transitions.cubic,
					step: (state) => {
						reactions[0].style.opacity = state.opacity / 100;
						reactions[1].style.opacity = state.opacity / 100;
						reactions[2].style.opacity = state.opacity / 100;
						reactions[3].style.opacity = state.opacity / 100;
						reactions[4].style.opacity = state.opacity / 100;
						reactions[5].style.opacity = state.opacity / 100;
						reactions[6].style.opacity = state.opacity / 100;
					},
					complete: () => {
						this.reactionsPopup.classList.add('feed-post-emoji-popup-active-final-item');
						reactions[0].style.opacity = '';
						reactions[1].style.opacity = '';
						reactions[2].style.opacity = '';
						reactions[3].style.opacity = '';
						reactions[4].style.opacity = '';
						reactions[5].style.opacity = '';
						reactions[6].style.opacity = '';
					},
				});
				this.reactionsPopupAnimation2.animate();
			}, 100);
		}

		if (!this.reactionsPopup.classList.contains('feed-post-emoji-popup-active'))
		{
			this.reactionsPopup.classList.add('feed-post-emoji-popup-active');
		}

		if (!RatingManager.mobile)
		{
			document.addEventListener('mousemove', this.reactionsPopupMouseOutHandler);
		}
		else
		{
			this.touchScrollTop = GetWindowSize().scrollTop;
			this.hasMobileTouchMoved = null;

			window.addEventListener('touchend', this.reactionsPopupMobileTouchEndHandler);
			window.addEventListener('touchmove', this.reactionsPopupMobileTouchMoveHandler);
		}
	}

	static reactionsPopupMobileTouchEnd(e)
	{
		const coords = {
			x: e.changedTouches[0].pageX, // e.touches[0].clientX + window.pageXOffset
			y: e.changedTouches[0].pageY, // e.touches[0].clientY + window.pageYOffset
		};

		if (this.hasMobileTouchMoved === true)
		{
			let userReaction = null;
			const reactionNode = this.reactionsPopupMobileGetHoverNode(coords.x, coords.y);

			if (
				reactionNode
				&& (userReaction = reactionNode.getAttribute('data-reaction'))
			)
			{
				RatingLike.ClickVote(
					e,
					this.reactionsPopupLikeId,
					userReaction,
					true
				);
			}
			this.reactionsPopupMobileHideHandler();
		}
		else // show reactions popup and handle clicks
		{
			window.addEventListener('touchend', this.reactionsPopupMobileHideHandler);
		}

		window.removeEventListener('touchend', this.reactionsPopupMobileTouchEndHandler);
		window.removeEventListener('touchmove', this.reactionsPopupMobileTouchMoveHandler);

		this.touchStartPosition = null;
		e.preventDefault();
	}

	static reactionsPopupMobileTouchMove(e)
	{
		const coords = {
			x: e.touches[0].pageX, // e.touches[0].clientX + window.pageXOffset
			y: e.touches[0].pageY, // e.touches[0].clientY + window.pageYOffset
		};


		this.touchCurrentPosition = {
			x: coords.x,
			y: coords.y,
		};

		if (this.touchStartPosition === null)
		{
			this.touchStartPosition = {
				x: coords.x,
				y: coords.y,
			};
		}
		else
		{
			if (this.hasMobileTouchMoved !== true)
			{
				this.hasMobileTouchMoved = !this.reactionsPopupMobileCheckTouchMove();
			}
		}

		if (this.hasMobileTouchMoved === true)
		{
			const reactionNode = this.reactionsPopupMobileGetHoverNode(coords.x, coords.y);
			if (reactionNode)
			{
				if (
					this.currentReactionNodeHover
					&& this.currentReactionNodeHover !== reactionNode
				)
				{
					this.reactionsPopupMobileRemoveHover(this.currentReactionNodeHover);
				}
				this.reactionsPopupMobileAddHover(reactionNode);
				this.currentReactionNodeHover = reactionNode;
			}
			else if (this.currentReactionNodeHover)
			{
				this.reactionsPopupMobileRemoveHover(this.currentReactionNodeHover);
			}
		}
		else
		{
			if (this.currentReactionNodeHover)
			{
				this.reactionsPopupMobileRemoveHover(this.currentReactionNodeHover);
			}
		}
	}

	static blockReactionsPopup()
	{
		if (this.blockShowPopupTimeout)
		{
			window.clearTimeout(this.blockShowPopupTimeout);
		}

		this.blockShowPopup = true;
		this.blockShowPopupTimeout = setTimeout(() => {
			this.blockShowPopup = false;
		}, 500);
	}

	static hideReactionsPopup(params)
	{
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : false);

		if (this.reactionsPopup)
		{
			if (RatingManager.mobile)
			{
				this.reactionsPopup.classList.add('feed-post-emoji-popup-invisible-final');
				this.reactionsPopup.classList.add('feed-post-emoji-popup-invisible-final-mobile');
				this.reactionsPopup.classList.remove('feed-post-emoji-popup-active');
				this.reactionsPopup.classList.remove('feed-post-emoji-popup-active-final');
				this.reactionsPopup.classList.remove('feed-post-emoji-popup-active-final-item');
				this.reactionsPopupMobileEnableScroll();
				Dom.remove(this.reactionsPopup);
				this.reactionsPopup = null;
			}
			else
			{
				if (this.reactionsPopupAnimation)
				{
					this.reactionsPopupAnimation.stop();
				}
				if (this.reactionsPopupAnimation2)
				{
					this.reactionsPopupAnimation2.stop();
				}

				this.reactionsPopup.classList.add('feed-post-emoji-popup-invisible');

				this.reactionsPopupAnimation4 = new BX.easing({
					duration: 500,
					start: {
						opacity: this.reactionsPopupOpacityState,
					},
					finish: {
						opacity: 0,
					},
					transition: BX.easing.transitions.linear,
					step: (state) => {
						this.reactionsPopup.style.opacity = state.opacity / 100;
						this.reactionsPopupOpacityState = state.opacity;
					},
					complete: () => {
						this.reactionsPopup.style.opacity = '';
						this.reactionsPopup.classList.add('feed-post-emoji-popup-invisible-final');
						this.reactionsPopup.classList.remove('feed-post-emoji-popup-active');
						this.reactionsPopup.classList.remove('feed-post-emoji-popup-active-final');
						this.reactionsPopup.classList.remove('feed-post-emoji-popup-active-final-item');
						Dom.remove(this.reactionsPopup);
						this.reactionsPopup = null;
					},
				});

				this.reactionsPopupAnimation4.animate();
			}

			this.reactionsPopupLikeId = null;

			if (likeId)
			{
				RatingLike.getInstance(likeId).box.classList.remove('feed-post-emoji-control-active');
			}
		}

		this.reactionsPopupMobileRemoveHover(this.currentReactionNodeHover);

		if (likeId)
		{
			this.bindReactionsPopup({
				likeId: likeId,
			});
		}
	}

	static reactionsPopupMobileCheckTouchMove()
	{
		if (this.touchStartPosition === null)
		{
			return true;
		}
		else
		{
			if (
				Math.abs(this.touchCurrentPosition.x - this.touchStartPosition.x) > 5
				|| Math.abs(this.touchCurrentPosition.y - this.touchStartPosition.y) > 5
			)
			{
				return false;
			}
		}

		return true;
	}

	static reactionsPopupMobileHide(e)
	{
		window.removeEventListener('touchend', this.reactionsPopupMobileHideHandler);
		if (this.reactionsPopupLikeId)
		{
			this.hideReactionsPopup({
				likeId: this.reactionsPopupLikeId,
			});

			if (e)
			{
				e.preventDefault();
			}
		}
	}

	static reactionsPopupMobileGetHoverNode(x, y)
	{
		const nodeAboveFinger = document.elementFromPoint(x, (y + this.touchMoveDeltaY - this.touchScrollTop));
		const nodeBelowFinger = document.elementFromPoint(x, (y - this.touchScrollTop));

		const iconNodeAboveFinger = nodeAboveFinger?.closest('[data-reaction]');
		const iconNodeBelowFinger = nodeBelowFinger?.closest('[data-reaction]');

		const reactionNode = iconNodeAboveFinger || iconNodeBelowFinger;

		const userReaction = reactionNode?.getAttribute('data-reaction');

		return Type.isStringFilled(userReaction) ? reactionNode : null;
	}

	static reactionsPopupMobileAddHover(reactionNode)
	{
		if (!reactionNode)
		{
			return;
		}

		reactionNode.classList.add('feed-post-emoji-icon-item-hover');
	}

	static reactionsPopupMobileRemoveHover(reactionNode)
	{
		if (!reactionNode)
		{
			return;
		}

		reactionNode.classList.remove('feed-post-emoji-icon-item-hover');
	}

	static reactionsPopupMobileEnableScroll()
	{
		document.removeEventListener('touchmove', this.touchMoveScrollListener, { passive: false });
		EventEmitter.emit('onPullDownEnable');

		if (this.mobileOverlay !== null)
		{
			Dom.clean(this.mobileOverlay);
			Dom.remove(this.mobileOverlay);

			this.mobileOverlay = null;
		}
	}

	static reactionsPopupMobileDisableScroll()
	{
		document.addEventListener('touchmove', this.touchMoveScrollListener, { passive: false });
		if (app)
		{
			app.exec('disableTabScrolling');
		}
		EventEmitter.emit('onPullDownDisable');

		if (!Type.isNull(this.mobileOverlay))
		{
			return;
		}

		this.mobileOverlay = Dom.create('DIV', {
			props: {
				className: 'feed-post-emoji-popup-mobile-overlay',
			},
		});
		setTimeout(() => {
			if (Type.isNull(this.mobileOverlay))
			{
				return
			}

			Dom.append(this.mobileOverlay, document.body);
		}, 1000); // to avoid blink
	}

	static bindReactionsPopup(params) {

		if (RatingManager.mobile)
		{
			return false;
		}

		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');

		if (!Type.isStringFilled(likeId))
		{
			return false;
		}

		const likeInstance = RatingLike.getInstance(likeId);
		if (!likeInstance)
		{
			return false;
		}

		likeInstance.mouseOverHandler = Runtime.debounce(this.getMouseOverHandler(likeId), 500);

		likeInstance.box.addEventListener('mouseenter', likeInstance.mouseOverHandler);
		likeInstance.box.addEventListener('mouseleave', this.blockReactionsPopup);
	}

	static touchMoveScrollListener(e)
	{
		e.preventDefault();
	}

	static getReactionsPopupMouseOutHandler(likeId)
	{
		return (e) => {

			if (!this.reactionsPopup)
			{
				document.removeEventListener('mousemove', this.reactionsPopupMouseOutHandler)
				this.reactionsPopupMouseOutHandler = null;
				return;
			}

			const popupPosition = this.reactionsPopup.getBoundingClientRect();
			const inverted = this.reactionsPopup.classList.contains('feed-post-emoji-popup-inverted');

			if (
				e.clientX >= popupPosition.left
				&& e.clientX <= popupPosition.right
				&& e.clientY >= popupPosition.top - (inverted ? 25 : 0)
				&& e.clientY <= (popupPosition.bottom + (inverted ? 0 : 25))
			)
			{
				return;
			}

			this.blockReactionsPopup();
			this.hideReactionsPopup({
				likeId: likeId
			});

			document.removeEventListener('mousemove', this.reactionsPopupMouseOutHandler)
			this.reactionsPopupMouseOutHandler = null;
		};
	}

	static getMouseOverHandler(likeId)
	{
		return () => {

			const likeInstance = RatingLike.getInstance(likeId);

			if (
				this.reactionsPopup
				&& !this.reactionsPopup?.classList.contains('feed-post-emoji-popup-invisible')
				&& !(
					RatingManager.mobile
					&& this.reactionsPopup?.classList.contains('feed-post-emoji-popup-invisible-final-mobile')
				)
			)
			{
				return;
			}

			if (!this.afterClickBlockShowPopup)
			{
				if (this.blockShowPopup)
				{
					return;
				}

				if (RatingManager.mobile)
				{
					app.exec('callVibration');
				}

				this.showReactionsPopup({
					bindElement: likeInstance.box,
					likeId: likeId,
					onComplete: () => {
						likeInstance.box.removeEventListener('mouseenter', likeInstance.mouseOverHandler);
						likeInstance.box.removeEventListener('mouseleave', this.blockReactionsPopup.bind(this));
					},
				});
			}
		};
	}

	static buildPopupContent(params)
	{
		const clear = (params.clear ? Boolean(params.clear) : false);
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');
		const rating = params.rating;
		const requestReaction = (Type.isStringFilled(params.reaction) ? params.reaction : '');
		const page = (Number(params.page) > 0 ? Number(params.page) : 1);
		const data = params.data;
		const reaction = false;

		const reactionsList = [];
		let reactionsCount = 0;

		if (
			clear
			&& page === 1
		)
		{
			this.clearPopupContent({
				likeId: likeId,
			});
		}

		this.popupCurrentReaction = (Type.isStringFilled(requestReaction) ? requestReaction : 'all');

		if (
			requestReaction.length <= 0
			|| requestReaction == 'all'
		) // first current tab
		{
			this.popupSizeInitialized = false;
			document.getElementById(`bx-ilike-popup-cont-${likeId}`).style.height = 'auto';
			document.getElementById(`bx-ilike-popup-cont-${likeId}`).style.minWidth = 'auto';
		}

		if (!Type.isStringFilled(requestReaction))
		{
			this.popupPagesList = {};
		}

		this.popupPagesList[(requestReaction == '' ? 'all' : requestReaction)] = (page + 1);

		if (Type.isPlainObject(data.reactions))
		{
			Object.entries(data.reactions).forEach(([ reaction, count ]) => {
				if (Number(count) <= 0)
				{
					return;
				}

				reactionsList.push({
					reaction: reaction,
					count: Number(count)
				});
				reactionsCount++;
			});
		}

		const tabsNode = Dom.create('span', {
			props: {
				className: 'bx-ilike-popup-head',
			},
		});

		if (reactionsCount > 1)
		{
			const headClassList = [ 'bx-ilike-popup-head-item' ];
			if (!Type.isStringFilled(requestReaction) || requestReaction == 'all')
			{
				headClassList.push('bx-ilike-popup-head-item-current');
			}

			tabsNode.appendChild(Dom.create('span', {
				props: {
					className: headClassList.join(' '),
				},
				children: [
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-head-icon feed-post-emoji-icon-all',
						},
					}),
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-head-text',
						},
						html: Loc.getMessage('RATING_LIKE_POPUP_ALL').replace('#CNT#', Number(data.items_all)),
					})
				],
				events: {
					click: ((e) => {
						this.changePopupTab({
							likeId: likeId,
							rating: rating,
							reaction: 'all',
						});
						e. preventDefault();
					}),
				},
			}));
		}

		if (reactionsCount === 0)
		{
			reactionsList.push({
				reaction: Loc.getMessage('RATING_LIKE_REACTION_DEFAULT'),
				count: Number(data.items_all),
			});
		}

		reactionsList.sort((a, b) => {
			const sample = {
				like: 0,
				kiss: 1,
				laugh: 2,
				wonder: 3,
				cry: 4,
				angry: 5,
				facepalm: 6,
			};
			if (sample[a.reaction] < sample[b.reaction])
			{
				return -1;
			}
			if (sample[a.reaction] > sample[b.reaction])
			{
				return 1;
			}
			return 0;
		});

		reactionsList.forEach((reactionData) => {

			const headItemClassList = [ 'bx-ilike-popup-head-item' ];
			if (requestReaction === reactionData.reaction)
			{
				headItemClassList.push('bx-ilike-popup-head-item-current');
			}

			tabsNode.appendChild(Dom.create('span', {
				props: {
					className: headItemClassList.join(' '),
				},
				attrs: {
					title: Loc.getMessage(`RATING_LIKE_EMOTION_${reactionData.reaction.toUpperCase()}_CALC`),
				},
				children: [
					Dom.create('span', {
						props: {
							className: [
								'bx-ilike-popup-head-icon',
								'feed-post-emoji-icon-item',
								`feed-post-emoji-icon-${reactionData.reaction}`,
							].join(' '),
						}
					}),
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-head-text',
						},
						html: reactionData.count,
					})
				],
				events: {
					click: (e) => {

						const popupContent = document.getElementById(`bx-ilike-popup-cont-${likeId}`);
						const popupContentPosition = popupContent.getBoundingClientRect();

						if (
							requestReaction.length <= 0
							|| requestReaction === 'all'
						) // first current tab
						{
							this.popupSizeInitialized = true;
							popupContent.style.height = `${popupContentPosition.height}px`;
							popupContent.style.minWidth = `${popupContentPosition.width}px`;
						}
						else
						{
							if (popupContentPosition.width > Number(popupContent.style.minWidth))
							{
								popupContent.style.minWidth = `${popupContentPosition.width}px`;
							}
						}

						this.changePopupTab({
							likeId: likeId,
							rating: rating,
							reaction: reactionData.reaction,
						});
						e. preventDefault();
					},
				},
			}));
		});

		let usersNode = rating.popupContent.querySelector('.bx-ilike-popup-content-container');
		let usersNodeExists = false;

		if (!usersNode)
		{
			usersNode = Dom.create('span', {
				props: {
					className: 'bx-ilike-popup-content-container',
				}
			});
		}
		else
		{
			usersNodeExists = true;
		}

		usersNode.querySelectorAll('.bx-ilike-popup-content').forEach((contentNode) => {
			contentNode.classList.add('bx-ilike-popup-content-invisible');
		});

		let reactionUsersNode = usersNode.querySelector(`.bx-ilike-popup-content-${this.popupCurrentReaction}`);
		if (!reactionUsersNode)
		{
			reactionUsersNode = Dom.create('span', {
				props: {
					className: [
						'bx-ilike-popup-content',
						`bx-ilike-popup-content-${this.popupCurrentReaction}`,
					].join(' '),
				}
			});
			usersNode.appendChild(reactionUsersNode);
		}
		else
		{
			reactionUsersNode.classList.remove('bx-ilike-popup-content-invisible');
		}

		data.items.forEach((item) => {

			const userItemClassList = [ 'bx-ilike-popup-user-item' ];
			if (Type.isStringFilled(item.USER_TYPE))
			{
				userItemClassList.push(`bx-ilike-popup-user-item-${item.USER_TYPE}`);
			}

			reactionUsersNode.appendChild(Dom.create('a', {
				props: {
					className: userItemClassList.join(' '),
				},
				attrs: {
					href: item.URL,
					target: '_blank',
				},
				children: [
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-user-icon',
						},
						style: (
							Type.isStringFilled(item.PHOTO_SRC)
								? {
									'background-image': `url("${encodeURI(item.PHOTO_SRC)}")`,
								}
								: {}
						)
					}),
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-user-name'
						},
						html: item.FULL_NAME,
					}),
					Dom.create('span', {
						props: {
							className: 'bx-ilike-popup-user-status',
						},
					}),
				],
			}));
		});


		const waitNode = rating.popupContent.querySelector('.bx-ilike-wait');
		if (waitNode)
		{
			Dom.clean(waitNode);
			Dom.remove(waitNode);
		}
		const tabsNodeOld = rating.popupContent.querySelector('.bx-ilike-popup-head');
		if (tabsNodeOld)
		{
			tabsNodeOld.parentNode.insertBefore(tabsNode, tabsNodeOld);
			tabsNodeOld.parentNode.removeChild(tabsNodeOld);
		}
		else
		{
			rating.popupContent.appendChild(tabsNode);
		}

		if (!usersNodeExists)
		{
			rating.popupContent.appendChild(usersNode);
		}
	}

	static clearPopupContent(params)
	{
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');

		const likeInstance = RatingLike.getInstance(likeId);
		likeInstance.popupContent.innerHTML = '';
		document.getElementById(`bx-ilike-popup-cont-${likeId}`).style.height = 'auto';
		document.getElementById(`bx-ilike-popup-cont-${likeId}`).style.minWidth = 'auto';
		likeInstance.popupContent.appendChild(Dom.create('span', {
			props: {
				className: 'bx-ilike-wait',
			},
		}));
	}

	static changePopupTab(params)
	{
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');
		const rating = params.rating;
		const reaction = (Type.isStringFilled(params.reaction) ? params.reaction : '');

		const contentContainerNode = rating.popupContent.querySelector('.bx-ilike-popup-content-container');
		if (!contentContainerNode)
		{
			return false;
		}

		const reactionUsersNode = contentContainerNode.querySelector('.bx-ilike-popup-content-' + reaction);
		if (reactionUsersNode)
		{
			this.popupCurrentReaction = (Type.isStringFilled(reaction) ? reaction : 'all');

			rating.popupContent.querySelectorAll('.bx-ilike-popup-head-item').forEach((tabNode) => {
				tabNode.classList.remove('bx-ilike-popup-head-item-current');
				const reactionTabNode = tabNode.querySelector(`.feed-post-emoji-icon-${reaction}`);
				if (reactionTabNode)
				{
					tabNode.classList.add('bx-ilike-popup-head-item-current');
				}
			});

			contentContainerNode.querySelectorAll('.bx-ilike-popup-content').forEach((contentNode) => {
				contentNode.classList.add('bx-ilike-popup-content-invisible');
			});
			reactionUsersNode.classList.remove('bx-ilike-popup-content-invisible');
		}
		else
		{
			ListPopup.List(likeId, 1, reaction);
		}
	}

	static buildPopupContentNoReactions(params)
	{
		const page = (Number(params.page) > 0 ? Number(params.page) : 1);
		const likeInstance = (!Type.isUndefined(params.rating) ? params.rating : null);
		const data = params.data;

		if (!likeInstance)
		{
			return false;
		}

		if (page === 1)
		{
			likeInstance.popupContent.innerHTML = '';
			likeInstance.popupContent.appendChild(Dom.create('span', {
				props: {
					className: 'bx-ilike-bottom_scroll',
				}
			}));
		}

		likeInstance.popupContentPage += 1;

		data.items.forEach((item) => {
			let avatarNode = null;

			if (Type.isStringFilled(item.PHOTO_SRC))
			{
				avatarNode = Dom.create('img', {
					attrs: {
						src: encodeURI(item.PHOTO_SRC),
					},
					props: {
						className: 'bx-ilike-popup-avatar-img',
					},
				});
			}
			else
			{
				avatarNode = Dom.create('img', {
					attrs: {
						src: '/bitrix/images/main/blank.gif',
					},
					props: {
						className: 'bx-ilike-popup-avatar-img bx-ilike-popup-avatar-img-default',
					},
				});
			}

			const imgClassList = [
				'bx-ilike-popup-img',
			];
			if (Type.isStringFilled(item.USER_TYPE))
			{
				imgClassList.push(`bx-ilike-popup-img-${item.USER_TYPE}`);
			}

			likeInstance.popupContent.appendChild(
				Dom.create('a', {
					attrs: {
						href: item.URL,
						target: '_blank',
					},
					props: {
						className: imgClassList.join(' '),
					},
					children: [
						Dom.create('span', {
							props: {
								className: 'bx-ilike-popup-avatar-new',
							},
							children: [
								avatarNode,
								Dom.create('span', {
									props: {
										className: 'bx-ilike-popup-avatar-status-icon',
									},
								})
							]
						}),
						Dom.create('span', {
							props: {
								className: 'bx-ilike-popup-name-new',
							},
							html: item.FULL_NAME,
						}),
					],
				})
			);
		});
	}

	static afterClick(params)
	{
		const likeId = (Type.isStringFilled(params.likeId) ? params.likeId : '');

		if (!Type.isStringFilled(likeId))
		{
			return;
		}

		this.afterClickBlockShowPopup = true;

		this.afterClickHandler = this.getAfterClickHandler(likeId);

		RatingLike.getInstance(likeId).box.addEventListener('mouseleave', this.afterClickHandler);
	}

	static getAfterClickHandler(likeId)
	{
		return () => {
			this.afterClickBlockShowPopup = false;

			RatingLike.getInstance(likeId).box.removeEventListener('mouseleave', this.afterClickHandler);
		};
	}

	static resultReactionClick(e)
	{
		const likeId = e.currentTarget.getAttribute('data-like-id');
		let reaction = e.currentTarget.getAttribute('data-reaction');

		if (!Type.isSet(reaction))
		{
			reaction = '';
		}

		ListPopup.onResultClick({
			likeId: likeId,
			event: e,
			reaction: reaction,
		});

		e.stopPropagation();
	}

	static resultReactionMouseEnter(e)
	{
		const likeId = e.currentTarget.getAttribute('data-like-id');
		const reaction = e.currentTarget.getAttribute('data-reaction');

		ListPopup.onResultMouseEnter({
			likeId: likeId,
			event: e,
			reaction: reaction,
		});
	}

	static resultReactionMouseLeave(e)
	{
		const likeId = e.currentTarget.getAttribute('data-like-id');
		const reaction = e.currentTarget.getAttribute('data-reaction');

		ListPopup.onResultMouseLeave({
			likeId: likeId,
			reaction: reaction,
		});
	}

	static openMobileReactionsPage(params)
	{
		BXMobileApp.PageManager.loadPageBlank({
			url: `${Loc.getMessage('SITE_DIR')}mobile/like/result.php`,
			title: Loc.getMessage('RATING_LIKE_RESULTS'),
			backdrop: {
				mediumPositionPercent: 65,
			},
			cache: true,
			data: {
				entityTypeId: params.entityTypeId,
				entityId: params.entityId,
			}
		});
	}

	static onRatingLike(eventData)
	{
		RatingLike.repo.forEach((likeInstance, likeId) => {
			if (
				likeInstance.entityTypeId !== eventData.entityTypeId
				&& Number(likeInstance.entityId) !== Number(eventData.entityId)
			)
			{
				return;
			}

			let voteAction = (Type.isStringFilled(eventData.voteAction) ? eventData.voteAction.toUpperCase() : 'ADD');
			voteAction = (voteAction === 'PLUS' ? 'ADD' : voteAction);

			if (
				Number(eventData.userId) === Number(Loc.getMessage('USER_ID'))
				&& likeInstance.button
			)
			{
				if (voteAction === 'CANCEL')
				{
					likeInstance.button.classList.remove('bx-you-like-button');

				}
				else
				{
					likeInstance.button.classList.add('bx-you-like-button');
				}
			}

			RatingLike.Draw(likeId, {
				TYPE: voteAction,
				USER_ID: eventData.userId,
				ENTITY_TYPE_ID: eventData.entityTypeId,
				ENTITY_ID: eventData.entityId,
				USER_DATA: eventData.userData,
				REACTION: eventData.voteReaction,
				REACTION_OLD: eventData.voteReactionOld,
				TOTAL_POSITIVE_VOTES: eventData.itemsAll,
			});
		});
	}

	static onMobileCommentsGet()
	{
		const ratingEmojiSelectorPopup = document.querySelector('.feed-post-emoji-popup-container');
		if (ratingEmojiSelectorPopup)
		{
			ratingEmojiSelectorPopup.style.top = 0;
			ratingEmojiSelectorPopup.style.left = 0;
			ratingEmojiSelectorPopup.classList.remove('feed-post-emoji-popup-active');
			ratingEmojiSelectorPopup.classList.remove('feed-post-emoji-popup-active-final');
			ratingEmojiSelectorPopup.classList.remove('feed-post-emoji-popup-active-final-item');
			ratingEmojiSelectorPopup.classList.add('feed-post-emoji-popup-invisible-final');
			ratingEmojiSelectorPopup.classList.add('feed-post-emoji-popup-invisible-final-mobile');
		}
	}

	static getNode(node)
	{
		if (Type.isDomNode(node))
		{
			return node;
		}
		else if (Type.isStringFilled(node))
		{
			return document.getElementById(node);
		}
		else
		{
			return null;
		}
	}
}