Source: Sharing.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.
 */

import 'clay-multi-select';

import 'clay-sticker';
import {PortletBase} from 'frontend-js-web';
import dom from 'metal-dom';
import Soy from 'metal-soy';
import {Config} from 'metal-state';

import templates from './Sharing.soy';

class Sharing extends PortletBase {
	constructor(config, ...args) {
		super(config, ...args);

		this._classNameId = config.classNameId;
		this._classPK = config.classPK;
		this._dialogId = config.dialogId;
		this._refererPortletNamespace = config.refererPortletNamespace;
		this._userEmailAddresses = [];
	}

	attached() {
		const portalElement = dom.toElement('#clay_dropdown_portal');

		if (portalElement) {
			dom.addClasses(portalElement, 'show');
		}
	}

	/**
	 * Fetches autocomplete results
	 * @private
	 * @review
	 */
	_dataSource(query) {
		return this.fetch(this.sharingUserAutocompleteURL, {
			query
		})
			.then(res => res.json())
			.then(users =>
				users.map(({emailAddress, fullName, portraitURL, userId}) => ({
					emailAddress,
					fullName,
					label: fullName,
					portraitURL,
					spritemap: this.spritemap,
					userId,
					value: emailAddress
				}))
			);
	}

	/**
	 * Disables filtering of results
	 * @private
	 * @review
	 */
	_handleDataChange(e) {
		e.preventDefault();

		if (e.data && e.target.refs.autocomplete._query) {
			e.target.filteredItems = e.data.map((element, index) => ({
				data: element,
				index,
				matches: [],
				score: 0,
				value: element
			}));
		} else {
			e.target.filteredItems = [];
		}

		e.target.refs.autocomplete._isFetching = false;
		e.target.refs.autocomplete.refs.dataProvider.isLoading = false;
	}

	/**
	 * Close the SharingDialog
	 * @private
	 * @review
	 */
	_closeDialog() {
		const sharingDialog = Liferay.Util.getWindow(this._dialogId);

		if (sharingDialog && sharingDialog.hide) {
			sharingDialog.hide();
		}
	}

	/**
	 * Sync the inputs with the state
	 * @param {!Event} event
	 * @private
	 * @review
	 */
	_handleInputChange(event) {
		const target = event.target;

		const name = target.name;
		const value =
			target.type === 'checkbox' ? target.checked : target.value;

		this[name] = value;
	}

	/**
	 * Validates if the email addresses introduced is valid
	 * and exists as a user.
	 *
	 * @param {!Event} event
	 * @private
	 * @review
	 */
	_handleEmailAddressAdded(event) {
		const {item, selectedItems} = event.data;

		this._userEmailAddresses = selectedItems;

		this.emailAddressErrorMessage = '';
		this._inputValue = '';

		const itemAdded = item.value;

		if (!this._isEmailAddressValid(itemAdded)) {
			this.emailAddressErrorMessage = Liferay.Language.get(
				'please-enter-a-valid-email-address'
			);
			this._inputValue = itemAdded;
			this._userEmailAddresses.pop();
		} else {
			this.fetch(this.sharingVerifyEmailAddressURL, {
				emailAddress: itemAdded
			})
				.then(response => response.json())
				.then(result => {
					const {userExists} = result;

					if (!userExists) {
						this.emailAddressErrorMessage = Liferay.Util.sub(
							Liferay.Language.get('user-x-does-not-exist'),
							itemAdded
						);

						this._userEmailAddresses = this._userEmailAddresses.filter(
							item => item.value != itemAdded
						);

						setTimeout(() => {
							this._inputValue = itemAdded;
						}, 0);
					}
				});
		}
	}

	/**
	 * When input has been cleared removes the errors.
	 *
	 * @param  {!Event} event
	 * @private
	 * @review
	 */
	_handleEmailInputChange(event) {
		if (!event.data.value) {
			this._inputValue = '';
			this.emailAddressErrorMessage = '';
		}
	}

	/**
	 * Checks wether the input has emails or not.
	 *
	 * @param {!Event} event
	 * @private
	 * @review
	 */
	_handleEmailRemoved(event) {
		this._userEmailAddresses = event.data.selectedItems;
		this._validateRequiredEmailAddress();
	}

	/**
	 * Save the share permisions
	 * @param {!Event} event
	 * @private
	 * @review
	 */
	_handleSubmit(event) {
		event.preventDefault();

		if (!this.submitting && this._validateRequiredEmailAddress()) {
			this.submitting = true;

			this.fetch(this.shareActionURL, {
				classNameId: this._classNameId,
				classPK: this._classPK,
				shareable: this.shareable,
				sharingEntryPermissionDisplayActionId: this
					.sharingEntryPermissionDisplayActionId,
				userEmailAddress: this._userEmailAddresses
					.map(({value}) => value)
					.join(',')
			})
				.then(response => {
					this.submitting = false;

					const jsonResponse = response.json();

					return response.ok
						? jsonResponse
						: jsonResponse.then(json => {
								const error = new Error(
									json.errorMessage || response.statusText
								);
								throw Object.assign(error, {response});
						  });
				})
				.then(json => {
					parent.Liferay.Portlet.refresh(
						`#p_p_id${this._refererPortletNamespace}`
					);

					this._showNotification(json.successMessage);
				})
				.catch(error => {
					this.submitting = false;

					this._showNotification(error.message, true);
				});
		}
	}

	/**
	 * Show notification in the opener and closes dialog
	 * after is rendered
	 * @param {string} message message for notification
	 * @param {boolean} error Flag indicating if is an error or not
	 * @private
	 * @review
	 */
	_showNotification(message, error) {
		const parentOpenToast = Liferay.Util.getOpener().Liferay.Util.openToast;

		const openToastParams = {
			events: {
				attached: this._closeDialog.bind(this)
			},
			message
		};

		if (error) {
			openToastParams.title = Liferay.Language.get('error');
			openToastParams.type = 'danger';
		}

		parentOpenToast(openToastParams);
	}

	/**
	 * Check if a passed email has a valid format
	 * @private
	 * @review
	 * @return {Boolean} is valid or not
	 */
	_isEmailAddressValid(email) {
		const emailRegex = /.+@.+\..+/i;

		return emailRegex.test(email);
	}

	/**
	 * Check if the userEmailAddresses is filled and show error message
	 * @private
	 * @review
	 * @return {Boolean} is valid or not
	 */
	_validateRequiredEmailAddress() {
		const valid = !!this._userEmailAddresses.length;

		this.emailAddressErrorMessage = valid
			? ''
			: Liferay.Language.get('this-field-is-required');

		return valid;
	}
}

/**
 * State definition.
 * @review
 * @static
 * @type {!Object}
 */
Sharing.STATE = {
	_inputValue: Config.string().internal(),
	emailAddressErrorMessage: Config.string().value(''),
	shareActionURL: Config.string().required(),
	shareable: Config.bool().value(true),
	sharingEntryPermissionDisplayActionId: Config.string().required(),
	sharingUserAutocompleteURL: Config.string().required(),
	sharingVerifyEmailAddressURL: Config.string().required(),
	spritemap: Config.string().required(),
	submitting: Config.bool().value(false)
};

Soy.register(Sharing, templates);

export default Sharing;