Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.332.2.12
diff -u -p -r1.332.2.12 views.module
--- views.module	11 Nov 2009 01:08:28 -0000	1.332.2.12
+++ views.module	11 Nov 2009 03:19:13 -0000
@@ -984,14 +984,35 @@ function views_exposed_form(&$form_state
   foreach ($view->display_handler->handlers as $type => $value) {
     foreach ($view->$type as $id => $handler) {
       if ($handler->can_expose() && $handler->is_exposed()) {
-        $handler->exposed_form($form, $form_state);
-        if ($info = $handler->exposed_info()) {
-          $form['#info']["$type-$id"] = $info;
+        if ($type == 'sort') {
+          if ($info = $handler->exposed_info()) {
+            $exposed_sorts[$id] = check_plain($info['label']);
+          }
+        }
+        else {
+          $handler->exposed_form($form, $form_state);
+          if ($info = $handler->exposed_info()) {
+            $form['#info']["$type-$id"] = $info;
+          }         
         }
       }
     }
   }
 
+  if (count($exposed_sorts)) {
+    $form['sort_by'] = array(
+      '#type' => 'select',
+      '#options' => $exposed_sorts,
+      '#title' => t($form_state['exposed_sorts_label']),
+    );
+    
+    $form['exposed_sort_order'] = array(
+      '#type' => 'select',
+      '#options' => array('asc' => t('Asc'), 'desc' => t('Desc')),
+      '#title' => t('Order'),
+    );    
+  }
+
   $form['submit'] = array(
     '#name' => '', // prevent from showing up in $_GET.
     '#type' => 'submit',
@@ -1042,7 +1063,7 @@ function views_exposed_form_submit(&$for
   $form_state['view']->exposed_raw_input = array();
 
   foreach ($form_state['values'] as $key => $value) {
-    if (!in_array($key, array('q', 'submit', 'form_build_id', 'form_id', 'form_token', 'submit_button', ''))) {
+    if (!in_array($key, array('q', 'submit', 'form_build_id', 'form_id', 'form_token', 'submit_button', 'exposed_sorts_label', ''))) {
       $form_state['view']->exposed_raw_input[$key] = $value;
     }
   }
Index: handlers/views_handler_sort.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/handlers/views_handler_sort.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 views_handler_sort.inc
--- handlers/views_handler_sort.inc	26 Jun 2009 00:23:37 -0000	1.1.2.1
+++ handlers/views_handler_sort.inc	11 Nov 2009 03:19:14 -0000
@@ -10,6 +10,160 @@
  * Base sort handler that has no options and performs a simple sort
  */
 class views_handler_sort extends views_handler {
+
+  /**
+   * Determine if a sort can be exposed.
+   */
+  function can_expose() { return TRUE; }
+
+  /**
+   * Provide the basic form which calls through to subforms.
+   * If overridden, it is best to call through to the parent,
+   * or to at least make sure all of the functions in this form
+   * are called.
+   */
+  function options_form(&$form, &$form_state) {
+    if ($this->can_expose()) {
+      $this->show_expose_button($form, $form_state);
+    }
+    $form['start'] = array('#value' => '<div class="clear-block">');
+    $this->sort_form($form, $form_state);
+    $form['end'] = array('#value' => '</div>');
+    if ($this->can_expose()) {
+      $this->show_expose_form($form, $form_state);
+    }
+  }
+
+  /**
+   * Simple validate handler
+   */
+  function options_validate(&$form, &$form_state) {
+    $this->sort_validate($form, $form_state);
+    if (!empty($this->options['exposed'])) {
+      $this->expose_validate($form, $form_state);
+    }
+  }
+
+  /**
+   * Validate the sort form.
+   */
+  function sort_validate($form, &$form_state) { }
+
+  /**
+   * Perform any necessary changes to the form values prior to storage.
+   * There is no need for this function to actually store the data.
+   */
+  function sort_submit($form, &$form_state) { }
+
+  /**
+   * Simple submit handler
+   */
+  function options_submit(&$form, &$form_state) {
+    unset($form_state['values']['expose_button']); // don't store this.
+    $this->sort_submit($form, $form_state);
+    if (!empty($this->options['exposed'])) {
+      $this->expose_submit($form, $form_state);
+    }
+  }
+
+  /**
+   * Provide a form for setting the sort.
+   *
+   * This may be overridden by child classes, and it must
+   * define $form['order'];
+   */
+  function sort_form(&$form, &$form_state) {
+    $options = $this->sort_options();
+    if (!empty($options)) {
+      $form['order'] = array(
+        '#type' => 'radios',
+        '#options' => $options,
+        '#default_value' => $this->options['order'],
+      );
+    }
+  }
+
+  /**
+   * Provide a list of options for the default sort form.
+   * Should be overridden by classes that don't override sort_form
+   */
+  function sort_options() { return array(
+    'ASC' => t('Sort ascending'), 
+    'DESC' => t('Sort descending'),
+    ); 
+  }
+
+ function expose_form_left(&$form, &$form_state) {
+    $form['expose']['label'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $this->options['expose']['label'],
+      '#title' => t('Label'),
+      '#size' => 40,
+   );
+  }
+  
+  /**
+   * Handle the 'left' side fo the exposed options form.
+   */
+  function expose_form_right(&$form, &$form_state) {
+
+    $form['expose']['order'] = array(
+      '#type' => 'value',
+      '#value' => 'ASC',
+     );
+
+    $form['expose']['label'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $this->options['expose']['label'],
+      '#title' => t('Label'),
+      '#size' => 40,
+      '#required' => TRUE,
+    );
+  }
+
+  /**
+   * Provide default options for exposed sorts.
+   */
+  function expose_options() {
+    $this->options['expose'] = array(
+      'order' => $this->options['order'],
+      'label' => $this->ui_name(),
+    );
+  }
+
+  /**
+   * Tell the renderer about our exposed form. This only needs to be
+   * overridden for particularly complex forms. And maybe not even then.
+   * 
+   * @return
+   *   An array with the following keys:
+   *   - operator: The $form key of the operator. Set to NULL if no operator.
+   *   - value: The $form key of the value. Set to NULL if no value.
+   *   - label: The label to use for this piece.
+   */
+  function exposed_info() {
+   if (empty($this->options['exposed'])) {
+      return;
+    }
+
+    return array(
+      'order' => $this->options['expose']['order'],
+      'label' => $this->options['expose']['label'],
+    );
+ }
+
+  /**
+   * Check to see if input from the exposed sorts should change
+   * the behavior of this sort.
+   */
+  function accept_exposed_input($input) {
+    return TRUE;
+  }
+
+  function store_exposed_input($input, $status) {
+    return TRUE;
+  }
+
   /**
    * Called to add the sort to a query.
    */
@@ -22,40 +176,33 @@ class views_handler_sort extends views_h
   function option_definition() {
     $options = parent::option_definition();
 
+    $options['exposed'] = array('default' => FALSE);
     $options['order'] = array('default' => 'ASC');
 
     return $options;
   }
 
   /**
-   * Display whether or not the sort order is ascending or descending
+   * Display whether or not the sort sort is ascending or descending
    */
   function admin_summary() {
+    if (!empty($this->options['exposed'])) {
+      return t('exposed');
+    }
+
     switch ($this->options['order']) {
       case 'ASC':
       case 'asc':
       default:
-        $type = t('asc');
+        return t('asc');
         break;
       case 'DESC';
       case 'desc';
-        $type = t('desc');
+        return t('desc');
         break;
     }
-    return '<span class="views-ascending"><span>' . $type . '</span></span>';
   }
 
-  /**
-   * Basic options for all sort criteria
-   */
-  function options_form(&$form, &$form_state) {
-    $form['order'] = array(
-      '#type' => 'radios',
-      '#title' => t('Sort order'),
-      '#options' => array('ASC' => t('Ascending'), 'DESC' => t('Descending')),
-      '#default_value' => $this->options['order'],
-    );
-  }
 }
 
 /**
Index: plugins/views_plugin_exposed_form.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/Attic/views_plugin_exposed_form.inc,v
retrieving revision 1.1.2.1
diff -u -p -r1.1.2.1 views_plugin_exposed_form.inc
--- plugins/views_plugin_exposed_form.inc	11 Nov 2009 01:42:53 -0000	1.1.2.1
+++ plugins/views_plugin_exposed_form.inc	11 Nov 2009 03:19:16 -0000
@@ -33,6 +33,7 @@ class views_plugin_exposed_form extends 
   function option_definition() {
     $options = parent::option_definition();
     $options['submit_button'] = array('default' => t('Apply'), 'translatable' => TRUE);
+    $options['exposed_sorts'] = array('default' => 'Sort By');
     return $options;
   }
 
@@ -43,6 +44,13 @@ class views_plugin_exposed_form extends 
       '#description' => t('Text to display in the submit button of the exposed form.'),
       '#default_value' => $this->options['submit_button'],
     );
+
+    $form['exposed_sorts_label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Exposed sorts label'),
+      '#description' => t('Text to display as the label of the exposed form element.'),
+      '#default_value' => isset($this->options['exposed_sorts_label'])?$this->options['exposed_sorts_label']:'Sort By',
+    );
   }
 
   /**
@@ -61,6 +69,7 @@ class views_plugin_exposed_form extends 
       'rerender' => TRUE,
       'no_redirect' => TRUE,
       'submit_button' => $this->options['submit_button'],
+      'exposed_sorts_label' => isset($this->options['exposed_sorts_label'])?$this->options['exposed_sorts_label']:'Sort By',
     );
 
     // Some types of displays (eg. attachments) may wish to use the exposed
@@ -82,7 +91,27 @@ class views_plugin_exposed_form extends 
     return $output;
   }
 
-  function query() { }
+  function query() {
+    $view = $this->view;
+    $exposed_data = $view->exposed_data;
+    $sort_by = $exposed_data['sort_by'];
+    if (!empty($sort_by)) {
+      $handler = $view->sort[$sort_by];
+      if (isset($handler)) {
+
+        $view->query->orderby = array();
+        if (isset($exposed_data['exposed_sort_order']) && in_array($exposed_data['exposed_sort_order'], array('asc', 'desc'))) {
+          $handler->options['order'] = $exposed_data['exposed_sort_order'];
+        }
+        $handler->query();  
+        foreach ($view->sort as $sort) {
+          if (!$sort->is_exposed()) {
+            $sort->query();
+          }
+        }
+      }
+    }
+  }
 
   function pre_render() { }
 
