diff --git a/core/misc/ajax.js b/core/misc/ajax.js
index d80c2c5a8961f007273ccce98bcda6cca97d57a7..5ec87f5356720eb98986d25068e2bc6a67e6ea34 100644
--- a/core/misc/ajax.js
+++ b/core/misc/ajax.js
@@ -2,20 +2,6 @@
 
   "use strict";
 
-  /**
-   * Provides Ajax page updating via jQuery $.ajax (Asynchronous JavaScript and XML).
-   *
-   * Ajax is a method of making a request via JavaScript while viewing an HTML
-   * page. The request returns an array of commands encoded in JSON, which is
-   * then executed to make any changes that are necessary to the page.
-   *
-   * Drupal uses this file to enhance form elements with #ajax['url'] and
-   * #ajax['wrapper'] properties. If set, this file will automatically be included
-   * to provide Ajax capabilities.
-   */
-
-  Drupal.ajax = Drupal.ajax || {};
-
   /**
    * Attaches the Ajax behavior to each Ajax form element.
    */
@@ -29,7 +15,8 @@
         }
         $(element_settings.selector).once('drupal-ajax').each(function () {
           element_settings.element = this;
-          Drupal.ajax[element_settings.selector] = new Drupal.ajax(base, this, element_settings);
+          element_settings.base = base;
+          Drupal.ajax(element_settings);
         });
       }
 
@@ -54,8 +41,9 @@
         }
         element_settings.dialogType = $(this).data('dialog-type');
         element_settings.dialog = $(this).data('dialog-options');
-        var baseUseAjax = $(this).attr('id');
-        Drupal.ajax[baseUseAjax] = new Drupal.ajax(baseUseAjax, this, element_settings);
+        element_settings.base = $(this).attr('id');
+        element_settings.element = this;
+        Drupal.ajax(element_settings);
       });
 
       // This class means to submit the form to the action using Ajax.
@@ -72,15 +60,16 @@
         element_settings.event = 'click';
         // Clicked form buttons look better with the throbber than the progress bar.
         element_settings.progress = {'type': 'throbber'};
+        element_settings.base = $(this).attr('id');
+        element_settings.element = this;
 
-        var baseUseAjaxSubmit = $(this).attr('id');
-        Drupal.ajax[baseUseAjaxSubmit] = new Drupal.ajax(baseUseAjaxSubmit, this, element_settings);
+        Drupal.ajax(element_settings);
       });
     }
   };
 
   /**
-   * Extends Error to provide handling for Errors in AJAX
+   * Extends Error to provide handling for Errors in Ajax.
    */
   Drupal.AjaxError = function (xmlhttp, uri) {
 
@@ -115,7 +104,7 @@
       responseText = "\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText)});
     }
     catch (e) {
-      // empty
+      // Empty.
     }
 
     // Make the responseText more readable by stripping HTML tags and newlines.
