Index: views_bonus.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/views_bonus/views_bonus.module,v
retrieving revision 1.1
diff -u -r1.1 views_bonus.module
--- views_bonus.module	25 Jul 2006 00:06:48 -0000	1.1
+++ views_bonus.module	11 Sep 2006 14:27:33 -0000
@@ -1,160 +1,557 @@
-<?php
-// $Id: views_bonus.module,v 1.1 2006/07/25 00:06:48 merlinofchaos Exp $
-
-function views_bonus_help($section = NULL) {
-  switch ($section) {
-    case 'admin/modules#description':
-      return t('A collection of plugins and default views for the views module.');
-  }
-}
-
-/**
- * Define plugins
- */
-function views_bonus_views_style_plugins() {
-  $items = array();
-  if (module_exist('panels')) {
-    $items['panels_twocol_stk'] = array(
-      'name' => t('Panels: Teasers, 1 top + 2 columns'),
-      'theme' => 'views_bonus_panels_twocol_stacked',
-    );
-    $items['panels_twocol'] = array(
-      'name' => t('Panels: Teasers, 2 columns'),
-      'theme' => 'views_bonus_panels_twocol',
-    );
-    $items['panels_threecol_stk'] = array(
-      'name' => t('Panels: Teasers, 1 top + 3 columns'),
-      'theme' => 'views_bonus_panels_threecol_stacked',
-    );
-    $items['panels_threecol'] = array(
-      'name' => t('Panels: Teasers, 3 columns'),
-      'theme' => 'views_bonus_panels_threecol',
-    );
-  }  
-  return $items;
-}
-
-// --------------------------------------------------------------------------
-// Plugin themes
-
-/**
- * Because views doesn't currently support configuration options for
- * plugins, the best way to make configuration changes here is 
- * to override the theme.
- */
-function theme_views_bonus_panels_twocol_stacked($view, $nodes, $type) {
-  $teasers = true;
-  $links = true;
-
-  if (!module_exist('panels')) {
-    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
-  }
-
-  $content = array();
-  foreach ($nodes as $count => $n) {
-    $node = node_load($n->nid);
-    if ($count == 0) {
-      $section = 'top';
-    }
-    else if ($count % 2) {
-      $section = 'left';
-    }
-    else {
-      $section = 'right';
-    }
-
-    $content[$section] .= node_view($node, $teasers, false, $links);
-  }
-  return panels_print_layout('twocol_stacked', $content);
-}
-
-/**
- * Same as above but doesn't put one in the top content section.
- */
-function theme_views_bonus_panels_twocol($view, $nodes, $type) {
-  $teasers = true;
-  $links = true;
-
-  if (!module_exist('panels')) {
-    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
-  }
-
-  $content = array();
-  foreach ($nodes as $count => $n) {
-    $node = node_load($n->nid);
-    if ($count % 2) {
-      $section = 'right';
-    }
-    else {
-      $section = 'left';
-    }
-
-    $content[$section] .= node_view($node, $teasers, false, $links);
-  }
-  return panels_print_layout('twocol', $content);
-}
-
-/**
- * Similar to above; 1 top, 1 per each of 3 columns
- */
-function theme_views_bonus_panels_threecol_stacked($view, $nodes, $type) {
-  $teasers = true;
-  $links = true;
-
-  if (!module_exist('panels')) {
-    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
-  }
-
-  $content = array();
-  foreach ($nodes as $count => $n) {
-    $node = node_load($n->nid);
-    if ($count == 0) {
-      $section = 'top';
-    }
-    else switch (($count - 1) % 3) {
-      case 0:
-        $section = 'left';
-        break;
-      case 1:
-        $section = 'middle';
-        break;
-      case 2:
-        $section = 'right';
-        break;
-    }
-
-    $content[$section] .= node_view($node, $teasers, false, $links);
-  }
-  return panels_print_layout('threecol_33_34_33_stacked', $content);
-}
-
-/**
- * Same as above but doesn't put one in the top content section.
- */
-function theme_views_bonus_panels_threecol($view, $nodes, $type) {
-  $teasers = true;
-  $links = true;
-
-  if (!module_exist('panels')) {
-    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
-  }
-
-  $content = array();
-  foreach ($nodes as $count => $n) {
-    $node = node_load($n->nid);
-    switch ($count % 3) {
-      case 0:
-        $section = 'left';
-        break;
-      case 1:
-        $section = 'middle';
-        break;
-      case 2:
-        $section = 'right';
-        break;
-    }
-
-    $content[$section] .= node_view($node, $teasers, false, $links);
-  }
-  return panels_print_layout('threecol_33_34_33', $content);
-}
+<?php
+// $Id: views_bonus.module,v 1.1 2006/07/25 00:06:48 merlinofchaos Exp $
+
+function views_bonus_help($section = NULL) {
+  switch ($section) {
+    case 'admin/modules#description':
+      return t('A collection of plugins and default views for the views module.');
+  }
+}
+
+/**
+ * Define plugins
+ */
+function views_bonus_views_style_plugins() {
+  $items = array();
+  if (module_exist('panels')) {
+    $items['panels_twocol_stk'] = array(
+      'name' => t('Panels: Teasers, 1 top + 2 columns'),
+      'theme' => 'views_bonus_panels_twocol_stacked',
+      'summary_theme' => 'views_summary',
+    );
+    $items['panels_twocol'] = array(
+      'name' => t('Panels: Teasers, 2 columns'),
+      'theme' => 'views_bonus_panels_twocol',
+      'summary_theme' => 'views_summary',
+    );
+    $items['panels_threecol_stk'] = array(
+      'name' => t('Panels: Teasers, 1 top + 3 columns'),
+      'theme' => 'views_bonus_panels_threecol_stacked',
+      'summary_theme' => 'views_summary',
+    );
+    $items['panels_threecol'] = array(
+      'name' => t('Panels: Teasers, 3 columns'),
+      'theme' => 'views_bonus_panels_threecol',
+      'summary_theme' => 'views_summary',
+    );
+  }
+  $items['summary_combo'] = array(
+    'name' => t('Bonus: Summary + full view'),
+    'theme' => 'views_bonus_summary_combo',
+    'summary_theme' => 'views_bonus_summary_combo_summary',
+  );
+  if (module_exist('lineage') && module_exist('taxonomy')) {
+    $items['lineage_tree'] = array(
+      'name' => t('Lineage: Nested taxonomy summary'),
+      'theme' => 'views_bonus_lineage_tree',
+      'summary_theme' => 'views_bonus_lineage_tree_summary',
+      'needs_fields' => TRUE,
+    );
+  }
+  return $items;
+}
+
+// --------------------------------------------------------------------------
+// Plugin themes
+
+/**
+ * Because views doesn't currently support configuration options for
+ * plugins, the best way to make configuration changes here is 
+ * to override the theme.
+ */
+function theme_views_bonus_panels_twocol_stacked($view, $nodes, $type) {
+  $teasers = true;
+  $links = true;
+
+  if (!module_exist('panels')) {
+    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
+  }
+
+  $content = array();
+  foreach ($nodes as $count => $n) {
+    $node = node_load($n->nid);
+    if ($count == 0) {
+      $section = 'top';
+    }
+    else if ($count % 2) {
+      $section = 'left';
+    }
+    else {
+      $section = 'right';
+    }
+
+    $content[$section] .= node_view($node, $teasers, false, $links);
+  }
+  return panels_print_layout('twocol_stacked', $content);
+}
+
+/**
+ * Same as above but doesn't put one in the top content section.
+ */
+function theme_views_bonus_panels_twocol($view, $nodes, $type) {
+  $teasers = true;
+  $links = true;
+
+  if (!module_exist('panels')) {
+    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
+  }
+
+  $content = array();
+  foreach ($nodes as $count => $n) {
+    $node = node_load($n->nid);
+    if ($count % 2) {
+      $section = 'right';
+    }
+    else {
+      $section = 'left';
+    }
+
+    $content[$section] .= node_view($node, $teasers, false, $links);
+  }
+  return panels_print_layout('twocol', $content);
+}
+
+/**
+ * Similar to above; 1 top, 1 per each of 3 columns
+ */
+function theme_views_bonus_panels_threecol_stacked($view, $nodes, $type) {
+  $teasers = true;
+  $links = true;
+
+  if (!module_exist('panels')) {
+    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
+  }
+
+  $content = array();
+  foreach ($nodes as $count => $n) {
+    $node = node_load($n->nid);
+    if ($count == 0) {
+      $section = 'top';
+    }
+    else switch (($count - 1) % 3) {
+      case 0:
+        $section = 'left';
+        break;
+      case 1:
+        $section = 'middle';
+        break;
+      case 2:
+        $section = 'right';
+        break;
+    }
+
+    $content[$section] .= node_view($node, $teasers, false, $links);
+  }
+  return panels_print_layout('threecol_33_34_33_stacked', $content);
+}
+
+/**
+ * Same as above but doesn't put one in the top content section.
+ */
+function theme_views_bonus_panels_threecol($view, $nodes, $type) {
+  $teasers = true;
+  $links = true;
+
+  if (!module_exist('panels')) {
+    return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
+  }
+
+  $content = array();
+  foreach ($nodes as $count => $n) {
+    $node = node_load($n->nid);
+    switch ($count % 3) {
+      case 0:
+        $section = 'left';
+        break;
+      case 1:
+        $section = 'middle';
+        break;
+      case 2:
+        $section = 'right';
+        break;
+    }
+
+    $content[$section] .= node_view($node, $teasers, false, $links);
+  }
+  return panels_print_layout('threecol_33_34_33', $content);
+}
+
+// --------------------------------------------------------------------------
+// Combo theme with summary on top and full view below
+
+/**
+ *  Combo full page theme
+ *  $level, $args, and $summary are only available if called by summary view
+ */
+function theme_views_bonus_summary_combo($view, $nodes, $type, $level = NULL, $args = NULL, $summary = FALSE) {
+  
+  $teasers = true;
+  $links = true;
+  
+  // keep the title from displaying both in the summary and full view
+  drupal_set_title($title);
+  unset($view->page_title);
+
+  // create page bottom first -- may be either a full view or a summary view
+  // it is possible to have several levels of summary views if multiple arguments set to summary are used
+
+  if ($summary && $level == 0 && isset($view->argument[0])) {
+    // don't display bottom if it will be same top level summary view displayed on top
+    $bottom = '';
+  }
+  elseif ($summary) {
+    // a summary view on the bottom of the page should be the regular summary view
+    $bottom = theme('views_summary', $view, $type, $level, $nodes, $args);
+  }
+  else {
+    // otherwise display the full view
+    $bottom = theme('views_view_nodes', $view, $nodes, $view->page_type, $teasers, $links);
+  } 
+
+  // the summary view on the top of the page should always be the top level summary view
+  // create this only after bottom view has been generated to avoid wiping out values from the original view
+  
+  if (isset($view->argument[0])) {
+    $summary = views_build_view('items', $view, array(), false, $view->nodes_per_page);
+    $top = theme('views_bonus_summary_combo_top', $view, $summary['items']);
+  }
+  return $top . $bottom;
+
+}
+
+/**
+ *  The combo summary theme, a wrapper function to send summary page theme through the full page theme
+ *  passing along $level, $args, and setting $summary = TRUE
+ */
+function theme_views_bonus_summary_combo_summary($view, $type, $level, $nodes, $args) {
+  return theme_views_bonus_summary_combo($view, $nodes, $type, $level, $args, TRUE);
+}
+
+/**
+ *  Style the summary list to be wide (side by side) instead of long when used above the full view
+ *  @return item list adapted with | separator and css to display list inline
+ */
+function theme_views_bonus_summary_combo_top($view, $nodes) {
+  
+  theme_add_style(drupal_get_path('module', 'views_bonus') .'/views_bonus.css');
+  foreach ($nodes as $node) {
+    $items[] = views_get_summary_link($view->argument[0]['type'], $node, $view->url)  . "&nbsp;(" . $node->num_nodes . ")&nbsp;| ";
+  }
+  if ($items) {
+    return '<div id="views_bonus_summary_top">'. theme('item_list', $items) .'</div>';
+  }
+
+}
+
+// --------------------------------------------------------------------------
+// Nested taxonomy tree summary view (displays teaser view for full page)
+
+/**
+ *  Nested taxonomy tree plugin displays teasers for full view
+ *  Override theme to display something else
+ */
+function theme_views_bonus_lineage_tree($view, $nodes, $type) {
+  $teasers = true;
+  $links = true;
+  return theme('views_view_nodes', $view, $nodes, $type, $teasers, $links);
+}
+
+/**
+ *  Nested taxonomy tree plugin summary view
+ *  This is the theme that creates the nested taxonomy view
+ */
+function theme_views_bonus_lineage_tree_summary($view, $type, $level, $nodes, $args) {
+  
+  // if lineage info is missing or this summary has no tid, bail out to normal summary view
+  if (!module_exist('lineage') || !module_exist('taxonomy') || !array_key_exists('tid', $nodes[0])) {
+    return theme('views_summary', $view, $type, $level, $nodes, $args);
+  }
+  
+  $trees = array();
+  foreach ($nodes as $node) {
+    // get terms for each node, add depth to term info
+    // and create sorted array of values
+    $term = taxonomy_get_term($node->tid);
+    $node->depth = $node->term_lineage_depth ? $node->term_lineage_depth : -1;
+    $items[$term->vid][$node->tid] = $node; 
+  }
+  
+  $output = '';
+  foreach ($items as $vid => $terms) {
+    $last_depth = -1;
+    foreach ($terms as $term) {
+    
+      // Adjust the depth of the <ul> based on the change
+      // in $term->depth since the $last_depth.
+
+      if ($term->depth > $last_depth) {
+        $output .= "\n" . '<ul>' . "\n";
+      }
+      else if ($term->depth < $last_depth) {
+     
+      for ($i = 0; $i < ($last_depth - $term->depth); $i++) {
+          $output .= '</li>' . "\n";
+          $output .= '</ul>' . "\n";
+        }
+      }
+      else {
+        $output .= '</li>' . "\n";
+      }
+      // Display the $term.
+      $output .= '<li>';
+    
+      $output .= views_get_summary_link($view->argument[$level]['type'], $term, $view->real_url) 
+      .' ('. $term->num_nodes .')';
+    
+      // Reset $last_depth in preparation for the next $term.
+      $last_depth = $term->depth;
+    }
+
+    // Bring the depth back to where it began, -1.
+    if ($last_depth > -1) {
+      for ($i = 0; $i < ($last_depth + 1); $i++) {
+        $output .= '</li>' . "\n";
+        $output .= '</ul>' . "\n";
+      }
+    }
+  }
+  return $output;
+}
+
+/**
+ *  This handler provides a way to limit a taxonomy tree listing to a specific branch of the tree
+ */
+function views_bonus_lineage_tree_branch_arg($op, &$query, $argtype, $arg = '') {
+  
+  if (!module_exist('lineage') || !module_exist('taxonomy')) {
+    return;
+  }
+
+  switch($op) {
+    case 'summary':
+      // join in the lineage table to get hierarchy info for nested tree view of options
+      // and the term_data table to get the term name for each lineage item
+      $query->add_table('term_node');
+      $query->add_table('term_lineage', false, 1, array('left' => array('table' => 'term_node', 'field' => 'tid'), 'right' => array('field' => 'tid')));
+      $query->add_table('term_data', false, 1, array('left' => array('table' => 'term_lineage', 'field' => 'tid'), 'right' => array('field' => 'tid')));
+      $query->add_field('tid', 'term_lineage', 'tid');
+      $fieldinfo['field'] = "term_data.name";
+      $fieldinfo['fieldname'] = 'name';
+      return $fieldinfo;
+      break;
+    case 'sort':
+      $query->add_orderby('term_lineage', 'lineage', $argtype);
+      break;
+    case 'filter':
+      // filter for any lineage that contains the requested value
+      $query->add_where("term_lineage.lineage LIKE '%0$arg\n%'");
+      break;
+    case 'link':
+      return l($query->name, "$arg/$query->name");
+    case 'title':
+      return check_plain($query);
+  }
+
+}
+
+// --------------------------------------------------------------------------
+// Implementation of hook_views_query_alter()
+// may be needed by other plugins
+
+function views_bonus_views_query_alter(&$query, &$view, $summary, $level) {
+  
+  if ($view->page_type == 'lineage_tree' && module_exist('lineage') && module_exist('taxonomy')) {
+    
+    // these must be in taxonomy tree query for it to work correctly
+    if (!in_array('term_lineage.depth', $query->fields)) {
+      $query->add_field('depth', 'term_lineage', 'term_lineage_depth');
+    }
+    if (!in_array('term_lineage.lineage', $query->fields)) {
+      $query->add_field('lineage', 'term_lineage', 'term_lineage_lineage');
+    }
+    if (!in_array('term_lineage.lineage ASC', $query->orderby)) {
+      $query->add_orderby('term_lineage', 'lineage', 'ASC');
+    }
+  }
+}
+
+// --------------------------------------------------------------------------
+// Implementation of hook_views_arguments()
+// may be needed by other plugins
+
+function views_bonus_views_arguments() {
+  
+  $arguments = array();
+  if (module_exist('lineage') && module_exist('taxonomy')) {
+    $arguments = array(
+    'lineage_branch' => array(
+      'name' => t('Lineage: Term Branch'),
+      'handler' => 'views_bonus_lineage_tree_branch_arg',
+      'help' => t('The argument will limit a view to terms that descend from a selected term name. Use it as a top-level selector for a branch and follow it with a taxonomy term name argument to view the selected branch of the taxonomy tree.'),
+    ),
+    );
+  }
+  return $arguments;
+}
+
+// --------------------------------------------------------------------------
+// Implementation of hook_views_default_views()
+// may be needed by other plugins
+
+function views_bonus_views_default_views() {
+    
+  if (module_exist('taxonomy')) {
+
+    // this view takes advantage of the summary_combo plugin
+
+    $view = new stdClass();
+    $view->name = 'taxonomy_directory';
+    $view->description = t('First letter of term on top and related view on bottom of each page.');
+    $view->access = array ();
+    $view->view_args_php = '';
+    $view->page = TRUE;
+    $view->page_title = t('directory');
+    $view->page_header = '';
+    $view->page_header_format = '3';
+    $view->page_footer = '';
+    $view->page_footer_format = '1';
+    $view->page_empty = '';
+    $view->page_empty_format = '1';
+    $view->page_type = 'summary_combo';
+    $view->url = 'directory';
+    $view->use_pager = TRUE;
+    $view->nodes_per_page = '50';
+    $view->menu = TRUE;
+    $view->menu_title = t('directory');
+    $view->menu_tab = FALSE;
+    $view->menu_tab_default = FALSE;
+    $view->menu_weight = '';
+    $view->sort = array (
+    array (
+      'tablename' => 'term_data',
+      'field' => 'weight',
+      'sortorder' => 'ASC',
+      'options' => '',
+    ),
+    array (
+      'tablename' => 'node',
+      'field' => 'sticky',
+      'sortorder' => 'DESC',
+      'options' => '',
+    ),
+    array (
+      'tablename' => 'node',
+      'field' => 'created',
+      'sortorder' => 'DESC',
+      'options' => '',
+    ),
+    );
+    $view->argument = array (
+    array (
+      'type' => 'taxletter',
+      'argdefault' => '6',
+      'title' => '%1',
+      'options' => '1',
+      'wildcard' => '',
+      'wildcard_substitution' => '',
+    ),
+    array (
+      'type' => 'taxletter',
+      'argdefault' => '6',
+      'title' => '%2',
+      'options' => '',
+      'wildcard' => '',
+      'wildcard_substitution' => '',
+    ),
+    );
+    $view->field = array (
+    array (
+      'tablename' => 'node',
+      'field' => 'title',
+      'label' => '',
+      'handler' => 'views_handler_field_nodelink',
+      'sortable' => '1',
+    ),
+    );
+    $view->filter = array (
+    array (
+      'tablename' => 'node',
+      'field' => 'status',
+      'operator' => '=',
+      'options' => '',
+      'value' => '1',
+    ),
+    );
+    $view->exposed_filter = array ();
+    $view->requires = array(term_data, node);
+    $views[$view->name] = $view;
+  }
+
+  if (module_exist('lineage') && module_exist('taxonomy')) {
+
+    // this default view provides an example of the taxonomy tree plugin summary view
+    $view = new stdClass();
+    $view->name = 'taxonomy_tree';
+    $view->description = t('Nested, hierarchical taxonomy view.');
+    $view->access = array ();
+    $view->view_args_php = '';
+    $view->page = TRUE;
+    $view->page_title = t('tree');
+    $view->page_header = '';
+    $view->page_header_format = '1';
+    $view->page_footer = '';
+    $view->page_footer_format = '1';
+    $view->page_empty = '';
+    $view->page_empty_format = '1';
+    $view->page_type = 'lineage_tree';
+    $view->url = 'tree';
+    $view->use_pager = TRUE;
+    $view->nodes_per_page = '999';
+    $view->menu = TRUE;
+    $view->menu_title = t('tree');
+    $view->menu_tab = FALSE;
+    $view->menu_tab_default = FALSE;
+    $view->menu_weight = '';
+    $view->sort = array (
+    array (
+      'tablename' => 'term_lineage',
+      'field' => 'lineage',
+      'sortorder' => 'ASC',
+      'options' => '',
+    ),
+    );
+    $view->argument = array (
+    array (
+      'type' => 'lineage_branch',
+      'argdefault' => '6',
+      'title' => '%1',
+      'options' => '',
+      'wildcard' => '',
+      'wildcard_substitution' => '',
+    ),
+    array (
+      'type' => 'taxletter',
+      'argdefault' => '6',
+      'title' => '%2',
+      'options' => '',
+      'wildcard' => '',
+      'wildcard_substitution' => '',
+    ),
+    );
+    $view->field = array ();
+    $view->filter = array (
+    array (
+      'tablename' => 'node',
+      'field' => 'status',
+      'operator' => '=',
+      'options' => '',
+      'value' => '1',
+    ),
+    );
+    $view->exposed_filter = array ();
+    $view->requires = array(term_lineage, node);
+    $views[$view->name] = $view;
+  }
+
+  return $views;
+}
