1/** 2 * @file 3 * Extends methods from core/misc/ajax.js. 4 */ 5 6(function ($, window, Drupal, drupalSettings) { 7 8 /** 9 * Attempts to find the closest glyphicon progress indicator. 10 * 11 * @param {jQuery|Element} element 12 * A DOM element. 13 * 14 * @returns {jQuery} 15 * A jQuery object. 16 */ 17 Drupal.Ajax.prototype.findGlyphicon = function (element) { 18 return $(element).closest('.form-item').find('.ajax-progress.glyphicon') 19 }; 20 21 /** 22 * Starts the spinning of the glyphicon progress indicator. 23 * 24 * @param {jQuery|Element} element 25 * A DOM element. 26 * @param {string} [message] 27 * An optional message to display (tooltip) for the progress. 28 * 29 * @returns {jQuery} 30 * A jQuery object. 31 */ 32 Drupal.Ajax.prototype.glyphiconStart = function (element, message) { 33 var $glyphicon = this.findGlyphicon(element); 34 if ($glyphicon[0]) { 35 $glyphicon.addClass('glyphicon-spin'); 36 37 // Add any message as a tooltip to the glyphicon. 38 if (drupalSettings.bootstrap.tooltip_enabled) { 39 $glyphicon 40 .removeAttr('data-toggle') 41 .removeAttr('data-original-title') 42 .removeAttr('title') 43 .tooltip('destroy') 44 ; 45 46 if (message) { 47 $glyphicon.attr('data-toggle', 'tooltip').attr('title', message).tooltip(); 48 } 49 } 50 51 // Append a message for screen readers. 52 if (message) { 53 $glyphicon.parent().append('<div class="sr-only message">' + message + '</div>'); 54 } 55 } 56 return $glyphicon; 57 }; 58 59 /** 60 * Stop the spinning of a glyphicon progress indicator. 61 * 62 * @param {jQuery|Element} element 63 * A DOM element. 64 */ 65 Drupal.Ajax.prototype.glyphiconStop = function (element) { 66 var $glyphicon = this.findGlyphicon(element); 67 if ($glyphicon[0]) { 68 $glyphicon.removeClass('glyphicon-spin'); 69 if (drupalSettings.bootstrap.tooltip_enabled) { 70 $glyphicon 71 .removeAttr('data-toggle') 72 .removeAttr('data-original-title') 73 .removeAttr('title') 74 .tooltip('destroy') 75 ; 76 } 77 } 78 }; 79 80 /** 81 * Sets the throbber progress indicator. 82 */ 83 Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () { 84 var $element = $(this.element); 85 86 // Find an existing glyphicon progress indicator. 87 var $glyphicon = this.glyphiconStart($element, this.progress.message); 88 if ($glyphicon[0]) { 89 this.progress.element = $glyphicon.parent(); 90 this.progress.glyphicon = true; 91 return; 92 } 93 94 // Otherwise, add a glyphicon throbber after the element. 95 if (!this.progress.element) { 96 this.progress.element = $(Drupal.theme('ajaxThrobber')); 97 } 98 if (this.progress.message) { 99 this.progress.element.after('<div class="message">' + this.progress.message + '</div>'); 100 } 101 102 // If element is an input DOM element type (not :input), append after. 103 if ($element.is('input')) { 104 $element.after(this.progress.element); 105 } 106 // Otherwise append the throbber inside the element. 107 else { 108 $element.append(this.progress.element); 109 } 110 }; 111 112 113 /** 114 * Handler for the form redirection completion. 115 * 116 * @param {Array.<Drupal.AjaxCommands~commandDefinition>} response 117 * @param {number} status 118 */ 119 Drupal.Ajax.prototype.success = function (response, status) { 120 if (this.progress.element) { 121 122 // Stop a glyphicon throbber. 123 if (this.progress.glyphicon) { 124 this.glyphiconStop(this.progress.element); 125 } 126 // Remove the progress element. 127 else { 128 this.progress.element.remove(); 129 } 130 131 // Remove any message set. 132 this.progress.element.parent().find('.message').remove(); 133 } 134 135 // -------------------------------------------------------- 136 // Everything below is from core/misc/ajax.js. 137 // -------------------------------------------------------- 138 139 if (this.progress.object) { 140 this.progress.object.stopMonitoring(); 141 } 142 $(this.element).prop('disabled', false); 143 144 // Save element's ancestors tree so if the element is removed from the dom 145 // we can try to refocus one of its parents. Using addBack reverse the 146 // result array, meaning that index 0 is the highest parent in the hierarchy 147 // in this situation it is usually a <form> element. 148 var elementParents = $(this.element).parents('[data-drupal-selector]').addBack().toArray(); 149 150 // Track if any command is altering the focus so we can avoid changing the 151 // focus set by the Ajax command. 152 var focusChanged = false;
153 for (var i in response) { 154 if (response.hasOwnProperty(i) && response[i].command && this.commands[response[i].command]) { 155 this.commands[response[i].command](this, response[i], status); 156 if (response[i].command === 'invoke' && response[i].method === 'focus') { 157 focusChanged = true; 158 } 159 } 160 } 161 162 // If the focus hasn't be changed by the ajax commands, try to refocus the 163 // triggering element or one of its parents if that element does not exist 164 // anymore. 165 if (!focusChanged && this.element && !$(this.element).data('disable-refocus')) { 166 var target = false; 167 168 for (var n = elementParents.length - 1; !target && n > 0; n--) { 169 target = document.querySelector('[data-drupal-selector="' + elementParents[n].getAttribute('data-drupal-selector') + '"]'); 170 } 171 172 if (target) { 173 $(target).trigger('focus'); 174 } 175 } 176 177 // Reattach behaviors, if they were detached in beforeSerialize(). The 178 // attachBehaviors() called on the new content from processing the response 179 // commands is not sufficient, because behaviors from the entire form need 180 // to be reattached. 181 if (this.$form) { 182 var settings = this.settings || drupalSettings; 183 Drupal.attachBehaviors(this.$form.get(0), settings); 184 } 185 186 // Remove any response-specific settings so they don't get used on the next 187 // call by mistake. 188 this.settings = null; 189 }; 190 191})(jQuery, this, Drupal, drupalSettings);
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.