improvements-2.x-dev/modules/improvements_form/assets/improvements.ajax.js
modules/improvements_form/assets/improvements.ajax.js
(function (Drupal) {
Drupal.ajaxProgressClasses = {
element: 'ajax-loading',
form: 'form--ajax-loading',
modalBody: 'page--dialog-loading'
};
/**
* Add ajax helper classes.
*
* @param {Element} element
*/
function addAjaxHelperClasses(element) {
// Add class to triggered element
element.classList.add(Drupal.ajaxProgressClasses.element);
// Add class to form containing triggered element
var form = element.closest('form');
if (form) {
form.classList.add(Drupal.ajaxProgressClasses.form);
}
// Add class to body if triggered element opens modal dialog
if (element.dataset.dialogType == 'modal') {
document.querySelector('body').classList.add(Drupal.ajaxProgressClasses.modalBody);
}
}
/**
* Remove ajax helper classes.
*
* @param {Element} element
*/
function removeHelperClasses(element) {
// Remove class from triggered element
element.classList.remove(Drupal.ajaxProgressClasses.element);
// Remove class from form containing triggered element
var form = element.closest('form');
if (form) {
form.classList.remove(Drupal.ajaxProgressClasses.form);
}
// Remove class to body if triggered element opens modal dialog
if (element.dataset.dialogType == 'modal') {
document.querySelector('body').classList.remove(Drupal.ajaxProgressClasses.modalBody);
}
}
/**
* Override AJAX "beforeSerialize" callback.
*/
var originalAjaxBeforeSerialize = Drupal.Ajax.prototype.beforeSerialize;
Drupal.Ajax.prototype.beforeSerialize = function (element, options) {
// Change request url to url from element data-ajax-url attribute
if (this.element) {
var elementAjaxUrl = this.element.dataset.ajaxUrl;
if (elementAjaxUrl) {
var wrapperFormatIndex = options.url.indexOf(Drupal.ajax.WRAPPER_FORMAT);
if (wrapperFormatIndex > 0) {
elementAjaxUrl += (elementAjaxUrl.indexOf('?') === -1) ? '?' : '&';
elementAjaxUrl += options.url.substring(wrapperFormatIndex);
}
options.url = elementAjaxUrl;
}
}
// Trigger custom event "ajaxBeforeSerialize"
if (this.element) {
this.element.dispatchEvent(new CustomEvent('ajaxBeforeSerialize', {
detail: {
context: this,
options: options,
},
}));
}
// Call original callback
return originalAjaxBeforeSerialize.apply(this, arguments);
};
/**
* Override AJAX "beforeSend" callback.
*/
var originalAjaxBeforeSend = Drupal.Ajax.prototype.beforeSend;
Drupal.Ajax.prototype.beforeSend = function (xmlhttprequest, options) {
var elementFocused = this.element ? this.element.matches(':focus') : false;
// Save text caret position
if (this.element && 'selectionStart' in this.element && this.element.selectionStart) {
this.element.dataset.selectionStart = this.element.selectionStart;
this.element.dataset.selectionEnd = this.element.selectionEnd;
}
// Add custom css classes
if (this.element) {
addAjaxHelperClasses(this.element);
}
// Set progress type from "data-progress-type" attribute
// @TODO Remove after close issue https://www.drupal.org/project/drupal/issues/2818463
if (this.element && this.element.dataset.progressType) {
this.progress.type = this.element.dataset.progressType;
}
// Trigger custom event "ajaxBeforeSend"
if (this.element) {
this.element.dispatchEvent(new CustomEvent('ajaxBeforeSend', {
detail: {
context: this,
options: options,
},
}));
}
// Call original callback
originalAjaxBeforeSend.apply(this, arguments);
// Remove "disabled" attribute from input
if ('disable_when_loading' in this && !this.disable_when_loading) {
this.ajaxing = false;
this.element.disabled = false;
// Restore focus after delete "disabled" attribute
if (elementFocused) {
this.element.focus();
}
// Abort previous ajax request
if (this.$form && this.$form.data('jqxhr')) {
this.$form.data('jqxhr').abort();
}
}
};
/**
* Override AJAX "success" callback.
*/
var originalAjaxSuccess = Drupal.Ajax.prototype.success;
Drupal.Ajax.prototype.success = function (response, status) {
var element = this.element || null;
// Remove custom css classes
if (element) {
removeHelperClasses(element);
}
// Call original callback
var originalAjaxSuccessPromise = originalAjaxSuccess.apply(this, arguments);
// Restore text caret position
if (element) {
var elementSavedSelectionStart = element.dataset.selectionStart;
var elementSavedSelectionEnd = element.dataset.selectionEnd;
if (elementSavedSelectionStart) {
originalAjaxSuccessPromise.then(function () {
var newElement = document.querySelector('[data-drupal-selector="' + element.dataset.drupalSelector + '"]');
if (newElement && 'setSelectionRange' in newElement) {
newElement.setSelectionRange(elementSavedSelectionStart, elementSavedSelectionEnd);
}
});
}
}
return originalAjaxSuccessPromise;
};
/**
* Override AJAX "error" callback.
*/
var originalAjaxError = Drupal.Ajax.prototype.error;
Drupal.Ajax.prototype.error = function (response, status) {
// Remove custom css classes
removeHelperClasses(this.element);
// Call original callback
return originalAjaxError.apply(this, arguments);
};
/**
* Override AJAX "eventResponse" function.
*/
var originalAjaxEventResponse = Drupal.Ajax.prototype.eventResponse;
Drupal.Ajax.prototype.eventResponse = function (element, event) {
// AJAX "once" functionality
if (element.classList.contains('use-ajax-once')) {
if (element.dataset.ajaxDone) {
this.ajaxing = true;
}
else {
element.dataset.ajaxDone = true;
}
}
// Call original callback
return originalAjaxEventResponse.apply(this, arguments);
};
/**
* Override "Insert" command.
*/
var originalInsertCommand = Drupal.AjaxCommands.prototype.insert;
Drupal.AjaxCommands.prototype.insert = function (ajax, response, status) {
// Trim data
if (response.data) {
response.data = response.data.trim();
}
// Call original command
return originalInsertCommand.apply(this, arguments);
};
/**
* Create custom progress type "toggleClass".
* @see Drupal.Ajax.prototype.beforeSend()
*/
Drupal.Ajax.prototype.setProgressIndicatorToggleclass = function () {
var progressTarget = this.progress.target ? document.querySelector(this.progress.target) : this.element;
var progressClass = this.progress.class ? this.progress.class : 'ajax-progress-animation';
// Add class
progressTarget.classList.add(progressClass);
// Remove class
this.progress.object = {
stopMonitoring: function () {
progressTarget.classList.remove(progressClass);
}
};
};
/**
* Send Ajax request and execute response commands using Drupal Ajax API.
*/
Drupal.ajaxExecute = function (url, options) {
options = options || {};
if (url) {
options.url = url;
}
var ajax = new Drupal.Ajax(false, false, options);
return ajax.execute();
}
})(Drupal);
