util.es6.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /**
  2. * @file
  3. * Provides utility functions for Quick Edit.
  4. */
  5. (function($, Drupal) {
  6. /**
  7. * @namespace
  8. */
  9. Drupal.quickedit.util = Drupal.quickedit.util || {};
  10. /**
  11. * @namespace
  12. */
  13. Drupal.quickedit.util.constants = {};
  14. /**
  15. *
  16. * @type {string}
  17. */
  18. Drupal.quickedit.util.constants.transitionEnd =
  19. 'transitionEnd.quickedit webkitTransitionEnd.quickedit transitionend.quickedit msTransitionEnd.quickedit oTransitionEnd.quickedit';
  20. /**
  21. * Converts a field id into a formatted url path.
  22. *
  23. * @example
  24. * Drupal.quickedit.util.buildUrl(
  25. * 'node/1/body/und/full',
  26. * '/quickedit/form/!entity_type/!id/!field_name/!langcode/!view_mode'
  27. * );
  28. *
  29. * @param {string} id
  30. * The id of an editable field.
  31. * @param {string} urlFormat
  32. * The Controller route for field processing.
  33. *
  34. * @return {string}
  35. * The formatted URL.
  36. */
  37. Drupal.quickedit.util.buildUrl = function(id, urlFormat) {
  38. const parts = id.split('/');
  39. return Drupal.formatString(decodeURIComponent(urlFormat), {
  40. '!entity_type': parts[0],
  41. '!id': parts[1],
  42. '!field_name': parts[2],
  43. '!langcode': parts[3],
  44. '!view_mode': parts[4],
  45. });
  46. };
  47. /**
  48. * Shows a network error modal dialog.
  49. *
  50. * @param {string} title
  51. * The title to use in the modal dialog.
  52. * @param {string} message
  53. * The message to use in the modal dialog.
  54. */
  55. Drupal.quickedit.util.networkErrorModal = function(title, message) {
  56. const $message = $(`<div>${message}</div>`);
  57. const networkErrorModal = Drupal.dialog($message.get(0), {
  58. title,
  59. dialogClass: 'quickedit-network-error',
  60. buttons: [
  61. {
  62. text: Drupal.t('OK'),
  63. click() {
  64. networkErrorModal.close();
  65. },
  66. primary: true,
  67. },
  68. ],
  69. create() {
  70. $(this)
  71. .parent()
  72. .find('.ui-dialog-titlebar-close')
  73. .remove();
  74. },
  75. close(event) {
  76. // Automatically destroy the DOM element that was used for the dialog.
  77. $(event.target).remove();
  78. },
  79. });
  80. networkErrorModal.showModal();
  81. };
  82. /**
  83. * @namespace
  84. */
  85. Drupal.quickedit.util.form = {
  86. /**
  87. * Loads a form, calls a callback to insert.
  88. *
  89. * Leverages {@link Drupal.Ajax}' ability to have scoped (per-instance)
  90. * command implementations to be able to call a callback.
  91. *
  92. * @param {object} options
  93. * An object with the following keys:
  94. * @param {string} options.fieldID
  95. * The field ID that uniquely identifies the field for which this form
  96. * will be loaded.
  97. * @param {bool} options.nocssjs
  98. * Boolean indicating whether no CSS and JS should be returned (necessary
  99. * when the form is invisible to the user).
  100. * @param {bool} options.reset
  101. * Boolean indicating whether the data stored for this field's entity in
  102. * PrivateTempStore should be used or reset.
  103. * @param {function} callback
  104. * A callback function that will receive the form to be inserted, as well
  105. * as the ajax object, necessary if the callback wants to perform other
  106. * Ajax commands.
  107. */
  108. load(options, callback) {
  109. const fieldID = options.fieldID;
  110. // Create a Drupal.ajax instance to load the form.
  111. const formLoaderAjax = Drupal.ajax({
  112. url: Drupal.quickedit.util.buildUrl(
  113. fieldID,
  114. Drupal.url(
  115. 'quickedit/form/!entity_type/!id/!field_name/!langcode/!view_mode',
  116. ),
  117. ),
  118. submit: {
  119. nocssjs: options.nocssjs,
  120. reset: options.reset,
  121. },
  122. error(xhr, url) {
  123. // Show a modal to inform the user of the network error.
  124. const fieldLabel = Drupal.quickedit.metadata.get(fieldID, 'label');
  125. const message = Drupal.t(
  126. 'Could not load the form for <q>@field-label</q>, either due to a website problem or a network connection problem.<br>Please try again.',
  127. { '@field-label': fieldLabel },
  128. );
  129. Drupal.quickedit.util.networkErrorModal(
  130. Drupal.t('Network problem!'),
  131. message,
  132. );
  133. // Change the state back to "candidate", to allow the user to start
  134. // in-place editing of the field again.
  135. const fieldModel = Drupal.quickedit.app.model.get('activeField');
  136. fieldModel.set('state', 'candidate');
  137. },
  138. });
  139. // Implement a scoped quickeditFieldForm AJAX command: calls the callback.
  140. formLoaderAjax.commands.quickeditFieldForm = function(
  141. ajax,
  142. response,
  143. status,
  144. ) {
  145. callback(response.data, ajax);
  146. Drupal.ajax.instances[this.instanceIndex] = null;
  147. };
  148. // This will ensure our scoped quickeditFieldForm AJAX command gets
  149. // called.
  150. formLoaderAjax.execute();
  151. },
  152. /**
  153. * Creates a {@link Drupal.Ajax} instance that is used to save a form.
  154. *
  155. * @param {object} options
  156. * Submit options to the form.
  157. * @param {bool} options.nocssjs
  158. * Boolean indicating whether no CSS and JS should be returned (necessary
  159. * when the form is invisible to the user).
  160. * @param {Array.<string>} options.other_view_modes
  161. * Array containing view mode IDs (of other instances of this field on the
  162. * page).
  163. * @param {jQuery} $submit
  164. * The submit element.
  165. *
  166. * @return {Drupal.Ajax}
  167. * A {@link Drupal.Ajax} instance.
  168. */
  169. ajaxifySaving(options, $submit) {
  170. // Re-wire the form to handle submit.
  171. const settings = {
  172. url: $submit.closest('form').attr('action'),
  173. setClick: true,
  174. event: 'click.quickedit',
  175. progress: false,
  176. submit: {
  177. nocssjs: options.nocssjs,
  178. other_view_modes: options.other_view_modes,
  179. },
  180. /**
  181. * Reimplement the success handler.
  182. *
  183. * Ensure {@link Drupal.attachBehaviors} does not get called on the
  184. * form.
  185. *
  186. * @param {Drupal.AjaxCommands~commandDefinition} response
  187. * The Drupal AJAX response.
  188. * @param {number} [status]
  189. * The HTTP status code.
  190. */
  191. success(response, status) {
  192. Object.keys(response || {}).forEach(i => {
  193. if (response[i].command && this.commands[response[i].command]) {
  194. this.commands[response[i].command](this, response[i], status);
  195. }
  196. });
  197. },
  198. base: $submit.attr('id'),
  199. element: $submit[0],
  200. };
  201. return Drupal.ajax(settings);
  202. },
  203. /**
  204. * Cleans up the {@link Drupal.Ajax} instance that is used to save the form.
  205. *
  206. * @param {Drupal.Ajax} ajax
  207. * A {@link Drupal.Ajax} instance that was returned by
  208. * {@link Drupal.quickedit.form.ajaxifySaving}.
  209. */
  210. unajaxifySaving(ajax) {
  211. $(ajax.element).off('click.quickedit');
  212. },
  213. };
  214. })(jQuery, Drupal);