Index: modules/views_bonus/README.txt =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/views_bonus/README.txt,v retrieving revision 1.9 diff -u -p -r1.9 README.txt --- modules/views_bonus/README.txt 11 Mar 2007 19:12:26 -0000 1.9 +++ modules/views_bonus/README.txt 19 Apr 2007 09:36:49 -0000 @@ -25,6 +25,29 @@ Panels: Teasers, 3 columns Panels: By term, 3 columns Requires panels.module -- terms presented as tables within columns such as http://sfbay.craigslist.org/. +Bonus: Cross Table + 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 + + If room is a multivalue field, and more than one room is checked for a node, + the node will colspan those columns. + Bonus: Grid View Displays items in a very simple 4 across table; the CSS sets the table to 100%, but this is easily overridden if you like. It is good Index: modules/views_bonus/views_bonus_crosstab.info =================================================================== RCS file: modules/views_bonus/views_bonus_crosstab.info diff -N modules/views_bonus/views_bonus_crosstab.info --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/views_bonus/views_bonus_crosstab.info 19 Apr 2007 09:36:49 -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 Index: modules/views_bonus/views_bonus_crosstab.module =================================================================== RCS file: modules/views_bonus/views_bonus_crosstab.module diff -N modules/views_bonus/views_bonus_crosstab.module --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/views_bonus/views_bonus_crosstab.module 19 Apr 2007 09:36:49 -0000 @@ -0,0 +1,260 @@ + t('Bonus: Cross Table'), + 'theme' => 'views_bonus_crosstab', + 'validate' => 'views_bonus_crosstab_validate', + 'needs_fields' => TRUE, + ); + return $items; +} + +/** + * View plugin validation callback. + */ +function views_bonus_crosstab_validate($type, $view, $form) { + // Validate as a table. + views_ui_plugin_validate_table($type, $view, $form); + + // Make sure at least three fields are specified. + if ($view['field']['count'] < 3) { + form_error($form['field']['add']['id'], t('Cross Table type requires at least three fields; the first field will be the row value, the second field the column value, and additional fields will be displayed for each node within the table cells.')); + } + + // TODO: Other validation? Turning off paging, setting number of nodes to high value? +} + +/** + * Themes output of a cross table view. + * + * @ingroup themeable + */ +function theme_views_bonus_crosstab($view, $nodes, $type) { + $fields = _views_get_fields(); + + // Fetch the table structure information. + $cellfields = array(); + foreach ($view->field as $fielddata) { + switch ($fielddata['position']) { + case '0': + $rowdata = $fielddata; + break; + case '1': + $coldata = $fielddata; + 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->$rowdata['queryname']; + // TODO: We should be able to handle multivalue columns... + $column = $node->$coldata['queryname']; + if (!in_array($column, $colnames)) { + $colnames[$node->nid] = $column; + $colnodes[$node->nid] = $node; + } + $tablecells[$row][$column][] = $node; + } + + // + // Create the table + // + + // Header Row + $header = array($rowdata['label']); + foreach ($colnames as $nid => $columnlabel) { + $header[] = views_theme_field('views_handle_field', $coldata['queryname'], $fields, $coldata, $colnodes[$nid], $view); + } + $column_count = count($header); + + // Table Body + $rows = array(); + foreach ($tablecells as $tablerowname => $columncells) { // table rows + $header_col = array(); + $row = array(); + foreach ($colnames as $columnname) { // table columns + if (isset($columncells[$columnname])) { + foreach ($columncells[$columnname] as $cellnode) { // cell nodes + if (empty($header_col)) { + $header_col[] = array( + 'data' => views_theme_field('views_handle_field', $rowdata['queryname'], $fields, $rowdata, $cellnode, $view), + 'class' => 'rowlabel', + ); + } + // TODO: If item is in more than one column, colspan. + // TODO: rowspan...? + $row[] = array( + 'data' => theme('crosstab_item', $cellfields, $cellnode, $view, $fields), + // 'colspan' => X, + ); + } + } + else { + // No record was found for this intersection. + $row[] = t('x'); + } + } + $rows[] = array_merge($header_col, $row); + } + + return theme('table', $header, $rows, array('class' => 'view-crosstab view-' . $view->name)); +} + + +/** + * Theme contents of table cell. + * + * @ingroup themeable + */ +function theme_crosstab_item($nodedisplayfields, $node, $view, $fields) { + $item = ''; + foreach ($nodedisplayfields as $field) { + if ($fields[$field['id']]['visible'] !== FALSE) { + if ($field['label']) { + $item .= "
" . $field['label'] . "
"; + } + $item .= "
" + . views_theme_field('views_handle_field', $field['queryname'], $fields, $field, $node, $view) + . "
"; + } + } + + return $item; +} + + +/////////// TODO: Delete me, and make the default 'cross table' view work like this. + +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 .= '

The next field you add to this view will be the column

'; + } + if (count($view->field) == 2) { + $content .= '

The next field or fields you add to this view will become table cell data

'; + } + + + // 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 = '
'; + $itemdiv = '
'; + $allitemdiv = '
'; + + // Start table + $content .= '\n"; + + // Header Row + $content .= ''; + $content .= ''; // Column heading for row field + foreach ($colnames as $columnlabel) { + $content .= ''; + } + $content .= "\n"; + + // Table Body + $count = 1; + foreach ($tablecells as $tablerowname => $columncells) { + $content .= ''; + // Leftmost column/label for the row + $content .= ''; + // 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 .= ''; + } else { + // Place each cell in its own column + foreach ($colnames as $columnname) { // table columns + $content .= ''; + } + } + $content .= "\n"; + $count++; + } + $content .= "
' . $rowfieldlabel . '' . $columnlabel . '
' . $rowlabeldiv . $tablerowname . ''; + $content .= $allitemdiv; + foreach ($columncells as $columnname => $cellnodes) { + foreach ($cellnodes as $cellnode) { + $content .= $itemdiv; + $content .= theme('crosstab_item', $cellfields, $cellnode, $view, $fields); + $content .= ''; + } + } + $content .= ''; + foreach ((array)$columncells[$columnname] as $cellnode) { // cell nodes + $content .= $itemdiv; + $content .= theme('crosstab_item', $cellfields, $cellnode, $view, $fields); + $content .= ''; + } + $content .= '
\n"; + + return $content; +}