Security update for Core, with self-updated composer
[yaffs-website] / web / core / misc / dialog / dialog.ajax.es6.js
diff --git a/web/core/misc/dialog/dialog.ajax.es6.js b/web/core/misc/dialog/dialog.ajax.es6.js
new file mode 100644 (file)
index 0000000..798673a
--- /dev/null
@@ -0,0 +1,242 @@
+/**
+ * @file
+ * Extends the Drupal AJAX functionality to integrate the dialog API.
+ */
+
+(function ($, Drupal) {
+  /**
+   * Initialize dialogs for Ajax purposes.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the behaviors for dialog ajax functionality.
+   */
+  Drupal.behaviors.dialog = {
+    attach(context, settings) {
+      const $context = $(context);
+
+      // Provide a known 'drupal-modal' DOM element for Drupal-based modal
+      // dialogs. Non-modal dialogs are responsible for creating their own
+      // elements, since there can be multiple non-modal dialogs at a time.
+      if (!$('#drupal-modal').length) {
+        // Add 'ui-front' jQuery UI class so jQuery UI widgets like autocomplete
+        // sit on top of dialogs. For more information see
+        // http://api.jqueryui.com/theming/stacking-elements/.
+        $('<div id="drupal-modal" class="ui-front"/>').hide().appendTo('body');
+      }
+
+      // Special behaviors specific when attaching content within a dialog.
+      // These behaviors usually fire after a validation error inside a dialog.
+      const $dialog = $context.closest('.ui-dialog-content');
+      if ($dialog.length) {
+        // Remove and replace the dialog buttons with those from the new form.
+        if ($dialog.dialog('option', 'drupalAutoButtons')) {
+          // Trigger an event to detect/sync changes to buttons.
+          $dialog.trigger('dialogButtonsChange');
+        }
+
+        // Force focus on the modal when the behavior is run.
+        $dialog.dialog('widget').trigger('focus');
+      }
+
+      const originalClose = settings.dialog.close;
+      // Overwrite the close method to remove the dialog on closing.
+      settings.dialog.close = function (event) {
+        originalClose.apply(settings.dialog, arguments);
+        $(event.target).remove();
+      };
+    },
+
+    /**
+     * Scan a dialog for any primary buttons and move them to the button area.
+     *
+     * @param {jQuery} $dialog
+     *   An jQuery object containing the element that is the dialog target.
+     *
+     * @return {Array}
+     *   An array of buttons that need to be added to the button area.
+     */
+    prepareDialogButtons($dialog) {
+      const buttons = [];
+      const $buttons = $dialog.find('.form-actions input[type=submit], .form-actions a.button');
+      $buttons.each(function () {
+        // Hidden form buttons need special attention. For browser consistency,
+        // the button needs to be "visible" in order to have the enter key fire
+        // the form submit event. So instead of a simple "hide" or
+        // "display: none", we set its dimensions to zero.
+        // See http://mattsnider.com/how-forms-submit-when-pressing-enter/
+        const $originalButton = $(this).css({
+          display: 'block',
+          width: 0,
+          height: 0,
+          padding: 0,
+          border: 0,
+          overflow: 'hidden',
+        });
+        buttons.push({
+          text: $originalButton.html() || $originalButton.attr('value'),
+          class: $originalButton.attr('class'),
+          click(e) {
+            // If the original button is an anchor tag, triggering the "click"
+            // event will not simulate a click. Use the click method instead.
+            if ($originalButton.is('a')) {
+              $originalButton[0].click();
+            }
+            else {
+              $originalButton.trigger('mousedown').trigger('mouseup').trigger('click');
+              e.preventDefault();
+            }
+          },
+        });
+      });
+      return buttons;
+    },
+  };
+
+  /**
+   * Command to open a dialog.
+   *
+   * @param {Drupal.Ajax} ajax
+   *   The Drupal Ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {number} [status]
+   *   The HTTP status code.
+   *
+   * @return {bool|undefined}
+   *   Returns false if there was no selector property in the response object.
+   */
+  Drupal.AjaxCommands.prototype.openDialog = function (ajax, response, status) {
+    if (!response.selector) {
+      return false;
+    }
+    let $dialog = $(response.selector);
+    if (!$dialog.length) {
+      // Create the element if needed.
+      $dialog = $(`<div id="${response.selector.replace(/^#/, '')}" class="ui-front"/>`).appendTo('body');
+    }
+    // Set up the wrapper, if there isn't one.
+    if (!ajax.wrapper) {
+      ajax.wrapper = $dialog.attr('id');
+    }
+
+    // Use the ajax.js insert command to populate the dialog contents.
+    response.command = 'insert';
+    response.method = 'html';
+    ajax.commands.insert(ajax, response, status);
+
+    // Move the buttons to the jQuery UI dialog buttons area.
+    if (!response.dialogOptions.buttons) {
+      response.dialogOptions.drupalAutoButtons = true;
+      response.dialogOptions.buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
+    }
+
+    // Bind dialogButtonsChange.
+    $dialog.on('dialogButtonsChange', () => {
+      const buttons = Drupal.behaviors.dialog.prepareDialogButtons($dialog);
+      $dialog.dialog('option', 'buttons', buttons);
+    });
+
+    // Open the dialog itself.
+    response.dialogOptions = response.dialogOptions || {};
+    const dialog = Drupal.dialog($dialog.get(0), response.dialogOptions);
+    if (response.dialogOptions.modal) {
+      dialog.showModal();
+    }
+    else {
+      dialog.show();
+    }
+
+    // Add the standard Drupal class for buttons for style consistency.
+    $dialog.parent().find('.ui-dialog-buttonset').addClass('form-actions');
+  };
+
+  /**
+   * Command to close a dialog.
+   *
+   * If no selector is given, it defaults to trying to close the modal.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {string} response.selector
+   *   The selector of the dialog.
+   * @param {bool} response.persist
+   *   Whether to persist the dialog element or not.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.closeDialog = function (ajax, response, status) {
+    const $dialog = $(response.selector);
+    if ($dialog.length) {
+      Drupal.dialog($dialog.get(0)).close();
+      if (!response.persist) {
+        $dialog.remove();
+      }
+    }
+
+    // Unbind dialogButtonsChange.
+    $dialog.off('dialogButtonsChange');
+  };
+
+  /**
+   * Command to set a dialog property.
+   *
+   * JQuery UI specific way of setting dialog options.
+   *
+   * @param {Drupal.Ajax} [ajax]
+   *   The Drupal Ajax object.
+   * @param {object} response
+   *   Object holding the server response.
+   * @param {string} response.selector
+   *   Selector for the dialog element.
+   * @param {string} response.optionsName
+   *   Name of a key to set.
+   * @param {string} response.optionValue
+   *   Value to set.
+   * @param {number} [status]
+   *   The HTTP status code.
+   */
+  Drupal.AjaxCommands.prototype.setDialogOption = function (ajax, response, status) {
+    const $dialog = $(response.selector);
+    if ($dialog.length) {
+      $dialog.dialog('option', response.optionName, response.optionValue);
+    }
+  };
+
+  /**
+   * Binds a listener on dialog creation to handle the cancel link.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   *   The dialog instance.
+   * @param {jQuery} $element
+   *   The jQuery collection of the dialog element.
+   * @param {object} [settings]
+   *   Dialog settings.
+   */
+  $(window).on('dialog:aftercreate', (e, dialog, $element, settings) => {
+    $element.on('click.dialog', '.dialog-cancel', (e) => {
+      dialog.close('cancel');
+      e.preventDefault();
+      e.stopPropagation();
+    });
+  });
+
+  /**
+   * Removes all 'dialog' listeners.
+   *
+   * @param {jQuery.Event} e
+   *   The event triggered.
+   * @param {Drupal.dialog~dialogDefinition} dialog
+   *   The dialog instance.
+   * @param {jQuery} $element
+   *   jQuery collection of the dialog element.
+   */
+  $(window).on('dialog:beforeclose', (e, dialog, $element) => {
+    $element.off('.dialog');
+  });
+}(jQuery, Drupal));