Index: README.txt
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_bonus/README.txt,v
retrieving revision 1.6
diff -u -F^f -r1.6 README.txt
--- README.txt	4 Nov 2006 22:59:00 -0000	1.6
+++ README.txt	22 Feb 2007 20:36:54 -0000
@@ -24,6 +24,30 @@
 
 Panels: By term, 3 columns
   Requires panels.module -- terms presented as tables within columns such as http://sfbay.craigslist.org/.
+
+Bonus: Cross Table - Basic
+  Creates a table where field values are used as row/column coordinates. The
+  first field in the fields list (in the Views UI) designates the row, the
+  second the column, and subsequent selected fields are placed into the table
+  cells. For example, given a set of four nodes with CCK fields Room and Time:
+  Node 1: Title="Morning Cartoons", Room="Room 101, Time="10am"
+  Node 2: Title="Evening Cartoons", Room="Room 101, Time="11am"
+  Node 3: Title="Morning Soaps",    Room="Room 102, Time="10am"
+  Node 4: Title="Evening Soaps",    Room="Room 102, Time="11am"
+
+  With field 1 = Time, field 2 = Room, and field 3 = Title, the following
+  table would be created:
+  Time  Room 101          Room 102
+  ====  ================  =============
+  10am  Morning Cartoons  Morning Soaps
+  11am  Evening Cartoons  Evening Soaps
+
+Bonus: Cross Table - Extended
+  This special version of Cross Table adds the following feature:
+  Row Value: All
+  A row value of "All" will display across all the columns in that row (using
+  td colspan attribute). This is useful for displaying a coffee or lunch break
+  in a schedule.
   
 Bonus: Grid View
   Displays items in a very simple 4 across table; the CSS sets the
