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