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);