Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.341.4.39
diff -u -p -r1.341.4.39 views.module
--- views.module	26 Oct 2010 05:05:27 -0000	1.341.4.39
+++ views.module	27 Oct 2010 16:40:02 -0000
@@ -180,9 +180,11 @@ function views_menu() {
   $items['views/ajax'] = array(
     'title' => 'Views',
     'page callback' => 'views_ajax',
+    'delivery callback' => 'ajax_deliver',
     'access callback' => TRUE,
     'description' => 'Ajax callback for view loading.',
     'type' => MENU_CALLBACK,
+    'file' => 'includes/ajax.inc',
   );
   // Path is not admin/structure/views due to menu complications with the wildcards from
   // the generic ajax callback.
Index: includes/ajax.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/ajax.inc,v
retrieving revision 1.20.4.13
diff -u -p -r1.20.4.13 ajax.inc
--- includes/ajax.inc	17 Oct 2010 10:42:44 -0000	1.20.4.13
+++ includes/ajax.inc	27 Oct 2010 16:40:02 -0000
@@ -26,44 +26,41 @@ function views_ajax() {
 
     $arg = explode('/', $_REQUEST['view_path']);
 
+    // @TODO: this can probably be deprecated.
     if ($arg[0] == 'admin' || (variable_get('node_admin_theme', '0') && $arg[0] == 'node' && ($arg[1] == 'add' || $arg[2] == 'edit'))) {
-        global $custom_theme;
-        $custom_theme = variable_get('admin_theme', '0');
-        drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
+      global $custom_theme;
+      $custom_theme = variable_get('admin_theme', '0');
+      drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
     }
-    // Load the view.
-    if ($view = views_get_view($name)) {
-      if ($view->access($display_id)) {
 
-        // Fix 'q' for paging.
-        if (!empty($path)) {
-          $_GET['q'] = $path;
-        }
+    // Load the view.
+    $view = views_get_view($name);
+    if ($view && $view->access($display_id)) {
+      // Fix 'q' for paging.
+      if (!empty($path)) {
+        $_GET['q'] = $path;
+      }
 
-        // Override the display's pager_element with the one actually used.
-        if (isset($pager_element)) {
-          $view->display[$display_id]->handler->set_option('pager_element', $pager_element);
-        }
-        // Reuse the same DOM id so it matches that in Drupal.settings.
-        $view->dom_id = $dom_id;
+      // Override the display's pager_element with the one actually used.
+      if (isset($pager_element)) {
+        $view->display[$display_id]->handler->set_option('pager_element', $pager_element);
+      }
+      // Reuse the same DOM id so it matches that in Drupal.settings.
+      $view->dom_id = $dom_id;
 
-        $errors = $view->validate();
-        if ($errors === TRUE) {
-          $commands[] = ajax_command_replace('#' . $domid, $view->get_title());
-          $commands[] = ajax_command_replace('#' . $dom_id, $view->preview($display_id, $args));
-        }
-        else {
-          foreach ($errors as $error) {
-            drupal_set_message($error, 'error');
-          }
+      $errors = $view->validate();
+      if ($errors === TRUE) {
+        // @TODO: how did this ever work?
+        // $commands[] = ajax_command_replace('#' . $domid, $view->get_title());
+        $commands[] = ajax_command_replace('.view-dom-id-' . $dom_id, $view->preview($display_id, $args));
+      }
+      else {
+        foreach ($errors as $error) {
+          drupal_set_message($error, 'error');
         }
       }
     }
-
-    $messages = theme('status_messages');
-    $commands[] = ajax_command_replace('.views-messages', $messages);
-
-    return $commands;
+    return array('#type' => 'ajax', '#commands' => $commands);
   }
 }
 
Index: js/ajax_view.js
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/js/ajax_view.js,v
retrieving revision 1.19.4.3
diff -u -p -r1.19.4.3 ajax_view.js
--- js/ajax_view.js	11 May 2010 21:05:11 -0000	1.19.4.3
+++ js/ajax_view.js	27 Oct 2010 16:40:02 -0000
@@ -7,40 +7,177 @@
  */
 (function ($) {
 
-Drupal.Views.Ajax = Drupal.Views.Ajax || {};
-
 /**
- * An ajax responder that accepts a packet of JSON data and acts appropriately.
- *
- * The following fields control behavior.
- * - 'display': Display the associated data in the view area.
+ * Extend Drupal.ajax with Drupal.Views.Ajax. A near direct copy of Drupal.ajax
+ * with the only difference being that an 'httpMethod' option can be provided
+ * in the element_settings, allowing for GET requests.
  */
-Drupal.Views.Ajax.ajaxViewResponse = function(target, response) {
+Drupal.Views.Ajax = function(base, element, element_settings) {
+  var defaults = {
+    url: 'system/ajax',
+    event: 'mousedown',
+    keypress: true,
+    selector: '#' + base,
+    effect: 'none',
+    speed: 'slow',
+    method: 'replaceWith',
+    progress: {
+      type: 'bar',
+      message: 'Please wait...'
+    },
+    submit: {
+      'js': true
+    },
+    // Override this.httpMethod
+    httpMethod: 'POST'
+  };
+
+  $.extend(this, defaults, element_settings);
+
+  this.element = element;
+
+  // Replacing 'nojs' with 'ajax' in the URL allows for an easy method to let
+  // the server detect when it needs to degrade gracefully.
+  this.url = element_settings.url.replace(/\/nojs(\/|$)/g, '/ajax$1');
+  this.wrapper = '#' + element_settings.wrapper;
+
+  // 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);
+  }
+
+  // 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);
+    },
+    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',
+    // Override: type
+    type: ajax.httpMethod
+  };
+
+  // Bind the ajaxSubmit function to the element event.
+  $(this.element).bind(element_settings.event, function () {
+    if (ajax.ajaxing) {
+      return false;
+    }
+
+    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.
+          this.form.clk = this;
+        }
 
-  if (response.debug) {
-    alert(response.debug);
+        ajax.form.ajaxSubmit(ajax.options);
+      }
+      else {
+        ajax.beforeSerialize(ajax.element, ajax.options);
+        $.ajax(ajax.options);
+      }
+    }
+    catch (e) {
+      alert("An error occurred while attempting to process " + ajax.options.url + ": " + e.message);
+    }
+
+    return false;
+  });
+
+  // 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) {
+    $(element_settings.element).keypress(function (event) {
+      // Detect enter key.
+      if (event.keyCode == 13) {
+        $(element_settings.element).trigger(element_settings.event);
+        return false;
+      }
+    });
   }
+};
 
