Source: UserNameFields.es.js

  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. import {PortletBase, createPortletURL} from 'frontend-js-web';
  15. import {Config} from 'metal-state';
  16. /**
  17. * Handles actions to display user name field for a given locale.
  18. */
  19. class UserNameFields extends PortletBase {
  20. /**
  21. * @inheritDoc
  22. */
  23. attached() {
  24. this.languageIdSelectNode.addEventListener(
  25. 'change',
  26. this._handleSelectChange
  27. );
  28. }
  29. /**
  30. * @inheritDoc
  31. */
  32. created() {
  33. this._handleSelectChange = this._handleSelectChange.bind(this);
  34. this._formDataCache = {};
  35. this._maxLengthsCache = {};
  36. this._loadingAnimationMarkupText = `<div class="loading-animation" id="${this.portletNamespace}loadingUserNameFields"></div>`;
  37. }
  38. /**
  39. * @inheritDoc
  40. */
  41. detached() {
  42. super.detached();
  43. this.languageIdSelectNode.removeEventListener(
  44. 'change',
  45. this._handleSelectChange
  46. );
  47. }
  48. /**
  49. * Updates the user name fields to display the appropriate fields for the
  50. * given locale.
  51. *
  52. * @param {string} languageId The language id used when retrieving the user
  53. * name fields.
  54. */
  55. updateUserNameFields(languageId) {
  56. this._setUp();
  57. this._getURL(languageId)
  58. .then(fetch)
  59. .then((response) => response.text())
  60. .then(this._insertUserNameFields.bind(this))
  61. .then(this._cleanUp.bind(this))
  62. .catch(this._handleError.bind(this));
  63. }
  64. /**
  65. * Caches the values and maxLength attribute values from the current
  66. * user name fields.
  67. *
  68. * @protected
  69. */
  70. _cacheData() {
  71. const formData = new FormData(this.formNode);
  72. if (!formData.forEach) {
  73. return;
  74. }
  75. formData.forEach((value, name) => {
  76. const field = this.userNameFieldsNode.querySelector('#' + name);
  77. if (field) {
  78. this._formDataCache[name] = value;
  79. if (field.hasAttribute('maxLength')) {
  80. this._maxLengthsCache[name] = field.getAttribute(
  81. 'maxLength'
  82. );
  83. }
  84. }
  85. });
  86. }
  87. /**
  88. * Inserts a loading indicator before the user name fields and hide
  89. * the user name fields.
  90. *
  91. * @protected
  92. */
  93. _createLoadingIndicator() {
  94. this.userNameFieldsNode.insertAdjacentHTML(
  95. 'beforebegin',
  96. this._loadingAnimationMarkupText
  97. );
  98. this.userNameFieldsNode.classList.add('hide');
  99. }
  100. _cleanUp() {
  101. this._removeLoadingIndicator();
  102. this._populateData();
  103. }
  104. /**
  105. * Returns a promise containing the URL to be used to retrieve the user
  106. * name fields.
  107. *
  108. * @param {string} languageId The language id to be set on the URL.
  109. * @protected
  110. * @return {Promise} A promise to be resolved with the constructed URL
  111. */
  112. _getURL(languageId) {
  113. return new Promise((resolve) => {
  114. const url = createPortletURL(this.baseURL, {
  115. languageId,
  116. });
  117. resolve(url);
  118. });
  119. }
  120. /**
  121. * Logs any error in the promise chain and removes the loading indicator.
  122. *
  123. * @param {Error} error The error object
  124. * @protected
  125. */
  126. _handleError(error) {
  127. console.error(error);
  128. this._removeLoadingIndicator();
  129. }
  130. /**
  131. * Handles the change event when selecting a new language.
  132. *
  133. * @param {Event} event The event object.
  134. * @protected
  135. */
  136. _handleSelectChange(event) {
  137. this.updateUserNameFields(event.currentTarget.value);
  138. }
  139. /**
  140. * Replaces the HTML of the user name fields with the given HTML.
  141. *
  142. * @param {string} markupText The markup text used to create and insert the
  143. * new user name fields.
  144. * @protected
  145. */
  146. _insertUserNameFields(markupText) {
  147. const temp = document.implementation.createHTMLDocument('');
  148. temp.body.innerHTML = markupText;
  149. const newUserNameFields = temp.getElementById(
  150. `${this.portletNamespace}userNameFields`
  151. );
  152. if (newUserNameFields) {
  153. this.userNameFieldsNode.innerHTML = newUserNameFields.innerHTML;
  154. }
  155. }
  156. /**
  157. * Sets the values and maxLength attributes of the current user name fields
  158. * with the data cached in this._cacheData.
  159. *
  160. * @protected
  161. */
  162. _populateData() {
  163. const entries = Object.entries(this._formDataCache);
  164. entries.forEach(([name, value]) => {
  165. const newField = this.userNameFieldsNode.querySelector('#' + name);
  166. if (newField) {
  167. newField.value = value;
  168. if (Object.hasOwnProperty.call(this._maxLengthsCache, name)) {
  169. newField.setAttribute(
  170. 'maxLength',
  171. this._maxLengthsCache[name]
  172. );
  173. }
  174. }
  175. });
  176. }
  177. /**
  178. * Removes the loading indicator and shows the user name
  179. * fields.
  180. *
  181. * @protected
  182. */
  183. _removeLoadingIndicator() {
  184. const loadingUserNameFields = this.one('#loadingUserNameFields');
  185. if (loadingUserNameFields) {
  186. loadingUserNameFields.remove();
  187. }
  188. this.userNameFieldsNode.classList.remove('hide');
  189. }
  190. /**
  191. * Stores the current user name fields data and creates the loading
  192. * indicator
  193. *
  194. * @protected
  195. */
  196. _setUp() {
  197. this._cacheData();
  198. this._createLoadingIndicator();
  199. }
  200. }
  201. UserNameFields.STATE = {
  202. /**
  203. * Uri to return the user name data.
  204. * @instance
  205. * @memberof UserNameFields
  206. * @type {String}
  207. */
  208. baseURL: Config.required().string().writeOnce(),
  209. /**
  210. * Form node.
  211. * @instance
  212. * @memberof UserNameFields
  213. * @type {String}
  214. */
  215. formNode: Config.required()
  216. .setter((selector) => document.querySelector(selector))
  217. .writeOnce(),
  218. /**
  219. * Language id select field.
  220. * @instance
  221. * @memberof UserNameFields
  222. * @type {String}
  223. */
  224. languageIdSelectNode: Config.required()
  225. .setter((selector) => document.querySelector(selector))
  226. .writeOnce(),
  227. /**
  228. * HTML element containing the user name fields.
  229. * @instance
  230. * @memberof UserNameFields
  231. * @type {String}
  232. */
  233. userNameFieldsNode: Config.required()
  234. .setter((selector) => document.querySelector(selector))
  235. .writeOnce(),
  236. };
  237. export default UserNameFields;