Source: components/FormBuilder/withActionableFields.es.js

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

/* eslint no-unused-vars: "warn" */

import * as FormSupport from 'dynamic-data-mapping-form-renderer/js/components/FormRenderer/FormSupport.es';
import ClayButton from 'clay-button';
import ClayModal from 'clay-modal';
import Component from 'metal-jsx';
import dom from 'metal-dom';
import {Config} from 'metal-state';
import {EventHandler} from 'metal-events';
import {
	focusedFieldStructure,
	pageStructure,
	ruleStructure
} from '../../util/config.es';

class Actions extends Component {
	render() {
		const {spritemap} = this.props;

		return (
			<div class='ddm-field-actions-container' ref='actionsContainer'>
				<ClayButton
					editable={true}
					events={{
						click: this._handleDuplicateButtonClicked.bind(this)
					}}
					icon='paste'
					monospaced={true}
					size='sm'
					spritemap={spritemap}
					style='secondary'
				/>

				<ClayButton
					editable={true}
					events={{
						click: this._handleDeleteButtonClicked.bind(this)
					}}
					icon='trash'
					monospaced={true}
					size='sm'
					spritemap={spritemap}
					style='secondary'
				/>
			</div>
		);
	}

	_handleDeleteButtonClicked(event) {
		const indexes = FormSupport.getIndexes(
			dom.closest(event.target, '.col-ddm')
		);

		this.emit('fieldDeleted', {indexes});
	}

	_handleDuplicateButtonClicked(event) {
		const indexes = FormSupport.getIndexes(
			dom.closest(event.target, '.col-ddm')
		);

		this.emit('fieldDuplicated', {
			indexes
		});
	}
}

const withActionableFields = ChildComponent => {
	class ActionableFields extends Component {
		attached() {
			this._eventHandler = new EventHandler();

			this._eventHandler.add(
				this.delegate(
					'mouseenter',
					'.ddm-field-container',
					this._handleMouseEnterField.bind(this)
				)
			);
		}

		disposeInternal() {
			super.disposeInternal();

			this._eventHandler.removeAllListeners();
		}

		getEvents() {
			return {
				fieldDeleted: this._handleDeleteRequest.bind(this),
				fieldDuplicated: this._handleDuplicateRequest.bind(this)
			};
		}

		isActionsEnabled() {
			const {defaultLanguageId, editingLanguageId} = this.props;

			return defaultLanguageId === editingLanguageId;
		}

		render() {
			const {spritemap} = this.props;

			return (
				<div>
					<ClayModal
						body={Liferay.Language.get(
							'are-you-sure-you-want-to-delete-this-field'
						)}
						events={{
							clickButton: this._handleDeleteConfirmationModalButtonClicked.bind(
								this
							)
						}}
						footerButtons={[
							{
								alignment: 'right',
								label: Liferay.Language.get('dismiss'),
								style: 'primary',
								type: 'close'
							},
							{
								alignment: 'right',
								label: Liferay.Language.get('delete'),
								style: 'primary',
								type: 'button'
							}
						]}
						ref='deleteModal'
						size='sm'
						spritemap={spritemap}
						title={Liferay.Language.get(
							'delete-field-dialog-title'
						)}
					/>

					<ChildComponent {...this.props} events={this.getEvents()} />

					{this.isActionsEnabled() && (
						<Actions
							events={this.getEvents()}
							portalElement={this.element}
							ref='actions'
							spritemap={spritemap}
						/>
					)}
				</div>
			);
		}

		showDeleteConfirmationModal() {
			const {deleteModal} = this.refs;

			deleteModal.show();
		}

		_handleDeleteConfirmationModalButtonClicked(event) {
			const {store} = this.context;
			const {target} = event;
			const {deleteModal} = this.refs;
			const {indexes} = this.state;

			event.stopPropagation();

			deleteModal.emit('hide');

			if (!target.classList.contains('close-modal')) {
				store.emit('fieldDeleted', {indexes});
			}
		}

		_handleDeleteRequest({indexes}) {
			this.setState({
				indexes
			});

			this.showDeleteConfirmationModal();
		}

		_handleDuplicateRequest(indexes) {
			this._handleFieldDuplicated(indexes);
		}

		_handleFieldDuplicated(indexes) {
			const {store} = this.context;

			store.emit('fieldDuplicated', indexes);
		}

		_handleMouseEnterField({delegateTarget}) {
			if (this.isActionsEnabled()) {
				dom.append(delegateTarget, this.refs.actions.element);
			}
		}
	}

	ActionableFields.STATE = {
		/**
		 * @default undefined
		 * @instance
		 * @memberof ActionableFields
		 * @type {?array<string>}
		 */

		indexes: Config.object()
	};

	ActionableFields.PROPS = {
		/**
		 * @default
		 * @instance
		 * @memberof FormBuilder
		 * @type {?number}
		 */

		activePage: Config.number().value(0),

		/**
		 * @default undefined
		 * @instance
		 * @memberof FormBuilder
		 * @type {?string}
		 */

		defaultLanguageId: Config.string(),

		/**
		 * @default undefined
		 * @instance
		 * @memberof FormBuilder
		 * @type {?string}
		 */

		editingLanguageId: Config.string(),

		/**
		 * @default []
		 * @instance
		 * @memberof Sidebar
		 * @type {?(array|undefined)}
		 */

		fieldTypes: Config.array().value([]),

		/**
		 * @default {}
		 * @instance
		 * @memberof FormBuilder
		 * @type {?object}
		 */

		focusedField: focusedFieldStructure.value({}),

		/**
		 * @default []
		 * @instance
		 * @memberof FormBuilder
		 * @type {?array<object>}
		 */

		pages: Config.arrayOf(pageStructure).value([]),

		/**
		 * @instance
		 * @memberof FormBuilder
		 * @type {string}
		 */

		paginationMode: Config.string().required(),

		/**
		 * @instance
		 * @memberof FormBuilder
		 * @type {string}
		 */

		portletNamespace: Config.string().required(),

		/**
		 * @instance
		 * @memberof FormBuilder
		 * @type {string}
		 */

		rules: Config.arrayOf(ruleStructure).required(),

		/**
		 * @default undefined
		 * @instance
		 * @memberof FormRenderer
		 * @type {!string}
		 */

		spritemap: Config.string().required()
	};

	return ActionableFields;
};

export default withActionableFields;