-  var $view = $(target);
+/**
+ * Inherit all prototype methods from Drupal.ajax.
+ */
+Drupal.Views.Ajax.prototype = Drupal.ajax.prototype;
+
+/**
+ * Override beforeSerialize() method. Only difference is that ajax state
+ * payload elements are skipped when httpMethod is 'GET' as they will blow
+ * the URL length limit on most servers.
+ */
+Drupal.Views.Ajax.prototype.beforeSerialize = function (element, options) {
+  if (this.httpMethod === 'GET') {
+    return;
+  }
 
-  // Check the 'display' for data.
-  if (response.status && response.display) {
-    var $newView = $(response.display);
-    $view.replaceWith($newView);
-    $view = $newView;
-    Drupal.attachBehaviors($view.parent());
+  // 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 || Drupal.settings;
+    Drupal.detachBehaviors(this.form, settings, 'serialize');
   }
 
-  if (response.messages) {
-    // Show any messages (but first remove old ones, if there are any).
-    $view.find('.views-messages').remove().end().prepend(response.messages);
+  // Prevent duplicate HTML ids in the returned markup.
+  // @see drupal_html_id()
+  options.data['ajax_html_ids[]'] = [];
+  $('[id]').each(function () {
+    options.data['ajax_html_ids[]'].push(this.id);
+  });
+
+  // Allow Drupal to return new JavaScript and CSS files to load without
+  // returning the ones already loaded.
+  // @see ajax_base_page_theme()
+  // @see drupal_get_css()
+  // @see drupal_get_js()
+  options.data['ajax_page_state[theme]'] = Drupal.settings.ajaxPageState.theme;
+  options.data['ajax_page_state[theme_token]'] = Drupal.settings.ajaxPageState.theme_token;
+  for (var key in Drupal.settings.ajaxPageState.css) {
+    options.data['ajax_page_state[css][' + key + ']'] = 1;
+  }
+  for (var key in Drupal.settings.ajaxPageState.js) {
+    options.data['ajax_page_state[js][' + key + ']'] = 1;
   }
 };
 
 /**
- * Ajax behavior for views.
+ * Attaches the AJAX behavior to Views exposed filter forms and key View links.
  */
-Drupal.behaviors.ViewsAjaxView = function() {
+Drupal.behaviors.ViewsAjaxView = {};
+Drupal.behaviors.ViewsAjaxView.attach = function() {
   if (Drupal.settings && Drupal.settings.views && Drupal.settings.views.ajaxViews) {
     var ajax_path = Drupal.settings.views.ajax_path;
     // If there are multiple views this might've ended up showing up multiple times.
@@ -56,44 +193,23 @@ Drupal.behaviors.ViewsAjaxView = functio
         view = '.view-id-' + settings.view_name + '.view-display-id-' + settings.view_display_id;
       }
 
-
       // Process exposed filter forms.
       $('form#views-exposed-form-' + settings.view_name.replace(/_/g, '-') + '-' + settings.view_display_id.replace(/_/g, '-'))
       .filter(':not(.views-processed)')
       .each(function () {
-        // remove 'q' from the form; it's there for clean URLs
-        // so that it submits to the right place with regular submit
-        // but this method is submitting elsewhere.
-        $('input[name=q]', this).remove();
-        var form = this;
-        // ajaxSubmit doesn't accept a data argument, so we have to
-        // pass additional fields this way.
-        $.each(settings, function(key, setting) {
-          $(form).append('<input type="hidden" name="'+ key + '" value="'+ setting +'"/>');
-        });
+        var button = $('input[type=submit]', this);
+        button.form = this;
+
+        var element_settings = {};
+        element_settings.url = ajax_path;
+        element_settings.submit = settings;
+        element_settings.setClick = true;
+        element_settings.event = 'click';
+        element_settings.selector = view;
+        element_settings.httpMethod = 'GET';
+        new Drupal.Views.Ajax($(button).attr('id'), button, element_settings);
       })
       .addClass('views-processed')
-      .submit(function () {
-        $('input[type=submit], button', this).after('<span class="views-throbbing">&nbsp</span>');
-        var object = this;
-        $(this).ajaxSubmit({
-          url: ajax_path,
-          type: 'GET',
-          success: function(response) {
-            // Call all callbacks.
-            if (response.__callbacks) {
-              $.each(response.__callbacks, function(i, callback) {
-                eval(callback)(view, response);
-              });
-              $('.views-throbbing', object).remove();
-            }
-          },
-          error: function() { alert(Drupal.t("An error occurred at @path.", {'@path': ajax_path})); $('.views-throbbing', object).remove(); },
-          dataType: 'json'
-        });
-
-        return false;
-      });
 
       $(view).filter(':not(.views-processed)')
         // Don't attach to nested views. Doing so would attach multiple behaviors
@@ -121,48 +237,21 @@ Drupal.behaviors.ViewsAjaxView = functio
                 // Extract argument data from the URL.
                 Drupal.Views.parseViewArgs($(this).attr('href'), settings.view_base_path)
               );
-              $(this).click(function () {
-                $.extend(viewData, Drupal.Views.parseViewArgs($(this).attr('href'), settings.view_base_path));
-                $(this).addClass('views-throbbing');
-                $.ajax({
-                  url: ajax_path,
-                  type: 'GET',
-                  data: viewData,
-                  success: function(response) {
-                    $(this).removeClass('views-throbbing');
-                    // Scroll to the top of the view. This will allow users
-                    // to browse newly loaded content after e.g. clicking a pager
-                    // link.
-                    var offset = $(target).offset();
-                    // We can't guarantee that the scrollable object should be
-                    // the body, as the view could be embedded in something
-                    // more complex such as a modal popup. Recurse up the DOM
-                    // and scroll the first element that has a non-zero top.
-                    var scrollTarget = target;
-                    while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) {
-                      scrollTarget = $(scrollTarget).parent()
-                    }
-                    // Only scroll upward
-                    if (offset.top - 10 < $(scrollTarget).scrollTop()) {
-                      $(scrollTarget).animate({scrollTop: (offset.top - 10)}, 500);
-                    }
-                    // Call all callbacks.
-                    if (response.__callbacks) {
-                      $.each(response.__callbacks, function(i, callback) {
-                        eval(callback)(target, response);
-                      });
-                    }
-                  },
-                  error: function() { $(this).removeClass('views-throbbing'); alert(Drupal.t("An error occurred at @path.", {'@path': ajax_path})); },
-                  dataType: 'json'
-                });
 
-                return false;
-              });
+              // For anchor tags, these will go to the target of the anchor rather
+              // than the usual location.
+              $.extend(viewData, Drupal.Views.parseViewArgs($(this).attr('href'), settings.view_base_path));
+
+              var element_settings = {};
+              element_settings.url = ajax_path;
+              element_settings.submit = viewData;
+              element_settings.event = 'click';
+              element_settings.selector = view;
+              element_settings.httpMethod = 'GET';
+              new Drupal.Views.Ajax(false, this, element_settings);
             }); // .each function () {
       }); // $view.filter().each
     }); // .each Drupal.settings.views.ajaxViews
   } // if
 };
-
 })(jQuery);
