| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: admin.inc,v 1.161.2.12 2010/06/17 02:45:36 merlinofchaos Exp $ 3 /** 4 * @file admin.inc 5 * Provides the Views' administrative interface. 6 */ 7 8 /** 9 * Page callback to list views in the system. 10 */ 11 function views_ui_list_views($arg = NULL) { 12 if ($arg != NULL) { 13 return drupal_not_found(); 14 } 15 16 $output = theme('views_ui_list_views'); 17 views_ui_check_advanced_help(); 18 return $output; 19 } 20 21 /** 22 * Check to see if the advanced help module is installed, and if not put up 23 * a message. 24 * 25 * Only call this function if the user is already in a position for this to 26 * be useful. 27 */ 28 function views_ui_check_advanced_help() { 29 if (variable_get('views_hide_help_message', FALSE)) { 30 return; 31 } 32 33 if (!module_exists('advanced_help')) { 34 $filename = db_result(db_query("SELECT filename FROM {system} WHERE type = 'module' AND name = 'advanced_help'")); 35 if ($filename && file_exists($filename)) { 36 drupal_set_message(t('If you <a href="@modules">enable the advanced help module</a>, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('@modules' => url('admin/build/modules'),'@hide' => url('admin/build/views/tools')))); 37 } 38 else { 39 drupal_set_message(t('If you install the advanced help module from !href, Views will provide more and better help. <a href="@hide">Hide this message.</a>', array('!href' => l('http://drupal.org/project/advanced_help', 'http://drupal.org/project/advanced_help'), '@hide' => url('admin/build/views/tools')))); 40 } 41 } 42 } 43 44 /** 45 * Preprocess the list views theme 46 */ 47 function template_preprocess_views_ui_list_views(&$vars) { 48 $items = array(); 49 $sorts = array(); 50 51 $views = views_get_all_views(); 52 53 $token_enable = drupal_get_token('views-enable'); 54 $token_disable = drupal_get_token('views-disable'); 55 56 // Respond to a reset command by clearing session and doing a drupal goto 57 // back to the base URL. 58 if (isset($_GET['op']) && $_GET['op'] == t('Reset')) { 59 unset($_SESSION['views']['#admin']); 60 drupal_goto('admin/build/views'); 61 } 62 if (count($_GET) <= 1) { 63 if (isset($_SESSION['views']['#admin']) && is_array($_SESSION['views']['#admin'])) { 64 $_GET += $_SESSION['views']['#admin']; 65 } 66 } 67 else { 68 $_SESSION['views']['#admin'] = $_GET; 69 unset($_SESSION['views']['#admin']['q']); 70 } 71 72 $form_state = array( 73 'views' => $views, 74 'input' => $_GET, 75 'method' => 'get', 76 'rerender' => TRUE, 77 'no_redirect' => TRUE, 78 ); 79 80 $vars['widgets'] = drupal_build_form('views_ui_list_views_form', $form_state); 81 82 $vars['help_type_icon'] = theme('advanced_help_topic', 'views', 'view-type'); 83 84 $base_tables = views_fetch_base_tables(); 85 86 foreach ($views as $view) { 87 if ($form_state['values']['tag'] != 'all') { 88 if ($form_state['values']['tag'] == 'none') { 89 if (!empty($view->tag)) { 90 continue; 91 } 92 } 93 else if ($form_state['values']['tag'] != $view->tag) { 94 continue; 95 } 96 } 97 if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $view->type) { 98 continue; 99 } 100 101 if ($form_state['values']['base'] != 'all' && $form_state['values']['base'] != $view->base_table) { 102 continue; 103 } 104 105 if ($form_state['values']['display'] != 'all' && empty($view->display[$form_state['values']['display']])) { 106 continue; 107 } 108 109 $item = new stdClass(); 110 $item->ops = array(); 111 if (empty($view->disabled)) { 112 $item->ops[] = l(t('Edit'), "admin/build/views/edit/$view->name"); 113 $item->ops[] = l(t('Export'), "admin/build/views/export/$view->name"); 114 $item->ops[] = l(t('Clone'), "admin/build/views/clone/$view->name"); 115 } 116 if ($view->type != t('Default')) { 117 $text = $view->type == t('Overridden') ? t('Revert') : t('Delete'); 118 $item->ops[] = l($text, "admin/build/views/delete/$view->name"); 119 } 120 else { 121 if (empty($view->disabled)) { 122 $item->ops[] = l(t('Disable'), "admin/build/views/disable/$view->name", array('query' => drupal_get_destination() . '&token=' . $token_disable)); 123 } 124 else { 125 $item->ops[] = l(t('Enable'), "admin/build/views/enable/$view->name", array('query' => drupal_get_destination() . '&token=' . $token_enable)); 126 } 127 } 128 129 $item->ops = implode(' | ', $item->ops); 130 if (empty($view->display)) { 131 $item->path = t('Warning! Broken view!'); 132 } 133 else { 134 $item->path = $raw_path = $view->get_path(); 135 $item->path = $item->path && empty($view->disabled) && strpos($item->path, '%') === FALSE ? l($item->path, $item->path) : check_plain($item->path); 136 } 137 138 $item->type = $view->type; 139 $item->name = $view->name; 140 141 if (!empty($view->tag)) { 142 $item->tag = $view->tag; 143 } 144 145 $item->title = $view->get_title(); 146 $item->base = !empty($base_tables[$view->base_table]['title']) ? $base_tables[$view->base_table]['title'] : t('Broken'); 147 148 $item->displays = array(); 149 foreach ($view->display as $display) { 150 if (!empty($display->handler->definition['admin'])) { 151 $item->displays[$display->handler->definition['admin']] = TRUE; 152 } 153 } 154 155 if ($item->displays) { 156 ksort($item->displays); 157 $item->displays = implode(', ', array_keys($item->displays)); 158 } 159 160 $item->description = check_plain($view->description); 161 $item->classes = empty($view->disabled) ? 'view-enabled' : 'view-disabled'; 162 $items[] = $item; 163 164 $sort = intval(empty($view->disabled) xor $form_state['values']['sort'] == 'asc'); 165 166 switch ($form_state['values']['order']) { 167 case 'name': 168 default: 169 $sort .= strtolower($view->name); 170 break; 171 case 'title': 172 $sort .= strtolower($item->title); 173 break; 174 case 'path': 175 $sort .= strtolower($raw_path); // $path; 176 break; 177 case 'type': 178 $sort .= $view->type . $view->name; 179 break; 180 case 'tag': 181 $sort .= strtolower($view->tag); 182 break; 183 case 'desc': 184 $sort .= strtolower($view->description); 185 break; 186 } 187 188 $sorts[] = $sort; 189 } 190 191 if ($form_state['values']['sort'] == 'desc') { 192 arsort($sorts); 193 } 194 else { 195 asort($sorts); 196 } 197 198 $i = array(); 199 foreach ($sorts as $id => $title) { 200 $i[] = $items[$id]; 201 } 202 203 views_add_css('views-list'); 204 $vars['views'] = $i; 205 206 $getting_started = theme('advanced_help_topic', 'views', 'getting-started', 'title'); 207 if (!$getting_started) { 208 $getting_started = t('Install the advanced help module for the getting started'); 209 } 210 211 $vars['help'] = t('Not sure what to do? Try the "!getting-started" page.', array('!getting-started' => $getting_started)); 212 } 213 214 /** 215 * Provide a form for sorting and filtering the list of views. 216 */ 217 function views_ui_list_views_form(&$form_state) { 218 if (!variable_get('clean_url', FALSE)) { 219 $form['q'] = array( 220 '#type' => 'hidden', 221 '#value' => $_GET['q'], 222 ); 223 } 224 225 $all = array('all' => t('<All>')); 226 $none = array('none' => t('<None>')); 227 228 $form['type'] = array( 229 '#type' => 'select', 230 '#title' => t('Storage'), 231 '#options' => array( 232 'all' => t('<All>'), 233 t('Normal') => t('Normal'), 234 t('Default') => t('Default'), 235 t('Overridden') => t('Overridden'), 236 ), 237 '#default_value' => 'all', 238 ); 239 240 $bases = array(); 241 foreach (views_fetch_base_tables() as $table => $info) { 242 $bases[$table] = $info['title']; 243 } 244 245 $form['base'] = array( 246 '#type' => 'select', 247 '#title' => t('Type'), 248 '#options' => array_merge($all, $bases), 249 '#default_value' => 'all', 250 ); 251 252 $tags = array(); 253 254 $extras = array(); 255 foreach ($form_state['views'] as $name => $view) { 256 if (!empty($view->tag)) { 257 $tags[$view->tag] = $view->tag; 258 } 259 } 260 261 asort($tags); 262 263 $form['tag'] = array( 264 '#type' => 'select', 265 '#title' => t('Tag'), 266 '#options' => array_merge($all, $none, $tags), 267 '#default_value' => 'all', 268 ); 269 270 $displays = array(); 271 foreach (views_fetch_plugin_data('display') as $id => $info) { 272 if (!empty($info['admin'])) { 273 $displays[$id] = $info['admin']; 274 } 275 } 276 277 asort($displays); 278 279 $form['display'] = array( 280 '#type' => 'select', 281 '#title' => t('Displays'), 282 '#options' => array_merge($all, $displays), 283 '#default_value' => 'all', 284 ); 285 286 $form['order'] = array( 287 '#type' => 'select', 288 '#title' => t('Sort by'), 289 '#options' => array( 290 'name' => t('Name'), 291 'title' => t('Title'), 292 'tag' => t('Tag'), 293 'path' => t('Path'), 294 'type' => t('Type'), 295 'desc' => t('Description'), 296 ), 297 '#default_value' => 'name', 298 ); 299 300 $form['sort'] = array( 301 '#type' => 'select', 302 '#title' => t('Order'), 303 '#options' => array( 304 'asc' => t('Up'), 305 'desc' => t('Down'), 306 ), 307 '#default_value' => 'asc', 308 ); 309 310 $form['submit'] = array( 311 '#name' => '', // so it won't in the $_GET args 312 '#type' => 'submit', 313 '#id' => 'edit-views-apply', 314 '#value' => t('Apply'), 315 ); 316 317 if (!empty($_SESSION['views']['#admin'])) { 318 $form['reset'] = array( 319 '#type' => 'submit', 320 '#id' => 'edit-views-reset', 321 '#value' => t('Reset'), 322 ); 323 } 324 325 $form['#theme'] = array('views_ui_list_views_form'); 326 return $form; 327 } 328 329 function theme_views_ui_list_views_form($form) { 330 // Don't render these: 331 unset($form['form_id']); 332 unset($form['form_build_id']); 333 unset($form['form_token']); 334 return drupal_render($form); 335 } 336 337 /** 338 * Page callback for the live preview. 339 * 340 * @todo make this use a template 341 */ 342 function views_ui_preview($js, $view) { 343 // Take off the items we know so that we can have just the args passed 344 // in for later use. 345 $func_args = func_get_args(); 346 array_shift($func_args); // $js 347 array_shift($func_args); // $view 348 $display_id = (count($func_args)) ? array_shift($func_args) : 'default'; 349 350 $form_state = array( 351 'display_id' => $display_id, 352 'view_args' => $func_args ? implode('/', $func_args) : '', 353 'rerender' => TRUE, 354 'no_redirect' => TRUE, 355 'view' => &$view, 356 'ajax' => $js 357 ); 358 359 $output = drupal_build_form('views_ui_preview_form', $form_state); 360 $args = array(); 361 if (isset($form_state['view_args']) && $form_state['view_args'] !== '') { 362 $args = explode('/', $form_state['view_args']); 363 } 364 365 $errors = $view->validate(); 366 if ($errors === TRUE) { 367 $view->ajax = $js; 368 $view->live_preview = TRUE; 369 370 // Store the current view URL for later use: 371 $view->set_display($form_state['display_id']); 372 $view->set_arguments($args); 373 374 if ($view->display_handler->get_option('path')) { 375 $path = $view->get_url(); 376 } 377 378 // Make view links come back to preview. 379 $view->override_path = 'admin/build/views/nojs/preview/' . $view->name . '/' . $form_state['display_id']; 380 381 // also override $_GET['q'] so we get the pager 382 $_GET['q'] = $view->override_path; 383 if ($form_state['view_args']) { 384 $_GET['q'] .= '/' . $form_state['view_args']; 385 } 386 387 $preview = $view->preview($form_state['display_id'], $args); 388 389 // Get information from the preview for display. 390 if (!empty($view->build_info['query'])) { 391 $rows = array(); 392 $query = db_prefix_tables($view->build_info['query']); 393 if ($view->build_info['query_args']) { 394 _db_query_callback($view->build_info['query_args'], TRUE); 395 $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); 396 } 397 $rows[] = array('<strong>' . t('Query') . '</strong>', '<pre>' . check_plain($query) . '</pre>'); 398 if (!empty($view->additional_queries)) { 399 $queries = '<strong>' . t('These queries were run during view rendering:') . '</strong>'; 400 foreach ($view->additional_queries as $query) { 401 if ($queries) { 402 $queries .= "\n"; 403 } 404 $queries .= t('[@time ms]', array('@time' => intval($query[1] * 100000) / 100)) . ' ' . check_plain($query[0]); 405 } 406 407 $rows[] = array('<strong>' . t('Other queries') . '</strong>', '<pre>' . $queries . '</pre>'); 408 } 409 410 $rows[] = array('<strong>' . t('Title') . '</strong>', filter_xss_admin($view->get_title())); 411 if (isset($path)) { 412 $path = l($path, $path); 413 } 414 else { 415 $path = t('This display has no path.'); 416 } 417 418 $rows[] = array('<strong>' . t('Path') . '</strong>', $path); 419 420 $rows[] = array('<strong>' . t('Query build time') . '</strong>', t('@time ms', array('@time' => intval($view->build_time * 100000) / 100))); 421 $rows[] = array('<strong>' . t('Query execute time') . '</strong>', t('@time ms', array('@time' => intval($view->execute_time * 100000) / 100))); 422 $rows[] = array('<strong>' . t('View render time') . '</strong>', t('@time ms', array('@time' => intval($view->render_time * 100000) / 100))); 423 drupal_alter('views_preview_info', $rows, $view); 424 425 $info = theme('table', array(), $rows); 426 } 427 else { 428 $info = theme('table', array(), array(array('<strong>' . t('Query') . '</strong>', t('No query was run')))); 429 } 430 } 431 else { 432 foreach ($errors as $error) { 433 drupal_set_message($error, 'error'); 434 } 435 $preview = t('Unable to preview due to validation errors.'); 436 $info = ''; 437 } 438 439 $info = '<div class="views-query-info">' . $info . '</div>'; 440 441 if (variable_get('views_ui_query_on_top', FALSE)) { 442 $output .= $info . $preview; 443 } 444 else { 445 $output .= $preview . $info; 446 } 447 448 if (!$js) { 449 views_add_css('views-admin'); 450 drupal_set_title($view->get_title()); 451 return $output; 452 } 453 else { 454 views_include('ajax'); 455 $object = new stdClass(); 456 if (!empty($view->js_settings)) { 457 $object->js = $view->js_settings; 458 } 459 $object->display = ''; 460 if ($messages = theme('status_messages')) { 461 $object->display = '<div class="views-messages">' . $messages . '</div>'; 462 } 463 $object->display .= $output; 464 $object->title = $view->get_title(); 465 views_ajax_render($object); 466 } 467 } 468 469 /** 470 * Form for generating argument information for the live preview. 471 */ 472 function views_ui_preview_form(&$form_state) { 473 $view = &$form_state['view']; 474 $view->init_display(); 475 $options = array(); 476 foreach ($view->display as $id => $display) { 477 $options[$id] = $display->display_title; 478 } 479 480 $form['#attributes'] = array( 481 'class' => 'clear-block', 482 ); 483 484 $form['display_id'] = array( 485 '#type' => 'select', 486 '#title' => t('Display'), 487 '#options' => $options, 488 '#default_value' => $form_state['display_id'], 489 '#id' => 'preview-display-id', 490 ); 491 492 $form['args'] = array( 493 '#type' => 'textfield', 494 '#title' => t('Arguments'), 495 '#default_value' => $form_state['view_args'], 496 '#description' => t('Separate arguments with a / as though they were a URL path.'), 497 '#id' => 'preview-args', 498 ); 499 500 $form['preview'] = array( 501 '#type' => 'submit', 502 '#value' => t('Preview'), 503 '#id' => 'preview-submit', 504 ); 505 506 507 $form['live_preview'] = array( 508 '#type' => 'checkbox', 509 '#title' => t('Automatic live preview'), 510 '#default_value' => !variable_get('views_ui_disable_live_preview', 0), 511 ); 512 513 $form['#action'] = url("admin/build/views/nojs/preview/$view->name"); 514 return $form; 515 } 516 517 /** 518 * Submit the preview form. 519 * 520 * This just takes the data and stores it on the form state in a 521 * known location. The caller will be responsible for using it. 522 */ 523 function views_ui_preview_form_submit(&$form, &$form_state) { 524 $form_state['display_id'] = $form_state['values']['display_id']; 525 $form_state['view_args'] = $form_state['values']['args']; 526 } 527 528 /** 529 * Page callback to add a new view. 530 */ 531 function views_ui_add_page() { 532 $form_state = array( 533 'view' => NULL 534 ); 535 536 return drupal_build_form('views_ui_add_form', $form_state); 537 } 538 539 /** 540 * Page callback to add a new view. 541 */ 542 function views_ui_clone_page($view) { 543 $form_state = array( 544 'view' => $view->copy(), 545 ); 546 547 drupal_set_title(t('Clone view %view', array('%view' => $view->name))); 548 return drupal_build_form('views_ui_add_form', $form_state); 549 } 550 551 /** 552 * Form constructor callback to create the views Add Form, phase 1. 553 */ 554 function views_ui_add_form(&$form_state) { 555 $view = $form_state['view']; 556 $form = array(); 557 558 $form['name'] = array( 559 '#type' => 'textfield', 560 '#title' => t('View name'), 561 '#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.'), 562 '#required' => TRUE, 563 '#maxlength' => 32, 564 '#default_value' => $view ? $view->name : '', 565 '#attributes' => array('dir'=>'ltr'), 566 ); 567 568 $form['description'] = array( 569 '#type' => 'textfield', 570 '#title' => t('View description'), 571 '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'), 572 '#default_value' => $view ? $view->description : '', 573 ); 574 575 $form['tag'] = array( 576 '#type' => 'textfield', 577 '#title' => t('View tag'), 578 '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'), 579 '#default_value' => $view ? $view->tag : '', 580 '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag', 581 ); 582 583 $base_tables = array(); 584 foreach (views_fetch_base_tables() as $table => $info) { 585 $base_tables[$table] = $info['title'] . '<div class="description">' . $info['description'] . '</div>'; 586 } 587 588 $form['base_table'] = array( 589 '#type' => 'radios', 590 '#title' => t('View type'), 591 '#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 <strong>cannot be changed</strong>.'), 592 '#default_value' => $view ? $view->base_table : 'node', 593 '#options' => $base_tables, 594 ); 595 596 if ($view) { 597 $form['base_table']['#disabled'] = TRUE; 598 } 599 600 $form['submit'] = array( 601 '#type' => 'submit', 602 '#value' => t('Next'), 603 '#validate' => array('views_ui_add_form_validate'), 604 '#submit' => array('views_ui_add_form_submit'), 605 ); 606 607 return $form; 608 } 609 610 /** 611 * Validate the add view form. 612 */ 613 function views_ui_add_form_validate($form, &$form_state) { 614 $name = $form_state['values']['name']; 615 616 // View name must be alphanumeric or underscores, no other punctuation. 617 if (preg_match('/[^a-zA-Z0-9_]/', $name)) { 618 form_error($form['name'], t('View name must be alphanumeric or underscores only.')); 619 } 620 621 // View name must already exist. 622 $view = views_get_view($form_state['values']['name']); 623 if ($view && $view->type != t('Default')) { 624 form_error($form['name'], t('You must use a unique name for this view.')); 625 } 626 } 627 628 /** 629 * Process the add view form 630 */ 631 function views_ui_add_form_submit($form, &$form_state) { 632 $view = $form_state['view'] ? $form_state['view'] : views_new_view(); 633 $view->name = $form_state['values']['name']; 634 $view->description = $form_state['values']['description']; 635 $view->tag = $form_state['values']['tag']; 636 if (empty($form['base_table']['#disabled'])) { 637 $view->base_table = $form_state['values']['base_table']; 638 } 639 640 views_ui_cache_set($view); 641 $form_state['redirect'] ='admin/build/views/edit/' . $view->name; 642 } 643 644 /** 645 * Page to delete a view. 646 */ 647 function views_ui_delete_confirm(&$form_state, $view) { 648 $form_state['view'] = &$view; 649 $form = array(); 650 651 $cancel = 'admin/build/views'; 652 if (!empty($_REQUEST['cancel'])) { 653 $cancel = $_REQUEST['cancel']; 654 } 655 656 if ($view->type == t('Overridden')) { 657 $title = t('Are you sure you want to revert the view %name?', array('%name' => $view->name)); 658 $desc = t('Reverting the view will delete the view that is in the database, reverting it to the original default view. Any changes you have made will be lost and cannot be recovered.'); 659 $button = t('Revert'); 660 } 661 else { 662 $title = t('Are you sure you want to delete the view %name?', array('%name' => $view->name)); 663 $desc = t('Deleting a view cannot be undone.'); 664 $button = t('Delete'); 665 } 666 667 return confirm_form($form, 668 $title, 669 $cancel, 670 $desc, 671 $button, 672 t('Cancel')); 673 } 674 675 /** 676 * Submit handler to delete a view. 677 */ 678 function views_ui_delete_confirm_submit(&$form, &$form_state) { 679 $form_state['view']->delete(); 680 views_object_cache_clear('view', $form_state['view']->name); 681 drupal_set_message(t('The view has been deleted.')); 682 $form_state['redirect'] = 'admin/build/views'; 683 } 684 685 /** 686 * Page to delete a view. 687 */ 688 function views_ui_break_lock_confirm(&$form_state, $view) { 689 $form_state['view'] = &$view; 690 $form = array(); 691 692 if (empty($view->locked)) { 693 return t('There is no lock on view %view to break.', array('%name' => $view->name)); 694 } 695 696 $cancel = 'admin/build/views/edit/' . $view->name; 697 if (!empty($_REQUEST['cancel'])) { 698 $cancel = $_REQUEST['cancel']; 699 } 700 701 $account = user_load($view->locked->uid); 702 return confirm_form($form, 703 t('Are you sure you want to break the lock on view %name?', 704 array('%name' => $view->name)), 705 $cancel, 706 t('By breaking this lock, any unsaved changes made by !user will be lost!', array('!user' => theme('username', $account))), 707 t('Break lock'), 708 t('Cancel')); 709 } 710 711 /** 712 * Submit handler to break_lock a view. 713 */ 714 function views_ui_break_lock_confirm_submit(&$form, &$form_state) { 715 db_query("DELETE FROM {views_object_cache} WHERE obj = 'view' AND name = '%s'", $form_state['view']->name); 716 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; 717 drupal_set_message(t('The lock has been broken and you may now edit this view.')); 718 } 719 720 /** 721 * The main view edit page 722 */ 723 function views_ui_edit_page($view) { 724 drupal_set_title(t('Edit view %view', array('%view' => $view->name))); 725 $output = theme('views_ui_edit_view', $view); 726 views_ui_check_advanced_help(); 727 return $output; 728 } 729 730 /** 731 * Export a view for cut & paste. 732 */ 733 function views_ui_export_page(&$form_state, $view) { 734 $code = $view->export(); 735 $lines = substr_count($code, "\n"); 736 $form['code'] = array( 737 '#type' => 'textarea', 738 '#title' => $view->name, 739 '#default_value' => $code, 740 '#rows' => $lines, 741 ); 742 return $form; 743 } 744 745 /** 746 * Import a view from cut & paste 747 */ 748 function views_ui_import_page(&$form_state) { 749 $form['name'] = array( 750 '#type' => 'textfield', 751 '#title' => t('View name'), 752 '#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.'), 753 ); 754 755 $form['view'] = array( 756 '#type' => 'textarea', 757 '#title' => t('Paste view code here'), 758 '#required' => TRUE, 759 ); 760 761 $form['submit'] = array( 762 '#type' => 'submit', 763 '#value' => t('Import'), 764 '#submit' => array('views_ui_import_submit'), 765 '#validate' => array('views_ui_import_validate'), 766 ); 767 return $form; 768 } 769 770 /** 771 * Validate handler to import a view 772 */ 773 function views_ui_import_validate($form, &$form_state) { 774 $view = ''; 775 views_include('view'); 776 ob_start(); 777 eval($form_state['values']['view']); 778 ob_end_clean(); 779 780 if (!is_object($view)) { 781 return form_error($form['view'], t('Unable to interpret view code.')); 782 } 783 784 if (empty($view->api_version) || $view->api_version < 2) { 785 // Check for some value that would only exist on a Views 1 view. 786 if (isset($view->url) || isset($view->page) || isset($view->block)) { 787 views_include('convert'); 788 $view = views1_import($view); 789 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'); 790 } 791 else { 792 form_error($form['view'], t('That view is not compatible with this version of Views.')); 793 } 794 } 795 elseif ($view->api_version > views_api_version()) { 796 form_error($form['view'], t('That view is created for the version @import_version of views, but you only have @api_version', array( 797 '@import_version' => $view->api_version, 798 '@api_version' => views_api_version()))); 799 } 800 801 // View name must be alphanumeric or underscores, no other punctuation. 802 if (!empty($form_state['values']['name']) && preg_match('/[^a-zA-Z0-9_]/', $form_state['values']['name'])) { 803 form_error($form['name'], t('View name must be alphanumeric or underscores only.')); 804 } 805 806 if ($form_state['values']['name']) { 807 $view->name = $form_state['values']['name']; 808 } 809 810 $test = views_get_view($view->name); 811 if ($test && $test->type != t('Default')) { 812 form_set_error('', t('A view by that name already exists; please choose a different name')); 813 } 814 815 $view->init_display(); 816 817 $broken = FALSE; 818 // Make sure that all plugins and handlers needed by this view actually exist. 819 foreach ($view->display as $id => $display) { 820 if (empty($display->handler) || !empty($display->handler->broken)) { 821 drupal_set_message(t('Display plugin @plugin is not available.', array('@plugin' => $display->display_plugin)), 'error'); 822 $broken = TRUE; 823 continue; 824 } 825 826 $plugin = views_get_plugin('style', $display->handler->get_option('style_plugin')); 827 if (!$plugin) { 828 drupal_set_message(t('Style plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('style_plugin'))), 'error'); 829 $broken = TRUE; 830 } 831 else if ($plugin->uses_row_plugin()) { 832 $plugin = views_get_plugin('row', $display->handler->get_option('row_plugin')); 833 if (!$plugin) { 834 drupal_set_message(t('Row plugin @plugin is not available.', array('@plugin' => $display->handler->get_option('row_plugin'))), 'error'); 835 $broken = TRUE; 836 } 837 } 838 839 foreach (views_object_types() as $type => $info) { 840 $handlers = $display->handler->get_handlers($type); 841 if ($handlers) { 842 foreach ($handlers as $id => $handler) { 843 if ($handler->broken()) { 844 drupal_set_message(t('@type handler @table.@field is not available.', array( 845 '@type' => $info['stitle'], 846 '@table' => $handler->table, 847 '@field' => $handler->field, 848 )), 'error'); 849 $broken = TRUE; 850 } 851 } 852 } 853 } 854 } 855 856 if ($broken) { 857 form_set_error('', t('Unable to import view.')); 858 } 859 860 $form_state['view'] = &$view; 861 } 862 863 /** 864 * Submit handler for view import 865 */ 866 function views_ui_import_submit($form, &$form_state) { 867 // Store in cache and then go to edit. 868 views_ui_cache_set($form_state['view']); 869 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; 870 } 871 872 /** 873 * The main edit view form, which is really just a save/cancel/delete button. 874 */ 875 function views_ui_edit_view_form(&$form_state, $view) { 876 $form['buttons']['save'] = array( 877 '#type' => 'submit', 878 '#value' => t('Save'), 879 '#validate' => array('views_ui_edit_view_form_validate'), 880 '#submit' => array('views_ui_edit_view_form_submit'), 881 ); 882 883 $form['buttons']['cancel'] = array( 884 '#type' => 'submit', 885 '#value' => t('Cancel'), 886 '#submit' => array('views_ui_edit_view_form_cancel'), 887 ); 888 889 if (is_numeric($view->vid)) { 890 $form['buttons']['delete'] = array( 891 '#type' => 'submit', 892 '#value' => $view->type == t('Overridden') ? t('Revert') : t('Delete'), 893 '#submit' => array('views_ui_edit_view_form_delete'), 894 ); 895 } 896 897 $form_state['view'] = &$view; 898 return $form; 899 } 900 901 /** 902 * Validate that a view is complete and whole. 903 */ 904 function views_ui_edit_view_form_validate($form, &$form_state) { 905 // Do not validate cancel or delete or revert. 906 if (empty($form_state['clicked_button']['#value']) || $form_state['clicked_button']['#value'] != t('Save')) { 907 return; 908 } 909 910 $errors = $form_state['view']->validate(); 911 if ($errors !== TRUE) { 912 foreach ($errors as $error) { 913 form_set_error('', $error); 914 } 915 } 916 } 917 918 /** 919 * Submit handler for the edit view form. 920 */ 921 function views_ui_edit_view_form_submit($form, &$form_state) { 922 // Go through and remove displayed scheduled for removal. 923 foreach ($form_state['view']->display as $id => $display) { 924 if (!empty($display->deleted)) { 925 unset($form_state['view']->display[$id]); 926 } 927 } 928 929 $form_state['view']->save(); 930 drupal_set_message(t('The view %name has been saved.', array('%name' => $form_state['view']->name))); 931 932 // Make sure menu items get rebuilt as neces 933 menu_rebuild(); 934 935 // Clear the views cache. 936 cache_clear_all('*', 'cache_views'); 937 938 // Clear the page cache. 939 cache_clear_all(); 940 941 // Remove this view from cache so we can edit it properly. 942 views_object_cache_clear('view', $form_state['view']->name); 943 } 944 945 /** 946 * Submit handler for the edit view form. 947 */ 948 function views_ui_edit_view_form_cancel($form, &$form_state) { 949 // Remove this view from cache so edits will be lost. 950 views_object_cache_clear('view', $form_state['view']->name); 951 if (empty($form['view']->vid)) { 952 // I seem to have to drupal_goto here because I can't get fapi to 953 // honor the redirect target. Not sure what I screwed up here. 954 drupal_goto('admin/build/views'); 955 } 956 } 957 958 function views_ui_edit_view_form_delete($form, &$form_state) { 959 unset($_REQUEST['destination']); 960 // Redirect to the delete confirm page 961 $form_state['redirect'] = array('admin/build/views/delete/' . $form_state['view']->name, 'cancel=admin/build/views/edit/' . $form_state['view']->name); 962 } 963 964 /** 965 * Preprocess the view edit page. 966 */ 967 function template_preprocess_views_ui_edit_view(&$vars) { 968 $view = &$vars['view']; 969 970 $vars['save_button'] = drupal_get_form('views_ui_edit_view_form', $view); 971 972 $table = views_fetch_data($view->base_table); 973 $vars['base_table'] = !empty($table['table']['base']['title']) ? 974 $table['table']['base']['title'] : t('Unknown or missing table name'); 975 976 views_include('tabs'); 977 $tabs = new views_tabset; 978 979 $vars['message'] = '<div class="message">' . t("Click on an item to edit that item's details.") . '</div>'; 980 981 if (!$view->set_display('default')) { 982 drupal_set_message(t('This view has a broken default display and cannot be used.'), 'error'); 983 } 984 985 foreach ($view->display as $display) { 986 list($title, $body) = views_ui_display_tab($view, $display); 987 // The first display is the default. 988 $tabs->set($display->id, $title, $body); 989 } 990 991 // This is the area that will render beneath the links 992 $form_state = array( 993 'view' => &$view, 994 'ajax' => FALSE, 995 ); 996 997 $display_button = drupal_build_form('views_ui_add_display_form', $form_state); 998 $analyze_button = drupal_get_form('views_ui_analyze_view_button', $view); 999 $tabs->add_extra($display_button . $analyze_button); 1000 1001 $vars['tabs'] = $tabs->render(); 1002 1003 $form_state = array( 1004 'display_id' => 'default', 1005 'view_args' => '', 1006 'rerender' => FALSE, 1007 'no_redirect' => TRUE, 1008 'view' => &$view, 1009 'input' => array(), 1010 ); 1011 $vars['preview'] = drupal_build_form('views_ui_preview_form', $form_state); 1012 1013 $vars['locked'] = NULL; 1014 if (isset($view->locked) && is_object($view->locked)) { 1015 $account = user_load($view->locked->uid); 1016 $vars['locked'] = theme('username', $account); 1017 $vars['lock_age'] = format_interval(time() - $view->locked->updated); 1018 $vars['break'] = url('admin/build/views/break-lock/' . $view->name); 1019 } 1020 1021 $vars['quick_links_raw'] = array( 1022 array( 1023 'title' => t('Export'), 1024 'alt' => t("Export this view"), 1025 'href' => "admin/build/views/export/$view->name", 1026 ), 1027 array( 1028 'title' => t('Clone'), 1029 'alt' => t("Create a copy of this view"), 1030 'href' => "admin/build/views/clone/$view->name", 1031 ), 1032 ); 1033 1034 $paths = array(); 1035 foreach ($view->display as $id => $display) { 1036 if (!empty($display->handler) && $display->handler->has_path()) { 1037 $path = $display->handler->get_path(); 1038 if (strpos($path, '%') === FALSE && !isset($paths[$path])) { 1039 $vars['quick_links_raw'][] = array( 1040 'title' => t('View "@display"', array('@display' => $display->display_title)), 1041 'alt' => t("Go to the real page for this display"), 1042 'href' => $path, 1043 ); 1044 // Displays can have the same path; no point in showing more than one link. 1045 $paths[$path] = TRUE; 1046 } 1047 } 1048 } 1049 1050 $vars['quick_links'] = theme('links', $vars['quick_links_raw']); 1051 views_add_css('views-admin'); 1052 views_add_js('ajax'); 1053 drupal_add_js('misc/jquery.form.js'); 1054 1055 // Also add any js files required by plugins: 1056 $plugins = views_fetch_plugin_data(); 1057 foreach ($plugins as $type => $type_plugins) { 1058 foreach ($type_plugins as $name => $plugin) { 1059 if (!empty($plugin['js'])) { 1060 foreach ($plugin['js'] as $file) { 1061 drupal_add_js($file); 1062 } 1063 } 1064 } 1065 } 1066 1067 $settings = array('views' => array('ajax' => array( 1068 'id' => '#views-ajax-pad', 1069 'title' => '#views-ajax-title', 1070 'defaultForm' => $vars['message'], 1071 ))); 1072 1073 drupal_add_js($settings, 'setting'); 1074 } 1075 1076 function template_preprocess_views_ui_edit_tab(&$vars) { 1077 $view = $vars['view']; 1078 $display = $vars['display']; 1079 $plugin = $display->handler->definition; 1080 1081 $top = $left = $middle = $right = ''; 1082 1083 // If this form was submitted it was already handled, so force it not to 1084 // submit again. 1085 1086 $vars['remove'] = ''; 1087 if (empty($plugin['no remove'])) { 1088 if (!empty($_POST['form_id']) && $_POST['form_id'] == 'views_ui_remove_display_form') { 1089 unset($_POST['form_id']); 1090 } 1091 $form_state = array('view' => &$view, 'display_id' => $display->id, 'ajax' => FALSE); 1092 $vars['remove'] = drupal_build_form('views_ui_remove_display_form', $form_state); 1093 } 1094 1095 // basic fields 1096 $vars['title'] = check_plain($display->display_title); 1097 $vars['description'] = check_plain($plugin['help']); 1098 1099 // Special fields if tihs is the default display. 1100 $vars['default'] = ($display->id == 'default'); 1101 $vars['details_class'] = views_ui_item_css('details'); 1102 if (!empty($view->changed_sections['details'])) { 1103 $vars['details_changed'] = TRUE; 1104 } 1105 1106 $tag = empty($view->tag) ? t('None') : $view->tag; 1107 $vars['details'] = t('Description') . '/' . t('Tag') . ': ' . l($tag, "admin/build/views/nojs/details/$view->name", array('attributes' => array('class' => 'views-ajax-link'))); 1108 1109 // Calculate options from display plugin. 1110 $options = $categories = array(); 1111 $display->handler->options_summary($categories, $options); 1112 1113 // Build all of the options we were returned and put them into the 1114 // category data fields. 1115 foreach ($options as $id => $option) { 1116 if (empty($categories[$option['category']]['data'])) { 1117 $categories[$option['category']]['data'] = array(); 1118 } 1119 $categories[$option['category']]['data'][$id] = array(); 1120 $data = &$categories[$option['category']]['data'][$id]; 1121 $data['content'] = ''; 1122 $data['links'] = ''; 1123 $data['overridden'] = FALSE; 1124 $data['defaulted'] = FALSE; 1125 1126 // If there are optional links, build them first so they float properly. 1127 if (!empty($option['links'])) { 1128 foreach ($option['links'] as $link_id => $link_value) { 1129 $data['links'] .= $display->handler->option_link($link_value, $link_id, 'views-button-configure'); 1130 } 1131 } 1132 if (!empty($option['title'])) { 1133 $data['content'] .= $option['title'] . ': '; 1134 } 1135 1136 $data['content'] .= $display->handler->option_link($option['value'], $id, '', empty($option['desc']) ? '' : $option['desc']); 1137 if (!empty($display->handler->options['defaults'][$id])) { 1138 $display_id = 'default'; 1139 $data['defaulted'] = TRUE; 1140 } 1141 else { 1142 $display_id = $display->id; 1143 if (!$display->handler->is_default_display()) { 1144 if ($display->handler->defaultable_sections($id)) { 1145 $data['overridden'] = TRUE; 1146 } 1147 } 1148 } 1149 $data['class'] = views_ui_item_css($display_id . '-' . $id); 1150 if (!empty($view->changed_sections[$display_id . '-' . $id])) { 1151 $data['changed'] = TRUE; 1152 } 1153 } 1154 1155 $vars['categories'] = $categories; 1156 1157 // Add a help icon 1158 if (isset($plugin['help topic'])) { 1159 $vars['display_help_icon'] = theme('advanced_help_topic', $plugin['module'], $plugin['help topic']); 1160 } 1161 else { 1162 $vars['display_help_icon'] = ''; 1163 } 1164 1165 // Fetch style plugin info because it has some effect on how/what we render. 1166 $style_plugin = $display->handler->get_plugin(); 1167 1168 $vars['fields'] = ''; 1169 $vars['fields'] = theme('views_ui_edit_item', 'field', $view, $display, !($style_plugin && $style_plugin->uses_fields())); 1170 $vars['relationships'] = theme('views_ui_edit_item', 'relationship', $view, $display); 1171 $vars['arguments'] = theme('views_ui_edit_item', 'argument', $view, $display); 1172 $vars['filters'] = theme('views_ui_edit_item', 'filter', $view, $display); 1173 $vars['sorts'] = theme('views_ui_edit_item', 'sort', $view, $display); 1174 } 1175 1176 /** 1177 * Generate the summary output for a single display to render in a tab. 1178 */ 1179 function views_ui_display_tab($view, $display) { 1180 if (isset($display->handler)) { 1181 $plugin = $display->handler->definition; 1182 } 1183 if (empty($plugin)) { 1184 $title = isset($display->display_title) ? $display->display_title : t('Invalid'); 1185 return array($title, t("Error: Display @display refers to a plugin named '@plugin', but that plugin doesn't exist!", array('@display' => $display->id, '@plugin' => $display->display_plugin))); 1186 1187 // @todo We can do a better 'plugin does not exist' tab. 1188 } 1189 1190 // The display should always be initialized prior to this call. 1191 if (empty($display->handler)) { 1192 return FALSE; 1193 } 1194 1195 $body = theme('views_ui_edit_tab', $view, $display); 1196 return array($display->display_title, $body); 1197 } 1198 1199 /** 1200 * Add information about a section to a display. 1201 */ 1202 function template_preprocess_views_ui_edit_item(&$vars) { 1203 $type = $vars['type']; 1204 $view = $vars['view']; 1205 $display = $vars['display']; 1206 1207 $types = views_object_types(); 1208 1209 $vars['overridden'] = FALSE; 1210 $vars['defaulted'] = FALSE; 1211 1212 if ($vars['no_fields']) { 1213 $vars['title'] = $types[$type]['title']; 1214 $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type); 1215 $vars['rearrange'] = NULL; 1216 $vars['add'] = NULL; 1217 return; 1218 } 1219 1220 $vars['rearrange'] = l('<span>' . t('Rearrange') . '</span>', "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)); 1221 1222 $vars['add'] = l('<span>' . t('Add') . '</span>', "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)); 1223 1224 if (!$display->handler->is_default_display()) { 1225 if (!$display->handler->is_defaulted($types[$type]['plural'])) { 1226 $vars['overridden'] = TRUE; 1227 } 1228 else { 1229 $vars['defaulted'] = TRUE; 1230 } 1231 } 1232 1233 $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link'))); 1234 // $vars['title'] = l($types[$type]['title'], "admin/build/views/nojs/config-type/$view->name/$display->id/$type", array('attributes' => array('class' => 'views-ajax-link'))); 1235 1236 $fields = array(); 1237 1238 static $relationships = NULL; 1239 if (!isset($relationships)) { 1240 // Get relationship labels 1241 $relationships = array(); 1242 // @todo: get_handlers() 1243 foreach ($display->handler->get_option('relationships') as $id => $relationship) { 1244 $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); 1245 if (empty($handler)) { 1246 continue; 1247 } 1248 $handler->init($view, $relationship); 1249 $relationships[$id] = $handler->label(); 1250 } 1251 } 1252 1253 // @todo: get_handlers() 1254 foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) { 1255 $fields[$id] = array(); 1256 1257 $handler = views_get_handler($field['table'], $field['field'], $type); 1258 if (empty($handler)) { 1259 $fields[$id]['class'] = 'broken'; 1260 $field_name = t('Broken/missing handler: @table > @field', array('@table' => $field['table'], '@field' => $field['field'])); 1261 $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'), 'html' => TRUE)); 1262 $fields[$id]['info'] = ''; 1263 continue; 1264 } 1265 $handler->init($view, $field); 1266 1267 $field_name = $handler->ui_name(TRUE); 1268 if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) { 1269 $field_name = '(' . $relationships[$field['relationship']] . ') ' . $field_name; 1270 } 1271 1272 $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'), 'html' => TRUE)); 1273 $fields[$id]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $id); 1274 if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $id])) { 1275 $fields[$id]['changed'] = TRUE; 1276 } 1277 $fields[$id]['info'] = $handler->admin_summary(); 1278 1279 if ($handler->has_extra_options()) { 1280 $fields[$id]['links'] = l('<span>' . t('Settings') . '</span>', "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)); 1281 } 1282 1283 if ($handler->needs_style_plugin()) { 1284 $style_plugin = views_fetch_plugin_data('style', $handler->options['style_plugin']); 1285 $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin['title']; 1286 $pid = $id . '-style-plugin'; 1287 1288 if (!empty($style_plugin['uses options'])) { 1289 $fields[$pid]['links'] = l('<span>' . t('Change settings for this style') . '</span>', "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)); 1290 } 1291 1292 $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'))))); 1293 $fields[$pid]['class'] = views_ui_item_css($display->id . '-' . $type . '-' . $pid); 1294 if (!empty($view->changed_sections[$display->id . '-' . $type . '-' . $pid])) { 1295 $fields[$pid]['changed'] = TRUE; 1296 } 1297 $fields[$pid]['info'] = ''; 1298 } 1299 } 1300 1301 $vars['fields'] = $fields; 1302 $vars['item_help_icon'] = theme('advanced_help_topic', 'views', $type); 1303 } 1304 1305 /** 1306 * Regenerate the tabs for AJAX updates. 1307 */ 1308 function views_ui_regenerate_tabs(&$view, $display_id = NULL, $object = NULL) { 1309 if (empty($display_id)) { 1310 $displays = array_keys($view->display); 1311 } 1312 elseif (!is_array($display_id)) { 1313 $displays = array($display_id); 1314 if ($display_id != 'default') { 1315 $displays[] = 'default'; 1316 } 1317 } 1318 else { 1319 $displays = $display_id; 1320 } 1321 1322 if (!$view->set_display('default')) { 1323 views_ajax_render(t('Invalid display id found while regenerating tabs')); 1324 } 1325 1326 if (!is_object($object)) { 1327 $object = new stdClass(); 1328 } 1329 1330 $object->replace = array(); 1331 foreach ($displays as $id) { 1332 list($title, $body) = views_ui_display_tab($view, $view->display[$id]); 1333 $object->replace['#views-tab-' . $id] = $body; 1334 $object->replace['#views-tab-title-' . $id] = check_plain($title); 1335 } 1336 1337 if (!empty($view->changed)) { 1338 $object->changed = TRUE; 1339 } 1340 1341 views_ajax_render($object); 1342 } 1343 1344 /** 1345 * Provide standard buttons for the forms to make it easy. Also provide 1346 * a hidden op operator because the forms plugin doesn't seem to properly 1347 * provide which button was clicked. 1348 */ 1349 function views_ui_standard_form_buttons(&$form, &$form_state, $form_id, $name = NULL, $third = NULL, $submit = NULL) { 1350 $form['buttons'] = array( 1351 '#prefix' => '<div class="clear-block"><div class="form-buttons">', 1352 '#suffix' => '</div></div>', 1353 ); 1354 1355 if (empty($name)) { 1356 $name = t('Update'); 1357 } 1358 // remove default validate handler 1359 $form['#validate'] = array(); 1360 1361 if (empty($form_state['ok_button'])) { 1362 // but be sure submit button validates! 1363 $form['buttons']['submit'] = array( 1364 '#type' => 'submit', 1365 '#value' => $name, 1366 '#submit' => array($form_id . '_submit'), 1367 '#validate' => array('views_ui_standard_submit', $form_id . '_validate'), 1368 ); 1369 } 1370 1371 $cancel_submit = function_exists($form_id . '_cancel') ? $form_id . '_cancel' : 'views_ui_standard_cancel'; 1372 $form['buttons']['cancel'] = array( 1373 '#type' => 'submit', 1374 '#value' => empty($form_state['ok_button']) ? t('Cancel') : t('Ok'), 1375 '#submit' => array($cancel_submit), 1376 '#validate' => array(), 1377 ); 1378 1379 if ($third) { 1380 if (empty($submit)) { 1381 $submit = 'third'; 1382 } 1383 $third_submit = function_exists($form_id . '_' . $submit) ? $form_id . '_' . $submit : 'views_ui_standard_cancel'; 1384 1385 $form['buttons'][$submit] = array( 1386 '#type' => 'submit', 1387 '#value' => $third, 1388 '#validate' => array(), 1389 '#submit' => array($third_submit), 1390 ); 1391 } 1392 1393 // Compatibility, to be removed later: 1394 // We used to set these items on the form, but now we want them on the $form_state: 1395 if (isset($form['#title'])) { 1396 $form_state['title'] = $form['#title']; 1397 } 1398 if (isset($form['#help_topic'])) { 1399 $form_state['help_topic'] = $form['#help_topic']; 1400 } 1401 if (isset($form['#help_module'])) { 1402 $form_state['help_module'] = $form['#help_module']; 1403 } 1404 if (isset($form['#url'])) { 1405 $form_state['url'] = $form['#url']; 1406 } 1407 if (isset($form['#js'])) { 1408 if (!empty($form_state['js settings']) && is_array($form_state['js settings'])) { 1409 $form_state['js settings'] = array_merge($form_state['js settings'], $form['#js']); 1410 } 1411 else { 1412 $form_state['js settings'] = $form['#js']; 1413 } 1414 } 1415 if (isset($form['#section'])) { 1416 $form_state['#section'] = $form['#section']; 1417 } 1418 // Finally, we never want these cached -- our object cache does that for us. 1419 $form['#no_cache'] = TRUE; 1420 1421 // If this isn't an ajaxy form, then we want to set the title. 1422 if (!empty($form['#title'])) { 1423 drupal_set_title($form['#title']); 1424 } 1425 views_add_css('views-admin'); 1426 } 1427 1428 /** 1429 * Basic submit handler applicable to all 'standard' forms 1430 */ 1431 function views_ui_standard_submit($form, &$form_state) { 1432 if (!empty($form['#section'])) { 1433 $form_state['view']->changed_sections[$form['#section']] = TRUE; 1434 } 1435 } 1436 1437 /** 1438 * Submit handler for cancel button 1439 */ 1440 function views_ui_standard_cancel($form, &$form_state) { 1441 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; 1442 } 1443 1444 // -------------------------------------------------------------------------- 1445 // Various subforms for editing the pieces of a view. 1446 1447 function views_ui_ajax_forms($key = NULL) { 1448 $forms = array( 1449 'display' => array( 1450 'form_id' => 'views_ui_edit_display_form', 1451 'args' => array('section'), 1452 ), 1453 'remove-display' => array( 1454 'form_id' => 'views_ui_remove_display_form', 1455 'args' => array(), 1456 ), 1457 'config-type' => array( 1458 'form_id' => 'views_ui_config_type_form', 1459 'args' => array('type'), 1460 ), 1461 'rearrange' => array( 1462 'form_id' => 'views_ui_rearrange_form', 1463 'args' => array('type'), 1464 ), 1465 'add-item' => array( 1466 'form_id' => 'views_ui_add_item_form', 1467 'args' => array('type'), 1468 ), 1469 'config-item' => array( 1470 'form_id' => 'views_ui_config_item_form', 1471 'args' => array('type', 'id'), 1472 ), 1473 'config-item-extra' => array( 1474 'form_id' => 'views_ui_config_item_extra_form', 1475 'args' => array('type', 'id'), 1476 ), 1477 'change-style' => array( 1478 'form_id' => 'views_ui_change_style_form', 1479 'args' => array('type', 'id'), 1480 ), 1481 'config-style' => array( 1482 'form_id' => 'views_ui_config_style_form', 1483 'args' => array('type', 'id'), 1484 ), 1485 ); 1486 1487 if ($key) { 1488 return !empty($forms[$key]) ? $forms[$key] : NULL; 1489 } 1490 1491 return $forms; 1492 } 1493 1494 /** 1495 * Build a form identifier that we can use to see if one form 1496 * is the same as another. Since the arguments differ slightly 1497 * we do a lot of spiffy concenation here. 1498 */ 1499 function views_ui_build_identifier($key, $view, $display_id, $args) { 1500 $form = views_ui_ajax_forms($key); 1501 $identifier = implode('-', array($key, $view->name, $display_id)); 1502 1503 foreach ($form['args'] as $id) { 1504 $arg = (!empty($args)) ? array_shift($args) : NULL; 1505 $identifier .= '-' . $arg; 1506 } 1507 return $identifier; 1508 } 1509 1510 /** 1511 * Build up a $form_state object suitable for use with drupal_build_form 1512 * based on known information about a form. 1513 */ 1514 function views_ui_build_form_state($js, $key, &$view, $display_id, $args) { 1515 $form = views_ui_ajax_forms($key); 1516 // Build up form state 1517 $form_state = array( 1518 'form_key' => $key, 1519 'form_id' => $form['form_id'], 1520 'view' => &$view, 1521 'ajax' => $js, 1522 'display_id' => $display_id, 1523 'no_redirect' => TRUE, 1524 ); 1525 1526 foreach ($form['args'] as $id) { 1527 $form_state[$id] = (!empty($args)) ? array_shift($args) : NULL; 1528 } 1529 1530 return $form_state; 1531 } 1532 1533 /** 1534 * Create the URL for one of our standard AJAX forms based upon known 1535 * information about the form. 1536 */ 1537 function views_ui_build_form_url($form_state) { 1538 $form = views_ui_ajax_forms($form_state['form_key']); 1539 $ajax = empty($form_state['ajax']) ? 'nojs' : 'ajax'; 1540 $name = $form_state['view']->name; 1541 $url = "admin/build/views/$ajax/$form_state[form_key]/$name/$form_state[display_id]"; 1542 foreach ($form['args'] as $arg) { 1543 $url .= '/' . $form_state[$arg]; 1544 } 1545 return $url; 1546 } 1547 1548 /** 1549 * Add another form to the stack; clicking 'update' will go to this form 1550 * rather than closing the ajax pad. 1551 */ 1552 function views_ui_add_form_to_stack($key, &$view, $display_id, $args, $top = FALSE) { 1553 if (empty($view->stack)) { 1554 $view->stack = array(); 1555 } 1556 1557 $stack = array(views_ui_build_identifier($key, $view, $display_id, $args), $key, &$view, $display_id, $args); 1558 if ($top) { 1559 array_unshift($view->stack, $stack); 1560 } 1561 else { 1562 $view->stack[] = $stack; 1563 } 1564 } 1565 1566 /** 1567 * Generic entry point to handle forms. 1568 * 1569 * We do this for consistency and to make it easy to chain forms 1570 * together. This only works for forms that use both $view 1571 * and $display_id, so we have a couple of ajax forms that we don't 1572 * use with this system. 1573 */ 1574 function views_ui_ajax_form($js, $key, $view, $display_id) { 1575 $form = views_ui_ajax_forms($key); 1576 if (empty($form)) { 1577 return drupal_not_found(); 1578 } 1579 1580 views_include('ajax'); 1581 $args = func_get_args(); 1582 // Remove the known args 1583 array_splice($args, 0, 4); 1584 1585 $form_state = views_ui_build_form_state($js, $key, $view, $display_id, $args); 1586 // check to see if this is the top form of the stack. If it is, pop 1587 // it off; if it isn't, the user clicked somewhere else and the stack is 1588 // now irrelevant. 1589 if (!empty($view->stack)) { 1590 $identifier = views_ui_build_identifier($key, $view, $display_id, $args); 1591 $top = array_shift($view->stack); 1592 if (array_shift($top) != $identifier) { 1593 $view->stack = array(); 1594 } 1595 } 1596 1597 $output = views_ajax_form_wrapper($form_state['form_id'], $form_state); 1598 1599 if (!$output) { 1600 // Sometimes we need to re-generate the form for multi-step type operations. 1601 $object = NULL; 1602 if (!empty($view->stack)) { 1603 $stack = $view->stack; // copy so the next shift doesn't break the array 1604 $top = array_shift($stack); 1605 $top[0] = $js; // change identifier into $js setting 1606 $form_state = call_user_func_array('views_ui_build_form_state', $top); 1607 $form_state['input'] = array(); // this is a new form, make sure it 1608 // doesn't try to inherit $_POST info. 1609 if (!$js) { 1610 return drupal_goto(views_ui_build_form_url($form_state)); 1611 } 1612 $object = views_ajax_form_wrapper($form_state['form_id'], $form_state); 1613 $object->url = url(views_ui_build_form_url($form_state)); 1614 } 1615 else if (!$js) { 1616 // if nothing on the stack, non-js forms just go back to the main view editor. 1617 return drupal_goto("admin/build/views/edit/$view->name"); 1618 } 1619 // regenerate all tabs because changes to the default tab could ripple. 1620 return views_ui_regenerate_tabs($view, NULL, $object); 1621 } 1622 1623 return ($js) ? views_ajax_render($output) : $output; 1624 } 1625 1626 /** 1627 * AJAX callback to add a display. 1628 */ 1629 function views_ui_add_display($js, $view) { 1630 views_include('ajax'); 1631 $form_state = array( 1632 'view' => &$view, 1633 'ajax' => $js, 1634 ); 1635 1636 $output = views_ajax_form_wrapper('views_ui_add_display_form', $form_state); 1637 1638 if ($js) { 1639 // If we don't have an output object, it was submitted. Set up the submission. 1640 if (empty($output)) { 1641 $id = $form_state['id']; 1642 1643 // Make sure the new display is active 1644 if (!$view->set_display('default')) { 1645 views_ajax_render(t('Unable to initialize default display')); 1646 } 1647 1648 // Render the new display 1649 list($title, $body) = views_ui_display_tab($view, $view->display[$id]); 1650 1651 // Instruct the javascript on the browser to render the new tab. 1652 $output = new stdClass; 1653 $output->tab = array('#views-tab-' . $id => array('title' => $title, 'body' => $body)); 1654 } 1655 // Render the command object. This automatically exits. 1656 views_ajax_render($output); 1657 } 1658 1659 // But the non-js variant will return output if it didn't redirect us. 1660 return $output; 1661 } 1662 1663 /** 1664 * Form to add a display to a view. 1665 */ 1666 function views_ui_add_display_form(&$form_state) { 1667 $view = &$form_state['view']; 1668 1669 $form['display']['display'] = array( 1670 '#type' => 'select', 1671 '#options' => views_fetch_plugin_names('display'), 1672 '#default_value' => 'page', 1673 ); 1674 1675 $form['display']['add_display'] = array( 1676 '#type' => 'submit', 1677 '#value' => t('Add display'), 1678 '#submit' => array('views_ui_add_display_form_submit'), 1679 ); 1680 1681 $form['#id'] = 'views-add-display-form'; 1682 $form['#attributes'] = array('class' => 'views-ajax-form'); 1683 $form['#action'] = url("admin/build/views/nojs/add-display/$view->name"); 1684 1685 return $form; 1686 } 1687 1688 /** 1689 * Submit handler to add a display to a view. 1690 */ 1691 function views_ui_add_display_form_submit($form, &$form_state) { 1692 // Create the new display 1693 $plugin = $form_state['values']['display']; 1694 $form_state['id'] = $form_state['view']->add_display($plugin); 1695 1696 // Store in cache 1697 views_ui_cache_set($form_state['view']); 1698 1699 // Send it back 1700 $form_state['redirect'] = array('admin/build/views/edit/' . $form_state['view']->name, NULL, 'views-tab-' . $form_state['id']); 1701 } 1702 1703 /** 1704 * Form to remove a display from a view. 1705 */ 1706 function views_ui_remove_display_form(&$form_state) { 1707 $view = &$form_state['view']; 1708 $display_id = $form_state['display_id']; 1709 1710 if (empty($view->display[$display_id]->deleted)) { 1711 $form['display'] = array( 1712 '#prefix' => '<div class="display-button remove-display">', 1713 '#suffix' => '</div>', 1714 ); 1715 $form['remove_display'] = array( 1716 '#type' => 'submit', 1717 '#value' => t('Remove display'), 1718 '#submit' => array('views_ui_remove_display_form_submit'), 1719 ); 1720 } 1721 else { 1722 $form['display'] = array( 1723 '#prefix' => '<div class="display-button restore-display">', 1724 '#suffix' => '</div>', 1725 ); 1726 $form['restore_display'] = array( 1727 '#type' => 'submit', 1728 '#value' => t('Restore display'), 1729 '#submit' => array('views_ui_remove_display_form_restore'), 1730 ); 1731 } 1732 $form['#action'] = url("admin/build/views/nojs/remove-display/$view->name/$display_id"); 1733 $form['#attributes'] = array('class' => 'views-ajax-form'); 1734 1735 return $form; 1736 } 1737 1738 /** 1739 * Submit handler to add a remove to a display from a view. 1740 */ 1741 function views_ui_remove_display_form_submit($form, &$form_state) { 1742 // Create the new display 1743 $plugin = views_fetch_plugin_data('display', $form_state['view']->display[$form_state['display_id']]->display_plugin); 1744 if (empty($plugin['no remove'])) { 1745 $id = $form_state['display_id']; 1746 $form_state['view']->display[$id]->deleted = TRUE; 1747 1748 // Store in cache 1749 views_ui_cache_set($form_state['view']); 1750 } 1751 } 1752 1753 /** 1754 * Submit handler to add a restore a removed display to a view. 1755 */ 1756 function views_ui_remove_display_form_restore($form, &$form_state) { 1757 // Create the new display 1758 $id = $form_state['display_id']; 1759 $form_state['view']->display[$id]->deleted = FALSE; 1760 1761 // Store in cache 1762 views_ui_cache_set($form_state['view']); 1763 } 1764 1765 /** 1766 * Page callback to display analysis information on a view. 1767 */ 1768 function views_ui_analyze_view($js, $view) { 1769 views_include('ajax'); 1770 $form_state = array( 1771 'view' => &$view, 1772 'ajax' => $js, 1773 ); 1774 1775 $output = views_ajax_form_wrapper('views_ui_analyze_view_form', $form_state); 1776 1777 if ($js) { 1778 // If we don't have an output object, it was submitted. Set up the submission. 1779 if (empty($output)) { 1780 return views_ui_regenerate_tabs($view); 1781 } 1782 return views_ajax_render($output); 1783 1784 } 1785 return $output; 1786 } 1787 1788 /** 1789 * This form doesn't particularly do much; it's really just providing a link 1790 * but a button seems like it would be nicer here. 1791 * 1792 * It has no submit or anything, as we will never actually submit this form 1793 * where the form is placed. 1794 */ 1795 function views_ui_analyze_view_button(&$form_state, $view) { 1796 $form['#action'] = url("admin/build/views/nojs/analyze/$view->name"); 1797 $form['#attributes'] = array('class' => 'views-ajax-form'); 1798 $form['submit'] = array( 1799 '#type' => 'submit', 1800 '#value' => t('Analyze'), 1801 ); 1802 1803 return $form; 1804 } 1805 1806 /** 1807 * Form constructor callback to display analysis information on a view 1808 */ 1809 function views_ui_analyze_view_form(&$form_state) { 1810 $view = &$form_state['view']; 1811 1812 $form['#title'] = t('View analysis'); 1813 $form['#section'] = 'analyze'; 1814 1815 views_include('analyze'); 1816 $messages = views_analyze_view($view); 1817 1818 $form['analysis'] = array( 1819 '#prefix' => '<div class="form-item">', 1820 '#suffix' => '</div>', 1821 '#value' => views_analyze_format_result($view, $messages), 1822 ); 1823 1824 // Inform the standard button function that we want an OK button. 1825 $form_state['ok_button'] = TRUE; 1826 views_ui_standard_form_buttons($form, $form_state, 'views_ui_analyze_view_form'); 1827 return $form; 1828 } 1829 1830 /** 1831 * Submit handler for views_ui_analyze_view_form 1832 */ 1833 function views_ui_analyze_view_form_submit($form, &$form_state) { 1834 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; 1835 } 1836 1837 /** 1838 * Page callback to edit details of a view. 1839 */ 1840 function views_ui_edit_details($js, $view) { 1841 views_include('ajax'); 1842 $form_state = array( 1843 'view' => &$view, 1844 'ajax' => $js, 1845 ); 1846 1847 $output = views_ajax_form_wrapper('views_ui_edit_details_form', $form_state); 1848 1849 if ($js) { 1850 // If we don't have an output object, it was submitted. Set up the submission. 1851 if (empty($output)) { 1852 return views_ui_regenerate_tabs($view); 1853 } 1854 return views_ajax_render($output); 1855 1856 } 1857 return $output; 1858 } 1859 1860 /** 1861 * Form constructor callback to edit details of a view 1862 */ 1863 function views_ui_edit_details_form(&$form_state) { 1864 $view = &$form_state['view']; 1865 1866 $form['#title'] = t('View details'); 1867 $form['#section'] = 'details'; 1868 1869 $form['description'] = array( 1870 '#type' => 'textfield', 1871 '#title' => t('View description'), 1872 '#description' => t('This description will appear on the Views administrative UI to tell you what the view is about.'), 1873 '#default_value' => $view->description, 1874 ); 1875 1876 $form['tag'] = array( 1877 '#type' => 'textfield', 1878 '#title' => t('View tag'), 1879 '#description' => t('Enter an optional tag for this view; it is used only to help sort views on the administrative page.'), 1880 '#default_value' => $view->tag, 1881 '#autocomplete_path' => 'admin/views/ajax/autocomplete/tag', 1882 ); 1883 1884 views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_details_form'); 1885 return $form; 1886 } 1887 1888 /** 1889 * Submit handler for views_ui_edit_details_form 1890 */ 1891 function views_ui_edit_details_form_submit($form, &$form_state) { 1892 $form_state['view']->description = $form_state['values']['description']; 1893 $form_state['view']->tag = $form_state['values']['tag']; 1894 views_ui_cache_set($form_state['view']); 1895 $form_state['redirect'] = 'admin/build/views/edit/' . $form_state['view']->name; 1896 } 1897 1898 /** 1899 * Form constructor callback to edit display of a view 1900 */ 1901 function views_ui_edit_display_form(&$form_state) { 1902 $view = &$form_state['view']; 1903 $display_id = $form_state['display_id']; 1904 $section = $form_state['section']; 1905 1906 if (!$view->set_display($display_id)) { 1907 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 1908 } 1909 $display = &$view->display[$display_id]; 1910 1911 // Get form from the handler. 1912 $display->handler->options_form($form, $form_state); 1913 $name = NULL; 1914 if (isset($form_state['update_name'])) { 1915 $name = $form_state['update_name']; 1916 } 1917 1918 views_ui_standard_form_buttons($form, $form_state, 'views_ui_edit_display_form', $name); 1919 return $form; 1920 } 1921 1922 /** 1923 * Validate handler for views_ui_edit_display_form 1924 */ 1925 function views_ui_edit_display_form_validate($form, &$form_state) { 1926 $display = &$form_state['view']->display[$form_state['display_id']]; 1927 $display->handler->options_validate($form, $form_state); 1928 } 1929 1930 /** 1931 * Submit handler for views_ui_edit_display_form 1932 */ 1933 function views_ui_edit_display_form_submit($form, &$form_state) { 1934 $display = &$form_state['view']->display[$form_state['display_id']]; 1935 $display->handler->options_submit($form, $form_state); 1936 1937 views_ui_cache_set($form_state['view']); 1938 } 1939 1940 /** 1941 * Override handler for views_ui_edit_display_form 1942 */ 1943 function views_ui_edit_display_form_override($form, &$form_state) { 1944 $display = &$form_state['view']->display[$form_state['display_id']]; 1945 $display->handler->options_override($form, $form_state); 1946 1947 views_ui_cache_set($form_state['view']); 1948 $form_state['rerender'] = TRUE; 1949 $form_state['rebuild'] = TRUE; 1950 } 1951 /** 1952 * Form to config items in the views UI. 1953 */ 1954 function views_ui_config_type_form(&$form_state) { 1955 $view = &$form_state['view']; 1956 $display_id = $form_state['display_id']; 1957 $type = $form_state['type']; 1958 1959 $types = views_object_types(); 1960 if (!$view->set_display($display_id)) { 1961 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 1962 } 1963 $display = &$view->display[$display_id]; 1964 $form['#title'] = check_plain($display->display_title) . ': '; 1965 $form['#title'] .= t('Configure @type', array('@type' => $types[$type]['ltitle'])); 1966 $form['#section'] = $display_id . 'config-item'; 1967 1968 if ($display->handler->defaultable_sections($types[$type]['plural'])) { 1969 $form_state['section'] = $types[$type]['plural']; 1970 $display->handler->add_override_button($form, $form_state, $form_state['section']); 1971 } 1972 1973 if (!empty($types[$type]['options']) && function_exists($types[$type]['options'])) { 1974 $options = $type . '_options'; 1975 $form[$options] = array('#tree' => TRUE); 1976 $types[$type]['options']($form, $form_state); 1977 } 1978 1979 $name = NULL; 1980 if (isset($form_state['update_name'])) { 1981 $name = $form_state['update_name']; 1982 } 1983 1984 views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_type_form', $name); 1985 return $form; 1986 } 1987 1988 /** 1989 * Submit handler for type configuration form 1990 */ 1991 function views_ui_config_type_form_submit($form, &$form_state) { 1992 $types = views_object_types(); 1993 $display = &$form_state['view']->display[$form_state['display_id']]; 1994 1995 // Store in cache 1996 views_ui_cache_set($form_state['view']); 1997 } 1998 1999 /** 2000 * Configure settings particular to filters. 2001 */ 2002 function views_ui_config_filters_form(&$form, &$form_state) { 2003 2004 } 2005 2006 /** 2007 * Form to rearrange items in the views UI. 2008 */ 2009 function views_ui_rearrange_form(&$form_state) { 2010 $view = &$form_state['view']; 2011 $display_id = $form_state['display_id']; 2012 $type = $form_state['type']; 2013 2014 $types = views_object_types(); 2015 if (!$view->set_display($display_id)) { 2016 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2017 } 2018 $display = &$view->display[$display_id]; 2019 $form['#title'] = check_plain($display->display_title) . ': '; 2020 $form['#title'] .= t('Rearrange @type', array('@type' => $types[$type]['ltitle'])); 2021 $form['#section'] = $display_id . 'rearrange-item'; 2022 2023 if ($display->handler->defaultable_sections($types[$type]['plural'])) { 2024 $form_state['section'] = $types[$type]['plural']; 2025 $display->handler->add_override_button($form, $form_state, $form_state['section']); 2026 } 2027 2028 $count = 0; 2029 2030 // Get relationship labels 2031 $relationships = array(); 2032 // @todo: get_handlers() 2033 foreach ($display->handler->get_option('relationships') as $id => $relationship) { 2034 $handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); 2035 if (empty($handler)) { 2036 continue; 2037 } 2038 $handler->init($view, $relationship); 2039 $relationships[$id] = $handler->label(); 2040 } 2041 2042 // @todo: get_handlers() 2043 foreach ($display->handler->get_option($types[$type]['plural']) as $id => $field) { 2044 $form[$id] = array('#tree' => TRUE); 2045 $form[$id]['weight'] = array( 2046 '#type' => 'weight', 2047 '#delta' => 200, 2048 '#default_value' => ++$count, 2049 ); 2050 $handler = views_get_handler($field['table'], $field['field'], $type); 2051 if ($handler) { 2052 $handler->init($view, $field); 2053 $name = $handler->ui_name() . ' ' . $handler->admin_summary(); 2054 if (!empty($field['relationship']) && !empty($relationships[$field['relationship']])) { 2055 $name = '(' . $relationships[$field['relationship']] . ') ' . $name; 2056 } 2057 2058 $form[$id]['name'] = array( 2059 '#value' => $name, 2060 ); 2061 } 2062 else { 2063 $form[$id]['name'] = array('#value' => t('Broken field @id', array('@id' => $id))); 2064 } 2065 $form[$id]['removed'] = array( 2066 '#type' => 'checkbox', 2067 '#id' => 'views-removed-' . $id, 2068 '#attributes' => array('class' => 'views-remove-checkbox'), 2069 '#default_value' => 0, 2070 ); 2071 } 2072 2073 // Add javascript settings that will be added via $.extend for tabledragging 2074 $form['#js']['tableDrag']['arrange']['weight'][0] = array( 2075 'target' => 'weight', 2076 'source' => NULL, 2077 'relationship' => 'sibling', 2078 'action' => 'order', 2079 'hidden' => TRUE, 2080 'limit' => 0, 2081 ); 2082 2083 $name = NULL; 2084 if (isset($form_state['update_name'])) { 2085 $name = $form_state['update_name']; 2086 } 2087 2088 views_ui_standard_form_buttons($form, $form_state, 'views_ui_rearrange_form'); 2089 return $form; 2090 } 2091 2092 /** 2093 * Turn the rearrange form into a proper table 2094 */ 2095 function theme_views_ui_rearrange_form($form) { 2096 $rows = array(); 2097 foreach (element_children($form) as $id) { 2098 if (isset($form[$id]['name'])) { 2099 $row = array(); 2100 $row[] = drupal_render($form[$id]['name']); 2101 $form[$id]['weight']['#attributes']['class'] = 'weight'; 2102 $row[] = drupal_render($form[$id]['weight']); 2103 $row[] = drupal_render($form[$id]['removed']) . l('<span>' . t('Remove') . '</span>', '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)); 2104 2105 $rows[] = array('data' => $row, 'class' => 'draggable', 'id' => 'views-row-' . $id); 2106 } 2107 } 2108 if (empty($rows)) { 2109 $rows[] = array(array('data' => t('No fields available.'), 'colspan' => '2')); 2110 } 2111 2112 $header = array('', t('Weight'), t('Remove')); 2113 drupal_add_tabledrag('arrange', 'order', 'sibling', 'weight'); 2114 $output = drupal_render($form['override']); 2115 $output .= theme('table', $header, $rows, array('id' => 'arrange')); 2116 $output .= drupal_render($form); 2117 return $output; 2118 2119 } 2120 2121 /** 2122 * Submit handler for rearranging form 2123 */ 2124 function views_ui_rearrange_form_submit($form, &$form_state) { 2125 $types = views_object_types(); 2126 $display = &$form_state['view']->display[$form_state['display_id']]; 2127 2128 $old_fields = $display->handler->get_option($types[$form_state['type']]['plural']); 2129 $new_fields = $order = array(); 2130 2131 // Make an array with the weights 2132 foreach ($form_state['values'] as $field => $info) { 2133 // add each value that is a field with a weight to our list, but only if 2134 // it has had its 'removed' checkbox checked. 2135 if (is_array($info) && isset($info['weight']) && empty($info['removed'])) { 2136 $order[$field] = $info['weight']; 2137 } 2138 } 2139 2140 // Sort the array 2141 asort($order); 2142 2143 // Create a new list of fields in the new order. 2144 foreach (array_keys($order) as $field) { 2145 $new_fields[$field] = $old_fields[$field]; 2146 } 2147 $display->handler->set_option($types[$form_state['type']]['plural'], $new_fields); 2148 2149 // Store in cache 2150 views_ui_cache_set($form_state['view']); 2151 } 2152 2153 /** 2154 * Form to add_item items in the views UI. 2155 */ 2156 function views_ui_add_item_form(&$form_state) { 2157 $view = &$form_state['view']; 2158 $display_id = $form_state['display_id']; 2159 $type = $form_state['type']; 2160 2161 if (!$view->set_display($display_id)) { 2162 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2163 } 2164 $display = &$view->display[$display_id]; 2165 2166 $types = views_object_types(); 2167 $form['#title'] = check_plain($display->display_title) . ': '; 2168 $form['#title'] .= t('Add @type', array('@type' => $types[$type]['ltitle'])); 2169 $form['#section'] = $display_id . 'add-item'; 2170 2171 // Figure out all the base tables allowed based upon what the relationships provide. 2172 $base_tables = $view->get_base_tables(); 2173 $options = views_fetch_fields(array_keys($base_tables), $type); 2174 2175 if (!empty($options)) { 2176 $groups = array('all' => t('<All>')); 2177 $form['group'] = array( 2178 '#type' => 'select', 2179 '#title' => t('Groups'), 2180 '#options' => array(), 2181 '#attributes' => array('class' => 'views-master-dependent'), 2182 ); 2183 2184 $form['name'] = array( 2185 '#prefix' => '<div class="views-radio-box form-checkboxes">', 2186 '#suffix' => '</div>', 2187 '#tree' => TRUE, 2188 '#default_value' => 'all', 2189 ); 2190 2191 // Group options first to simplify the DOM objects that Views 2192 // dependent JS will act upon. 2193 $grouped_options = array(); 2194 foreach ($options as $key => $option) { 2195 $group = preg_replace('/[^a-z0-9]/', '-', strtolower($option['group'])); 2196 $groups[$group] = $option['group']; 2197 $grouped_options[$group][$key] = $option; 2198 } 2199 2200 foreach ($grouped_options as $group => $group_options) { 2201 $form['name'][$group . '_start'] = array('#type' => 'markup', '#value' => '<div class="views-dependent-all views-dependent-' . $group . '">'); 2202 foreach ($group_options as $key => $option) { 2203 $form['name'][$key] = array( 2204 '#type' => 'checkbox', 2205 '#title' => t('!group: !field', array('!group' => $option['group'], '!field' => $option['title'])), 2206 '#description' => $option['help'], 2207 '#return_value' => $key, 2208 ); 2209 } 2210 $form['name'][$group . '_end'] = array('#type' => 'markup', '#value' => '</div>'); 2211 } 2212 2213 $form['group']['#options'] = $groups; 2214 } 2215 else { 2216 $form['markup'] = array( 2217 '#value' => '<div class="form-item">' . t('There are no @types available to add.', array('@types' => $types[$type]['ltitle'])) . '</div>', 2218 ); 2219 } 2220 views_ui_standard_form_buttons($form, $form_state, 'views_ui_add_item_form', t('Add')); 2221 2222 return $form; 2223 } 2224 2225 /** 2226 * Submit handler for adding new item(s) to a view. 2227 */ 2228 function views_ui_add_item_form_submit($form, &$form_state) { 2229 $type = $form_state['type']; 2230 $types = views_object_types(); 2231 2232 if (!empty($form_state['values']['name']) && is_array($form_state['values']['name'])) { 2233 // Loop through each of the items that were checked and add them to the view. 2234 foreach (array_keys(array_filter($form_state['values']['name'])) as $field) { 2235 list($table, $field) = explode('.', $field, 2); 2236 $id = $form_state['view']->add_item($form_state['display_id'], $type, $table, $field); 2237 2238 // check to see if this type has settings, if so add the settings form first 2239 $handler = views_get_handler($table, $field, $type); 2240 if ($handler && $handler->has_extra_options()) { 2241 views_ui_add_form_to_stack('config-item-extra', $form_state['view'], $form_state['display_id'], array($type, $id)); 2242 } 2243 // Then add the form to the stack 2244 views_ui_add_form_to_stack('config-item', $form_state['view'], $form_state['display_id'], array($type, $id)); 2245 } 2246 } 2247 2248 // Store in cache 2249 views_ui_cache_set($form_state['view']); 2250 } 2251 2252 2253 /** 2254 * Form to config_item items in the views UI. 2255 */ 2256 function views_ui_config_item_form(&$form_state) { 2257 $view = &$form_state['view']; 2258 $display_id = $form_state['display_id']; 2259 $type = $form_state['type']; 2260 $id = $form_state['id']; 2261 2262 $form = array('options' => array('#tree' => TRUE)); 2263 if (!$view->set_display($display_id)) { 2264 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2265 } 2266 $item = $view->get_item($display_id, $type, $id); 2267 2268 if ($item) { 2269 $handler = views_get_handler($item['table'], $item['field'], $type); 2270 if (empty($handler)) { 2271 $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field']))); 2272 } 2273 else { 2274 $handler->init($view, $item); 2275 $types = views_object_types(); 2276 2277 if ($view->display_handler->defaultable_sections($types[$type]['plural'])) { 2278 $form_state['section'] = $types[$type]['plural']; 2279 $view->display_handler->add_override_button($form['options'], $form_state, $form_state['section']); 2280 } 2281 2282 // A whole bunch of code to figure out what relationships are valid for 2283 // this item. 2284 $relationships = $view->display_handler->get_option('relationships'); 2285 $relationship_options = array(); 2286 2287 foreach ($relationships as $relationship) { 2288 // relationships can't link back to self. But also, due to ordering, 2289 // relationships can only link to prior relationships. 2290 if ($type == 'relationship' && $id == $relationship['id']) { 2291 break; 2292 } 2293 $relationship_handler = views_get_handler($relationship['table'], $relationship['field'], 'relationship'); 2294 // ignore invalid/broken relationships. 2295 if (empty($relationship_handler)) { 2296 continue; 2297 } 2298 2299 // If this relationship is valid for this type, add it to the list. 2300 $data = views_fetch_data($relationship['table']); 2301 $base = $data[$relationship['field']]['relationship']['base']; 2302 $base_fields = views_fetch_fields($base, $form_state['type']); 2303 if (isset($base_fields[$item['table'] . '.' . $item['field']])) { 2304 $relationship_handler->init($view, $relationship); 2305 $relationship_options[$relationship['id']] = $relationship_handler->label(); 2306 } 2307 } 2308 2309 if (!empty($relationship_options)) { 2310 // Make sure the existing relationship is even valid. If not, force 2311 // it to none. 2312 $base_fields = views_fetch_fields($view->base_table, $form_state['type']); 2313 if (isset($base_fields[$item['table'] . '.' . $item['field']])) { 2314 $relationship_options = array_merge(array('none' => t('Do not use a relationship')), $relationship_options); 2315 } 2316 $rel = empty($item['relationship']) ? 'none' : $item['relationship']; 2317 if (empty($relationship_options[$rel])) { 2318 // Pick the first relationship. 2319 $rel = key($relationship_options); 2320 // We want this relationship option to get saved even if the user 2321 // skips submitting the form. 2322 $view->set_item_option($display_id, $type, $id, 'relationship', $rel); 2323 $temp_view = $view->clone_view(); 2324 views_ui_cache_set($temp_view); 2325 } 2326 2327 $form['options']['relationship'] = array( 2328 '#type' => 'select', 2329 '#title' => t('Relationship'), 2330 '#options' => $relationship_options, 2331 '#default_value' => $rel, 2332 ); 2333 } 2334 else { 2335 $form['options']['relationship'] = array( 2336 '#type' => 'value', 2337 '#value' => 'none', 2338 ); 2339 } 2340 2341 $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': '; 2342 $form['#title'] .= t('Configure @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name())); 2343 2344 $form['#section'] = $display_id . '-' . $type . '-' . $id; 2345 2346 // Get form from the handler. 2347 $handler->options_form($form['options'], $form_state); 2348 $form_state['handler'] = &$handler; 2349 } 2350 2351 $name = NULL; 2352 if (isset($form_state['update_name'])) { 2353 $name = $form_state['update_name']; 2354 } 2355 2356 views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_form', $name, t('Remove'), 'remove'); 2357 } 2358 return $form; 2359 } 2360 2361 /** 2362 * Submit handler for configing new item(s) to a view. 2363 */ 2364 function views_ui_config_item_form_validate($form, &$form_state) { 2365 $form_state['handler']->options_validate($form['options'], $form_state); 2366 } 2367 2368 /** 2369 * Submit handler for configing new item(s) to a view. 2370 */ 2371 function views_ui_config_item_form_submit($form, &$form_state) { 2372 // Run it through the handler's submit function. 2373 $form_state['handler']->options_submit($form['options'], $form_state); 2374 $item = $form_state['handler']->options; 2375 2376 // Unset a button 2377 unset($form_state['values']['options']['expose_button']); 2378 2379 // Store the data we're given. 2380 foreach ($form_state['values']['options'] as $key => $value) { 2381 $item[$key] = $value; 2382 } 2383 2384 // Store the item back on the view 2385 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); 2386 2387 $handler = views_get_handler($item['table'], $item['field'], $form_state['type']); 2388 $handler->init($form_state['view'], $item); 2389 if ($handler && $handler->needs_style_plugin()) { 2390 views_ui_add_form_to_stack('change-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE); 2391 } 2392 2393 // Write to cache 2394 views_ui_cache_set($form_state['view']); 2395 } 2396 2397 /** 2398 * Submit handler for removing an item from a view 2399 */ 2400 function views_ui_config_item_form_remove($form, &$form_state) { 2401 // Store the item back on the view 2402 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], NULL); 2403 2404 // Write to cache 2405 views_ui_cache_set($form_state['view']); 2406 } 2407 2408 /** 2409 * Override handler for views_ui_edit_display_form 2410 */ 2411 function views_ui_config_item_form_expose($form, &$form_state) { 2412 $item = &$form_state['handler']->options; 2413 // flip 2414 $item['exposed'] = empty($item['exposed']); 2415 2416 // If necessary, set new defaults: 2417 if ($item['exposed']) { 2418 $form_state['handler']->expose_options(); 2419 } 2420 2421 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); 2422 2423 views_ui_cache_set($form_state['view']); 2424 $form_state['rerender'] = TRUE; 2425 $form_state['rebuild'] = TRUE; 2426 $form_state['force_expose_options'] = TRUE; 2427 } 2428 2429 /** 2430 * Form to config_item items in the views UI. 2431 */ 2432 function views_ui_config_item_extra_form(&$form_state) { 2433 $view = &$form_state['view']; 2434 $display_id = $form_state['display_id']; 2435 $type = $form_state['type']; 2436 $id = $form_state['id']; 2437 2438 $form = array('options' => array('#tree' => TRUE)); 2439 if (!$view->set_display($display_id)) { 2440 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2441 } 2442 $item = $view->get_item($display_id, $type, $id); 2443 2444 if ($item) { 2445 $handler = views_get_handler($item['table'], $item['field'], $type); 2446 if (empty($handler)) { 2447 $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field']))); 2448 break; 2449 } 2450 else { 2451 $handler->init($view, $item); 2452 $types = views_object_types(); 2453 2454 $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': '; 2455 $form['#title'] .= t('Configure extra settings for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name())); 2456 2457 $form['#section'] = $display_id . '-' . $type . '-' . $id; 2458 2459 // Get form from the handler. 2460 $handler->extra_options_form($form['options'], $form_state); 2461 $form_state['handler'] = &$handler; 2462 2463 } 2464 2465 views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_item_extra_form'); 2466 } 2467 return $form; 2468 } 2469 2470 /** 2471 * Submit handler for configing new item(s) to a view. 2472 */ 2473 function views_ui_config_item_extra_form_validate($form, &$form_state) { 2474 $form_state['handler']->extra_options_validate($form['options'], $form_state); 2475 } 2476 2477 /** 2478 * Submit handler for configing new item(s) to a view. 2479 */ 2480 function views_ui_config_item_extra_form_submit($form, &$form_state) { 2481 // Run it through the handler's submit function. 2482 $form_state['handler']->extra_options_submit($form['options'], $form_state); 2483 $item = $form_state['handler']->options; 2484 2485 // Store the data we're given. 2486 foreach ($form_state['values']['options'] as $key => $value) { 2487 $item[$key] = $value; 2488 } 2489 2490 // Store the item back on the view 2491 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); 2492 2493 // Write to cache 2494 views_ui_cache_set($form_state['view']); 2495 } 2496 2497 /** 2498 * Form to change_style items in the views UI. 2499 */ 2500 function views_ui_change_style_form(&$form_state) { 2501 $view = &$form_state['view']; 2502 $display_id = $form_state['display_id']; 2503 $type = $form_state['type']; 2504 $id = $form_state['id']; 2505 2506 $form = array('options' => array('#tree' => TRUE)); 2507 if (!$view->set_display($display_id)) { 2508 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2509 } 2510 $item = $view->get_item($display_id, $type, $id); 2511 2512 if ($item) { 2513 $handler = views_get_handler($item['table'], $item['field'], $type); 2514 if (empty($handler)) { 2515 $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field']))); 2516 break; 2517 } 2518 $handler->init($view, $item); 2519 $types = views_object_types(); 2520 $form['#title'] = t('Change summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name())); 2521 2522 $form['#section'] = $display_id . '-' . $type . '-' . $id . '-style-plugin'; 2523 2524 $form['style_plugin'] = array( 2525 '#type' => 'radios', 2526 '#options' => views_fetch_plugin_names('style', 'summary'), 2527 '#default_value' => $item['style_plugin'], 2528 ); 2529 2530 $form_state['handler'] = &$handler; 2531 2532 views_ui_standard_form_buttons($form, $form_state, 'views_ui_change_style_form'); 2533 } 2534 return $form; 2535 } 2536 2537 function views_ui_change_style_form_validate($form, &$form_state) { 2538 // Run it through the handler's submit function. 2539 $form_state['handler']->options_validate($form['options'], $form_state); 2540 2541 $plugin = views_get_plugin('style', $form_state['values']['style_plugin']); 2542 if (!$plugin) { 2543 form_error($form['style_plugin'], t('Internal error: broken plugin.')); 2544 } 2545 } 2546 2547 /** 2548 * Submit handler for configing new item(s) to a view. 2549 */ 2550 function views_ui_change_style_form_submit($form, &$form_state) { 2551 // Run it through the handler's submit function. 2552 $form_state['handler']->options_submit($form['options'], $form_state); 2553 $item = $form_state['handler']->options; 2554 2555 $plugin = views_get_plugin('style', $form_state['values']['style_plugin']); 2556 if (!$plugin) { 2557 drupal_set_message(t('Internal error: broken plugin.'), 'error'); 2558 return; 2559 } 2560 2561 $plugin->init($form_state['view'], $form_state['view']->display[$form_state['display_id']]); 2562 2563 // If changing style plugin, reset options to defaults. 2564 if (empty($item['style_plugin']) || $item['style_plugin'] != $form_state['values']['style_plugin']) { 2565 $item['style_options'] = $plugin->options; 2566 } 2567 2568 // Store the data we're given. 2569 $item['style_plugin'] = $form_state['values']['style_plugin']; 2570 2571 // Store the item back on the view 2572 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); 2573 2574 if (!empty($plugin->definition['uses options'])) { 2575 views_ui_add_form_to_stack('config-style', $form_state['view'], $form_state['display_id'], array($form_state['type'], $form_state['id']), TRUE); 2576 } 2577 2578 // Write to cache 2579 views_ui_cache_set($form_state['view']); 2580 } 2581 2582 /** 2583 * Form to config_style items in the views UI. 2584 */ 2585 function views_ui_config_style_form(&$form_state) { 2586 $view = &$form_state['view']; 2587 $display_id = $form_state['display_id']; 2588 $type = $form_state['type']; 2589 $id = $form_state['id']; 2590 2591 $form = array('options' => array('#tree' => TRUE)); 2592 if (!$view->set_display($display_id)) { 2593 views_ajax_render(t('Invalid display id @display', array('@display' => $display_id))); 2594 } 2595 $item = $view->get_item($display_id, $type, $id); 2596 2597 if ($item) { 2598 $handler = views_get_handler($item['table'], $item['field'], $type); 2599 if (empty($handler)) { 2600 $form['markup'] = array('#value' => t("Error: handler for @table > @field doesn't exist!", array('@table' => $item['table'], '@field' => $item['field']))); 2601 break; 2602 } 2603 $handler->init($view, $item); 2604 $types = views_object_types(); 2605 2606 $form['#title'] = check_plain($view->display[$display_id]->display_title) . ': '; 2607 $form['#title'] .= t('Configure summary style for @type %item', array('@type' => $types[$type]['lstitle'], '%item' => $handler->ui_name())); 2608 2609 $form['#section'] = $display_id . '-' . $type . '-style-options'; 2610 2611 $plugin = views_get_plugin('style', $item['style_plugin']); 2612 if ($plugin) { 2613 $form['style_options'] = array( 2614 '#tree' => TRUE, 2615 ); 2616 $plugin->init($view, $view->display[$display_id], $item['style_options']); 2617 2618 $plugin->options_form($form['style_options'], $form_state); 2619 } 2620 2621 $form_state['handler'] = &$handler; 2622 2623 views_ui_standard_form_buttons($form, $form_state, 'views_ui_config_style_form'); 2624 } 2625 return $form; 2626 } 2627 2628 /** 2629 * Submit handler for configing new item(s) to a view. 2630 */ 2631 function views_ui_config_style_form_submit($form, &$form_state) { 2632 // Run it through the handler's submit function. 2633 $form_state['handler']->options_submit($form['style_options'], $form_state); 2634 $item = $form_state['handler']->options; 2635 2636 // Store the data we're given. 2637 $item['style_options'] = $form_state['values']['style_options']; 2638 2639 // Store the item back on the view 2640 $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); 2641 2642 // Write to cache 2643 views_ui_cache_set($form_state['view']); 2644 } 2645 2646 /** 2647 * Get a list of roles in the system. 2648 */ 2649 function views_ui_get_roles() { 2650 static $roles = NULL; 2651 if (!isset($roles)) { 2652 $roles = array(); 2653 $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name"); 2654 while ($obj = db_fetch_object($result)) { 2655 $roles[$obj->rid] = $obj->name; 2656 } 2657 } 2658 2659 return $roles; 2660 } 2661 2662 /** 2663 * Get a css safe id for a particular section. 2664 */ 2665 function views_ui_item_css($item) { 2666 return views_css_safe('views-item-' . $item); 2667 } 2668 2669 /** 2670 * Page callback for the Views enable page. 2671 */ 2672 function views_ui_enable_page($view) { 2673 if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-enable')) { 2674 $views_status = variable_get('views_defaults', array()); 2675 $views_status[$view->name] = FALSE; // false is enabled 2676 variable_set('views_defaults', $views_status); 2677 views_invalidate_cache(); 2678 menu_rebuild(); 2679 drupal_goto('admin/build/views'); 2680 } 2681 else { 2682 return drupal_access_denied(); 2683 } 2684 } 2685 2686 /** 2687 * Page callback for the Views enable page 2688 */ 2689 function views_ui_disable_page($view) { 2690 if (isset($_GET['token']) && drupal_valid_token($_GET['token'], 'views-disable')) { 2691 $views_status = variable_get('views_defaults', array()); 2692 $views_status[$view->name] = TRUE; // True is disabled 2693 variable_set('views_defaults', $views_status); 2694 views_invalidate_cache(); 2695 menu_rebuild(); 2696 drupal_goto('admin/build/views'); 2697 } 2698 else { 2699 return drupal_access_denied(); 2700 } 2701 } 2702 2703 /** 2704 * Page callback for the tools - other page 2705 */ 2706 function views_ui_admin_tools() { 2707 $form['clear_cache'] = array( 2708 '#type' => 'submit', 2709 '#value' => t("Clear Views' cache"), 2710 '#submit' => array('views_ui_tools_clear_cache'), 2711 ); 2712 2713 $form['views_sql_signature'] = array( 2714 '#type' => 'checkbox', 2715 '#title' => t('Add Views signature to all SQL queries'), 2716 '#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."), 2717 '#default_value' => variable_get('views_sql_signature', FALSE), 2718 ); 2719 2720 $form['views_skip_cache'] = array( 2721 '#type' => 'checkbox', 2722 '#title' => t('Disable views data caching'), 2723 '#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."), 2724 '#default_value' => variable_get('views_skip_cache', FALSE), 2725 ); 2726 2727 $form['views_hide_help_message'] = array( 2728 '#type' => 'checkbox', 2729 '#title' => t('Ignore missing advanced help module'), 2730 '#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."), 2731 '#default_value' => variable_get('views_hide_help_message', FALSE), 2732 ); 2733 2734 $form['views_ui_query_on_top'] = array( 2735 '#type' => 'checkbox', 2736 '#title' => t('Show query above live preview'), 2737 '#description' => t("The live preview feature will show you the output of the view you're creating, as well as the view. Check here to show the query and other information above the view; leave this unchecked to show that information below the view."), 2738 '#default_value' => variable_get('views_ui_query_on_top', FALSE), 2739 ); 2740 2741 $form['views_ui_disable_live_preview'] = array( 2742 '#type' => 'checkbox', 2743 '#title' => t('Disable automatic live preview'), 2744 '#description' => t("Don't automatically update the preview. This can speed up the editing of views a bit.'"), 2745 '#default_value' => variable_get('views_ui_disable_live_preview', 0), 2746 ); 2747 2748 $form['views_show_additional_queries'] = array( 2749 '#type' => 'checkbox', 2750 '#title' => t('Show other queries run during render during live preview'), 2751 '#description' => t("Drupal has the potential to run many queries while a view is being rendered. Checking this box will display every query run during view render as part of the live preview."), 2752 '#default_value' => variable_get('views_show_additional_queries', FALSE), 2753 ); 2754 2755 $form['views_no_hover_links'] = array( 2756 '#type' => 'checkbox', 2757 '#title' => t('Do not show hover links over views'), 2758 '#description' => t("To make it easier to administrate your views, Views provides 'hover' links to take you to the edit and export screen of a view whenever the view is used. This can be distracting on some themes, though; if it is problematic, you can turn it off here."), 2759 '#default_value' => variable_get('views_no_hover_links', FALSE), 2760 ); 2761 2762 $form['views_devel_output'] = array( 2763 '#type' => 'checkbox', 2764 '#title' => t('Enable views performance statistics via the Devel module'), 2765 '#description' => t("Check this to enable some Views query and performance statistics <em>if Devel is installed</em>."), 2766 '#default_value' => variable_get('views_devel_output', FALSE), 2767 ); 2768 2769 $form['views_no_javascript'] = array( 2770 '#type' => 'checkbox', 2771 '#title' => t('Disable javascript with Views'), 2772 '#description' => t("If you are having problems with the javascript, you can disable it here; the Views UI should degrade and still be usable without javascript, it just not as good."), 2773 '#default_value' => variable_get('views_no_javascript', FALSE), 2774 ); 2775 2776 $regions = system_region_list(variable_get('theme_default', 'garland')); 2777 $regions['watchdog'] = t('Watchdog'); 2778 2779 $form['views_devel_region'] = array( 2780 '#type' => 'select', 2781 '#title' => t('Page region to output performance statistics'), 2782 '#default_value' => variable_get('views_devel_region', 'footer'), 2783 '#options' => $regions, 2784 ); 2785 2786 $form['views_exposed_filter_any_label'] = array( 2787 '#type' => 'select', 2788 '#title' => t('Label for "Any" value on optional single-select exposed filters'), 2789 '#options' => array('old_any' => '<Any>', 'new_any' => t('- Any -')), 2790 '#default_value' => variable_get('views_exposed_filter_any_label', 'old_any'), 2791 ); 2792 2793 return system_settings_form($form); 2794 } 2795 2796 /** 2797 * Submit hook to clear the views cache. 2798 */ 2799 function views_ui_tools_clear_cache() { 2800 views_invalidate_cache(); 2801 drupal_set_message(t('The cache has been cleared.')); 2802 } 2803 2804 /** 2805 * Submit hook to clear Drupal's theme registry (thereby triggering 2806 * a templates rescan). 2807 */ 2808 function views_ui_config_item_form_rescan($form, &$form_state) { 2809 drupal_rebuild_theme_registry(); 2810 2811 // The 'Theme: Information' page is about to be shown again. That page 2812 // analyzes the output of theme_get_registry(). However, this latter 2813 // function uses an internal cache (which was initialized before we 2814 // called drupal_rebuild_theme_registry()) so it won't reflect the 2815 // current state of our theme registry. The only way to clear that cache 2816 // is to re-initialize the theme system: 2817 unset($GLOBALS['theme']); 2818 init_theme(); 2819 2820 $form_state['rerender'] = TRUE; 2821 $form_state['rebuild'] = TRUE; 2822 } 2823 2824 /** 2825 * Override handler for views_ui_edit_display_form 2826 */ 2827 function views_ui_edit_display_form_change_theme($form, &$form_state) { 2828 // This is just a temporary variable. 2829 $form_state['view']->theme = $form_state['values']['theme']; 2830 2831 views_ui_cache_set($form_state['view']); 2832 $form_state['rerender'] = TRUE; 2833 $form_state['rebuild'] = TRUE; 2834 } 2835 2836 /** 2837 * Page callback for views tag autocomplete 2838 */ 2839 function views_ui_autocomplete_tag($string = '') { 2840 $matches = array(); 2841 // get matches from default views: 2842 views_include('view'); 2843 $views = views_discover_default_views(); 2844 foreach ($views as $view) { 2845 if (!empty($view->tag) && strpos($view->tag, $string) === 0) { 2846 $matches[$view->tag] = $view->tag; 2847 } 2848 } 2849 2850 if ($string) { 2851 $result = db_query_range("SELECT DISTINCT tag FROM {views_view} WHERE LOWER(tag) LIKE LOWER('%s%%')", $string, 0, 10 - count($matches)); 2852 while ($view = db_fetch_object($result)) { 2853 $matches[$view->tag] = check_plain($view->tag); 2854 } 2855 } 2856 2857 drupal_json($matches); 2858 } 2859 2860 // ------------------------------------------------------------------ 2861 // Get information from the Views data 2862 2863 function _views_weight_sort($a, $b) { 2864 if ($a['weight'] != $b['weight']) { 2865 return $a['weight'] < $b['weight'] ? -1 : 1; 2866 } 2867 if ($a['title'] != $b['title']) { 2868 return $a['title'] < $b['title'] ? -1 : 1; 2869 } 2870 2871 return 0; 2872 } 2873 2874 /** 2875 * Fetch a list of all base tables available 2876 * 2877 * @return 2878 * A keyed array of in the form of 'base_table' => 'Description'. 2879 */ 2880 function views_fetch_base_tables() { 2881 static $base_tables = array(); 2882 if (empty($base_tables)) { 2883 $weights = array(); 2884 $tables = array(); 2885 $data = views_fetch_data(); 2886 foreach ($data as $table => $info) { 2887 if (!empty($info['table']['base'])) { 2888 $tables[$table] = array( 2889 'title' => $info['table']['base']['title'], 2890 'description' => $info['table']['base']['help'], 2891 'weight' => !empty($info['table']['base']['weight']) ? $info['table']['base']['weight'] : 0, 2892 ); 2893 } 2894 } 2895 uasort($tables, '_views_weight_sort'); 2896 $base_tables = $tables; 2897 } 2898 2899 return $base_tables; 2900 } 2901 2902 function _views_sort_types($a, $b) { 2903 if ($a['group'] != $b['group']) { 2904 return $a['group'] < $b['group'] ? -1 : 1; 2905 } 2906 2907 if ($a['title'] != $b['title']) { 2908 return $a['title'] < $b['title'] ? -1 : 1; 2909 } 2910 2911 return 0; 2912 } 2913 2914 /** 2915 * Fetch a list of all fields available for a given base type. 2916 * 2917 * @return 2918 * A keyed array of in the form of 'base_table' => 'Description'. 2919 */ 2920 function views_fetch_fields($base, $type) { 2921 static $fields = array(); 2922 if (empty($fields)) { 2923 $data = views_fetch_data(); 2924 $start = views_microtime(); 2925 // This constructs this ginormous multi dimensional array to 2926 // collect the important data about fields. In the end, 2927 // the structure looks a bit like this (using nid as an example) 2928 // $strings['nid']['filter']['title'] = 'string'. 2929 // 2930 // This is constructed this way because the above referenced strings 2931 // can appear in different places in the actual data structure so that 2932 // the data doesn't have to be repeated a lot. This essentially lets 2933 // each field have a cheap kind of inheritance. 2934 2935 foreach ($data as $table => $table_data) { 2936 $bases = array(); 2937 $strings = array(); 2938 $skip_bases = array(); 2939 foreach ($table_data as $field => $info) { 2940 // Collect table data from this table 2941 if ($field == 'table') { 2942 // calculate what tables this table can join to. 2943 if (!empty($info['join'])) { 2944 $bases = array_keys($info['join']); 2945 } 2946 // And it obviously joins to itself. 2947 $bases[] = $table; 2948 continue; 2949 } 2950 foreach (array('field', 'sort', 'filter', 'argument', 'relationship') as $key) { 2951 if (!empty($info[$key])) { 2952 if (!empty($info[$key]['skip base'])) { 2953 foreach ((array) $info[$key]['skip base'] as $base_name) { 2954 $skip_bases[$field][$key][$base_name] = TRUE; 2955 } 2956 } 2957 elseif (!empty($info['skip base'])) { 2958 foreach ((array) $info['skip base'] as $base_name) { 2959 $skip_bases[$field][$key][$base_name] = TRUE; 2960 } 2961 } 2962 foreach (array('title', 'group', 'help', 'base') as $string) { 2963 // First, try the lowest possible level 2964 if (!empty($info[$key][$string])) { 2965 $strings[$field][$key][$string] = $info[$key][$string]; 2966 } 2967 // Then try the field level 2968 elseif (!empty($info[$string])) { 2969 $strings[$field][$key][$string] = $info[$string]; 2970 } 2971 // Finally, try the table level 2972 elseif (!empty($table_data['table'][$string])) { 2973 $strings[$field][$key][$string] = $table_data['table'][$string]; 2974 } 2975 else { 2976 if ($string != 'base') { 2977 $strings[$field][$key][$string] = t("Error: missing @component", array('@component' => $string)); 2978 } 2979 } 2980 } 2981 } 2982 } 2983 } 2984 foreach ($bases as $base_name) { 2985 foreach ($strings as $field => $field_strings) { 2986 foreach ($field_strings as $type_name => $type_strings) { 2987 if (empty($skip_bases[$field][$type_name][$base_name])) { 2988 $fields[$base_name][$type_name]["$table.$field"] = $type_strings; 2989 } 2990 } 2991 } 2992 } 2993 } 2994 // vsm('Views UI data build time: ' . (views_microtime() - $start) * 1000 . ' ms'); 2995 } 2996 2997 // If we have an array of base tables available, go through them 2998 // all and add them together. Duplicate keys will be lost and that's 2999 // Just Fine. 3000 if (is_array($base)) { 3001 $strings = array(); 3002 foreach ($base as $base_table) { 3003 if (isset($fields[$base_table][$type])) { 3004 $strings += $fields[$base_table][$type]; 3005 } 3006 } 3007 uasort($strings, '_views_sort_types'); 3008 return $strings; 3009 } 3010 3011 if (isset($fields[$base][$type])) { 3012 uasort($fields[$base][$type], '_views_sort_types'); 3013 return $fields[$base][$type]; 3014 } 3015 return array(); 3016 } 3017 3018 /** 3019 * Fetch a list of all base tables available 3020 * 3021 * @param $type 3022 * Either 'display', 'style' or 'row' 3023 * @param $key 3024 * For style plugins, this is an optional type to restrict to. May be 'normal', 3025 * 'summary', 'feed' or others based on the neds of the display. 3026 * @param $base 3027 * An array of possible base tables. 3028 * 3029 * @return 3030 * A keyed array of in the form of 'base_table' => 'Description'. 3031 */ 3032 function views_fetch_plugin_names($type, $key = NULL, $base = array()) { 3033 $data = views_fetch_plugin_data(); 3034 3035 $plugins[$type] = array(); 3036 3037 foreach ($data[$type] as $id => $plugin) { 3038 // Skip plugins that don't conform to our key. 3039 if ($key && (empty($plugin['type']) || $plugin['type'] != $key)) { 3040 continue; 3041 } 3042 if (empty($plugin['no ui']) && (empty($base) || empty($plugin['base']) || array_intersect($base, $plugin['base']))) { 3043 $plugins[$type][$id] = $plugin['title']; 3044 } 3045 } 3046 3047 if (!empty($plugins[$type])) { 3048 asort($plugins[$type]); 3049 return $plugins[$type]; 3050 } 3051 // fall-through 3052 return array(); 3053 } 3054 3055 3056 /** 3057 * Theme the form for the table style plugin 3058 */ 3059 function theme_views_ui_style_plugin_table($form) { 3060 $output = drupal_render($form['description_markup']); 3061 3062 $header = array( 3063 t('Field'), 3064 t('Column'), 3065 t('Separator'), 3066 array( 3067 'data' => t('Sortable'), 3068 'align' => 'center', 3069 ), 3070 array( 3071 'data' => t('Default sort'), 3072 'align' => 'center', 3073 ), 3074 ); 3075 $rows = array(); 3076 foreach (element_children($form['columns']) as $id) { 3077 $row = array(); 3078 $row[] = drupal_render($form['info'][$id]['name']); 3079 $row[] = drupal_render($form['columns'][$id]); 3080 $row[] = drupal_render($form['info'][$id]['separator']); 3081 if (!empty($form['info'][$id]['sortable'])) { 3082 $row[] = array( 3083 'data' => drupal_render($form['info'][$id]['sortable']), 3084 'align' => 'center', 3085 ); 3086 $row[] = array( 3087 'data' => drupal_render($form['default'][$id]), 3088 'align' => 'center', 3089 ); 3090 } 3091 else { 3092 $row[] = ''; 3093 $row[] = ''; 3094 } 3095 $rows[] = $row; 3096 } 3097 3098 // Add the special 'None' row. 3099 $rows[] = array(t('None'), '', '', '', array('align' => 'center', 'data' => drupal_render($form['default'][-1]))); 3100 3101 $output .= theme('table', $header, $rows); 3102 $output .= drupal_render($form); 3103 return $output; 3104 } 3105
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |