Now all modules are in core modules folder
This commit is contained in:
parent
5ba1cdfa0b
commit
05b6a91b0c
1907 changed files with 0 additions and 0 deletions
|
@ -0,0 +1,321 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* An extended subclass for field handling that adds multiple field grouping.
|
||||
*
|
||||
* Fields that want multiple value grouping options in addition to basic
|
||||
* field and formatter handling can extend this class.
|
||||
*/
|
||||
class content_handler_field_multiple extends content_handler_field {
|
||||
var $defer_query;
|
||||
|
||||
function init(&$view, $options) {
|
||||
$field = $this->content_field;
|
||||
parent::init($view, $options);
|
||||
|
||||
$this->defer_query = !empty($options['multiple']['group']) && $field['multiple'];
|
||||
|
||||
if ($this->defer_query) {
|
||||
// Grouped field: ditch the existing additional_fields (field columns + delta).
|
||||
// In the main query we'll only need:
|
||||
// - vid, which will be used to retrieve the actual values in pre_render,
|
||||
// - node type and nid, which wil be used in the pseudo-node used when
|
||||
// rendering.
|
||||
$this->additional_fields = array(
|
||||
'type' => array('table' => 'node', 'field' => 'type'),
|
||||
'nid' => array('table' => 'node', 'field' => 'nid'),
|
||||
);
|
||||
if ($view->base_table == 'node_revisions') {
|
||||
$this->additional_fields['vid'] = array('table' => 'node_revisions', 'field' => 'vid');
|
||||
}
|
||||
else {
|
||||
$this->additional_fields['vid'] = array('table' => 'node', 'field' => 'vid');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function option_definition() {
|
||||
$options = parent::option_definition();
|
||||
|
||||
$options['multiple'] = array(
|
||||
'contains' => array(
|
||||
'group' => array('default' => TRUE),
|
||||
'multiple_number' => array('default' => ''),
|
||||
'multiple_from' => array('default' => ''),
|
||||
'multiple_reversed' => array('default' => FALSE),
|
||||
),
|
||||
);
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide 'group multiple values' option.
|
||||
*/
|
||||
function options_form(&$form, &$form_state) {
|
||||
parent::options_form($form, $form_state);
|
||||
|
||||
$field = $this->content_field;
|
||||
$options = $this->options;
|
||||
|
||||
$form['multiple'] = array(
|
||||
'#access' => $field['multiple'],
|
||||
'#weight' => 1,
|
||||
);
|
||||
$form['multiple']['group'] = array(
|
||||
'#title' => t('Group multiple values'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $options['multiple']['group'],
|
||||
'#description' => t('If unchecked, each item in the field will create a new row, which may appear to cause duplicates. This setting is not compatible with click-sorting in table displays.'),
|
||||
);
|
||||
// Make the string translatable by keeping it as a whole rather than
|
||||
// translating prefix and suffix separately.
|
||||
list($prefix, $suffix) = explode('@count', t('Show @count value(s)'));
|
||||
$form['multiple']['multiple_number'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 5,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $options['multiple']['multiple_number'],
|
||||
'#prefix' => '<div class="container-inline">',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
);
|
||||
list($prefix, $suffix) = explode('@count', t('starting from @count'));
|
||||
$form['multiple']['multiple_from'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 5,
|
||||
'#field_prefix' => $prefix,
|
||||
'#field_suffix' => $suffix,
|
||||
'#default_value' => $options['multiple']['multiple_from'],
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
'#description' => t('(first item is 0)'),
|
||||
);
|
||||
$form['multiple']['multiple_reversed'] = array(
|
||||
'#title' => t('Reversed'),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => $options['multiple']['multiple_reversed'],
|
||||
'#suffix' => '</div>',
|
||||
'#process' => array('views_process_dependency'),
|
||||
'#dependency' => array('edit-options-multiple-group' => array(TRUE)),
|
||||
'#description' => t('(start from last values)'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this field is click sortable.
|
||||
*/
|
||||
function click_sortable() {
|
||||
$field = $this->content_field;
|
||||
$options = $this->options;
|
||||
|
||||
// Grouped fields are not click-sortable.
|
||||
return !empty($this->definition['click sortable']) && !$this->defer_query;
|
||||
}
|
||||
|
||||
function query() {
|
||||
// If this is not a grouped field, use the generic query().
|
||||
if (!$this->defer_query) {
|
||||
return parent::query();
|
||||
}
|
||||
|
||||
// Grouped field: do NOT call ensure_my_table, only add additional fields.
|
||||
$this->add_additional_fields();
|
||||
$this->field_alias = $this->aliases['vid'];
|
||||
}
|
||||
|
||||
function pre_render($values) {
|
||||
// If there are no values to render (displaying a summary, or query returned no results),
|
||||
// or if this is not a grouped field, do nothing specific.
|
||||
if (isset($this->view->build_info['summary']) || empty($values) || !$this->defer_query) {
|
||||
return parent::pre_render($values);
|
||||
}
|
||||
|
||||
$field = $this->content_field;
|
||||
$db_info = content_database_info($field);
|
||||
$options = $this->options;
|
||||
|
||||
// Build the list of vids to retrieve.
|
||||
// TODO: try fetching from cache_content first ??
|
||||
$vids = array();
|
||||
$this->field_values = array();
|
||||
foreach ($values as $result) {
|
||||
if (isset($result->{$this->field_alias})) {
|
||||
$vids[] = $result->{$this->field_alias};
|
||||
}
|
||||
}
|
||||
|
||||
// It may happend that the multiple values field is related to a non
|
||||
// required relation for which no node data related to the field being
|
||||
// processed here is available.
|
||||
if (empty($vids)) {
|
||||
return parent::pre_render($values);
|
||||
}
|
||||
|
||||
// List columns to retrieve.
|
||||
$alias = content_views_tablename($field);
|
||||
// Prefix aliases with '_' to avoid clashing with field columns names.
|
||||
$query_columns = array(
|
||||
'vid AS _vid',
|
||||
"delta as _delta",
|
||||
// nid is needed to generate the links for 'link to node' option.
|
||||
'nid AS _nid',
|
||||
);
|
||||
// The actual field columns.
|
||||
foreach ($db_info['columns'] as $column => $attributes) {
|
||||
$query_columns[] = "$attributes[column] AS $column";
|
||||
}
|
||||
$query = 'SELECT '. implode(', ', $query_columns) .
|
||||
' FROM {'. $db_info['table'] ."}".
|
||||
" WHERE vid IN (". implode(',', $vids) .')'.
|
||||
" ORDER BY _nid ASC, _delta ". ($options['multiple']['multiple_reversed'] ? 'DESC' : 'ASC');
|
||||
$result = db_query($query);
|
||||
|
||||
while ($item = db_fetch_array($result)) {
|
||||
// Clean up the $item from vid and delta. We keep nid for now.
|
||||
$vid = $item['_vid'];
|
||||
unset($item['_vid']);
|
||||
$delta = !empty($item['_delta']) ? $item['_delta'] : 0;
|
||||
$item['#delta'] = $item['_delta'];
|
||||
unset($item['_delta']);
|
||||
$this->field_values[$vid][$delta] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return DIV or SPAN based upon the field's element type.
|
||||
*
|
||||
* Fields rendered with the 'group multiple' option use <div> markers,
|
||||
* and thus shouldn't be wrapped in a <span>.
|
||||
*/
|
||||
function element_type($none_supported = FALSE, $default_empty = FALSE) {
|
||||
// If this is not a grouped field, use the parent method.
|
||||
if (!$this->defer_query) {
|
||||
return parent::element_type($none_supported, $default_empty);
|
||||
}
|
||||
|
||||
// The 'element_type' property denotes Views 3.x ('semantic views'
|
||||
// functionnality). If the property is set, and not set to '' ("default"),
|
||||
// let the generic method handle the output.
|
||||
if (isset($this->options['element_type']) && $this->options['element_type'] !== '') {
|
||||
return parent::element_type($none_supported, $default_empty);
|
||||
}
|
||||
|
||||
if ($default_empty) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (isset($this->definition['element type'])) {
|
||||
return $this->definition['element type'];
|
||||
}
|
||||
|
||||
return 'div';
|
||||
}
|
||||
|
||||
function render($values) {
|
||||
// If this is not a grouped field, use content_handler_field::render().
|
||||
if (!$this->defer_query) {
|
||||
return parent::render($values);
|
||||
}
|
||||
|
||||
// We're down to a single node here, so we can retrieve the actual field
|
||||
// definition for the node type being considered.
|
||||
$field = content_fields($this->content_field['field_name'], $values->{$this->aliases['type']});
|
||||
|
||||
// If the field does not appear in the node type, then we have no value
|
||||
// to display, and can just return.
|
||||
if (empty($field)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$options = $this->options;
|
||||
|
||||
$vid = $values->{$this->field_alias};
|
||||
if (isset($this->field_values[$vid])) {
|
||||
// Gather items, respecting the 'Display n values starting from m' settings.
|
||||
$count_skipped = 0;
|
||||
$items = array();
|
||||
foreach ($this->field_values[$vid] as $item) {
|
||||
if (empty($options['multiple']['multiple_from']) || ($count_skipped >= $options['multiple']['multiple_from'])) {
|
||||
if (empty($options['multiple']['multiple_number']) || (count($items) < $options['multiple']['multiple_number'])) {
|
||||
// Grab the nid - needed for render_link().
|
||||
$nid = $item['_nid'];
|
||||
unset($item['_nid']);
|
||||
$items[] = $item;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$count_skipped++;
|
||||
}
|
||||
|
||||
// Build a pseudo-node from the retrieved values.
|
||||
$node = drupal_clone($values);
|
||||
// content_format and formatters will need a 'type'.
|
||||
$node->type = $values->{$this->aliases['type']};
|
||||
$node->nid = $values->{$this->aliases['nid']};
|
||||
$node->vid = $values->{$this->aliases['vid']};
|
||||
|
||||
// Some formatters need to behave differently depending on the build_mode
|
||||
// (for instance: preview), so we provide one.
|
||||
$node->build_mode = NODE_BUILD_NORMAL;
|
||||
|
||||
// Render items.
|
||||
$formatter_name = $options['format'];
|
||||
if ($items && ($formatter = _content_get_formatter($formatter_name, $field['type']))) {
|
||||
$rendered = array();
|
||||
if (content_handle('formatter', 'multiple values', $formatter) == CONTENT_HANDLE_CORE) {
|
||||
// Single-value formatter.
|
||||
foreach ($items as $item) {
|
||||
$output = content_format($field, $item, $formatter_name, $node);
|
||||
if (!empty($output)) {
|
||||
$rendered[] = $this->render_link($output, (object) array('nid' => $nid));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Multiple values formatter.
|
||||
$output = content_format($field, $items, $formatter_name, $values);
|
||||
if (!empty($output)) {
|
||||
$rendered[] = $this->render_link($output, (object) array('nid' => $nid));
|
||||
}
|
||||
}
|
||||
|
||||
if (count($rendered) > 1) {
|
||||
// TODO: could we use generic field display ?
|
||||
return theme('content_view_multiple_field', $rendered, $field, $values);
|
||||
}
|
||||
elseif ($rendered) {
|
||||
return $rendered[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
function render_link($data, $values) {
|
||||
if (!$this->defer_query) {
|
||||
return parent::render_link($data, $values);
|
||||
}
|
||||
|
||||
if (!empty($this->options['link_to_node']) && $data !== NULL && $data !== '') {
|
||||
if (method_exists('render_as_link', 'views_handler_field')) {
|
||||
// Views 2.3+
|
||||
$this->options['alter']['make_link'] = TRUE;
|
||||
$this->options['alter']['path'] = "node/" . $values->{$this->aliases['nid']};
|
||||
}
|
||||
else {
|
||||
// Views up to 2.2
|
||||
return l($data, "node/" . $values->nid, array('html' => TRUE));
|
||||
}
|
||||
}
|
||||
else {
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue