util.es6.js 6.7 KB

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