t('View name'), 'field' => 'name', 'sort' => 'asc'), array('data' => t('Description')), array('data' => t('Title'), 'field' => 'title'), array('data' => t('Type'), 'field' => 'type'), array('data' => t('URL'), 'field' => 'url'), array('data' => t('Operations')), ); foreach (views_get_all_views() as $view) { $ops = array(); if (empty($view->disabled)) { $ops[] = l(t('Edit'), "admin/build/views/edit/$view->name"); $ops[] = l(t('Export'), "admin/build/views/export/$view->name"); $ops[] = l(t('Clone'), "admin/build/views/clone/$view->name"); } if ($view->type != t('Default')) { $text = $view->type == t('Overridden') ? t('Revert') : t('Delete'); $ops[] = l($text, "admin/build/views/delete/$view->name"); } else { if (empty($view->disabled)) { $ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination())); } else { $ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination())); } } if (empty($view->display)) { $path = t('Warning! Broken view!'); } else { $path = $view->get_path(); $path = empty($view->disabled) && strpos($path, '%') === FALSE ? l($path, $path) : check_plain($path); } $item = array(); $item[] = check_plain($view->name); $item[] = check_plain($view->description); $item[] = check_plain($view->get_title()); $item[] = $view->type; // this is safe as it's always programmatic $item[] = $path; $item[] = implode(' | ', $ops); $items[] = $item; $ts = tablesort_init($header); switch ($ts['sql']) { case 'name': default: $sorts[] = $item[0]; break; case 'title': $sorts[] = $item[1]; break; case 'url': $sorts[] = 'todo: path'; // $path; break; case 'type': $sorts[] = $view->type . $item[0]; break; } } if (!empty($ts)) { if (strtolower($ts['sort']) == 'desc') { arsort($sorts); } else { asort($sorts); } } $i = array(); foreach ($sorts as $id => $title) { $i[] = $items[$id]; } $output = theme('table', $header, $i); return $output; } /** * 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) : '', 're_render' => 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, '#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 : '', // TODO: This should be an autocomplete field. ); $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' => views_fetch_base_table_names(), ); 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))); 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); $tabs->add_extra($display_button); $vars['tabs'] = $tabs->render(); $form_state = array( 'display_id' => 'default', 'view_args' => '', 're_render' => 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); } 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); 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; // Fetch style plugin info because it has some effect on how/what we render. $style_plugin = views_get_plugin('style', $display->handler->get_option('style_plugin')); if ($style_plugin) { $style_plugin->init($view, $display); } $vars['fields'] = ''; if ($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'), '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'), '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/rearrange/$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->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('Settings') . '', "admin/build/views/nojs/config-style/$view->name/$display->id/$type/$id", array('attributes' => array('class' => 'views-button-configure views-ajax-link'), '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; } /** * 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(); // 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' => t('Cancel'), '#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']; } // 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. /** * 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'), ); $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']); } /** * AJAX callback to remove a display. */ function views_ui_remove_display($js, $view, $display_id) { views_include('ajax'); $form_state = array( 'view' => &$view, 'display_id' => $display_id, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_remove_display_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, $display_id); } return views_ajax_render($output); } return $output; } /** * 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']); } // Send it back $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['display_id']); } /** * 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']); // Send it back $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['display_id']); } /** * 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; } /** * Page callback to edit options on a display of a view. */ function views_ui_edit_display($js, $view, $display_id, $section) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, 'display_id' => $display_id, 'section' => $section, ); $output = views_ajax_form_wrapper('views_ui_edit_display_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { // Sometimes we need to re-generate the form for multi-step type operations. $object = NULL; if (!empty($form_state['regenerate form'])) { $form_state['input'] = array(); // Remove the input so it can't post. $form_state['executed'] = FALSE; $object = views_ajax_form_wrapper('views_ui_edit_display_form', $form_state); } // regenerate all tabs because changes to the default tab could ripple. return views_ui_regenerate_tabs($view, NULL, $object); } return views_ajax_render($output); } return $output; } /** * 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']); // @todo: Need a safe function to use for drupal_set_message in an ajax environ. // This function would check $form_state for the ajax flag and, if set, simply // discard the message. That way we could set some success messages for the // non-jsy types here. $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * 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['regenerate form'] = TRUE; } /** * Page callback to rearrange a type. */ function views_ui_rearrange_type($js, $view, $display_id, $type) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, 'display_id' => $display_id, 'type' => $type, ); $output = views_ajax_form_wrapper('views_ui_rearrange_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { // Sometimes we need to re-generate the form for multi-step type operations. $object = NULL; if (!empty($form_state['regenerate form'])) { $form_state['input'] = array(); // Remove the input so it can't post. $form_state['executed'] = FALSE; $object = views_ajax_form_wrapper('views_ui_rearrange_form', $form_state); } return views_ui_regenerate_tabs($view, $display_id, $object); } return views_ajax_render($output); } return $output; } /** * 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' => 10, '#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_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * Page callback to add_item a type. */ function views_ui_add_item($js, $view, $display_id, $type) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, 'display_id' => $display_id, 'type' => $type, ); $output = views_ajax_form_wrapper('views_ui_add_item_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { // Sometimes we need to re-generate the form for multi-step type operations. $object = NULL; if (!empty($form_state['id'])) { $form_state['input'] = array(); // Remove the input so it can't post. $form_state['executed'] = FALSE; $form_state['stack'] = TRUE; // tell it to continue stacking forms up $object = views_ajax_form_wrapper('views_ui_config_item_form', $form_state); // This form is at a different URL than $_GET['q'] so we have to pass via the object. $object->url = url("admin/build/views/ajax/config-item/$view->name/$display_id/$type/$form_state[id]"); } return views_ui_regenerate_tabs($view, $display_id, $object); } return views_ajax_render($output); } return $output; } /** * 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); $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_field_names(array_keys($base_tables), $type); if (!empty($options)) { $form['name'] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'checkboxes', '#options' => $options, ); } 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(); $form_state['view']->stack = array(); 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); if (empty($form_state['id'])) { $form_state['id'] = $id; } else { $form_state['view']->stack[] = $id; } } } // Store in cache views_ui_cache_set($form_state['view']); if (!empty($form_state['id'])) { $form_state['redirect'] = 'admin/build/views/nojs/config-item/' . $form_state['view']->name . "/$form_state[display_id]/$type/$form_state[id]"; } else { $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } } /** * Page callback to configure an item */ function views_ui_config_item($js, $view, $display_id, $type, $id) { views_include('ajax'); $form_state = array( 'view' => &$view, 'ajax' => $js, 'display_id' => $display_id, 'id' => $id, 'type' => $type, 'stack' => TRUE, ); $output = views_ajax_form_wrapper('views_ui_config_item_form', $form_state); if ($js) { // If we don't have an output object, it was submitted. Set up the submission. if (empty($output)) { // Sometimes we need to re-generate the form for multi-step type operations. $object = NULL; if (!empty($form_state['next'])) { $form_state['input'] = array(); // Remove the input so it can't post. $form_state['executed'] = FALSE; $form_state['id'] = $form_state['next']; $object = views_ajax_form_wrapper('views_ui_config_item_form', $form_state); // This form is at a different URL than $_GET['q'] so we have to pass via the object. $object->url = url("admin/build/views/ajax/config-item/$view->name/$display_id/$type/$form_state[id]"); } return views_ui_regenerate_tabs($view, $display_id, $object); } return views_ajax_render($output); } return $output; } /** * 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; } $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. $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; } // Set this hidden field so that when we come back, our stacking state // will be retained. $form['stack'] = array( '#type' => 'hidden', // default value means that what we receive in $_POST is more important. '#default_value' => !empty($form_state['stack']), ); 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); } /** * Check to see if there is another config item on the 'stack' that should * be displayed next. */ function views_ui_check_stack(&$form_state) { if (!empty($form_state['view']->stack)) { // If we came in through a 'stack' system, advance to the next. if ($form_state['stack'] || $form_state['values']['stack']) { $form_state['next'] = array_shift($form_state['view']->stack); } else { // Otherwise, the user has clicked elsewhere and come back; our stack needs // to be removed. unset($form_state['view']->stack); } } } /** * 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); views_ui_check_stack($form_state); // Write to cache views_ui_cache_set($form_state['view']); if (isset($form_state['next'])) { $form_state['redirect'] = 'admin/build/views/nojs/config-item/' . $form_state['view']->name . "/$form_state[display_id]/$form_state[type]/$form_state[next]"; } else { $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } } /** * 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); views_ui_check_stack($form_state); // Write to cache views_ui_cache_set($form_state['view']); if (isset($form_state['next'])) { $form_state['redirect'] = 'admin/build/views/nojs/config-item/' . $form_state['view']->name . "/$form_state[display_id]/$form_state[type]/$form_state[next]"; } else { $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } } /** * 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['next'] = $form_state['id']; } /** * Page callback to change the summary style of an argument */ function views_ui_change_style($js, $view, $display_id, $type, $id) { views_include('ajax'); $form_state = array( 'view' => &$view, 'display_id' => $display_id, 'type' => $type, 'id' => $id, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_change_style_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, $display_id); } return views_ajax_render($output); } return $output; } /** * 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', TRUE), '#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; // 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); // Write to cache views_ui_cache_set($form_state['view']); $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * Page callback to config the summary style of an argument */ function views_ui_config_style($js, $view, $display_id, $type, $id) { views_include('ajax'); $form_state = array( 'view' => &$view, 'display_id' => $display_id, 'type' => $type, 'id' => $id, 'ajax' => $js, ); $output = views_ajax_form_wrapper('views_ui_config_style_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, $display_id); } return views_ajax_render($output); } return $output; } /** * 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']); $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; } /** * 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['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), ); return system_settings_form($form); } /** * Page callback for views user autocomplete */ function views_ui_autocomplete_user($string = '') { error_log($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); }