Source: UserNameFields.es.js

import dom from 'metal-dom';
import {EventHandler} from 'metal-events';
import {Config} from 'metal-state';

import PortletBase from 'frontend-js-web/liferay/PortletBase.es';

/**
 * Handles actions to display user name field for a given locale.
 */
class UserNameFields extends PortletBase {

	/**
	 * @inheritDoc
	 */
	attached() {
		this._eventHandler.add(
			dom.on(this.languageIdSelectNode, 'change', this._handleSelectChange.bind(this))
		);
	}

	/**
	 * @inheritDoc
	 */
	created() {
		this._eventHandler = new EventHandler();

		this._formDataCache = {};
		this._maxLengthsCache = {};

		this._loadingAnimationMarkupText = `<div class="loading-animation" id="${this.portletNamespace}loadingUserNameFields"></div>`;
	}

	/**
	 * @inheritDoc
	 */
	detached() {
		super.detached();

		this._eventHandler.removeAllListeners();
	}

	/**
	 * Updates the user name fields to display the appropriate fields for the
	 * given locale.
	 *
	 * @param {string} languageId The language id used when retrieving the user
	 * name fields.
	 */
	updateUserNameFields(languageId) {
		this._setUp();

		this._getURL(languageId)
			.then(fetch)
			.then(
				response => response.text()
			)
			.then(
				this._insertUserNameFields.bind(this)
			)
			.then(
				this._cleanUp.bind(this)
			)
			.catch(
				this._handleError.bind(this)
			);
	}

	/**
	 * Caches the values and maxLength attribute values from the current
	 * user name fields.
	 *
	 * @protected
	 */
	_cacheData() {
		for (const [name, value] of new FormData(this.formNode)) {
			const field = this.userNameFieldsNode.querySelector('#' + name);

			if (field) {
				this._formDataCache[name] = value;

				if (field.hasAttribute('maxLength')) {
					this._maxLengthsCache[name] = field.getAttribute('maxLength');
				}
			}
		}
	}

	/**
	 * Inserts a loading indicator before the user name fields and hide
	 * the user name fields.
	 *
	 * @protected
	 */
	_createLoadingIndicator() {
		this.userNameFieldsNode.insertAdjacentHTML(
			'beforebegin',
			this._loadingAnimationMarkupText
		);

		dom.addClasses(this.userNameFieldsNode, 'hide');
	}

	_cleanUp() {
		this._removeLoadingIndicator();

		this._populateData();
	}

	/**
	 * Returns a promise containing the URL to be used to retrieve the user
	 * name fields.
	 *
	 * @param {string} languageId The language id to be set on the URL.
	 * @protected
	 * @return {Promise} A promise to be resolved with the constructed URL
	 */
	_getURL(languageId) {
		return new Promise(
			resolve => {
				AUI().use(
					'liferay-portlet-url',
					A => {
						const url = Liferay.PortletURL.createURL(this.baseURL);

						url.setParameter('languageId', languageId);

						resolve(url);
					}
				);
			}
		);
	}

	/**
	 * Logs any error in the promise chain and removes the loading indicator.
	 *
	 * @param {Error} error The error object
	 * @protected
	 */
	_handleError(error) {
		console.error(error);

		this._removeLoadingIndicator();
	}

	/**
	 * Handles the change event when selecting a new language.
	 *
	 * @param {Event} event The event object.
	 * @protected
	 */
	_handleSelectChange(event) {
		this.updateUserNameFields(event.currentTarget.value);
	}

	/**
	 * Replaces the HTML of the user name fields with the given HTML.
	 *
	 * @param {string} markupText The markup text used to create and insert the
	 * new user name fields.
	 * @protected
	 */
	_insertUserNameFields(markupText) {
		const temp = document.implementation.createHTMLDocument();

		temp.body.innerHTML = markupText;

		const newUserNameFields = temp.getElementById(`${this.portletNamespace}userNameFields`);

		if (newUserNameFields) {
			this.userNameFieldsNode.innerHTML = newUserNameFields.innerHTML;
		}
	}

	/**
	 * Sets the values and maxLength attributes of the current user name fields
	 * with the data cached in this._cacheData.
	 *
	 * @protected
	 */
	_populateData() {
		for (const [name, value] of Object.entries(this._formDataCache)) {
			const newField = this.userNameFieldsNode.querySelector('#' + name);

			if (newField) {
				newField.value = value;

				if (this._maxLengthsCache.hasOwnProperty(name)) {
					newField.setAttribute('maxLength', this._maxLengthsCache[name]);
				}
			}
		}
	}

	/**
	 * Removes the loading indicator and shows the user name
	 * fields.
	 *
	 * @protected
	 */
	_removeLoadingIndicator() {
		dom.exitDocument(this.one('#loadingUserNameFields'));

		dom.removeClasses(this.userNameFieldsNode, 'hide');
	}

	/**
	 * Stores the current user name fields data and creates the loading
	 * indicator
	 *
	 * @protected
	 */
	_setUp() {
		this._cacheData();

		this._createLoadingIndicator();
	}
}

UserNameFields.STATE = {

	/**
	 * Uri to return the user name data.
	 * @instance
	 * @memberof UserNameFields
	 * @type {String}
	 */
	baseURL: Config.required().string().writeOnce(),

	/**
	 * Form node.
	 * @instance
	 * @memberof UserNameFields
	 * @type {String}
	 */
	formNode: Config.required().setter(dom.toElement).writeOnce(),

	/**
	 * Language id select field.
	 * @instance
	 * @memberof UserNameFields
	 * @type {String}
	 */
	languageIdSelectNode: Config.required().setter(dom.toElement).writeOnce(),

	/**
	 * HTML element containing the user name fields.
	 * @instance
	 * @memberof UserNameFields
	 * @type {String}
	 */
	userNameFieldsNode: Config.required().setter(dom.toElement).writeOnce()
};

export default UserNameFields;