'viewreference autocomplete',
'page callback' => 'viewreference_autocomplete',
'page arguments' => array(2, 3),
'access callback' => 'viewreference_autocomplete_access',
'access arguments' => array(2, 3),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Implements hook_theme().
*/
function viewreference_theme() {
return array(
'viewreference_display_title' => array(
'variables' => array(
'view' => NULL,
'view_name' => NULL,
'display_key' => NULL,
'append_id' => FALSE,
),
),
'viewreference_formatter_default' => array(
'variables' => array('element' => NULL),
),
'viewreference_formatter_full' => array(
'variables' => array('element' => NULL),
),
'viewreference_formatter_plain' => array(
'variables' => array('element' => NULL),
),
'viewreference_formatter_link' => array(
'variables' => array('element' => NULL),
),
'viewreference_formatter_path' => array(
'variables' => array('element' => NULL),
),
);
}
/**
* Implements hook_field_info().
*/
function viewreference_field_info() {
$field_info = array(
'viewreference' => array(
'label' => t('View reference'),
'description' => t('Reference a views display from the views module.'),
'settings' => array(
'referenceable_views' => array(),
'referenceable_tags' => array(
'allow' => '',
'deny' => '',
),
'arguments' => array(
'dsv_arguments' => 0,
'php_arguments' => 0,
'delimiter' => '/',
'rows' => 1,
'label' => '!field_label ' . t('arguments'),
),
'append_id' => 0,
'skip_default' => 1,
'skip_empty' => 0,
),
'default_widget' => 'viewreference_autocomplete',
'default_formatter' => 'viewreference_default',
),
);
return $field_info;
}
/**
* Implements hook_field_schema().
*/
function viewreference_field_schema($field) {
$columns = array(
'view_id' => array(
'type' => 'varchar',
'length' => '255',
'default' => NULL,
'not null' => FALSE,
),
'arguments' => array(
'type' => 'text',
'size' => 'big',
),
);
return array(
'columns' => $columns,
'indexes' => array('view_id' => array('view_id')),
);
}
/**
* Implements hook_field_settings_form().
*/
function viewreference_field_settings_form($field, $instance, $has_data) {
$settings = $field['settings'];
$form = array();
$form['referenceable_views'] = array(
'#type' => 'checkboxes',
'#title' => t('Views that can be referenced'),
'#description' => t('Select the Views that can be referenced. If no Views are selected here, and tags are not entered below, then all the Views will be available.'),
'#multiple' => TRUE,
'#default_value' => is_array($settings['referenceable_views']) ? $settings['referenceable_views'] : array(),
'#options' => viewreference_get_views($settings['append_id']), // This call doesn't supply $settings, so they aren't filtered.
);
$form['referenceable_tags'] = array(
'#type' => 'fieldset',
'#title' => t('Views tags that can be referenced'),
'#collapsible' => TRUE,
'#collapsed' => (!empty($settings['referenceable_tags']['allow']) || !empty($settings['referenceable_tags']['deny'])) ? FALSE : TRUE,
'#description' => t('Optionally you can allow views by tags here instead of, or in addition to, using Views that can be referenced, then other Views will be excluded. You can also deny views by tags, and if Views that can be referenced and the Allow list are left blank all other Views will be available.'),
);
$form['referenceable_tags']['allow'] = array(
'#type' => 'textfield',
'#title' => t('Allow list'),
'#default_value' => !empty($settings['referenceable_tags']['allow']) ? $settings['referenceable_tags']['allow'] : '',
'#size' => 128,
'#maxlength' => 512,
'#description' => t('Enter a comma delimited list of tags to include.'),
);
$form['referenceable_tags']['deny'] = array(
'#type' => 'textfield',
'#title' => t('Deny list'),
'#default_value' => !empty($settings['referenceable_tags']['deny']) ? $settings['referenceable_tags']['deny'] : '',
'#size' => 128,
'#maxlength' => 512,
'#description' => t('Enter a comma delimited list of tags to exclude.'),
);
$form['arguments'] = array(
'#type' => 'fieldset',
'#title' => t('Contextual filter arguments'),
'#collapsible' => TRUE,
'#collapsed' => ($settings['arguments']['dsv_arguments'] || $settings['arguments']['php_arguments']) ? FALSE : TRUE,
'#description' => t('Enabling the following options will provide an input field for passing arguments (aka contextual filters) to the View.'),
);
$form['arguments']['dsv_arguments'] = array(
'#type' => 'checkbox',
'#title' => t('Allow delimiter seperated values.'),
'#default_value' => isset($settings['arguments']['dsv_arguments']) ? $settings['arguments']['dsv_arguments'] : 0,
'#description' => t('Users can provide a list of arguments seperated by a delimiter. e.g: term_1/term_2'),
);
$form['arguments']['php_arguments'] = array(
'#type' => 'checkbox',
'#title' => t('Allow PHP code.'),
'#default_value' => isset($settings['arguments']['php_arguments']) ? $settings['arguments']['php_arguments'] : 0,
'#description' => t('Users can insert PHP code to generate the list of arguments. e.g: term_1/<?php print "term_x/term_y"; ?>/term_2') .
'
' . t('Note: The users must have the use PHP for settings permission.'),
'#disabled' => !user_access('use PHP for settings'),
);
$form['arguments']['delimiter'] = array(
'#type' => 'textfield',
'#title' => t('Delimiter'),
'#default_value' => !empty($settings['arguments']['delimiter']) ? $settings['arguments']['delimiter'] : '/',
'#size' => 3,
'#maxlength' => 30,
'#required' => TRUE,
);
$row_range = range(0, 10);
unset($row_range[0]);
$form['arguments']['rows'] = array(
'#type' => 'select',
'#title' => t('Number of rows in argument field'),
'#default_value' => isset($settings['arguments']['rows']) ? $settings['arguments']['rows'] : 1,
'#options' => $row_range,
'#description' => t('Set as 1 for textfield, or larger values for textarea (may be easier to write PHP with a textarea)'),
'#required' => TRUE,
);
$form['arguments']['label'] = array(
'#type' => 'textfield',
'#title' => t('Label for arguments field'),
'#default_value' => isset($settings['arguments']['label']) ? $settings['arguments']['label'] : '!field_label ' . t('arguments'),
'#description' => t('Use !field_label to insert the field label.'),
);
$form['append_id'] = array(
'#type' => 'checkbox',
'#title' => t('Append unique ID in lists.'),
'#default_value' => isset($settings['append_id']) ? $settings['append_id'] : 0,
'#description' => t('It is possible for Views displays to have the same title, this option will append [view:view_display_n] in lists used by this field to disambiguate the options.'),
);
$form['skip_default'] = array(
'#type' => 'checkbox',
'#title' => t('Exclude the master (default) display from lists.'),
'#default_value' => isset($settings['skip_default']) ? $settings['skip_default'] : 1,
);
$form['skip_empty'] = array(
'#type' => 'checkbox',
'#title' => t('Do not output view if no rows are detected'),
'#default_value' => isset($settings['skip_empty']) ? $settings['skip_empty'] : 0,
);
$form['skip_disabled'] = array(
'#type' => 'checkbox',
'#title' => t('Do not allow selection of disabled views'),
'#default_value' => isset($settings['skip_disabled']) ? $settings['skip_disabled'] : 0,
);
$form['sort_views'] = array(
'#type' => 'checkbox',
'#title' => t('Sort the views by title'),
'#default_value' => isset($settings['sort_views']) ? $settings['sort_views'] : 1,
);
return $form;
}
/**
* Implements hook_field_validate().
*/
function viewreference_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
$views = viewreference_get_views($field['settings']['append_id'], $field['settings']);
foreach ($items as $delta => $item) {
if (is_array($item)) {
if (!empty($item['view_id'])) {
if (!in_array($item['view_id'], array_keys($views))) {
$errors[$field['field_name']][$langcode][$delta][] = array(
'error' => 'invalid_view',
'message' => t("%name: This view can't be referenced.",
array('%name' => $instance['label'])),
);
}
}
}
}
}
/**
* Implements hook_field_is_empty().
*/
function viewreference_field_is_empty($item, $field) {
return empty($item['view_id']);
}
/**
* Implements hook_field_formatter_info().
*/
function viewreference_field_formatter_info() {
$ret = array(
'viewreference_default' => array(
'label' => t('Default (view)'),
'description' => t('Display the referenced view.'),
'field types' => array('viewreference'),
),
'viewreference_full' => array(
'label' => t('Full (title and view)'),
'description' => t('Display the referenced view with a title.'),
'field types' => array('viewreference'),
),
'viewreference_plain' => array(
'label' => t('Title (no link)'),
'description' => t('Display the title of the referenced view.'),
'field types' => array('viewreference'),
),
'viewreference_link' => array(
'label' => t('Title (link)'),
'description' => t('Display the title of the referenced view as a link (if possible).'),
'field types' => array('viewreference'),
),
'viewreference_path' => array(
'label' => t('Path'),
'description' => t('Display the path of the referenced view (if possible).'),
'field types' => array('viewreference'),
),
);
return $ret;
}
/**
* Implements hook_field_formatter_view().
*/
function viewreference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
$element = array();
$formatter = str_replace('viewreference_', '', $display['type']);
foreach ($items as $delta => $item) {
$element[$delta] = array(
'#theme' => 'viewreference_formatter_' . $formatter,
'#element' => array(
'entity_type' => &$entity_type,
'entity' => &$entity,
'field' => &$field,
'instance' => &$instance,
'langcode' => &$langcode,
'item' => $item,
'display' => &$display,
),
);
$element[$delta]['#element']['view'] = viewreference_get_view($element[$delta]['#element']);
if (!$element[$delta]['#element']['view']) {
unset($element[$delta]);
}
}
return $element;
}
/**
* Value callback for a viewreference_autocomplete element.
*/
function viewreference_autocomplete_value($element, $input = FALSE, $form_state) {
if ($input === FALSE) {
$field_key = $element['#columns'][0];
$args_key = $element['#columns'][1];
if (!empty($element['#default_value'][$field_key])) {
$field_name = $element['#field_name'];
$field = field_info_field($field_name);
$settings = $field['settings'];
$settings['referenceable_views'] = array($element['#default_value'][$field_key]);
$views = viewreference_get_views(TRUE, $settings);
$value = $views[$element['#default_value'][$field_key]];
return array($field_key => $value, $args_key => $element['#default_value'][$args_key]);
}
return array($field_key => NULL, $args_key => $element['#default_value'][$args_key]);
}
}
/**
* Validation callback for a viewreference_autocomplete element.
*/
function viewreference_autocomplete_validate($element, &$form_state, $form) {
$field = field_widget_field($element, $form_state);
$value = $element['#value'];
$new_value = NULL;
if (!empty($value)) {
$regex = '/' // Start of string
. '(.*).*?' // Any non-greedy
. '(\\[)' // [
. '((?:[a-z][a-z0-9_]*))' // Variable 1
. '(:)' // :
. '((?:[a-z][a-z0-9_]*))' // Variable 2
. '(\\])' // ]
. '/is'; // End of string
preg_match($regex, $value, $matches);
if (!empty($matches)) {
$new_value = $matches[3] . ':' . $matches[5];
$allowed = viewreference_get_views(FALSE, $field['settings']);
if (!isset($allowed[$new_value])) {
form_error(
$element,
t(
'%name: View display %value cannot be referenced.',
array(
'%name' => $element['#title'],
'%value' => $new_value,
)
)
);
}
}
else {
form_error(
$element,
t(
'%name: The value %value is in an unexpected format. Expecting: %format',
array(
'%name' => $element['#title'],
'%value' => $value,
'%format' => 'View title [view:display_n]',
)
)
);
}
}
form_set_value($element, $new_value, $form_state);
}
/**
* Implements hook_field_widget_error().
*/
function viewreference_field_widget_error($element, $error, $form, &$form_state) {
form_error($element['view_id'], $error['message']);
}
/**
* Menu access callback for the autocomplete path.
*
* Check for both 'edit' and 'view' access in the unlikely event
* a user has edit but not view access.
*/
function viewreference_autocomplete_access($entity_type, $field_name) {
return user_access('access content') && ($field = field_info_field($field_name)) && field_access('view', $field, $entity_type) && field_access('edit', $field, $entity_type);
}
/**
* Menu callback for the autocomplete results.
*/
function viewreference_autocomplete($bundle_name, $field_name, $string = '') {
// If the request has a '/' in the search text, then the menu system will have
// split it into multiple arguments, recover the intended $string.
$args = func_get_args();
// Shift off the $bundle_name argument.
array_shift($args);
// Shift off the $field_name argument.
array_shift($args);
$string = implode('/', $args);
$field = field_info_field($field_name);
$settings = $field['settings'];
$matches = viewreference_get_views($settings['append_id'], $settings, FALSE, $string, FALSE, TRUE);
drupal_json_output($matches);
}
/**
* Implements hook_options_list().
*/
function viewreference_options_list($field) {
$references = viewreference_get_views($field['settings']['append_id'], $field['settings']);
$options = array();
foreach ($references as $key => $value) {
$options[$key] = $value['rendered'];
}
return $options;
}
/**
* Create a display title for a view display.
*/
function viewreference_views_display_title($view_name, $view, $display) {
// Build the display title.
if (isset($view->display[$display]->display_options['title'])) {
// This view display has a nice title, let's use that.
return $view->display[$display]->display_options['title'];
}
elseif (isset($view->display['default']->display_options['title'])) {
// This view display inherits it's title from the default display.
return $view->display['default']->display_options['title'];
}
else {
// This view display does not have a title configured, we have to construct a title.
return ucfirst($view_name) . ' ' . strtolower($view->display[$display]->display_title);
}
}
/**
* Get an array of data and rendered HTML items that are useful in theming the
* formatter output.
*
* @param $element
* An array of parameters used in viewing the element.
* @param $params
* An array of special features needed to be built:
* 'embed' - The $view->preview() of the view display
* 'title' - The display title of the view display
* 'link' - A link to the view display, or the title if link not available.
* 'path' - The path to the view display, or the title if path not available.
* 'contextual' - The contextual links.
* @return
* The array of useful data about the view.
*/
function viewreference_get_view($element, $params = array()) {
if (!empty($element['item']['view_id'])) {
if (!empty($element['view'])) {
$view = $element['view'];
}
if (empty($view['view']) || empty($view['display']) || empty($view['name'])) {
$view_id_parts = explode(':', $element['item']['view_id']);
$view['name'] = $view_id_parts[0];
$view['display'] = $view_id_parts[1];
$view['view'] = views_get_view($view['name']);
}
if ($view['view'] && $view['view']->access($view['display'])) {
// Save $_GET['q'] so it can be restored before returning from this function.
//$q = $_GET['q'];
if (empty($view['embed']) && (in_array('embed', $params) || !empty($element['field']['settings']['skip_empty']))) {
$view['args'] = viewreference_get_element_args($element);
//if (!empty($view['args'])) {
// $_GET['q'] .= '/' . implode('/', $view['args']);
//}
$view['embed'] = $view['view']->preview($view['display'], $view['args']);
// If the view is empty and the viewreference field is configured with
// "skip empty views" enabled, skip outputting the view.
if (!empty($element['field']['settings']['skip_empty']) && empty($view['view']->result)) {
// Restore $_GET['q'] before skipping the view.
//$_GET['q'] = $q;
return FALSE;
}
}
if ((in_array('title', $params) && empty($view['title'])) || (in_array('link', $params) && empty($view['link']))) {
$view['display_key'] = $view['display'];
$view['title'] = theme('viewreference_display_title', $view);
if (in_array('link', $params) && empty($view['link'])) {
$disabled = isset($view['view']->disabled) ? $view['view']->disabled: FALSE;
if (isset($view['view']->display[$view['display']]->display_options['path']) && !$disabled) {
$view['args'] = isset($view['args']) ? $view['args'] : viewreference_get_element_args($element);
$view['url_args'] = implode('/', $view['args']);
$view['path'] = $view['view']->display[$view['display']]->display_options['path'];
if ($view['url_args']) {
$view['path'] .= '/' . $view['url_args'];
}
$view['link'] = l($view['title'], $view['view']->get_url($view['args'], $view['path']));
}
else {
$view['link'] = $view['title'];
}
}
}
if (in_array('contextual', $params) && empty($view['contextual'])) {
$view['contextual'] = '';
if (module_exists('contextual')) {
$contextual = contextual_element_info();
views_add_contextual_links($contextual['contextual_links'], 'special_block_-exp', $view['view'], $view['display']);
if (!empty($contextual['contextual_links']['#contextual_links'])) {
$view['contextual'] = drupal_render($contextual['contextual_links']);
}
}
}
//$_GET['q'] = $q;
return $view;
}
}
}
/**
* Theme function for 'default' viewreference field formatter.
*/
function theme_viewreference_formatter_default($variables) {
$element = &$variables['element'];
$output = '';
if ($view = viewreference_get_view($element, array('contextual', 'embed'))) {
$output .= '