| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: page_manager.admin.inc,v 1.27.2.18 2010/10/29 22:40:52 merlinofchaos Exp $ 3 4 /** 5 * @file 6 * Administrative functions for the page manager. 7 * 8 * This provides the UI to list, create, edit and delete pages, though much 9 * of this is delegated through to individual tasks. 10 */ 11 12 /** 13 * Output a list of pages that are managed. 14 */ 15 function page_manager_list_page($js = NULL) { 16 // Prevent this page from showing up when random other links fail. 17 if ($js && $js != 'ajax' && $js != 'nojs') { 18 return drupal_not_found(); 19 } 20 21 // TRUE if 'ajax', FALSE if otherwise. 22 $js = $js == 'ajax'; 23 24 if (module_exists('advanced_help') && !$js) { 25 drupal_set_message(theme('advanced_help_topic', 'page_manager', 'getting-started', t('See the getting started guide for more information.'))); 26 } 27 28 $tasks = page_manager_get_tasks_by_type('page'); 29 $pages = array('operations' => array(), 'tasks' => array()); 30 31 page_manager_get_pages($tasks, $pages); 32 33 // Add lock icon to all locked tasks. 34 global $user; 35 ctools_include('object-cache'); 36 $locks = ctools_object_cache_test_objects('page_manager_page', $pages['tasks']); 37 foreach ($locks as $task_name => $lock) { 38 if ($lock->uid == $user->uid) { 39 $pages['rows'][$task_name]['class'] .= ' page-manager-locked'; 40 $pages['rows'][$task_name]['title'] = t('This page is currently locked for editing by you. Nobody else may edit this page until these changes are saved or canceled.'); 41 } 42 else { 43 $pages['rows'][$task_name]['class'] .= ' page-manager-locked-other'; 44 $pages['rows'][$task_name]['title'] = t('This page is currently locked for editing by another user. You may not edit this page without breaking the lock.'); 45 } 46 } 47 48 $input = $_POST; 49 50 // Respond to a reset command by clearing session and doing a drupal goto 51 // back to the base URL. 52 if (isset($input['op']) && $input['op'] == t('Reset')) { 53 unset($_SESSION['page_manager']['#admin']); 54 if (!$js) { 55 return drupal_goto($_GET['q']); 56 } 57 // clear everything but form id, form build id and form token: 58 $keys = array_keys($input); 59 foreach ($keys as $id) { 60 if ($id != 'form_id' && $id != 'form_build_id' && $id != 'form_token') { 61 unset($input[$id]); 62 } 63 } 64 $replace_form = TRUE; 65 } 66 if (count($input) <= 1) { 67 if (isset($_SESSION['page_manager']['#admin']) && is_array($_SESSION['page_manager']['#admin'])) { 68 $input = $_SESSION['page_manager']['#admin']; 69 } 70 } 71 else { 72 $_SESSION['page_manager']['#admin'] = $input; 73 unset($_SESSION['page_manager']['#admin']['q']); 74 } 75 76 $form_state = array( 77 'pages' => &$pages, 78 'input' => $input, 79 'rerender' => TRUE, 80 'no_redirect' => TRUE, 81 ); 82 83 // This form will sort and filter the pages. 84 ctools_include('form'); 85 $form = ctools_build_form('page_manager_list_pages_form', $form_state); 86 87 $header = array( 88 array('data' => t('Type'), 'class' => 'page-manager-page-type'), 89 array('data' => t('Name'), 'class' => 'page-manager-page-name'), 90 array('data' => t('Title'), 'class' => 'page-manager-page-title'), 91 array('data' => t('Path'), 'class' => 'page-manager-page-path'), 92 array('data' => t('Storage'), 'class' => 'page-manager-page-storage'), 93 ); 94 95 $header[] = array('data' => t('Operations'), 'class' => 'page-manager-page-operations'); 96 $table = theme('table', $header, $pages['rows'], array('id' => 'page-manager-list-pages')); 97 98 $operations = '<div id="page-manager-links" class="links">' . theme('links', $pages['operations']) . '</div>'; 99 100 drupal_add_css(drupal_get_path('module', 'page_manager') . '/css/page-manager.css'); 101 102 if (!$js) { 103 return $form . $table . $operations; 104 } 105 106 ctools_include('ajax'); 107 $commands = array(); 108 $commands[] = ctools_ajax_command_replace('#page-manager-list-pages', $table); 109 if (!empty($replace_form)) { 110 $commands[] = ctools_ajax_command_replace('#page-manager-list-pages-form', $form); 111 } 112 ctools_ajax_render($commands); 113 } 114 115 /** 116 * Sort tasks into buckets based upon whether or not they have subtasks. 117 */ 118 function page_manager_get_pages($tasks, &$pages, $task_id = NULL) { 119 foreach ($tasks as $id => $task) { 120 if (empty($task_id) && !empty($task['page operations'])) { 121 $pages['operations'] = array_merge($pages['operations'], $task['page operations']); 122 } 123 124 // If a type has subtasks, add its subtasks in its own table. 125 if (!empty($task['subtasks'])) { 126 page_manager_get_pages(page_manager_get_task_subtasks($task), $pages, $task['name']); 127 continue; 128 } 129 130 if (isset($task_id)) { 131 $task_name = page_manager_make_task_name($task_id, $task['name']); 132 } 133 else { 134 $task_name = $task['name']; 135 } 136 137 $class = 'page-task-' . $id; 138 if (isset($task['row class'])) { 139 $class .= ' ' . $task['row class']; 140 } 141 142 if (!empty($task['disabled'])) { 143 $class .= ' page-manager-disabled'; 144 } 145 146 $path = array(); 147 $visible_path = ''; 148 if (!empty($task['admin path'])) { 149 foreach (explode('/', $task['admin path']) as $bit) { 150 if ($bit[0] != '!') { 151 $path[] = $bit; 152 } 153 } 154 155 $path = implode('/', $path); 156 if (empty($task['disabled']) && strpos($path, '%') === FALSE) { 157 $visible_path = l('/' . $task['admin path'], $path); 158 } 159 else { 160 $visible_path = '/' . $task['admin path']; 161 } 162 } 163 164 $row = array('data' => array(), 'class' => $class, 'title' => strip_tags($task['admin description'])); 165 166 $type = isset($task['admin type']) ? $task['admin type'] : t('System'); 167 $pages['types'][$type] = $type; 168 $row['data']['type'] = array('data' => $type, 'class' => 'page-manager-page-type'); 169 170 $row['data']['name'] = array('data' => $task_name, 'class' => 'page-manager-page-name'); 171 $row['data']['title'] = array('data' => $task['admin title'], 'class' => 'page-manager-page-title'); 172 $row['data']['path'] = array('data' => $visible_path, 'class' => 'page-manager-page-path'); 173 174 $storage = isset($task['storage']) ? $task['storage'] : t('In code'); 175 $pages['storages'][$storage] = $storage; 176 $row['data']['storage'] = array('data' => $storage, 'class' => 'page-manager-page-storage'); 177 178 179 /* 180 if (empty($task['disabled'])) { 181 $item = menu_get_item($path); 182 if (empty($item)) { 183 dsm($path); 184 } 185 else { 186 dsm($item); 187 } 188 } 189 */ 190 $operations = array( 191 array( 192 'title' => t('Edit'), 193 'href' => page_manager_edit_url($task_name), 194 ), 195 ); 196 197 if (!empty($task['enable callback'])) { 198 if (!empty($task['disabled'])) { 199 $operations[] = array( 200 'title' => t('Enable'), 201 'href' => 'admin/build/pages/nojs/enable/' . $task_name, 202 'query' => array('token' => drupal_get_token($task_name)), 203 ); 204 } 205 else { 206 $operations[] = array( 207 'title' => t('Disable'), 208 'href' => 'admin/build/pages/nojs/disable/' . $task_name, 209 'query' => array('token' => drupal_get_token($task_name)), 210 ); 211 } 212 } 213 214 $row['data']['operations'] = array('data' => theme('links', $operations), 'class' => 'page-manager-page-operations'); 215 216 $pages['disabled'][$task_name] = !empty($task['disabled']); 217 $pages['tasks'][] = $task_name; 218 $pages['rows'][$task_name] = $row; 219 } 220 } 221 222 /** 223 * Provide a form for sorting and filtering the list of pages. 224 */ 225 function page_manager_list_pages_form(&$form_state) { 226 // This forces the form to *always* treat as submitted which is 227 // necessary to make it work. 228 if (empty($_POST)) { 229 $form["#programmed"] = TRUE; 230 } 231 $form['#action'] = url('admin/build/pages/nojs/', array('absolute' => TRUE)); 232 if (!variable_get('clean_url', FALSE)) { 233 $form['q'] = array( 234 '#type' => 'hidden', 235 '#value' => $_GET['q'], 236 ); 237 } 238 239 $all = array('all' => t('<All>')); 240 241 $form['type'] = array( 242 '#type' => 'select', 243 '#title' => t('Type'), 244 '#options' => $all + $form_state['pages']['types'], 245 '#default_value' => 'all', 246 ); 247 248 $form['storage'] = array( 249 '#type' => 'select', 250 '#title' => t('Storage'), 251 '#options' => $all + $form_state['pages']['storages'], 252 '#default_value' => 'all', 253 ); 254 255 $form['disabled'] = array( 256 '#type' => 'select', 257 '#title' => t('Enabled'), 258 '#options' => $all + array('0' => t('Enabled'), '1' => t('Disabled')), 259 '#default_value' => 'all', 260 ); 261 262 $form['search'] = array( 263 '#type' => 'textfield', 264 '#title' => t('Search'), 265 ); 266 267 $form['order'] = array( 268 '#type' => 'select', 269 '#title' => t('Sort by'), 270 '#options' => array( 271 'disabled' => t('Enabled, title'), 272 'title' => t('Title'), 273 'name' => t('Name'), 274 'path' => t('Path'), 275 'type' => t('Type'), 276 'storage' => t('Storage'), 277 ), 278 '#default_value' => 'disabled', 279 ); 280 281 $form['sort'] = array( 282 '#type' => 'select', 283 '#title' => t('Order'), 284 '#options' => array( 285 'asc' => t('Up'), 286 'desc' => t('Down'), 287 ), 288 '#default_value' => 'asc', 289 ); 290 291 $form['submit'] = array( 292 '#name' => '', // so it won't in the $_GET args 293 '#type' => 'submit', 294 '#id' => 'edit-pages-apply', 295 '#value' => t('Apply'), 296 '#attributes' => array('class' => 'ctools-use-ajax'), 297 ); 298 299 $form['reset'] = array( 300 '#type' => 'submit', 301 '#id' => 'edit-pages-reset', 302 '#value' => t('Reset'), 303 '#attributes' => array('class' => 'ctools-use-ajax'), 304 ); 305 306 ctools_add_js('ajax-responder'); 307 drupal_add_js('misc/jquery.form.js'); 308 drupal_add_js(drupal_get_path('module', 'page_manager') . '/js/page-list.js'); 309 $form['#theme'] = array('page_manager_list_pages_form'); 310 return $form; 311 } 312 313 /** 314 * Accept submission from the page manager sort/filter form and apply it 315 * to the list of pages. 316 */ 317 function page_manager_list_pages_form_submit(&$form, &$form_state) { 318 // Filter and re-sort the pages. 319 320 // This is a copy. 321 $rows = $form_state['pages']['rows']; 322 323 $sorts = array(); 324 foreach ($rows as $name => $data) { 325 // Filter 326 if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $data['data']['type']['data']) { 327 continue; 328 } 329 330 if ($form_state['values']['storage'] != 'all' && $form_state['values']['storage'] != $data['data']['storage']['data']) { 331 continue; 332 } 333 334 if ($form_state['values']['disabled'] != 'all' && $form_state['values']['disabled'] != $form_state['pages']['disabled'][$name]) { 335 continue; 336 } 337 338 if ($form_state['values']['search'] && 339 strpos($data['data']['name']['data'], $form_state['values']['search']) === FALSE && 340 strpos($data['data']['path']['data'], $form_state['values']['search']) === FALSE && 341 strpos($data['data']['title']['data'], $form_state['values']['search']) === FALSE) { 342 continue; 343 } 344 // Set up sorting 345 switch ($form_state['values']['order']) { 346 case 'disabled': 347 $sorts[$name] = !$form_state['pages']['disabled'][$name] . $data['data']['title']['data']; 348 break; 349 case 'title': 350 $sorts[$name] = $data['data']['title']['data']; 351 break; 352 case 'name': 353 $sorts[$name] = $data['data']['name']['data']; 354 break; 355 case 'path': 356 $sorts[$name] = $data['data']['path']['data']; 357 break; 358 case 'type': 359 $sorts[$name] = $data['data']['type']['data']; 360 break; 361 case 'storage': 362 $sorts[$name] = $data['data']['storage']['data']; 363 break; 364 } 365 } 366 367 // Now actually sort 368 if ($form_state['values']['sort'] == 'desc') { 369 arsort($sorts); 370 } 371 else { 372 asort($sorts); 373 } 374 375 // Nuke the original. 376 $form_state['pages']['rows'] = array(); 377 // And restore. 378 foreach ($sorts as $name => $title) { 379 $form_state['pages']['rows'][$name] = $rows[$name]; 380 } 381 382 } 383 384 /** 385 * Render the edit page for a a page, custom or system. 386 */ 387 function page_manager_edit_page($page) { 388 ctools_include('form'); 389 drupal_set_title($page->subtask['admin title']); 390 // Provide and process the save page form before anything else. 391 $form_state = array('page' => &$page); 392 $form = ctools_build_form('page_manager_save_page_form', $form_state); 393 394 $operations = page_manager_get_operations($page); 395 $args = array('summary'); 396 $rendered_operations = page_manager_render_operations($page, $operations, $args, array('class' => 'operations-main'), 'nav'); 397 $content = page_manager_get_operation_content(FALSE, $page, $args, $operations); 398 399 $output = theme('page_manager_edit_page', $page, $form, $rendered_operations, $content); 400 return $output; 401 } 402 403 /** 404 * Entry point to edit a single operation for a page. 405 * 406 * @param $js 407 * Whether or not the page was called via javascript. 408 * @param $page 409 * The cached page that is being edited. 410 * @param ... 411 * A number of items used to drill down into the actual operation called. 412 */ 413 function page_manager_edit_page_operation() { 414 $args = func_get_args(); 415 $js = array_shift($args); 416 $page = array_shift($args); 417 418 $operations = page_manager_get_operations($page); 419 $content = page_manager_get_operation_content($js, $page, $args, $operations); 420 421 // If the operation requested we go somewhere else afterward, oblige it. 422 if (isset($content['new trail'])) { 423 $args = $content['new trail']; 424 // Get operations again, for the operation may have changed their availability. 425 $operations = page_manager_get_operations($page); 426 $content = page_manager_get_operation_content($js, $page, $args, $operations); 427 } 428 429 // Rendering the content may have been a form submission that changed the 430 // operations, such as renaming or adding a handler. Thus we get a new set 431 // of operations. 432 $operations = page_manager_get_operations($page); 433 $rendered_operations = page_manager_render_operations($page, $operations, $args, array('class' => 'operations-main'), 'nav'); 434 435 // Since this form should never be submitted to this page, process it late so 436 // that we can be sure it notices changes. 437 ctools_include('form'); 438 $form_state = array('page' => &$page); 439 $form = ctools_build_form('page_manager_save_page_form', $form_state); 440 441 $output = theme('page_manager_edit_page', $page, $form, $rendered_operations, $content); 442 443 if ($js) { 444 $commands = array(); 445 if (isset($content['js settings'])) { 446 $commands[] = ctools_ajax_command_settings($content['js settings']); 447 } 448 $commands[] = ctools_ajax_command_replace('#page-manager-edit', $output); 449 450 ctools_ajax_render($commands); 451 } 452 453 drupal_set_title($page->subtask['admin title']); 454 return $output; 455 } 456 457 /** 458 * Take the operations array from a task and expand it. 459 * 460 * This allows some of the operations to be dynamic, based upon settings 461 * on the task or the task's handlers. Each operation should have a type. In 462 * addition to all the types allowed in page_manager_render_operations, these 463 * types will be dynamically replaced with something else: 464 * - 'handlers': An automatically created group that contains all the task's 465 * handlers and appropriate links. 466 * - 'function': A callback (which will be placed in the 'function' parameter 467 * that should return an array of operations. This can be used to provide 468 * additional, dynamic links if needed. 469 */ 470 function page_manager_get_operations($page, $operations = NULL) { 471 if (!isset($operations)) { 472 // All tasks have at least these 2 ops: 473 $operations = array( 474 'summary' => array( 475 'title' => t('Summary'), 476 'description' => t('Get a summary of the information about this page.'), 477 'path' => 'admin/build/pages/edit', 478 'ajax' => FALSE, 479 'no operations' => TRUE, 480 'form info' => array( 481 'no buttons' => TRUE, 482 ), 483 'form' => 'page_manager_page_summary', 484 ), 485 'actions' => array( 486 'type' => 'group', 487 'title' => '', 488 'class' => 'operations-actions', 489 'location' => 'primary', 490 'children' => array(), 491 ), 492 ); 493 494 if (isset($page->subtask['operations'])) { 495 $operations += $page->subtask['operations']; 496 // add actions separately. 497 if (!empty($page->subtask['operations']['actions'])) { 498 $operations['actions']['children'] += $page->subtask['operations']['actions']['children']; 499 } 500 } 501 $operations['handlers'] = array('type' => 'handlers'); 502 } 503 504 $result = array(); 505 foreach ($operations as $id => $operation) { 506 if (empty($operation['type'])) { 507 $operation['type'] = 'operation'; 508 } 509 switch ($operation['type']) { 510 case 'handlers': 511 $result[$id] = page_manager_get_handler_operations($page); 512 break; 513 case 'function': 514 if (function_exists($operation['function'])) { 515 $retval = $function($page, $operation); 516 if (is_array($retval)) { 517 $result[$id] = $retval; 518 } 519 } 520 break; 521 default: 522 $result[$id] = $operation; 523 } 524 } 525 526 if (!empty($page->subtask['enable callback']) && !empty($page->subtask['disabled']) && empty($result['actions']['children']['enable'])) { 527 $result['actions']['children']['enable'] = array( 528 'title' => t('Enable'), 529 'description' => t('Activate this page so that it will be in use in your system.'), 530 'form' => 'page_manager_enable_form', 531 'ajax' => FALSE, 532 'silent' => TRUE, 533 'no update and save' => TRUE, 534 'form info' => array( 535 'finish text' => t('Enable'), 536 ), 537 ); 538 } 539 540 if (!empty($page->subtask['enable callback']) && empty($page->subtask['disabled']) && empty($result['actions']['children']['disable'])) { 541 $result['actions']['children']['disable'] = array( 542 'title' => t('Disable'), 543 'description' => t('De-activate this page. The data will remain but the page will not be in use on your system.'), 544 'form' => 'page_manager_disable_form', 545 'ajax' => FALSE, 546 'silent' => TRUE, 547 'no update and save' => TRUE, 548 'form info' => array( 549 'finish text' => t('Disable'), 550 ), 551 ); 552 } 553 554 $result['actions']['children']['add'] = array( 555 'title' => t('Add variant'), 556 'description' => t('Add a new variant to this page.'), 557 'form' => 'page_manager_handler_add', 558 'ajax' => FALSE, 559 'silent' => TRUE, // prevents a message about updating and prevents this item from showing as changed. 560 'no update and save' => TRUE, // get rid of update and save button which is bad here. 561 'form info' => array( 562 'finish text' => t('Create variant'), 563 ), 564 ); 565 566 // Restrict variant import to users who can already execute arbitrary PHP 567 if (user_access('use PHP for block visibility')) { 568 $result['actions']['children']['import'] = array( 569 'title' => t('Import variant'), 570 'description' => t('Add a new variant to this page from code exported from another page.'), 571 'form' => 'page_manager_handler_import', 572 ); 573 } 574 575 if (count($page->handlers) > 1) { 576 $result['actions']['children']['rearrange'] = array( 577 'title' => t('Reorder variants'), 578 'ajax' => FALSE, 579 'description' => t('Change the priority of the variants to ensure that the right one gets selected.'), 580 'form' => 'page_manager_handler_rearrange', 581 ); 582 } 583 584 // This is a special operation used to configure a new task handler before 585 // it is added. 586 if (isset($page->new_handler)) { 587 $plugin = page_manager_get_task_handler($page->new_handler->handler); 588 $result['actions']['children']['configure'] = array( 589 'title' => t('Configure'), 590 'description' => t('Configure a newly created variant prior to actually adding it to the page.'), 591 'ajax' => FALSE, 592 'no update and save' => TRUE, // get rid of update and save button which is bad here. 593 'form info' => array( 594 // We use our own cancel and finish callback to handle the fun stuff. 595 'finish callback' => 'page_manager_handler_add_finish', 596 'cancel callback' => 'page_manager_handler_add_cancel', 597 'show trail' => TRUE, 598 'show back' => TRUE, 599 'finish text' => t('Create variant'), 600 ), 601 'form' => array( 602 'forms' => $plugin['forms'], 603 ), 604 ); 605 606 foreach ($page->forms as $id) { 607 if (isset($plugin['add features'][$id])) { 608 $result['actions']['children']['configure']['form']['order'][$id] = $plugin['add features'][$id]; 609 } 610 else if (isset($plugin['required forms'][$id])) { 611 $result['actions']['children']['configure']['form']['order'][$id] = $plugin['required forms'][$id]; 612 } 613 } 614 } 615 616 if ($page->locked) { 617 $result['actions']['children']['break-lock'] = array( 618 'title' => t('Break lock'), 619 'description' => t('Break the lock on this page so that you can edit it.'), 620 'form' => 'page_manager_break_lock', 621 'ajax' => FALSE, 622 'no update and save' => TRUE, // get rid of update and save button which is bad here. 623 'form info' => array( 624 'finish text' => t('Break lock'), 625 ), 626 'even locked' => TRUE, // show button even if locked 627 'silent' => TRUE, 628 ); 629 } 630 631 drupal_alter('page_manager_operations', $result, $page); 632 return $result; 633 } 634 635 /** 636 * Collect all the operations related to task handlers (variants) and 637 * build a menu. 638 */ 639 function page_manager_get_handler_operations(&$page) { 640 ctools_include('export'); 641 $group = array( 642 'type' => 'group', 643 'class' => 'operations-handlers', 644 'title' => t('Variants'), 645 ); 646 647 $operations = array(); 648 649 // If there is only one variant, let's not have it collapsible. 650 $collapsible = count($page->handler_info) != 1; 651 foreach ($page->handler_info as $id => $info) { 652 if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) { 653 continue; 654 } 655 $handler = $page->handlers[$id]; 656 $plugin = page_manager_get_task_handler($handler->handler); 657 658 $operations[$id] = array( 659 'type' => 'group', 660 'class' => 'operations-handlers-' . $id, 661 'title' => page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id), 662 'collapsible' => $collapsible, 663 'children' => array(), 664 ); 665 666 $operations[$id]['children']['actions'] = array( 667 'type' => 'group', 668 'class' => 'operations-handlers-actions-' . $id, 669 'title' => t('Variant operations'), 670 'children' => array(), 671 'location' => $id, 672 ); 673 674 // There needs to be a 'summary' item here for variants. 675 $operations[$id]['children']['summary'] = array( 676 'title' => t('Summary'), 677 'description' => t('Get a summary of the information about this variant.'), 678 'form info' => array( 679 'no buttons' => TRUE, 680 ), 681 'form' => 'page_manager_handler_summary', 682 ); 683 684 if ($plugin && isset($plugin['operations'])) { 685 $operations[$id]['children'] += $plugin['operations']; 686 } 687 688 $actions = &$operations[$id]['children']['actions']['children']; 689 690 $actions['clone'] = array( 691 'title' => t('Clone'), 692 'description' => t('Make an exact copy of this variant.'), 693 'form' => 'page_manager_handler_clone', 694 ); 695 $actions['export'] = array( 696 'title' => t('Export'), 697 'description' => t('Export this variant into code to import into another page.'), 698 'form' => 'page_manager_handler_export', 699 ); 700 if ($handler->export_type == (EXPORT_IN_CODE | EXPORT_IN_DATABASE)) { 701 $actions['delete'] = array( 702 'title' => t('Revert'), 703 'description' => t('Remove all changes to this variant and revert to the version in code.'), 704 'form' => 'page_manager_handler_delete', 705 'no update and save' => TRUE, 706 'form info' => array( 707 'finish text' => t('Revert'), 708 ), 709 ); 710 } 711 else if ($handler->export_type != EXPORT_IN_CODE) { 712 $actions['delete'] = array( 713 'title' => t('Delete'), 714 'description' => t('Remove this variant from the page completely.'), 715 'form' => 'page_manager_handler_delete', 716 'form info' => array( 717 'finish text' => t('Delete'), 718 'save text' => t('Delete and save'), 719 ), 720 ); 721 } 722 if (!empty($handler->disabled)) { 723 $actions['enable'] = array( 724 'title' => t('Enable'), 725 'description' => t('Activate this variant so that it will be in use in your system.'), 726 'form' => 'page_manager_handler_enable', 727 'silent' => TRUE, 728 'form info' => array( 729 'finish text' => t('Enable'), 730 'save text' => t('Enable and save'), 731 ), 732 ); 733 } 734 else { 735 $actions['disable'] = array( 736 'title' => t('Disable'), 737 'description' => t('De-activate this variant. The data will remain but the variant will not be in use on your system.'), 738 'form' => 'page_manager_handler_disable', 739 'silent' => TRUE, 740 'form info' => array( 741 'finish text' => t('Disable'), 742 'save text' => t('Disable and save'), 743 ), 744 ); 745 } 746 747 drupal_alter('page_manager_variant_operations', $operations[$id], $handler); 748 } 749 if (empty($operations)) { 750 $operations['empty'] = array( 751 'type' => 'text', 752 'title' => t('No variants'), 753 ); 754 } 755 756 $group['children'] = $operations; 757 return $group; 758 } 759 760 /** 761 * Get an operation from a trail. 762 * 763 * @return array($operation, $active, $args) 764 */ 765 function page_manager_get_operation($operations, $trail) { 766 $args = $trail; 767 $stop = FALSE; 768 $active = array(); 769 $titles = array(); 770 // Drill down into operations array: 771 while (!$stop) { 772 $check = reset($args); 773 $stop = TRUE; 774 if (is_array($operations)) { 775 if (isset($operations[$check])) { 776 $active[] = $check; 777 $operation = array_shift($args); 778 // check to see if this operation has children. If so, we continue. 779 if (!isset($operations[$check]['children'])) { 780 $operations = $operations[$check]; 781 } 782 else { 783 $titles[] = $operations[$check]['title']; 784 $operations = $operations[$check]['children']; 785 // continue only if the operation hs children. 786 $stop = FALSE; 787 } 788 } 789 } 790 } 791 792 return array($operations, $active, $args, $titles); 793 } 794 795 /** 796 * Fetch the content for an operation. 797 * 798 * First, this drills down through the arguments to find the operation, and 799 * turns whatever it finds into the active trail which is then used to 800 * hilite where we are when rendering the operation list. 801 * 802 * The arguments are discovered from the URL, and are an exact match for where 803 * the operation is in the hierarchy. For example, handlers/foo/settings will 804 * be the operation to edit the settings for the handler named foo. This comes 805 * in as an array ('handlers', 'foo', 'settings') and is used to find where the 806 * data for that operation is in the array. 807 */ 808 function page_manager_get_operation_content($js, &$page, $trail, $operations) { 809 list($operation, $active, $args, $titles) = page_manager_get_operation($operations, $trail); 810 // Once we've found the operation, send it off to render. 811 if ($operation) { 812 $content = _page_manager_get_operation_content($js, $page, $active, $operation, $titles, $args); 813 } 814 815 if (empty($content)) { 816 $content = _page_manager_get_operation_content($js, $page, array('summary'), $operations['summary']); 817 } 818 819 return $content; 820 } 821 822 /** 823 * Fetch the content for an operation, after it's been discovered from arguments. 824 * 825 * This system runs through the CTools form wizard. Each operation specifies a form 826 * or set of forms that it may use. Operations may also specify wrappers and can 827 * set their own next/finish handlers so that they can make additional things happen 828 * at the end. 829 */ 830 function _page_manager_get_operation_content($js, &$page, $active, $operation, $titles = array(), $args = array()) { 831 if (isset($operation['form'])) { 832 $form_info = array( 833 'id' => 'page_manager_page', 834 'finish text' => t('Update'), 835 'show trail' => FALSE, 836 'show back' => FALSE, 837 'show return' => FALSE, 838 'show cancel' => FALSE, 839 'next callback' => 'page_manager_edit_page_next', 840 'finish callback' => 'page_manager_edit_page_finish', 841 // Items specific to the 'edit' routines that will get moved over: 842 'path' => page_manager_edit_url($page->task_name, $active) . "/%step", 843 // wrapper function to add an extra finish button. 844 'wrapper' => 'page_manager_operation_wrapper', 845 ); 846 847 // If $operation['form'] is simply a string, then it is the function 848 // name of the form. 849 if (!is_array($operation['form'])) { 850 $form_info['order'] = array( 851 'form' => $operation['title'], 852 ); 853 $form_info['forms'] = array( 854 'form' => array('form id' => $operation['form']), 855 ); 856 if (isset($operation['wrapper'])) { 857 $form_info['forms']['form']['wrapper'] = $operation['wrapper']; 858 } 859 } 860 // Otherwise it's the order and forms arrays directly. 861 else { 862 $form_info['order'] = $operation['form']['order']; 863 $form_info['forms'] = $operation['form']['forms']; 864 } 865 866 // Allow the operation to override any form info settings: 867 if (isset($operation['form info'])) { 868 foreach ($operation['form info'] as $key => $setting) { 869 $form_info[$key] = $setting; 870 } 871 } 872 873 if (!empty($page->subtask['operations include'])) { 874 // Quickly load any files necessary to display the forms. 875 $page->subtask['operations include']['function'] = 'nop'; 876 ctools_plugin_get_function($page->subtask, 'operations include'); 877 } 878 879 $step = array_shift($args); 880 // If step is unset, go with the basic step. 881 if (!isset($step)) { 882 $step = current(array_keys($form_info['order'])); 883 } 884 885 // If it is locked, hide the buttonzzz! 886 if ($page->locked && empty($operation['even locked'])) { 887 $form_info['no buttons'] = TRUE; 888 } 889 890 ctools_include('wizard'); 891 $form_state = array( 892 'page' => $page, 893 'type' => 'edit', 894 'ajax' => $js && (!isset($operation['ajax']) || !empty($operation['ajax'])), 895 'rerender' => TRUE, 896 'trail' => $active, 897 'task_name' => $page->task_name, 898 'task_id' => $page->task_id, 899 'task' => $page->task, 900 'subtask_id' => $page->subtask_id, 901 'subtask' => $page->subtask, 902 'operation' => $operation, 903 ); 904 905 if ($active && $active[0] == 'handlers' && isset($form_state['page']->handlers[$form_state['trail'][1]])) { 906 $form_state['handler_id'] = $form_state['trail'][1]; 907 $form_state['handler'] = &$form_state['page']->handlers[$form_state['handler_id']]; 908 } 909 910 if ($active && $active[0] == 'actions' && $active[1] == 'configure' && isset($form_state['page']->new_handler)) { 911 $form_state['handler_id'] = $form_state['page']->new_handler->name; 912 $form_state['handler'] = &$form_state['page']->new_handler; 913 } 914 915 $output = ctools_wizard_multistep_form($form_info, $step, $form_state); 916 $title = empty($form_state['title']) ? $operation['title'] : $form_state['title']; 917 $titles[] = $title; 918 $title = implode(' » ', array_filter($titles)); 919 if (isset($form_state['js settings'])) { 920 $js_settings = $form_state['js settings']; 921 } 922 923 // If there are messages for the form, render them. 924 if ($messages = theme('status_messages')) { 925 $output = $messages . $output; 926 } 927 928 $description = isset($operation['admin description']) ? $operation['admin description'] : (isset($operation['description']) ? $operation['description'] : ''); 929 $return = array( 930 'title' => $title, 931 'content' => $output, 932 'description' => $description, 933 ); 934 935 // Append any extra content, used for the preview which is submitted then 936 // rendered. 937 if (isset($form_state['content'])) { 938 $return['content'] .= $form_state['content']; 939 } 940 941 // If the form wanted us to go somewhere else next, pass that along. 942 if (isset($form_state['new trail'])) { 943 $return['new trail'] = $form_state['new trail']; 944 } 945 } 946 else { 947 $return = array( 948 'title' => t('Error'), 949 'content' => t('This operation trail does not exist.'), 950 ); 951 } 952 953 if (isset($js_settings)) { 954 $return['js settings'] = $js_settings; 955 } 956 957 $return['active'] = $active; 958 return $return; 959 } 960 961 function page_manager_operation_wrapper(&$form, &$form_state) { 962 if (empty($form_state['operation']['no update and save']) && !empty($form['buttons']['return']['#wizard type']) && $form['buttons']['return']['#wizard type']) { 963 $form['buttons']['save'] = array( 964 '#type' => 'submit', 965 '#value' => !empty($form_state['form_info']['save text']) ? $form_state['form_info']['save text'] : t('Update and save'), 966 '#wizard type' => 'finish', 967 '#attributes' => $form['buttons']['return']['#attributes'], 968 '#save' => TRUE, 969 ); 970 } 971 } 972 973 /** 974 * Callback generated when the an operation edit finished. 975 */ 976 function page_manager_edit_page_finish(&$form_state) { 977 if (empty($form_state['operation']['silent'])) { 978 if (empty($form_state['clicked_button']['#save'])) { 979 drupal_set_message(t('The page has been updated. Changes will not be permanent until you save.')); 980 } 981 else { 982 drupal_set_message(t('The page has been updated and saved.')); 983 } 984 $path = array(); 985 foreach ($form_state['trail'] as $operation) { 986 $path[] = $operation; 987 $form_state['page']->changes[implode('/', $path)] = TRUE; 988 } 989 } 990 991 // If a handler was modified, set it to changed so we know to overwrite it. 992 if (isset($form_state['handler_id'])) { 993 $form_state['page']->handler_info[$form_state['handler_id']]['changed'] |= PAGE_MANAGER_CHANGED_CACHED; 994 } 995 996 // While we make buttons go away on locked pages, it is still possible to 997 // have a lock a appear while you were editing, and have your changes 998 // disappear. This at least warns the user that this has happened. 999 if (!empty($page->locked)) { 1000 drupal_set_message(t('Unable to update changes due to lock.')); 1001 } 1002 1003 // If the 'Update and Save' button was selected, write our cache out. 1004 if (!empty($form_state['clicked_button']['#save'])) { 1005 page_manager_save_page_cache($form_state['page']); 1006 page_manager_clear_page_cache($form_state['page']->task_name); 1007 $form_state['page'] = page_manager_get_page_cache($form_state['page']->task_name); 1008 } 1009 else { 1010 if (empty($form_state['do not cache'])) { 1011 page_manager_set_page_cache($form_state['page']); 1012 } 1013 } 1014 1015 // We basically always want to force a rerender when the forms 1016 // are finished, so make sure there is a new trail. 1017 if (empty($form_state['new trail'])) { 1018 // force a rerender to get rid of old form items that may have changed 1019 // during save. 1020 $form_state['new trail'] = $form_state['trail']; 1021 } 1022 1023 if (isset($form_state['new trail']) && empty($form_state['ajax'])) { 1024 $form_state['redirect'] = page_manager_edit_url($form_state['page']->task_name, $form_state['new trail']); 1025 } 1026 1027 $form_state['complete'] = TRUE; 1028 } 1029 1030 /** 1031 * Callback generated when the 'next' button is clicked. 1032 * 1033 * All we do here is store the cache. 1034 */ 1035 function page_manager_edit_page_next(&$form_state) { 1036 page_manager_set_page_cache($form_state['page']); 1037 } 1038 1039 /** 1040 * Callback generated when the 'cancel' button is clicked. 1041 * 1042 * All we do here is clear the cache. 1043 */ 1044 function page_manager_edit_page_cancel(&$form_state) { 1045 $page = $form_state['page']; 1046 } 1047 1048 /** 1049 * Render an operations array. 1050 * 1051 * This renders an array of operations into a series of nested UL statements, 1052 * with ajax automatically on unless specified otherwise. Operations will 1053 * automatically have the URLs generated nested. 1054 * 1055 * Each operation should have a 'type', which tells the renderer how to deal 1056 * with it: 1057 * - 'operation': An AJAX link to render. This is the default and is 1058 * assumed if a type is not specified. Other fields for the operation: 1059 * - - 'title': The text to display. Can be an image. Must be pre-sanitized. 1060 * - - 'description': Text to place in the hover box over the link using the 1061 * title attribute. 1062 * - - 'arguments': Anything optional to put at the end of the URL. 1063 * - - 'path': If set, overrides the default path. 1064 * - - 'no operations': If set, the path will not have operations appended. 1065 * - - 'no task': If set, the path will not have the task id. 1066 * - - 'no link': If set, this item will just be text, not a link. 1067 * - - 'ajax': If set to TRUE, ajax will be used. The default is TRUE. 1068 * - - 'class': An optional class to specify for the link. 1069 * - - 'form': The form to display for this operation, if using a single form. 1070 * - - 'forms': An array of forms that must be paired with 'order' of this 1071 * operation uses multiple forms. See wizard tool for details. 1072 * - - 'order': The form order to use for multiple forms. See wizard tool for 1073 * details. 1074 * - - 'form info': Form info overrides for the wizard. See the wizard tool 1075 * for available settings 1076 * - 'group': 1077 * - - 'title': The title of the link. May be HTML. 1078 * - - 'title class': A class to apply to the title. 1079 * - - 'children': An array of more operations that this group represents. 1080 * All operations within this group will have this group's ID as part 1081 * of the AJAX url to make it easier to find. 1082 * - - 'class': A class to apply to the UL of the children. 1083 * - - 'collapsible': If TRUE the collapsible tool will be used. 1084 */ 1085 function page_manager_render_operations(&$page, $operations, $active_trail, $attributes, $location, $parents = array()) { 1086 if (!isset($output[$location])) { 1087 $output[$location] = ''; 1088 } 1089 1090 $keys = array_keys($operations); 1091 $first = array_shift($keys); 1092 $last = array_pop($keys); 1093 1094 // Make sure the 'first' and 'last' operations are part of THIS nav tree: 1095 while ($keys && isset($operations[$first]['location']) && $operations[$first]['location'] != $location) { 1096 $first = array_shift($keys); 1097 } 1098 while ($keys && isset($operations[$last]['location']) && $operations[$last]['location'] != $location) { 1099 $last = array_pop($keys); 1100 } 1101 1102 $active = reset($active_trail); 1103 foreach ($operations as $id => $operation) { 1104 $current_path = ''; 1105 if ($parents) { 1106 $current_path .= implode('/', $parents) . '/'; 1107 } 1108 $current_path .= $id; 1109 1110 if (empty($operation['type'])) { 1111 $operation['type'] = 'operation'; 1112 } 1113 1114 // We only render an li for things in the same nav tree. 1115 if (empty($operation['location']) || $operation['location'] == $location) { 1116 $class = $attributes['class']; 1117 if ($id == $first) { 1118 $class .= ' operation-first'; 1119 } 1120 else if ($id == $last) { 1121 $class .= ' operation-last'; 1122 } 1123 1124 if (empty($operation['silent']) && !empty($page->changes[$current_path])) { 1125 $class .= $operation['type'] == 'group' ? ' changed-group' : ' changed'; 1126 } 1127 else { 1128 $class .= ' not-changed'; 1129 } 1130 1131 if ($active == $id) { 1132 $class .= $operation['type'] == 'group' ? ' active-group' : ' active'; 1133 } 1134 else { 1135 $class .= ' not-active'; 1136 } 1137 1138 $output[$location] .= '<li class="' . $class . '">'; 1139 } 1140 1141 switch ($operation['type']) { 1142 case 'text': 1143 $output[$location] .= $operation['title']; 1144 break; 1145 case 'operation': 1146 $path = isset($operation['path']) ? $operation['path'] : 'admin/build/pages/nojs/operation'; 1147 if (!isset($operation['no task'])) { 1148 $path .= '/' . $page->task_name; 1149 } 1150 1151 if (!isset($operation['no operations'])) { 1152 $path .= '/' . $current_path; 1153 if (isset($operation['arguments'])) { 1154 $path .= '/' . $arguments; 1155 } 1156 } 1157 1158 $class = 'page-manager-operation'; 1159 if (!isset($operation['ajax']) || !empty($operation['ajax'])) { 1160 $class .= ' ctools-use-ajax'; 1161 } 1162 if (!empty($operation['class'])) { 1163 $class .= ' ' . $operation['class']; 1164 } 1165 1166 $description = isset($operation['description']) ? $operation['description'] : ''; 1167 if (empty($operation['silent']) && !empty($page->changes[$current_path])) { 1168 $description .= ' ' . t('This setting contains unsaved changes.'); 1169 } 1170 1171 $output[$location] .= l($operation['title'], $path, array('attributes' => array('id' => 'page-manager-operation-' . $id, 'class' => $class, 'title' => $description), 'html' => TRUE)); 1172 break; 1173 case 'group': 1174 if ($active == $id) { 1175 $trail = $active_trail; 1176 array_shift($trail); 1177 } 1178 else { 1179 $trail = array(); 1180 } 1181 $group_location = isset($operation['location']) ? $operation['location'] : $location; 1182 $temp = page_manager_render_operations($page, $operation['children'], $trail, $operation, $group_location, array_merge($parents, array($id))); 1183 if ($temp) { 1184 foreach ($temp as $id => $text) { 1185 if (empty($output[$id])) { 1186 $output[$id] = ''; 1187 } 1188 $output[$id] .= $text; 1189 } 1190 } 1191 break; 1192 } 1193 1194 if (empty($operation['location']) || $operation['location'] == $location) { 1195 $output[$location] .= '</li>'; 1196 } 1197 } 1198 1199 if ($output[$location]) { 1200 $output[$location] = '<ul class="page-manager-operations ' . $attributes['class'] . '">' . $output[$location] . '</ul>'; 1201 1202 if (!empty($attributes['title'])) { 1203 $class = ''; 1204 if (isset($attributes['title class'])) { 1205 $class = $attributes['title class']; 1206 } 1207 $title = '<div class="page-manager-group-title' . $class . '">' . $attributes['title'] . '</div>'; 1208 1209 if (!empty($attributes['collapsible'])) { 1210 $output[$location] = theme('ctools_collapsible', $title, $output[$location], empty($active_trail)); 1211 } 1212 else { 1213 $output[$location] = $title . $output[$location]; 1214 } 1215 } 1216 return $output; 1217 } 1218 } 1219 1220 /** 1221 * Provide a simple form for saving the page manager info out of the cache. 1222 */ 1223 function page_manager_save_page_form(&$form_state) { 1224 if (!empty($form_state['page']->changed)) { 1225 $form['markup'] = array( 1226 '#value' => '<div class="changed-notification">' . t('You have unsaved changes to this page. You must select Save to write them to the database, or Cancel to discard these changes. Please note that if you have changed any form, you must submit that form before saving.') . '</div>', 1227 ); 1228 1229 // Always make sure we submit back to the proper page. 1230 $form['#action'] = url('admin/build/pages/edit/' . $form_state['page']->task_name); 1231 $form['save'] = array( 1232 '#type' => 'submit', 1233 '#value' => t('Save'), 1234 '#submit' => array('page_manager_save_page_form_submit'), 1235 ); 1236 1237 $form['cancel'] = array( 1238 '#type' => 'submit', 1239 '#value' => t('Cancel'), 1240 '#submit' => array('page_manager_save_page_form_cancel'), 1241 ); 1242 return $form; 1243 } 1244 } 1245 1246 /** 1247 * Save the page. 1248 */ 1249 function page_manager_save_page_form_submit(&$form, &$form_state) { 1250 page_manager_save_page_cache($form_state['page']); 1251 } 1252 1253 /** 1254 * Discard changes to the page. 1255 */ 1256 function page_manager_save_page_form_cancel(&$form, &$form_state) { 1257 drupal_set_message(t('All pending changes have been discarded, and the page is now unlocked.')); 1258 page_manager_clear_page_cache($form_state['page']->task_name); 1259 1260 if (!empty($form_state['page']->new)) { 1261 $form_state['redirect'] = 'admin/build/pages'; 1262 } 1263 } 1264 1265 // -------------------------------------------------------------------------- 1266 // Handler (variant) related forms. 1267 1268 /** 1269 * Add a new task handler. 1270 */ 1271 function page_manager_handler_add(&$form, &$form_state) { 1272 // Get a list of possible task handlers for this task. 1273 page_manager_handler_add_form($form, $form_state); 1274 } 1275 1276 /** 1277 * Handler related forms. 1278 */ 1279 function page_manager_handler_add_submit(&$form, &$form_state) { 1280 $cache = $form_state['page']; 1281 $plugin = page_manager_get_task_handler($form_state['values']['handler']); 1282 1283 // Create a new handler. 1284 $handler = page_manager_new_task_handler($plugin); 1285 if (!empty($form_state['values']['title'])) { 1286 $handler->conf['title'] = $form_state['values']['title']; 1287 } 1288 else { 1289 $handler->conf['title'] = $plugin['title']; 1290 } 1291 $cache->new_handler = $handler; 1292 1293 // Figure out which forms to present them with 1294 $cache->forms = array(); 1295 1296 $features = $form_state['values']['features']; 1297 if (isset($features[$form_state['values']['handler']])) { 1298 $cache->forms = array_merge($cache->forms, array_keys(array_filter($features[$form_state['values']['handler']]))); 1299 } 1300 1301 if (isset($plugin['required forms'])) { 1302 $cache->forms = array_merge($cache->forms, array_keys($plugin['required forms'])); 1303 } 1304 1305 $form_state['no_rerender'] = TRUE; 1306 if (!empty($cache->forms)) { 1307 // Tell the form to go to the config page. 1308 drupal_set_message(t('Before this variant can be added, it must be configured. When you are finished, click "Create variant" at the end of this wizard to add this to your page.')); 1309 $form_state['new trail'] = array('actions', 'configure'); 1310 } 1311 else { 1312 // It has no forms at all. Add the variant and go to its first operation. 1313 page_manager_handler_add_finish($form_state); 1314 } 1315 } 1316 1317 /** 1318 * Finish the add process and make the new handler official. 1319 */ 1320 function page_manager_handler_add_finish(&$form_state) { 1321 $page = &$form_state['page']; 1322 $handler = $page->new_handler; 1323 page_manager_handler_add_to_page($page, $handler); 1324 1325 // Remove the temporary page. 1326 unset($page->new_handler); 1327 unset($page->forms); 1328 1329 // Set the new destination 1330 $plugin = page_manager_get_task_handler($handler->handler); 1331 if (!empty($plugin['add finish'])) { 1332 $location = $plugin['add finish']; 1333 } 1334 else { 1335 $keys = array_keys($plugin['operations']); 1336 $location = reset($keys); 1337 } 1338 1339 $form_state['new trail'] = array('handlers', $handler->name, $location); 1340 1341 // Pass through. 1342 page_manager_edit_page_finish($form_state); 1343 } 1344 1345 /** 1346 * Throw away a new handler and return to the add form 1347 */ 1348 function page_manager_handler_add_cancel(&$form_state) { 1349 $form_state['new trail'] = array('handlers', 'add'); 1350 1351 // Remove the temporary page. 1352 unset($page->new_handler); 1353 unset($page->forms); 1354 } 1355 1356 /** 1357 * Provide a consistent UI for adding handlers. 1358 */ 1359 function page_manager_handler_add_form(&$form, $form_state, $features = array()) { 1360 $task = $form_state['task']; 1361 $task_handler_plugins = page_manager_get_task_handler_plugins($task); 1362 if (empty($task_handler_plugins)) { 1363 drupal_set_message(t('There are currently no variants available and a page may not be added. Perhaps you need to install the Panels module to get a variant?'), 'error'); 1364 $form['buttons']['return']['#disabled'] = TRUE; 1365 return; 1366 } 1367 1368 foreach ($task_handler_plugins as $id => $plugin) { 1369 $options[$id] = $plugin['title']; 1370 if (isset($plugin['add features'])) { 1371 $features[$id] = $plugin['add features']; 1372 } 1373 } 1374 1375 if (!isset($form_state['type']) || $form_state['type'] != 'add') { 1376 $form['title'] = array( 1377 '#type' => 'textfield', 1378 '#title' => t('Title'), 1379 '#description' => t('Administrative title of this variant. If you leave blank it will be automatically assigned.'), 1380 ); 1381 } 1382 1383 $form['handler'] = array( 1384 '#title' => t('Variant type'), 1385 '#type' => 'select', 1386 '#options' => $options, 1387 ); 1388 1389 // This set of checkboxes is not dangerous at all. 1390 $form['features'] = array( 1391 '#type' => 'checkboxes', 1392 '#validated' => TRUE, 1393 '#title' => t('Optional features'), 1394 '#options' => array(), 1395 '#description' => t('Check any optional features you need to be presented with forms for configuring them. If you do not check them here you will still be able to utilize these features once the new page is created. If you are not sure, leave these unchecked.'), 1396 '#tree' => TRUE, 1397 ); 1398 1399 ctools_include('dependent'); 1400 foreach ($features as $plugin => $feature_list) { 1401 foreach ($feature_list as $feature_id => $feature) { 1402 $form['features'][$plugin][$feature_id] = array( 1403 '#type' => 'checkbox', 1404 '#title' => $feature, 1405 ); 1406 if (!empty($form_state['page']->forms) && in_array($feature_id, $form_state['page']->forms)) { 1407 $form['features'][$plugin][$feature_id]['#default_value'] = TRUE; 1408 } 1409 1410 if ($plugin != 'default') { 1411 $form['features'][$plugin][$feature_id] += array( 1412 '#process' => array('ctools_dependent_process'), 1413 '#dependency' => array('edit-handler' => array($plugin)), 1414 ); 1415 } 1416 } 1417 } 1418 } 1419 1420 /** 1421 * Rearrange the order of variants. 1422 */ 1423 function page_manager_handler_import(&$form, &$form_state) { 1424 $form['title'] = array( 1425 '#type' => 'textfield', 1426 '#title' => t('Variant name'), 1427 '#description' => t('Enter the name of the new variant.'), 1428 ); 1429 1430 if (user_access('use PHP for block visibility')) { 1431 $form['object'] = array( 1432 '#type' => 'textarea', 1433 '#title' => t('Paste variant code here'), 1434 '#rows' => 15, 1435 ); 1436 } 1437 // Users ordinarily can't get here without the PHP block visibility perm. 1438 // In case they somehow do, though, disable the form widget for extra safety. 1439 else { 1440 $form['shoveoff'] = array( 1441 '#value' => '<div>' . t('You do not have sufficient permissions to perform this action.') . '</div>', 1442 ); 1443 } 1444 } 1445 1446 /** 1447 * Make sure that an import actually provides a handler. 1448 */ 1449 function page_manager_handler_import_validate($form, &$form_state) { 1450 if (!user_access('use PHP for block visibility')) { 1451 form_error($form['shoveoff'], t('You account permissions do not permit you to import.')); 1452 return; 1453 } 1454 ob_start(); 1455 eval($form_state['values']['object']); 1456 ob_end_clean(); 1457 1458 if (empty($handler)) { 1459 $errors = ob_get_contents(); 1460 if (empty($errors)) { 1461 $errors = t('No variant found.'); 1462 } 1463 1464 form_error($form['object'], t('Unable to get a variant from the import. Errors reported: @errors', array('@errors' => $errors))); 1465 } 1466 1467 $form_state['handler'] = $handler; 1468 } 1469 1470 /** 1471 * Clone an existing task handler into a new handler. 1472 */ 1473 function page_manager_handler_import_submit($form, &$form_state) { 1474 $handler = $form_state['handler']; 1475 1476 page_manager_handler_add_to_page($form_state['page'], $handler, $form_state['values']['title']); 1477 1478 $plugin = page_manager_get_task_handler($handler->handler); 1479 // It has no forms at all. Add the variant and go to its first operation. 1480 $keys = array_keys($plugin['operations']); 1481 $form_state['new trail'] = array('handlers', $handler->name, reset($keys)); 1482 } 1483 1484 /** 1485 * Rearrange the order of variants. 1486 */ 1487 function page_manager_handler_rearrange(&$form, &$form_state) { 1488 $page = $form_state['page']; 1489 1490 $form['handlers'] = array('#tree' => TRUE); 1491 1492 foreach ($page->handler_info as $id => $info) { 1493 if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) { 1494 continue; 1495 } 1496 $handler = $page->handlers[$id]; 1497 $plugin = page_manager_get_task_handler($handler->handler); 1498 1499 $form['handlers'][$id]['title'] = array( 1500 '#value' => page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id), 1501 ); 1502 1503 $form['handlers'][$id]['weight'] = array( 1504 '#type' => 'weight', 1505 '#default_value' => $info['weight'], 1506 '#delta' => 30, 1507 ); 1508 } 1509 } 1510 1511 function page_manager_handler_rearrange_submit(&$form, &$form_state) { 1512 $handler_info = &$form_state['page']->handler_info; 1513 1514 foreach ($form_state['values']['handlers'] as $id => $info) { 1515 if ($handler_info[$id]['weight'] = $info['weight']) { 1516 $handler_info[$id]['weight'] = $info['weight']; 1517 $handler_info[$id]['changed'] |= PAGE_MANAGER_CHANGED_MOVED; 1518 } 1519 } 1520 1521 // Sort the new cache. 1522 uasort($handler_info, '_page_manager_handler_sort'); 1523 1524 } 1525 1526 /** 1527 * Used as a callback to uasort to sort the task cache by weight. 1528 * 1529 * The 'name' field is used as a backup when weights are the same, which 1530 * can happen when multiple modules put items out there at the same 1531 * weight. 1532 */ 1533 function _page_manager_handler_sort($a, $b) { 1534 if ($a['weight'] < $b['weight']) { 1535 return -1; 1536 } 1537 elseif ($a['weight'] > $b['weight']) { 1538 return 1; 1539 } 1540 elseif ($a['name'] < $b['name']) { 1541 return -1; 1542 } 1543 elseif ($a['name'] > $b['name']) { 1544 return 1; 1545 } 1546 } 1547 1548 /** 1549 * Rearrange the order of variants. 1550 */ 1551 function page_manager_handler_delete(&$form, &$form_state) { 1552 if ($form_state['handler']->type == t('Overridden')) { 1553 $text = t('Reverting the variant will delete the variant that is in the database, reverting it to the original default variant. This deletion will not be made permanent until you click Save.'); 1554 } 1555 else { 1556 $text = t('Are you sure you want to delete this variant? This deletion will not be made permanent until you click Save.'); 1557 } 1558 $form['markup'] = array( 1559 '#value' => '<p>' . $text . '</p>', 1560 ); 1561 1562 } 1563 1564 /** 1565 * Submit handler to delete a view. 1566 */ 1567 function page_manager_handler_delete_submit(&$form, &$form_state) { 1568 $form_state['page']->handler_info[$form_state['handler_id']]['changed'] |= PAGE_MANAGER_CHANGED_DELETED; 1569 $form_state['new trail'] = array('summary'); 1570 } 1571 1572 /** 1573 * Entry point to export a page. 1574 */ 1575 function page_manager_handler_export(&$form, &$form_state) { 1576 $export = page_manager_export_task_handler($form_state['handler']); 1577 1578 $lines = substr_count($export, "\n"); 1579 $form['code'] = array( 1580 '#type' => 'textarea', 1581 '#default_value' => $export, 1582 '#rows' => $lines, 1583 ); 1584 1585 unset($form['buttons']); 1586 } 1587 1588 /** 1589 * Rearrange the order of variants. 1590 */ 1591 function page_manager_handler_clone(&$form, &$form_state) { 1592 // This provides its own button because it does something totally different. 1593 $form['title'] = array( 1594 '#type' => 'textfield', 1595 '#title' => t('Variant name'), 1596 '#description' => t('Enter the name of the new variant.'), 1597 ); 1598 } 1599 1600 /** 1601 * Clone an existing task handler into a new handler. 1602 */ 1603 function page_manager_handler_clone_submit($form, &$form_state) { 1604 $export = page_manager_export_task_handler($form_state['handler']); 1605 ob_start(); 1606 eval($export); 1607 ob_end_clean(); 1608 1609 page_manager_handler_add_to_page($form_state['page'], $handler, $form_state['values']['title']); 1610 1611 $plugin = page_manager_get_task_handler($handler->handler); 1612 // It has no forms at all. Add the variant and go to its first operation. 1613 $keys = array_keys($plugin['operations']); 1614 $form_state['new trail'] = array('handlers', $handler->name, reset($keys)); 1615 } 1616 1617 /** 1618 * Form to enable a handler. 1619 */ 1620 function page_manager_handler_enable(&$form, &$form_state) { 1621 $form['markup'] = array( 1622 '#value' => t('This variant is currently disabled. Enabling it will make it available in your system. This will not take effect until you save this page.'), 1623 ); 1624 } 1625 1626 /** 1627 * Enable the page after it has been confirmed. 1628 */ 1629 function page_manager_handler_enable_submit(&$form, &$form_state) { 1630 $form_state['handler']->disabled = FALSE; 1631 $form_state['page']->handler_info[$form_state['handler_id']]['disabled'] = FALSE; 1632 $form_state['page']->handler_info[$form_state['handler_id']]['changed'] |= PAGE_MANAGER_CHANGED_STATUS; 1633 $form_state['new trail'] = array('handlers', $form_state['handler_id'], 'actions', 'disable'); 1634 } 1635 1636 /** 1637 * Form to disable a page. 1638 */ 1639 function page_manager_handler_disable(&$form, &$form_state) { 1640 $form['markup'] = array( 1641 '#value' => t('This variant is currently enabled. Disabling it will make it unavailable in your system, and it will not be used. This will not take effect until you save this page.'), 1642 ); 1643 } 1644 1645 /** 1646 * Form to disable a page. 1647 */ 1648 function page_manager_handler_summary(&$form, &$form_state) { 1649 $handler = $form_state['handler']; 1650 $page = $form_state['page']; 1651 $plugin = page_manager_get_task_handler($handler->handler); 1652 1653 $form['markup'] = array( 1654 '#value' => page_manager_get_handler_summary($plugin, $handler, $page, FALSE), 1655 ); 1656 } 1657 1658 /** 1659 * Disable the page after it has been confirmed. 1660 */ 1661 function page_manager_handler_disable_submit(&$form, &$form_state) { 1662 $form_state['handler']->disabled = TRUE; 1663 $form_state['page']->handler_info[$form_state['handler_id']]['disabled'] = TRUE; 1664 $form_state['page']->handler_info[$form_state['handler_id']]['changed'] |= PAGE_MANAGER_CHANGED_STATUS; 1665 $form_state['new trail'] = array('handlers', $form_state['handler_id'], 'actions', 'enable'); 1666 } 1667 1668 /** 1669 * Break the lock on a page so that it can be edited. 1670 */ 1671 function page_manager_break_lock(&$form, &$form_state) { 1672 $form['markup'] = array( 1673 '#value' => t('Breaking the lock on this page will <strong>discard</strong> any pending changes made by the locking user. Are you REALLY sure you want to do this?') 1674 ); 1675 } 1676 1677 /** 1678 * Submit to break the lock on a page. 1679 */ 1680 function page_manager_break_lock_submit(&$form, &$form_state) { 1681 $page = &$form_state['page']; 1682 $form_state['page']->locked = FALSE; 1683 ctools_object_cache_clear_all('page_manager_page', $page->task_name); 1684 $form_state['do not cache'] = TRUE; 1685 drupal_set_message(t('The lock has been cleared and all changes discarded. You may now make changes to this page.')); 1686 1687 $form_state['new trail'] = array('summary'); 1688 } 1689 1690 /** 1691 * Form to enable a page. 1692 */ 1693 function page_manager_enable_form(&$form, &$form_state) { 1694 $form['markup'] = array( 1695 '#value' => t('Enabling this page will immediately make it available in your system (there is no need to wait for a save.)'), 1696 ); 1697 } 1698 1699 /** 1700 * Enable the page after it has been confirmed. 1701 */ 1702 function page_manager_enable_form_submit(&$form, &$form_state) { 1703 $page = &$form_state['page']; 1704 if ($function = ctools_plugin_get_function($page->subtask, 'enable callback')) { 1705 $result = $function($page, FALSE); 1706 menu_rebuild(); 1707 } 1708 $form_state['new trail'] = array('actions', 'disable'); 1709 1710 // We don't want to cause this to cache if it wasn't already. If it was 1711 // cached, however, we want to update the enabled state. 1712 if (empty($form_state['page']->changed)) { 1713 $form_state['do not cache'] = TRUE; 1714 } 1715 } 1716 1717 /** 1718 * Form to disable a page. 1719 */ 1720 function page_manager_disable_form(&$form, &$form_state) { 1721 $form['markup'] = array( 1722 '#value' => t('Disabling this page will immediately make it unavailable in your system (there is no need to wait for a save.)'), 1723 ); 1724 } 1725 1726 /** 1727 * Disable the page after it has been confirmed. 1728 */ 1729 function page_manager_disable_form_submit(&$form, &$form_state) { 1730 $page = &$form_state['page']; 1731 if ($function = ctools_plugin_get_function($page->subtask, 'enable callback')) { 1732 $result = $function($page, TRUE); 1733 menu_rebuild(); 1734 $form_state['new trail'] = array('actions', 'enable'); 1735 1736 // We don't want to cause this to cache if it wasn't already. If it was 1737 // cached, however, we want to update the enabled state. 1738 if (empty($form_state['page']->changed)) { 1739 $form_state['do not cache'] = TRUE; 1740 } 1741 } 1742 } 1743 1744 /** 1745 * Print the summary information for a page. 1746 */ 1747 function page_manager_page_summary(&$form, &$form_state) { 1748 $page = $form_state['page']; 1749 1750 $output = ''; 1751 1752 /* 1753 if (isset($form_state['subtask']['admin title'])) { 1754 $form_state['title'] = $form_state['subtask']['admin title']; 1755 } 1756 */ 1757 1758 if (isset($form_state['subtask']['admin description'])) { 1759 $output .= '<div class="description">' . $form_state['subtask']['admin description'] . '</div>'; 1760 } 1761 1762 $output .= page_manager_get_page_summary($page->task, $page->subtask); 1763 1764 if (!empty($page->handlers)) { 1765 foreach ($page->handler_info as $id => $info) { 1766 if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) { 1767 continue; 1768 } 1769 1770 $handler = $page->handlers[$id]; 1771 $plugin = page_manager_get_task_handler($handler->handler); 1772 1773 $output .= '<div class="handler-summary">'; 1774 $output .= page_manager_get_handler_summary($plugin, $handler, $page); 1775 $output .= '</div>'; 1776 1777 } 1778 } 1779 else { 1780 $output .= '<p>' . t('This page has no variants and thus no output of its own.') . '</p>'; 1781 } 1782 1783 $links = array( 1784 array( 1785 'title' => ' » ' . t('Add a new variant'), 1786 'href' => page_manager_edit_url($page->task_name, array('actions', 'add')), 1787 'html' => TRUE, 1788 ), 1789 ); 1790 1791 $output .= '<div class="links">' . theme('links', $links) . '</div>'; 1792 $form['markup'] = array( 1793 '#value' => $output, 1794 ); 1795 } 1796 1797 /** 1798 * Menu callback to enable or disable a page 1799 */ 1800 function page_manager_enable_page($disable, $js, $page) { 1801 if (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], $page->task_name)) { 1802 return MENU_ACCESS_DENIED; 1803 } 1804 if ($page->locked) { 1805 if ($disable) { 1806 drupal_set_message(t('Unable to disable due to lock.')); 1807 } 1808 else { 1809 drupal_set_message(t('Unable to enable due to lock.')); 1810 } 1811 } 1812 else { 1813 if ($function = ctools_plugin_get_function($page->subtask, 'enable callback')) { 1814 $result = $function($page, $disable); 1815 menu_rebuild(); 1816 1817 // We want to re-cache this if it's changed so that status is properly 1818 // updated on the changed form. 1819 if (!empty($page->changed)) { 1820 page_manager_set_page_cache($page); 1821 } 1822 } 1823 } 1824 1825 // For now $js is not actually in use on this. 1826 drupal_goto('admin/build/pages'); 1827 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |