viewfield.module in Viewfield 6.2
Same filename and directory in other branches
Core functions.
@todo Double-check potential performance issues mentioned in code comments.
File
viewfield.moduleView source
<?php
/**
* @file
* Core functions.
*
* @todo Double-check potential performance issues mentioned in code comments.
*/
/**
* Implementation of hook_field_info().
*/
function viewfield_field_info() {
return array(
'viewfield' => array(
// Should be "View", but that would translate into "view" (show) for many
// languages due to missing string translation contexts.
'label' => t('Views'),
'description' => t('Displays a selected view in a node.'),
'callbacks' => array(
'tables' => CONTENT_CALLBACK_NONE,
'arguments' => CONTENT_CALLBACK_NONE,
),
),
);
}
/**
* Implementation of hook_field_settings().
*/
function viewfield_field_settings($op, $field) {
switch ($op) {
case 'form':
$form['allowed_views'] = array(
'#type' => 'checkboxes',
'#title' => t('Allowed values'),
'#default_value' => is_array($field['allowed_views']) ? $field['allowed_views'] : array(),
'#options' => drupal_map_assoc(array_keys(views_get_all_views())),
'#description' => t('Only selected views will be available for content authors. Leave empty to allow all.'),
);
return $form;
case 'validate':
if ($field['force_default'] && $field['multiple']) {
form_set_error('multiple', t('Multiple views are not supported if force default is enabled.'));
}
break;
case 'save':
return array(
'allowed_views',
);
case 'database columns':
return array(
// Views requires at least 96 chars for the view name and display, plus
// we need 1 for our delimiter. Round up to a common value of 128.
'vname' => array(
'type' => 'varchar',
'not null' => FALSE,
'length' => 128,
),
'vargs' => array(
'type' => 'varchar',
'not null' => FALSE,
'length' => 255,
),
);
}
}
/**
* Implementation of hook_field().
*/
function viewfield_field($op, &$node, $field, &$items, $teaser, $page) {
switch ($op) {
case 'presave':
foreach ($items as $delta => $item) {
if (empty($item['vname'])) {
unset($items[$delta]);
}
}
break;
case 'sanitize':
// Replace field values with widget defaults when force_default is set.
if ($field['widget']['force_default']) {
$items = $field['widget']['default_value'];
}
break;
}
}
/**
* Implementation of hook_content_is_empty().
*/
function viewfield_content_is_empty($item, $field) {
return empty($item['vname']);
}
/**
* Implementation of hook_field_formatter_info().
*/
function viewfield_field_formatter_info() {
return array(
'default' => array(
'label' => t('Default'),
'field types' => array(
'viewfield',
),
),
);
}
/**
* Return a themed view avoiding viewfield recursion.
*/
function theme_viewfield_formatter_default($element) {
// $_viewfield_stack keeps a record of the current node to prevent infinite
// recursion during the view rendering process.
global $_viewfield_stack;
$node = $element['#node'];
if (!empty($element['#item']['vname']) && !isset($_viewfield_stack[$node->nid])) {
// Push id of current node unless it's a new node being previewed.
if ($node->nid) {
$_viewfield_stack[$node->nid] = $node->nid;
}
list($view_name, $display) = explode('|', $element['#item']['vname'], 2);
$view_args = _viewfield_get_view_args($element['#item']['vargs'], $element['#node']);
// Render the view like Views would do.
// @see views_embed_view()
$view = views_get_view($view_name);
if ($view && $view
->access($display)) {
// Override the view's path to the current path. Otherwise, exposed views
// filters would submit to the front page.
$view->override_path = $_GET['q'];
$output = $view
->preview($display, $view_args);
}
// This node is "safe" again.
if ($node->nid) {
unset($_viewfield_stack[$node->nid]);
}
// Only return an actual view result to not break empty value behavior.
if (isset($output)) {
return $output;
}
}
}
/**
* Implementation of hook_widget_info().
*/
function viewfield_widget_info() {
return array(
'viewfield_select' => array(
'label' => 'Select List',
'field types' => array(
'viewfield',
),
'multiple_values' => CONTENT_HANDLE_CORE,
'callbacks' => array(
'default value' => CONTENT_CALLBACK_DEFAULT,
),
),
);
}
/**
* Implementation of hook_widget_settings().
*/
function viewfield_widget_settings($op, $widget) {
switch ($op) {
case 'form':
$form['force_default'] = array(
'#type' => 'checkbox',
'#title' => t('Always use default value'),
'#default_value' => $widget['force_default'],
'#description' => t('Hides this field in forms and forces the default value defined below.'),
);
return $form;
case 'save':
return array(
'force_default',
);
}
}
/**
* Implementation of hook_widget().
*/
function viewfield_widget(&$form, &$form_state, $field, $items, $delta = 0) {
$element = array(
'#type' => $field['widget']['type'],
'#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
);
return $element;
}
/**
* Implementation of FAPI hook_elements().
*/
function viewfield_elements() {
return array(
'viewfield_select' => array(
'#input' => TRUE,
'#columns' => array(
'vname',
'vargs',
),
'#delta' => 0,
'#process' => array(
'viewfield_select_process',
),
),
);
}
function viewfield_select_process($element, $edit, $form_state, $form) {
// This form is used for both the default value field in the admin as well as
// the node edit form, so we have to make sure we show the default value field
// always.
$is_field_settings_form = !isset($form['#node']);
$field = isset($form['#field_info'][$element['#field_name']]) ? $form['#field_info'][$element['#field_name']] : NULL;
$element['#field'] = $field;
// Display the form to let the user pick a view.
$options = _viewfield_potential_references($field, $element['#delta']);
$element['vname'] = array(
'#type' => 'select',
'#title' => $element['#title'],
'#options' => $options,
'#default_value' => isset($element['#default_value']['vname']) ? $element['#default_value']['vname'] : NULL,
'#required' => $element['#required'],
'#access' => $is_field_settings_form || !$field['widget']['force_default'],
'#description' => $element['#description'],
);
// If there is only one option, only show arguments.
if (count($options) == 1 && !$is_field_settings_form) {
list($key, $label) = each($options);
$element['vname']['#access'] = FALSE;
$element['vname']['#default_value'] = $key;
}
$element['vargs'] = array(
'#type' => 'textfield',
'#title' => !isset($label) ? t('Arguments') : t('%field (@value) arguments', array(
'%field' => $field['widget']['label'],
'@value' => $label,
)),
'#default_value' => isset($element['#default_value']['vargs']) ? $element['#default_value']['vargs'] : NULL,
'#access' => $is_field_settings_form || !$field['widget']['force_default'],
'#description' => t('A comma separated list of arguments to pass to the selected view. Wrap arguments containing commas in double quotes. Replace double quotes in arguments with two double quotes.'),
);
$token_description = t('Available tokens: %nid for the id of the current node; %author for the node author; %viewer for the viewing user');
if (module_exists('token')) {
$element['vargs']['#description'] .= '<br />' . $token_description . '; ' . t('or any token from the placeholder token list.') . '<br />' . t('Note: Using placeholder tokens in combination with the %fields row style may negatively affect site performance.', array(
'%fields' => t('Fields'),
));
// Only show token help for first value or in field settings form.
if ($element['#delta'] == 0 && ($is_field_settings_form || !$field['widget']['force_default'])) {
$element['token_help'] = array(
'#type' => 'fieldset',
'#title' => t('Placeholder tokens'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
);
$element['token_help']['tokens'] = array(
'#value' => theme('token_help', 'node'),
);
}
}
else {
$element['vargs']['#description'] .= '<br />' . $token_description . '.';
}
return $element;
}
/**
* Prepare a list of views for selection.
*/
function _viewfield_potential_references($field, $delta = 0) {
$options = array();
if (isset($field['allowed_views']) && is_array($field['allowed_views'])) {
$field['allowed_views'] = array_filter($field['allowed_views']);
}
if (empty($field['allowed_views'])) {
$field['allowed_views'] = array_keys(views_get_all_views());
}
foreach ($field['allowed_views'] as $view_name) {
// Check for deleted views saved in allowed_views.
if ($view = views_get_view($view_name)) {
foreach ($view->display as $display) {
$options[$view->name . '|' . $display->id] = $view->name . ' - ' . $display->display_title;
}
}
}
// Add a '0' option for non-required or subsequent values of multiple fields.
if (empty($field['required']) || $field['multiple'] && $delta > 0) {
array_unshift($options, '<' . t('none') . '>');
}
return $options;
}
/**
* Implementation of hook_theme().
*/
function viewfield_theme() {
return array(
'viewfield_select' => array(
'arguments' => array(
'element' => NULL,
),
),
'viewfield_formatter_default' => array(
'arguments' => array(
'element' => NULL,
),
),
);
}
/**
* Add CSS to force help text to wrap correctly on node edit form.
*/
function theme_viewfield_select($element) {
if (!empty($element['#children'])) {
$field = $element['#field'];
if ($field['multiple'] && $element['#delta'] == 0) {
// This is needed only for multiple viewfields.
drupal_add_css(drupal_get_path('module', 'viewfield') . '/viewfield.css');
}
return '<div class="viewfield-select">' . $element['#children'] . '</div>';
}
}
/**
* Perform argument replacement
*/
function _viewfield_get_view_args($vargs, $node) {
$args = array();
// Prevent token_replace() from running this function a second time
// before it completes the first time.
static $tokens = TRUE;
if ($tokens && !empty($vargs)) {
$pos = 0;
while ($pos < strlen($vargs)) {
$found = FALSE;
// If string starts with a quote, start after quote and get everything
// before next quote.
if (strpos($vargs, '"', $pos) === $pos) {
if (($quote = strpos($vargs, '"', ++$pos)) !== FALSE) {
// Skip pairs of quotes.
while (!(($ql = strspn($vargs, '"', $quote)) & 1)) {
$quote = strpos($vargs, '"', $quote + $ql);
}
$args[] = str_replace('""', '"', substr($vargs, $pos, $quote + $ql - $pos - 1));
$pos = $quote + $ql + 1;
$found = TRUE;
}
}
elseif (($comma = strpos($vargs, ',', $pos)) !== FALSE) {
// Otherwise, get everything before next comma.
$args[] = substr($vargs, $pos, $comma - $pos);
// Skip to after comma and repeat
$pos = $comma + 1;
$found = TRUE;
}
if (!$found) {
$args[] = substr($vargs, $pos);
$pos = strlen($vargs);
}
}
// Try to replace tokens if $args might contain one.
if (strpos($vargs, '[') !== FALSE && module_exists('token')) {
$tokens = FALSE;
// If the view field is being loaded as a "view field" of "view row",
// instead of a simple "node field", the node object is not fully populated:
// we need a full node to perform a correct replacement.
$node = node_load($node->nid);
foreach ($args as $key => $text) {
$args[$key] = token_replace($text, 'node', $node);
}
$tokens = TRUE;
}
// For backwards compatibility, we scan for %nid, etc.
foreach ($args as $key => $value) {
$args[$key] = strtr($value, array(
'%nid' => $node->nid,
'%author' => isset($node->uid) ? $node->uid : (isset($node_values->uid) ? $node_values->uid : NULL),
'%viewer' => $GLOBALS['user']->uid,
));
}
}
return $args;
}
Functions
Name | Description |
---|---|
theme_viewfield_formatter_default | Return a themed view avoiding viewfield recursion. |
theme_viewfield_select | Add CSS to force help text to wrap correctly on node edit form. |
viewfield_content_is_empty | Implementation of hook_content_is_empty(). |
viewfield_elements | Implementation of FAPI hook_elements(). |
viewfield_field | Implementation of hook_field(). |
viewfield_field_formatter_info | Implementation of hook_field_formatter_info(). |
viewfield_field_info | Implementation of hook_field_info(). |
viewfield_field_settings | Implementation of hook_field_settings(). |
viewfield_select_process | |
viewfield_theme | Implementation of hook_theme(). |
viewfield_widget | Implementation of hook_widget(). |
viewfield_widget_info | Implementation of hook_widget_info(). |
viewfield_widget_settings | Implementation of hook_widget_settings(). |
_viewfield_get_view_args | Perform argument replacement |
_viewfield_potential_references | Prepare a list of views for selection. |