--- better_exposed_filters-HEAD/better_exposed_filters_exposed_form_plugin.inc	2010-08-27 17:54:15.000000000 +0100
+++ better_exposed_filters/better_exposed_filters_exposed_form_plugin.inc	2010-09-14 17:26:38.000000000 +0100
@@ -1,5 +1,5 @@
 <?php
-// $Id: better_exposed_filters_exposed_form_plugin.inc,v 1.12 2010/08/27 16:54:15 mikeker Exp $
+// $Id: better_exposed_filters_exposed_form_plugin.inc,v 1.11 2010/05/25 17:36:47 mikeker Exp $
 
 /**
  * @file
@@ -23,12 +23,65 @@ class better_exposed_filters_exposed_for
   function options_form(&$form, &$form_state) {
     parent::options_form($form, $form_state);
 
+    $bef_options = array();
+
+    /*
+     * Add options for exposed sorts
+     */
+    $exposed = FALSE;
+    foreach ($this->display->handler->get_handlers('sort') as $label => $sort) {
+      if ($sort->options['exposed']) {
+        $exposed = TRUE;
+        break;
+      }
+    }
+    if ($exposed) {
+      $bef_options['sort']['bef_format'] = array(
+        '#type' => 'select',
+        '#title' => t('Display exposed sort options as'),
+        '#default_value' => $this->options['bef']['sort']['bef_format'],
+        '#options' => array(
+          'default' => t('Default select list'),
+          'bef' => t('Radio Buttons'),
+          'bef_links' => t('Links'),
+        ),
+        '#description' => t('Select a format for the exposed sort options.'),
+      );
+      $bef_options['sort']['allow_no_sort'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Display a "Do not sort" option'),
+        '#default_value' => $this->options['bef']['sort']['allow_no_sort'],
+        '#description' => t('Adds a "do not sort" option to the existing Asc/Desc options'),
+      );
+      $bef_options['sort']['no_sort_label'] = array(
+        '#type' => 'textfield',
+        '#title' => t('"Do not sort" label'),
+        '#default_value' => $this->options['bef']['sort']['no_sort_label'],
+        '#description' => t('Text to use if the above option is checked'),
+      );
+    }
+
+    /*
+     * Add options for exposed pager
+     */
+    if ($this->display->display_options['pager'] && $this->display->display_options['pager']['options']['expose']['items_per_page']) {
+      $bef_options['pager']['bef_format'] = array(
+        '#type' => 'select',
+        '#title' => t('Display exposed pager options as'),
+        '#default_value' => $this->options['bef']['pager']['bef_format'],
+        '#options' => array(
+          'default' => t('Default select list'),
+          'bef' => t('Radio Buttons'),
+          'bef_links' => t('Links'),
+        ),
+        '#description' => t('Select a format for the exposed pager options.'),
+      );
+    }
+
     /*
      * Changes to the options form need to be mirrored in hook_form_alter in
      * better_exposed_filters.module to maintain Views 2.x support
      */
