// $Id$ (function ($) { /** * Provides AJAX-like page updating via AHAH (Asynchronous HTML and HTTP). * * AHAH is a method of making a request via Javascript while viewing an HTML * page. The request returns a small chunk of HTML, which is then directly * injected into the page. * * Drupal uses this file to enhance form elements with #ahah[path] and * #ahah[wrapper] properties. If set, this file will automatically be included * to provide AHAH capabilities. */ Drupal.ahah = Drupal.ahah || {}; /** * Attaches the ahah behavior to each ahah form element. */ Drupal.behaviors.ahah = { attach: function (context, settings) { for (var base in settings.ahah) { if (!$('#' + base + '.ahah-processed').size()) { var element_settings = settings.ahah[base]; $(element_settings.selector).each(function () { element_settings.element = this; Drupal.ahah[base] = new Drupal.ahah(base, element_settings); }); $('#' + base).addClass('ahah-processed'); } } } }; /** * AHAH object. * * All AHAH objects on a page are accessible through the global Drupal.ahah 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 AHAH 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.myCustomAhahStuff = { * attach: function(context, settings) { * Drupal.ahah['edit-submit'].insertNewContent = function(response, status) { * new_content = $(response.data); * $('#my-wrapper').append(new_content); * alert('New content was appended to #my-wrapper'); * } * } * }; * @endcode */ Drupal.ahah = function (base, element_settings) { // Set the properties for this object. this.element = element_settings.element; this.selector = element_settings.selector; this.event = element_settings.event; this.keypress = element_settings.keypress; this.url = element_settings.url; this.wrapper = '#' + element_settings.wrapper; this.effect = element_settings.effect; this.method = element_settings.method; this.progress = element_settings.progress; this.button = element_settings.button || { }; if (this.effect == 'none') { this.showEffect = 'show'; this.hideEffect = 'hide'; this.showSpeed = ''; } else if (this.effect == 'fade') { this.showEffect = 'fadeIn'; this.hideEffect = 'fadeOut'; this.showSpeed = 'slow'; } else { this.showEffect = this.effect + 'Toggle'; this.hideEffect = this.effect + 'Toggle'; this.showSpeed = 'slow'; } // Record the form action and target, needed for iFrame file uploads. var form = $(this.element).parents('form'); this.form_action = form.attr('action'); this.form_target = form.attr('target'); this.form_encattr = form.attr('encattr'); // Set the options for the ajaxSubmit function. // The 'this' variable will not persist inside of the options object. var ahah = this; var options = { url: ahah.url, data: ahah.button, beforeSubmit: function (form_values, element_settings, options) { return ahah.beforeSubmit(form_values, element_settings, 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 = Drupal.parseJson(response); } return ahah.success(response, status); }, complete: function (response, status) { if (status == 'error' || status == 'parsererror') { return ahah.error(response, ahah.url); } }, dataType: 'json', type: 'POST' }; // Bind the ajaxSubmit function to the element event. $(element_settings.element).bind(element_settings.event, function () { $(element_settings.element).parents('form').ajaxSubmit(options); return false; }); // If necessary, enable keyboard submission so that AHAH behaviors // can be triggered through keyboard input as well as e.g. a mousedown // action. if (element_settings.keypress) { $(element_settings.element).keypress(function (event) { // Detect enter key. if (event.keyCode == 13) { $(element_settings.element).trigger(element_settings.event); return false; } }); } }; /** * Handler for the form redirection submission. */ Drupal.ahah.prototype.beforeSubmit = function (form_values, element, options) { // Disable the element that received the change. $(this.element).addClass('progress-disabled').attr('disabled', true); // Insert progressbar or throbber. if (this.progress.type == 'bar') { var progressBar = new Drupal.progressBar('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback)); 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('ahah-progress ahah-progress-bar'); this.progress.object = progressBar; $(this.element).after(this.progress.element); } else if (this.progress.type == 'throbber') { this.progress.element = $('
 
'); if (this.progress.message) { $('.throbber', this.progress.element).after('
' + this.progress.message + '
'); } $(this.element).after(this.progress.element); } }; /** * Handler for the form redirection completion. */ Drupal.ahah.prototype.success = function (response, status) { var form = $(this.element).parents('form'); // Restore the previous action and target to the form. form.attr('action', this.form_action); this.form_target ? form.attr('target', this.form_target) : form.removeAttr('target'); this.form_encattr ? form.attr('target', this.form_encattr) : form.removeAttr('encattr'); // 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').attr('disabled', false); Drupal.freezeHeight(); // Call the insertNewContent handler to insert the new content into the page. this.insertNewContent(response, status); Drupal.unfreezeHeight(); }; /** * Handler to insert the new content into the page. */ Drupal.ahah.prototype.insertNewContent = function (response, status) { var wrapper = $(this.wrapper); // Manually insert HTML into the jQuery object, using $() directly crashes // Safari with long string lengths. http://dev.jquery.com/ticket/1152 var new_content = $('
').html(response.data); // Add the new content to the page. if (this.method == 'replace') { wrapper.empty().append(new_content); } else { wrapper[this.method](new_content); } // Immediately hide the new content if we're using any effects. if (this.showEffect != 'show') { new_content.hide(); } // Determine what effect use and what content will receive the effect, then // show the new content. if ($('.ahah-new-content', new_content).size() > 0) { $('.ahah-new-content', new_content).hide(); new_content.show(); $('.ahah-new-content', new_content)[this.showEffect](this.showSpeed); } else if (this.showEffect != 'show') { new_content[this.showEffect](this.showSpeed); } // Attach all javascript behaviors to the new content, if it was successfully // added to the page, this if statement allows #ahah[wrapper] to be optional. if (new_content.parents('html').length > 0) { // Apply any settings from the returned JSON if available. var settings = response.settings || Drupal.settings; Drupal.attachBehaviors(new_content, settings); } }; /** * Handler for the form redirection error. */ Drupal.ahah.prototype.error = function (response, uri) { alert(Drupal.ahahError(response, uri)); // Resore the previous action and target to the form. $(this.element).parent('form').attr({ action: this.form_action, target: this.form_target }); // 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').attr('disabled', false); }; })(jQuery);