AnonSec Shell
Server IP : 85.193.89.191  /  Your IP : 18.219.178.243
Web Server : Apache
System : Linux 956367-cx40159.tmweb.ru 3.10.0-1160.105.1.el7.x86_64 #1 SMP Thu Dec 7 15:39:45 UTC 2023 x86_64
User : bitrix ( 600)
PHP Version : 8.1.27
Disable Function : NONE
MySQL : OFF  |  cURL : OFF  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : ON  |  Pkexec : ON
Directory :  /home/bitrix/www/bitrix/js/landing/utils/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ HOME ]     

Current File : /home/bitrix/www/bitrix/js/landing/utils/utils.js
(function() {
	"use strict";

	BX.namespace("BX.Landing");

	/**
	 * Landing utils.
	 */
	BX.Landing.Utils = function() {};

	/**
	 * Shows element
	 * @param {Element|HTMLElement} element
	 * @return {Promise}
	 * @constructor
	 */
	BX.Landing.Utils.Show = function(element)
	{
		return new Promise(function(resolve) {
			if (!!element && !BX.Landing.Utils.isShown(element))
			{
				BX.Landing.Utils.onAnimationEnd(element)
					.then(function(event) {
						element.dataset.isShown = true;
						resolve(event);
					});

				element.hidden = false;
				element.classList.remove("landing-ui-hide");
				element.classList.add("landing-ui-show");
			}
			else
			{
				resolve();
			}
		});
	};


	/**
	 * Checks that element is shown
	 * @param {HTMLElement} element
	 * @return {boolean}
	 */
	BX.Landing.Utils.isShown = function(element)
	{
		return element.dataset.isShown === "true";
	};


	/**
	 * Hides element
	 * @param {HTMLElement} element
	 * @return {Promise}
	 * @constructor
	 */
	BX.Landing.Utils.Hide = function(element)
	{
		return new Promise(function(resolve) {
			if (!!element && BX.Landing.Utils.isShown(element))
			{
				BX.Landing.Utils.onAnimationEnd(element)
					.then(function(event) {
						element.hidden = true;
						element.dataset.isShown = false;
						resolve(event);
					});

				element.classList.remove("landing-ui-show");
				element.classList.add("landing-ui-hide");
			}
			else
			{
				resolve();
			}
		});
	};

	BX.Landing.Utils.isValidElementId = function(id)
	{
		var re = new RegExp('^[A-Za-z]+[\\w\\-\\:\\.]*$');
		return re.test(id)
	};

	BX.Landing.Utils.ignorePromiseDecorator = function(fn)
	{
		var nothing = function() {};

		return function() {
			fn.apply(null, arguments).then(nothing);
		}
	};


	BX.Landing.Utils.appendHTML = function(element, html)
	{
		element.innerHTML = element.innerHTML + html;
	};


	/**
	 * Gets CSS unique selector of element
	 * @param {HTMLElement} element
	 * @return {string}
	 */
	BX.Landing.Utils.getCSSSelector = function(element)
	{
		var names = [];

		while (element.parentNode)
		{
			if (element.id)
			{
				names.unshift('#'+element.id);
				break;
			}
			else
			{
				if (element === element.ownerDocument.documentElement)
				{
					names.unshift(element.tagName.toLowerCase());
				}
				else
				{
					for (var c=1, e=element; e.previousElementSibling; e=e.previousElementSibling, c++)
					{
					}
					names.unshift(element.tagName.toLowerCase()+":nth-child("+c+")");
				}

				element = element.parentNode;
			}
		}
		return names.join(" > ");
	};


	/**
	 * Handles transition end event
	 * @param {HTMLElement|HTMLElement[]} elements
	 */
	BX.Landing.Utils.onTransitionEnd = function(elements)
	{
		elements = BX.type.isArray(elements) ? elements : [elements];

		return Promise.all(elements.map(function(element) {
			return new Promise(function(resolve) {
				element.addEventListener("webkitTransitionEnd", resolve);
				element.addEventListener("transitionend", resolve);
				element.addEventListener("msTransitionEnd", resolve);
				element.addEventListener("oTransitionEnd", resolve);
				return resolve;
			}).then(function(resolver) {
				element.removeEventListener("webkitTransitionEnd", resolver);
				element.removeEventListener("transitionend", resolver);
				element.removeEventListener("msTransitionEnd", resolver);
				element.removeEventListener("oTransitionEnd", resolver);
			})
		}));
	};


	/**
	 * Handles animationend event
	 * @param {Element} element
	 * @param {string} [animationName]
	 * @return {Promise<AnimationEvent>}
	 */
	BX.Landing.Utils.onAnimationEnd = function(element, animationName)
	{
		return new Promise(function(resolve) {
			var onAnimationEnd = function(event)
			{
				if (!animationName || (event.animationName === animationName))
				{
					resolve(event);
					element.removeEventListener("animationend", onAnimationEnd);
					element.removeEventListener("oAnimationEnd", onAnimationEnd);
					element.removeEventListener("webkitAnimationEnd", onAnimationEnd);
				}
			};

			element.addEventListener("animationend", onAnimationEnd);
			element.addEventListener("oAnimationEnd", onAnimationEnd);
			element.addEventListener("webkitAnimationEnd", onAnimationEnd);
		});
	};


	/**
	 * Converts html to Element
	 * @param {string} html
	 * @return {?HTMLElement}
	 */
	BX.Landing.Utils.htmlToElement = function(html)
	{
		return BX.create("div", {html: html}).firstElementChild;
	};


	/**
	 * Converts html to DocumentFragment
	 * @param {string} html
	 * @return {DocumentFragment}
	 */
	BX.Landing.Utils.htmlToFragment = function(html)
	{
		var tmpElement = BX.create("div", {html: html});
		var fragment = document.createDocumentFragment();

		[].slice.call(tmpElement.children).forEach(function(element) {
			fragment.appendChild(element);
		});

		return fragment;
	};


	/**
	 * Freezes object
	 * @param {object} object
	 * @return {object}
	 */
	BX.Landing.Utils.deepFreeze = function(object)
	{
		Object.freeze(object);

		Object.keys(object).forEach(function(prop) {
			if (!!object[prop] && (typeof object[prop] === "object" || typeof object[prop] === "function"))
			{
				BX.Landing.Utils.deepFreeze(object[prop]);
			}
		});

		return object;
	};


	/**
	 * Inserts element with a specified position
	 * @param {HTMLElement} container
	 * @param {HTMLElement} element
	 * @param {int} position
	 * @static
	 */
	BX.Landing.Utils.insert = function(container, element, position)
	{
		if (position === 0)
		{
			BX.prepend(element, container);
		}
		else if (position > 0 && position <= container.children.length-1)
		{
			container.insertBefore(element, container.children[position]);
		}
		else
		{
			container.appendChild(element);
		}
	};

	/**
	 * Contains RegExp's form media services
	 * @type {{
	 * 		youtube: RegExp,
	 * 		vimeo: RegExp,
	 * 		vine: RegExp,
	 * 		instagram: RegExp,
	 * 		googleMapsSearch: RegExp,
	 * 		googleMapsPlace: RegExp
	 * 	}}
	 */
	BX.Landing.Utils.Matchers = {
		youtube: new RegExp("(youtube\\.com|youtu\\.be|youtube\\-nocookie\\.com)\\/((watch\\?(.*&)?v=|v\\/|u\\/|embed\\/?)|(shorts\\/))?(videoseries\\?list=(.*)|[\\w-]{11}|\\?listType=(.*)&list=(.*))(.*)"),
		vimeo: new RegExp("^.+vimeo.com\\/(.*\\/)?([\\d]+)(.*)?"),
		vine: new RegExp("vine.co\\/v\\/([a-zA-Z0-9\\?\\=\\-]+)"),
		instagram: new RegExp("(instagr\\.am|instagram\\.com)\\/p\\/([a-zA-Z0-9_\\-]+)\\/?"),
		rutube: new RegExp("rutube\\.ru\\/video\\/(private\\/)?([a-zA-Z0-9]+)\\/?"),
		vk: new RegExp("vk\\.(com|ru)\\/.*(video|clip)(-?\\d+_\\d+)\\/?"),

		// Examples:
		// https://www.google.com/maps/search/Bitrix24+office/
		// https://www.google.com/maps/search/?api=1&query=Bitrix24+office
		// https://www.google.com/maps/search/?api=1&query=47.5951518,-122.3316393
		googleMapsSearch: new RegExp("(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(maps\\/search\\/)(.*)", "i"),

		// Examples:
		// http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
		// https://www.google.com/maps/@37.7852006,-122.4146355,14.65z
		// https://www.google.com/maps/place/Bitrix24+office/@37.4220041,-122.0833494,17z/data=!4m5!3m4!1s0x0:0x6c296c66619367e0!8m2!3d37.4219998!4d-122.0840572
		googleMapsPlace: new RegExp("(maps\\.)?google\\.([a-z]{2,3}(\\.[a-z]{2})?)\\/(((maps\\/(place\\/(.*)\\/)?\\@(.*),(\\d+.?\\d+?)z))|(\\?ll=))(.*)?", "i"),
		headerTag: new RegExp("^H[1-6]$"),
		russianText: new RegExp("[\u0400-\u04FF]"),
		facebookPages: new RegExp("(?:http:\/\/)?(?:www\.)?facebook\.com\/(?:(?:\w)*#!\/)?(?:pages\/)?(?:[\w\-]*\/)*([\w\-]*)"),
		facebookPosts: new RegExp("^https:\/\/www\.facebook\.com\/(photo(\.php|s)|permalink\.php|media|questions|notes|[^\/]+\/(activity|posts))[\/?].*$"),
		facebookVideos: new RegExp("^(?:(?:https?:)?\/\/)?(?:www\.)?facebook\.com\/[a-z0-9\.]+\/videos\/(?:[a-z0-9\.]+\/)?([0-9]+)\/?(?:\\?.*)?$")
	};


	/**
	 * Gets URL preview object
	 * @param {string} url
	 * @return {Promise<Object, Object>}
	 */
	BX.Landing.Utils.getURLPreview = function(url)
	{
		return BX.Landing.Backend.getInstance()
			.action("Utils::getUrlPreview", {url: url});
	};


	/**
	 * Converts HTML string to HTMLElement
	 * @param {string} html
	 * @return {HTMLElement}
	 * @static
	 */
	BX.Landing.Utils.HTMLToElement = function(html)
	{
		return BX.create("div", {html: html}).firstElementChild;
	};



	/**
	 * Gets all URL params with value
	 * @param {string} url
	 * @return {object.<string, string>}
	 */
	BX.Landing.Utils.getQueryParams = function(url)
	{
		var result = {};

		if (typeof url === "string")
		{
			var queryString = url.split("?")[1];

			if (queryString)
			{
				var vars = queryString.split("&");

				for (var i = 0; i < vars.length; i++)
				{
					var pair = vars[i].split("=");

					if (typeof result[pair[0]] === "undefined")
					{
						result[pair[0]] = decodeURIComponent(pair[1]);
					}
					else if (typeof result[pair[0]] === "string")
					{
						result[pair[0]] = [result[pair[0]], decodeURIComponent(pair[1])];
					}
					else
					{
						result[pair[0]].push(decodeURIComponent(pair[1]));
					}
				}
			}
		}

		return result;
	};


	/**
	 * Escapes html
	 * @param {string} html
	 * @return {string}
	 */
	BX.Landing.Utils.escapeHtml = function(html)
	{
		return BX.util.htmlspecialchars(
			BX.util.htmlspecialcharsback("" + html)
		);
	};


	/**
	 * Escapes text
	 * @param {*} text
	 * @return {string}
	 */
	BX.Landing.Utils.escapeText = function(text)
	{
		var result = text;

		if (typeof text === "number" || typeof text === "boolean")
		{
			result = "" + text;
		}
		else if (!!text && typeof text === "object")
		{
			result = JSON.stringify(text);
		}

		return BX.Landing.Utils.escapeHtml(result);
	};


	/**
	 * Escapes attribute value
	 * @param {*} value
	 * @return {string}
	 */
	BX.Landing.Utils.escapeAttributeValue = function(value)
	{
		if (BX.Landing.Utils.isPlainObject(value) || BX.Landing.Utils.isArray(value))
		{
			value = JSON.stringify(value);
		}

		return BX.util.jsencode("" + value);
	};


	/**
	 * Sets text content to node
	 * @param {HTMLElement} element
	 * @param {string} text
	 * @param {string} classForTextNode
	 */
	BX.Landing.Utils.setTextContent = function(element, text, classForTextNode = '')
	{
		var addClass = BX.Landing.Utils.addClass;
		if (typeof text === "string")
		{
			var firstNode = element.firstChild;
			var textNode = document.createElement('div');

			if (firstNode &&
				firstNode === element.lastChild &&
				firstNode.nodeType === Node.TEXT_NODE)
			{
				firstNode.nodeValue = text;
				if (classForTextNode.length > 0)
				{
					addClass(textNode, classForTextNode);
					textNode.textContent = element.innerText;
					element.innerText = '';
					BX.Dom.append(textNode, element);
				}
				return;
			}
		}

		element.textContent = text;
		if (classForTextNode.length > 0)
		{
			addClass(textNode, classForTextNode);
			textNode.textContent = element.innerText;
			element.innerText = '';
			BX.Dom.append(textNode, element);
		}
	};


	/**
	 * Encodes data attribute value
	 * @param {*} value
	 * @return {string}
	 */
	BX.Landing.Utils.encodeDataValue = function(value)
	{
		if (BX.Landing.Utils.isPlainObject(value) || BX.Landing.Utils.isArray(value))
		{
			value = JSON.stringify(value);
		}
		else
		{
			if (BX.Landing.Utils.isString(value))
			{
				value = BX.Landing.Utils.escapeHtml(value);
			}
		}

		return "" + value;
	};


	/**
	 * Decodes data attribute value
	 * @param {string} value
	 * @return {*}
	 */
	BX.Landing.Utils.decodeDataValue = function(value)
	{
		var result = value;

		try
		{
			result = JSON.parse(value);
		}
		catch(e)
		{
			result = value;
		}

		if (BX.Landing.Utils.isString(result))
		{
			result = BX.util.htmlspecialcharsback(result);
		}

		return result;
	};


	/**
	 * Works with data-attributes.
	 * @param {HTMLElement} element
	 * @param {string|object} [name]
	 * @param {*} [value]
	 * @return {*}
	 */
	BX.Landing.Utils.data = function(element, name, value)
	{
		var decodeDataValue = BX.Landing.Utils.decodeDataValue;
		var encodeDataValue = BX.Landing.Utils.encodeDataValue;
		var isPlainObject = BX.Landing.Utils.isPlainObject;
		var isString = BX.Landing.Utils.isString;
		var dataRegExp = new RegExp("^data-");

		if (!element)
		{
			throw new TypeError("Element is required");
		}

		// Get all data attributes if name not set
		if (!name)
		{
			var result = {};

			[].forEach.call(element.attributes, function(attr) {
				if (dataRegExp.test(attr.name))
				{
					result[attr.name] = decodeDataValue(attr.value);
				}
			});

			return result;
		}

		if (isString(name))
		{
			name = !dataRegExp.test(name) ? "data-" + name : name;

			// Get single value
			if (value === undefined)
			{
				return decodeDataValue(element.getAttribute(name));
			}

			// Remove attribute
			if (value === null)
			{
				return element.removeAttribute(name);
			}

			// Sets single value
			return element.setAttribute(name, encodeDataValue(value));
		}

		if (isPlainObject(name))
		{
			// Sets attributes values from object
			Object.keys(name).forEach(function(attr) {
				BX.Landing.Utils.data(element, attr, name[attr]);
			});
		}
	};


	function getTextNodes(el)
	{
		el = el || document.body;

		var doc = el.ownerDocument || document;
		var walker = doc.createTreeWalker(el, NodeFilter.SHOW_TEXT, null, false);
		var textNodes = [];
		var node;

		while (node = walker.nextNode())
		{
			textNodes.push(node)
		}

		return textNodes
	}

	function rangesIntersect(rangeA, rangeB)
	{
		return rangeA.compareBoundaryPoints(Range.END_TO_START, rangeB) === -1 &&
			rangeA.compareBoundaryPoints(Range.START_TO_END, rangeB) === 1
	}

	function createRangeFromNode(node)
	{
		var range = node.ownerDocument.createRange();

		try {
			range.selectNode(node)
		} catch (e) {
			range.selectNodeContents(node)
		}

		return range
	}

	function rangeIntersectsNode(range, node)
	{
		if (range.intersectsNode)
		{
			return range.intersectsNode(node)
		}
		else
		{
			return rangesIntersect(range, createRangeFromNode(node))
		}
	}

	function getRangeTextNodes(range)
	{
		var container = range.commonAncestorContainer;
		var nodes = getTextNodes(container.parentNode || container);

		return nodes.filter(function (node) {
			return rangeIntersectsNode(range, node) && isNonEmptyTextNode(node);
		})
	}

	function isNonEmptyTextNode(node)
	{
		return node.textContent.length > 0;
	}

	function remove(el)
	{
		if (el.parentNode)
		{
			el.parentNode.removeChild(el);
		}
	}

	function replaceNode(replacementNode, node)
	{
		remove(replacementNode);
		node.parentNode.insertBefore(replacementNode, node);
		remove(node)
	}

	function unwrap(el)
	{
		var range = document.createRange();
		range.selectNodeContents(el);
		replaceNode(range.extractContents(), el);
	}

	function undo(nodes)
	{
		nodes.forEach(function (node) {
			var parent = node.parentNode;
			unwrap(node);
			parent.normalize();
		})
	}

	function createWrapperFunction(wrapperEl, range)
	{
		var startNode = range.startContainer;
		var endNode = range.endContainer;
		var startOffset = range.startOffset;
		var endOffset = range.endOffset;

		return function wrapNode(node)
		{
			var currentRange = document.createRange();
			var currentWrapper = wrapperEl;

			currentRange.selectNodeContents(node);

			if (node === startNode && startNode.nodeType === 3)
			{
				currentRange.setStart(node, startOffset);
				startNode = currentWrapper;
				startOffset = 0;
			}

			if (node === endNode && endNode.nodeType === 3)
			{
				currentRange.setEnd(node, endOffset);
				endNode = currentWrapper;
				endOffset = 1;
			}

			currentRange.surroundContents(currentWrapper);
			return currentWrapper;
		}
	}

	BX.Landing.Utils.wrapSelection = function(wrapperEl, range)
	{
		var nodes;
		var wrapNode;
		var wrapperObj = {};

		if (typeof range === 'undefined')
		{
			range = window.getSelection().getRangeAt(0);
		}

		if (range.isCollapsed)
		{
			return [];
		}

		if (typeof wrapperEl === 'undefined')
		{
			wrapperEl = 'span';
		}

		if (typeof wrapperEl === 'string')
		{
			wrapperEl = document.createElement(wrapperEl);
		}

		wrapNode = createWrapperFunction(wrapperEl, range);

		nodes = getRangeTextNodes(range);
		nodes = nodes.map(wrapNode);

		wrapperObj.nodes = nodes;
		wrapperObj.unwrap = function() {
			if (this.nodes.length)
			{
				undo(this.nodes);
				this.nodes = [];
			}
		};

		return wrapperObj;
	};


	BX.Landing.Utils.createRangeFromNode = createRangeFromNode;


	/**
	 * Creates selection range for node, from start and end points
	 * @param {HTMLElement} el
	 * @param {int} start
	 * @param {int} end
	 * @return {Range}
	 */
	BX.Landing.Utils.createSelectionRange = function(el, start, end)
	{
		var range;

		if (document.createRange && window.getSelection)
		{
			range = document.createRange();
			range.selectNodeContents(el);
			var textNodes = getTextNodes(el);
			var foundStart = false;
			var charCount = 0, endCharCount;

			for (var i = 0, textNode; textNode = textNodes[i++]; )
			{
				endCharCount = charCount + textNode.length;
				if (!foundStart && start >= charCount && (start < endCharCount || (start === endCharCount && i <= textNodes.length)))
				{
					range.setStart(textNode, start - charCount);
					foundStart = true;
				}

				if (foundStart && end <= endCharCount)
				{
					range.setEnd(textNode, end - charCount);
					break;
				}

				charCount = endCharCount;
			}
		}
		else if (document.selection && document.body.createTextRange)
		{
			range = document.body.createTextRange();
			range.moveToElementText(el);
			range.collapse(true);
			range.moveEnd("character", end);
			range.moveStart("character", start);
		}

		return range;
	};


	/**
	 * Sets element styles
	 *
	 * @param {HTMLElement} element
	 * @param {?object} styles - Null removes all styles
	 *
	 * @return {Promise} - Resolves when styles applied
	 */
	BX.Landing.Utils.style = function(element, styles)
	{
		return new Promise(function(resolve) {
			if (styles === null)
			{
				requestAnimationFrame(function() {
					element.style = null;
					resolve();
				});
			}

			if (!!styles && typeof styles === "object")
			{
				requestAnimationFrame(function() {
					Object.keys(styles).forEach(function(style) {
						element.style.setProperty(style, styles[style]);
					});
					resolve();
				});
			}
		});
	};


	/**
	 * Translates element by y axis
	 * @param {HTMLElement} element
	 * @param {Number} translateLength
	 * @return {Promise}
	 */
	BX.Landing.Utils.translateY = function(element, translateLength)
	{
		return BX.Landing.Utils.translate("y", element, translateLength);
	};


	/**
	 * Translates element by x axis
	 * @param {HTMLElement} element
	 * @param {Number} translateLength
	 * @return {Promise}
	 */
	BX.Landing.Utils.translateX = function(element, translateLength)
	{
		return BX.Landing.Utils.translate("x", element, translateLength);
	};


	/**
	 * Translates element by axis
	 * @param {string} axis - x|y
 	 * @param {HTMLElement} element
	 * @param {Number} translateLength
	 * @return {Promise}
	 */
	BX.Landing.Utils.translate = function(axis, element, translateLength)
	{
		void BX.Landing.Utils.style(element, {
			"transition": "transform 200ms ease",
			"transform": "translate"+axis.toUpperCase()+"("+translateLength+"px) translateZ(0)"
		});
		return BX.Landing.Utils.onTransitionEnd(element);
	};


	/**
	 * Inserts element before target element
	 * @param {HTMLElement} element
	 * @param {HTMLElement} targetElement
	 */
	BX.Landing.Utils.insertBefore = function(element, targetElement)
	{
		targetElement.parentElement.insertBefore(element, targetElement);
	};


	/**
	 * Gets bounding client rect of element or range
	 * @param {Element|Range} element
	 * @return {ClientRect | {left, top, width, height}}
	 */
	BX.Landing.Utils.rect = function(element)
	{
		return element.getBoundingClientRect();
	};


	/**
	 * Finds next element sibling
	 * @param {HTMLElement} element
	 * @param {String} [className]
	 * @return {HTMLElement}
	 */
	BX.Landing.Utils.nextSibling = function(element, className)
	{
		return className ? BX.findNextSibling(element, {className: className}) : element.nextElementSibling;
	};


	/**
	 * Finds previous element sibling
	 * @param {HTMLElement} element
	 * @param {String} className
	 * @return {HTMLElement}
	 */
	BX.Landing.Utils.prevSibling = function(element, className)
	{
		return className ? BX.findPreviousSibling(element, {className: className}) : element.previousElementSibling;
	};


	/**
	 * Joins arguments
	 * @return {string}
	 */
	BX.Landing.Utils.join = function()
	{
		return [].slice.call(arguments).join("");
	};


	/**
	 * @param item
	 * @return {*[]}
	 */
	BX.Landing.Utils.slice = function(item)
	{
		return [].slice.call(item);
	};


	/**
	 * Set element attributes
	 * @param {HTMLElement|Element} element
	 * @param {Object.<String, ?String>|String} attrs
	 * @param {?String} [value]
	 * @return {String|void}
	 */
	BX.Landing.Utils.attr = function(element, attrs, value)
	{
		if (BX.Landing.Utils.isString(attrs))
		{
			if (typeof value === "undefined")
			{
				return element.getAttribute(attrs);
			}

			element.setAttribute(attrs, BX.Landing.Utils.encodeDataValue(value));
		}

		if (BX.Landing.Utils.isPlainObject(attrs))
		{
			Object.keys(attrs).forEach(function(key) {
				if (attrs[key] === null)
				{
					element.removeAttribute(key);
				}
				else
				{
					element.setAttribute(key, BX.Landing.Utils.encodeDataValue(attrs[key]));
				}
			});
		}
	};


	/**
	 * Removes all panels from element
	 * @param {HTMLElement} element
	 * @return {?HTMLElement}
	 */
	BX.Landing.Utils.removePanels = function(element)
	{
		[].slice.call(element.querySelectorAll(".landing-ui-panel"))
			.forEach(function(panel) {
				BX.remove(panel);
			});
		return element;
	};


	/**
	 * Gets file extension
	 * @param {string} filename
	 * @return {string}
	 */
	BX.Landing.Utils.getFileExtension = function(filename)
	{
		var name = "fm";
		var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)");
		var results = regex.exec(filename);

		if (!results || !results[2])
		{
			return '';
		}

		return decodeURIComponent(results[2].replace(/\+/g, " "));
	};


	/**
	 * Checks pressed key
	 * @type {{
	 * 		isUp: BX.Landing.Utils.key.isUp,
	 * 		isDown: BX.Landing.Utils.key.isDown,
	 * 		isRight: BX.Landing.Utils.key.isRight,
	 * 		isLeft: BX.Landing.Utils.key.isLeft,
	 * 		isEnter: BX.Landing.Utils.key.isEnter,
	 * 		isEscape: BX.Landing.Utils.key.isEscape
	 * 	}}
	 */
	BX.Landing.Utils.key = {
		isUp: function(event) {
			return event.keyCode === 38;
		},

		isDown: function(event) {
			return event.keyCode === 40;
		},

		isRight: function(event) {
			return event.keyCode === 39;
		},

		isLeft: function(event) {
			return event.keyCode === 37;
		},

		isEnter: function(event) {
			return event.keyCode === 13;
		},

		isEscape: function(event)
		{
			return event.keyCode === 27;
		}
	};


	/**
	 * Extends BX.PopupMenuWindow. Adds menu items filter/search
	 * @param {BX.PopupMenuWindow} menu
	 */
	BX.Landing.Utils.makeFilterablePopupMenu = function(menu)
	{
		var append = BX.Landing.Utils.append;
		var prepend = BX.Landing.Utils.prepend;
		var onCustomEvent = BX.Landing.Utils.onCustomEvent;
		var create = BX.Landing.Utils.create;
		var addClass = BX.Landing.Utils.addClass;


		/**
		 * Checks that menuItems list contains visible item
		 * @param {BX.PopupMenuItem[]} menuItems
		 * @return {boolean}
		 */
		function containsVisibleItems(menuItems)
		{
			return menuItems.some(function(menuItem) {
				return !menuItem.layout.item.hidden;
			});
		}


		/**
		 * Handles filter input event
		 * @param event
		 */
		function onInput(event)
		{
			var search = event.currentTarget.value.toLowerCase();
			menu.menuItems.forEach(function(item) {
				item.layout.item.hidden = !item.text.toLowerCase().includes(search);
			});

			emptyResult.hidden = containsVisibleItems(menu.menuItems);
		}

		var filter = create("div", {props: {className: "landing-ui-popup-filter"}});
		var filterInput = create("input", {
			props: {className: "landing-ui-popup-filter-input"},
			attrs: {placeholder: BX.Landing.Loc.getMessage("LANDING_MENU_ITEM_FILTER")},
			events: {"input": onInput}
		});
		var emptyResult = create("div", {
			props: {className: "landing-ui-popup-filter-empty"},
			children: [create("span", {
				props: {className: "landing-ui-popup-filter-empty-text"},
				html: BX.Landing.Loc.getMessage("LANDING_MENU_ITEM_FILTER_EMPTY")
			})],
			attrs: {hidden: true}
		});

		append(filterInput, filter);
		prepend(filter, menu.popupWindow.contentContainer);
		append(emptyResult, menu.popupWindow.contentContainer);

		addClass(menu.popupWindow.popupContainer, "landing-ui-popup-filterable");

		filterInput.focus();

		onCustomEvent(menu.popupWindow, "onAfterPopupShow", function() {
			requestAnimationFrame(function() {
				filterInput.focus()
			});
		});
	};


	/**
	 * Extends BX.PopupMenuWindow. Makes navigation by arrows keys
	 * @param {BX.PopupMenuWindow} menu
	 */
	BX.Landing.Utils.makeSelectablePopupMenu = function(menu)
	{
		var addClass = BX.Landing.Utils.addClass;
		var removeClass = BX.Landing.Utils.removeClass;
		var hasClass = BX.Landing.Utils.hasClass;
		var bind = BX.Landing.Utils.bind;
		var key = BX.Landing.Utils.key;

		var currentItem = null;
		var currentIndex = -1;

		/**
		 * Selects menu items
		 * @param {BX.PopupMenuItem} menuItem
		 */
		function selectItem(menuItem)
		{
			addClass(menuItem.layout.item, "landing-ui-select");
		}


		/**
		 * Removes selection from menu item
		 * @param {BX.PopupMenuItem} menuItem
		 */
		function unselectMenuItem(menuItem)
		{
			removeClass(menuItem.layout.item, "landing-ui-select");
		}


		/**
		 * Removes selection from all menu items
		 * @param {BX.PopupMenuItem[]} menuItems
		 */
		function unselectItems(menuItems)
		{
			menuItems.forEach(unselectMenuItem);
		}


		/**
		 * Get selected item
		 * @param {BX.PopupMenuItem[]} menuItems
		 */
		function getSelected(menuItems)
		{
			return menuItems.find(function(item) {
				return hasClass(item.layout.item, "landing-ui-select");
			});
		}


		/**
		 * Gets menu item index
		 * @param {BX.PopupMenuItem[]} menuItems
		 * @param {BX.PopupMenuItem} menuItem
		 * @return {number|*}
		 */
		function getItemIndex(menuItems, menuItem)
		{
			return menuItems.findIndex(function(item) {
				return menuItem === item;
			});
		}


		/**
		 * Gets first item
		 * @param {BX.PopupMenuItem[]} menuItems
		 * @return {?BX.PopupMenuItem}
		 */
		function getFirstItem(menuItems)
		{
			return menuItems.find(function(item) {
				return !item.layout.item.hidden;
			});
		}


		/**
		 * Gets net item
		 * @param {BX.PopupMenuItem[]} menuItems
		 * @return {BX.PopupMenuItem}
		 */
		function getNextItem(menuItems)
		{
			if (currentItem)
			{
				currentIndex = getItemIndex(menuItems, currentItem);
			}

			var nextItem = menuItems.find(function(item, index) {
				return index > currentIndex && !item.layout.item.hidden;
			});

			if (nextItem)
			{
				currentItem = nextItem;
				return nextItem;
			}

			nextItem = getFirstItem(menuItems);
			currentItem = nextItem;

			return nextItem;
		}


		/**
		 * Checks that pressed key from allowed list
		 * @param {KeyboardEvent} event
		 * @return {boolean}
		 */
		function isAllowedKeyPress(event)
		{
			var key = BX.Landing.Utils.key;

			return (
				key.isLeft(event) ||
				key.isRight(event) ||
				key.isUp(event) ||
				key.isDown(event) ||
				key.isEnter(event)
			);
		}


		/**
		 * Closes all sub menu
		 * @param {BX.PopupMenuItem[]} menuItems
		 */
		function closeAllSubMenu(menuItems)
		{
			menuItems.forEach(function(item) {
				item.closeSubMenu();

				var subMenu = item.getSubMenu();

				if (subMenu)
				{
					unselectItems(subMenu.menuItems);
				}
			});
		}

		var isRevert = false;

		bind(menu.popupWindow.popupContainer, "keydown", function(event) {
			var currentMenu = menu;
			if (currentItem && currentItem.menuWindow.popupWindow.isShown())
			{
				currentMenu = currentItem.menuWindow;
			}

			if (isAllowedKeyPress(event))
			{
				var selectedItem = getSelected(currentMenu.menuItems);

				if (key.isDown(event) && isRevert && currentMenu === menu)
				{
					isRevert = false;
					currentMenu.menuItems = currentMenu.menuItems.reverse();
				}

				if (key.isUp(event) && !isRevert && currentMenu === menu)
				{
					isRevert = true;
					currentMenu.menuItems = currentMenu.menuItems.reverse();
				}

				if (key.isRight(event))
				{
					if (selectedItem)
					{
						selectedItem.showSubMenu();

						if (selectedItem.hasSubMenu())
						{
							var submenu = selectedItem.getSubMenu();
							unselectItems(submenu.menuItems);
							selectItem(submenu.menuItems[0]);
							currentItem = submenu.menuItems[0];
						}
					}

					return;
				}

				if (key.isLeft(event))
				{
					closeAllSubMenu(menu.menuItems);
					currentItem = getSelected(menu.menuItems);
					return;
				}

				if (key.isEnter(event))
				{
					if (selectedItem)
					{
						BX.fireEvent(selectedItem.layout.item, "click");
						return;
					}
				}

				unselectItems(currentMenu.menuItems);

				var nextItem = getNextItem(currentMenu.menuItems);

				if (nextItem)
				{
					selectItem(nextItem);
					return;
				}
			}

			if (key.isEscape(event))
			{
				currentMenu.close();
			}

			closeAllSubMenu(menu.menuItems);
		});
	};


	BX.Landing.Utils.delay = function(delay, data)
	{
		return new Promise(function(resolve) {
			setTimeout(resolve.bind(null, data), delay);
		});
	};


	/**
	 * Highlights node
	 * @param {HTMLElement} node
	 * @param {?boolean} [useRangeRect = false]
	 * @param {?boolean} [highlightBottom = false]
	 * @return {Promise}
	 */
	BX.Landing.Utils.highlight = function(node, useRangeRect, highlightBottom)
	{
		var rect;

		if (useRangeRect)
		{
			var range = document.createRange();
			range.selectNodeContents(node);
			rect = range.getBoundingClientRect();
		}
		else
		{
			rect = node.getBoundingClientRect();
		}

		if (highlightBottom)
		{
			rect = {
				top: rect.bottom,
				left: rect.left,
				right: rect.right,
				bottom: rect.bottom+1,
				height: 20,
				width: rect.width
			};
		}

		return BX.Landing.History.Highlight.getInstance().show(node, rect);
	};



	/**
	 * Scrolls to node
	 * @param {HTMLElement} node
	 * @return {Promise}
	 */
	BX.Landing.Utils.scrollTo = function(node)
	{
		return BX.Landing.PageObject.getInstance().view().then(function(iframe) {
			return BX.Landing.UI.Panel.Content.scrollTo(iframe, node)
				.then(function() {
					return new Promise(function(resolve) {
						setTimeout(resolve, 50);
					})
				})
		});
	};


	/**
	 * @todo refactoring
	 * @param element
	 * @param offsetParent
	 * @return {number}
	 */
	BX.Landing.Utils.offsetTop = function(element, offsetParent)
	{
		var elementRect = element.getBoundingClientRect();
		var parentRect = offsetParent.getBoundingClientRect();
		var scrollTop = offsetParent.scrollTop;
		var borderTopWidth = parseInt(BX.style(offsetParent, "border-top-width"));
		borderTopWidth = borderTopWidth === borderTopWidth ? borderTopWidth : 0;

		return (elementRect.top + scrollTop) - parentRect.top - borderTopWidth;
	};


	/**
	 * @todo refactoring
	 * @param element
	 * @param offsetParent
	 * @return {number}
	 */
	BX.Landing.Utils.offsetLeft = function(element, offsetParent)
	{
		var elementRect = element.getBoundingClientRect();
		var parentRect = offsetParent.getBoundingClientRect();
		var scrollLeft = offsetParent.scrollLeft;

		return (elementRect.left + scrollLeft) - parentRect.left;
	};


	/**
	 * Checks that value is array-like object
	 * @param value
	 * @return {boolean}
	 */
	BX.Landing.Utils.isArrayLike = function(value)
	{
		var isBoolean = BX.Landing.Utils.isBoolean;
		var isNumber = BX.Landing.Utils.isNumber;
		var isFunction = BX.Landing.Utils.isFunction;

		return (
			value !== null &&
			!isFunction(value) &&
			!isBoolean(value) &&
			!isNumber(value) &&
			value.length > 0 &&
			value.length <= Number.MAX_SAFE_INTEGER
		);
	};


	/**
	 * Check that value is arguments
	 * @param value
	 * @return {boolean}
	 */
	BX.Landing.Utils.isArguments = function(value)
	{
		var isArrayLike = BX.Landing.Utils.isArrayLike;
		return isArrayLike(value) && value.toString() === "[object Arguments]";
	};


	/**
	 * Checks that value is empty
	 * @param value
	 * @return {boolean}
	 */
	BX.Landing.Utils.isEmpty = function(value)
	{
		var isArrayLike = BX.Landing.Utils.isArrayLike;

		if (value == null)
		{
			return true;
		}

		if (isArrayLike(value))
		{
			return !value.length;
		}

		for (var key in value)
		{
			if (value.hasOwnProperty(key))
			{
				return false;
			}
		}

		return true;
	};


	/**
	 * Gets random integer
	 * @param {int} min
	 * @param {int} max
	 * @return {int}
	 */
	BX.Landing.Utils.randomInt = function(min, max)
	{
		max += 1;
		return Math.floor(Math.random() * (max - min)) + min;
	};


	/**
	 * Produces an array that contains every
	 * item shared between all the passed-in arrays.
	 * @param {...}
	 * @return {*[]}
	 */
	BX.Landing.Utils.intersection = function()
	{
		var slice = BX.Landing.Utils.slice;

		return slice(arguments).reduce(function(previous, current){
			return previous.filter(function(element){
				return current.includes(element);
			});
		});
	};


	/**
	 * Takes the difference between one array
	 * and a number of other arrays.
	 * @param {...}
	 * @return {*[]}
	 */
	BX.Landing.Utils.difference = function()
	{
		var slice = BX.Landing.Utils.slice;

		return slice(arguments).reduce(function(previous, current){
			return previous.filter(function(element){
				return !current.includes(element);
			});
		});
	};


	BX.Landing.Utils.changeTagName = function(element, tagName)
	{
		if (!element || !tagName)
		{
			return null;
		}

		var slice = BX.Landing.Utils.slice;
		var create = BX.Landing.Utils.create;
		var attributes = slice(element.attributes);
		var newElement = create(tagName);
		var innerHTML = element.innerHTML;

		attributes.forEach(function(attribute) {
			newElement.setAttribute(attribute.nodeName, attribute.nodeValue);
		});

		newElement.innerHTML = innerHTML;

		element.parentElement.replaceChild(newElement, element);

		return newElement;
	};


	/**
	 * Creates hash from array like objects
	 * @param value
	 * @return {string}
	 */
	BX.Landing.Utils.hash = function(value)
	{
		if (BX.Landing.Utils.isArray(value) || BX.Landing.Utils.isPlainObject(value))
		{
			value = JSON.stringify(BX.Landing.Utils.sortObject(value));
		}

		return "" + BX.util.hashCode(value);
	};


	/**
	 * Sort object by keys
	 * @param unordered
	 * @return {{}}
	 */
	BX.Landing.Utils.sortObject = function(unordered)
	{
		return Object.keys(unordered).sort().reduce(function(ordered, key) {
			return ordered[key] = unordered[key], ordered;
		}, {});
	};


	/**
	 * Capitalizes string
	 * @param {string} str
	 * @return {string}
	 */
	BX.Landing.Utils.capitalize = function(str)
	{
		return str.charAt(0).toUpperCase() + str.slice(1);
	};

	BX.Landing.Utils.textToPlaceholders = function(str)
	{
		var matcher = new RegExp("<span[^>]*data-placeholder=\"(\\w+)\"[^>]*>(.+?)<\\/span>", 'gm');
		var segments = matcher.exec(str);

		if (segments)
		{
			return str.replace(matcher, "{{"+segments[1]+"}}");
		}

		return str;
	};

	/**
	 * Changes file path extension
	 * @param {string} path
	 * @param {string} newExtension
	 * @return {*}
	 */
	BX.Landing.Utils.changeExtension = function(path, newExtension)
	{
		return !!path ? path.replace(/\.[^\.]+$/, "." + newExtension) : path;
	};

	/**
	 * @param path
	 * @return {*}
	 */
	BX.Landing.Utils.rename2x = function(path)
	{
		path = path.replace(/@2x/, "");
		let extension = BX.util.getExtension(path);
		if (extension.length > 4)
		{
			extension = extension.split('_').pop();
		}

		return !!path ? path.replace(/\.[^\.]+$/, "@2x." + extension) : path;
	};

	/**
	 * Gets delta from event
	 * @param event
	 * @return {{x, y: number}}
	 */
	BX.Landing.Utils.getDeltaFromEvent = function(event)
	{
		var deltaX = event.deltaX;
		var deltaY = -1 * event.deltaY;

		if (typeof deltaX === "undefined" || typeof deltaY === "undefined")
		{
			deltaX = -1 * event.wheelDeltaX / 6;
			deltaY = event.wheelDeltaY / 6;
		}

		if (event.deltaMode && event.deltaMode === 1)
		{
			deltaX *= 10;
			deltaY *= 10;
		}

		if (event.deltaMode && event.deltaMode === 1)
		{
			deltaX *= 10;
			deltaY *= 10;
		}

		/** NaN checks */
		if (deltaX !== deltaX && deltaY !== deltaY)
		{
			deltaX = 0;
			deltaY = event.wheelDelta;
		}

		return {x: deltaX, y: deltaY};
	};

	/**
	 * Loads file as blob
	 * @param url
	 * @return {Promise<Blob, string>}
	 */
	BX.Landing.Utils.urlToBlob = function(url)
	{
		if (!BX.type.isString(url))
		{
			return Promise.resolve(url);
		}

		return new Promise(function(resolve, reject) {
			try {
				var xhr = BX.ajax.xhr();
				xhr.open("GET", url);
				xhr.responseType = "blob";
				xhr.onerror = function()
				{
					reject("Network error.")
				};
				xhr.onload = function()
				{
					if (xhr.status === 200)
					{
						resolve(xhr.response);
					}
					else
					{
						reject("Loading error:" + xhr.statusText);
					}
				};
				xhr.send();
			}
			catch(err)
			{
				reject(err.message);
			}
		});
	};

	BX.Landing.Utils.getFileName = function(path)
	{
		return path.split('\\').pop().split('/').pop();
	};

	BX.Landing.Utils.getSelectedElement = function(contextDocument)
	{
		const currentDocument =
			(typeof contextDocument !== 'undefined' && contextDocument.nodeType === Node.DOCUMENT_NODE)
				? contextDocument
				: document
		;

		let range;
		let sel;
		let container;
		if (currentDocument.selection)
		{
			range = currentDocument.selection.createRange();
			return range.parentElement();
		}
		else
		{
			sel = currentDocument.defaultView.getSelection();
			if (sel.getRangeAt)
			{
				if (sel.rangeCount > 0)
				{
					range = sel.getRangeAt(0);
				}
			}
			else
			{
				// Old WebKit
				range = currentDocument.createRange();
				range.setStart(sel.anchorNode, sel.anchorOffset);
				range.setEnd(sel.focusNode, sel.focusOffset);

				if (range.collapsed !== sel.isCollapsed) {
					range.setStart(sel.focusNode, sel.focusOffset);
					range.setEnd(sel.anchorNode, sel.anchorOffset);
				}
			}

			if (range)
			{
				container = range["endContainer"];

				return container.nodeType === 3 ? container.parentNode : container;
			}
		}
	};

	/**
	 * Fires custom event
	 * @param {Object} [target = window]
	 * @param {string} eventName
	 * @param {*[]} [params]
	 */
	BX.Landing.Utils.fireCustomEvent = function(target, eventName, params)
	{
		try
		{
			BX.onCustomEvent(target, eventName, params);
		}
		catch (err)
		{
			console.error(eventName, err);
		}
	};

	BX.Landing.Utils.onCustomEvent = BX.addCustomEvent;
	BX.Landing.Utils.removeCustomEvent = BX.removeCustomEvent;


	BX.Landing.Utils.insertAfter = BX.insertAfter;
	BX.Landing.Utils.isPlainObject = BX.type.isPlainObject;
	BX.Landing.Utils.append = BX.append;
	BX.Landing.Utils.prepend = BX.prepend;
	BX.Landing.Utils.isBoolean = BX.type.isBoolean;
	BX.Landing.Utils.isNumber = BX.type.isNumber;
	BX.Landing.Utils.isString = BX.type.isString;
	BX.Landing.Utils.isArray = BX.type.isArray;
	BX.Landing.Utils.isFunction = BX.type.isFunction;
	BX.Landing.Utils.addClass = BX.addClass;
	BX.Landing.Utils.removeClass = BX.removeClass;
	BX.Landing.Utils.toggleClass = BX.toggleClass;
	BX.Landing.Utils.hasClass = BX.hasClass;
	BX.Landing.Utils.debounce = BX.debounce;
	BX.Landing.Utils.throttle = BX.throttle;
	BX.Landing.Utils.bind = BX.bind;
	BX.Landing.Utils.unbind = BX.unbind;
	BX.Landing.Utils.getClass = BX.getClass;
	BX.Landing.Utils.pos = BX.pos;
	BX.Landing.Utils.assign = Object.assign || BX.util.objectMerge;
	BX.Landing.Utils.clone = BX.clone;
	BX.Landing.Utils.create = BX.create;
	BX.Landing.Utils.remove = BX.remove;
	BX.Landing.Utils.trim = BX.util.trim;
	BX.Landing.Utils.random = BX.util.getRandomString;
	BX.Landing.Utils.findParent = BX.findParent;
	BX.Landing.Utils.proxy = BX.proxy;
	BX.Landing.Utils.arrayUnique = BX.util.array_unique;
	BX.Landing.Utils.keys = Object.keys;
	BX.Landing.Utils.fireEvent = BX.fireEvent;
	BX.Landing.Utils.addQueryParams = BX.util.add_url_param.bind(BX.util);
})();

Anon7 - 2022
AnonSec Team