Index: views.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/views.module,v retrieving revision 1.280 diff -u -p -r1.280 views.module --- views.module 27 May 2008 22:10:58 -0000 1.280 +++ views.module 28 May 2008 22:34:25 -0000 @@ -29,7 +29,7 @@ function views_theme() { $arguments = array( 'display' => array('view' => NULL), - 'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL), + 'style' => array('view' => NULL, 'options' => NULL, 'rows' => NULL, 'title' => NULL), 'row' => array('view' => NULL, 'options' => NULL, 'row' => NULL), ); Index: includes/field.handlers.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/field.handlers.inc,v retrieving revision 1.10 diff -u -p -r1.10 field.handlers.inc --- includes/field.handlers.inc 8 May 2008 21:20:31 -0000 1.10 +++ includes/field.handlers.inc 28 May 2008 22:34:25 -0000 @@ -25,6 +25,18 @@ class views_handler_field extends views_ if (!empty($this->definition['additional fields'])) { $this->additional_fields = $this->definition['additional fields']; } + + if (!isset($this->options['exclude'])) { + $this->options['exclude'] = ''; + } + } + + function init(&$view, $options) { + parent::init($view, $options); + + $this->options += array( + 'exclude' => FALSE, + ); } /** @@ -117,6 +129,12 @@ class views_handler_field extends views_ '#default_value' => isset($this->options['label']) ? $this->options['label'] : '', '#description' => t('The label for this field that will be displayed to end users if the style requires it.'), ); + $form['exclude'] = array( + '#type' => 'checkbox', + '#title' => t('Exclude from display'), + '#default_value' => $this->options['exclude'], + '#description' => t('Check this box to not display this field, but still load it in the view. Use this option to not show a grouping field in each record, or when doing advanced theming.'), + ); } /** Index: includes/plugins.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/includes/plugins.inc,v retrieving revision 1.100 diff -u -p -r1.100 plugins.inc --- includes/plugins.inc 27 May 2008 21:57:06 -0000 1.100 +++ includes/plugins.inc 28 May 2008 22:34:26 -0000 @@ -80,6 +80,8 @@ function views_views_plugins() { 'handler' => 'views_plugin_style_default', 'theme' => 'views_view_unformatted', 'uses row plugin' => TRUE, + 'uses options' => TRUE, + 'uses grouping' => TRUE, 'type' => 'normal', ), 'list' => array( @@ -2485,6 +2487,14 @@ class views_plugin_style extends views_p if ($this->uses_row_plugin() && $display->handler->get_option('row_plugin')) { $this->row_plugin = $display->handler->get_plugin('row'); } + + $this->options += array( + 'grouping' => '', + ); + + $this->definition += array( + 'uses grouping' => TRUE, + ); } /** @@ -2510,7 +2520,34 @@ class views_plugin_style extends views_p /** * Static member function to set default options. */ - function options(&$options) { } + function options(&$options) { + $options['grouping'] = ''; + } + + function options_form(&$form, &$form_state) { + // Only fields-based views can handle grouping. Style plugins can also exclude + // themselves from being groupable by setting their "use grouping" definiton + // key to FALSE. + // @TODO: Document "uses grouping" in docs.php when docs.php is written. + if ($this->uses_fields() && $this->definition['uses grouping']) { + $options = array('' => t('')); + foreach ($this->display->handler->get_option('fields') as $field) { + $label = (empty($field['label']) ? '' : $field['label'] . ' ' ) ; + $options[$field['id']] = $label . '(' . $field['id'] .')'; + } + + // If there are no fields, we can't group on them. + if (count($options) > 1) { + $form['grouping'] = array( + '#type' => 'select', + '#title' => t('Grouping field'), + '#options' => $options, + '#default_value' => $this->options['grouping'], + '#description' => t('You may optionally specify a field by which to group the records. Leave blank to not group.'), + ); + } + } + } /** * Called by the view builder to see if this style handler wants to @@ -2542,11 +2579,50 @@ class views_plugin_style extends views_p vpr('views_plugin_style_default: Missing row plugin'); return; } - $rows = array(); - foreach ($this->view->result as $row) { - $rows[] = $this->row_plugin->render($row); + + // Group the rows according to the grouping field, if specified. + $sets = $this->render_grouping($this->view->result, $this->options['grouping']); + + // Render each group separately and concatenate. Plugins may override this + // method if they wish some other way of handling grouping. + $output = ''; + foreach ($sets as $title => $records) { + $rows = array(); + foreach ($records as $label => $row) { + $rows[] = $this->row_plugin->render($row); + } + $output .= theme($this->theme_functions(), $this->view, $this->options, $rows, $title); + } + return $output; + } + + /** + * Group records as needed for rendering. + * + * @param $records + * An array of records from the view to group. + * @param $grouping_field + * The field id on which to group. If empty, the result set will be given + * a single group with an empty string as a label. + * @return + * The grouped record set. + */ + function render_grouping($records, $grouping_field = '') { + $sets = array(); + if ($grouping_field) { + foreach ($records as $row) { + // Group on the rendered version of the field, not the raw. That way, + // we can control any special formatting of the grouping field through + // the admin or theme layer or anywhere else we'd like. + $grouping = $this->view->field[$grouping_field]['handler']->theme($row); + $sets[$grouping][] = $row; + } } - return theme($this->theme_functions(), $this->view, $this->options, $rows); + else { + // Create a single group with an empty grouping field. + $sets[''] = $records; + } + return $sets; } function validate() { @@ -2567,19 +2643,28 @@ class views_plugin_style extends views_p * decorations. */ class views_plugin_style_default extends views_plugin_style { + /** + * Set default options + */ + function options(&$options) { + parent::options($options); + } + function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); // @todo -- separator option } } /** - * Style plugin to render each item in an ordered or unordered list + * Style plugin to render each item in an ordered or unordered list. */ class views_plugin_style_list extends views_plugin_style { /** * Set default options */ function options(&$options) { + parent::options($options); $options['type'] = 'ul'; } @@ -2587,6 +2672,7 @@ class views_plugin_style_list extends vi * Render the given style. */ function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); $form['type'] = array( '#type' => 'radios', '#title' => t('List type'), @@ -2604,6 +2690,7 @@ class views_plugin_style_grid extends vi * Set default options */ function options(&$options) { + parent::options($options); $options['columns'] = 4; $options['alignment'] = 'horizontal'; } @@ -2612,6 +2699,7 @@ class views_plugin_style_grid extends vi * Render the given style. */ function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); $form['columns'] = array( '#type' => 'textfield', '#title' => t('Number of columns'), @@ -2635,6 +2723,7 @@ class views_plugin_style_table extends v * Set default options */ function options(&$options) { + parent::options($options); $options['columns'] = array(); $options['default'] = ''; $options['info'] = array(); @@ -2735,6 +2824,7 @@ class views_plugin_style_table extends v * Render the given style. */ function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); $fields = $this->display->handler->get_option('fields'); if (empty($fields)) { $form['error_markup'] = array( @@ -2862,7 +2952,13 @@ class views_plugin_style_table extends v * Render the table style. */ function render() { - return theme($this->theme_functions(), $this->view, $this->options, array()); + $sets = $this->render_grouping($this->view->result, $this->options['grouping']); + + $output = ''; + foreach ($sets as $title => $records) { + $output .= theme($this->theme_functions(), $this->view, $this->options, $records, $title); + } + return $output; } } Index: theme/theme.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/theme.inc,v retrieving revision 1.44 diff -u -p -r1.44 theme.inc --- theme/theme.inc 21 May 2008 16:36:19 -0000 1.44 +++ theme/theme.inc 28 May 2008 22:34:26 -0000 @@ -141,7 +141,7 @@ function template_preprocess_views_view_ // Loop through the fields for this view. $inline = FALSE; foreach ($view->field as $id => $field) { - if (!empty($field['handler']) && is_object($field['handler'])) { + if (!empty($field['handler']) && is_object($field['handler']) && empty($field['exclude'])) { $object = new stdClass(); $object->content = $field['handler']->theme($vars['row']); @@ -217,7 +217,14 @@ function template_preprocess_views_view_ */ function template_preprocess_views_view_table(&$vars) { $view = $vars['view']; - $result = $view->result; + + // We need the raw data for this grouping, which is passed in as $vars['rows']. + // However, the template also needs to use for the rendered fields. We + // therefore swap the raw data out to a new variable and reset $vars['rows'] + // so that it can get rebuilt. + $result = $vars['rows']; + $vars['rows'] = array(); + $options = $view->style_plugin->options; $handler = $view->style_plugin; @@ -231,10 +238,10 @@ function template_preprocess_views_view_ if ($query) { $query = '&' . $query; } - + foreach ($columns as $field => $column) { // render the header labels - if ($field == $column) { + if ($field == $column && empty($fields[$field]['exclude'])) { $label = check_plain(!empty($fields[$field]['handler']) ? $fields[$field]['handler']->label() : ''); if (empty($options['info'][$field]['sortable'])) { $vars['header'][$field] = $label; @@ -267,7 +274,7 @@ function template_preprocess_views_view_ // Render each field into its appropriate column. foreach ($result as $num => $row) { - if (!empty($fields[$field]['handler']) && is_object($fields[$field]['handler'])) { + if (!empty($fields[$field]['handler']) && is_object($fields[$field]['handler']) && empty($fields[$field]['exclude'])) { $handler = &$fields[$field]['handler']; $field_output = $handler->theme($row); Index: theme/views-view-grid.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/views-view-grid.tpl.php,v retrieving revision 1.1 diff -u -p -r1.1 views-view-grid.tpl.php --- theme/views-view-grid.tpl.php 20 Apr 2008 23:41:06 -0000 1.1 +++ theme/views-view-grid.tpl.php 28 May 2008 22:34:26 -0000 @@ -10,6 +10,9 @@ * @ingroup views_templates */ ?> + +

+ $columns): ?> Index: theme/views-view-list.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/views-view-list.tpl.php,v retrieving revision 1.1 diff -u -p -r1.1 views-view-list.tpl.php --- theme/views-view-list.tpl.php 15 Feb 2008 04:11:48 -0000 1.1 +++ theme/views-view-list.tpl.php 28 May 2008 22:34:26 -0000 @@ -4,11 +4,15 @@ * @file views-view-list.tpl.php * Default simple view template to display a list of rows. * + * - $title : The title of this group of rows. May be empty. * - $options['type'] will either be ul or ol. * @ingroup views_templates */ ?>
+ +

+ <>
  • Index: theme/views-view-table.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/views-view-table.tpl.php,v retrieving revision 1.4 diff -u -p -r1.4 views-view-table.tpl.php --- theme/views-view-table.tpl.php 14 May 2008 01:32:55 -0000 1.4 +++ theme/views-view-table.tpl.php 28 May 2008 22:34:26 -0000 @@ -4,6 +4,7 @@ * @file views-view-table.tpl.php * Template to display a view as a table. * + * - $title : The title of this group of rows. May be empty. * - $header: An array of header labels keyed by field id. * - $fields: An array of CSS IDs to use for each field id. * - $class: A class or classes to apply to the table, based on settings. @@ -13,6 +14,9 @@ */ ?>
    + + + $label): ?> Index: theme/views-view-unformatted.tpl.php =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views/theme/views-view-unformatted.tpl.php,v retrieving revision 1.2 diff -u -p -r1.2 views-view-unformatted.tpl.php --- theme/views-view-unformatted.tpl.php 15 Feb 2008 04:11:48 -0000 1.2 +++ theme/views-view-unformatted.tpl.php 28 May 2008 22:34:26 -0000 @@ -7,6 +7,9 @@ * @ingroup views_templates */ ?> + +

    + \ No newline at end of file