Your IP : 18.221.108.142


Current Path : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/landing/history/src/
Upload File :
Current File : /var/www/www-root/data/www/www.monolith-realty.ru/bitrix/js/landing/history/src/history.js

import {Main} from 'landing.main';
import {PageObject} from 'landing.pageobject';
import {Backend} from 'landing.backend';
import {RESOLVED, PENDING, HISTORY_TYPES} from './internal/constants';
import registerBaseCommands from './internal/register-base-commands';
import removePageHistory from './internal/remove-page-history';
import clear from './internal/clear';
import onUpdate from './internal/on-update';
import onInit from './internal/on-init';
import Command from './history-command';
import Entry from './history-entry';
import Stack from './stack';
import Highlight from './history-highlight';    // not delete - just for export

import './css/style.css';

/**
 * Implements interface for works with landing history
 * Implements singleton pattern use as BX.Landing.History.getInstance()
 * @memberOf BX.Landing
 */
export class History
{
	/**
	 * Stack of action commands
	 */
	stack: ?Stack = null;

	/**
	 * Key - command name, value - a Command object
	 */
	commands: {[string]: Command} = {};

	/**
	 * If command now running - set to PENDING
	 * @type {string}
	 */
	commandState: string = RESOLVED;

	/**
	 * Type of current entity
	 * @type {string}
	 */
	entityType: string = HISTORY_TYPES.landing;

	/**
	 * Landing or Block ID in relation to type
	 * @type {number}
	 */
	entityId: number;

	constructor()
	{
		try
		{
			this.entityId = Main.getInstance().id;
		}
		catch (err)
		{
			this.entityId = -1;
		}

		this.stack = new Stack(this.entityId);
		this.stack.init()
			.then(() => {
				return registerBaseCommands(this)
			})
			.then(onInit);
	}

	static Command = Command;
	static Entry = Entry;
	static Highlight = Highlight; // not delete - just for export

	static getInstance(): History
	{
		const rootWindow = PageObject.getRootWindow();
		if (!rootWindow.BX.Landing.History.instance)
		{
			rootWindow.BX.Landing.History.instance = new BX.Landing.History();
		}

		return rootWindow.BX.Landing.History.instance;
	}

	/**
	 * Set special type for designer block history
	 * @param blockId
	 * @return {Promise<BX.Landing.History>|*}
	 */
	setTypeDesignerBlock(blockId: number): Promise<History>
	{
		this.entityType = HISTORY_TYPES.designerBlock;
		this.entityId = blockId;

		return this.stack.setTypeDesignerBlock(blockId)
			.then(() => {
				return this;
			})
	}

	getEntityId(): number
	{
		return this.entityId;
	}

	beforeUndo(): Promise
	{
		const commandName = this.stack.getCommandName();
		if (commandName && this.commands[commandName])
		{
			const command = this.commands[commandName];

			return command.onBeforeCommand();
		}

		return Promise.resolve();
	}

	beforeRedo(): Promise
	{
		const commandName = this.stack.getCommandName(false);
		if (commandName && this.commands[commandName])
		{
			const command = this.commands[commandName];

			return command.onBeforeCommand();
		}

		return Promise.resolve();
	}

	/**
	 * Applies preview history entry
	 * @return {Promise}
	 */
	undo(): Promise
	{
		if (this.canUndo())
		{
			this.commandState = PENDING;
			return this.beforeUndo()
				.then(() => {
					return Backend.getInstance()
						.action(
							this.getBackendActionName(true),
							this.getBackendActionParams(true),
						)
				})
				.then(command => {
					if (command)
					{
						const params = command.params;
						const entry = new Entry({
							block: params.block,
							selector: params.selector,
							command: command.command,
							params: params,
						});

						return this.runCommand(entry);
					}

					return Promise.reject();
				})
				.then(() => {
					return this.offset();
				})
				.then(onUpdate)
			;
		}

		return Promise.resolve(this);
	}


	/**
	 * Applies preview next history entry
	 * @return {Promise}
	 */
	redo(): Promise
	{
		if (this.canRedo())
		{
			this.commandState = PENDING;
			return this.beforeRedo()
				.then(() => {
					return Backend.getInstance()
						.action(
							this.getBackendActionName(false),
							this.getBackendActionParams(false),
						)
				})
				.then(command => {
					if (command)
					{
						const params = command.params;
						const entry = new Entry({
							block: params.block,
							selector: params.selector,
							command: command.command,
							params: params,
						});

						return this.runCommand(entry);
					}

					return Promise.reject();
				})
				.then(() => {
					return this.offset(false);
				})
				.then(onUpdate)
			;
		}

		return Promise.resolve(this);
	}

	/**
	 * Get name for backend action
	 * @param {boolean} undo - true, if need undo, false for redo
	 * @return {string}
	 */
	getBackendActionName(undo: boolean = true): string
	{
		if (this.entityType === HISTORY_TYPES.designerBlock)
		{
			return undo ? 'History::undoDesignerBlock' : 'History::redoDesignerBlock';
		}

		return undo ? 'History::undoLanding' : 'History::redoLanding';
	}

	/**
	 * Get id for entity for backend action
	 * @param {boolean} undo - true, if need undo, false for redo
	 * @return {string}
	 */
	getBackendActionParams(undo: boolean = true): string
	{
		if (this.entityType === HISTORY_TYPES.designerBlock)
		{
			return {
				blockId: this.entityId,
			};
		}

		return {
			lid: this.stack.getCommandEntityId(undo),
		};
	}

	runCommand(entry: Entry)
	{
		if (entry)
		{
			const command = this.commands[entry.command];
			if (command)
			{
				this.commandState = PENDING;

				return command.command(entry)
					.then(() => {
						this.commandState = RESOLVED;

						return this;
					})
					.catch(() => {
						this.commandState = RESOLVED;

						return this;
					});
			}
		}
	}

	offset(undo: boolean = true): Promise<History>
	{
		if (this.commandState === PENDING)
		{
			return Promise.resolve(this);
		}

		return this.stack.offset(undo)
			.then(() => {
				return this;
			});
	}

	/**
	 * Check that there are actions to undo
	 * @returns {boolean}
	 */
	canUndo()
	{
		return (
			this.commandState !== PENDING
			&& this.stack.canUndo()
		);
	}


	/**
	 * Check that there are actions to redo
	 * @returns {boolean}
	 */
	canRedo()
	{
		return (
			this.commandState !== PENDING
			&& this.stack.canRedo()
		);
	}


	/**
	 * Adds entry to history stack
	 */
	push(): Promise<History>
	{
		return this.stack.push()
			.then(() => {
				return onUpdate(this);
			})
		;
	}


	/**
	 * Registers unique history command
	 * @param {Command} command
	 */
	registerCommand(command: Command)
	{
		if (command instanceof Command)
		{
			this.commands[command.id] = command;
		}
	}

	/**
	 * Removes page history from storage
	 * @param {int} pageId
	 * @return {Promise<BX.Landing.History>}
	 */
	removePageHistory(pageId)
	{
		return removePageHistory(pageId, this)
			.then((history) => {
				let currentPageId;

				try
				{
					currentPageId = BX.Landing.Main.getInstance().id;
				}
				catch (err)
				{
					currentPageId = -1;
				}

				if (currentPageId === pageId)
				{
					return clear(history);
				}

				return Promise.reject();
			})
			.then(onUpdate)
			.catch(() => {});
	}
}