Newer
Older
(function ($, window, Drupal, drupalSettings) {
Angie Byron
committed
"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['path'] 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.
*/
Drupal.behaviors.AJAX = {
attach: function (context, settings) {
function loadAjaxBehavior(base) {
var element_settings = settings.ajax[base];
if (typeof element_settings.selector === 'undefined') {
element_settings.selector = '#' + base;
}
$(element_settings.selector).once('drupal-ajax', function () {
element_settings.element = this;
Drupal.ajax[element_settings.selector] = new Drupal.ajax(base, this, element_settings);
});
Angie Byron
committed
}
// Load all Ajax behaviors specified in the settings.
for (var base in settings.ajax) {
if (settings.ajax.hasOwnProperty(base)) {
loadAjaxBehavior(base);
}
// Bind Ajax behaviors to all items showing the class.
$('.use-ajax').once('ajax', function () {
var element_settings = {};
// Clicked links look better with the throbber than the progress bar.
element_settings.progress = { 'type': 'throbber' };
// For anchor tags, these will go to the target of the anchor rather
// than the usual location.
if ($(this).attr('href')) {
element_settings.url = $(this).attr('href');
element_settings.event = 'click';
}
element_settings.accepts = $(this).data('accepts');
element_settings.dialog = $(this).data('dialog-options');
var base = $(this).attr('id');
Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
});
Angie Byron
committed
// This class means to submit the form to the action using Ajax.
$('.use-ajax-submit').once('ajax', function () {
var element_settings = {};
// Ajax submits specified in this manner automatically submit to the
// normal form action.
element_settings.url = $(this.form).attr('action');
// Form submit button clicks need to tell the form what was clicked so
// it gets passed in the POST request.
element_settings.setClick = true;
// Form buttons use the 'click' event rather than mousedown.
Angie Byron
committed
element_settings.event = 'click';
// Clicked form buttons look better with the throbber than the progress bar.
element_settings.progress = { 'type': 'throbber' };
Angie Byron
committed
var base = $(this).attr('id');
Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
});
Angie Byron
committed
};
/**
* Extends Error to provide handling for Errors in AJAX
*/
Drupal.AjaxError = function (xmlhttp, uri) {
var statusCode, statusText, pathText, responseText, readyStateText;
if (xmlhttp.status) {
statusCode = "\n" + Drupal.t("An AJAX HTTP error occurred.") + "\n" + Drupal.t("HTTP Result Code: !status", {'!status': xmlhttp.status});
}
else {
statusCode = "\n" + Drupal.t("An AJAX HTTP request terminated abnormally.");
}
statusCode += "\n" + Drupal.t("Debugging information follows.");
pathText = "\n" + Drupal.t("Path: !uri", {'!uri': uri});
statusText = '';
// In some cases, when statusCode === 0, xmlhttp.statusText may not be defined.
// Unfortunately, testing for it with typeof, etc, doesn't seem to catch that
// and the test causes an exception. So we need to catch the exception here.
try {
statusText = "\n" + Drupal.t("StatusText: !statusText", {'!statusText': $.trim(xmlhttp.statusText)});
}
catch (e) {}
responseText = '';
// Again, we don't have a way to know for sure whether accessing
// xmlhttp.responseText is going to throw an exception. So we'll catch it.
try {
responseText = "\n" + Drupal.t("ResponseText: !responseText", {'!responseText': $.trim(xmlhttp.responseText) });
// Make the responseText more readable by stripping HTML tags and newlines.
responseText = responseText.replace(/<("[^"]*"|'[^']*'|[^'">])*>/gi, "");
responseText = responseText.replace(/[\n]+\s+/g, "\n");
// We don't need readyState except for status == 0.
readyStateText = xmlhttp.status === 0 ? ("\n" + Drupal.t("ReadyState: !readyState", {'!readyState': xmlhttp.readyState})) : "";
this.message = statusCode + pathText + statusText + responseText + readyStateText;
this.name = 'AjaxError';
Angie Byron
committed
};
Drupal.AjaxError.prototype = new Error();
Drupal.AjaxError.prototype.constructor = Drupal.AjaxError;
Angie Byron
committed
Angie Byron
committed
/**
* Ajax object.
*
* 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.
*
* 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
Angie Byron
committed
*/
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
Drupal.ajax = function (base, element, element_settings) {
var defaults = {
event: 'mousedown',
keypress: true,
selector: '#' + base,
effect: 'none',
speed: 'none',
method: 'replaceWith',
progress: {
type: 'throbber',
message: Drupal.t('Please wait...')
},
submit: {
'js': true
}
};
$.extend(this, defaults, element_settings);
this.commands = new Drupal.AjaxCommands();
// @todo Remove this after refactoring the PHP code to:
// - Call this 'selector'.
// - Include the '#' for ID-based selectors.
// - Support non-ID-based selectors.
if (this.wrapper) {
this.wrapper = '#' + this.wrapper;
}
this.element = element;
this.element_settings = element_settings;
Angie Byron
committed
// 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) {
this.$form = $(this.element.form);
Angie Byron
committed
}
// 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');
}
else if (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
// 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
// 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.
if (this.$form.find(':file').length) {
return;
}
}
Angie Byron
committed
}
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
// the server detect when it needs to degrade gracefully.
// There are four scenarios to check for:
// 1. /nojs/
// 2. /nojs$ - The end of a URL string.
// 3. /nojs? - Followed by a query (e.g. path/nojs?destination=foobar).
// 4. /nojs# - Followed by a fragment (e.g.: path/nojs#myfragment).
this.url = this.url.replace(/\/nojs(\/|$|\?|#)/g, '/ajax$1');
// Set the options for the ajaxSubmit function.
// The 'this' variable will not persist inside of the options object.
var ajax = this;
ajax.options = {
url: ajax.url,
data: ajax.submit,
beforeSerialize: function (element_settings, options) {
return ajax.beforeSerialize(element_settings, options);
},
beforeSubmit: function (form_values, element_settings, options) {
ajax.ajaxing = true;
return ajax.beforeSubmit(form_values, element_settings, options);
},
beforeSend: function (xmlhttprequest, options) {
ajax.ajaxing = true;
return ajax.beforeSend(xmlhttprequest, options);
},
success: function (response, status) {
// Sanity check for browser support (object expected).
// When using iFrame uploads, responses must be returned as a string.
if (typeof response === 'string') {
response = $.parseJSON(response);
}
return ajax.success(response, status);
},
complete: function (response, status) {
ajax.ajaxing = false;
if (status === 'error' || status === 'parsererror') {
return ajax.error(response, ajax.url);
}
},
dataType: 'json',
accepts: {
json: element_settings.accepts || 'application/vnd.drupal-ajax'
},
type: 'POST'
};
if (element_settings.dialog) {
ajax.options.data.dialogOptions = element_settings.dialog;
}
// Bind the ajaxSubmit function to the element event.
$(ajax.element).on(element_settings.event, function (event) {
return ajax.eventResponse(this, event);
});
// If necessary, enable keyboard submission so that Ajax behaviors
// can be triggered through keyboard input as well as e.g. a mousedown
// action.
if (element_settings.keypress) {
$(ajax.element).on('keypress', function (event) {
return ajax.keypressResponse(this, event);
});
Angie Byron
committed
}
// 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.
if (element_settings.prevent) {
$(ajax.element).on(element_settings.prevent, false);
Angie Byron
committed
}
};
Angie Byron
committed
/**
* Handle a key press.
*
* The Ajax object will, if instructed, bind to a key press response. This
* will test to see if the key press is valid to trigger this event and
* if it is, trigger it for us and prevent other keypresses from triggering.
* In this case we're handling RETURN and SPACEBAR keypresses (event codes 13
* 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.
Angie Byron
committed
*/
Drupal.ajax.prototype.keypressResponse = function (element, event) {
// Create a synonym for this to reduce code confusion.
var ajax = this;
// Detect enter key and space bar and allow the standard response for them,
// except for form elements of type 'text', 'tel', 'number' and 'textarea',
// where the spacebar activation causes inappropriate activation if
// #ajax['keypress'] is TRUE. On a text-type widget a space should always be a
// space.
if (event.which === 13 || (event.which === 32 && element.type !== 'text' &&
element.type !== 'textarea' && element.type !== 'tel' && element.type !== 'number')) {
event.preventDefault();
event.stopPropagation();
$(ajax.element_settings.element).trigger(ajax.element_settings.event);
}
};
Angie Byron
committed
/**
* Handle an event that triggers an Ajax response.
*
* 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.
Angie Byron
committed
*/
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
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.
if (ajax.ajaxing) {
return;
}
try {
if (ajax.$form) {
// If setClick is set, we must set this to ensure that the button's
// value is passed.
if (ajax.setClick) {
// Mark the clicked button. 'form.clk' is a special variable for
// ajaxSubmit that tells the system which element got clicked to
// trigger the submit. Without it there would be no 'op' or
// equivalent.
element.form.clk = element;
}
ajax.$form.ajaxSubmit(ajax.options);
}
else {
ajax.beforeSerialize(ajax.element, ajax.options);
$.ajax(ajax.options);
Angie Byron
committed
}
}
catch (e) {
// Unset the ajax.ajaxing flag here because it won't be unset during
// the complete response.
ajax.ajaxing = false;
window.alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message);
}
};
Angie Byron
committed
/**
* Handler for the form serialization.
*
* Runs before the beforeSend() handler (see below), and unlike that one, runs
* before field data is collected.
Angie Byron
committed
*/
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
// $.ajax(). When there is no form and $.ajax() is used, beforeSerialize()
// isn't called, but don't rely on that: explicitly check this.$form.
if (this.$form) {
var settings = this.settings || drupalSettings;
Drupal.detachBehaviors(this.$form.get(0), settings, 'serialize');
}
Angie Byron
committed
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Prevent duplicate HTML ids in the returned markup.
// @see drupal_html_id()
var ids = document.querySelectorAll('[id]');
var ajaxHtmlIds = [];
for (var i = 0, il = ids.length; i < il; i++) {
ajaxHtmlIds.push(ids[i].id);
}
// Join IDs to minimize request size.
options.data.ajax_html_ids = ajaxHtmlIds.join(' ');
// Allow Drupal to return new JavaScript and CSS files to load without
// returning the ones already loaded.
// @see \Drupal\Core\Theme\AjaxBasePageNegotiator
// @see drupal_get_css()
// @see drupal_get_js()
var pageState = drupalSettings.ajaxPageState;
options.data['ajax_page_state[theme]'] = pageState.theme;
options.data['ajax_page_state[theme_token]'] = pageState.theme_token;
for (var cssFile in pageState.css) {
if (pageState.css.hasOwnProperty(cssFile)) {
options.data['ajax_page_state[css][' + cssFile + ']'] = 1;
}
}
for (var jsFile in pageState.js) {
if (pageState.js.hasOwnProperty(jsFile)) {
options.data['ajax_page_state[js][' + jsFile + ']'] = 1;
}
}
};
Angie Byron
committed
/**
* Modify form values prior to form submission.
*/
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.
};
Angie Byron
committed
/**
* Prepare the Ajax request before it is sent.
Angie Byron
committed
*/
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
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
// with file inputs, the jQuery Form plugin uses the browser's normal form
// submission mechanism, but captures the response in a hidden IFRAME. In this
// circumstance, it calls this handler first, and then appends hidden fields
// to the form to submit the values in options.extraData. There is no simple
// way to know which submission mechanism will be used, so we add to extraData
// regardless, and allow it to be ignored in the former case.
if (this.$form) {
options.extraData = options.extraData || {};
// Let the server know when the IFRAME submission mechanism is used. The
// server can use this information to wrap the JSON response in a TEXTAREA,
// as per http://jquery.malsup.com/form/#file-upload.
options.extraData.ajax_iframe_upload = '1';
// The triggering element is about to be disabled (see below), but if it
// contains a value (e.g., a checkbox, textfield, select, etc.), ensure that
// value is included in the submission. As per above, submissions that use
// $.ajax() are already serialized prior to the element being disabled, so
// this is only needed for IFRAME submissions.
var v = $.fieldValue(this.element);
if (v !== null) {
options.extraData[this.element.name] = v;
}
Angie Byron
committed
}
// Disable the element that received the change to prevent user interface
// interaction while the Ajax request is in progress. ajax.ajaxing prevents
// the element from triggering a new request, but does not prevent the user
// from changing its value.
$(this.element).addClass('progress-disabled').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);
Angie Byron
committed
}
else if (this.progress.type === 'throbber') {
this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </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);
}
else if (this.progress.type === 'fullscreen') {
this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen"> </div>');
$('body').after(this.progress.element);
}
};
Angie Byron
committed
/**
* Handler for the form redirection completion.
Angie Byron
committed
*/
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
Drupal.ajax.prototype.success = function (response, status) {
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
}
if (this.progress.object) {
this.progress.object.stopMonitoring();
}
$(this.element).removeClass('progress-disabled').prop('disabled', false);
for (var i in response) {
if (response.hasOwnProperty(i) && response[i].command && this.commands[response[i].command]) {
this.commands[response[i].command](this, response[i], status);
}
}
// Reattach behaviors, if they were detached in beforeSerialize(). The
// attachBehaviors() called on the new content from processing the response
// commands is not sufficient, because behaviors from the entire form need
// to be reattached.
if (this.$form) {
var settings = this.settings || drupalSettings;
Drupal.attachBehaviors(this.$form.get(0), settings);
}
// Remove any response-specific settings so they don't get used on the next
// call by mistake.
this.settings = null;
};
Angie Byron
committed
Angie Byron
committed
/**
* Build an effect object which tells us how to apply the effect when adding new HTML.
Angie Byron
committed
*/
Drupal.ajax.prototype.getEffect = function (response) {
var type = response.effect || this.effect;
var speed = response.speed || this.speed;
var effect = {};
if (type === 'none') {
effect.showEffect = 'show';
effect.hideEffect = 'hide';
effect.showSpeed = '';
}
else if (type === 'fade') {
effect.showEffect = 'fadeIn';
effect.hideEffect = 'fadeOut';
effect.showSpeed = speed;
}
else {
effect.showEffect = type + 'Toggle';
effect.hideEffect = type + 'Toggle';
effect.showSpeed = speed;
}
return effect;
};
Angie Byron
committed
Angie Byron
committed
/**
* Handler for the form redirection error.
Angie Byron
committed
*/
Drupal.ajax.prototype.error = function (response, uri) {
// Remove the progress element.
if (this.progress.element) {
$(this.progress.element).remove();
}
if (this.progress.object) {
this.progress.object.stopMonitoring();
}
// Undo hide.
$(this.wrapper).show();
// Re-enable the element.
$(this.element).removeClass('progress-disabled').prop('disabled', false);
// Reattach behaviors, if they were detached in beforeSerialize().
if (this.$form) {
var settings = response.settings || this.settings || drupalSettings;
Drupal.attachBehaviors(this.$form.get(0), settings);
}
throw new Drupal.AjaxError(response, uri);
};
/**
* Provide a series of commands that the server can request the client perform.
Drupal.AjaxCommands = function () {};
Drupal.AjaxCommands.prototype = {
/**
* Command to insert new content into the DOM.
*/
insert: function (ajax, response, status) {
// Get information from the response. If it is not there, default to
// our presets.
var wrapper = response.selector ? $(response.selector) : $(ajax.wrapper);
var method = response.method || ajax.method;
var effect = ajax.getEffect(response);
var settings;
// We don't know what response.data contains: it might be a string of text
// without HTML, so don't rely on jQuery correctly interpreting
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
// $(response.data) as new HTML rather than a CSS selector. Also, if
// response.data contains top-level text nodes, they get lost with either
// $(response.data) or $('<div></div>').replaceWith(response.data).
var new_content_wrapped = $('<div></div>').html(response.data);
var new_content = new_content_wrapped.contents();
// For legacy reasons, the effects processing code assumes that new_content
// consists of a single top-level element. Also, it has not been
// sufficiently tested whether attachBehaviors() can be successfully called
// with a context object that includes top-level text nodes. However, to
// give developers full control of the HTML appearing in the page, and to
// enable Ajax content to be inserted in places where DIV elements are not
// allowed (e.g., within TABLE, TR, and SPAN parents), we check if the new
// content satisfies the requirement of a single top-level element, and
// only use the container DIV created above when it doesn't. For more
// information, please see http://drupal.org/node/736066.
if (new_content.length !== 1 || new_content.get(0).nodeType !== 1) {
new_content = new_content_wrapped;
}
// If removing content from the wrapper, detach behaviors first.
switch (method) {
case 'html':
case 'replaceWith':
case 'replaceAll':
case 'empty':
case 'remove':
settings = response.settings || ajax.settings || drupalSettings;
Drupal.detachBehaviors(wrapper.get(0), settings);
}
// Add the new content to the page.
wrapper[method](new_content);
// Immediately hide the new content if we're using any effects.
if (effect.showEffect !== 'show') {
new_content.hide();
}
// Determine which effect to use and what content will receive the
// effect, then show the new content.
if (new_content.find('.ajax-new-content').length > 0) {
new_content.find('.ajax-new-content').hide();
new_content.show();
new_content.find('.ajax-new-content')[effect.showEffect](effect.showSpeed);
}
else if (effect.showEffect !== 'show') {
new_content[effect.showEffect](effect.showSpeed);
}
// Attach all JavaScript behaviors to the new content, if it was successfully
// added to the page, this if statement allows #ajax['wrapper'] to be
// optional.
if (new_content.parents('html').length > 0) {
// Apply any settings from the returned JSON if available.
settings = response.settings || ajax.settings || drupalSettings;
Drupal.attachBehaviors(new_content.get(0), settings);
}
},
/**
* Command to remove a chunk from the page.
*/
remove: function (ajax, response, status) {
var settings = response.settings || ajax.settings || drupalSettings;
$(response.selector).each(function () {
Drupal.detachBehaviors(this, settings);
})
.remove();
},
/**
* Command to mark a chunk changed.
*/
changed: function (ajax, response, status) {
if (!$(response.selector).hasClass('ajax-changed')) {
$(response.selector).addClass('ajax-changed');
if (response.asterisk) {
$(response.selector).find(response.asterisk).append(' <abbr class="ajax-changed" title="' + Drupal.t('Changed') + '">*</abbr> ');
}
}
},
/**
* Command to provide an alert.
*/
alert: function (ajax, response, status) {
window.alert(response.text, response.title);
},
/**
* Command to set the window.location, redirecting the browser.
*/
redirect: function (ajax, response, status) {
window.location = response.url;
},
/**
* Command to provide the jQuery css() function.
*/
css: function (ajax, response, status) {
$(response.selector).css(response.argument);
},
/**
* Command to set the settings that will be used for other commands in this response.
*/
settings: function (ajax, response, status) {
if (response.merge) {
$.extend(true, drupalSettings, response.settings);
}
else {
ajax.settings = response.settings;
}
},
/**
* Command to attach data using jQuery's data API.
*/
data: function (ajax, response, status) {
$(response.selector).data(response.name, response.value);
},
/**
* Command to apply a jQuery method.
*/
invoke: function (ajax, response, status) {
var $element = $(response.selector);
$element[response.method].apply($element, response.args);
},
/**
* Command to restripe a table.
*/
restripe: function (ajax, response, status) {
// :even and :odd are reversed because jQuery counts from 0 and
// we count from 1, so we're out of sync.
// Match immediate children of the parent element to allow nesting.
$(response.selector).find('> tbody > tr:visible, > tr:visible')
.removeClass('odd even')
.filter(':even').addClass('odd').end()
.filter(':odd').addClass('even');
},
/**
* Command to update a form's build ID.
*/
update_build_id: function(ajax, response, status) {
$('input[name="form_build_id"][value="' + response.old + '"]').val(response.new);
},
/**
* Command to add css.
*
* Uses the proprietary addImport method if available as browsers which
* support that method ignore @import statements in dynamically added
* stylesheets.
*/
add_css: function (ajax, response, status) {
// Add the styles in the normal way.
$('head').prepend(response.data);
// Add imports in the styles using the addImport method if available.
var match, importMatch = /^@import url\("(.*)"\);$/igm;
if (document.styleSheets[0].addImport && importMatch.test(response.data)) {
importMatch.lastIndex = 0;
do {
match = importMatch.exec(response.data);
document.styleSheets[0].addImport(match[1]);
} while (match);
}
}
};
Angie Byron
committed
})(jQuery, this, Drupal, drupalSettings);