-    
-    $bef_options = array();
 
     // Go through each filter and add the same options we used to add in hook_form_alter()
     foreach ($this->display->handler->get_handlers('filter') as $label => $filter) {
@@ -101,15 +154,108 @@ class better_exposed_filters_exposed_for
    */
   function exposed_form_alter(&$form, &$form_state) {
     parent::exposed_form_alter($form, $form_state);
-    
+
+    /*
+     * Handle exposed sort elements
+     */
+    if (isset($this->options['bef']['sort'])) {
+      // Add "Do not sort" option if selected
+      if ($this->options['bef']['sort']['allow_no_sort']) {
+        array_unshift($form['sort_order']['#options'], $this->options['bef']['sort']['no_sort_label']);
+
+        // JavaScript support is needed to remove the sort_by and sort_order form elements on form submission
+        drupal_add_js(drupal_get_path('module', 'better_exposed_filters') .'/better_exposed_filters.js');
+      }
+
+      switch($this->options['bef']['sort']['bef_format']) {
+        case 'bef':
+          if (1 == count($form['sort_by']['#options'])) {
+            // Don't show radio buttons when there's just one option.
+            // NOTE: Views' exposed forms code does some manipulations after form_alter is called, so we can't
+            //       add the markup and hidden form items as proper FAPI elements as they won't get positioned
+            //       correctly. Thus we 'display: none' the select element and add the display text using #suffix.
+            // TODO: should this be theme-able?  Should we move all select-as-radios to theme functions?
+    //        if (empty($form['sort_by']['#suffix'])) {
+    //          $form['sort_by']['#suffix'] = '';
+    //        }
+    //        if (empty($form['sort_by']['#prefix'])) {
+    //          $form['sort_by']['#prefix'] = '';
+    //        }
+            $form['sort_by']['#prefix'] .= '<div class="bef-sortby bef-single-sortby-option">';
+            $form['sort_by']['#suffix'] .= array_pop(array_values($form['sort_by']['#options'])) .'</div>';
+            $form['sort_by']['#attributes'] = array('style' => 'display: none;');
+          }
+          else {
+            $form['sort_by']['#type'] = 'radios';
+            $form['sort_by']['#process'] = array('expand_radios', 'views_process_dependency');
+            $form['sort_by']['#prefix'] = '<div class="bef-sortby bef-select-as-radios">';
+            $form['sort_by']['#suffix'] = '</div>';
+          }
+
+          $form['sort_order']['#type'] = 'radios';
+          $form['sort_order']['#process'] = array('expand_radios', 'views_process_dependency');
+          $form['sort_order']['#prefix'] = '<div class="bef-sortorder bef-select-as-radios">';
+          $form['sort_order']['#suffix'] = '</div>';
+        break;
+        case 'bef_links':
+          if (count($form['sort_by']['#options']) > 1) {
+            $form['sort_by']['#theme'] = 'select_as_links_sort';
+            $form['sort_order']['#sort_order'] = $form['sort_order']['#default_value'] ? $form['sort_order']['#default_value'] : key($form['sort_order']['#options']);
+            $form['sort_by']['#sort_by'] = $form['sort_by']['#default_value'] ? $form['sort_by']['#default_value'] : key($form['sort_by']['#options']);
+            $form['sort_order']['#attributes'] = array('style' => 'display: none;');
+          }
+        break;
+      }
+
+    }
+
+    /*
+     * Handle exposed pager elements
+     */
+    if (isset($this->options['bef']['pager'])) {
+      switch($this->options['bef']['pager']['bef_format']) {
+        case 'bef':
+          if (1 == count($form['items_per_page']['#options'])) {
+            // Don't show radio buttons when there's just one option.
+            // NOTE: Views' exposed forms code does some manipulations after form_alter is called, so we can't
+            //       add the markup and hidden form items as proper FAPI elements as they won't get positioned
+            //       correctly. Thus we 'display: none' the select element and add the display text using #suffix.
+            // TODO: should this be theme-able?  Should we move all select-as-radios to theme functions?
+    //        if (empty($form['items_per_page']['#suffix'])) {
+    //          $form['items_per_page']['#suffix'] = '';
+    //        }
+    //        if (empty($form['items_per_page']['#prefix'])) {
+    //          $form['items_per_page']['#prefix'] = '';
+    //        }
+            $form['items_per_page']['#prefix'] .= '<div class="bef-items-per-page bef-single-sortby-option">';
+            $form['items_per_page']['#suffix'] .= array_pop(array_values($form['items_per_page']['#options'])) .'</div>';
+            $form['items_per_page']['#attributes'] = array('style' => 'display: none;');
+          }
+          else {
+            $form['items_per_page']['#type'] = 'radios';
+            $form['items_per_page']['#process'] = array('expand_radios', 'views_process_dependency');
+            $form['items_per_page']['#prefix'] = '<div class="bef-sortby bef-select-as-radios">';
+            $form['items_per_page']['#suffix'] = '</div>';
+          }
+
+        break;
+        case 'bef_links':
+          if (count($form['items_per_page']['#options']) > 1) {
+            $form['items_per_page']['#theme'] = 'select_as_links_pager';
+            $form['items_per_page']['#items_per_page'] = max($form['items_per_page']['#default_value'], key($form['items_per_page']['#options']));
+          }
+        break;
+      }
+    }
+
     /*
      * Changes to the display of BEF filters need to be mirrored in hook_form_alter in
      * better_exposed_filters.module to maintain Views 2.x support
      */
-    
+
     // Shorthand for all filters in this view
     $filters = $form_state['view']->display_handler->handlers['filter'];
-    
+
     // Go through each saved option looking for Better Exposed Filter settings
     foreach ($this->options['bef'] as $label => $options) {
 
@@ -117,7 +263,7 @@ class better_exposed_filters_exposed_for
       if (!$filters[$label]->options['exposed']) {
         continue;
       }
-      
+
       // Form element is designated by the element ID which is user-configurable
       $field_id = $form['#info']["filter-$label"]['value'];
 
@@ -125,7 +271,7 @@ class better_exposed_filters_exposed_for
       if (!empty($options['more_options']['bef_filter_description'])) {
         $form[$field_id]['#description'] = $options['more_options']['bef_filter_description'];
       }
-        
+
       switch ($options['bef_format']) {
         case 'bef':
           if (empty($form[$field_id]['#multiple'])) {
@@ -133,22 +279,9 @@ class better_exposed_filters_exposed_for
             // radio buttons.
             $form[$field_id]['#type'] = 'radios';
             $form[$field_id]['#process'] = array('expand_radios', 'views_process_dependency');
-            $form[$field_id]['#prefix'] = '<div class="bef-select-as-radios">';
+            $form[$field_id]['#prefix'] = '<div class="bef-filter bef-select-as-radios">';
             $form[$field_id]['#suffix'] = '</div>';
 
-            // Clean up objects from the options array (happens for taxonomy-based filters)
-            $options = $form[$field_id]['#options'];
-            $form[$field_id]['#options'] = array();
-            foreach ($options as $index => $option) {
-              if (is_object($option)) {
-                list($key, $val) = each($option->option);
-                $form[$field_id]['#options'][$key] = $val;
-              }
-              else {
-                $form[$field_id]['#options'][$index] = $option;
-              }
-            }
-
             if (isset($form[$field_id]['#options']['All'])) {
               // @TODO: The terms 'All' and 'Any' are customizable in Views
               if (!$filters[$label]->options['expose']['optional']) {
--- better_exposed_filters-HEAD/better_exposed_filters.module	2010-08-27 17:54:15.000000000 +0100
+++ better_exposed_filters/better_exposed_filters.module	2010-09-14 17:26:38.000000000 +0100
@@ -1,5 +1,5 @@
 <?php
-// $Id: better_exposed_filters.module,v 1.15 2010/08/27 16:54:15 mikeker Exp $
+// $Id: better_exposed_filters.module,v 1.14 2010/08/14 19:21:56 mikeker Exp $
 
 /**
  * @file
@@ -130,19 +130,6 @@ function better_exposed_filters_form_alt
                 $form[$field_id]['#prefix'] = '<div class="bef-select-as-radios">';
                 $form[$field_id]['#suffix'] = '</div>';
 
-                // Clean up objects from the options array (happens for taxonomy-based filters)
-                $options = $form[$field_id]['#options'];
-                $form[$field_id]['#options'] = array();
-                foreach ($options as $index => $option) {
-                  if (is_object($option)) {
-                    list($key, $val) = each($option->option);
-                    $form[$field_id]['#options'][$key] = $val;
-                  }
-                  else {
-                    $form[$field_id]['#options'][$index] = $option;
-                  }
-                }
-
                 if (isset($form[$field_id]['#options']['All'])) {
                   // @TODO: The terms 'All' and 'Any' are customizable in Views
                   if (!$filter->options['expose']['optional']) {
@@ -197,8 +184,10 @@ function better_exposed_filters_form_alt
  */
 function better_exposed_filters_theme($existing, $type, $theme, $path) {
   return array(
-    'select_as_checkboxes' => array('function' => 'theme_select_as_checkboxes'),
-    'select_as_hidden'     => array('function' => 'theme_select_as_hidden'),
+    'select_as_checkboxes'  => array('function' => 'theme_select_as_checkboxes'),
+    'select_as_hidden'      => array('function' => 'theme_select_as_hidden'),
+    'select_as_links_sort'  => array('function' => 'theme_select_as_links_sort'),
+    'select_as_links_pager' => array('function' => 'theme_select_as_links_pager'),
   );
 }
 
@@ -287,6 +276,147 @@ function theme_select_as_checkboxes($ele
 }
 
 /**
+ * Themes a select element as a series of links (for sort)
+ *
+ * @see theme_select(), http://api.drupal.org/api/function/theme_select/6, http://drupal.org/node/894312
+ * @param object $element - An associative array containing the properties of the element.
+ *                          Properties used: title, value, options, description, extra, multiple, required
+ * @return HTML string representing the form element.
+ */
+function theme_select_as_links_sort($element) {
+  $output = '';
+  $selected_options = (array)$element['#post'][$element['#name']];   // the selected keys from #options
+  if (empty($_REQUEST['sort_by'])) {
+    $selected_options[] = $element['#sort_by'];
+  }
+  $properties = array(
+    'title' => $element['#title'],
+    'description' => $element['#description'],
+    'required' => FALSE,
+  );
+
+  foreach ($element['#options'] as $option => $elem) {
+    // Check for Taxonomy-based filters
+    if (is_object($elem)) {
+      list($option, $elem) = each(array_slice($elem->option, 0, 1, TRUE));
+    }
+
+    /*
+     * Check for optgroups.  Put subelements in the $element_set array and add a group heading.
+     * Otherwise, just add the element to the set
+     */
+    $element_set = array();
+    if (is_array($elem)) {
+      $element_set = $elem;
+    }
+    else {
+      $element_set[$option] = $elem;
+    }
+
+    $form_state = array('storage' => NULL, 'submitted' => FALSE);
+    $form_build_id = $element['#post']['form_build_id'];
+    $form = form_get_cache($form_build_id, $form_state);
+
+    $is_link = TRUE;
+    $links = array();
+    foreach ($element_set as $key => $value) {
+
+      // Custom ID for each hidden field based on the <select>'s original ID
+      $id = form_clean_id($element['#id'] . '-' . $key);
+      if (array_search($key, $selected_options) === FALSE) {
+        define('BEF_SORT_REVERSE', FALSE); // TODO: this option needs some work and testing
+        $is_link = TRUE;
+        if (BEF_SORT_REVERSE) {
+          $is_link = TRUE;
+          if (!$sort_order = better_exposed_filters_get_uri_value('sort_order')) {
+            $sort_order = $element['#sort_order'];
+          }
+          switch ($sort_order) {
+            case 'ASC':
+              $sort_order = 'DESC';
+            break;
+            case 'DESC':
+              $sort_order = 'ASC';
+            break;
+            default:
+              $sort_order = 'ASC';
+          }
+        }
+        $link = $is_link ? better_exposed_filters_replace_uri_value($element['#name'], $key, $value) : $value;
+        $sort_order = NULL;
+
+        // Very similar to theme_hidden (http://api.drupal.org/api/function/theme_hidden/6)
+        $output .= theme('form_element', array_merge($properties, array('#id' => $id)), $link);
+      } else {
+        $is_link = FALSE;
+        $link = $is_link ? better_exposed_filters_replace_uri_value('sort_order', NULL, $value, $is_link) : $value;
+
+        $output .= theme('form_element', array_merge($properties, array('#id' => $id)), $link);
+      }
+    }
+  }
+  return $output;
+}
+
+/**
+ * Themes a select element as a series of links (for pager)
+ *
+ * @see theme_select(), http://api.drupal.org/api/function/theme_select/6, http://drupal.org/node/894312
+ * @param object $element - An associative array containing the properties of the element.
+ *                          Properties used: title, value, options, description, extra, multiple, required
+ * @return HTML string representing the form element.
+ */
+function theme_select_as_links_pager($element) {
+  $output = '';
+  $selected_options = (array)$element['#post'][$element['#name']];   // the selected keys from #options
+  if (empty($_REQUEST['items_per_page'])) {
+    $selected_options[] = $element['#items_per_page'];
+  }
+  $properties = array(
+    'title' => $element['#title'],
+    'description' => $element['#description'],
+    'required' => FALSE,
+  );
+
+  foreach ($element['#options'] as $option => $elem) {
+    // Check for Taxonomy-based filters
+    if (is_object($elem)) {
+      list($option, $elem) = each(array_slice($elem->option, 0, 1, TRUE));
+    }
+
+    /*
+     * Check for optgroups.  Put subelements in the $element_set array and add a group heading.
+     * Otherwise, just add the element to the set
+     */
+    $element_set = array();
+    if (is_array($elem)) {
+      $element_set = $elem;
+    }
+    else {
+      $element_set[$option] = $elem;
+    }
+
+    $links = array();
+    foreach ($element_set as $key => $value) {
+
+      // Custom ID for each hidden field based on the <select>'s original ID
+      $id = form_clean_id($element['#id'] . '-' . $key);
+      if (array_search($key, $selected_options) === FALSE) {
+
+        $link = better_exposed_filters_replace_uri_value($element['#name'], $key, $value);
+
+        // Very similar to theme_hidden (http://api.drupal.org/api/function/theme_hidden/6)
+        $output .= theme('form_element', array_merge($properties, array('#id' => $id)), $link);
+      } else {
+        // $link = better_exposed_filters_replace_uri_value($element['#name'], $sort_order, $value);
+        $output .= theme('form_element', array_merge($properties, array('#id' => $id)), $value);
+      }
+    }
+  }
+  return $output;
+}
+
+/**
  * Themes a select element as a series of hidden fields
  *
  * @see theme_select(), http://api.drupal.org/api/function/theme_select/6
@@ -359,3 +489,76 @@ function better_exposed_filters_views_ap
   );
 }
 
+/**
+ * Replace URI value of selected argument
+ *
+ * @param string $arg name of the argument in URI
+ * @param string $value value of the argument in URI
+ * @return array
+ *    Return base URL, URL-encoded query string
+ *
+ * TODO: Any easier method to change the value of URI argument?
+ */
+function better_exposed_filters_replace_uri_value($arg, $arg_value, $name = NULL, $link = TRUE) {
+  $urllist = parse_url(request_uri());
+  if (strpos($urllist['query'], $arg . '=') !== FALSE) {
+    $keyvalue_list = explode("&",($urllist["query"])); // Explode into key/value array
+    $keyvalue_result = array(); // Store resulting key/value pairs
+    foreach($keyvalue_list as $key => $value) {
+      $keyvalue=explode("=", $value); // Explode each individual key/value into an array
+    
+      if(count($keyvalue) == 2) { // Make sure we have a "key=value" array
+        $keyvalue[1]=urldecode($keyvalue[1]); // Encode the value portion
+
+        if ($keyvalue[0] == $arg) {
+          $keyvalue[1] = $arg_value; // change value of our argument
+        }
+        $keyvalue_result[$keyvalue[0]] = $keyvalue[1]; // Add our key and encoded value into the result
+      } // end: if
+    } // end: foreach
+    // $urllist["query"] = implode("&", $keyvalue_result); // Repopulate our query key with encoded results
+    $urllist["query"] = $keyvalue_result; // assign array of query key/value-pairs without any URL-encoding
+  } else {
+    $urllist['query'] .= !empty($urllist['query']) ? '&' : '';
+    $urllist['query'] .= $arg . '=' . $arg_value;
+  }     
+    $url=(isset($urllist["scheme"])?$urllist["scheme"]."://":"").
+         (isset($urllist["user"])?$urllist["user"].":":"").
+         (isset($urllist["pass"])?$urllist["pass"]."@":"").
+         (isset($urllist["host"])?$urllist["host"]:"").
+         (isset($urllist["port"])?":".$urllist["port"]:"").
+         (isset($urllist["path"])?$urllist["path"]:"").
+         (isset($urllist["query"])?"?".$urllist["query"]:"").
+         (isset($urllist["fragment"])?"#".$urllist["fragment"]:"");
+  return $link ? l($name ? $name : $arg_value, substr($urllist["path"], 1), $urllist) : substr(url($urllist["path"], $urllist), 1);
+}
+
+/**
+ * Get URI value of selected argument
+ *
+ * @param string $arg name of the argument in URI
+ * @return string
+ *    Return value of the argument
+ *
+ * TODO: Any easier method to get the value of URI argument?
+ */
+function better_exposed_filters_get_uri_value($arg) {
+  $res = NULL;
+  $urllist = parse_url(request_uri());
+  if (strpos($urllist['query'], $arg . '=') !== FALSE) {
+    $keyvalue_list = explode("&",($urllist["query"])); // Explode into key/value array
+    foreach($keyvalue_list as $key => $value) {
+      $keyvalue=explode("=", $value); // Explode each individual key/value into an array
+    
+      if(count($keyvalue) == 2) { // Make sure we have a "key=value" array
+
+        if ($keyvalue[0] == $arg) {
+          $res = $keyvalue[1];
+          break;
+        }
+      } // end: if
+    } // end: foreach
+  }
+  return $res;
+}
+

