diff --git handlers/views_handler_field.inc handlers/views_handler_field.inc index 86b4c1d..efe0616 100644 --- handlers/views_handler_field.inc +++ handlers/views_handler_field.inc @@ -17,6 +17,7 @@ * 'field' => fieldname); as many fields as are necessary * may be in this array. * - click sortable: If TRUE, this field may be click sorted. + * - no semantic: If TRUE, it disables the semantic output. */ class views_handler_field extends views_handler { var $field_alias = 'unknown'; @@ -142,9 +143,22 @@ class views_handler_field extends views_handler { } /** - * Return DIV or SPAN based upon the field's element type. + * Return an HTML element based upon the field's element type. */ - function element_type() { + function element_type($none_supported = FALSE, $default_empty = FALSE) { + if ($none_supported) { + if ($this->options['element_type'] === '0') { + return ''; + } + } + if ($this->options['element_type']) { + return check_plain($this->options['element_type']); + } + + if ($default_empty) { + return ''; + } + if (isset($this->definition['element type'])) { return $this->definition['element type']; } @@ -152,6 +166,108 @@ class views_handler_field extends views_handler { return 'span'; } + /** + * Return an HTML element based upon the field's element type. + */ + function element_label_type($none_supported = FALSE, $default_empty = FALSE) { + if ($none_supported) { + if ($this->options['element_label_type'] === '0') { + return ''; + } + } + if ($this->options['element_label_type']) { + return check_plain($this->options['element_label_type']); + } + + if ($default_empty) { + return ''; + } + + return 'span'; + } + + /** + * Return an HTML element based upon the field's element type. + */ + function element_wrapper_type($none_supported = FALSE, $default_empty = FALSE) { + if ($none_supported) { + if ($this->options['element_wrapper_type'] === '0') { + return 0; + } + } + if ($this->options['element_wrapper_type']) { + return check_plain($this->options['element_wrapper_type']); + } + + if ($default_empty) { + return ''; + } + + return 'div'; + } + + function get_elements() { + return array( + '' => t('- Use default -'), + '0' => t('- None -'), + 'div' => t('DIV'), + 'span' => t('SPAN'), + 'h1' => t('H1'), + 'h2' => t('H2'), + 'h3' => t('H3'), + 'h4' => t('H4'), + 'h5' => t('H5'), + 'h6' => t('H6'), + 'p' => t('P'), + 'strong' => t('STRONG'), + 'em' => t('EM'), + ); + } + + /** + * Return the class of the field. + */ + function element_classes() { + $classes = $this->tokenize_value($this->options['element_class']); + return views_css_safe($classes); + } + + function tokenize_value($value) { + if (strpos($value, '[') !== FALSE) { + $fake_item = array( + 'alter_text' => TRUE, + 'text' => $value, + ); + + // Get tokens from the last field. + $last_field = end($this->view->field); + if (isset($last_field->last_tokens)) { + $tokens = $last_field->last_tokens; + } + else { + $tokens = $last_field->get_render_tokens($fake_item); + } + + $value = strip_tags($this->render_altered($fake_item, $tokens)); + } + + return $value; + } + + /** + * Return the class of the field's label. + */ + function element_label_classes() { + return views_css_safe($this->options['element_label_class']); + } + + /** + * Return the class of the field's wrapper. + */ + function element_wrapper_classes() { + return views_css_safe($this->options['element_wrapper_class']); + } + function option_definition() { $options = parent::option_definition(); @@ -177,6 +293,18 @@ class views_handler_field extends views_handler { 'html' => array('default' => FALSE), ), ); + $options['element_type'] = array('default' => ''); + $options['element_class'] = array('default' => ''); + + $options['element_label_type'] = array('default' => ''); + $options['element_label_class'] = array('default' => ''); + $options['element_label_colon'] = array('default' => TRUE); + + $options['element_wrapper_type'] = array('default' => ''); + $options['element_wrapper_class'] = array('default' => ''); + + $options['element_default_classes'] = array('default' => TRUE); + $options['empty'] = array('default' => '', 'translatable' => TRUE); $options['hide_empty'] = array('default' => FALSE); $options['empty_zero'] = array('default' => FALSE); @@ -191,17 +319,91 @@ class views_handler_field extends views_handler { function options_form(&$form, &$form_state) { parent::options_form($form, $form_state); + // Use prefix and suffix to fake a fieldset because we use #tree. + $form['style_prefix'] = array( + '#value' => '
', + ); + + $form['alter'] = array( + '#title' => t('Rewriting'), + '#type' => 'fieldset', ); if ($this->allow_advanced_render()) { @@ -411,6 +613,11 @@ If you would like to have the characters %5B and %5D please use the html entity ); } + // Use prefix and suffix to fake a fieldset because we use #tree. + $form['empty_prefix'] = array( + '#value' => '', + ); + } /** @@ -703,6 +915,7 @@ If you would like to have the characters %5B and %5D please use the html entity } } + $this->last_tokens = $tokens; return $tokens; } diff --git includes/plugins.inc includes/plugins.inc index 134c1a0..2aa2a9a 100644 --- includes/plugins.inc +++ includes/plugins.inc @@ -96,6 +96,7 @@ function views_views_plugins() { 'handler' => 'views_plugin_style_default', 'theme' => 'views_view_unformatted', 'uses row plugin' => TRUE, + 'uses row class' => TRUE, 'uses grouping' => TRUE, 'uses options' => TRUE, 'type' => 'normal', @@ -107,6 +108,7 @@ function views_views_plugins() { 'handler' => 'views_plugin_style_list', 'theme' => 'views_view_list', 'uses row plugin' => TRUE, + 'uses row class' => TRUE, 'uses options' => TRUE, 'type' => 'normal', 'help topic' => 'style-list', @@ -117,6 +119,7 @@ function views_views_plugins() { 'handler' => 'views_plugin_style_grid', 'theme' => 'views_view_grid', 'uses row plugin' => TRUE, + 'uses row class' => TRUE, 'uses options' => TRUE, 'type' => 'normal', 'help topic' => 'style-grid', @@ -127,6 +130,7 @@ function views_views_plugins() { 'handler' => 'views_plugin_style_table', 'theme' => 'views_view_table', 'uses row plugin' => FALSE, + 'uses row class' => TRUE, 'uses fields' => TRUE, 'uses options' => TRUE, 'type' => 'normal', diff --git plugins/views_plugin_row.inc plugins/views_plugin_row.inc index 40d5e5c..8319739 100644 --- plugins/views_plugin_row.inc +++ plugins/views_plugin_row.inc @@ -132,7 +132,7 @@ class views_plugin_row extends views_plugin { * of some form, but not always. */ function render($row) { - return theme($this->theme_functions(), $this->view, $this->options, $row, $this->field_alias); + return theme($this->theme_functions(), $this->view, $this->options, $row, isset($this->field_alias) ? $this->field_alias : ''); } } diff --git plugins/views_plugin_row_fields.inc plugins/views_plugin_row_fields.inc index f114125..c2cda2c 100644 --- plugins/views_plugin_row_fields.inc +++ plugins/views_plugin_row_fields.inc @@ -27,6 +27,7 @@ class views_plugin_row_fields extends views_plugin_row { * Provide a form for setting options. */ function options_form(&$form, &$form_state) { + parent::options_form($form, $form_state); $options = $this->display->handler->get_field_labels(); if (empty($this->options['inline'])) { diff --git plugins/views_plugin_style.inc plugins/views_plugin_style.inc index 79ac5c7..277d3b2 100644 --- plugins/views_plugin_style.inc +++ plugins/views_plugin_style.inc @@ -64,6 +64,13 @@ class views_plugin_style extends views_plugin { } /** + * Return TRUE if this style also uses a row plugin. + */ + function uses_row_class() { + return !empty($this->definition['uses row class']); + } + + /** * Return TRUE if this style also uses fields. */ function uses_fields() { @@ -76,9 +83,58 @@ class views_plugin_style extends views_plugin { return !empty($this->definition['uses fields']); } + /** + * Return TRUE if this style uses tokens. + * + * Used to ensure we don't fetch tokens when not needed for performance. + */ + function uses_tokens() { + if ($this->uses_row_class()) { + $class = $this->options['row_class']; + if (strpos($class, '[') !== FALSE) { + return TRUE; + } + } + } + + /** + * Return the token replaced row class for the specified row. + */ + function get_row_class($row_index) { + $class = $this->options['row_class']; + if ($this->uses_fields() && $this->view->field) { + $class = $this->tokenize_value($class, $row_index); + } + + return views_css_safe($class); + } + + /** + * Take a value and apply token replacement logic to it. + */ + function tokenize_value($value, $row_index) { + if (strpos($value, '[') !== FALSE) { + $fake_item = array( + 'alter_text' => TRUE, + 'text' => $value, + ); + + $tokens = $this->row_tokens[$row_index]; + // Grab a random field handler to perform the render. + $field = end($this->view->field); + $value = strip_tags($field->render_altered($fake_item, $tokens)); + } + + return $value; + } + function option_definition() { $options = parent::option_definition(); $options['grouping'] = array('default' => ''); + if ($this->uses_row_class()) { + $options['row_class'] = array('default' => ''); + } + return $options; } @@ -102,6 +158,19 @@ class views_plugin_style extends views_plugin { ); } } + + if ($this->uses_row_class()) { + $form['row_class'] = array( + '#title' => t('Row class'), + '#description' => t('The class to provide on each row.'), + '#type' => 'textfield', + '#default_value' => $this->options['row_class'], + ); + + if ($this->uses_fields()) { + $form['row_class']['#description'] .= ' ' . t('You may use field tokens from as per the "Replacement patterns" used in "Rewrite the output of this field" for all fields.'); + } + } } /** @@ -221,6 +290,10 @@ class views_plugin_style extends views_plugin { foreach ($keys as $id) { $this->rendered_fields[$count][$id] = $this->view->field[$id]->theme($row); } + + if ($this->uses_tokens()) { + $this->row_tokens[$count] = $this->view->field[$id]->get_render_tokens(array()); + } } unset($this->view->row_index); } diff --git plugins/views_plugin_style_list.inc plugins/views_plugin_style_list.inc index 7b25785..96b016e 100644 --- plugins/views_plugin_style_list.inc +++ plugins/views_plugin_style_list.inc @@ -18,6 +18,8 @@ class views_plugin_style_list extends views_plugin_style { $options = parent::option_definition(); $options['type'] = array('default' => 'ul'); + $options['class'] = array('default' => ''); + $options['wrapper_class'] = array('default' => 'item-list'); return $options; } @@ -33,6 +35,20 @@ class views_plugin_style_list extends views_plugin_style { '#options' => array('ul' => t('Unordered list'), 'ol' => t('Ordered list')), '#default_value' => $this->options['type'], ); + $form['wrapper_class'] = array( + '#title' => t('Wrapper class'), + '#description' => t('The class to provide on the wrapper, outside the list.'), + '#type' => 'textfield', + '#size' => '30', + '#default_value' => $this->options['wrapper_class'], + ); + $form['class'] = array( + '#title' => t('List class'), + '#description' => t('The class to provide on the list element itself.'), + '#type' => 'textfield', + '#size' => '30', + '#default_value' => $this->options['class'], + ); } } diff --git theme/theme.inc theme/theme.inc index 50246e9..fabd57b 100644 --- theme/theme.inc +++ theme/theme.inc @@ -156,6 +156,30 @@ function template_preprocess_views_view_fields(&$vars) { $empty = $field_output !== 0 && empty($field_output); if (empty($field->options['exclude']) && (!$empty || (empty($field->options['hide_empty']) && empty($vars['options']['hide_empty'])))) { $object = new stdClass(); + $object->handler = &$view->field[$id]; + + $object->element_type = $object->handler->element_type(TRUE); + if ($object->element_type) { + $class = ''; + if ($object->handler->options['element_default_classes']) { + $class = 'field-content'; + } + + if ($classes = $object->handler->element_classes()) { + if ($class) { + $class .= ' '; + } + $class .= $classes; + } + + $field_output = '<' . $object->element_type . ' class="' . $class . '">' . $field_output . '' . $object->element_type . '>'; + } + + // Protect ourself somewhat for backward compatibility. This will prevent + // old templates from producing invalid HTML when no element type is selected. + if (empty($object->element_type)) { + $object->element_type = 'span'; + } $object->content = $field_output; if (isset($view->field[$id]->field_alias) && isset($vars['row']->{$view->field[$id]->field_alias})) { @@ -164,19 +188,73 @@ function template_preprocess_views_view_fields(&$vars) { else { $object->raw = NULL; // make sure it exists to reduce NOTICE } - $object->inline = !empty($vars['options']['inline'][$id]); - $object->inline_html = $object->inline ? 'span' : 'div'; + if (!empty($vars['options']['separator']) && $inline && $object->inline && $object->content) { $object->separator = filter_xss_admin($vars['options']['separator']); } + $object->class = views_css_safe($id); + $object->inline = !empty($vars['options']['inline'][$id]); $inline = $object->inline; + $object->inline_html = $object->handler->element_wrapper_type(TRUE, TRUE); - $object->handler = &$view->field[$id]; - $object->element_type = $object->handler->element_type(); + if ($object->inline_html === '') { + $object->inline_html = $object->inline ? 'span' : 'div'; + } - $object->class = views_css_safe($id); + // Set up the wrapper HTML. + $object->wrapper_prefix = ''; + $object->wrapper_suffix = ''; + + if ($object->inline_html) { + $class = ''; + if ($object->handler->options['element_default_classes']) { + $class = "views-field views-field-" . $object->class; + } + + if ($classes = $object->handler->element_wrapper_classes()) { + if ($class) { + $class .= ' '; + } + $class .= ' ' . $classes; + } + + $object->wrapper_prefix = '<' . $object->inline_html; + if ($class) { + $object->wrapper_prefix .= ' class="' . $class . '"'; + } + $object->wrapper_prefix .= '>'; + $object->wrapper_suffix = '' . $object->inline_html . '>'; + } + + // Set up the label for the value and the HTML to make it easier + // on the template. $object->label = check_plain($view->field[$id]->label()); + $object->label_html = ''; + $object->element_label_type = $object->handler->element_label_type(TRUE); + if ($object->element_label_type && $object->label) { + $class = ''; + if ($object->handler->options['element_default_classes']) { + $class = 'views-label-' . $object->class; + } + + $element_label_class = $object->handler->element_label_classes(); + if ($element_label_class) { + if ($class) { + $class .= ' '; + } + + $class .= $element_label_class; + } + + $object->label_html = '<' . $object->element_label_type . ' class="' . $class . '">'; + $object->label_html .= $object->label; + if ($object->handler->options['element_label_colon']) { + $object->label_html .= ': '; + } + $object->label_html .= '' . $object->element_label_type . '>'; + } + $vars['fields'][$id] = $object; } } @@ -286,6 +364,7 @@ function template_preprocess_views_view_table(&$vars) { // Store rows so that they may be used by further preprocess functions. $result = $vars['result'] = $vars['rows']; $vars['rows'] = array(); + $vars['field_classes'] = array(); $options = $view->style_plugin->options; $handler = $view->style_plugin; @@ -306,6 +385,13 @@ function template_preprocess_views_view_table(&$vars) { $renders = $handler->render_fields($result); foreach ($columns as $field => $column) { + // Create a second variable so we can easily find what fields we have and what the + // CSS classes should be. + $vars['fields'][$field] = views_css_safe($field); + if ($active == $field) { + $vars['fields'][$field] .= ' active'; + } + // render the header labels if ($field == $column && empty($fields[$field]->options['exclude'])) { $label = check_plain(!empty($fields[$field]) ? $fields[$field]->label() : ''); @@ -330,13 +416,28 @@ function template_preprocess_views_view_table(&$vars) { ); $vars['header'][$field] = l($label, $_GET['q'], $link_options); } - } - // Create a second variable so we can easily find what fields we have and what the - // CSS classes should be. - $vars['fields'][$field] = views_css_safe($field); - if ($active == $field) { - $vars['fields'][$field] .= ' active'; + $vars['header_classes'][$field] = ''; + // Set up the header label class. + if ($fields[$field]->options['element_default_classes']) { + $vars['header_classes'][$field] .= "views-field views-field-" . $vars['fields'][$field]; + } + $class = $fields[$field]->element_label_classes(); + if ($class) { + if ($vars['header_classes'][$field]) { + $vars['header_classes'][$field] .= ' '; + } + $vars['header_classes'][$field] .= $class; + } + + // Add a header label wrapper if one was selected. + if ($vars['header'][$field]) { + $element_label_type = $fields[$field]->element_label_type(TRUE, TRUE); + if ($element_label_type) { + $vars['header'][$field] = '<' . $element_label_type . '>' . $vars['header'][$field] . '' . $element_label_type . '>'; + } + } + } // Add a CSS align class to each field if one was set @@ -346,8 +447,25 @@ function template_preprocess_views_view_table(&$vars) { // Render each field into its appropriate column. foreach ($result as $num => $row) { + // Add field classes + $vars['field_classes'][$field][$num] = ''; + if ($fields[$field]->options['element_default_classes']) { + $vars['field_classes'][$field][$num] = "views-field views-field-" . $vars['fields'][$field]; + } + if ($classes = $fields[$field]->element_classes()) { + if ($vars['field_classes'][$field][$num]) { + $vars['field_classes'][$field][$num] .= ' '; + } + + $vars['field_classes'][$field][$num] .= $classes; + } + if (!empty($fields[$field]) && empty($fields[$field]->options['exclude'])) { $field_output = $renders[$num][$field]; + $element_type = $fields[$field]->element_type(TRUE, TRUE); + if ($element_type) { + $field_output = '<' . $element_type . '>' . $field_output . '' . $element_type . '>'; + } // Don't bother with separators and stuff if the field does not show up. if (empty($field_output) && !empty($vars['rows'][$num][$column])) { @@ -372,6 +490,9 @@ function template_preprocess_views_view_table(&$vars) { $count = 0; foreach ($vars['rows'] as $num => $row) { $vars['row_classes'][$num][] = ($count++ % 2 == 0) ? 'odd' : 'even'; + if ($row_class = $handler->get_row_class($num)) { + $vars['row_classes'][$num][] = $row_class; + } } $vars['row_classes'][0][] = 'views-row-first'; @@ -447,6 +568,27 @@ function template_preprocess_views_view_grid(&$vars) { } } } + + // Apply the row classes + foreach ($vars['rows'] as $row_number => $row) { + $row_classes = array(); + $row_classes[] = 'row-' . ($row_number + 1); + if ($row_number == 0) { + $row_classes[] = 'row-first'; + } + if (count($rows) == ($row_number + 1)) { + $row_classes[] = 'row-last'; + } + $vars['row_classes'][$row_number] = implode(' ', $row_classes); + foreach ($rows[$row_number] as $column_number => $item) { + $column_classes = array(); + $column_classes[] = 'col-'. ($column_number + 1); + if ($column_class = $view->style_plugin->get_row_class($column_number)) { + $column_classes[] = $column_class; + } + $vars['column_classes'][$row_number][$column_number] = implode(' ', $column_classes); + } + } $vars['rows'] = $rows; } @@ -470,6 +612,11 @@ function template_preprocess_views_view_unformatted(&$vars) { if ($id == count($rows) -1) { $row_classes[] = 'views-row-last'; } + + if ($row_class = $view->style_plugin->get_row_class($id)) { + $row_classes[] = $row_class; + } + // Flatten the classes to a string for each row for the template file. $vars['classes'][$id] = implode(' ', $row_classes); } @@ -479,6 +626,22 @@ function template_preprocess_views_view_unformatted(&$vars) { * Display the view as an HTML list element */ function template_preprocess_views_view_list(&$vars) { + $handler = $vars['view']->style_plugin; + + $vars['class'] = views_css_safe($handler->options['class']); + $vars['wrapper_class'] = views_css_safe($handler->options['wrapper_class']); + $vars['wrapper_prefix'] = ''; + $vars['wrapper_suffix'] = ''; + $vars['list_type_prefix'] = '<' . $handler->options['type'] . '>'; + $vars['list_type_suffix'] = '' . $handler->options['type'] . '>'; + if ($vars['wrapper_class']) { + $vars['wrapper_prefix'] = '+ | diff --git theme/views-view-list.tpl.php theme/views-view-list.tpl.php index 067c511..b7db537 100644 --- theme/views-view-list.tpl.php +++ theme/views-view-list.tpl.php @@ -9,13 +9,13 @@ * @ingroup views_templates */ ?> - | ||||
+ | @@ -32,7 +35,7 @@ $row): ?> | ||||
---|---|---|---|---|---|
+ |