// $Id$ /** * 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. */ /** * Attaches the ahah behavior to each ahah form element. */ Drupal.behaviors.ahah = function(context) { for (var base in Drupal.settings.ahah) { if (!$('#'+ base + '.ahah-processed').size()) { var element_settings = Drupal.settings.ahah[base]; $(element_settings.selector).each(function() { element_settings.element = this; var ahah = new Drupal.ahah(base, element_settings); }); $('#'+ base).addClass('ahah-processed'); } } }; /** * AHAH object. */ 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.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') { return ahah.error(response.responseText); } }, 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; }); }; /** * 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 wrapper = $(this.wrapper); var form = $(this.element).parents('form'); // 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); // 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); // Add the new content to the page. Drupal.freezeHeight(); 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. For browser compatibility, Safari is excluded from // using effects on table rows. if (($.browser.safari && $("tr.ahah-new-content", new_content).size() > 0)) { new_content.show(); } else 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) { Drupal.attachBehaviors(new_content); } Drupal.unfreezeHeight(); }; /** * Handler for the form redirection error. */ Drupal.ahah.prototype.error = function (error) { alert(Drupal.t('An error occurred:\n\n@error', { '@error': error })); // Resore the previous action and target to the form. 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('progess-disabled').attr('disabled', false); };