' . $info . '
';
if (variable_get('views_ui_query_on_top', FALSE)) {
$output .= $info . $preview;
}
else {
$output .= $preview . $info;
}
if (!$js) {
views_add_css('views-admin');
drupal_set_title($view->get_title());
return $output;
}
else {
views_include('ajax');
$object = new stdClass();
if (!empty($view->js_settings)) {
$object->js = $view->js_settings;
}
$object->display = '';
if ($messages = theme('status_messages')) {
$object->display = '' . $messages . '
';
}
$object->display .= $output;
$object->title = $view->get_title();
views_ajax_render($object);
}
}
/**
* Form for generating argument information for the live preview.
*/
function views_ui_preview_form(&$form_state) {
$view = &$form_state['view'];
$view->init_display();
$options = array();
foreach ($view->display as $id => $display) {
$options[$id] = $display->display_title;
}
$form['#attributes'] = array(
'class' => 'clear-block',
);
$form['display_id'] = array(
'#type' => 'select',
'#title' => t('Display'),
'#options' => $options,
'#default_value' => $form_state['display_id'],
'#id' => 'preview-display-id',
);
$form['args'] = array(
'#type' => 'textfield',
'#title' => t('Arguments'),
'#default_value' => $form_state['view_args'],
'#description' => t('Separate arguments with a / as though they were a URL path.'),
'#id' => 'preview-args',
);
$form['preview'] = array(
'#type' => 'submit',
'#value' => t('Preview'),
'#id' => 'preview-submit',
);
$form['live_preview'] = array(
'#type' => 'checkbox',
'#title' => t('Automatic live preview'),
'#default_value' => !variable_get('views_ui_disable_live_preview', 0),
);
$form['#action'] = url("admin/build/views/nojs/preview/$view->name");
return $form;
}
/**
* Submit the preview form.
*
* This just takes the data and stores it on the form state in a
* known location. The caller will be responsible for using it.
*/
function views_ui_preview_form_submit(&$form, &$form_state) {
$form_state['display_id'] = $form_state['values']['display_id'];
$form_state['view_args'] = $form_state['values']['args'];
}
/**
* Page callback to add a new view.
*/
function views_ui_add_page() {
$form_state = array(
'view' => NULL
);
return drupal_build_form('views_ui_add_form', $form_state);
}
/**
* Page callback to add a new view.
*/
function views_ui_clone_page($view) {
$form_state = array(
'view' => $view->copy(),
);
drupal_set_title(t('Clone view %view', array('%view' => $view->name)));
return drupal_build_form('views_ui_add_form', $form_state);
}
/**
* Form constructor callback to create the views Add Form, phase 1.
*/
function views_ui_add_form(&$form_state) {
$view = $form_state['view'];
$form = array();
$form['name'] = array(
'#type' => 'textfield',
'#title' => t('View name'),
'#description' => t('This is the unique name of the view. It must contain only alphanumeric characters and underscores; it is used to identify the view internally and to generate unique theming template names for this view. If overriding a module provided view, the name must not be changed or instead a new view will be created.'),
'#required' => TRUE,
'#maxlength' => 32,
'#default_value' => $view ? $view->name : '',
'#attributes' => array('dir'=>'ltr'),
);
$form['description'] = array(
'#type' => 'textfield',
'#title' => t('View description'),
'#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'),
'#default_value' => $view ? $view->description : '',
);
$form['tag'] = array(
'#type' => 'textfield',
'#title' => t('View tag'),
'#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'),
'#default_value' => $view ? $view->tag : '',
'#autocomplete_path' => 'admin/views/ajax/autocomplete/tag',
);
$base_tables = array();
foreach (views_fetch_base_tables() as $table => $info) {
$base_tables[$table] = $info['title'] . '' . $info['description'] . '
';
}
$form['base_table'] = array(
'#type' => 'radios',
'#title' => t('View type'),
'#description' => t('The view type is the primary table for which information is being retrieved. The view type controls what arguments, fields, sort criteria and filters are available, so once this is set it ' . t("Click on an item to edit that item's details.") . '
';
if (!$view->set_display('default')) {
drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error');
}
foreach ($view->display as $display) {
list($title, $body) = views_ui_display_tab($view, $display);
// The first display is the default.
$tabs->set($display->id, $title, $body);
}
// This is the area that will render beneath the links
$form_state = array(
'view' => &$view,
'ajax' => FALSE,
);
$display_button = drupal_build_form('views_ui_add_display_form', $form_state);
$analyze_button = drupal_get_form('views_ui_analyze_view_button', $view);
$tabs->add_extra($display_button . $analyze_button);
$vars['tabs'] = $tabs->render();
$form_state = array(
'display_id' => 'default',
'view_args' => '',
'rerender' => FALSE,
'no_redirect' => TRUE,
'view' => &$view,
'input' => array(),
);
$vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state);
$vars['locked'] = NULL;
if (isset($view->locked) && is_object($view->locked)) {
$account = user_load($view->locked->uid);
$vars['locked'] = theme('username', $account);
$vars['lock_age'] = format_interval(time() - $view->locked->updated);
$vars['break'] = url('admin/build/views/break-lock/' . $view->name);
}
$vars['quick_links_raw'] = array(
array(
'title' => t('Export'),
'alt' => t("Export this view"),
'href' => "admin/build/views/export/$view->name",
),
array(
'title' => t('Clone'),
'alt' => t("Create a copy of this view"),
'href' => "admin/build/views/clone/$view->name",
),
);
$paths = array();
foreach ($view->display as $id => $display) {
if (!empty($display->handler) && $display->handler->has_path()) {
$path = $display->handler->get_path();
if (strpos($path, '%') === FALSE && !isset($paths[$path])) {
$vars['quick_links_raw'][] = array(
'title' => t('View "@display"', array('@display' => $display->display_title)),
'alt' => t("Go to the real page for this display"),
'href' => $path,
);
// Displays can have the same path; no point in showing more than one link.
$paths[$path] = TRUE;
}
}
}
$vars['quick_links'] = theme('links', $vars['quick_links_raw']);
views_add_css('views-admin');
views_add_js('ajax');
drupal_add_js('misc/jquery.form.js');
// Also add any js files required by plugins:
$plugins = views_fetch_plugin_data();
foreach ($plugins as $type => $type_plugins) {
foreach ($type_plugins as $name => $plugin) {
if (!empty($plugin['js'])) {
foreach ($plugin['js'] as $file) {
drupal_add_js($file);
}
}
}
}
$settings = array('views' => array('ajax' => array(
'id' => '#views-ajax-pad',
'title' => '#views-ajax-title',
'defaultForm' => $vars['message'],
)));
drupal_add_js($settings, 'setting');
}
function template_preprocess_views_ui_edit_tab(&$vars) {
$view = $vars['view'];
$display = $vars['display'];
$plugin = $display->handler->definition;
$top = $left = $middle = $right = '';
// If this form was submitted it was already handled, so force it not to
// submit again.
$vars['remove'] = '';
if (empty($plugin['no remove'])) {
if (!empty($_POST['form_id']) && $_POST['form_id'] == 'views_ui_remove_display_form') {
unset($_POST['form_id']);
}
$form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE);
$vars['remove'] = drupal_build_form('views_ui_remove_display_form', $form_state);
}
// basic fields
$vars['title'] = check_plain($display->display_title);
$vars['description'] = check_plain($plugin['help']);
// Special fields if tihs is the default display.
$vars['default'] = ($display->id == 'default');
$vars['details_class'] = views_ui_item_css('details');
if (!empty($view->changed_sections['details'])) {
$vars['details_changed'] = TRUE;
}
$tag = empty($view->tag) ? t('None') : $view->tag;
$vars['details'] = t('Description') . '/' . t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link')));
// Calculate options from display plugin.
$options = $categories = array();
$display->handler->options_summary($categories, $options);
// Build all of the options we were returned and put them into the
// category data fields.
foreach ($options as $id => $option) {
if (empty($categories[$option['category']]['data'])) {
$categories[$option['category']]['data'] = array();
}
$categories[$option['category']]['data'][$id] = array();
$data = &$categories[$option['category']]['data'][$id];
$data['content'] = '';
$data['links'] = '';
$data['overridden'] = FALSE;
$data['defaulted'] = FALSE;
// If there are optional links, build them first so they float properly.
if (!empty($option['links'])) {
foreach ($option['links'] as $link_id => $link_value) {
$data['links'] .= $display->handler->option_link($link_value, $link_id, 'views-button-configure');
}
}
if (!empty($option['title'])) {
$data['content'] .= $option['title'] . ': ';
}
$data['content'] .= $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']);
if (!empty($display->handler->options['defaults'][$id])) {
$display_id = 'default';
$data['defaulted'] = TRUE;
}
else {
$display_id = $display->id;
if (!$display->handler->is_default_display()) {
if ($display->handler->defaultable_sections($id)) {
$data['overridden'] = TRUE;
}
}
}
$data['class'] = views_ui_item_css($display_id . '-' . $id);
if (!empty($view->changed_sections[$display_id . '-' . $id])) {
$data['changed'] = TRUE;
}
}
$vars['categories'] = $categories;
// Add a help icon
if (isset($plugin['help topic'])) {
$vars['display_help_icon'] = theme('advanced_help_topic', $plugin['module'], $plugin['help topic']);
}
else {
$vars['display_help_icon'] = '';
}
// Fetch style plugin info because it has some effect on how/what we render.
$style_plugin = $display->handler->get_plugin();
$vars['fields'] = '';
$vars['fields'] = theme('views_ui_edit_item', 'field', $view, $display, !($style_plugin && $style_plugin->uses_fields()));
$vars['relationships'] = theme('views_ui_edit_item', 'relationship', $view, $display);
$vars['arguments'] = theme('views_ui_edit_item', 'argument', $view, $display);
$vars['filters'] = theme('views_ui_edit_item', 'filter', $view, $display);
$vars['sorts'] = theme('views_ui_edit_item', 'sort', $view, $display);
}
/**
* Generate the summary output for a single display to render in a tab.
*/
function views_ui_display_tab($view, $display) {
if (isset($display->handler)) {
$plugin = $display->handler->definition;
}
if (empty($plugin)) {
$title = isset($display->display_title) ? $display->display_title : t('Invalid');
return array($title, t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin)));
// @todo We can do a better 'plugin does not exist' tab.
}
// The display should always be initialized prior to this call.
if (empty($display->handler)) {
return FALSE;
}
$body = theme('views_ui_edit_tab', $view, $display);
return array($display->display_title, $body);
}
/**
* Add information about a section to a display.
*/
function template_preprocess_views_ui_edit_item(&$vars) {
$type = $vars['type'];
$view = $vars['view'];
$display = $vars['display'];
$types = views_object_types();
$vars['overridden'] = FALSE;
$vars['defaulted'] = FALSE;
if ($vars['no_fields']) {
$vars['title'] = $types[$type]['title'];
$vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type);
$vars['rearrange'] = NULL;
$vars['add'] = NULL;
return;
}
$vars['rearrange'] = l(''));
$form['group'] = array(
'#type' => 'select',
'#title' => t('Groups'),
'#options' => array(),
'#attributes' => array('class' => 'views-master-dependent'),
);
$form['name'] = array(
'#prefix' => '',
'#suffix' => '
',
'#tree' => TRUE,
'#default_value' => 'all',
);
// Group options first to simplify the DOM objects that Views
// dependent JS will act upon.
$grouped_options = array();
foreach ($options as $key => $option) {
$group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group']));
$groups[$group] = $option['group'];
$grouped_options[$group][$key] = $option;
}
foreach ($grouped_options as $group => $group_options) {
$form['name'][$group . '_start'] = array('#type' => 'markup', '#value' => '');
foreach ($group_options as $key => $option) {
$form['name'][$key] = array(
'#type' => 'checkbox',
'#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])),
'#description' => $option['help'],
'#return_value' => $key,
);
}
$form['name'][$group . '_end'] = array('#type' => 'markup', '#value' => '
');
}
$form['group']['#options'] = $groups;
}
else {
$form['markup'] = array(
'#value' => '' . t('There are no @types available to add.', array('@types' => $types[$type]['ltitle'])) . '
',
);
}
views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add'));
return $form;
}
/**
* Submit handler for adding new item(s) to a view.
*/
function views_ui_add_item_form_submit($form, &$form_state) {
$type = $form_state['type'];
$types = views_object_types();
if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) {
// Loop through each of the items that were checked and add them to the view.
foreach (array_keys(array_filter($form_state['values']['name'])) as $field) {
list($table, $field) = explode('.', $field, 2);
$id = $form_state['view']->add_item($form_state['display_id'], $type, $table, $field);
// check to see if this type has settings, if so add the settings form first
$handler = views_get_handler($table, $field, $type);
if ($handler && $handler->has_extra_options()) {
views_ui_add_form_to_stack('config-item-extra', $form_state['view'], $form_state['display_id'], array($type, $id));
}
// Then add the form to the stack
views_ui_add_form_to_stack('config-item', $form_state['view'], $form_state['display_id'], array($type, $id));
}
}
// Store in cache
views_ui_cache_set($form_state['view']);
}
/**
* Form to config_item items in the views UI.
*/
function views_ui_config_item_form(&$form_state) {
$view = &$form_state['view'];
$display_id = $form_state['display_id'];
$type = $form_state['type'];
$id = $form_state['id'];
$form = array('options' => array('#tree' => TRUE));
if (!$view->set_display($display_id)) {
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
}
$item = $view->get_item($display_id, $type, $id);
if ($item) {
$handler = views_get_handler($item['table'], $item['field'], $type);
if (empty($handler)) {
$form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
}
else {
$handler->init($view, $item);
$types = views_object_types();
if ($view->display_handler->defaultable_sections($types[$type]['plural'])) {
$form_state['section'] = $types[$type]['plural'];
$view->display_handler->add_override_button($form['options'], $form_state, $form_state['section']);
}
// A whole bunch of code to figure out what relationships are valid for
// this item.
$relationships = $view->display_handler->get_option('relationships');
$relationship_options = array();
foreach ($relationships as $relationship) {
// relationships can't link back to self. But also, due to ordering,
// relationships can only link to prior relationships.
if ($type == 'relationship' && $id == $relationship['id']) {
break;
}
$relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship');
// ignore invalid/broken relationships.
if (empty($relationship_handler)) {
continue;
}
// If this relationship is valid for this type, add it to the list.
$data = views_fetch_data($relationship['table']);
$base = $data[$relationship['field']]['relationship']['base'];
$base_fields = views_fetch_fields($base, $form_state['type']);
if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
$relationship_handler->init($view, $relationship);
$relationship_options[$relationship['id']] = $relationship_handler->label();
}
}
if (!empty($relationship_options)) {
// Make sure the existing relationship is even valid. If not, force
// it to none.
$base_fields = views_fetch_fields($view->base_table, $form_state['type']);
if (isset($base_fields[$item['table'] . '.' . $item['field']])) {
$relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options);
}
$rel = empty($item['relationship']) ? 'none' : $item['relationship'];
if (empty($relationship_options[$rel])) {
// Pick the first relationship.
$rel = key($relationship_options);
// We want this relationship option to get saved even if the user
// skips submitting the form.
$view->set_item_option($display_id, $type, $id, 'relationship', $rel);
$temp_view = $view->clone_view();
views_ui_cache_set($temp_view);
}
$form['options']['relationship'] = array(
'#type' => 'select',
'#title' => t('Relationship'),
'#options' => $relationship_options,
'#default_value' => $rel,
);
}
else {
$form['options']['relationship'] = array(
'#type' => 'value',
'#value' => 'none',
);
}
$form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
$form['#title'] .= t('Configure @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-' . $id;
// Get form from the handler.
$handler->options_form($form['options'], $form_state);
$form_state['handler'] = &$handler;
}
$name = NULL;
if (isset($form_state['update_name'])) {
$name = $form_state['update_name'];
}
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove');
}
return $form;
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_config_item_form_validate($form, &$form_state) {
$form_state['handler']->options_validate($form['options'], $form_state);
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_config_item_form_submit($form, &$form_state) {
// Run it through the handler's submit function.
$form_state['handler']->options_submit($form['options'], $form_state);
$item = $form_state['handler']->options;
// Unset a button
unset($form_state['values']['options']['expose_button']);
// Store the data we're given.
foreach ($form_state['values']['options'] as $key => $value) {
$item[$key] = $value;
}
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
$handler = views_get_handler($item['table'], $item['field'], $form_state['type']);
$handler->init($form_state['view'], $item);
if ($handler && $handler->needs_style_plugin()) {
views_ui_add_form_to_stack('change-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
}
// Write to cache
views_ui_cache_set($form_state['view']);
}
/**
* Submit handler for removing an item from a view
*/
function views_ui_config_item_form_remove($form, &$form_state) {
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], NULL);
// Write to cache
views_ui_cache_set($form_state['view']);
}
/**
* Override handler for views_ui_edit_display_form
*/
function views_ui_config_item_form_expose($form, &$form_state) {
$item = &$form_state['handler']->options;
// flip
$item['exposed'] = empty($item['exposed']);
// If necessary, set new defaults:
if ($item['exposed']) {
$form_state['handler']->expose_options();
}
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
$form_state['force_expose_options'] = TRUE;
}
/**
* Form to config_item items in the views UI.
*/
function views_ui_config_item_extra_form(&$form_state) {
$view = &$form_state['view'];
$display_id = $form_state['display_id'];
$type = $form_state['type'];
$id = $form_state['id'];
$form = array('options' => array('#tree' => TRUE));
if (!$view->set_display($display_id)) {
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
}
$item = $view->get_item($display_id, $type, $id);
if ($item) {
$handler = views_get_handler($item['table'], $item['field'], $type);
if (empty($handler)) {
$form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
break;
}
else {
$handler->init($view, $item);
$types = views_object_types();
$form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
$form['#title'] .= t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-' . $id;
// Get form from the handler.
$handler->extra_options_form($form['options'], $form_state);
$form_state['handler'] = &$handler;
}
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form');
}
return $form;
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_config_item_extra_form_validate($form, &$form_state) {
$form_state['handler']->extra_options_validate($form['options'], $form_state);
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_config_item_extra_form_submit($form, &$form_state) {
// Run it through the handler's submit function.
$form_state['handler']->extra_options_submit($form['options'], $form_state);
$item = $form_state['handler']->options;
// Store the data we're given.
foreach ($form_state['values']['options'] as $key => $value) {
$item[$key] = $value;
}
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
// Write to cache
views_ui_cache_set($form_state['view']);
}
/**
* Form to change_style items in the views UI.
*/
function views_ui_change_style_form(&$form_state) {
$view = &$form_state['view'];
$display_id = $form_state['display_id'];
$type = $form_state['type'];
$id = $form_state['id'];
$form = array('options' => array('#tree' => TRUE));
if (!$view->set_display($display_id)) {
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
}
$item = $view->get_item($display_id, $type, $id);
if ($item) {
$handler = views_get_handler($item['table'], $item['field'], $type);
if (empty($handler)) {
$form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
break;
}
$handler->init($view, $item);
$types = views_object_types();
$form['#title'] = t('Change summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin';
$form['style_plugin'] = array(
'#type' => 'radios',
'#options' => views_fetch_plugin_names('style', 'summary'),
'#default_value' => $item['style_plugin'],
);
$form_state['handler'] = &$handler;
views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form');
}
return $form;
}
function views_ui_change_style_form_validate($form, &$form_state) {
// Run it through the handler's submit function.
$form_state['handler']->options_validate($form['options'], $form_state);
$plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
if (!$plugin) {
form_error($form['style_plugin'], t('Internal error: broken plugin.'));
}
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_change_style_form_submit($form, &$form_state) {
// Run it through the handler's submit function.
$form_state['handler']->options_submit($form['options'], $form_state);
$item = $form_state['handler']->options;
$plugin = views_get_plugin('style', $form_state['values']['style_plugin']);
if (!$plugin) {
drupal_set_message(t('Internal error: broken plugin.'), 'error');
return;
}
$plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]);
// If changing style plugin, reset options to defaults.
if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) {
$item['style_options'] = $plugin->options;
}
// Store the data we're given.
$item['style_plugin'] = $form_state['values']['style_plugin'];
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
if (!empty($plugin->definition['uses options'])) {
views_ui_add_form_to_stack('config-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE);
}
// Write to cache
views_ui_cache_set($form_state['view']);
}
/**
* Form to config_style items in the views UI.
*/
function views_ui_config_style_form(&$form_state) {
$view = &$form_state['view'];
$display_id = $form_state['display_id'];
$type = $form_state['type'];
$id = $form_state['id'];
$form = array('options' => array('#tree' => TRUE));
if (!$view->set_display($display_id)) {
views_ajax_render(t('Invalid display id @display', array('@display' => $display_id)));
}
$item = $view->get_item($display_id, $type, $id);
if ($item) {
$handler = views_get_handler($item['table'], $item['field'], $type);
if (empty($handler)) {
$form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field'])));
break;
}
$handler->init($view, $item);
$types = views_object_types();
$form['#title'] = check_plain($view->display[$display_id]->display_title) . ': ';
$form['#title'] .= t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name()));
$form['#section'] = $display_id . '-' . $type . '-style-options';
$plugin = views_get_plugin('style', $item['style_plugin']);
if ($plugin) {
$form['style_options'] = array(
'#tree' => TRUE,
);
$plugin->init($view, $view->display[$display_id], $item['style_options']);
$plugin->options_form($form['style_options'], $form_state);
}
$form_state['handler'] = &$handler;
views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form');
}
return $form;
}
/**
* Submit handler for configing new item(s) to a view.
*/
function views_ui_config_style_form_submit($form, &$form_state) {
// Run it through the handler's submit function.
$form_state['handler']->options_submit($form['style_options'], $form_state);
$item = $form_state['handler']->options;
// Store the data we're given.
$item['style_options'] = $form_state['values']['style_options'];
// Store the item back on the view
$form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item);
// Write to cache
views_ui_cache_set($form_state['view']);
}
/**
* Get a list of roles in the system.
*/
function views_ui_get_roles() {
static $roles = NULL;
if (!isset($roles)) {
$roles = array();
$result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
while ($obj = db_fetch_object($result)) {
$roles[$obj->rid] = $obj->name;
}
}
return $roles;
}
/**
* Get a css safe id for a particular section.
*/
function views_ui_item_css($item) {
return views_css_safe('views-item-' . $item);
}
/**
* Page callback for the Views enable page.
*/
function views_ui_enable_page($view) {
if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-enable')) {
$views_status = variable_get('views_defaults', array());
$views_status[$view->name] = FALSE; // false is enabled
variable_set('views_defaults', $views_status);
views_invalidate_cache();
menu_rebuild();
drupal_goto('admin/build/views');
}
else {
return drupal_access_denied();
}
}
/**
* Page callback for the Views enable page
*/
function views_ui_disable_page($view) {
if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-disable')) {
$views_status = variable_get('views_defaults', array());
$views_status[$view->name] = TRUE; // True is disabled
variable_set('views_defaults', $views_status);
views_invalidate_cache();
menu_rebuild();
drupal_goto('admin/build/views');
}
else {
return drupal_access_denied();
}
}
/**
* Page callback for the tools - other page
*/
function views_ui_admin_tools() {
$form['clear_cache'] = array(
'#type' => 'submit',
'#value' => t("Clear Views' cache"),
'#submit' => array('views_ui_tools_clear_cache'),
);
$form['views_sql_signature'] = array(
'#type' => 'checkbox',
'#title' => t('Add Views signature to all SQL queries'),
'#description' => t("All Views-generated queries will include a special 'VIEWS' = 'VIEWS' string in the WHERE clause. This makes identifying Views queries in database server logs simpler, but should only be used when troubleshooting."),
'#default_value' => variable_get('views_sql_signature', FALSE),
);
$form['views_skip_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Disable views data caching'),
'#description' => t("Views caches data about tables, modules and views available, to increase performance. By checking this box, Views will skip this cache and always rebuild this data when needed. This can have a serious performance impact on your site."),
'#default_value' => variable_get('views_skip_cache', FALSE),
);
$form['views_hide_help_message'] = array(
'#type' => 'checkbox',
'#title' => t('Ignore missing advanced help module'),
'#description' => t("Views uses the advanced help module to provide help text; if this module is not present Views will complain, unless this setting is checked."),
'#default_value' => variable_get('views_hide_help_message', FALSE),
);
$form['views_ui_query_on_top'] = array(
'#type' => 'checkbox',
'#title' => t('Show query above live preview'),
'#description' => t("The live preview feature will show you the output of the view you're creating, as well as the view. Check here to show the query and other information above the view; leave this unchecked to show that information below the view."),
'#default_value' => variable_get('views_ui_query_on_top', FALSE),
);
$form['views_ui_disable_live_preview'] = array(
'#type' => 'checkbox',
'#title' => t('Disable automatic live preview'),
'#description' => t("Don't automatically update the preview. This can speed up the editing of views a bit.'"),
'#default_value' => variable_get('views_ui_disable_live_preview', 0),
);
$form['views_show_additional_queries'] = array(
'#type' => 'checkbox',
'#title' => t('Show other queries run during render during live preview'),
'#description' => t("Drupal has the potential to run many queries while a view is being rendered. Checking this box will display every query run during view render as part of the live preview."),
'#default_value' => variable_get('views_show_additional_queries', FALSE),
);
$form['views_no_hover_links'] = array(
'#type' => 'checkbox',
'#title' => t('Do not show hover links over views'),
'#description' => t("To make it easier to administrate your views, Views provides 'hover' links to take you to the edit and export screen of a view whenever the view is used. This can be distracting on some themes, though; if it is problematic, you can turn it off here."),
'#default_value' => variable_get('views_no_hover_links', FALSE),
);
$form['views_devel_output'] = array(
'#type' => 'checkbox',
'#title' => t('Enable views performance statistics via the Devel module'),
'#description' => t("Check this to enable some Views query and performance statistics if Devel is installed."),
'#default_value' => variable_get('views_devel_output', FALSE),
);
$form['views_no_javascript'] = array(
'#type' => 'checkbox',
'#title' => t('Disable javascript with Views'),
'#description' => t("If you are having problems with the javascript, you can disable it here; the Views UI should degrade and still be usable without javascript, it just not as good."),
'#default_value' => variable_get('views_no_javascript', FALSE),
);
$regions = system_region_list(variable_get('theme_default', 'garland'));
$regions['watchdog'] = t('Watchdog');
$form['views_devel_region'] = array(
'#type' => 'select',
'#title' => t('Page region to output performance statistics'),
'#default_value' => variable_get('views_devel_region', 'footer'),
'#options' => $regions,
);
$form['views_exposed_filter_any_label'] = array(
'#type' => 'select',
'#title' => t('Label for "Any" value on optional single-select exposed filters'),
'#options' => array('old_any' => '', 'new_any' => t('- Any -')),
'#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'),
);
return system_settings_form($form);
}
/**
* Submit hook to clear the views cache.
*/
function views_ui_tools_clear_cache() {
views_invalidate_cache();
drupal_set_message(t('The cache has been cleared.'));
}
/**
* Submit hook to clear Drupal's theme registry (thereby triggering
* a templates rescan).
*/
function views_ui_config_item_form_rescan($form, &$form_state) {
drupal_rebuild_theme_registry();
// The 'Theme: Information' page is about to be shown again. That page
// analyzes the output of theme_get_registry(). However, this latter
// function uses an internal cache (which was initialized before we
// called drupal_rebuild_theme_registry()) so it won't reflect the
// current state of our theme registry. The only way to clear that cache
// is to re-initialize the theme system:
unset($GLOBALS['theme']);
init_theme();
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
}
/**
* Override handler for views_ui_edit_display_form
*/
function views_ui_edit_display_form_change_theme($form, &$form_state) {
// This is just a temporary variable.
$form_state['view']->theme = $form_state['values']['theme'];
views_ui_cache_set($form_state['view']);
$form_state['rerender'] = TRUE;
$form_state['rebuild'] = TRUE;
}
/**
* Page callback for views tag autocomplete
*/
function views_ui_autocomplete_tag($string = '') {
$matches = array();
// get matches from default views:
views_include('view');
$views = views_discover_default_views();
foreach ($views as $view) {
if (!empty($view->tag) && strpos($view->tag, $string) === 0) {
$matches[$view->tag] = $view->tag;
}
}
if ($string) {
$result = db_query_range("SELECT DISTINCT tag FROM {views_view} WHERE LOWER(tag) LIKE LOWER('%s%%')", $string, 0, 10 - count($matches));
while ($view = db_fetch_object($result)) {
$matches[$view->tag] = check_plain($view->tag);
}
}
drupal_json($matches);
}
// ------------------------------------------------------------------
// Get information from the Views data
function _views_weight_sort($a, $b) {
if ($a['weight'] != $b['weight']) {
return $a['weight'] < $b['weight'] ? -1 : 1;
}
if ($a['title'] != $b['title']) {
return $a['title'] < $b['title'] ? -1 : 1;
}
return 0;
}
/**
* Fetch a list of all base tables available
*
* @return
* A keyed array of in the form of 'base_table' => 'Description'.
*/
function views_fetch_base_tables() {
static $base_tables = array();
if (empty($base_tables)) {
$weights = array();
$tables = array();
$data = views_fetch_data();
foreach ($data as $table => $info) {
if (!empty($info['table']['base'])) {
$tables[$table] = array(
'title' => $info['table']['base']['title'],
'description' => $info['table']['base']['help'],
'weight' => !empty($info['table']['base']['weight']) ? $info['table']['base']['weight'] : 0,
);
}
}
uasort($tables, '_views_weight_sort');
$base_tables = $tables;
}
return $base_tables;
}
function _views_sort_types($a, $b) {
if ($a['group'] != $b['group']) {
return $a['group'] < $b['group'] ? -1 : 1;
}
if ($a['title'] != $b['title']) {
return $a['title'] < $b['title'] ? -1 : 1;
}
return 0;
}
/**
* Fetch a list of all fields available for a given base type.
*
* @return
* A keyed array of in the form of 'base_table' => 'Description'.
*/
function views_fetch_fields($base, $type) {
static $fields = array();
if (empty($fields)) {
$data = views_fetch_data();
$start = views_microtime();
// This constructs this ginormous multi dimensional array to
// collect the important data about fields. In the end,
// the structure looks a bit like this (using nid as an example)
// $strings['nid']['filter']['title'] = 'string'.
//
// This is constructed this way because the above referenced strings
// can appear in different places in the actual data structure so that
// the data doesn't have to be repeated a lot. This essentially lets
// each field have a cheap kind of inheritance.
foreach ($data as $table => $table_data) {
$bases = array();
$strings = array();
$skip_bases = array();
foreach ($table_data as $field => $info) {
// Collect table data from this table
if ($field == 'table') {
// calculate what tables this table can join to.
if (!empty($info['join'])) {
$bases = array_keys($info['join']);
}
// And it obviously joins to itself.
$bases[] = $table;
continue;
}
foreach (array('field', 'sort', 'filter', 'argument', 'relationship') as $key) {
if (!empty($info[$key])) {
if (!empty($info[$key]['skip base'])) {
foreach ((array) $info[$key]['skip base'] as $base_name) {
$skip_bases[$field][$key][$base_name] = TRUE;
}
}
elseif (!empty($info['skip base'])) {
foreach ((array) $info['skip base'] as $base_name) {
$skip_bases[$field][$key][$base_name] = TRUE;
}
}
foreach (array('title', 'group', 'help', 'base') as $string) {
// First, try the lowest possible level
if (!empty($info[$key][$string])) {
$strings[$field][$key][$string] = $info[$key][$string];
}
// Then try the field level
elseif (!empty($info[$string])) {
$strings[$field][$key][$string] = $info[$string];
}
// Finally, try the table level
elseif (!empty($table_data['table'][$string])) {
$strings[$field][$key][$string] = $table_data['table'][$string];
}
else {
if ($string != 'base') {
$strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string));
}
}
}
}
}
}
foreach ($bases as $base_name) {
foreach ($strings as $field => $field_strings) {
foreach ($field_strings as $type_name => $type_strings) {
if (empty($skip_bases[$field][$type_name][$base_name])) {
$fields[$base_name][$type_name]["$table.$field"] = $type_strings;
}
}
}
}
}
// vsm('Views UI data build time: ' . (views_microtime() - $start) * 1000 . ' ms');
}
// If we have an array of base tables available, go through them
// all and add them together. Duplicate keys will be lost and that's
// Just Fine.
if (is_array($base)) {
$strings = array();
foreach ($base as $base_table) {
if (isset($fields[$base_table][$type])) {
$strings += $fields[$base_table][$type];
}
}
uasort($strings, '_views_sort_types');
return $strings;
}
if (isset($fields[$base][$type])) {
uasort($fields[$base][$type], '_views_sort_types');
return $fields[$base][$type];
}
return array();
}
/**
* Fetch a list of all base tables available
*
* @param $type
* Either 'display', 'style' or 'row'
* @param $key
* For style plugins, this is an optional type to restrict to. May be 'normal',
* 'summary', 'feed' or others based on the neds of the display.
* @param $base
* An array of possible base tables.
*
* @return
* A keyed array of in the form of 'base_table' => 'Description'.
*/
function views_fetch_plugin_names($type, $key = NULL, $base = array()) {
$data = views_fetch_plugin_data();
$plugins[$type] = array();
foreach ($data[$type] as $id => $plugin) {
// Skip plugins that don't conform to our key.
if ($key && (empty($plugin['type']) || $plugin['type'] != $key)) {
continue;
}
if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) {
$plugins[$type][$id] = $plugin['title'];
}
}
if (!empty($plugins[$type])) {
asort($plugins[$type]);
return $plugins[$type];
}
// fall-through
return array();
}
/**
* Theme the form for the table style plugin
*/
function theme_views_ui_style_plugin_table($form) {
$output = drupal_render($form['description_markup']);
$header = array(
t('Field'),
t('Column'),
t('Separator'),
array(
'data' => t('Sortable'),
'align' => 'center',
),
array(
'data' => t('Default sort'),
'align' => 'center',
),
);
$rows = array();
foreach (element_children($form['columns']) as $id) {
$row = array();
$row[] = drupal_render($form['info'][$id]['name']);
$row[] = drupal_render($form['columns'][$id]);
$row[] = drupal_render($form['info'][$id]['separator']);
if (!empty($form['info'][$id]['sortable'])) {
$row[] = array(
'data' => drupal_render($form['info'][$id]['sortable']),
'align' => 'center',
);
$row[] = array(
'data' => drupal_render($form['default'][$id]),
'align' => 'center',
);
}
else {
$row[] = '';
$row[] = '';
}
$rows[] = $row;
}
// Add the special 'None' row.
$rows[] = array(t('None'), '', '', '', array('align' => 'center', 'data' => drupal_render($form['default'][-1])));
$output .= theme('table', $header, $rows);
$output .= drupal_render($form);
return $output;
}