? views-exposed-sorts-228510-1.patch
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	18 Sep 2009 15:15:16 -0000
@@ -10,52 +10,264 @@
  * 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['sort'];
+   */
+  function sort_form(&$form, &$form_state) {
+    $options = $this->sort_options();
+    if (!empty($options)) {
+      $form['sort'] = array(
+        '#type' => 'radios',
+        '#options' => $options,
+        '#default_value' => $this->options['sort'],
+      );
+    }
+  }
+
+  /**
+   * 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(
+    '' => t('Unsorted'),
+    '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,
+    );
+    $form['expose']['identifier'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $this->options['expose']['identifier'],
+      '#title' => t('Sort identifier'),
+      '#size' => 40,
+      '#description' => t('This will appear in the URL after the ? to identify this sort. Cannot be blank.'),
+    );
+  }
+  
+  /**
+   * Handle the 'left' side fo the exposed options form.
+   */
+  function expose_form_right(&$form, &$form_state) {
+
+    $form['expose']['sort'] = array(
+      '#type' => 'value',
+      '#value' => '',
+     );
+
+    $form['expose']['label'] = array(
+      '#type' => 'textfield',
+      '#default_value' => $this->options['expose']['label'],
+      '#title' => t('Label'),
+      '#size' => 40,
+    );
+  }
+
+  /**
+   * Provide default options for exposed sorts.
+   */
+  function expose_options() {
+    $this->options['expose'] = array(
+      'sort' => $this->options['sort'],
+      'label' => t('Sort by: ') . $this->ui_name(),
+      'identifier' => $this->options['id'] .'_sort',
+    );
+  }
+
+  /**
+   * Validate the options form.
+   */
+  function expose_validate($form, &$form_state) {
+    if (empty($this->options['expose']['identifier'])) {
+      if (empty($form_state['values']['options']['expose']['identifier'])) {
+        form_error($form['expose']['identifier'], t('The identifier is required if the sort is exposed.'));
+      }
+    }
+
+    if (!empty($form_state['values']['options']['expose']['identifier']) && $form_state['values']['options']['expose']['identifier'] == 'value') {
+      form_error($form['expose']['identifier'], t('This identifier is not allowed.'));
+    }
+  }
+  
+  /**
+   * Render our chunk of the exposed sort form when selecting
+   *
+   * You can override this if it doesn't do what you expect.
+   */
+  function exposed_form(&$form, &$form_state) {
+    if (empty($this->options['exposed'])) {
+      return;
+    }
+    
+    if (!empty($this->options['expose']['identifier'])) {
+      $value = $this->options['expose']['identifier'];
+      
+      $this->sort_form($form, $form_state);
+      $form[$value] = $form['sort'];
+
+      $this->exposed_translate($form[$value], 'sort');
+
+      unset($form['sort']);
+    }
+
+  }
+
+  /**
+   * Make some translations to a form item to make it more suitable to
+   * exposing.
+   */
+  function exposed_translate(&$form, $type) {
+    if (!isset($form['#type'])) {
+      return;
+    }
+
+    if ($form['#type'] == 'radios') {
+      $form['#type'] = 'select';
+    }
+  }
+
+  /**
+   * Tell the renderer about our exposed form. This only needs to be
+   * overridden for particularly complex forms. And maybe not even then.
+   */
+  function exposed_info() {
+    if (empty($this->options['exposed'])) {
+      return;
+    }
+
+    return array(
+      'sort' => $this->options['expose']['sort'],
+      'label' => $this->options['expose']['label'],
+      'value' => $this->options['expose']['identifier'],
+    );
+  }
+
+  /**
+   * 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.
    */
   function query() {
-    $this->ensure_my_table();
-    // Add the field.
-    $this->query->add_orderby($this->table_alias, $this->real_field, $this->options['order']);
+    
+    if (empty($this->options['exposed'])) {
+      return;
+    }
+
+    $sort = drupal_strtolower($this->view->exposed_input[$this->options['expose']['identifier']]);
+    
+    // Ensure $this->sort is valid.
+    if (!empty($sort) && ($sort == 'asc' || $sort == 'desc')) {
+      $this->ensure_my_table();
+      // Add the field.
+      $this->query->add_orderby($this->table_alias, $this->real_field, $sort);
+    }
   }
 
   function option_definition() {
     $options = parent::option_definition();
 
-    $options['order'] = array('default' => 'ASC');
+    $options['exposed'] = array('default' => FALSE);
+    $options['sort'] = array('default' => '');
+    $options['identifier'] = array('default' => '');
 
     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() {
-    switch ($this->options['order']) {
+    switch ($this->options['sort']) {
       case 'ASC':
       case 'asc':
-      default:
         $type = t('asc');
         break;
       case 'DESC';
       case 'desc';
         $type = t('desc');
         break;
+      default:
+        $type = t('unsorted');
+        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: handlers/views_handler_sort_random.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/handlers/views_handler_sort_random.inc,v
retrieving revision 1.1
diff -u -p -r1.1 views_handler_sort_random.inc
--- handlers/views_handler_sort_random.inc	3 Sep 2008 19:21:28 -0000	1.1
+++ handlers/views_handler_sort_random.inc	18 Sep 2009 15:15:17 -0000
@@ -5,6 +5,9 @@
  * Handle a random sort.
  */
 class views_handler_sort_random extends views_handler_sort {
+
+  function can_expose() {return FALSE;}
+
   function query() {
     global $db_type;
     switch ($db_type) {
