Index: views.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v
retrieving revision 1.332.2.10
diff -u -p -r1.332.2.10 views.module
--- views.module	24 Sep 2009 23:33:40 -0000	1.332.2.10
+++ views.module	7 Nov 2009 14:03:07 -0000
@@ -956,22 +956,45 @@ function views_exposed_form(&$form_state
     );
   }
 
+  $exposed_sorts = array('' => t('- Select One -'));
+
   // Go through each handler and let it generate its exposed widget.
   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',
-    '#value' => t('Apply'),
+    '#value' => t($form_state['submit_button']),
     '#id' => form_clean_id('edit-submit-' . $view->name),
   );
 
@@ -1018,7 +1041,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', ''))) {
+    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	7 Nov 2009 14:03:08 -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,31 @@ 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: includes/plugins.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/plugins.inc,v
retrieving revision 1.152.2.5
diff -u -p -r1.152.2.5 plugins.inc
--- includes/plugins.inc	24 Sep 2009 23:28:23 -0000	1.152.2.5
+++ includes/plugins.inc	7 Nov 2009 14:03:09 -0000
@@ -267,6 +267,25 @@ function views_views_plugins() {
         'help topic' => 'cache-time',
       ),
     ),
+    'exposed_form' => array(
+      'parent' => array(
+        'no ui' => TRUE,
+        'handler' => 'views_plugin_exposed_form',
+        'parent' => '',
+      ),
+      'basic' => array(
+        'title' => t('Basic'),
+        'help' => t('Basic exposed form'),
+        'handler' => 'views_plugin_exposed_form_basic',
+        'uses options' => TRUE,
+      ),
+      'on_demand' => array(
+        'title' => t('On demand'),
+        'help' => t('On demand exposed form'),
+        'handler' => 'views_plugin_exposed_form_on_demand',
+        'uses options' => TRUE,
+      ),
+    ),
   );
 }
 
