PageSourceSearch

https://www.nmp.co.jp/core/misc/dialog/dialog.ajax.js?v=11.3.10

js nmp.co.jp collected 2026-09-24 21:27:15 UTC 10,100 bytes, 303 lines download raw bytes

1/**
2 * @file
3 * Extends the Drupal AJAX functionality to integrate the dialog API.
4 */
5
6(function ($, Drupal, { focusable }) {
7  /**
8   * Initialize dialogs for Ajax purposes.
9   *
10   * @type {Drupal~behavior}
11   *
12   * @prop {Drupal~behaviorAttach} attach
13   *   Attaches the behaviors for dialog ajax functionality.
14   */
15  Drupal.behaviors.dialog = {
16    attach(context, settings) {
17      // Provide a known 'drupal-modal' DOM element for Drupal-based modal
18      // dialogs. Non-modal dialogs are responsible for creating their own
19      // elements, since there can be multiple non-modal dialogs at a time.
20      if (!document.querySelector('#drupal-modal')) {
21        // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
22        // sit on top of dialogs. For more information see
23        // http://api.jqueryui.com/theming/stacking-elements/.
24        document.body.insertAdjacentHTML(
25          'beforeend',
26          '<div id="drupal-modal" class="ui-front" style="display:none"></div>',
27        );
28      }
29
30      // Special behaviors specific when attaching content within a dialog.
31      // These behaviors usually fire after a validation error inside a dialog.
32      if (context !== document) {
33        const dialog = context.closest('.ui-dialog-content');
34        if (dialog) {
35          // Remove and replace the dialog buttons with those from the new form.
36          if ($(dialog).dialog('option', 'drupalAutoButtons')) {
37            // Trigger an event to detect/sync changes to buttons.
38            dialog.dispatchEvent(new CustomEvent('dialogButtonsChange'));
39          }
40
41          setTimeout(function () {
42            // Account for pre-existing focus handling that may have already moved
43            // the focus inside the dialog.
44            if (!dialog.contains(document.activeElement)) {
45              // Move focus to the first focusable element in the next event loop
46              // to allow dialog buttons to be changed first.
47              $(dialog).dialog('instance')._focusedElement = null;
48              $(dialog).dialog('instance')._focusTabbable();
49            }
50          }, 0);
51        }
52      }
53
54      const originalClose = settings.dialog.close;
55      // Overwrite the close method to remove the dialog on closing.
56      settings.dialog.close = function (event, ...args) {
57        originalClose.apply(settings.dialog, [event, ...args]);
58        // Check if the opener element is inside an AJAX container.
59        const $element = $(event.target);
60        const ajaxContainer = $element.data('uiDialog')
61          ? $element
62              .data('uiDialog')
63              .opener.closest('[data-drupal-ajax-container]')
64          : [];
65
66        // If the opener element was in an ajax container, and focus is on the
67        // body element, we can assume focus was lost. To recover, focus is
68        // moved to the first focusable element in the container.
69        if (
70          ajaxContainer.length &&
71          (document.activeElement === document.body ||
72            $(document.activeElement).not(':visible'))
73        ) {
74          const focusableChildren = focusable(ajaxContainer[0]);
75          if (focusableChildren.length > 0) {
76            setTimeout(() => {
77              focusableChildren[0].focus();
78            }, 0);
79          }
80        }
81        $(event.target).remove();
82      };
83    },
84
85    /**
86     * Scan a dialog for any primary buttons and move them to the button area.
87     *
88     * @param {jQuery} $dialog
89     *   A jQuery object containing the element that is the dialog target.
90     *
91     * @return {Array}
92     *   An array of buttons that need to be added to the button area.
93     */
94    prepareDialogButtons($dialog) {
95      const buttons = [];
96      const buttonSelectors =
97        '.form-actions input[type=submit], .form-actions a.button, .form-actions a.action-link';
98      const buttonElements = $dialog[0].querySelectorAll(buttonSelectors);
99
100      buttonElements.forEach((button) => {
101        button.style.display = 'none';
102        buttons.push({
103          text: button.innerHTML || button.getAttribute('value'),
104          class: button.getAttribute('class'),
105          'data-once': button.dataset.once,
106          click(e) {
107            if (button.tagName === 'A') {
108              button.click();
109            } else {
110              ['mousedown', 'mouseup', 'click'].forEach((event) =>
111                button.dispatchEvent(new MouseEvent(event)),
112              );
113            }
114            e.preventDefault();
115          },
116        });
117      });
118      return buttons;
119    },
120  };
121
122  /**
123   * Command to open a dialog.
124   *
125   * @param {Drupal.Ajax} ajax
126   *   The Drupal Ajax object.
127   * @param {object} response
128   *   Object holding the server response.
129   * @param {number} [status]
130   *   The HTTP status code.
131   *
132   * @return {boolean|undefined}
133   *   Returns false if there was no selector property in the response object.
134   */
135  Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
136    if (!response.selector) {
137      return false;
138    }
139    let dialog = document.querySelector(response.selector);
140    if (!dialog) {
141      // Create the element if needed.
142      dialog = document.createElement('div');
143      dialog.id = response.selector.replace(/^#/, '');
144      dialog.classList.add('ui-front');
145      document.body.appendChild(dialog);
146    }
147    // Set up the wrapper, if there isn't one.
148    if (!ajax.wrapper) {
149      ajax.wrapper = dialog.id;
150    }
151
152    // Use the ajax.js insert command to populate the dialog contents.
153    response.command = 'insert';
154    response.method = 'html';
155    ajax.commands.insert(ajax, response, status);
156
157    // Move the buttons to the jQuery UI dialog buttons area.
158    response.dialogOptions = response.dialogOptions || {};
159    if (typeof response.dialogOptions.drupalAutoButtons === 'undefined') {
160      response.dialogOptions.drupalAutoButtons = true;
161    } else if (response.dialogOptions.drupalAutoButtons === 'false') {
162      response.dialogOptions.drupalAutoButtons = false;
163    } else {
164      response.dialogOptions.drupalAutoButtons =
165        !!response.dialogOptions.drupalAutoButtons;
166    }
167    if (
168      !response.dialogOptions.buttons &&
169      response.dialogOptions.drupalAutoButtons
170    ) {
171      response.dialogOptions.buttons =
172        Drupal.behaviors.dialog.prepareDialogButtons($(dialog));
173    }
174
175    const dialogButtonsChange = () => {
176      const buttons = Drupal.behaviors.dialog.prepareDialogButtons($(dialog));
177      $(dialog).dialog('option', 'buttons', buttons);
178    };
179
180    // Bind dialogButtonsChange.
181    dialog.addEventListener('dialogButtonsChange', dialogButtonsChange);
182    dialog.addEventListener('dialog:beforeclose', (event) => {
183      dialog.removeEventListener('dialogButtonsChange', dialogButtonsChange);
184    });
185
186    // Open the dialog itself.
187    const createdDialog = Drupal.dialog(dialog, response.dialogOptions);
188    if (response.dialogOptions.modal) {
189      createdDialog.showModal();
190    } else {
191      createdDialog.show();
192    }
193
194    // Add the standard Drupal class for buttons for style consistency.
195    dialog.parentElement
196      ?.querySelector('.ui-dialog-buttonset')
197      ?.classList.add('form-actions');
198  };
199
200  /**
201   * Command to close a dialog.
202   *
203   * If no selector is given, it defaults to trying to close the modal.
204   *
205   * @param {Drupal.Ajax} [ajax]
206   *   The ajax object.
207   * @param {object} response
208   *   Object holding the server response.
209   * @param {string} response.selector
210   *   The selector of the dialog.
211   * @param {boolean} response.persist
212   *   Whether to persist the dialog element or not.
213   * @param {number} [status]
214   *   The HTTP status code.
215   */
216  Drupal.AjaxCommands.prototype.closeDialog = function (
217    ajax,
218    response,
219    status,
220  ) {
221    const dialog = document.querySelector(response.selector);
222    if (dialog) {
223      Drupal.dialog(dialog).close();
224      if (!response.persist) {
225        dialog.remove();
226      }
227    }
228  };
229
230  /**
231   * Command to set a dialog property.
232   *
233   * JQuery UI specific way of setting dialog options.
234   *
235   * @param {Drupal.Ajax} [ajax]
236   *   The Drupal Ajax object.
237   * @param {object} response
238   *   Object holding the server response.
239   * @param {string} response.selector
240   *   Selector for the dialog element.
241   * @param {string} response.optionsName
242   *   Name of a key to set.
243   * @param {string} response.optionValue
244   *   Value to set.
245   * @param {number} [status]
246   *   The HTTP status code.
247   */
248  Drupal.AjaxCommands.prototype.setDialogOption = function (
249    ajax,
250    response,
251    status,
252  ) {
253    const dialog = document.querySelector(response.selector);
254    if (dialog) {
255      $(dialog).dialog('option', response.optionName, response.optionValue);
256    }
257  };
258
259  /**
260   * Binds a listener on dialog creation to handle the cancel link.
261   *
262   * @param {DrupalDialogEvent} e
263   *   The event triggered.
264   * @param {Drupal.dialog~dialogDefinition} dialog
265   *   The dialog instance.
266   * @param {object} [settings]
267   *   Dialog settings.
268   */
269  window.addEventListener('dialog:aftercreate', (event) => {
270    const dialog = event.dialog;
271    const cancelButton = event.target.querySelector('.dialog-cancel');
272    const cancelClick = (e) => {
273      dialog.close('cancel');
274      e.preventDefault();
275      e.stopPropagation();
276    };
277    cancelButton?.removeEventListener('click', cancelClick);
278    cancelButton?.addEventListener('click', cancelClick);
279  });
280
281  /**
282   * Ajax command to open URL in a modal dialog.
283   *
284   * @param {Drupal.Ajax} [ajax]
285   *   An Ajax object.
286   * @param {object} response
287   *   The Ajax response.
288   */
289  Drupal.AjaxCommands.prototype.openModalDialogWithUrl = function (
290    ajax,
291    response,
292  ) {
293    const dialogOptions = response.dialogOptions || {};
294    const elementSettings = {
295      progress: { type: 'throbber' },
296      dialogType: 'modal',
297      dialog: dialogOptions,
298      url: response.url,
299      httpMethod: 'GET',
300    };
301    Drupal.ajax(elementSettings).execute();
302  };
303})(jQuery, Drupal, window.tabbable);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.