Hide this message.', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/build/views/tools')))); } } /** * Preprocess the list views theme */ function template_preprocess_views_ui_list_views(&$vars) { $items = array(); $sorts = array(); $views = views_get_all_views(); $form_state = array( 'views' => $views, 'input' => $_GET, 'method' => 'get', 'rerender' => TRUE, 'no_redirect' => TRUE, ); $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state); $vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type'); $base_tables = views_fetch_base_tables(); foreach ($views as $view) { if ($form_state['values']['tag'] != 'all') { if ($form_state['values']['tag'] == 'none') { if (!empty($view->tag)) { continue; } } else if ($form_state['values']['tag'] != $view->tag) { continue; } } if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) { continue; } if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) { continue; } if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) { continue; } $item = new stdClass(); $item->ops = array(); if (empty($view->disabled)) { $item->ops[] = l(t('Edit'), "admin/build/views/edit/$view->name"); $item->ops[] = l(t('Export'), "admin/build/views/export/$view->name"); $item->ops[] = l(t('Clone'), "admin/build/views/clone/$view->name"); } if ($view->type != t('Default')) { $text = $view->type == t('Overridden') ? t('Revert') : t('Delete'); $item->ops[] = l($text, "admin/build/views/delete/$view->name"); } else { if (empty($view->disabled)) { $item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination())); } else { $item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination())); } } $item->ops = implode(' | ', $item->ops); if (empty($view->display)) { $item->path = t('Warning! Broken view!'); } else { $item->path = $raw_path = $view->get_path(); $item->path = $item->path && empty($view->disabled) && strpos($item->path, '%') === FALSE ? l($item->path, $item->path) : check_plain($item->path); } $item->type = $view->type; $item->name = $view->name; if (!empty($view->tag)) { $item->tag = $view->tag; } $item->title = $view->get_title(); $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken'); $item->displays = array(); foreach ($view->display as $display) { if (!empty($display->handler->definition['admin'])) { $item->displays[$display->handler->definition['admin']] = TRUE; } } if ($item->displays) { ksort($item->displays); $item->displays = implode(', ', array_keys($item->displays)); } $item->description = check_plain($view->description); $items[] = $item; switch ($form_state['values']['order']) { case 'name': default: $sorts[] = strtolower($view->name); break; case 'title': $sorts[] = strtolower($title); break; case 'path': $sorts[] = strtolower($raw_path); // $path; break; case 'type': $sorts[] = $view->type . $view->name; break; case 'tag': $sorts[] = strtolower($view->tag); break; case 'desc': $sorts[] = strtolower($view->description); break; } } if ($form_state['values']['sort'] == 'desc') { arsort($sorts); } else { asort($sorts); } $i = array(); foreach ($sorts as $id => $title) { $i[] = $items[$id]; } views_add_css('views-list'); $vars['views'] = $i; } /** * Provide a form for sorting and filtering the list of views. */ function views_ui_list_views_form(&$form_state) { if (!variable_get('clean_url', FALSE)) { $form['q'] = array( '#type' => 'hidden', '#value' => $_GET['q'], ); } $all = array('all' => t('')); $none = array('none' => t('')); $tags = array(); $extras = array(); foreach ($form_state['views'] as $name => $view) { if (!empty($view->tag)) { $tags[$view->tag] = $view->tag; } } asort($tags); $form['tag'] = array( '#type' => 'select', '#title' => t('Tag'), '#options' => array_merge($all, $none, $tags), '#default_value' => 'all', ); $displays = array(); foreach (views_fetch_plugin_data('display') as $id => $info) { if (!empty($info['admin'])) { $displays[$id] = $info['admin']; } } asort($displays); $form['display'] = array( '#type' => 'select', '#title' => t('Displays'), '#options' => array_merge($all, $displays), '#default_value' => 'all', ); $bases = array(); foreach (views_fetch_base_tables() as $table => $info) { $bases[$table] = $info['title']; } $form['base'] = array( '#type' => 'select', '#title' => t('Type'), '#options' => array_merge($all, $bases), '#default_value' => 'all', ); $form['type'] = array( '#type' => 'select', '#title' => t('Storage'), '#options' => array( 'all' => t(''), t('Normal') => t('Normal'), t('Default') => t('Default'), t('Overridden') => t('Overridden'), ), '#default_value' => 'all', ); $form['order'] = array( '#type' => 'select', '#title' => t('Sort by'), '#options' => array( 'name' => t('Name'), 'title' => t('Title'), 'tag' => t('Tag'), 'path' => t('Path'), 'type' => t('Type'), 'desc' => t('Description'), ), '#default_value' => 'name', ); $form['sort'] = array( '#type' => 'select', '#title' => t('Order'), '#options' => array( 'asc' => t('Up'), 'desc' => t('Down'), ), '#default_value' => 'asc', ); $form['submit'] = array( '#name' => '', // so it won't in the $_GET args '#type' => 'submit', '#value' => t('Apply'), ); $form['#theme'] = array('views_ui_list_views_form'); return $form; } function theme_views_ui_list_views_form($form) { // Don't render these: unset($form['form_id']); unset($form['form_build_id']); unset($form['form_token']); return drupal_render($form); } /** * Page callback for the live preview. * * @todo make this use a template */ function views_ui_preview($js, $view) { // Take off the items we know so that we can have just the args passed // in for later use. $func_args = func_get_args(); array_shift($func_args); // $js array_shift($func_args); // $view $display_id = (count($func_args)) ? array_shift($func_args) : 'default'; $form_state = array( 'display_id' => $display_id, 'view_args' => $func_args ? implode('/', $func_args) : '', 'rerender' => TRUE, 'no_redirect' => TRUE, 'view' => &$view, 'ajax' => $js ); $output = drupal_build_form('views_ui_preview_form', $form_state); $args = array(); if (!empty($form_state['view_args'])) { $args = explode('/', $form_state['view_args']); } $errors = $view->validate(); if ($errors === TRUE) { $view->ajax = $js; // Store the current view URL for later use: $view->set_display($form_state['display_id']); $view->set_arguments($args); if ($view->display_handler->get_option('path')) { $path = $view->get_url(); } // Make view links come back to preview. $view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id']; // also override $_GET['q'] so we get the pager $_GET['q'] = $view->override_path; if ($form_state['view_args']) { $_GET['q'] .= '/' . $form_state['view_args']; } $preview = $view->preview($form_state['display_id'], $args); // Get information from the preview for display. if (!empty($view->build_info['query'])) { $rows = array(); $query = db_prefix_tables($view->build_info['query']); if ($view->build_info['query_args']) { _db_query_callback($view->build_info['query_args'], TRUE); $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); } $rows[] = array('' . t('Query') . '', '
' . check_plain($query) . '
'); $rows[] = array('' . t('Title') . '', filter_xss_admin($view->get_title())); if (isset($path)) { $path = l($path, $path); } else { $path = t('This display has no path.'); } $rows[] = array('' . t('Path') . '', $path); $info = theme('table', array(), $rows); } else { $info = theme('table', array(), array(array('' . t('Query') . '', t('No query was run')))); } } else { foreach ($errors as $error) { drupal_set_message($error, 'error'); } $preview = t('Unable to preview due to validation errors.'); $info = ''; } $output .= '
'; $output .= $info; $output .= '
'; $output .= $preview; if (!$js) { views_add_css('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['#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 : '', ); $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 cannot be changed.'), '#default_value' => $view ? $view->base_table : 'node', '#options' => $base_tables, ); if ($view) { $form['base_table']['#disabled'] = TRUE; } $form['submit'] = array( '#type' => 'submit', '#value' => t('Next'), '#validate' => array('views_ui_add_form_validate'), '#submit' => array('views_ui_add_form_submit'), ); return $form; } /** * Validate the add view form. */ function views_ui_add_form_validate($form, &$form_state) { $name = $form_state['values']['name']; // View name must be alphanumeric or underscores, no other punctuation. if (preg_match('/[^a-zA-Z0-9_]/', $name)) { form_error($form['name'], t('View name must be alphanumeric or underscores only.')); } // View name must already exist. $view = views_get_view($form_state['values']['name']); if ($view && $view->type != t('Default')) { form_error($form['name'], t('You must use a unique name for this view.')); } } /** * Process the add view form */ function views_ui_add_form_submit($form, &$form_state) { $view = $form_state['view'] ? $form_state['view'] : views_new_view(); $view->name = $form_state['values']['name']; $view->description = $form_state['values']['description']; $view->tag = $form_state['values']['tag']; if (empty($form['base_table']['#disabled'])) { $view->base_table = $form_state['values']['base_table']; } views_ui_cache_set($view); $form_state['redirect'] ='admin/build/views/edit/' . $view->name; } /** * Page to delete a view. */ function views_ui_delete_confirm(&$form_state, $view) { $form_state['view'] = &$view; $form = array(); $cancel = 'admin/build/views'; if (!empty($_REQUEST['cancel'])) { $cancel = $_REQUEST['cancel']; } return confirm_form($form, t('Are you sure you want to delete the view %name?', array('%name' => $view->name)), $cancel, t('Deleting a view cannot be undone.'), t('Delete'), t('Cancel')); } /** * Submit handler to delete a view. */ function views_ui_delete_confirm_submit(&$form, &$form_state) { $form_state['view']->delete(); views_object_cache_clear('view', $form_state['view']->name); drupal_set_message(t('The view has been deleted.')); $form_state['redirect'] = 'admin/build/views'; } /** * Page to delete a view. */ function views_ui_break_lock_confirm(&$form_state, $view) { $form_state['view'] = &$view; $form = array(); if (empty($view->locked)) { return t('There is no lock on view %view to break.', array('%name' => $view->name)); } $cancel = 'admin/build/views/edit/' . $view->name; if (!empty($_REQUEST['cancel'])) { $cancel = $_REQUEST['cancel']; } $account = user_load($view->locked->uid); return confirm_form($form, t('Are you sure you want to break the lock on view %name?', array('%name' => $view->name)), $cancel, t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))), t('Break lock'), t('Cancel')); } /** * Submit handler to break_lock a view. */ function views_ui_break_lock_confirm_submit(&$form, &$form_state) { db_query("DELETE FROM {views_object_cache} WHERE obj = 'view' AND name = '%s'", $form_state['view']->name); $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; drupal_set_message('The lock has been broken and you may now edit this view.'); } /** * The main view edit page */ function views_ui_edit_page($view) { drupal_set_title(t('Edit view "%view"', array('%view' => $view->name))); views_ui_check_advanced_help(); return theme('views_ui_edit_view', $view); } /** * Export a view for cut & paste. */ function views_ui_export_page(&$form_state, $view) { $code = $view->export(); $lines = substr_count($code, "\n"); $form['code'] = array( '#type' => 'textarea', '#title' => $view->name, '#default_value' => $code, '#rows' => $lines); return $form; } /** * Import a view from cut & paste */ function views_ui_import_page(&$form_state) { $form['name'] = array( '#type' => 'textfield', '#title' => t('View name'), '#description' => t('Enter the name to use for this view if it is different from the source view. Leave blank to use the name of the view.'), ); $form['view'] = array( '#type' => 'textarea', '#title' => t('Paste view code here'), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Import'), '#submit' => array('views_ui_import_submit'), '#validate' => array('views_ui_import_validate'), ); return $form; } /** * Validate handler to import a view */ function views_ui_import_validate($form, &$form_state) { views_include('view'); ob_start(); eval($form_state['values']['view']); ob_end_clean(); if (!is_object($view)) { form_error($form['view'], t('Unable to interpret view code.')); } if (empty($view->api_version) || $view->api_version < 2) { // Check for some value that would only exist on a Views 1 view. if (isset($view->url) || isset($view->page) || isset($view->block)) { views_include('convert'); $view = views1_import($view); drupal_set_message(t('You are importing a view created in Views version 1. You may need to adjust some parameters to work correctly in version 2.'), 'warning'); } else { form_error($form['view'], t('That view is not compatible with this version of Views.')); } } if ($form_state['values']['name']) { $view->name = $form_state['values']['name']; } $test = views_get_view($view->name); if ($test && $test->type != t('Default')) { form_set_error('', t('A view by that name already exists; please choose a different name')); } $form_state['view'] = &$view; } /** * Submit handler for view import */ function views_ui_import_submit($form, &$form_state) { // Store in cache and then go to edit. views_ui_cache_set($form_state['view']); $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * The main edit view form, which is really just a save/cancel/delete button. */ function views_ui_edit_view_form(&$form_state, $view) { $form['buttons']['save'] = array( '#type' => 'submit', '#value' => t('Save'), '#validate' => array('views_ui_edit_view_form_validate'), '#submit' => array('views_ui_edit_view_form_submit'), ); $form['buttons']['cancel'] = array( '#type' => 'submit', '#value' => t('Cancel'), '#submit' => array('views_ui_edit_view_form_cancel'), ); if (is_numeric($view->vid)) { $form['buttons']['delete'] = array( '#type' => 'submit', '#value' => t('Delete'), '#submit' => array('views_ui_edit_view_form_delete'), ); } $form_state['view'] = &$view; return $form; } /** * Validate that a view is complete and whole. */ function views_ui_edit_view_form_validate($form, $form_state) { $errors = $form_state['view']->validate(); if ($errors !== TRUE) { foreach ($errors as $error) { form_set_error('', $error); } } } /** * Submit handler for the edit view form. */ function views_ui_edit_view_form_submit($form, &$form_state) { // Go through and remove displayed scheduled for removal. foreach ($form_state['view']->display as $id => $display) { if (!empty($display->deleted)) { unset($form_state['view']->display[$id]); } } $form_state['view']->save(); drupal_set_message(t('The view has been saved.')); // Make sure menu items get rebuilt as neces menu_rebuild(); // Clear the views cache. cache_clear_all('*', 'cache_views'); // Clear the page cache. cache_clear_all(); // Remove this view from cache so we can edit it properly. views_object_cache_clear('view', $form_state['view']->name); } /** * Submit handler for the edit view form. */ function views_ui_edit_view_form_cancel($form, &$form_state) { // Remove this view from cache so edits will be lost. views_object_cache_clear('view', $form_state['view']->name); } function views_ui_edit_view_form_delete($form, &$form_state) { // Remove this view from cache so edits will be lost. $form_state['redirect'] = array('admin/build/views/delete/' . $form_state['view']->name, 'cancel=admin/build/views/edit/' . $form_state['view']->name); } /** * Preprocess the view edit page. */ function template_preprocess_views_ui_edit_view(&$vars) { $view = &$vars['view']; $vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view); $table = views_fetch_data($view->base_table); $vars['base_table'] = !empty($table['table']['base']['title']) ? $table['table']['base']['title'] : t('Unknown or missing table name'); views_include('tabs'); $tabs = new views_tabset; $vars['message'] = '
' . 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'] = l(t('break this lock'), '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 ($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('admin'); views_add_css('views'); 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('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'] = ''; // 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->display_options['defaults'][$id])) { $display_id = 'default'; } else { $display_id = $display->id; if ($display->handler->defaultable_sections($id) && !$display->handler->is_default_display()) { $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'] = ''; if ($style_plugin && $style_plugin->uses_fields()) { $vars['fields'] = theme('views_ui_edit_item', 'field', $view, $display); } $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) { $plugin = $display->handler->definition; if (empty($plugin)) { return array(t('Invalid'), t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin))); } // 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['rearrange'] = l('' . t('Rearrange') . '', "admin/build/views/nojs/rearrange/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-rearrange views-ajax-link', 'title' => t('Rearrange')), 'html' => true)); $vars['add'] = l('' . t('Add') . '', "admin/build/views/nojs/add-item/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-button-add views-ajax-link', 'title' => t('Add')), 'html' => true)); $vars['overridden'] = (!$display->handler->is_default_display() && empty($display->display_options['defaults'][$types[$type]['plural']])); $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link'))); // $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link'))); $fields = array(); static $relationships = NULL; if (!isset($relationships)) { // Get relationship labels $relationships = array(); foreach ($display->handler->get_option('relationships') as $id => $relationship) { $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); if (empty($handler)) { continue; } $handler->init($view, $relationship); $relationships[$id] = $handler->label(); } } foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) { $fields[$id] = array(); $handler = views_get_handler($field['table'], $field['field'], $type); if (empty($handler)) { $fields[$id]['class'] = 'broken'; $fields[$id]['title'] = t("Error: handler for @table > @field doesn't exist!", array('@table' => $field['table'], '@field' => $field['field'])); $fields[$id]['info'] = ''; continue; } $handler->init($view, $field); $field_name = $handler->ui_name(); if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) { $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name; } $fields[$id]['title'] = l($field_name, "admin/build/views/nojs/config-item/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link'))); $fields[$id]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $id); if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $id])) { $fields[$id]['changed'] = TRUE; } $fields[$id]['info'] = $handler->admin_summary(); if ($handler->has_extra_options()) { $fields[$id]['links'] = l('' . t('Settings') . '', "admin/build/views/nojs/config-item-extra/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true)); } if ($handler->needs_style_plugin()) { $style_plugin = views_fetch_plugin_data('style', $handler->options['style_plugin']); $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title']; $pid = $id . '-style-plugin'; if (!empty($style_plugin['uses options'])) { $fields[$pid]['links'] = l('' . t('Change settings for this style') . '', "admin/build/views/nojs/config-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link', 'title' => t('Settings')), 'html' => true)); } $fields[$pid]['title'] = t('   Style: !style', array('!style' => l($style_title, "admin/build/views/nojs/change-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-ajax-link'))))); $fields[$pid]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $pid); if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $pid])) { $fields[$pid]['changed'] = TRUE; } $fields[$pid]['info'] = ''; } } $vars['fields'] = $fields; $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type); } /** * Regenerate the tabs for AJAX updates. */ function views_ui_regenerate_tabs(&$view, $display_id = NULL, $object = NULL) { if (empty($display_id)) { $displays = array_keys($view->display); } elseif (!is_array($display_id)) { $displays = array($display_id); if ($display_id != 'default') { $displays[] = 'default'; } } else { $displays = $display_id; } if (!$view->set_display('default')) { views_ajax_render(t('Invalid display id while regenerating tabs')); } if (!is_object($object)) { $object = new stdClass(); } $object->replace = array(); foreach ($displays as $id) { list($title, $body) = views_ui_display_tab($view, $view->display[$id]); $object->replace['#views-tab-' . $id] = $body; $object->replace['#views-tab-title-' . $id] = $title; } if (!empty($view->changed)) { $object->changed = TRUE; } views_ajax_render($object); } /** * Provide standard buttons for the forms to make it easy. Also provide * a hidden op operator because the forms plugin doesn't seem to properly * provide which button was clicked. */ function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) { $form['buttons'] = array( '#prefix' => '
', '#suffix' => '
', ); if (empty($name)) { $name = t('Update'); } // remove default validate handler $form['#validate'] = array(); if (empty($form_state['ok_button'])) { // but be sure submit button validates! $form['buttons']['submit'] = array( '#type' => 'submit', '#value' => $name, '#submit' => array($form_id . '_submit'), '#validate' => array('views_ui_standard_submit', $form_id . '_validate'), ); } $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel'; $form['buttons']['cancel'] = array( '#type' => 'submit', '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'), '#submit' => array($cancel_submit), '#validate' => array(), ); if ($third) { if (empty($submit)) { $submit = 'third'; } $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel'; $form['buttons'][$submit] = array( '#type' => 'submit', '#value' => $third, '#validate' => array(), '#submit' => array($third_submit), ); } // Compatibility, to be removed later: // We used to set these items on the form, but now we want them on the $form_state: if (isset($form['#title'])) { $form_state['title'] = $form['#title']; } if (isset($form['#url'])) { $form_state['url'] = $form['#url']; } if (isset($form['#js'])) { if (!empty($form_state['js settings']) && is_array($form_state['js settings'])) { $form_state['js settings'] = array_merge($form_state['js settings'], $form['#js']); } else { $form_state['js settings'] = $form['#js']; } } if (isset($form['#section'])) { $form_state['#section'] = $form['#section']; } // Finally, we never want these cached -- our object cache does that for us. $form['#no_cache'] = TRUE; // If this isn't an ajaxy form, then we want to set the title. drupal_set_title($form['#title']); views_add_css('admin'); } /** * Basic submit handler applicable to all 'standard' forms */ function views_ui_standard_submit($form, &$form_state) { if (!empty($form['#section'])) { $form_state['view']->changed_sections[$form['#section']] = TRUE; } } /** * Submit handler for cancel button */ function views_ui_standard_cancel($form, &$form_state) { $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } // -------------------------------------------------------------------------- // Various subforms for editing the pieces of a view. function views_ui_ajax_forms($key = NULL) { $forms = array( 'display' => array( 'form_id' => 'views_ui_edit_display_form', 'args' => array('section'), ), 'remove-display' => array( 'form_id' => 'views_ui_remove_display_form', 'args' => array(), ), 'config-type' => array( 'form_id' => 'views_ui_config_type_form', 'args' => array('type'), ), 'rearrange' => array( 'form_id' => 'views_ui_rearrange_form', 'args' => array('type'), ), 'add-item' => array( 'form_id' => 'views_ui_add_item_form', 'args' => array('type'), ), 'config-item' => array( 'form_id' => 'views_ui_config_item_form', 'args' => array('type', 'id'), ), 'config-item-extra' => array( 'form_id' => 'views_ui_config_item_extra_form', 'args' => array('type', 'id'), ), 'change-style' => array( 'form_id' => 'views_ui_change_style_form', 'args' => array('type', 'id'), ), 'config-style' => array( 'form_id' => 'views_ui_config_style_form', 'args' => array('type', 'id'), ), ); if ($key) { return !empty($forms[$key]) ? $forms[$key] : NULL; } return $forms; } /** * Build a form identifier that we can use to see if one form * is the same as another. Since the arguments differ slightly * we do a lot of spiffy concenation here. */ function views_ui_build_identifier($key, $view, $display_id, $args) { $form = views_ui_ajax_forms($key); $identifier = implode('-', array($key, $view->name, $display_id)); foreach ($form['args'] as $id) { $arg = (!empty($args)) ? array_shift($args) : NULL; $identifier .= '-' . $arg; } return $identifier; } /** * Build up a $form_state object suitable for use with drupal_build_form * based on known information about a form. */ function views_ui_build_form_state($js, $key, &$view, $display_id, $args) { $form = views_ui_ajax_forms($key); // Build up form state $form_state = array( 'form_key' => $key, 'form_id' => $form['form_id'], 'view' => &$view, 'ajax' => $js, 'display_id' => $display_id, 'no_redirect' => TRUE, ); foreach ($form['args'] as $id) { $form_state[$id] = (!empty($args)) ? array_shift($args) : NULL; } return $form_state; } /** * Create the URL for one of our standard AJAX forms based upon known * information about the form. */ function views_ui_build_form_url($form_state) { $form = views_ui_ajax_forms($form_state['form_key']); $ajax = empty($form_state['ajax']) ? 'nojs' : 'ajax'; $name = $form_state['view']->name; $url = "admin/build/views/$ajax/$form_state[form_key]/$name/$form_state[display_id]"; foreach ($form['args'] as $arg) { $url .= '/' . $form_state[$arg]; } return $url; } /** * Add another form to the stack; clicking 'update' will go to this form * rather than closing the ajax pad. */ function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) { if (empty($view->stack)) { $view->stack = array(); } $stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, $view, $display_id, $args); if ($top) { array_unshift($view->stack, $stack); } else { $view->stack[] = $stack; } } /** * Generic entry point to handle forms. * * We do this for consistency and to make it easy to chain forms * together. This only works for forms that use both $view * and $display_id, so we have a couple of ajax forms that we don't * use with this system. */ function views_ui_ajax_form($js, $key, &$view, $display_id) { $form = views_ui_ajax_forms($key); if (empty($form)) { return drupal_not_found(); } views_include('ajax'); $args = func_get_args(); // Remove the known args array_splice($args, 0, 4); $form_state = views_ui_build_form_state($js, $key, $view, $display_id, $args); // check to see if this is the top form of the stack. If it is, pop // it off; if it isn't, the user clicked somewhere else and the stack is // now irrelevant. if (!empty($view->stack)) { $identifier = views_ui_build_identifier($key, $view, $display_id, $args); $top = array_shift($view->stack); if (array_shift($top) != $identifier) { $view->stack = array(); } } $output = views_ajax_form_wrapper($form_state['form_id'], $form_state); if (!$output) { // Sometimes we need to re-generate the form for multi-step type operations. $object = NULL; if (!empty($view->stack)) { $stack = $view->stack; // copy so the next shift doesn't break the array $top = array_shift($stack); $top[0] = $js; // change identifier into $js setting $form_state = call_user_func_array('views_ui_build_form_state', $top); $form_state['input'] = array(); // this is a new form, make sure it // doesn't try to inherit $_POST info. if (!$js) { return drupal_goto(views_ui_build_form_url($form_state)); } $object = views_ajax_form_wrapper($form_state['form_id'], $form_state); $object->url = url(views_ui_build_form_url($form_state)); } else if (!$js) { // if nothing on the stack, non-js forms just go back to the main view editor. return drupal_goto("admin/build/views/edit/$view->name"); } // regenerate all tabs because changes to the default tab could ripple. return views_ui_regenerate_tabs($view, NULL, $object); } return ($js) ? views_ajax_render($output) : $output; } /** * AJAX callback to add a display. */ function views_ui_add_display($js, $view) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { $id = $form_state['id']; // Make sure the new display is active if (!$view->set_display('default')) { views_ajax_render(t('Unable to initialize default display')); } // Render the new display list($title, $body) = views_ui_display_tab($view, $view->display[$id]); // Instruct the javascript on the browser to render the new tab. $output = new stdClass; $output->tab = array('#views-tab-' . $id => array('title' => $title, 'body' => $body)); } // Render the command object. This automatically exits. views_ajax_render($output); } // But the non-js variant will return output if it didn't redirect us. return $output; } /** * Form to add a display to a view. */ function views_ui_add_display_form(&$form_state) { $view = &$form_state['view']; $form['display']['display'] = array( '#type' => 'select', '#options' => views_fetch_plugin_names('display'), '#default_value' => 'page', ); $form['display']['add_display'] = array( '#type' => 'submit', '#value' => t('Add display'), '#submit' => array('views_ui_add_display_form_submit'), ); $form['#id'] = 'views-add-display-form'; $form['#attributes'] = array('class' => 'views-ajax-form'); $form['#action'] = url("admin/build/views/nojs/add-display/$view->name"); return $form; } /** * Submit handler to add a display to a view. */ function views_ui_add_display_form_submit($form, &$form_state) { // Create the new display $plugin = $form_state['values']['display']; $form_state['id'] = $form_state['view']->add_display($plugin); // Store in cache views_ui_cache_set($form_state['view']); // Send it back $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['id']); } /** * Form to remove a display from a view. */ function views_ui_remove_display_form(&$form_state) { $view = &$form_state['view']; $display_id = $form_state['display_id']; if (empty($view->display[$display_id]->deleted)) { $form['display'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['remove_display'] = array( '#type' => 'submit', '#value' => t('Remove display'), '#submit' => array('views_ui_remove_display_form_submit'), ); } else { $form['display'] = array( '#prefix' => '
', '#suffix' => '
', ); $form['restore_display'] = array( '#type' => 'submit', '#value' => t('Restore display'), '#submit' => array('views_ui_remove_display_form_restore'), ); } $form['#action'] = url("admin/build/views/nojs/remove-display/$view->name/$display_id"); $form['#id'] = 'views-add-display-form'; $form['#attributes'] = array('class' => 'views-ajax-form'); return $form; } /** * Submit handler to add a remove to a display from a view. */ function views_ui_remove_display_form_submit($form, &$form_state) { // Create the new display $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin); if (empty($plugin['no remove'])) { $id = $form_state['display_id']; $form_state['view']->display[$id]->deleted = TRUE; // Store in cache views_ui_cache_set($form_state['view']); } } /** * Submit handler to add a restore a removed display to a view. */ function views_ui_remove_display_form_restore($form, &$form_state) { // Create the new display $id = $form_state['display_id']; $form_state['view']->display[$id]->deleted = FALSE; // Store in cache views_ui_cache_set($form_state['view']); } /** * Page callback to display analysis information on a view. */ function views_ui_analyze_view($js, $view) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { return views_ui_regenerate_tabs($view); } return views_ajax_render($output); } return $output; } /** * This form doesn't particularly do much; it's really just providing a link * but a button seems like it would be nicer here. * * It has no submit or anything, as we will never actually submit this form * where the form is placed. */ function views_ui_analyze_view_button(&$form_state, $view) { $form['#action'] = url("admin/build/views/nojs/analyze/$view->name"); $form['#attributes'] = array('class' => 'views-ajax-form'); $form['submit'] = array( '#type' => 'submit', '#value' => t('Analyze'), ); return $form; } /** * Format an analysis message. */ function views_ui_analysis($message, $type = 'error') { return array('message' => $message, 'type' => $type); } /** * Implementation of hook_views_analyze(). */ function views_ui_views_analyze($view) { $ret = array(); // Check for something other than the default display: if (count($view->display) < 2) { $ret[] = views_ui_analysis(t('This view has only a default display and therefore will not be placed anywhere on your site; perhaps you want to add a page or a block display.'), 'warning'); } return $ret; } /** * Form constructor callback to display analysis information on a view */ function views_ui_analyze_view_form(&$form_state) { $view = &$form_state['view']; $form['#title'] = t('View analysis'); $form['#section'] = 'analyze'; $messages = array(); $view->init_display(); $messages = module_invoke_all('views_analyze', $view); if (empty($messages)) { $messages = array(views_ui_analysis(t('View analysis can find nothing to report.'), 'ok')); } $types = array('ok' => array(), 'warning' => array(), 'error' => array()); foreach ($messages as $message) { if (empty($types[$message['type']])) { $types[$message['type']] = array(); } $types[$message['type']][] = $message['message']; } $output = ''; foreach ($types as $type => $messages) { $message = ''; if (count($messages) > 1) { $message = theme('item_list', $messages); } else if ($messages) { $message = array_shift($messages); } if ($message) { $output .= "
$message
"; } } $form['analysis'] = array( '#prefix' => '
', '#suffix' => '
', '#value' => $output, ); // Inform the standard button function that we want an OK button. $form_state['ok_button'] = TRUE; views_ui_standard_form_buttons($form, $form_state, 'views_ui_analyze_view_form'); return $form; } /** * Submit handler for views_ui_analyze_view_form */ function views_ui_analyze_view_form_submit($form, &$form_state) { $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * Page callback to edit details of a view. */ function views_ui_edit_details($js, $view) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { return views_ui_regenerate_tabs($view); } return views_ajax_render($output); } return $output; } /** * Form constructor callback to edit details of a view */ function views_ui_edit_details_form(&$form_state) { $view = &$form_state['view']; $form['#title'] = t('View details'); $form['#section'] = 'details'; $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->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->tag, // TODO: This should be an autocomplete field. ); views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form'); return $form; } /** * Submit handler for views_ui_edit_details_form */ function views_ui_edit_details_form_submit($form, &$form_state) { $form_state['view']->description = $form_state['values']['description']; $form_state['view']->tag = $form_state['values']['tag']; views_ui_cache_set($form_state['view']); $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * Form constructor callback to edit display of a view */ function views_ui_edit_display_form(&$form_state) { $view = &$form_state['view']; $display_id = $form_state['display_id']; $section = $form_state['section']; if (!$view->set_display($display_id)) { views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); } $display = &$view->display[$display_id]; // Get form from the handler. $display->handler->options_form($form, $form_state); views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form'); return $form; } /** * Validate handler for views_ui_edit_display_form */ function views_ui_edit_display_form_validate($form, &$form_state) { $display = &$form_state['view']->display[$form_state['display_id']]; $display->handler->options_validate($form, $form_state); } /** * Submit handler for views_ui_edit_display_form */ function views_ui_edit_display_form_submit($form, &$form_state) { $display = &$form_state['view']->display[$form_state['display_id']]; $display->handler->options_submit($form, $form_state); views_ui_cache_set($form_state['view']); } /** * Override handler for views_ui_edit_display_form */ function views_ui_edit_display_form_override($form, &$form_state) { $display = &$form_state['view']->display[$form_state['display_id']]; $display->handler->options_override($form, $form_state); views_ui_cache_set($form_state['view']); $form_state['rerender'] = TRUE; $form_state['rebuild'] = TRUE; } /** * Form to config items in the views UI. */ function views_ui_config_type_form(&$form_state) { $view = &$form_state['view']; $display_id = $form_state['display_id']; $type = $form_state['type']; $types = views_object_types(); if (!$view->set_display($display_id)) { views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); } $display = &$view->display[$display_id]; $form['#title'] = check_plain($display->display_title) . ': '; $form['#title'] .= t('Configure @type', array('@type' => strtolower($types[$type]['title']))); $form['#section'] = $display_id . 'config-item'; if ($display->handler->defaultable_sections($types[$type]['plural'])) { $display->handler->add_override_button($form, $types[$type]['plural']); $form_state['section'] = $types[$type]['plural']; } if (!empty($types[$type]['options']) && function_exists($types[$type]['options'])) { $options = $type . '_options'; $form[$options] = array('#tree' => TRUE); $types[$type]['options']($form, $form_state); } views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form'); return $form; } /** * Submit handler for type configuration form */ function views_ui_config_type_form_submit($form, &$form_state) { $types = views_object_types(); $display = &$form_state['view']->display[$form_state['display_id']]; // Store in cache views_ui_cache_set($form_state['view']); } /** * Configure settings particular to filters. */ function views_ui_config_filters_form(&$form, &$form_state) { } /** * Form to rearrange items in the views UI. */ function views_ui_rearrange_form(&$form_state) { $view = &$form_state['view']; $display_id = $form_state['display_id']; $type = $form_state['type']; $types = views_object_types(); if (!$view->set_display($display_id)) { views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); } $display = &$view->display[$display_id]; $form['#title'] = check_plain($display->display_title) . ': '; $form['#title'] .= t('Rearrange @type', array('@type' => strtolower($types[$type]['title']))); $form['#section'] = $display_id . 'rearrange-item'; if ($display->handler->defaultable_sections($types[$type]['plural'])) { $display->handler->add_override_button($form, $types[$type]['plural']); $form_state['section'] = $types[$type]['plural']; } $count = 0; // Get relationship labels $relationships = array(); foreach ($display->handler->get_option('relationships') as $id => $relationship) { $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); if (empty($handler)) { continue; } $handler->init($view, $relationship); $relationships[$id] = $handler->label(); } foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) { $form[$id] = array('#tree' => TRUE); $form[$id]['weight'] = array( '#type' => 'weight', '#delta' => 25, '#default_value' => ++$count, ); $handler = views_get_handler($field['table'], $field['field'], $type); if ($handler) { $handler->init($view, $field); $name = $handler->ui_name() . ' ' . $handler->admin_summary(); if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) { $name = '(' . $relationships[$field['relationship']] . ') ' . $name; } $form[$id]['name'] = array( '#value' => $name, ); } else { $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id))); } $form[$id]['removed'] = array( '#type' => 'checkbox', '#id' => 'views-removed-' . $id, '#attributes' => array('class' => 'views-remove-checkbox'), '#default_value' => 0, ); } // Add javascript settings that will be added via $.extend for tabledragging $form['#js']['tableDrag']['arrange']['weight'][0] = array( 'target' => 'weight', 'source' => NULL, 'relationship' => 'sibling', 'action' => 'order', 'hidden' => TRUE, 'limit' => 0, ); views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form'); return $form; } /** * Turn the rearrange form into a proper table */ function theme_views_ui_rearrange_form($form) { $rows = array(); foreach (element_children($form) as $id) { if (isset($form[$id]['name'])) { $row = array(); $row[] = drupal_render($form[$id]['name']); $form[$id]['weight']['#attributes']['class'] = 'weight'; $row[] = drupal_render($form[$id]['weight']); $row[] = drupal_render($form[$id]['removed']) . l('' . t('Remove') . '', 'javascript:void()', array('attributes' => array('id' => 'views-remove-link-' . $id, 'class' => 'views-button-remove views-remove-link', 'alt' => t('Remove this item'), 'title' => t('Remove this item')), 'html' => true)); $rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id); } } if (empty($rows)) { $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2')); } $header = array('', t('Weight'), t('Remove')); drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight'); $output = drupal_render($form['override']); $output .= theme('table', $header, $rows, array('id' => 'arrange')); $output .= drupal_render($form); return $output; } /** * Submit handler for rearranging form */ function views_ui_rearrange_form_submit($form, &$form_state) { $types = views_object_types(); $display = &$form_state['view']->display[$form_state['display_id']]; $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']); $new_fields = $order = array(); // Make an array with the weights foreach ($form_state['values'] as $field => $info) { // add each value that is a field with a weight to our list, but only if // it has had its 'removed' checkbox checked. if (is_array($info) && isset($info['weight']) && empty($info['removed'])) { $order[$field] = $info['weight']; } } // Sort the array asort($order); // Create a new list of fields in the new order. foreach (array_keys($order) as $field) { $new_fields[$field] = $old_fields[$field]; } $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields); // Store in cache views_ui_cache_set($form_state['view']); } /** * Form to add_item items in the views UI. */ function views_ui_add_item_form(&$form_state) { $view = &$form_state['view']; $display_id = $form_state['display_id']; $type = $form_state['type']; if (!$view->set_display($display_id)) { views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); } $display = &$view->display[$display_id]; $types = views_object_types(); $form['#title'] = check_plain($display->display_title) . ': '; $form['#title'] .= t('Add @type', array('@type' => strtolower($types[$type]['title']))); $form['#section'] = $display_id . 'add-item'; // Figure out all the base tables allowed based upon what the relationships provide. $base_tables = array( $view->base_table => TRUE, '#global' => TRUE, ); $relationships = $display->handler->get_option('relationships'); foreach ($relationships as $relationship) { $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); if ($handler) { $base_tables[$handler->definition['base']] = TRUE; } } $options = views_fetch_fields(array_keys($base_tables), $type); if (!empty($options)) { $groups = array('all' => t('')); $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', ); foreach ($options as $key => $option) { $group = strtr(strtolower($option['group']), '_ ', '--'); $groups[$group] = $option['group']; $form['name'][$key] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'checkbox', '#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])), '#description' => $option['help'], '#return_value' => $key, ); } $form['group']['#options'] = $groups; } else { $form['markup'] = array( '#value' => '
' . t('There are no @types available to add.', array('@types' => strtolower($types[$type]['title']))) . '
', ); } 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']))); break; } else { $handler->init($view, $item); $types = views_object_types(); // 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[$handler->table . '.' . $handler->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[$handler->table . '.' . $handler->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])) { $rel = 'none'; } $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' => strtolower($types[$type]['stitle']), '@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; } views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', NULL, 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; // 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' => strtolower($types[$type]['stitle']), '@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', NULL, t('Remove'), 'remove'); } 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' => strtolower($types[$type]['stitle']), '@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; } /** * 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']); $plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]); if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) { $item['style_options'] = array(); $plugin->options($item['style_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' => strtolower($types[$type]['stitle']), '@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) { $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'); } /** * Page callback for the Views enable page */ function views_ui_disable_page($view) { $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'); } /** * 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), ); 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.')); } /** * Page callback for views user autocomplete */ function views_ui_autocomplete_user($string = '') { // The user enters a comma-separated list of tags. We only autocomplete the last tag. $array = drupal_explode_tags($string); // Fetch last tag $last_string = trim(array_pop($array)); $matches = array(); if ($last_string != '') { $prefix = count($array) ? implode(', ', $array) . ', ' : ''; if (strpos('anonymous', strtolower($last_string)) !== FALSE) { $matches[$prefix . 'Anonymous'] = 'Anonymous'; } $result = db_query_range("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $last_string, 0, 10); while ($account = db_fetch_object($result)) { $n = $account->name; // Commas and quotes in terms are special cases, so encode 'em. if (strpos($account->name, ',') !== FALSE || strpos($account->name, '"') !== FALSE) { $n = '"'. str_replace('"', '""', $account->name) .'"'; } $matches[$prefix . $n] = check_plain($account->name); } } drupal_json($matches); } /** * 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); }