'page_manager',
'topic' => 'getting-started',
'type' => t('See the getting started guide for more information.'),
)));
}
$tasks = page_manager_get_tasks_by_type('page');
$pages = array('operations' => array(), 'tasks' => array());
page_manager_get_pages($tasks, $pages);
// Add lock icon to all locked tasks.
global $user;
ctools_include('object-cache');
$locks = ctools_object_cache_test_objects('page_manager_page', $pages['tasks']);
foreach ($locks as $task_name => $lock) {
if ($lock->uid == $user->uid) {
$pages['rows'][$task_name]['class'][] = ' page-manager-locked';
$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.');
}
else {
$pages['rows'][$task_name]['class'][] = ' page-manager-locked-other';
$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.');
}
}
$input = $_POST;
// Respond to a reset command by clearing session and doing a drupal goto
// back to the base URL.
if (isset($input['op']) && $input['op'] == t('Reset')) {
unset($_SESSION['page_manager']['#admin']);
if (!$js) {
drupal_goto($_GET['q']);
}
// clear everything but form id, form build id and form token:
$keys = array_keys($input);
foreach ($keys as $id) {
if ($id != 'form_id' && $id != 'form_build_id' && $id != 'form_token') {
unset($input[$id]);
}
}
$replace_form = TRUE;
}
if (count($input) <= 1) {
if (isset($_SESSION['page_manager']['#admin']) && is_array($_SESSION['page_manager']['#admin'])) {
$input = $_SESSION['page_manager']['#admin'];
}
}
else {
$_SESSION['page_manager']['#admin'] = $input;
unset($_SESSION['page_manager']['#admin']['q']);
}
$form_state = array(
'pages' => &$pages,
'input' => $input,
'rerender' => TRUE,
'no_redirect' => TRUE,
);
// This form will sort and filter the pages.
$form = drupal_build_form('page_manager_list_pages_form', $form_state);
$header = array(
array('data' => t('Type'), 'class' => array('page-manager-page-type')),
array('data' => t('Name'), 'class' => array('page-manager-page-name')),
array('data' => t('Title'), 'class' => array('page-manager-page-title')),
array('data' => t('Path'), 'class' => array('page-manager-page-path')),
array('data' => t('Storage'), 'class' => array('page-manager-page-storage')),
);
$header[] = array('data' => t('Operations'), 'class' => array('page-manager-page-operations'));
$table = theme('table', array('header' => $header, 'rows' => $pages['rows'], 'attributes' => array('id' => 'page-manager-list-pages')));
$operations = '
' . theme('links', array('links' => $pages['operations'])) . '
';
drupal_add_css(drupal_get_path('module', 'page_manager') . '/css/page-manager.css');
if (!$js) {
return array('#markup' => drupal_render($form) . $table . $operations);
}
ctools_include('ajax');
$commands = array();
$commands[] = ajax_command_replace('#page-manager-list-pages', $table);
if (!empty($replace_form)) {
$commands[] = ajax_command_replace('#page-manager-list-pages-form', drupal_render($form));
}
print ajax_render($commands);
ajax_footer();
}
/**
* Sort tasks into buckets based upon whether or not they have subtasks.
*/
function page_manager_get_pages($tasks, &$pages, $task_id = NULL) {
foreach ($tasks as $id => $task) {
if (empty($task_id) && !empty($task['page operations'])) {
$pages['operations'] = array_merge($pages['operations'], $task['page operations']);
}
// If a type has subtasks, add its subtasks in its own table.
if (!empty($task['subtasks'])) {
page_manager_get_pages(page_manager_get_task_subtasks($task), $pages, $task['name']);
continue;
}
if (isset($task_id)) {
$task_name = page_manager_make_task_name($task_id, $task['name']);
}
else {
$task_name = $task['name'];
}
$class = array('page-task-' . $id);
if (isset($task['row class'])) {
$class[] = $task['row class'];
}
if (!empty($task['disabled'])) {
$class[] = 'page-manager-disabled';
}
$path = array();
$visible_path = '';
if (!empty($task['admin path'])) {
foreach (explode('/', $task['admin path']) as $bit) {
if (isset($bit[0]) && $bit[0] != '!') {
$path[] = $bit;
}
}
$path = implode('/', $path);
if (empty($task['disabled']) && strpos($path, '%') === FALSE) {
$visible_path = l('/' . $task['admin path'], $path);
}
else {
$visible_path = '/' . $task['admin path'];
}
}
$row = array('data' => array(), 'class' => $class, 'title' => strip_tags($task['admin description']));
$type = isset($task['admin type']) ? $task['admin type'] : t('System');
$pages['types'][$type] = $type;
$row['data']['type'] = array('data' => $type, 'class' => array('page-manager-page-type'));
$row['data']['name'] = array('data' => $task_name, 'class' => array('page-manager-page-name'));
$row['data']['title'] = array('data' => $task['admin title'], 'class' => array('page-manager-page-title'));
$row['data']['path'] = array('data' => $visible_path, 'class' => array('page-manager-page-path'));
$storage = isset($task['storage']) ? $task['storage'] : t('In code');
$pages['storages'][$storage] = $storage;
$row['data']['storage'] = array('data' => $storage, 'class' => array('page-manager-page-storage'));
/*
if (empty($task['disabled'])) {
$item = menu_get_item($path);
if (empty($item)) {
dsm($path);
}
else {
dsm($item);
}
}
*/
$operations = array(
array(
'title' => t('Edit'),
'href' => page_manager_edit_url($task_name),
),
);
if (!empty($task['enable callback'])) {
if (!empty($task['disabled'])) {
array_unshift($operations, array(
'title' => t('Enable'),
'href' => 'admin/structure/pages/nojs/enable/' . $task_name,
'query' => array('token' => drupal_get_token($task_name)),
));
}
else {
$operations[] = array(
'title' => t('Disable'),
'href' => 'admin/structure/pages/nojs/disable/' . $task_name,
'query' => array('token' => drupal_get_token($task_name)),
);
}
}
$ops = theme('links__ctools_dropbutton', array('links' => $operations, 'attributes' => array('class' => array('links', 'inline'))));
$row['data']['operations'] = array('data' => $ops, 'class' => array('page-manager-page-operations'));
$pages['disabled'][$task_name] = !empty($task['disabled']);
$pages['tasks'][] = $task_name;
$pages['rows'][$task_name] = $row;
}
}
/**
* Provide a form for sorting and filtering the list of pages.
*/
function page_manager_list_pages_form($form, &$form_state) {
// This forces the form to *always* treat as submitted which is
// necessary to make it work.
if (empty($_POST)) {
$form["#programmed"] = TRUE;
}
$form['#action'] = url('admin/structure/pages/nojs/', array('absolute' => TRUE));
if (!variable_get('clean_url', FALSE)) {
$form['q'] = array(
'#type' => 'hidden',
'#value' => $_GET['q'],
);
}
$all = array('all' => t(''));
$form['type'] = array(
'#type' => 'select',
'#title' => t('Type'),
'#options' => $all + $form_state['pages']['types'],
'#default_value' => 'all',
);
$form['storage'] = array(
'#type' => 'select',
'#title' => t('Storage'),
'#options' => $all + $form_state['pages']['storages'],
'#default_value' => 'all',
);
$form['disabled'] = array(
'#type' => 'select',
'#title' => t('Enabled'),
'#options' => $all + array('0' => t('Enabled'), '1' => t('Disabled')),
'#default_value' => 'all',
);
$form['search'] = array(
'#type' => 'textfield',
'#title' => t('Search'),
);
$form['order'] = array(
'#type' => 'select',
'#title' => t('Sort by'),
'#options' => array(
'disabled' => t('Enabled, title'),
'title' => t('Title'),
'name' => t('Name'),
'path' => t('Path'),
'type' => t('Type'),
'storage' => t('Storage'),
),
'#default_value' => 'disabled',
);
$form['sort'] = array(
'#type' => 'select',
'#title' => t('Order'),
'#options' => array(
'asc' => t('Up'),
'desc' => t('Down'),
),
'#default_value' => 'asc',
);
$form['submit'] = array(
'#name' => '', // so it won't in the $_GET args
'#type' => 'submit',
'#id' => 'edit-pages-apply',
'#value' => t('Apply'),
'#attributes' => array('class' => array('use-ajax-submit ctools-auto-submit-click')),
);
$form['reset'] = array(
'#type' => 'submit',
'#id' => 'edit-pages-reset',
'#value' => t('Reset'),
'#attributes' => array('class' => array('use-ajax-submit')),
);
$form['#attached']['js'] = array(ctools_attach_js('auto-submit'), ctools_attach_js('page-list', 'page_manager'));
$form['#attached']['library'][] = array('system', 'drupal.ajax');
$form['#attached']['library'][] = array('system', 'jquery.form');
$form['#prefix'] = '';
$form['#suffix'] = '
';
$form['#attributes'] = array('class' => array('ctools-auto-submit-full-form'));
return $form;
}
/**
* Accept submission from the page manager sort/filter form and apply it
* to the list of pages.
*/
function page_manager_list_pages_form_submit(&$form, &$form_state) {
// Filter and re-sort the pages.
// This is a copy.
$rows = $form_state['pages']['rows'];
$sorts = array();
foreach ($rows as $name => $data) {
// Filter
if ($form_state['values']['type'] != 'all' && $form_state['values']['type'] != $data['data']['type']['data']) {
continue;
}
if ($form_state['values']['storage'] != 'all' && $form_state['values']['storage'] != $data['data']['storage']['data']) {
continue;
}
if ($form_state['values']['disabled'] != 'all' && $form_state['values']['disabled'] != $form_state['pages']['disabled'][$name]) {
continue;
}
if ($form_state['values']['search'] &&
strpos($data['data']['name']['data'], $form_state['values']['search']) === FALSE &&
strpos($data['data']['path']['data'], $form_state['values']['search']) === FALSE &&
strpos($data['data']['title']['data'], $form_state['values']['search']) === FALSE) {
continue;
}
// Set up sorting
switch ($form_state['values']['order']) {
case 'disabled':
$sorts[$name] = !$form_state['pages']['disabled'][$name] . $data['data']['title']['data'];
break;
case 'title':
$sorts[$name] = $data['data']['title']['data'];
break;
case 'name':
$sorts[$name] = $data['data']['name']['data'];
break;
case 'path':
$sorts[$name] = $data['data']['path']['data'];
break;
case 'type':
$sorts[$name] = $data['data']['type']['data'];
break;
case 'storage':
$sorts[$name] = $data['data']['storage']['data'];
break;
}
}
// Now actually sort
if ($form_state['values']['sort'] == 'desc') {
arsort($sorts);
}
else {
asort($sorts);
}
// Nuke the original.
$form_state['pages']['rows'] = array();
// And restore.
foreach ($sorts as $name => $title) {
$form_state['pages']['rows'][$name] = $rows[$name];
}
}
/**
* Render the edit page for a a page, custom or system.
*/
function page_manager_edit_page($page) {
drupal_set_title($page->subtask['admin title']);
// Provide and process the save page form before anything else.
$form_state = array('page' => &$page);
$built_form = drupal_build_form('page_manager_save_page_form', $form_state);
$form = drupal_render($built_form);
$operations = page_manager_get_operations($page);
$args = array('summary');
$rendered_operations = page_manager_render_operations($page, $operations, $args, array('class' => array('operations-main')), 'nav');
$content = page_manager_get_operation_content(FALSE, $page, $args, $operations);
$output = theme('page_manager_edit_page', array('page' => $page, 'save' => $form, 'operations' => $rendered_operations, 'content' => $content));
return array('#markup' => $output);
}
/**
* Entry point to edit a single operation for a page.
*
* @param $js
* Whether or not the page was called via javascript.
* @param $page
* The cached page that is being edited.
* @param ...
* A number of items used to drill down into the actual operation called.
*/
function page_manager_edit_page_operation() {
$args = func_get_args();
$js = array_shift($args);
$page = array_shift($args);
$operations = page_manager_get_operations($page);
$content = page_manager_get_operation_content($js, $page, $args, $operations);
// If the operation requested we go somewhere else afterward, oblige it.
if (isset($content['new trail'])) {
$args = $content['new trail'];
// Get operations again, for the operation may have changed their availability.
$operations = page_manager_get_operations($page);
$content = page_manager_get_operation_content($js, $page, $args, $operations);
}
// Rendering the content may have been a form submission that changed the
// operations, such as renaming or adding a handler. Thus we get a new set
// of operations.
$operations = page_manager_get_operations($page);
$rendered_operations = page_manager_render_operations($page, $operations, $args, array('class' => array('operations-main')), 'nav');
// Since this form should never be submitted to this page, process it late so
// that we can be sure it notices changes.
$form_state = array('page' => &$page);
$built_form = drupal_build_form('page_manager_save_page_form', $form_state);
$form = drupal_render($built_form);
$output = theme('page_manager_edit_page', array('page' => $page, 'save' => $form, 'operations' => $rendered_operations, 'content' => $content));
if ($js) {
$commands = array();
$commands[] = ajax_command_replace('#page-manager-edit', $output);
print ajax_render($commands);
ajax_footer();
return;
}
drupal_set_title($page->subtask['admin title']);
return $output;
}
/**
* Take the operations array from a task and expand it.
*
* This allows some of the operations to be dynamic, based upon settings
* on the task or the task's handlers. Each operation should have a type. In
* addition to all the types allowed in page_manager_render_operations, these
* types will be dynamically replaced with something else:
* - 'handlers': An automatically created group that contains all the task's
* handlers and appropriate links.
* - 'function': A callback (which will be placed in the 'function' parameter
* that should return an array of operations. This can be used to provide
* additional, dynamic links if needed.
*/
function page_manager_get_operations($page, $operations = NULL) {
if (!isset($operations)) {
// All tasks have at least these 2 ops:
$operations = array(
'summary' => array(
'title' => t('Summary'),
'description' => t('Get a summary of the information about this page.'),
'path' => 'admin/structure/pages/edit',
'ajax' => FALSE,
'no operations' => TRUE,
'form info' => array(
'no buttons' => TRUE,
),
'form' => 'page_manager_page_summary',
),
'actions' => array(
'type' => 'group',
'title' => '',
'class' => array('operations-actions'),
'location' => 'primary',
'children' => array(),
),
);
if (isset($page->subtask['operations'])) {
$operations += $page->subtask['operations'];
// add actions separately.
if (!empty($page->subtask['operations']['actions'])) {
$operations['actions']['children'] += $page->subtask['operations']['actions']['children'];
}
}
$operations['handlers'] = array('type' => 'handlers');
}
$result = array();
foreach ($operations as $id => $operation) {
if (empty($operation['type'])) {
$operation['type'] = 'operation';
}
switch ($operation['type']) {
case 'handlers':
$result[$id] = page_manager_get_handler_operations($page);
break;
case 'function':
if (function_exists($operation['function'])) {
$retval = $function($page, $operation);
if (is_array($retval)) {
$result[$id] = $retval;
}
}
break;
default:
$result[$id] = $operation;
}
}
if (!empty($page->subtask['enable callback']) && !empty($page->subtask['disabled']) && empty($result['actions']['children']['enable'])) {
$result['actions']['children']['enable'] = array(
'title' => t('Enable'),
'description' => t('Activate this page so that it will be in use in your system.'),
'form' => 'page_manager_enable_form',
'ajax' => FALSE,
'silent' => TRUE,
'no update and save' => TRUE,
'form info' => array(
'finish text' => t('Enable'),
),
);
}
if (!empty($page->subtask['enable callback']) && empty($page->subtask['disabled']) && empty($result['actions']['children']['disable'])) {
$result['actions']['children']['disable'] = array(
'title' => t('Disable'),
'description' => t('De-activate this page. The data will remain but the page will not be in use on your system.'),
'form' => 'page_manager_disable_form',
'ajax' => FALSE,
'silent' => TRUE,
'no update and save' => TRUE,
'form info' => array(
'finish text' => t('Disable'),
),
);
}
$result['actions']['children']['add'] = array(
'title' => t('Add variant'),
'description' => t('Add a new variant to this page.'),
'form' => 'page_manager_handler_add',
'ajax' => FALSE,
'silent' => TRUE, // prevents a message about updating and prevents this item from showing as changed.
'no update and save' => TRUE, // get rid of update and save button which is bad here.
'form info' => array(
'finish text' => t('Create variant'),
),
);
// Restrict variant import to users who can already execute arbitrary PHP
if (user_access('use PHP for settings')) {
$result['actions']['children']['import'] = array(
'title' => t('Import variant'),
'description' => t('Add a new variant to this page from code exported from another page.'),
'form' => 'page_manager_handler_import',
);
}
if (count($page->handlers) > 1) {
$result['actions']['children']['rearrange'] = array(
'title' => t('Reorder variants'),
'ajax' => FALSE,
'description' => t('Change the priority of the variants to ensure that the right one gets selected.'),
'form' => 'page_manager_handler_rearrange',
);
}
// This is a special operation used to configure a new task handler before
// it is added.
if (isset($page->new_handler)) {
$plugin = page_manager_get_task_handler($page->new_handler->handler);
$result['actions']['children']['configure'] = array(
'title' => t('Configure'),
'description' => t('Configure a newly created variant prior to actually adding it to the page.'),
'ajax' => FALSE,
'no update and save' => TRUE, // get rid of update and save button which is bad here.
'form info' => array(
// We use our own cancel and finish callback to handle the fun stuff.
'finish callback' => 'page_manager_handler_add_finish',
'cancel callback' => 'page_manager_handler_add_cancel',
'show trail' => TRUE,
'show back' => TRUE,
'finish text' => t('Create variant'),
),
'form' => array(
'forms' => $plugin['forms'],
),
);
foreach ($page->forms as $id) {
if (isset($plugin['add features'][$id])) {
$result['actions']['children']['configure']['form']['order'][$id] = $plugin['add features'][$id];
}
else if (isset($plugin['required forms'][$id])) {
$result['actions']['children']['configure']['form']['order'][$id] = $plugin['required forms'][$id];
}
}
}
if ($page->locked) {
$result['actions']['children']['break-lock'] = array(
'title' => t('Break lock'),
'description' => t('Break the lock on this page so that you can edit it.'),
'form' => 'page_manager_break_lock',
'ajax' => FALSE,
'no update and save' => TRUE, // get rid of update and save button which is bad here.
'form info' => array(
'finish text' => t('Break lock'),
),
'even locked' => TRUE, // show button even if locked
'silent' => TRUE,
);
}
drupal_alter('page_manager_operations', $result, $page);
return $result;
}
/**
* Collect all the operations related to task handlers (variants) and
* build a menu.
*/
function page_manager_get_handler_operations(&$page) {
ctools_include('export');
$group = array(
'type' => 'group',
'class' => array('operations-handlers'),
'title' => t('Variants'),
);
$operations = array();
// If there is only one variant, let's not have it collapsible.
$collapsible = count($page->handler_info) != 1;
foreach ($page->handler_info as $id => $info) {
if ($info['changed'] & PAGE_MANAGER_CHANGED_DELETED) {
continue;
}
$handler = $page->handlers[$id];
$plugin = page_manager_get_task_handler($handler->handler);
$operations[$id] = array(
'type' => 'group',
'class' => array('operations-handlers-' . $id),
'title' => page_manager_get_handler_title($plugin, $handler, $page->task, $page->subtask_id),
'collapsible' => $collapsible,
'children' => array(),
);
$operations[$id]['children']['actions'] = array(
'type' => 'group',
'class' => array('operations-handlers-actions-' . $id),
'title' => t('Variant operations'),
'children' => array(),
'location' => $id,
);
// There needs to be a 'summary' item here for variants.
$operations[$id]['children']['summary'] = array(
'title' => t('Summary'),
'description' => t('Get a summary of the information about this variant.'),
'form info' => array(
'no buttons' => TRUE,
),
'form' => 'page_manager_handler_summary',
);
if ($plugin && isset($plugin['operations'])) {
$operations[$id]['children'] += $plugin['operations'];
}
$actions = &$operations[$id]['children']['actions']['children'];
$actions['clone'] = array(
'title' => t('Clone'),
'description' => t('Make an exact copy of this variant.'),
'form' => 'page_manager_handler_clone',
);
$actions['export'] = array(
'title' => t('Export'),
'description' => t('Export this variant into code to import into another page.'),
'form' => 'page_manager_handler_export',
);
if ($handler->export_type == (EXPORT_IN_CODE | EXPORT_IN_DATABASE)) {
$actions['delete'] = array(
'title' => t('Revert'),
'description' => t('Remove all changes to this variant and revert to the version in code.'),
'form' => 'page_manager_handler_delete',
'no update and save' => TRUE,
'form info' => array(
'finish text' => t('Revert'),
),
);
}
else if ($handler->export_type != EXPORT_IN_CODE) {
$actions['delete'] = array(
'title' => t('Delete'),
'description' => t('Remove this variant from the page completely.'),
'form' => 'page_manager_handler_delete',
'form info' => array(
'finish text' => t('Delete'),
'save text' => t('Delete and save'),
),
);
}
if (!empty($handler->disabled)) {
$actions['enable'] = array(
'title' => t('Enable'),
'description' => t('Activate this variant so that it will be in use in your system.'),
'form' => 'page_manager_handler_enable',
'silent' => TRUE,
'form info' => array(
'finish text' => t('Enable'),
'save text' => t('Enable and save'),
),
);
}
else {
$actions['disable'] = array(
'title' => t('Disable'),
'description' => t('De-activate this variant. The data will remain but the variant will not be in use on your system.'),
'form' => 'page_manager_handler_disable',
'silent' => TRUE,
'form info' => array(
'finish text' => t('Disable'),
'save text' => t('Disable and save'),
),
);
}
drupal_alter('page_manager_variant_operations', $operations[$id], $handler);
}
if (empty($operations)) {
$operations['empty'] = array(
'type' => 'text',
'title' => t('No variants'),
);
}
$group['children'] = $operations;
return $group;
}
/**
* Get an operation from a trail.
*
* @return array($operation, $active, $args)
*/
function page_manager_get_operation($operations, $trail) {
$args = $trail;
$stop = FALSE;
$active = array();
$titles = array();
// Drill down into operations array:
while (!$stop) {
$check = reset($args);
$stop = TRUE;
if (is_array($operations)) {
if (isset($operations[$check])) {
$active[] = $check;
$operation = array_shift($args);
// check to see if this operation has children. If so, we continue.
if (!isset($operations[$check]['children'])) {
$operations = $operations[$check];
}
else {
$titles[] = $operations[$check]['title'];
$operations = $operations[$check]['children'];
// continue only if the operation hs children.
$stop = FALSE;
}
}
}
}
return array($operations, $active, $args, $titles);
}
/**
* Fetch the content for an operation.
*
* First, this drills down through the arguments to find the operation, and
* turns whatever it finds into the active trail which is then used to
* hilite where we are when rendering the operation list.
*
* The arguments are discovered from the URL, and are an exact match for where
* the operation is in the hierarchy. For example, handlers/foo/settings will
* be the operation to edit the settings for the handler named foo. This comes
* in as an array ('handlers', 'foo', 'settings') and is used to find where the
* data for that operation is in the array.
*/
function page_manager_get_operation_content($js, &$page, $trail, $operations) {
list($operation, $active, $args, $titles) = page_manager_get_operation($operations, $trail);
// Once we've found the operation, send it off to render.
if ($operation) {
$content = _page_manager_get_operation_content($js, $page, $active, $operation, $titles, $args);
}
if (empty($content)) {
$content = _page_manager_get_operation_content($js, $page, array('summary'), $operations['summary']);
}
return $content;
}
/**
* Fetch the content for an operation, after it's been discovered from arguments.
*
* This system runs through the CTools form wizard. Each operation specifies a form
* or set of forms that it may use. Operations may also specify wrappers and can
* set their own next/finish handlers so that they can make additional things happen
* at the end.
*/
function _page_manager_get_operation_content($js, &$page, $active, $operation, $titles = array(), $args = array()) {
if (isset($operation['form'])) {
$form_info = array(
'id' => 'page_manager_page',
'finish text' => t('Update'),
'show trail' => FALSE,
'show back' => FALSE,
'show return' => FALSE,
'show cancel' => FALSE,
'next callback' => 'page_manager_edit_page_next',
'finish callback' => 'page_manager_edit_page_finish',
// Items specific to the 'edit' routines that will get moved over:
'path' => page_manager_edit_url($page->task_name, $active) . "/%step",
// wrapper function to add an extra finish button.
'wrapper' => 'page_manager_operation_wrapper',
);
// If $operation['form'] is simply a string, then it is the function
// name of the form.
if (!is_array($operation['form'])) {
$form_info['order'] = array(
'form' => $operation['title'],
);
$form_info['forms'] = array(
'form' => array('form id' => $operation['form']),
);
if (isset($operation['wrapper'])) {
$form_info['forms']['form']['wrapper'] = $operation['wrapper'];
}
}
// Otherwise it's the order and forms arrays directly.
else {
$form_info['order'] = $operation['form']['order'];
$form_info['forms'] = $operation['form']['forms'];
}
// Allow the operation to override any form info settings:
if (isset($operation['form info'])) {
foreach ($operation['form info'] as $key => $setting) {
$form_info[$key] = $setting;
}
}
if (!empty($page->subtask['operations include'])) {
// Quickly load any files necessary to display the forms.
$page->subtask['operations include']['function'] = 'nop';
ctools_plugin_get_function($page->subtask, 'operations include');
}
$step = array_shift($args);
// If step is unset, go with the basic step.
if (!isset($step)) {
$step = current(array_keys($form_info['order']));
}
// If it is locked, hide the buttonzzz!
if ($page->locked && empty($operation['even locked'])) {
$form_info['no buttons'] = TRUE;
}
ctools_include('wizard');
$form_state = array(
'page' => $page,
'type' => 'edit',
'ajax' => $js && (!isset($operation['ajax']) || !empty($operation['ajax'])),
'rerender' => TRUE,
'trail' => $active,
'task_name' => $page->task_name,
'task_id' => $page->task_id,
'task' => $page->task,
'subtask_id' => $page->subtask_id,
'subtask' => $page->subtask,
'operation' => $operation,
);
if ($active && $active[0] == 'handlers' && isset($form_state['page']->handlers[$form_state['trail'][1]])) {
$form_state['handler_id'] = $form_state['trail'][1];
$form_state['handler'] = &$form_state['page']->handlers[$form_state['handler_id']];
}
if ($active && $active[0] == 'actions' && $active[1] == 'configure' && isset($form_state['page']->new_handler)) {
$form_state['handler_id'] = $form_state['page']->new_handler->name;
$form_state['handler'] = &$form_state['page']->new_handler;
}
$built_form = ctools_wizard_multistep_form($form_info, $step, $form_state);
$output = drupal_render($built_form);
$title = empty($form_state['title']) ? $operation['title'] : $form_state['title'];
$titles[] = $title;
$title = implode(' » ', array_filter($titles));
// If there are messages for the form, render them.
if ($messages = theme('status_messages')) {
$output = $messages . $output;
}
$description = isset($operation['admin description']) ? $operation['admin description'] :