Index: views_bonus_crosstab.info
===================================================================
RCS file: views_bonus_crosstab.info
diff -N views_bonus_crosstab.info
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views_bonus_crosstab.info	22 Feb 2007 20:36:54 -0000
@@ -0,0 +1,4 @@
+name = Bonus: Cross Table
+description = "Views Plug-In for making Cross Tables (Useful for schedules and similar kinds of tables)"
+package = Views
+dependencies = views
\ No newline at end of file
Index: views_bonus_crosstab.module
===================================================================
RCS file: views_bonus_crosstab.module
diff -N views_bonus_crosstab.module
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views_bonus_crosstab.module	22 Feb 2007 20:36:54 -0000
@@ -0,0 +1,256 @@
+<?php
+// $Id$
+
+/**
+ * Define plugins
+ */
+function views_bonus_crosstab_views_style_plugins() {
+  $items = array();
+  $items['crosstab_plain'] = array(
+    'name' => t('Bonus: Cross Table - Basic'),
+    'theme' => 'views_bonus_crosstab_basic',
+    'validate' => 'views_ui_plugin_validate_list',
+    'needs_fields' => true
+  );
+  $items['crosstab_special'] = array(
+    'name' => t('Bonus: Cross Table - Extended'),
+    'theme' => 'views_bonus_crosstab_extended',
+    'validate' => 'views_ui_plugin_validate_list',
+    'needs_fields' => true
+  );
+  return $items;
+}
+
+
+function theme_views_bonus_crosstab_basic($view, $nodes, $type) {
+  if (file_exists(path_to_theme() .'/views-crosstab.css')) {
+    drupal_add_css(path_to_theme() .'/views-crosstab.css');
+  }
+  if (file_exists(path_to_theme() .'/views-' . $view->name . '.css')) {
+    drupal_add_css(path_to_theme() .'/views-' . $view->name . '.css');
+  }
+
+  $fields = _views_get_fields();
+
+  // This needs to be replaced with proper checking on the form
+  if (count($view->field) == 1) {
+    $content .= '<p><strong>The next field you add to this view will be the column</strong></p>';
+  }
+  if (count($view->field) == 2) {
+    $content .= '<p><strong>The next field or fields you add to this view will become table cell data</strong></p>';
+  }
+  
+  // Fetch the table structure inforomation
+  $cellfields = array();
+  foreach ($view->field as $fielddata) {
+    switch ($fielddata['position']) {
+      case '0':
+        $rowfieldname = $fielddata['queryname'];
+        $rowfieldlabel = $fielddata['label'];
+        break;
+      case '1':
+        $colfieldname = $fielddata['queryname'];
+        $colfieldlabel = $fielddata['label'];
+        break;
+      default:
+        $cellfields[$fielddata['position']] = $fielddata;
+    }
+  }
+  ksort($cellfields);
+
+  //
+  // Collate nodes into a multi-dimensional array
+  // $tablecells[row][column][node-index-number]node
+  //
+  $tablecells = array();
+  $colnames = array();
+  foreach ($nodes as $node) {
+    $row    = $node->$rowfieldname;
+    $column = $node->$colfieldname;
+    if (!in_array($column,$colnames)) {
+      $colnames[] = $column;
+    }
+    $tablecells[$row][$column][] = $node;
+  }  
+  sort($colnames);
+  
+  //
+  // Create the table
+  //
+  
+  // Some handy text strings
+  $rowlabeldiv = '<div class="view-crosstab-rowlabel view-' . $view->name . '-rowlabel">';
+  $itemdiv     = '<div class="view-crosstab-item view-' . $view->name . '-item">';
+  
+  // Start table
+  $content .= '<table class="view-crosstab view-' . $view->name . "\" >\n";
+
+  // Header Row
+  $content .= '<tr class="header">';
+  $content .= '<th>' . $rowfieldlabel . '</th>'; // Column heading for row field
+  foreach ($colnames as $columnlabel) {
+    $content .= '<th>' . $columnlabel . '</th>';
+  }
+  $content .= "</tr>\n";
+  
+  // Table Body
+  $count = 1;
+  foreach ($tablecells as $tablerowname => $columncells) { // table rows
+    $content .= '<tr class="' . (($count % 2) ? "odd" : "even") . '-row" >';
+    // Leftmost column/label for the row
+    $content .= '<td class="rowlabel">' . $rowlabeldiv . $tablerowname . '</div></td>';
+    // Remaining table columns
+    foreach ($colnames as $columnname) {  // table columns
+      $content .= '<td>';
+      foreach ((array)$columncells[$columnname] as $cellnode) { // cell nodes
+        $content .= $itemdiv;
+        $content .= _format_cell_item($cellfields, $cellnode, $view, $fields);
+        $content .= '</div>';
+      }
+      $content .= '</td>';
+    }
+    $content .= "</tr>\n";
+    $count++;
+  }
+  $content .= "</table>\n";
+
+  return $content;
+}
+
+
+function theme_views_bonus_crosstab_extended($view, $nodes, $type) {
+  if (file_exists(path_to_theme() .'/views-crosstabx.css')) {
+    drupal_add_css(path_to_theme() .'/views-crosstabx.css');
+  }
+  if (file_exists(path_to_theme() .'/views-' . $view->name . '.css')) {
+    drupal_add_css(path_to_theme() .'/views-' . $view->name . '.css');
+  }
+
+  $fields = _views_get_fields();
+
+  // This needs to be replaced with proper checking on the form
+  if (count($view->field) == 1) {
+    $content .= '<p><strong>The next field you add to this view will be the column</strong></p>';
+  }
+  if (count($view->field) == 2) {
+    $content .= '<p><strong>The next field or fields you add to this view will become table cell data</strong></p>';
+  }
+  
+  
+  // Fetch the table structure inforomation
+  $cellfields = array();
+  foreach ($view->field as $fielddata) {
+    switch ($fielddata['position']) {
+      case '0':
+        $rowfieldname = $fielddata['queryname'];
+        $rowfieldlabel = $fielddata['label'];
+        break;
+      case '1':
+        $colfieldname = $fielddata['queryname'];
+        $colfieldlabel = $fielddata['label'];
+        break;
+      default:
+        $cellfields[$fielddata['position']] = $fielddata;
+    }
+  }
+  ksort($cellfields);
+
+  //
+  // Collate nodes into a multi-dimensional array
+  // $tablecells[row][column][cell-field-index]
+  //
+  $tablecells      = array();
+  $colnames        = array();
+  $spancolumnslist = array();
+  foreach ($nodes as $node) {
+    $row    = $node->$rowfieldname;
+    $column = $node->$colfieldname;
+    if (!in_array($column,$colnames)) {
+      $colnames[] = $column;
+    }
+    $tablecells[$row][$column][] = $node;
+    if ($column == 'All') {
+      $spancolumnslist[] = $row;
+    }
+  }  
+  if (in_array('All', $colnames)) {
+    unset($colnames[array_search('All', $colnames)]);
+  }
+  sort($colnames);
+  
+  //
+  // Create the table
+  //
+  
+  // Some handy rtext strings
+  $rowlabeldiv  = '<div class="view-crosstabx-rowlabel view-' . $view->name . '-rowlabel">';
+  $itemdiv      = '<div class="view-crosstabx-item view-' . $view->name . '-item">';
+  $allitemdiv   = '<div class="view-crosstabx-allitem view-' . $view->name . '-allitem">';
+
+  // Start table
+  $content .= '<table class="view-crosstabx view-' . $view->name . "\" >\n";
+
+  // Header Row
+  $content .= '<tr class="header">';
+  $content .= '<th>' . $rowfieldlabel . '</th>'; // Column heading for row field
+  foreach ($colnames as $columnlabel) {
+    $content .= '<th>' . $columnlabel . '</th>';
+  }
+  $content .= "</tr>\n";
+  
+  // Table Body
+  $count = 1;
+  foreach ($tablecells as $tablerowname => $columncells) {
+    $content .= '<tr class="' . (($count % 2) ? "odd" : "even") . '-row" >';
+    // Leftmost column/label for the row
+    $content .= '<td class="rowlabel">' . $rowlabeldiv . $tablerowname . '</div></td>';
+    // Remaining table columns
+    // Test to see if all data columns should be spanned
+    if (in_array($tablerowname, $spancolumnslist)) {
+      // Span all of the columns and place all cells in a single cell
+      $content .= '<td colspan="' . count($colnames) . '" class="spanall">';
+      $content .= $allitemdiv;
+      foreach ($columncells as $columnname => $cellnodes) {
+        foreach ($cellnodes as $cellnode) {
+          $content .= $itemdiv;
+          $content .= _format_cell_item($cellfields, $cellnode, $view, $fields);
+          $content .= '</div>';
+        }
+      }
+      $content .= '</div></td>';
+    } else {
+      // Place each cell in its own column
+      foreach ($colnames as $columnname) {  // table columns
+        $content .= '<td>';
+        foreach ((array)$columncells[$columnname] as $cellnode) { // cell nodes
+          $content .= $itemdiv;
+          $content .= _format_cell_item($cellfields, $cellnode, $view, $fields);
+          $content .= '</div>';
+        }
+        $content .= '</td>';
+      }
+    }
+    $content .= "</tr>\n";
+    $count++;
+  }
+  $content .= "</table>\n";
+
+  return $content;
+}
+
+
+function _format_cell_item($nodedisplayfields, $node, $view, $fields) {
+  $item = '';
+  foreach ($nodedisplayfields as $field) {
+    if ($fields[$field['id']]['visible'] !== FALSE) {
+      if ($field['label']) {
+        $item .= "<div class='view-label view-label-$field[queryname]'>" . $field['label'] . "</div>";
+      }
+      $item .= "<div class='view-field view-data-$field[queryname]'>"
+               . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view)
+               . "</div>";
+    }
+  }
+
+  return $item;  
+}