@@ -276,7 +295,7 @@ function views_views_plugins() {
  * @return Nested array of plugins, grouped by type.
  */
 function views_discover_plugins() {
-  $cache = array('display' => array(), 'style' => array(), 'row' => array(), 'argument default' => array(), 'argument validator' => array(), 'access' => array(), 'cache' => array());
+  $cache = array('display' => array(), 'style' => array(), 'row' => array(), 'argument default' => array(), 'argument validator' => array(), 'access' => array(), 'cache' => array(), 'exposed_form' => array());
   // Get plugins from all mdoules.
   foreach (module_implements('views_plugins') as $module) {
     $function = $module . '_views_plugins';
Index: includes/view.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/view.inc,v
retrieving revision 1.151.2.16
diff -u -p -r1.151.2.16 view.inc
--- includes/view.inc	2 Nov 2009 23:34:26 -0000	1.151.2.16
+++ includes/view.inc	7 Nov 2009 14:03:13 -0000
@@ -383,42 +383,6 @@ class view extends views_db_object {
   }
 
   /**
-   * Render the exposed filter form.
-   *
-   * This actually does more than that; because it's using FAPI, the form will
-   * also assign data to the appropriate handlers for use in building the
-   * query.
-   */
-  function render_exposed_form($block = FALSE) {
-    // Deal with any exposed filters we may have, before building.
-    $form_state = array(
-      'view' => &$this,
-      'display' => &$this->display_handler->display,
-      'method' => 'get',
-      'rerender' => TRUE,
-      'no_redirect' => TRUE,
-    );
-
-    // Some types of displays (eg. attachments) may wish to use the exposed
-    // filters of their parent displays instead of showing an additional
-    // exposed filter form for the attachment as well as that for the parent.
-    if (!$this->display_handler->displays_exposed() || (!$block && $this->display_handler->get_option('exposed_block'))) {
-      unset($form_state['rerender']);
-    }
-
-    if (!empty($this->ajax)) {
-      $form_state['ajax'] = TRUE;
-    }
-
-    $output = drupal_build_form('views_exposed_form', $form_state);
-    if (!empty($form_state['js settings'])) {
-      $this->js_settings = $form_state['js settings'];
-    }
-
-    return $output;
-  }
-
-  /**
    * Build all the arguments.
    */
   function _build_arguments() {
@@ -584,7 +548,8 @@ class view extends views_db_object {
     $this->_pre_query();
 
     if ($this->display_handler->uses_exposed()) {
-      $this->exposed_widgets = $this->render_exposed_form();
+      $exposed_form = $this->display_handler->get_exposed_form_plugin();
+      $this->exposed_widgets = $exposed_form->render_exposed_form();
       if (form_set_error() || !empty($this->build_info['abort'])) {
         $this->built = TRUE;
         return empty($this->build_info['fail']);
@@ -633,6 +598,11 @@ class view extends views_db_object {
 
     // Allow style handler to affect the query:
     $this->style_plugin->query();
+    
+    // Allow exposed form to affect the query:
+    if (isset($exposed_form)) {
+      $exposed_form->query();
+    }
 
     if (variable_get('views_sql_signature', FALSE)) {
       $this->query->add_signature($this);
@@ -738,6 +708,9 @@ class view extends views_db_object {
       $this->start_query_capture();
     }
 
+    $exposed_form = $this->display_handler->get_exposed_form_plugin();
+    $exposed_form->pre_render();
+
     // Check for already-cached output.
     if (!empty($this->live_preview)) {
       $cache = FALSE;
@@ -785,6 +758,8 @@ class view extends views_db_object {
       }
     }
 
+    $exposed_form->post_render($this->display_handler->output);
+    
     if ($cache) {
       $cache->post_render($this->display_handler->output);
     }
Index: plugins/views_plugin_display.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views/plugins/views_plugin_display.inc,v
retrieving revision 1.20.2.11
diff -u -p -r1.20.2.11 views_plugin_display.inc
--- plugins/views_plugin_display.inc	2 Nov 2009 23:58:04 -0000	1.20.2.11
+++ plugins/views_plugin_display.inc	7 Nov 2009 14:03:18 -0000
@@ -180,6 +180,7 @@ class views_plugin_display extends views
       'link_display' => array('link_display'),
       'distinct' => array('distinct'),
       'exposed_block' => array('exposed_block'),
+      'exposed_form' => array('exposed_form'),
 
       // Force these to cascade properly.
       'style_plugin' => array('style_plugin', 'style_options', 'row_plugin', 'row_options'),
@@ -254,6 +255,7 @@ class views_plugin_display extends views
           'use_more_text' => TRUE,
           'distinct' => TRUE,
           'exposed_block' => TRUE,
+          'exposed_form' => TRUE,
 
           'link_display' => TRUE,
 
@@ -378,6 +380,11 @@ class views_plugin_display extends views
       'exposed_block' => array(
         'default' => FALSE,
       ),
+      'exposed_form' => array(
+        'contains' => array(
+          'type' => array('default' => 'basic'),
+         ),
+      ),
     );
 
     if ($this->is_default_display()) {
@@ -534,6 +541,23 @@ class views_plugin_display extends views
   }
 
   /**
+   * Get the exposed form plugin
+   */
+  function get_exposed_form_plugin($name = NULL) {
+    if (!$name) {
+      $exposed_form = $this->get_option('exposed_form');
+      $name = $exposed_form['type'];
+    }
+
+    $plugin = views_get_plugin('exposed_form', $name);
+    $options = $this->get_option($type . '_options');
+    if ($plugin) {
+      $plugin->init($this->view, $this->display, $options);
+      return $plugin;
+    }
+  }
+
+  /**
    * Get the handler object for a single handler.
    */
   function &get_handler($type, $id) {
@@ -800,6 +824,25 @@ class views_plugin_display extends views
       'desc' => t('Allow the exposed form to appear in a block instead of the view.'),
     );
 
+    $exposed_form_plugin = $this->get_exposed_form_plugin();
+    if (!$exposed_form_plugin) {
+      // default to the no cache control plugin.
+      $exposed_form_plugin = views_get_plugin('exposed_form', 'basic');
+    }
+
+    $exposed_form_str = $exposed_form_plugin->summary_title();
+    
+    $options['exposed_form'] = array(
+      'category' => 'exposed',
+      'title' => t('Exposed form style'),
+      'value' => $exposed_form_str,
+      'desc' => t('Select the kind of exposed filter to use.'),
+    );
+
+    if (!empty($exposed_form_plugin->definition['uses options'])) {
+      $options['exposed_form']['links']['exposed_form_options'] = t('Exposed form settings for this exposed form style.');
+    }
+
     foreach (array('header' => t('Header'), 'footer' => t('Footer'), 'empty' => t('Empty text')) as $type => $name) {
       if (!$this->get_option($type)) {
         $field = t('None');
@@ -1375,6 +1418,47 @@ class views_plugin_display extends views
           '#default_value' => $this->get_option('exposed_block') ? 1 : 0,
         );
         break;
+      case 'exposed_form':
+        $form['#title'] .= t('Exposed Form');
+        $form['exposed_form'] = array(
+          '#prefix' => '<div class="clear-block">',
+          '#suffix' => '</div>',
+          '#tree' => TRUE,
+        );
+
+        $exposed_form = $this->get_option('exposed_form');
+        $form['exposed_form']['type'] =  array(
+          '#type' => 'radios',
+          '#options' => views_fetch_plugin_names('exposed_form'),
+          '#default_value' => $exposed_form['type'],
+        );
+
+        $exposed_form_plugin = views_fetch_plugin_data('exposed_form', $exposed_form['type']);
+        if (!empty($exposed_form_plugin['uses options'])) {
+          $form['markup'] = array(
+            '#prefix' => '<div class="form-item description">',
+            '#suffix' => '</div>',
+            '#value' => t('You may also adjust the !settings for the currently selected style by clicking on the icon.', array('!settings' => $this->option_link(t('settings'), 'exposed_form_options'))),
+          );
+        }
+        break;
+      case 'exposed_form_options':
+        $exposed_form = $this->get_option('exposed_form');
+        $plugin = $this->get_exposed_form_plugin();
+        $form['#title'] .= t('Exposed form options');
+        if ($plugin) {
+          $form['#help_topic'] = $plugin->definition['help topic'];
+
+          $form['exposed_form_options'] = array(
+            '#tree' => TRUE,
+          );
+          $form['exposed_form_options']['type'] = array(
+            '#type' => 'value',
+            '#value' => $exposed_form['type'],
+          );
+          $plugin->options_form($form['exposed_form_options'], $form_state);
+        }
+        break;
     }
   }
 
@@ -1441,6 +1525,12 @@ class views_plugin_display extends views
           $plugin->options_validate($form['cache_options'], $form_state);
         }
         break;
+      case 'exposed_form_options':
+        $plugin = $this->get_exposed_form_plugin();
+        if ($plugin) {
+          $plugin->options_validate($form['exposed_form_options'], $form_state);
+        }
+        break;
     }
   }
 
@@ -1579,6 +1669,27 @@ class views_plugin_display extends views
       case 'exposed_block':
         $this->set_option($section, (bool) $form_state['values'][$section]);
         break;
+      case 'exposed_form':
+        $exposed_form = $this->get_option('exposed_form');
+        if ($exposed_form['type'] != $form_state['values']['exposed_form']['type']) {
+          $plugin = views_get_plugin('exposed_form', $form_state['values']['exposed_form']['type']);
+          if ($plugin) {
+            $exposed_form = array('type' => $form_state['values']['exposed_form']['type']);
+            $this->set_option('exposed_form', $exposed_form);
+            if (!empty($plugin->definition['uses options'])) {
+              views_ui_add_form_to_stack('display', $this->view, $this->display->id, array('exposed_form_options'));
+            }
+          }
+        }
+
+        break;
+      case 'exposed_form_options':
+        $plugin = views_get_plugin('exposed_form', $form_state['values'][$section]['type']);
+        if ($plugin) {
+          $plugin->options_submit($form['exposed_form_options'], $form_state);
+          $this->set_option('exposed_form', $form_state['values'][$section]);
+        }
+        break;    
     }
   }
 
Index: plugins/views_plugin_exposed_form.inc
===================================================================
RCS file: plugins/views_plugin_exposed_form.inc
diff -N plugins/views_plugin_exposed_form.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ plugins/views_plugin_exposed_form.inc	7 Nov 2009 14:03:19 -0000
@@ -0,0 +1,124 @@
+<?php
+// $Id: views_plugin_exposed_form.inc, Exp $
+
+/**
+ * The base plugin to handle exposed filter forms.
+ */
+class views_plugin_exposed_form extends views_plugin {
+
+  /**
+   * Initialize the plugin.
+   *
+   * @param $view
+   *   The view object.
+   * @param $display
+   *   The display handler.
+   */
+  function init(&$view, &$display, $options = NULL) {
+    $this->view = &$view;
+    $this->display = &$display;
+ 
+    $this->options = array();
+
+    $this->unpack_options($this->options, isset($options) ? $options : $display->handler->get_option('exposed_form'));
+  }
+
+  /**
+   * Return a string to display as the clickable title for the
+   * access control.
+   */
+  function summary_title() {
+    return t('Unknown');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['submit_button'] = array('default' => 'Apply');
+    $options['exposed_sorts'] = array('default' => 'Sort By');
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['submit_button'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Submit button text'),
+      '#description' => t('Text to display in the submit button of the exposed form.'),
+      '#default_value' => isset($this->options['submit_button'])?$this->options['submit_button']:'Apply',
+    );
+    
+    $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',
+    );
+  }
+  
+  /**
+   * Render the exposed filter form.
+   *
+   * This actually does more than that; because it's using FAPI, the form will
+   * also assign data to the appropriate handlers for use in building the
+   * query.
+   */
+  function render_exposed_form($block = FALSE) {
+    // Deal with any exposed filters we may have, before building.
+    $form_state = array(
+      'view' => &$this->view,
+      'display' => &$this->display,
+      'method' => 'get',
+      'rerender' => TRUE,
+      'no_redirect' => TRUE,
+      'submit_button' => isset($this->options['submit_button'])?$this->options['submit_button']:'Apply',
+      '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
+    // filters of their parent displays instead of showing an additional
+    // exposed filter form for the attachment as well as that for the parent.
+    if (!$this->view->display_handler->displays_exposed() || (!$block && $this->view->display_handler->get_option('exposed_block'))) {
+      unset($form_state['rerender']);
+    }
+
+    if (!empty($this->ajax)) {
+      $form_state['ajax'] = TRUE;
+    }
+
+    $output = drupal_build_form('views_exposed_form', $form_state);
+    if (!empty($form_state['js settings'])) {
+      $this->view->js_settings = $form_state['js settings'];
+    }
+
+    return $output;
+  }
+    
+  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() { }
+  
+  function post_render(&$output) { }
+  
+  function pre_execute() { }
+  
+  function post_execute() { }
+}
Index: plugins/views_plugin_exposed_form_basic.inc
===================================================================
RCS file: plugins/views_plugin_exposed_form_basic.inc
diff -N plugins/views_plugin_exposed_form_basic.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ plugins/views_plugin_exposed_form_basic.inc	7 Nov 2009 14:03:19 -0000
@@ -0,0 +1,13 @@
+<?php
+// $Id: views_plugin_exposed_form_basic.inc,v Exp $
+
+/**
+ * Exposed form plugin that provides basic exposed form
+ */
+class views_plugin_exposed_form_basic extends views_plugin_exposed_form {
+
+  function summary_title() {
+    return t('Basic');
+  }
+
+}
Index: plugins/views_plugin_exposed_form_on_demand.inc
===================================================================
RCS file: plugins/views_plugin_exposed_form_on_demand.inc
diff -N plugins/views_plugin_exposed_form_on_demand.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ plugins/views_plugin_exposed_form_on_demand.inc	7 Nov 2009 14:03:19 -0000
@@ -0,0 +1,74 @@
+<?php
+// $Id: views_plugin_exposed_form_basic.inc,v Exp $
+
+/**
+ * Exposed form plugin that provides basic exposed form
+ */
+class views_plugin_exposed_form_on_demand extends views_plugin_exposed_form {
+
+  function summary_title() {
+    return t('On demand');
+  }
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['submit_button'] = array('default' => 'Apply');
+    $options['text_on_demand'] = array('default' => t('Select any filter and click on Apply to see results'));
+    $options['text_on_demand_format'] = array('default' => FILTER_FORMAT_DEFAULT);
+
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);  
+    
+    $form['text_on_demand'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Text on demand'),
+      '#description' => t('Text to display instead results until user select and apply an expose filter.'),
+      '#default_value' => isset($this->options['text_on_demand'])?$this->options['text_on_demand']:t('Select any filter and click on Apply to see results.'),
+    );
+    
+    $form['text_on_demand_format'] = filter_form($this->options['text_on_demand_format'], NULL, array('text_on_demand_format'));
+  }
+  
+  function options_submit(&$form, &$form_state) {
+    $form_state['values']['exposed_form_options']['text_on_demand_format'] = $form_state['values']['text_on_demand_format'];
+
+    parent::options_submit($form, $form_state);
+  }
+
+  function exposed_filter_applied() {
+    $view = $this->view;
+    $exposed_data = $view->exposed_data;
+    if (is_array($view->filter) && count($view->filter)) {
+      foreach ($view->filter as $filter_id => $filter) {
+        if ($filter->is_exposed()) {
+          $filter_value = $exposed_data[$filter->options['expose']['identifier']];
+          if (!empty($filter_value) && $filter_value != 'All') {
+            return TRUE;
+          }
+        }
+      }
+    }
+    return FALSE;
+  }
+
+  function pre_render() {
+    if (!$this->exposed_filter_applied()) {
+      $this->view->display_handler->set_option('empty', $this->options['text_on_demand']);
+      $this->view->display_handler->set_option('empty_format', $this->options['text_on_demand_format']);
+    }
+  }
+  
+  function query() {
+    parent::query();
+    if (!$this->exposed_filter_applied()) {
+      // clear WHERE statment to display empty text
+      $this->view->query->where = array();
+      $this->view->query->add_where(0, '1 = 0');
+    }
+  }
+
+}
