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/ui/viewer/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/js/ui/viewer/ui.viewer.js
;(function () {

	'use strict';

	BX.namespace('BX.UI.Viewer');

	BX.UI.Viewer.Controller = function(options)
	{
		/**
		 * @type {BX.UI.Viewer.Item[]}
		 */
		this.items = null;
		this.currentIndex = null;
		this.handlers = {
			handleCarouselItemError: this.handleCarouselItemError.bind(this),
		};

		this.baseContainer = options.baseContainer || document.body;

		this.setItems(options.items || []);

		this.isBodyPaddingAdded = null;
		this.cycleMode = options.hasOwnProperty('cycleMode') ? options.cycleMode : true;
		this.stretch = options.hasOwnProperty('stretch') ? options.stretch : false;
		this.cachedData = {};
		this.optionsByGroup = {};
		this.layout = {
			container: null,
			content: null,
			inner: null,
			title: null,
			itemContainer: null,
			next: null,
			prev: null,
			close: null,
			downloadBtn: null,
			moreBtn: null,
			error: null,
			loader: null,
			loaderContainer: null,
			loaderText: null,
			defaultActions: null,
			extraActions: null,
			carouselItems: null,
			carouselContainer: null,
			carouselScrollable: null,
		};

		// Compatibility for BX.Disk.Viewer.Actions.runActionEdit
		this.actionPanel = {
			getItemById: () => {},
		};

		this.maxParallelLoads = 3;
		this.loadingItems = new Set();
		this.moreMenu = null;

		this.eventsAlreadyBinded = false;

		this.init();
	};

	BX.UI.Viewer.Controller.prototype = {
		/**
		 * @param {HTMLElement} node
		 * @return {BX.Promise}
		 */
		buildItemListByNode: function (node)
		{
			var promise = new BX.Promise();
			var nodes = [];

			if (this.isSeparateItem(node))
			{
				nodes = [node];
			}
			else if(node.dataset.viewerGroupBy)
			{
				nodes = [].slice.call(node.ownerDocument.querySelectorAll("[data-viewer][data-viewer-group-by='" + node.dataset.viewerGroupBy + "']"));
			}
			else
			{
				nodes = [node];
			}

			this.loadExtensions(this.collectExtensionsForItems(nodes)).then(function (){
				var items = nodes.map(function(node) {
					return BX.UI.Viewer.buildItemByNode(node);
				});

				promise.fulfill(items);
			}.bind(this));

			return promise;
		},

		/**
		 * @param {HTMLElement} node
		 * @return {boolean}
		 */
		isSeparateItem: function (node)
		{
			return node.dataset.viewerSeparateItem;
		},

		shouldProcessSeparateMode: function (items)
		{
			return items.length === 1 && items[0].isSeparateItem();
		},

		shouldRunViewer: function (node)
		{
			if (!BX.type.isDomNode(node) || !node.dataset)
			{
				return false;
			}

			if (!node.dataset.hasOwnProperty('viewer'))
			{
				return false;
			}

			return true;
		},

		/**
		 *
		 * @param {HTMLElement[]} nodes
		 * @return {Array}
		 */
		collectExtensionsForItems: function (nodes)
		{
			var extensionSet = new Set();
			nodes.forEach(function (node) {
				if (BX.type.isString(node.dataset.viewerExtension))
				{
					extensionSet.add(node.dataset.viewerExtension);
				}
			});

			var extensions = [];
			extensionSet.forEach(function (ext) {
				if (shouldLoadExtensions(ext))
				{
					extensions.push(ext);
				}
			});

			return extensions;
		},

		/**
		 * @param {MouseEvent} event
		 * @return {HTMLElement|null}
		 */
		extractTargetFromEvent: function (event)
		{
			var target = BX.getEventTarget(event);

			var shouldRunViewer = false;
			var maxDepth = 8;
			do
			{
				if (this.shouldRunViewer(target))
				{
					shouldRunViewer = true;
					break;
				}

				target = target.parentNode;
				maxDepth--;
			}
			while (maxDepth > 0 && target);

			return shouldRunViewer? target : null;
		},

		handleDocumentClick: function (event)
		{
			var target = this.extractTargetFromEvent(event);
			if (!target)
			{
				return;
			}

			if (target.tagName !== 'A' && target.closest('a[target="_blank"]'))
			{
				return false;
			}

			event.preventDefault();
			this.buildItemListByNode(target).then(function(items){
				if (items.length === 0)
				{
					return;
				}

				if (this.shouldProcessSeparateMode(items))
				{
					this.setItems(items).then(function(){
						this.openSeparate(0);
					}.bind(this));

					return;
				}

				// shortcut for download
				if ((BX.browser.IsMac() && event.metaKey) || event.ctrlKey)
				{
					this.runActionByNode(target, 'download');
				}
				else
				{
					this.setItems(items).then(function(){
						this.open(this.getIndexByNode(target));
					}.bind(this));
				}
			}.bind(this));
		},

		bindEvents: function ()
		{
			if (this.eventsAlreadyBinded)
			{
				return;
			}

			this.eventsAlreadyBinded = true;

			this.handlers.keyPress = this.handleKeyPress.bind(this);
			this.handlers.touchStart = this.handleTouchStart.bind(this);
			this.handlers.touchEnd = this.handleTouchEnd.bind(this);
			this.handlers.resize = this.handleWindowResize.bind(this);
			this.handlers.showNext = this.showNext.bind(this);
			this.handlers.showPrev = this.showPrev.bind(this);
			this.handlers.close = this.close.bind(this);
			this.handlers.handleClickOnItemContainer = this.handleClickOnItemContainer.bind(this);
			this.handlers.handleSliderCloseByEsc = this.handleSliderCloseByEsc.bind(this);

			BX.bind(document, 'keydown', this.handlers.keyPress);
			BX.bind(window, 'resize', this.handlers.resize);
			BX.bind(this.getItemContainer(), 'touchstart', this.handlers.touchStart);
			BX.bind(this.getItemContainer(), 'touchend', this.handlers.touchEnd);

			BX.bind(this.getItemContainer(), 'click', this.handlers.handleClickOnItemContainer);
			BX.bind(this.getNextButton(), 'click', this.handlers.showNext);
			BX.bind(this.getPrevButton(), 'click', this.handlers.showPrev);
			BX.bind(this.getCloseButton(), 'click', this.handlers.close);

			BX.addCustomEvent('SidePanel.Slider:onCloseByEsc', this.handlers.handleSliderCloseByEsc);
		},

		handleVisibleControls: function(ev)
		{
			if (BX.browser.IsMobile() || BX.hasClass(document.documentElement, 'bx-touch'))
			{
				return;
			}

			if (this._timerIdReadingMode)
			{
				clearTimeout(this._timerIdReadingMode);
			}

			if (!this.cursorInPerimeter(ev) || BX.findParent(ev.target, {className: 'ui-viewer-next'}) || BX.findParent(ev.target, {className: 'ui-viewer-prev'}))
			{
				this.disableReadingMode();
			}
			else
			{
				this._timerIdReadingMode = setTimeout(function () {
					this.enableReadingMode();
				}.bind(this), 2800);
			}
		},

		handleMoreBtnClick()
		{
			if (this.moreMenu === null)
			{
				const item = this.getCurrentItem();

				const menuItems = [
					...item.getMoreMenuItems(),
					...this.createMoreMenuItems(item),
				];

				if (menuItems.length === 0)
				{
					return;
				}

				this.moreMenu = new BX.Main.Menu({
					angle: true,
					minWidth: 150,
					bindElement: this.getMoreButton(),
					offsetLeft: 30,
					offsetTop: -20,
					items: menuItems,
					cacheable: false,
					events: {
						onDestroy: () => {
							this.moreMenu = null;
						},
					},
				});
			}

			this.moreMenu.show();
		},

		enableReadingMode: function(withTimer)
		{
			if (BX.browser.IsMobile() || !this.isOnTop())
			{
				return;
			}

			if(withTimer)
			{
				this._timerIdReadingMode = setTimeout(function()
				{
					this.layout.container.classList.add('ui-viewer-reading-mode');
				}.bind(this), 5000);

				return;
			}

			this.layout.container.classList.add('ui-viewer-reading-mode');
		},

		disableReadingMode: function()
		{
			if(this._timerIdReadingMode)
			{
				clearTimeout(this._timerIdReadingMode);
			}

			this.layout.container.classList.remove('ui-viewer-reading-mode');
		},

		cursorInPerimeter: function(ev)
		{
			var offsetVertical = document.body.clientHeight / 100 * 30;
			var offsetHorizontal = document.body.clientWidth / 100 * 30;

			offsetHorizontal < 300 ? offsetHorizontal = 300 : null;
			offsetVertical < 300 ? offsetVertical = 300 : null;

			if(	ev.y < offsetVertical || ev.y > document.body.clientHeight - offsetVertical ||
				ev.x < offsetHorizontal || ev.x > document.body.clientWidth - offsetHorizontal)
			{
				return false
			}

			return true;
		},

		/**
		 * @param {BX.SidePanel.Event} event
		 */
		handleSliderCloseByEsc: function(event)
		{
			if (this.isOpen() && (this.getZindex() > event.getSlider().getZindex()))
			{
				event.denyAction();
			}
		},

		adjustViewport: function ()
		{
			var viewportNode = document.querySelector('[name="viewport"]');
			if (!viewportNode)
			{
				return;
			}
			this._viewportContent = viewportNode.getAttribute('content');
			viewportNode.setAttribute('content', 'width=device-width, user-scalable=no');
		},

		restoreViewport: function ()
		{
			var viewportNode = document.querySelector('[name="viewport"]');
			if (!this._viewportContent || !viewportNode)
			{
				return;
			}

			viewportNode.setAttribute('content', this._viewportContent);
		},

		unbindEvents: function()
		{
			this.eventsAlreadyBinded = false;

			BX.unbind(document, 'keydown', this.handlers.keyPress);
			BX.unbind(window, 'resize', this.handlers.resize);
			BX.unbind(this.getItemContainer(), 'touchstart', this.handlers.touchStart);
			BX.unbind(this.getItemContainer(), 'touchend', this.handlers.touchEnd);

			BX.unbind(this.getItemContainer(), 'click', this.handlers.handleClickOnItemContainer);
			BX.unbind(this.getNextButton(), 'click', this.handlers.showNext);
			BX.unbind(this.getPrevButton(), 'click', this.handlers.showPrev);
			BX.unbind(this.getCloseButton(), 'click', this.handlers.close);
		},

		init: function ()
		{},

		openByNode: function (node)
		{
			this.buildItemListByNode(node).then(function (items) {
				if (items.length === 0)
				{
					return;
				}

				if (this.shouldProcessSeparateMode(items))
				{
					this.setItems(items).then(function(){
						this.openSeparate(0);
					}.bind(this));

					return;
				}

				this.setItems(items).then(function(){
					this.open(this.getIndexByNode(node));
				}.bind(this));
			}.bind(this));
		},

		runActionByNode: function (node, actionId, additionalParams)
		{
			this.buildItemListByNode(node).then(function (items) {
				if (items.length === 0)
				{
					return;
				}

				this.setItems(items).then(function(){
					this.runAction(this.getIndexByNode(node), actionId, additionalParams);
				}.bind(this));
			}.bind(this));
		},

		runAction(index, actionId, additionalParams)
		{
			const item = this.getItemByIndex(index);
			if (actionId === 'download')
			{
				// Compatibility: a download action doesn't exist anymore
				window.open(item.getDownloadUrl(), this.isExternalLink(item.getDownloadUrl()) ? '_blank' : '_self');

				return;
			}

			var actionToRun = item.getActions().find(function (action) {
				return action.id === actionId;
			});

			console.log('actionToRun', actionId, actionToRun);
			if (!BX.type.isFunction(actionToRun.action))
			{
				console.log('action is not a function');
				return;
			}

			actionToRun.action.call(this, item, additionalParams);
		},

		/**
		 * @returns {number}
		 */
		getZindex: function ()
		{
			var container = this.getViewerContainer();
			if (!container.parentNode)
			{
				return 0;
			}

			var component = BX.ZIndexManager.getComponent(container);

			return component.getZIndex();
		},

		/**
		 * @param items
		 * @return {Promise<extensionsCollection>}
		 */
		setItems: function (items)
		{
			if (!BX.type.isArray(items))
			{
				throw new Error("BX.UI.Viewer.Controller.setItems: 'items' has to be Array.");
			}

			BX.onCustomEvent('BX.UI.Viewer.Controller:onSetItems', [this, items]);

			if (this.items !== null)
			{
				this.items.forEach((item) => {
					item.destroy();
				});
			}

			this.items = items;
			this.items.forEach(function (item) {
				item.setController(this);
			}, this);

			return this.loadExtensions(this.collectExtensionsForAction(items));
		},

		/**
		 *
		 * @param {String|String[]} extensions - Extension name
		 * @return {Promise<extensionsCollection>}
		 */
		loadExtensions: function (extensions)
		{
			return BX.loadExt(extensions);
		},

		/**
		 *
		 * @param {BX.UI.Viewer.Item[]} items
		 * @return {Array}
		 */
		collectExtensionsForAction: function (items)
		{
			var extensionSet = new Set();

			items.forEach(function (item) {
				var actions = item.getActions() || [];
				actions.forEach(function (action) {
					if (!action.extension)
					{
						return;
					}

					if (!BX.type.isArray(action.extension))
					{
						action.extension = [action.extension];
					}

					action.extension.forEach(function (ext) {
						extensionSet.add(ext);
					});
				});
			});

			var extensions = [];
			extensionSet.forEach(function (ext) {
				if (shouldLoadExtensions(ext))
				{
					extensions.push(ext);
				}
			});

			return extensions;
		},

		appendItem: function (item)
		{
			if (!(item instanceof BX.UI.Viewer.Item))
			{
				throw new Error("BX.UI.Viewer.Controller.appendItem: 'item' has to be instance of BX.UI.Viewer.Item.");
			}

			item.setController(this);
			this.items.push(item);
		},

		/**
		 * Reloads item in collection items. It means that we replace old item by the one new
		 * which is the copy.
		 * @param {BX.UI.Viewer.Item} item
		 * @param {Object} options
		 */
		reloadItem: function (item, options)
		{
			options = options || {};

			if (!(item instanceof BX.UI.Viewer.Item))
			{
				throw new Error("BX.UI.Viewer.Controller.reloadItem: 'item' has to be instance of BX.UI.Viewer.Item.");
			}

			var index = this.items.indexOf(item);
			if (index === -1)
			{
				throw new Error("BX.UI.Viewer.Controller.reloadItem: there is no 'item' in items to reload.");
			}

			var newItem = null;
			if (item.sourceNode)
			{
				newItem = BX.UI.Viewer.buildItemByNode(item.sourceNode);
			}
			else
			{
				newItem = new item.constructor(item.options);
			}

			item.destroy();

			newItem.setController(this);
			newItem.applyReloadOptions(options);

			this.items[index] = newItem;
		},

		show: function (index, options)
		{
			options = options || {};
			if (typeof index === 'undefined')
			{
				index = 0;
			}

			BX.onCustomEvent('BX.UI.Viewer.Controller:onBeforeShow', [this, index]);

			var item = this.getItemByIndex(index);
			if (!item)
			{
				return;
			}

			this.hideErrorBlock();
			this.hideCurrentItem();
			this.disableReadingMode();
			this.showLoading();

			const moveToStart = index === 0 && this.currentIndex === this.items.length - 1;
			const moveToEnd = this.currentIndex === 0 && index === this.items.length - 1;

			const direction = (index < this.currentIndex && !moveToStart) || moveToEnd ? 'backward' : 'forward';
			this.currentIndex = index;

			this.updateActions(this.getCurrentItem());
			this.observeItemLoading(item);

			const title = item.getTitle();
			this.setTitle(BX.Type.isStringFilled(title) ? title : '');

			item.load()
				.then((loadedItem) => {
					this.unobserveItemLoading(item);

					if (this.getCurrentItem() === loadedItem)
					{
						console.log('show item');
						this.processShowItem(loadedItem, options);
						if (options.asFirstToShow)
						{
							loadedItem.asFirstToShow();
						}
					}

					this.processPreload(index, direction);
				})
				.catch((reason) => {
					this.unobserveItemLoading(item);

					var loadedItem = reason.item;

					console.log('catch viewer');

					BX.onCustomEvent('BX.UI.Viewer.Controller:onItemError', [this, reason, loadedItem]);

					if (this.getCurrentItem() === loadedItem)
					{
						this.processError(reason, loadedItem);
					}

					BX.onCustomEvent('BX.UI.Viewer.Controller:onAfterProcessItemError', [this, reason, loadedItem]);
				})
			;

			this.updateControls();
			this.lockScroll();
			this.adjustViewerHeight();

			const cycleMove = this.items.length > 20 && (moveToStart || moveToEnd);
			this.selectCarouselItem(this.currentIndex, options.asFirstToShow !== true && !cycleMove);
		},

		processPreload(fromIndex, direction)
		{
			if (this.maxParallelLoads < 1)
			{
				return;
			}

			const maxPreloads = this.maxParallelLoads - 1;
			let preloadIndex = direction === 'backward' ? fromIndex - 1 : fromIndex + 1;
			const shouldPreload = () => {
				if (direction === 'backward')
				{
					return preloadIndex > (fromIndex - 1 - maxPreloads);
				}

				return preloadIndex < (maxPreloads + fromIndex + 1);
			};

			while (shouldPreload())
			{
				const itemByIndex = this.getItemByIndex(preloadIndex);
				if (!itemByIndex)
				{
					break;
				}

				console.log('Trying to preload', preloadIndex);

				this.observeItemLoading(itemByIndex);
				itemByIndex.load()
					.then(() => {
						this.unobserveItemLoading(itemByIndex);
					})
					.catch(() => {
						this.unobserveItemLoading(itemByIndex);
					})
				;

				if (direction === 'backward')
				{
					preloadIndex--;
				}
				else
				{
					preloadIndex++;
				}
			}
		},

		/**
		 * Reloads item and rerun show if item was as current item.
		 * @param {BX.UI.Viewer.Item} item
		 * @param {Object} options
		 */
		reload: function (item, options)
		{
			var isCurrentVisibleItem = this.getCurrentItem() === item;
			this.reloadItem(item, options);

			if (isCurrentVisibleItem)
			{
				console.log('reload');
				this.show(this.currentIndex);
			}
		},

		/**
		 * Reloads and show current item.
		 * @param {?Object} options
		 */
		reloadCurrentItem: function (options)
		{
			this.reload(this.getCurrentItem(), options || {});
		},

		/**
		 * @param {BX.UI.Viewer.Item} item
		 */
		processShowItem: function(item, options)
		{

			this.hideCurrentItem();
			this.hideLoading();
			this.unlockExtraActions();

			var contentWrapper = BX.create('div', {
				props: {
					className: 'ui-viewer-inner-content-wrapper'
				},
			});

			const title = item.getTitle();
			this.setTitle(BX.Type.isStringFilled(title) ? title : '');

			var fragment = document.createDocumentFragment();
			fragment.appendChild(item.render(options));
			contentWrapper.appendChild(fragment);
			var classList = this.layout.container.classList;
			var containerModifiers = item.listContainerModifiers();
			if (containerModifiers.length)
			{
				classList.add.apply(classList, containerModifiers);
			}

			this.layout.itemContainer.appendChild(contentWrapper);

			item.afterRender();
			this.adjustControlsSize(item.getContentWidth());

			BX.onCustomEvent('BX.UI.Viewer.Controller:onAfterShow', [this, item]);
		},

		adjustControlsSize: function(contentWidth)
		{
			this.getNextButton().style.width = null;
			this.getPrevButton().style.width = null;
			this.getNextButton().style.maxWidth = null;
			this.getPrevButton().style.maxWidth = null;

			if (contentWidth && BX.Type.isFunction(contentWidth.then))
			{
				contentWidth.then((width) => {
					let controlWidth = Math.floor((document.body.offsetWidth - Math.ceil(width)) / 2);
					controlWidth = Math.max(controlWidth, 70);

					this.getNextButton().style.width = controlWidth + 'px';
					this.getPrevButton().style.width = controlWidth + 'px';
					this.getNextButton().style.maxWidth = 'none';
					this.getPrevButton().style.maxWidth = 'none';
				});
			}
		},

		/**
		 * @param {Object} reason
		 * @param {BX.UI.Viewer.Item} item
		 */
		processError: function(reason, item)
		{
			reason = reason || {};

			var message = reason.message || null;
			if (BX.type.isArray(reason.errors) && reason.errors.length)
			{
				if (reason.errors[0].code === 1000 && !reason.message)
				{
					message = BX.message("JS_UI_VIEWER_ITEM_TRANSFORMATION_ERROR_1").replace('#DOWNLOAD_LINK#', item.getSrc());
				}
			}

			this.hideCurrentItem();
			this.hideLoading();
			this.cleanExtraActions();

			var contentWrapper = BX.create('div', {
				props: {
					className: 'ui-viewer-inner-content-wrapper'
				}
			});

			var title = item.getTitle();
			this.setTitle(BX.Type.isStringFilled(title) ? title : '');

			var options = {};
			if (message)
			{
				options.title = message;
			}
			if (reason.description)
			{
				options.description = reason.description;
			}
			contentWrapper.appendChild(this.getErrorBlock(options, item));

			this.layout.itemContainer.appendChild(contentWrapper);
		},

		hideErrorBlock: function()
		{
			if (this.layout.error)
			{
				BX.remove(this.layout.error);
			}
		},

		/**
		 * @param {Object} options
		 * @param {?string} [options.viewType='info']
		 * @param {?string} [options.title]
		 * @param {?string} [options.description]
		 * @param {BX.UI.Viewer.Item} item
		 * @return {null}
		 */
		getErrorBlock: function(options, item)
		{
			this.hideErrorBlock();

			var viewType = BX.prop.getString(options, 'viewType', 'info');
			var title = BX.prop.getString(options, 'title', BX.message("JS_UI_VIEWER_ITEM_TRANSFORMATION_ERROR_1").replace('#DOWNLOAD_LINK#', item.getSrc()));
			var description = BX.prop.getString(options, 'description', BX.message("JS_UI_VIEWER_ITEM_TRANSFORMATION_HINT"));

			this.layout.error = BX.create('div', {
				props: {
					className: 'ui-viewer-error'
				},
				style: {
					maxWidth: description? '440px' : null
				},
				children: [
					BX.create('div', {
						props: {
							className: 'ui-viewer-' + viewType + '-title'
						},
						html: title
					}),
					BX.create('div', {
						props: {
							className: 'ui-viewer-' + viewType + '-text'
						},
						html: description
					})
				]
			});

			return this.layout.error;
		},

		/**
		 * @param {String} link
		 * @return {boolean}
		 */
		isExternalLink: function (link)
		{
			var isAbsoluteLink = new RegExp('^([a-z]+://|//)', 'i');
			if (!isAbsoluteLink.test(link))
			{
				return false;
			}

			if (!BX.getClass('URL'))
			{
				return link.indexOf(location.hostname) === -1;
			}

			try
			{
				return (new URL(link)).hostname !== location.hostname;
			}
			catch(e)
			{}

			return true;
		},

		/**
	 		* @param {BX.UI.Viewer.Item} item
	 	*/
		createMoreMenuItems(item)
		{
			return item.getActions().map((action) => {
				const menuItem = { ...action };

				if (!menuItem.href && BX.type.isFunction(menuItem.action))
				{
					const fn = menuItem.action;
					menuItem.onclick = (event, menuItem) => {
						fn.call(this, item, { event, menuItem });
						this.moreMenu?.close();
					};
				}

				menuItem.disabled = menuItem.disableBeforeLoaded === true && item.isLoaded === false;

				if (BX.Type.isArrayFilled(menuItem.items))
				{
					menuItem.items = menuItem.items.map((subMenuItem) => {
						const newMenuItem = { ...subMenuItem };
						if (BX.type.isString(newMenuItem.onclick))
						{
							const onclick = new Function('event', 'popupItem', newMenuItem.onclick);
							newMenuItem.onclick = (event, popupItem) => {
								onclick(event, popupItem);
								this.moreMenu?.close();
							};
						}

						return newMenuItem;
					});
				}

				return menuItem;
			});
		},

		/**
		 * @param {BX.UI.Viewer.Item} item
		 */
		refineItemActions(item)
		{
			const defaultActions = {
				download: {
					id: 'download',
					type: 'download',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_DOWNLOAD'),
					href: item.src,
					buttonIconClass: 'ui-btn-icon-download',
				},
				edit: {
					id: 'edit',
					type: 'edit',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_EDIT'),
					buttonIconClass: 'ui-btn-icon-edit',
				},
				share: {
					id: 'share',
					type: 'share',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_SHARE'),
					buttonIconClass: 'ui-btn-icon-share',
				},
				print: {
					id: 'print',
					type: 'print',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_PRINT'),
					buttonIconClass: 'ui-btn-icon-print ui-btn-disabled',
					disableBeforeLoaded: true,
				},
				info: {
					id: 'info',
					type: 'info',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_INFO'),
					buttonIconClass: 'ui-btn-icon-info ui-action-panel-item-last',
				},
				delete: {
					id: 'delete',
					type: 'delete',
					text: BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_DELETE'),
					buttonIconClass: 'ui-btn-icon-remove',
				},
			};

			const actions = [];
			for (const [, nakedAction] of item.getNakedActions().entries())
			{
				const action = (
					defaultActions[nakedAction.type]
						? BX.mergeEx(defaultActions[nakedAction.type], nakedAction)
						: nakedAction
				);

				if (!action.id)
				{
					action.id = action.type;
				}

				if (action.id === 'download' && BX.Type.isStringFilled(action.href))
				{
					item.setDownloadUrl(action.href);

					continue;
				}

				if (!action.action && action.href)
				{
					action.action = () => {
						window.open(action.href, this.isExternalLink(action.href) ? '_blank' : '_self');
					};
				}

				if (BX.type.isString(action.action))
				{
					const params = action.params || {};
					const actionString = action.action;

					action.action = (item, additionalParams) => {
						try
						{
							const fn = eval(actionString);
							fn.call(this, item, params, additionalParams);
						}
						catch (e)
						{
							console.log(e);
						}
					};
				}

				actions.push(action);
			}

			return actions;
		},

		getLoader: function(options)
		{
			if (!this.layout.loader)
			{
				this.layout.loader = BX.create('div', {
					props: {
						className: 'ui-viewer-loader'
					},
					style: {
						zIndex: -1
					},
					children: [
						this.layout.loaderContainer = BX.create('div', {
							props: {
								className: 'ui-viewer-loader-container'
							}
						}),
						this.layout.loaderText = BX.create('div', {
							props: {
								className: 'ui-viewer-loader-text'
							},
							text: ''
						})
					]
				});

				var loader = new BX.Loader({size: 130});
				loader.show(this.layout.loaderContainer);
			}

			return this.layout.loader;
		},

		getPrevButton: function()
		{
			if (!this.layout.prev)
			{
				this.layout.prev = BX.create('div', {
					props: {
						className: 'ui-viewer-prev'
					},
					events: {
						mousewheel: function(event) {
							this.handleMouseWheelOnControlButton(this.layout.prev, event);
						}.bind(this)
					}
				})
			}

			return this.layout.prev;
		},

		getNextButton: function()
		{
			if (!this.layout.next)
			{
				this.layout.next = BX.create('div', {
					props: {
						className: 'ui-viewer-next'
					},
					events: {
						mousewheel: function(event) {
							this.handleMouseWheelOnControlButton(this.layout.next, event);
						}.bind(this)
					}
				});
			}

			return this.layout.next;
		},

		handleMouseWheelOnControlButton: function(controlNode, event)
		{
			if (this._timeoutIdMouseWheel)
			{
				clearTimeout(this._timeoutIdMouseWheel);
			}

			controlNode.style.pointerEvents = 'none';

			this._timeoutIdMouseWheel = setTimeout(function() {
				controlNode.style.pointerEvents = null;
			}, 50);
		},

		getCloseButton: function()
		{
			if (!this.layout.close)
			{
				this.layout.close = BX.create('div', {
					props: {
						className: 'ui-viewer-close',
					},
					html:
						'<div class="ui-viewer-close-icon">'
							+ '<div class="ui-icon-set --cross-40"></div>'
						+ '</div>'
				});
			}

			return this.layout.close;
		},

		getDownloadButton: function()
		{
			if (!this.layout.downloadBtn)
			{
				this.layout.downloadBtn = BX.Tag.render`
					<a 
						class="ui-viewer-download-btn" 
						target="_blank" 
						title="${BX.Text.encode(BX.Loc.getMessage('JS_UI_VIEWER_ITEM_ACTION_DOWNLOAD'))}"
						href="" 
						download
					>
						<div class="ui-icon-set --download ui-viewer-download-btn-icon"></div>
					</a>
				`;
			}

			return this.layout.downloadBtn;
		},

		getMoreButton: function()
		{
			if (!this.layout.moreBtn)
			{
				this.layout.moreBtn = BX.Tag.render`
					<div class="ui-viewer-more-btn" onclick="${this.handleMoreBtnClick.bind(this)}">
						<div class="ui-icon-set --more ui-viewer-more-btn-icon"></div>
					</div>
				`;
			}

			return this.layout.moreBtn;
		},

		isOpen: function ()
		{
			return this._isOpen;
		},

		addBodyPadding: function()
		{
			var padding = window.innerWidth - document.documentElement.clientWidth;

			if (BX.getClass('BXIM.messenger.popupMessenger') ||
				padding === 0)
			{
				return;
			}

			document.body.style.paddingRight = padding + 'px';

			var imBar = document.getElementById('bx-im-bar');
			if(imBar)
			{
				var borderColor = 'rgb(238, 242, 244)';

				if(document.body.classList.contains('bitrix24-light-theme'))
				{
					borderColor = 'rgba(255, 255, 255, .1)';
				}

				if(document.body.classList.contains('bitrix24-dark-theme'))
				{
					borderColor = 'rgba(82, 92, 105, .1)';
				}

				imBar.style.borderRight = padding + 'px solid ' + borderColor;
			}

			this.isBodyPaddingAdded = true;
		},

		removeBodyPadding: function()
		{
			document.body.style.removeProperty('padding-right');

			var imBar = document.getElementById('bx-im-bar');
			if (imBar)
			{
				imBar.style.removeProperty('border-right');
			}

			this.isBodyPaddingAdded = false;
		},

		openSeparate: function(index)
		{
			var item = this.getItemByIndex(index);
			if (!item)
			{
				return;
			}

			item.load()
				.then(function (loadedItem) {}.bind(this))
				.catch(function (reason) {
					var loadedItem = reason.item;

					console.log('catch viewer');

					BX.onCustomEvent('BX.UI.Viewer.Controller:onItemError', [this, reason, loadedItem]);

					if (this.getCurrentItem() === loadedItem)
					{
						this.processError(reason, loadedItem);
					}

					BX.onCustomEvent('BX.UI.Viewer.Controller:onAfterProcessItemError', [this, reason, loadedItem]);
				}.bind(this));
		},

		open: function(index)
		{

			this.adjustViewport();
			this.addBodyPadding();

			var container = this.getViewerContainer();

			const baseContainer = this.baseContainer || document.body;
			baseContainer.appendChild(container);

			BX.focus(container);

			var component = BX.ZIndexManager.getComponent(container);
			if (!component)
			{
				BX.ZIndexManager.register(container);
			}

			BX.ZIndexManager.bringToFront(container);

			this.createCarouselItems(index);

			this.show(index, {
				asFirstToShow: true,
			});

			this.bindEvents();

			this._isOpen = true;
		},

		setTitle: function(title)
		{
			if (BX.Type.isStringFilled(title))
			{
				this.getTitleContainer().textContent = title;
			}
		},

		getTitleContainer: function()
		{
			if (!this.layout.title)
			{
				this.layout.title = BX.Tag.render`
					<span class="ui-viewer-title-text"></span>
				`;
			}

			return this.layout.title;
		},

		getExtraActions: function()
		{
			if (!this.layout.extraActions)
			{
				this.layout.extraActions = BX.Tag.render`
					<div class="ui-viewer-extra-actions"></div>
				`;
			}

			return this.layout.extraActions;
		},

		getDefaultActions: function()
		{
			if (!this.layout.defaultActions)
			{
				this.layout.defaultActions = BX.Tag.render`
					<div class="ui-viewer-default-actions">
						${this.getDownloadButton()}
						${this.getMoreButton()}
					</div>
				`;
			}

			return this.layout.defaultActions;
		},

		observeItemLoading(item)
		{
			const supportAbort = Object.hasOwn(Object.getPrototypeOf(item), 'abort');
			if (item.isLoaded === true || !supportAbort)
			{
				return;
			}

			this.loadingItems.add(item);

			if (this.loadingItems.size > this.maxParallelLoads)
			{
				for (const queueItem of this.loadingItems)
				{
					if (queueItem === item || queueItem === this.getCurrentItem())
					{
						continue;
					}

					const success = queueItem.abort();
					if (success === true)
					{
						this.loadingItems.delete(queueItem);
						break;
					}
				}
			}
		},

		unobserveItemLoading(item)
		{
			this.loadingItems.delete(item);
		},

		updateActions(item)
		{
			this.getDownloadButton().setAttribute('href', item.getDownloadUrl());

			if (item.getActions().length > 0)
			{
				BX.Dom.removeClass(this.getMoreButton(), '--hidden');
			}
			else
			{
				BX.Dom.addClass(this.getMoreButton(), '--hidden');
			}

			this.renderExtraActions(item);
			if (!item.isLoaded)
			{
				this.lockExtraActions();
			}
		},

		getCarouselContainer: function()
		{
			if (!this.layout.carouselContainer)
			{
				this.layout.carouselContainer = BX.Tag.render`
					<div class="ui-viewer-carousel">
						${this.getCarouselScrollable()}
					<div>
				`;
			}

			return this.layout.carouselContainer;
		},

		getCarouselScrollable: function()
		{
			if (!this.layout.carouselScrollable)
			{
				this.layout.carouselScrollable = BX.Tag.render`
					<div 
						class="ui-viewer-carousel-scrollable" 
						onscroll="${BX.Runtime.debounce(this.handleCarouselScroll, 200, this)}"
					>
						${this.getCarouselItems()}
					</div>
				`;
			}

			return this.layout.carouselScrollable;
		},

		getCarouselItems: function()
		{
			if (!this.layout.carouselItems)
			{
				this.layout.carouselItems = BX.Tag.render`
					<div class="ui-viewer-carousel-items" onclick="${this.handleCarouselClick.bind(this)}"></div>
				`;
			}

			return this.layout.carouselItems;
		},

		getCarouselItemWidth: function(selected = false)
		{
			const margin = 4 * 2;

			return selected ? 72 + margin : 46 + margin;
		},

		createCarouselItems: function(selectedIndex)
		{
			const itemsContainer = this.getCarouselItems();
			BX.Dom.clean(itemsContainer);
			BX.Dom.style(itemsContainer, { paddingLeft: null, paddingRight: null });
			BX.Dom.style(this.getCarouselContainer(), { width: null });

			BX.Dom.remove(this.getCarouselContainer());

			if (!this.isCarouselEnabled())
			{
				return;
			}

			for (const [index, item] of this.items.entries())
			{
				const container = BX.Tag.render`
					<div class="ui-viewer-carousel-item" data-index="${index}"></div>
				`;

				if (index === selectedIndex)
				{
					BX.Dom.addClass(container, '--selected');
				}

				if (item.getPreviewUrl() === null)
				{
					const icon = this.createItemIcon(item);
					icon.renderTo(container);
				}
				else
				{
					const img = document.createElement('img');
					img.className = 'ui-viewer-carousel-item-preview-img';
					img.onerror = this.handlers.handleCarouselItemError;

					// Preload first 10 items
					if (index <= 10 || item.getPreviewUrl().startsWith('blob:'))
					{
						img.src = item.getPreviewUrl();
					}
					else
					{
						img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
						container.dataset.lazyloadSrc = item.getPreviewUrl();
					}

					container.appendChild(img);
				}

				BX.Dom.append(container, this.getCarouselItems());
			}

			BX.Dom.append(this.getCarouselContainer(), this.getViewerContainer());

			const maxViewportWidth = this.getCarouselItemWidth() * 6 + this.getCarouselItemWidth(true); // 7 items
			const minViewportWidth = (
				(this.getItemsCount() - 1) * this.getCarouselItemWidth() + this.getCarouselItemWidth(true) / 2
			) * 2;

			const viewportWidth = Math.max(
				this.getCarouselContainer().offsetWidth,
				Math.min(minViewportWidth, maxViewportWidth),
			);
			const offset = viewportWidth / 2 - this.getCarouselItemWidth(true) / 2;

			BX.Dom.style(this.getCarouselContainer(), {
				width: `${viewportWidth}px`,
			});

			BX.Dom.style(itemsContainer, {
				paddingLeft: `${offset}px`,
				paddingRight: `${offset}px`,
			});
		},

		loadCarouselPreviews()
		{
			const itemWidth = this.getCarouselItemWidth();
			const scrollContainer = this.getCarouselItems().parentNode;
			const windowWidth = scrollContainer.parentNode.offsetWidth;
			const itemsInWindow = Math.round(windowWidth / itemWidth);
			const scrollLeft = scrollContainer.scrollLeft;

			const middleItemIndex = Math.ceil(scrollLeft / itemWidth);
			const leftItemIndex = Math.max(middleItemIndex - itemsInWindow, 0);
			const rightItemIndex = Math.min(middleItemIndex + itemsInWindow * 1.5, this.items.length - 1);

			for (let index = leftItemIndex; index <= rightItemIndex; index++)
			{
				const carouselItem = this.getCarouselItems().children[index];
				if (carouselItem.dataset.lazyloadSrc)
				{
					const img = carouselItem.firstElementChild;
					img.src = carouselItem.dataset.lazyloadSrc;

					BX.Dom.attr(carouselItem, 'data-lazyload-src', null);
				}
			}
		},

		getFileExtension: function(filename)
		{
			const position = BX.Type.isStringFilled(filename) ? filename.lastIndexOf('.') : -1;

			return position > 0 ? filename.slice(Math.max(0, position + 1)) : '';
		},

		handleCarouselClick: function(event)
		{
			const container = event.target.closest('.ui-viewer-carousel-item');
			if (!container)
			{
				return;
			}

			const index = Number(container.dataset.index);

			this.show(index);
		},

		handleCarouselScroll(event)
		{
			this.loadCarouselPreviews();
		},

		handleCarouselItemError(event)
		{
			const container = event.target.closest('.ui-viewer-carousel-item');
			const index = container.dataset.index;
			const item = this.getItemByIndex(index);

			BX.Dom.clean(container);

			const icon = this.createItemIcon(item);
			icon.renderTo(container);
		},

		createItemIcon(item)
		{
			return new BX.UI.Icons.Generator.FileIcon({
				name: this.getFileExtension(item.getTitle()) || '...',
				size: 18,
			});
		},

		isCarouselEnabled: function()
		{
			if (this.items.length < 2)
			{
				return false;
			}

			return this.items.some((item) => {
				return item.getPreviewUrl() !== null;
			});
		},

		selectCarouselItem: function(index, smooth = true)
		{
			if (!this.isCarouselEnabled())
			{
				return;
			}

			const currentSelected = this.getCarouselItems().querySelector('.ui-viewer-carousel-item.--selected');
			if (currentSelected)
			{
				BX.Dom.removeClass(currentSelected, '--selected');
			}

			const newSelected = this.getCarouselItems().querySelector(`.ui-viewer-carousel-item[data-index="${index}"]`);
			BX.Dom.addClass(newSelected, '--selected');

			this.adjustCarouselPosition(this.currentIndex, smooth);
			this.loadCarouselPreviews();
		},

		adjustCarouselPosition: function(index, smooth = true)
		{
			if (!this.isCarouselEnabled())
			{
				return false;
			}

			const scrollContainer = this.getCarouselItems().parentNode;
			const carouselItem = this.getCarouselItems().querySelector(`.ui-viewer-carousel-item[data-index="${index}"]`);
			if (carouselItem === null)
			{
				return false;
			}

			const scrollLeft = this.getCarouselItemWidth() * index;
			if (scrollContainer.scrollLeft !== scrollLeft)
			{
				scrollContainer.scrollTo({
					left: scrollLeft,
					behavior: smooth ? 'smooth' : 'instant',
				});

				return true;
			}

			return false;
		},

		hideCurrentItem: function()
		{
			if (this.getCurrentItem())
			{
				var classList = this.layout.container.classList;
				var containerModifiers = this.getCurrentItem().listContainerModifiers();
				if (containerModifiers.length)
				{
					classList.remove.apply(classList, containerModifiers);
				}

				this.getCurrentItem().beforeHide();
			}

			this.moreMenu?.close();

			BX.cleanNode(this.layout.itemContainer);
		},

		updateControls: function()
		{
			if (!this.allowToUseCycleMode() && this.currentIndex + 1 >= this.items.length)
			{
				BX.addClass(this.getNextButton(), 'ui-viewer-navigation-hide');
			}
			else
			{
				BX.removeClass(this.getNextButton(), 'ui-viewer-navigation-hide');
			}

			if (!this.allowToUseCycleMode() && this.currentIndex === 0)
			{
				BX.addClass(this.getPrevButton(), 'ui-viewer-navigation-hide');
			}
			else
			{
				BX.removeClass(this.getPrevButton(), 'ui-viewer-navigation-hide');
			}
		},

		/**
		 * @return {BX.UI.Viewer.Item}
		 */
		getCurrentItem: function ()
		{
			return this.getItemByIndex(this.currentIndex);
		},

		/**
		 * @param {HTMLElement} node
		 * @return {int}
		 */
		getIndexByNode: function (node)
		{
			var nodeIndex = null;
			this.items.forEach(function (item, index) {
				if (item.sourceNode === node)
				{
					nodeIndex = index;
				}
			});

			return nodeIndex;
		},

		/**
		 *
		 * @param index
		 * @returns BX.UI.Viewer.Item
		 */
		getItemByIndex: function (index)
		{
			index = parseInt(index, 10);

			BX.onCustomEvent('BX.UI.Viewer.Controller:onGetItemByIndex', [this, index]);

			if (index < 0 || (index - 1) > this.items.length)
			{
				return null;
			}

			return this.items[index];
		},

		getItemsCount: function()
		{
			return this.items.length;
		},

		handleClickOnItemContainer: function (event)
		{
			this.getCurrentItem().handleClickOnItemContainer(event);
		},

		allowToUseCycleMode: function ()
		{
			var cycleMode = this.cycleMode;
			var groupBy = this.getCurrentItem().getGroupBy();
			if (this.optionsByGroup[groupBy] && this.optionsByGroup[groupBy].hasOwnProperty('cycleMode'))
			{
				cycleMode = this.optionsByGroup[groupBy].cycleMode;
			}

			return this.items.length > 1 && cycleMode;
		},

		showNext: function ()
		{
			var index = this.currentIndex + 1;
			if (this.allowToUseCycleMode() && index >= this.items.length)
			{
				index = 0;
			}

			this.show(index);
		},

		showPrev: function ()
		{
			var index = this.currentIndex - 1;
			if (this.allowToUseCycleMode() && index === -1)
			{
				index = this.items.length - 1;
			}

			this.show(index);
		},

		close: function ()
		{
			this._isOpen = false;

			BX.onCustomEvent('BX.UI.Viewer.Controller:onClose', [this]);

			BX.addClass(this.layout.container, 'ui-viewer-hide');
			this.restoreViewport();
			this.hideCurrentItem();

			BX.bind(this.layout.container, 'transitionend', function()
			{
				BX.ZIndexManager.unregister(this.layout.container);
				BX.remove(this.layout.container);
				BX.removeClass(this.layout.container, 'ui-viewer-hide');
				BX.unbindAll(this.layout.container);

				this.unLockScroll();
				this.unbindEvents();
				this.disableReadingMode();
				if(this.isBodyPaddingAdded)
				{
					this.removeBodyPadding();
				}
			}.bind(this));

			// this.items = null;
			// this.currentIndex = null;
			// this.layout.container = null;
			// this.layout.close = null;
		},

		showLoading: function (options)
		{
			options = options || {};
			options.zIndex = BX.type.isNumber(options.zIndex)? options.zIndex : -1;

			this.layout.inner.appendChild(this.getLoader());
			this.setTextOnLoading(options.text || '');
			this.layout.loader.style.zIndex = options.zIndex;
		},

		setTextOnLoading: function (text)
		{
			this.layout.loaderText.textContent = text;
		},

		hideLoading: function ()
		{
			BX.remove(this.layout.loader);
		},

		lockScroll: function()
		{
			BX.addClass(document.body, 'ui-viewer-lock-body');
		},

		unLockScroll: function()
		{
			BX.removeClass(document.body, 'ui-viewer-lock-body');
		},

		renderExtraActions(item)
		{
			this.cleanExtraActions();
			BX.Dom.append(item.renderExtraActions(), this.getExtraActions());
		},

		cleanExtraActions()
		{
			BX.Dom.clean(this.getExtraActions());
		},

		lockExtraActions: function()
		{
			BX.Dom.addClass(this.getExtraActions(), '--locked');
		},

		unlockExtraActions: function()
		{
			BX.Dom.removeClass(this.getExtraActions(), '--locked');
		},

		handleWindowResize()
		{
			this.adjustViewerHeight();
			const item = this.getCurrentItem();
			if (item)
			{
				item.handleResize();
			}
		},

		adjustViewerHeight: function()
		{
			if(!this.layout.container || BX.browser.IsMobile())
				return;

			this.layout.container.style.height = document.documentElement.clientHeight + 'px';
		},

		getViewerContainer: function()
		{
			if (!this.layout.container)
			{
				this.layout.container = BX.create('div', {
					props: {
						className: 'ui-viewer',
						tabIndex: 22081990,
					},
					style: {
						height: window.clientHeight + 'px'
					},
					children: [
						BX.Tag.render`
							<div class="ui-viewer-header">
								<div class="ui-viewer-author"></div>
								<div class="ui-viewer-title">
									${this.getTitleContainer()}
								</div>
								<div class="ui-viewer-actions">
									${this.getExtraActions()}
									${this.getDefaultActions()}
									${this.getCloseButton()}
								</div>
							</div>
						`,
						this.layout.inner = BX.create('div', {
							props: {
								className: 'ui-viewer-inner',
							},
							children: [
								this.getItemContainer(),
							],
						}),
						this.getPrevButton(),
						this.getNextButton(),
					],
				});
			}

			return this.layout.container;
		},

		getItemContainer: function()
		{
			if (!this.layout.itemContainer)
			{
				this.layout.itemContainer = BX.create('div', {
					props: {
						className: 'ui-viewer-inner-content'
					}
				});
			}

			return this.layout.itemContainer
		},

		handleTouchStart: function(event)
		{
			var touchObject = event.changedTouches[0];
			this.swipeDirection = null;
			this.startX = touchObject.pageX;
			this.startY = touchObject.pageY;
			this.startTime = (new Date()).getTime();
			// event.preventDefault();

		},

		handleTouchEnd: function(event)
		{
			var touchObject = event.changedTouches[0];
			var allowedTime = 300;
			var threshold = 80;
			var restraint = 100;
			var distanceX = touchObject.pageX - this.startX;
			var distanceY = touchObject.pageY - this.startY;
			var elapsedTime = (new Date()).getTime() - this.startTime;

			if (elapsedTime <= allowedTime)
			{
				if (Math.abs(distanceX) >= threshold && Math.abs(distanceY) <= restraint)
				{
					this.swipeDirection = (distanceX < 0) ? 'left' : 'right';
				}
				// else if (Math.abs(distanceY) >= threshold && Math.abs(distanceX) <= restraint)
				// {
				// 	this.swipeDirection = (distanceY < 0) ? 'up' : 'down';
				// }
			}

			switch (this.swipeDirection)
			{
				case 'left':
					this.showPrev();
					break;
				case 'right':
					this.showNext();
					break;
			}

			// event.preventDefault();
		},

		isOnTop: function ()
		{
			if (!this.isOpen())
			{
				return false;
			}

			if (BX.getClass('BXIM.messenger') && BXIM.messenger.popupMessenger)
			{
				return true;
			}

			if (!BX.getClass('BX.SidePanel.Instance') || !BX.SidePanel.Instance.getTopSlider())
			{
				return true;
			}

			return this.getZindex() > BX.SidePanel.Instance.getTopSlider().getZindex();
		},

		handleKeyPress: function (event)
		{
			if (!this.isOnTop())
			{
				return;
			}

			if (event.metaKey)
			{
				return;
			}

			const handled = this.getCurrentItem().handleKeyPress(event);
			if (handled === true)
			{
				return;
			}

			switch (event.code)
			{
				case 'Space':
				case 'ArrowRight':
					this.showNext();
					event.preventDefault();
					event.stopPropagation();

					break;
				case 'ArrowLeft':
					this.showPrev();
					event.preventDefault();
					event.stopPropagation();

					break;
				case 'Escape':
					this.close();
					event.preventDefault();
					event.stopPropagation();

					break;
			}
		},

		setOptionsByGroup: function (groupBy, options)
		{
			this.optionsByGroup[groupBy] = options;

			return this;
		},

		getCachedData: function(id)
		{
			return this.cachedData[id];
		},

		setCachedData: function(id, data)
		{
			this.cachedData[id] = data;
		},

		unsetCachedData: function(id)
		{
			this.cachedData[id] = null;
		},

		/**
		 * @param {String} type
		 * @param {String} className
		 */
		addType: function (type, className)
		{
			return BX.UI.Viewer.addType(type, className);
		}
	};

	/**
	 * @extends {BX.UI.Viewer.Controller}
	 * @param options
	 * @constructor
	 */
	BX.UI.Viewer.InlineController = function (options)
	{
		options = options || {};

		BX.UI.Viewer.Controller.apply(this, arguments);
	};

	BX.UI.Viewer.InlineController.prototype =
	{
		__proto__: BX.UI.Viewer.Controller.prototype,
		constructor: BX.UI.Viewer.Controller,

		adjustViewport: function(){},
		addBodyPadding: function(){},
		adjustZindex: function(){},
		adjustViewerHeight: function(){},
		// showLoading: function(){},

		/**
		 * @param {HTMLElement} node
		 */
		renderItemByNode: function (node)
		{
			if (!node)
			{
				return;
			}

			this.buildItemListByNode(node).then(function(items){
				if (items.length === 0)
				{
					return;
				}

				this.setItems(items).then(function(){
					this.open(0);
				}.bind(this));
			}.bind(this));
		},

		getViewerContainer: function()
		{
			if (!this.layout.container)
			{
				//this.layout.inner? for showLoading
				this.layout.container = this.layout.inner = BX.create('div', {
					props: {
						className: 'ui-viewer-inner'
					},
					children: [
						this.getItemContainer()
					]
				});
			}

			return this.layout.container;
		},

		handleClickOnItemContainer: function(){},
		handleKeyPress: function(){},

		temp()
		{
			// timestamp update 207392
		},
	};
	/**
	 * @param type
	 * @param {HTMLElement} node
	 * @return {BX.UI.Viewer.Item}
	 */
	BX.UI.Viewer.buildItemByTypeAndNode = function (type, node)
	{
		var item = new type();

		if (!(item instanceof BX.UI.Viewer.Item))
		{
			throw new Error("BX.UI.Viewer.buildItemByTypeAndNode: 'item' has to be instance of BX.UI.Viewer.Item.");
		}

		item.bindSourceNode(node);
		item.setPropertiesByNode(node);
		item.setActions(BX.UI.Viewer.Instance.refineItemActions(item));

		return item;
	};

	/**
	 * @param {HTMLElement} node
	 * @returns {BX.UI.Viewer.Item}
	 */
	BX.UI.Viewer.buildItemByNode = function (node)
	{
		if (!BX.type.isDomNode(node))
		{
			throw new Error("BX.UI.Viewer.buildItemByNode: 'node' has to be DomNode.");
		}

		var typeCode = node.dataset.viewerType;
		if (!typeCode && node.tagName.toLowerCase() === 'img')
		{
			typeCode = 'image';
		}

		BX.UI.Viewer.triggerEventToFindTypeClass(typeCode);

		var className = types[typeCode];
		if (className)
		{
			return BX.UI.Viewer.buildItemByTypeAndNode(BX.getClass(className), node);
		}

		if (node.dataset.viewerTypeClass)
		{
			if (!BX.getClass(node.dataset.viewerTypeClass))
			{
				throw new Error("BX.UI.Viewer.buildItemByNode: could not find class " + node.dataset.viewerTypeClass);
			}

			return BX.UI.Viewer.buildItemByTypeAndNode(BX.getClass(node.dataset.viewerTypeClass), node);
		}

		console.warn("BX.UI.Viewer.buildItemByNode: could not find class to build type {" + typeCode + "}");

		return BX.UI.Viewer.buildItemByTypeAndNode(BX.getClass(types.unknown), node);
	};

	var types = {
		image: 'BX.UI.Viewer.Image',
		plainText: 'BX.UI.Viewer.PlainText',
		unknown: 'BX.UI.Viewer.Unknown',
		video: 'BX.UI.Viewer.Video',
		audio: 'BX.UI.Viewer.Audio',
		document: 'BX.UI.Viewer.Document',
		code: 'BX.UI.Viewer.HightlightCode'
	};

	/**
	 * @param {String} type
	 * @param {String} className
	 */
	BX.UI.Viewer.addType = function (type, className)
	{
		types[type] = className;
	};

	BX.UI.Viewer.triggerEventToFindTypeClass = function (type)
	{
		BX.onCustomEvent('BX.UI.Viewer.Controller:onFindType', [BX.UI.Viewer.Instance, type]);
	};

	/**
	 * @param {HTMLElement} container
	 * @param filter
	 * @returns {BX.Promise}
	 */
	BX.UI.Viewer.bind = function (container, filter)
	{
		if (!BX.type.isDomNode(container))
		{
			throw new Error("BX.UI.Viewer.bind: 'container' has to be DomNode.");
		}
		if (!BX.type.isPlainObject(filter) && !BX.type.isFunction(filter))
		{
			filter = function(node) {
				return BX.type.isElementNode(node) && node.dataset.hasOwnProperty('viewer');
			};
		}

		BX.bindDelegate(container, 'click', filter, function(event) {
			var nodes = BX.findChildren(container, filter, true);
			var indexToShow = 0;
			var targetNode = BX.getEventTarget(event);
			if (targetNode.tagName !== 'A' && targetNode.closest('a[target="_blank"]'))
			{
				return false;
			}

			const openViewer = () => {
				const items = nodes.map((node, index) => {
					if (node === targetNode)
					{
						indexToShow = index;
					}

					return top.BX.UI.Viewer.buildItemByNode(node);
				});

				top.BX.UI.Viewer.Instance.setItems(items)
					.then(() => {
						top.BX.UI.Viewer.Instance.open(indexToShow);
					})
					.catch(() => {
						// Fail silently
					});
			};

			if (window.top !== window && !BX.getClass('window.top.BX.UI.Viewer.Instance'))
			{
				top.BX.loadExt('ui.viewer')
					.then(() => {
						openViewer();
					})
					.catch(() => {
						// Fail Silently
					});
			}
			else
			{
				openViewer();
			}

			event.preventDefault();
		});
	};

	var shouldLoadExtensions = function(extension) {
		if (extension === 'disk.viewer.actions' && BX.getClass('BX.Disk.Viewer.Actions'))
		{
			return false;
		}
		if (extension === 'disk.viewer.document-item' && BX.getClass('BX.Disk.Viewer.DocumentItem'))
		{
			return false;
		}

		return true;
	}


	var instance = null;
	/**
	 * @memberOf BX.UI.Viewer
	 * @name BX.UI.Viewer#Instance
	 * @type BX.UI.Viewer.Controller
	 * @static
	 * @readonly
	 */
	Object.defineProperty(BX.UI.Viewer, 'Instance', {
		enumerable: false,
		get: function()
		{
			if (window.top !== window && BX.getClass('window.top.BX.UI.Viewer.Instance'))
			{
				return window.top.BX.UI.Viewer.Instance;
			}

			if (instance === null)
			{
				instance = new BX.UI.Viewer.Controller({});
			}

			return instance;
		}
	});

	window.document.addEventListener('click', function(event) {
		if (event.button !== 0)
		{
			return;
		}

		if (window.top !== window && !BX.getClass('window.top.BX.UI.Viewer.Instance'))
		{
			top.BX.loadExt('ui.viewer').then(function () {
				top.BX.UI.Viewer.Instance.handleDocumentClick(event);
			});
		}
		else
		{
			top.BX.UI.Viewer.Instance.handleDocumentClick(event);
		}
	}, true);

	//We have to show viewer only in top window not in iframe.
	//So we try to load ui.viewer to the top window if there is no viewer.
	if (window.top !== window && !BX.getClass('window.top.BX.UI.Viewer.Instance'))
	{
		top.BX.loadExt('ui.viewer');
	}
})();

Youez - 2016 - github.com/yon3zu
LinuXploit