#458194 by voxpelli: Add first and last row classes to table style.
[project/views.git] / theme / theme.inc
index abb5ba0..8ff3292 100644 (file)
@@ -24,6 +24,7 @@ function _views_theme_functions($hook, $view, $display = NULL) {
   if ($display) {
     $themes[] = $hook . '__' . $view->name . '__' . $display->id;
     $themes[] = $hook . '__' . $display->id;
+    $themes[] = $hook . '__' . preg_replace('/[^a-z0-9]/', '-', strtolower($view->tag));
     if ($display->id != $display->display_plugin) {
       $themes[] = $hook . '__' . $view->name . '__' . $display->display_plugin;
       $themes[] = $hook . '__' . $display->display_plugin;
@@ -31,7 +32,6 @@ function _views_theme_functions($hook, $view, $display = NULL) {
   }
   $themes[] = $hook . '__' . $view->name;
   $themes[] = $hook;
-
   return $themes;
 }
 
@@ -39,6 +39,8 @@ function _views_theme_functions($hook, $view, $display = NULL) {
  * Preprocess the primary theme implementation for a view.
  */
 function template_preprocess_views_view(&$vars) {
+  global $base_path;
+
   $view = $vars['view'];
 
   $vars['rows']       = !empty($view->result) || !empty($view->style_plugin->definition['even empty']) ? $view->style_plugin->render($view->result) : '';
@@ -105,14 +107,14 @@ function template_preprocess_views_view(&$vars) {
       ),
     );
 
-    drupal_alter('views_admin_links', $vars['admin_links_raw']);
+    drupal_alter('views_admin_links', $vars['admin_links_raw'], $view);
     $vars['admin_links'] = theme('links', $vars['admin_links_raw']);
-    views_add_css('views');
   }
   else {
     $vars['admin_links'] = '';
     $vars['admin_links_raw'] = array();
   }
+  views_add_css('views');
 
   // Our JavaScript needs to have some means to find the HTML belonging to this
   // view.
@@ -137,6 +139,9 @@ function template_preprocess_views_view(&$vars) {
             'view_display_id' => $view->current_display,
             'view_args' => implode('/', $view->args),
             'view_path' => $_GET['q'],
+            // Pass through URL to ensure we get e.g. language prefixes.
+//            'view_base_path' => isset($view->display['page']) ? substr(url($view->display['page']->display_options['path']), strlen($base_path)) : '',
+            'view_base_path' => $view->get_path(),
             'view_dom_id' => $vars['dom_id'],
             // To fit multiple views on a page, the programmer may have
             // overridden the display's pager_element.
@@ -161,10 +166,13 @@ function template_preprocess_views_view_fields(&$vars) {
   $inline = FALSE;
   $vars['fields'] = array(); // ensure it's at least an empty array.
   foreach ($view->field as $id => $field) {
-    if (empty($field->options['exclude'])) {
+    // render this even if set to exclude so it can be used elsewhere.
+    $field_output = $view->field[$id]->theme($vars['row']);
+    $empty = $field_output !== 0 && empty($field_output);
+    if (empty($field->options['exclude']) && (!$empty || empty($field->options['hide_empty']))) {
       $object = new stdClass();
 
-      $object->content = $view->field[$id]->theme($vars['row']);
+      $object->content = $field_output;
       if (isset($view->field[$id]->field_alias) && isset($vars['row']->{$view->field[$id]->field_alias})) {
         $object->raw = $vars['row']->{$view->field[$id]->field_alias};
       }
@@ -179,7 +187,9 @@ function template_preprocess_views_view_fields(&$vars) {
 
       $inline = $object->inline;
 
-      $object->handler = $view->field[$id];
+      $object->handler = &$view->field[$id];
+      $object->element_type = $object->handler->element_type();
+
       $object->class = views_css_safe($id);
       $object->label = check_plain($view->field[$id]->label());
       $vars['fields'][$id] = $object;
@@ -196,7 +206,7 @@ function template_preprocess_views_view_fields(&$vars) {
  * this: @code { $row->{$field->field_alias} @endcode
  */
 function theme_views_view_field($view, $field, $row) {
-  return $field->render($row);
+  return $field->advanced_render($row);
 }
 
 /**
@@ -204,10 +214,10 @@ function theme_views_view_field($view, $field, $row) {
  *
  * This preprocess function isn't normally run, as a function is used by
  * default, for performance. However, by creating a template, this
- * preprocess should get pickedup.
+ * preprocess should get picked up.
  */
 function template_preprocess_views_view_field(&$vars) {
-  $vars['output'] = $vars['field']->render($vars['row']);
+  $vars['output'] = $vars['field']->advanced_render($vars['row']);
 }
 
 /**
@@ -271,7 +281,8 @@ function template_preprocess_views_view_table(&$vars) {
   // 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'];
+  // Store rows so that they may be used by further preprocess functions.
+  $result   = $vars['result'] = $vars['rows'];
   $vars['rows'] = array();
 
   $options  = $view->style_plugin->options;
@@ -288,11 +299,24 @@ function template_preprocess_views_view_table(&$vars) {
     $query = '&' . $query;
   }
 
+  // Fields must be rendered in order as of Views 2.3, so we will pre-render
+  // everything.
+  $renders = array();
+  $view->row_index = 0;
+  $keys = array_keys($view->field);
+  foreach ($result as $count => $row) {
+    foreach ($keys as $id) {
+      $renders[$count][$id] = $view->field[$id]->theme($row);
+    }
+    $view->row_index = $count;
+  }
+  unset($view->row_index);
+
   foreach ($columns as $field => $column) {
     // render the header labels
     if ($field == $column && empty($fields[$field]->options['exclude'])) {
       $label = check_plain(!empty($fields[$field]) ? $fields[$field]->label() : '');
-      if (empty($options['info'][$field]['sortable'])) {
+      if (empty($options['info'][$field]['sortable']) || !$fields[$field]->click_sortable()) {
         $vars['header'][$field] = $label;
       }
       else {
@@ -303,14 +327,16 @@ function template_preprocess_views_view_table(&$vars) {
           $initial = 'desc';
         }
 
-        $image = theme('tablesort_indicator', $initial);
         $title = t('sort by @s', array('@s' => $label));
+        if ($active == $field) {
+          $label .= theme('tablesort_indicator', $initial);
+        }
         $link_options = array(
           'html' => true,
           'attributes' => array('title' => $title),
           'query' => 'order=' . urlencode($field) . '&sort=' . $initial . $query,
         );
-        $vars['header'][$field] = l($label . $image, $_GET['q'], $link_options);
+        $vars['header'][$field] = l($label, $_GET['q'], $link_options);
       }
     }
 
@@ -324,28 +350,36 @@ function template_preprocess_views_view_table(&$vars) {
     // Render each field into its appropriate column.
     foreach ($result as $num => $row) {
       if (!empty($fields[$field]) && empty($fields[$field]->options['exclude'])) {
-        $field_output = $fields[$field]->theme($row);
+        $field_output = $renders[$num][$field];
+
+        if (!isset($vars['rows'][$num][$column])) {
+          $vars['rows'][$num][$column] = '';
+        }
 
         // Don't bother with separators and stuff if the field does not show up.
-        if (!isset($field_output) && isset($vars['rows'][$num][$column])) {
+        if ($field_output === '') {
           continue;
         }
 
         // Place the field into the column, along with an optional separator.
-        if (isset($vars['rows'][$num][$column])) {
+        if ($vars['rows'][$num][$column] !== '') {
           if (!empty($options['info'][$column]['separator'])) {
             $vars['rows'][$num][$column] .= filter_xss_admin($options['info'][$column]['separator']);
           }
         }
-        else {
-          $vars['rows'][$num][$column] = '';
-        }
 
         $vars['rows'][$num][$column] .= $field_output;
       }
     }
   }
 
+  foreach ($vars['rows'] as $num => $row) {
+    $vars['row_classes'][$num][] = ($num % 2 == 0) ? 'odd' : 'even';
+  }
+
+  $vars['row_classes'][0][] = 'views-row-first';
+  $vars['row_classes'][count($vars['row_classes']) - 1][] = 'views-row-last';
+
   $vars['class'] = 'views-table';
   if (!empty($options['sticky'])) {
     drupal_add_js('misc/tableheader.js');
@@ -368,14 +402,21 @@ function template_preprocess_views_view_grid(&$vars) {
 
   if ($options['alignment'] == 'horizontal') {
     $row = array();
+    $row_count = 0;
     foreach ($vars['rows'] as $count => $item) {
       $row[] = $item;
+      $row_count++;
       if (($count + 1) % $columns == 0) {
         $rows[] = $row;
         $row = array();
+        $row_count = 0;
       }
     }
     if ($row) {
+      // Fill up the last line.
+      for ($i = 0; $i < ($columns - $row_count); $i++) {
+        $row[] = '';
+      }
       $rows[] = $row;
     }
   }
@@ -399,11 +440,44 @@ function template_preprocess_views_view_grid(&$vars) {
         $remainders--;
       }
     }
+    for ($i = 0; $i < count($rows[0]); $i++) {
+      // This should be string so that's okay :)
+      if (!isset($rows[count($rows) - 1][$i])) {
+        $rows[count($rows) - 1][$i] = '';
+      }
+    }
   }
   $vars['rows'] = $rows;
 }
 
 /**
+ * Display the simple view of rows one after another
+ */
+function template_preprocess_views_view_unformatted(&$vars) {
+  $view     = $vars['view'];
+  $rows     = $vars['rows'];
+
+  $vars['classes'] = array();
+  // Set up striping values.
+  foreach ($rows as $id => $row) {
+    $vars['classes'][$id] = 'views-row';
+    $vars['classes'][$id] .= ' views-row-' . ($id + 1);
+    $vars['classes'][$id] .= ' views-row-' . ($id % 2 ? 'even' : 'odd');
+    if ($id == 0) {
+      $vars['classes'][$id] .= ' views-row-first';
+    }
+  }
+  $vars['classes'][$id] .= ' views-row-last';
+}
+
+/**
+ * Display the view as an HTML list element
+ */
+function template_preprocess_views_view_list(&$vars) {
+  template_preprocess_views_view_unformatted($vars);
+}
+
+/**
  * Preprocess an RSS feed
  */
 function template_preprocess_views_view_rss(&$vars) {
@@ -422,6 +496,10 @@ function template_preprocess_views_view_rss(&$vars) {
   else {
     $description = $options['description'];
   }
+  // The RSS 2.0 "spec" doesn't indicate HTML can be used in the description.
+  // We strip all HTML tags, but need to prevent double encoding from properly
+  // escaped source data (such as &amp becoming &amp;amp;).
+  $vars['description'] = check_plain(decode_entities(strip_tags($description)));
 
   if ($view->display_handler->get_option('sitename_title')) {
     $title = variable_get('site_name', 'Drupal');
@@ -432,6 +510,7 @@ function template_preprocess_views_view_rss(&$vars) {
   else {
     $title = $view->get_title();
   }
+  $vars['title'] = check_plain($title);
 
   // Figure out which display which has a path we're using for this feed. If there isn't
   // one, use the global $base_url
@@ -455,13 +534,29 @@ function template_preprocess_views_view_rss(&$vars) {
     $vars['link'] = check_url(url($path, $url_options));
   }
 
+  $vars['langcode'] = check_plain($language->language);
   $vars['namespaces'] = drupal_attributes($style->namespaces);
-  $vars['channel'] = format_rss_channel($title, $vars['link'], $description, $items, $language->language);
+  $vars['items'] = $items;
+  $vars['channel_elements'] = format_xml_elements($style->channel_elements);
 
   drupal_set_header('Content-Type: application/rss+xml; charset=utf-8');
 }
 
 /**
+ * Default theme function for all RSS rows.
+ */
+function template_preprocess_views_view_row_rss(&$vars) {
+  $view     = &$vars['view'];
+  $options  = &$vars['options'];
+  $item     = &$vars['row'];
+
+  $vars['title'] = check_plain($item->title);
+  $vars['link'] = check_url($item->link);
+  $vars['description'] = check_plain($item->description);
+  $vars['item_elements'] = empty($item->elements) ? '' : format_xml_elements($item->elements);
+}
+
+/**
  * Default theme function for all filter forms.
  */
 function template_preprocess_views_exposed_form(&$vars) {
@@ -528,7 +623,14 @@ function theme_views_mini_pager($tags = array(), $limit = 10, $element = 0, $par
 
 
   $li_previous = theme('pager_previous', (isset($tags[1]) ? $tags[1] : t('‹‹')), $limit, $element, 1, $parameters);
+  if (empty($li_previous)) {
+    $li_previous = "&nbsp;";
+  }
+
   $li_next = theme('pager_next', (isset($tags[3]) ? $tags[3] : t('››')), $limit, $element, 1, $parameters);
+  if (empty($li_next)) {
+    $li_next = "&nbsp;";
+  }
 
   if ($pager_total[$element] > 1) {
     $items[] = array(