@@ -133,32 +122,114 @@
   Drupal.AjaxError.prototype.constructor = Drupal.AjaxError;
 
   /**
-   * Ajax object.
+   * Provides Ajax page updating via jQuery $.ajax.
+   *
+   * This function is designed to improve developer experience by wrapping the
+   * initialization of Drupal.Ajax objects and storing all created object in the
+   * Drupal.ajax.instances array.
+   *
+   * @example
+   * Drupal.behaviors.myCustomAJAXStuff = {
+   *   attach: function (context, settings) {
+   *
+   *     var ajaxSettings = {
+   *       url: 'my/url/path',
+   *       // If the old version of Drupal.ajax() needs to be used those
+   *       // properties can be added
+   *       base: 'myBase',
+   *       element: $(context).find('.someElement')
+   *     };
+   *
+   *     var myAjaxObject = Drupal.ajax(ajaxSettings);
+   *
+   *     // Declare a new Ajax command specifically for this Ajax object.
+   *     myAjaxObject.commands.insert = function (ajax, response, status) {
+   *       $('#my-wrapper').append(response.data);
+   *       alert('New content was appended to #my-wrapper');
+   *     };
+   *
+   *     // This command will remove this Ajax object from the page.
+   *     myAjaxObject.commands.destroyObject = function (ajax, response, status) {
+   *       Drupal.ajax.instances[this.instanceIndex] = null;
+   *     };
+   *
+   *     // Programmatically trigger the Ajax request.
+   *     myAjaxObject.execute();
+   *   }
+   * };
+   *
+   * @see Drupal.AjaxCommands
+   *
+   * @param {object} settings
+   *   The settings object passed to Drupal.Ajax constructor.
+   * @param {string} [settings.base]
+   *   Base is passed to Drupal.Ajax constructor as the 'base' parameter.
+   * @param {HTMLElement} [settings.element]
+   *   Element parameter of Drupal.Ajax constructor, element on which
+   *   event listeners will be bound.
+   *
+   * @return {Drupal.Ajax}
+   */
+  Drupal.ajax = function (settings) {
+    if (arguments.length !== 1) {
+      throw new Error('Drupal.ajax() function must be called with one configuration object only');
+    }
+    // Map those config keys to variables for the old Drupal.ajax function.
+    var base = settings.base || false;
+    var element = settings.element || false;
+    delete settings.base;
+    delete settings.element;
+
+    // By default do not display progress for ajax calls without an element.
+    if (!settings.progress && !element) {
+      settings.progress = false;
+    }
+
+    var ajax = new Drupal.Ajax(base, element, settings);
+    ajax.instanceIndex = Drupal.ajax.instances.length;
+    Drupal.ajax.instances.push(ajax);
+
+    return ajax;
+  };
+
+  /**
+   * Contains all created Ajax objects.
+   *
+   * @type {Array}
+   */
+  Drupal.ajax.instances = [];
+
+  /**
+   * Ajax constructor.
+   *
+   * The Ajax request returns an array of commands encoded in JSON, which is
+   * then executed to make any changes that are necessary to the page.
+   *
+   * Drupal uses this file to enhance form elements with #ajax['url'] and
+   * #ajax['wrapper'] properties. If set, this file will automatically be
+   * included to provide Ajax capabilities.
    *
-   * All Ajax objects on a page are accessible through the global Drupal.ajax
-   * object and are keyed by the submit button's ID. You can access them from
-   * your module's JavaScript file to override properties or functions.
+   * @constructor
    *
-   * For example, if your Ajax enabled button has the ID 'edit-submit', you can
-   * redefine the function that is called to insert the new content like this
-   * (inside a Drupal.behaviors attach block):
-   * @code
-   *    Drupal.behaviors.myCustomAJAXStuff = {
-   *      attach: function (context, settings) {
-   *        Drupal.ajax['edit-submit'].commands.insert = function (ajax, response, status) {
-   *          new_content = $(response.data);
-   *          $('#my-wrapper').append(new_content);
-   *          alert('New content was appended to #my-wrapper');
-   *        }
-   *      }
-   *    };
-   * @endcode
+   * @param {string} [base]
+   *   Base parameter of Drupal.Ajax constructor
+   * @param {HTMLElement} [element]
+   *   Element parameter of Drupal.Ajax constructor, element on which
+   *   event listeners will be bound.
+   * @param {object} element_settings
+   * @param {string} element_settings.url
+   *   Target of the Ajax request.
+   * @param {string} [element_settings.event]
+   *   Event bound to settings.element which will trigger the Ajax request.
+   * @param {string} [element_settings.method]
+   *   Name of the jQuery method used to insert new content in the targeted
+   *   element.
    */
-  Drupal.ajax = function (base, element, element_settings) {
+  Drupal.Ajax = function (base, element, element_settings) {
     var defaults = {
-      event: 'mousedown',
+      event: element ? 'mousedown' : null,
       keypress: true,
-      selector: '#' + base,
+      selector: base ? '#' + base : null,
       effect: 'none',
       speed: 'none',
       method: 'replaceWith',
@@ -174,6 +245,7 @@
     $.extend(this, defaults, element_settings);
 
     this.commands = new Drupal.AjaxCommands();
+    this.instanceIndex = false;
 
     // @todo Remove this after refactoring the PHP code to:
     //   - Call this 'selector'.
@@ -188,24 +260,25 @@
 
     // If there isn't a form, jQuery.ajax() will be used instead, allowing us to
     // bind Ajax to links as well.
-    if (this.element.form) {
+    if (this.element && this.element.form) {
       this.$form = $(this.element.form);
     }
 
     // If no Ajax callback URL was given, use the link href or form action.
     if (!this.url) {
-      if ($(element).is('a')) {
-        this.url = $(element).attr('href');
+      var $element = $(this.element);
+      if ($element.is('a')) {
+        this.url = $element.attr('href');
       }
-      else if (element.form) {
+      else if (this.element && element.form) {
         this.url = this.$form.attr('action');
 
         // @todo If there's a file input on this form, then jQuery will submit the
-        //   AJAX response with a hidden Iframe rather than the XHR object. If the
+        //   Ajax response with a hidden Iframe rather than the XHR object. If the
         //   response to the submission is an HTTP redirect, then the Iframe will
         //   follow it, but the server won't content negotiate it correctly,
         //   because there won't be an ajax_iframe_upload POST variable. Until we
-        //   figure out a work around to this problem, we prevent AJAX-enabling
+        //   figure out a work around to this problem, we prevent Ajax-enabling
         //   elements that submit to the same URL as the form when there's a file
         //   input. For example, this means the Delete button on the edit form of
         //   an Article node doesn't open its confirmation form in a dialog.
@@ -289,7 +362,7 @@
 
     // If necessary, prevent the browser default action of an additional event.
     // For example, prevent the browser default action of a click, even if the
-    // AJAX behavior binds to mousedown.
+    // Ajax behavior binds to mousedown.
     if (element_settings.prevent) {
       $(ajax.element).on(element_settings.prevent, false);
     }
@@ -303,6 +376,30 @@
    */
   Drupal.ajax.WRAPPER_FORMAT = '_wrapper_format';
 
+  /**
+   * Execute the ajax request.
+   *
+   * Allows developers to execute an Ajax request manually without specifying
+   * an event to respond to.
+   */
+  Drupal.Ajax.prototype.execute = function () {
+    // Do not perform another ajax command if one is already in progress.
+    if (this.ajaxing) {
+      return;
+    }
+
+    try {
+      this.beforeSerialize(this.element, this.options);
+      $.ajax(this.options);
+    }
+    catch (e) {
+      // Unset the ajax.ajaxing flag here because it won't be unset during
+      // the complete response.
+      this.ajaxing = false;
+      window.alert("An error occurred while attempting to process " + this.options.url + ": " + e.message);
+    }
+  };
+
   /**
    * Handle a key press.
    *
@@ -313,7 +410,7 @@
    * and 32. RETURN is often used to submit a form when in a textfield, and
    * SPACE is often used to activate an element without submitting.
    */
-  Drupal.ajax.prototype.keypressResponse = function (element, event) {
+  Drupal.Ajax.prototype.keypressResponse = function (element, event) {
     // Create a synonym for this to reduce code confusion.
     var ajax = this;
 
@@ -336,16 +433,16 @@
    * When an event that triggers an Ajax response happens, this method will
    * perform the actual Ajax call. It is bound to the event using
    * bind() in the constructor, and it uses the options specified on the
-   * ajax object.
+   * Ajax object.
    */
-  Drupal.ajax.prototype.eventResponse = function (element, event) {
+  Drupal.Ajax.prototype.eventResponse = function (element, event) {
     event.preventDefault();
     event.stopPropagation();
 
     // Create a synonym for this to reduce code confusion.
     var ajax = this;
 
-    // Do not perform another ajax command if one is already in progress.
+    // Do not perform another Ajax command if one is already in progress.
     if (ajax.ajaxing) {
       return;
     }
@@ -383,7 +480,7 @@
    * Runs before the beforeSend() handler (see below), and unlike that one, runs
    * before field data is collected.
    */
-  Drupal.ajax.prototype.beforeSerialize = function (element, options) {
+  Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
     // Allow detaching behaviors to update field values before collecting them.
     // This is only needed when field values are added to the POST data, so only
     // when there is a form such that this.$form.ajaxSubmit() is used instead of
@@ -419,7 +516,7 @@
   /**
    * Modify form values prior to form submission.
    */
-  Drupal.ajax.prototype.beforeSubmit = function (form_values, element, options) {
+  Drupal.Ajax.prototype.beforeSubmit = function (form_values, element, options) {
     // This function is left empty to make it simple to override for modules
     // that wish to add functionality here.
   };
@@ -427,7 +524,7 @@
   /**
    * Prepare the Ajax request before it is sent.
    */
-  Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) {
+  Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
     // For forms without file inputs, the jQuery Form plugin serializes the form
     // values, and then calls jQuery's $.ajax() function, which invokes this
     // handler. In this circumstance, options.extraData is never used. For forms
@@ -462,36 +559,57 @@
     // from changing its value.
     $(this.element).prop('disabled', true);
 
-    // Insert progressbar or throbber.
-    if (this.progress.type === 'bar') {
-      var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
-      if (this.progress.message) {
-        progressBar.setProgress(-1, this.progress.message);
-      }
-      if (this.progress.url) {
-        progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
-      }
-      this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar');
-      this.progress.object = progressBar;
-      $(this.element).after(this.progress.element);
+    if (!this.progress || !this.progress.type) {
+      return;
     }
-    else if (this.progress.type === 'throbber') {
-      this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber">&nbsp;</div></div>');
-      if (this.progress.message) {
-        this.progress.element.find('.throbber').after('<div class="message">' + this.progress.message + '</div>');
-      }
+
+    // Insert progress indicator
+    var progressIndicatorMethod = 'setProgressIndicator' + this.progress.type.slice(0, 1).toUpperCase() + this.progress.type.slice(1).toLowerCase();
+    if (progressIndicatorMethod in this && typeof this[progressIndicatorMethod] === 'function') {
+      this[progressIndicatorMethod].call(this);
       $(this.element).after(this.progress.element);
     }
-    else if (this.progress.type === 'fullscreen') {
-      this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen">&nbsp;</div>');
-      $('body').after(this.progress.element);
+  };
+
+  /**
+   * Sets the progress bar progress indicator.
+   */
+  Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
+    var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
+    if (this.progress.message) {
+      progressBar.setProgress(-1, this.progress.message);
+    }
+    if (this.progress.url) {
+      progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500);
     }
+    this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar');
+    this.progress.object = progressBar;
+    $(this.element).after(this.progress.element);
+  };
+
+  /**
+   * Sets the throbber progress indicator.
+   */
+  Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
+    this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber">&nbsp;</div></div>');
+    if (this.progress.message) {
+      this.progress.element.find('.throbber').after('<div class="message">' + this.progress.message + '</div>');
+    }
+    $(this.element).after(this.progress.element);
+  };
+
+  /**
+   * Sets the fullscreen progress indicator.
+   */
+  Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
+    this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen">&nbsp;</div>');
+    $('body').after(this.progress.element);
   };
 
   /**
    * Handler for the form redirection completion.
    */
-  Drupal.ajax.prototype.success = function (response, status) {
+  Drupal.Ajax.prototype.success = function (response, status) {
     // Remove the progress element.
     if (this.progress.element) {
       $(this.progress.element).remove();
@@ -524,7 +642,7 @@
   /**
    * Build an effect object which tells us how to apply the effect when adding new HTML.
    */
-  Drupal.ajax.prototype.getEffect = function (response) {
+  Drupal.Ajax.prototype.getEffect = function (response) {
     var type = response.effect || this.effect;
     var speed = response.speed || this.speed;
 
@@ -551,7 +669,7 @@
   /**
    * Handler for the form redirection error.
    */
-  Drupal.ajax.prototype.error = function (response, uri) {
+  Drupal.Ajax.prototype.error = function (response, uri) {
     // Remove the progress element.
     if (this.progress.element) {
       $(this.progress.element).remove();
diff --git a/core/modules/ckeditor/js/ckeditor.js b/core/modules/ckeditor/js/ckeditor.js
index 3df3366a3ce76b6608309542de36a7719f4b6412..59f8b2e19d3be0addc7d5ca54366b56cf0bffef2 100644
--- a/core/modules/ckeditor/js/ckeditor.js
+++ b/core/modules/ckeditor/js/ckeditor.js
@@ -158,23 +158,20 @@
 
       // Add a "Loading…" message, hide it underneath the CKEditor toolbar, create
       // a Drupal.ajax instance to load the dialog and trigger it.
-      var $content = $('<div class="ckeditor-dialog-loading"><span style="top: -40px;" class="ckeditor-dialog-loading-link"><a>' + Drupal.t('Loading...') + '</a></span></div>');
+      var $content = $('<div class="ckeditor-dialog-loading"><span style="top: -40px;" class="ckeditor-dialog-loading-link">' + Drupal.t('Loading...') + '</span></div>');
       $content.appendTo($target);
 
-      new Drupal.ajax('ckeditor-dialog', $content.find('a').get(0), {
+      var ckeditorAjaxDialog = Drupal.ajax({
         dialog: dialogSettings,
         dialogType: 'modal',
         selector: '.ckeditor-dialog-loading-link',
         url: url,
-        event: 'ckeditor-internal.ckeditor',
         progress: {'type': 'throbber'},
         submit: {
           editor_object: existingValues
         }
       });
-      $content.find('a')
-        .on('click', function () { return false; })
-        .trigger('ckeditor-internal.ckeditor');
+      ckeditorAjaxDialog.execute();
 
       // After a short delay, show "Loading…" message.
       window.setTimeout(function () {
diff --git a/core/modules/editor/js/editor.formattedTextEditor.js b/core/modules/editor/js/editor.formattedTextEditor.js
index faf4a6d10f0ac02d6c6784d4e6cd0385404d6e87..e624f67d7431d5ac51bf12c29c0dfc43666e6292 100644
--- a/core/modules/editor/js/editor.formattedTextEditor.js
+++ b/core/modules/editor/js/editor.formattedTextEditor.js
@@ -171,11 +171,9 @@
       var fieldID = this.fieldModel.get('fieldID');
 
       // Create a Drupal.ajax instance to load the form.
-      var textLoaderAjax = new Drupal.ajax(fieldID, this.$el, {
+      var textLoaderAjax = Drupal.ajax({
         url: Drupal.quickedit.util.buildUrl(fieldID, Drupal.url('editor/!entity_type/!id/!field_name/!langcode/!view_mode')),
-        event: 'editor-internal.editor',
-        submit: {nocssjs: true},
-        progress: {type: null} // No progress indicator.
+        submit: {nocssjs: true}
       });
 
       // Implement a scoped editorGetUntransformedText AJAX command: calls the
@@ -186,7 +184,7 @@
 
       // This will ensure our scoped editorGetUntransformedText AJAX command
       // gets called.
-      this.$el.trigger('editor-internal.editor');
+      textLoaderAjax.execute();
     }
 
   });
diff --git a/core/modules/quickedit/js/models/EntityModel.js b/core/modules/quickedit/js/models/EntityModel.js
index ab4dbd9014f66370282a288b565f7140be6d7571..0760aed1e0b2d625986a4583f008205bc94e3785 100644
--- a/core/modules/quickedit/js/models/EntityModel.js
+++ b/core/modules/quickedit/js/models/EntityModel.js
@@ -362,18 +362,10 @@
     save: function (options) {
       var entityModel = this;
 
-      // @todo Simplify this once https://drupal.org/node/1533366 lands.
-      // @see https://drupal.org/node/2029999.
-      var id = 'quickedit-save-entity';
-      // Create a temporary element to be able to use Drupal.ajax.
-      var $el = $('#quickedit-entity-toolbar').find('.action-save'); // This is the span element inside the button.
       // Create a Drupal.ajax instance to save the entity.
-      var entitySaverAjax = new Drupal.ajax(id, $el, {
+      var entitySaverAjax = Drupal.ajax({
         url: Drupal.url('quickedit/entity/' + entityModel.get('entityID')),
-        event: 'quickedit-save.quickedit',
-        progress: {type: 'none'},
         error: function () {
-          $el.off('quickedit-save.quickedit');
           // Let the Drupal.quickedit.EntityModel Backbone model's error()=
           // method handle errors.
           options.error.call(entityModel);
@@ -381,8 +373,6 @@
       });
       // Entity saved successfully.
       entitySaverAjax.commands.quickeditEntitySaved = function (ajax, response, status) {
-        // Clean up.
-        $(ajax.element).off('quickedit-save.quickedit');
         // All fields have been moved from PrivateTempStore to permanent
         // storage, update the "inTempStore" attribute on FieldModels, on the
         // EntityModel and clear EntityModel's "fieldInTempStore" attribute.
@@ -399,7 +389,7 @@
       };
       // Trigger the AJAX request, which will will return the
       // quickeditEntitySaved AJAX command to which we then react.
-      $el.trigger('quickedit-save.quickedit');
+      entitySaverAjax.execute();
     },
 
     /**
diff --git a/core/modules/quickedit/js/quickedit.js b/core/modules/quickedit/js/quickedit.js
index 238ba0d10ddd603b3f04786f93625ba4cf9e8da8..7dcb6cb196dc03164ef9e0e0202a8eaac5282652 100644
--- a/core/modules/quickedit/js/quickedit.js
+++ b/core/modules/quickedit/js/quickedit.js
@@ -408,18 +408,11 @@
       return;
     }
 
-    // @todo Simplify this once https://drupal.org/node/1533366 lands.
     // @see https://drupal.org/node/2029999.
-    var id = 'quickedit-load-editors';
-    // Create a temporary element to be able to use Drupal.ajax.
-    var $el = $('<div id="' + id + '" class="hidden"></div>').appendTo('body');
-    // Create a Drupal.ajax instance to load the form.
-    var loadEditorsAjax = new Drupal.ajax(id, $el, {
+    // Create a Drupal.Ajax instance to load the form.
+    var loadEditorsAjax = Drupal.ajax({
       url: Drupal.url('quickedit/attachments'),
-      event: 'quickedit-internal.quickedit',
-      submit: {'editors[]': missingEditors},
-      // No progress indicator.
-      progress: {type: null}
+      submit: {'editors[]': missingEditors}
     });
     // Implement a scoped insert AJAX command: calls the callback after all AJAX
     // command functions have been executed (hence the deferred calling).
@@ -427,12 +420,10 @@
     loadEditorsAjax.commands.insert = function (ajax, response, status) {
       _.defer(callback);
       realInsert(ajax, response, status);
-      $el.off('quickedit-internal.quickedit');
-      $el.remove();
     };
     // Trigger the AJAX request, which will should return AJAX commands to insert
     // any missing attachments.
-    $el.trigger('quickedit-internal.quickedit');
+    loadEditorsAjax.execute();
   }
 
   /**
diff --git a/core/modules/quickedit/js/util.js b/core/modules/quickedit/js/util.js
index 2f76665794604c8fbace1ad4a6d21f3f26a38381..e8a96435948e388d8c80a387d51e031cc9ae8258 100644
--- a/core/modules/quickedit/js/util.js
+++ b/core/modules/quickedit/js/util.js
@@ -89,21 +89,16 @@
      *   commands.
      */
     load: function (options, callback) {
-      var $el = options.$el;
       var fieldID = options.fieldID;
 
       // Create a Drupal.ajax instance to load the form.
-      var formLoaderAjax = new Drupal.ajax(fieldID, $el, {
+      var formLoaderAjax = Drupal.ajax({
         url: Drupal.quickedit.util.buildUrl(fieldID, Drupal.url('quickedit/form/!entity_type/!id/!field_name/!langcode/!view_mode')),
-        event: 'quickedit-internal.quickedit',
         submit: {
           nocssjs: options.nocssjs,
           reset: options.reset
         },
-        progress: {type: null}, // No progress indicator.
         error: function (xhr, url) {
-          $el.off('quickedit-internal.quickedit');
-
           // Show a modal to inform the user of the network error.
           var fieldLabel = Drupal.quickedit.metadata.get(fieldID, 'label');
           var 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});
@@ -118,11 +113,10 @@
       // Implement a scoped quickeditFieldForm AJAX command: calls the callback.
       formLoaderAjax.commands.quickeditFieldForm = function (ajax, response, status) {
         callback(response.data, ajax);
-        $el.off('quickedit-internal.quickedit');
-        formLoaderAjax = null;
+        Drupal.ajax.instances[this.instanceIndex] = null;
       };
       // This will ensure our scoped quickeditFieldForm AJAX command gets called.
-      $el.trigger('quickedit-internal.quickedit');
+      formLoaderAjax.execute();
     },
 
     /**
@@ -143,7 +137,7 @@
         url: $submit.closest('form').attr('action'),
         setClick: true,
         event: 'click.quickedit',
-        progress: {type: null},
+        progress: false,
         submit: {
           nocssjs: options.nocssjs,
           other_view_modes: options.other_view_modes
@@ -156,10 +150,12 @@
               this.commands[response[i].command](this, response[i], status);
             }
           }
-        }
+        },
+        base: $submit.attr('id'),
+        element: $submit[0]
       };
 
-      return new Drupal.ajax($submit.attr('id'), $submit[0], settings);
+      return Drupal.ajax(settings);
     },
 
     /**
diff --git a/core/modules/views/js/ajax_view.js b/core/modules/views/js/ajax_view.js
index e173df1a2aa034cb1d42ad5a8200899f81eebcdc..ae373bbed3cde705951d8444f8b2a37fccc88f9c 100644
--- a/core/modules/views/js/ajax_view.js
+++ b/core/modules/views/js/ajax_view.js
@@ -78,16 +78,23 @@
     // @code
     // jQuery('.view-name').trigger('RefreshView');
     // @endcode
-    var self_settings = this.element_settings;
-    self_settings.event = 'RefreshView';
-    this.refreshViewAjax = new Drupal.ajax(this.selector, this.$view, self_settings);
+    var self_settings = $.extend({}, this.element_settings, {
+      event: 'RefreshView',
+      base: this.selector,
+      element: this.$view
+    });
+    this.refreshViewAjax = Drupal.ajax(self_settings);
   };
 
   Drupal.views.ajaxView.prototype.attachExposedFormAjax = function () {
     var button = $('input[type=submit], input[type=image]', this.$exposed_form);
     button = button[0];
 
-    this.exposedFormAjax = new Drupal.ajax($(button).attr('id'), button, this.element_settings);
+    var self_settings = $.extend({}, this.element_settings, {
+      base: $(button).attr('id'),
+      element: button
+    });
+    this.exposedFormAjax = Drupal.ajax(self_settings);
   };
 
   Drupal.views.ajaxView.prototype.filterNestedViews = function () {
@@ -121,8 +128,12 @@
       Drupal.Views.parseViewArgs(href, this.settings.view_base_path)
     );
 
-    this.element_settings.submit = viewData;
-    this.pagerAjax = new Drupal.ajax(false, $link, this.element_settings);
+    var self_settings = $.extend({}, this.element_settings, {
+      submit: viewData,
+      base: false,
+      element: $link
+    });
+    this.pagerAjax = Drupal.ajax(self_settings);
   };
 
   Drupal.AjaxCommands.prototype.viewsScrollTop = function (ajax, response) {
diff --git a/core/modules/views_ui/js/ajax.js b/core/modules/views_ui/js/ajax.js
index e69349354c4686429ed219cb96b56cfe19561600..492b63ef39306eb2f4e2841e44b2ba77e38a1582 100644
--- a/core/modules/views_ui/js/ajax.js
+++ b/core/modules/views_ui/js/ajax.js
@@ -84,12 +84,14 @@
       // Bind AJAX behaviors to all items showing the class.
       $('a.views-ajax-link', context).once('views-ajax').each(function () {
         var element_settings = base_element_settings;
+        element_settings.base = base;
+        element_settings.element = this;
         // Set the URL to go to the anchor.
         if ($(this).attr('href')) {
           element_settings.url = $(this).attr('href');
         }
         var base = $(this).attr('id');
-        Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+        Drupal.ajax(element_settings);
       });
 
       $('div#views-live-preview a')
@@ -108,8 +110,10 @@
 
           element_settings.wrapper = 'views-preview-wrapper';
           element_settings.method = 'replaceWith';
+          element_settings.base = base;
+          element_settings.element = this;
           var base = $(this).attr('id');
-          Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+          Drupal.ajax(element_settings);
         });
 
       // Within a live preview, make exposed widget form buttons re-trigger the
@@ -132,9 +136,11 @@
           element_settings.wrapper = 'views-preview-wrapper';
           element_settings.method = 'replaceWith';
           element_settings.event = 'click';
+          element_settings.base = base;
+          element_settings.element = this;
 
           var base = $(this).attr('id');
-          Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
+          Drupal.ajax(element_settings);
         });
 
     }