annotate sites/all/modules/ctools/includes/wizard.inc @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
rev   line source
danielebarchiesi@0 1 <?php
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * @file
danielebarchiesi@0 5 * CTools' multi-step form wizard tool.
danielebarchiesi@0 6 *
danielebarchiesi@0 7 * This tool enables the creation of multi-step forms that go from one
danielebarchiesi@0 8 * form to another. The forms themselves can allow branching if they
danielebarchiesi@0 9 * like, and there are a number of configurable options to how
danielebarchiesi@0 10 * the wizard operates.
danielebarchiesi@0 11 *
danielebarchiesi@0 12 * The wizard can also be friendly to ajax forms, such as when used
danielebarchiesi@0 13 * with the modal tool.
danielebarchiesi@0 14 *
danielebarchiesi@0 15 * The wizard provides callbacks throughout the process, allowing the
danielebarchiesi@0 16 * owner to control the flow. The general flow of what happens is:
danielebarchiesi@0 17 *
danielebarchiesi@0 18 * Generate a form
danielebarchiesi@0 19 * submit a form
danielebarchiesi@0 20 * based upon button clicked, 'finished', 'next form', 'cancel' or 'return'.
danielebarchiesi@0 21 *
danielebarchiesi@0 22 * Each action has its own callback, so cached objects can be modifed and or
danielebarchiesi@0 23 * turned into real objects. Each callback can make decisions about where to
danielebarchiesi@0 24 * go next if it wishes to override the default flow.
danielebarchiesi@0 25 */
danielebarchiesi@0 26
danielebarchiesi@0 27 /**
danielebarchiesi@0 28 * Display a multi-step form.
danielebarchiesi@0 29 *
danielebarchiesi@0 30 * Aside from the addition of the $form_info which contains an array of
danielebarchiesi@0 31 * information and configuration so the multi-step wizard can do its thing,
danielebarchiesi@0 32 * this function works a lot like drupal_build_form.
danielebarchiesi@0 33 *
danielebarchiesi@0 34 * Remember that the form builders for this form will receive
danielebarchiesi@0 35 * &$form, &$form_state, NOT just &$form_state and no additional args.
danielebarchiesi@0 36 *
danielebarchiesi@0 37 * @param $form_info
danielebarchiesi@0 38 * An array of form info. @todo document the array.
danielebarchiesi@0 39 * @param $step
danielebarchiesi@0 40 * The current form step.
danielebarchiesi@0 41 * @param &$form_state
danielebarchiesi@0 42 * The form state array; this is a reference so the caller can get back
danielebarchiesi@0 43 * whatever information the form(s) involved left for it.
danielebarchiesi@0 44 */
danielebarchiesi@0 45 function ctools_wizard_multistep_form($form_info, $step, &$form_state) {
danielebarchiesi@0 46 // Make sure 'wizard' always exists for the form when dealing
danielebarchiesi@0 47 // with form caching.
danielebarchiesi@0 48 ctools_form_include($form_state, 'wizard');
danielebarchiesi@0 49
danielebarchiesi@0 50 // allow order array to be optional
danielebarchiesi@0 51 if (empty($form_info['order'])) {
danielebarchiesi@0 52 foreach ($form_info['forms'] as $step_id => $params) {
danielebarchiesi@0 53 $form_info['order'][$step_id] = $params['title'];
danielebarchiesi@0 54 }
danielebarchiesi@0 55 }
danielebarchiesi@0 56
danielebarchiesi@0 57 if (!isset($step)) {
danielebarchiesi@0 58 $keys = array_keys($form_info['order']);
danielebarchiesi@0 59 $step = array_shift($keys);
danielebarchiesi@0 60 }
danielebarchiesi@0 61
danielebarchiesi@0 62 ctools_wizard_defaults($form_info);
danielebarchiesi@0 63
danielebarchiesi@0 64 // If automated caching is enabled, ensure that everything is as it
danielebarchiesi@0 65 // should be.
danielebarchiesi@0 66 if (!empty($form_info['auto cache'])) {
danielebarchiesi@0 67 // If the cache mechanism hasn't been set, default to the simple
danielebarchiesi@0 68 // mechanism and use the wizard ID to ensure uniqueness so cache
danielebarchiesi@0 69 // objects don't stomp on each other.
danielebarchiesi@0 70 if (!isset($form_info['cache mechanism'])) {
danielebarchiesi@0 71 $form_info['cache mechanism'] = 'simple::wizard::' . $form_info['id'];
danielebarchiesi@0 72 }
danielebarchiesi@0 73
danielebarchiesi@0 74 // If not set, default the cache key to the wizard ID. This is often
danielebarchiesi@0 75 // a unique ID of the object being edited or similar.
danielebarchiesi@0 76 if (!isset($form_info['cache key'])) {
danielebarchiesi@0 77 $form_info['cache key'] = $form_info['id'];
danielebarchiesi@0 78 }
danielebarchiesi@0 79
danielebarchiesi@0 80 // If not set, default the cache location to storage. This is often
danielebarchiesi@0 81 // somnething like 'conf'.
danielebarchiesi@0 82 if (!isset($form_info['cache location'])) {
danielebarchiesi@0 83 $form_info['cache location'] = 'storage';
danielebarchiesi@0 84 }
danielebarchiesi@0 85
danielebarchiesi@0 86 // If absolutely nothing was set for the cache area to work on
danielebarchiesi@0 87 if (!isset($form_state[$form_info['cache location']])) {
danielebarchiesi@0 88 ctools_include('cache');
danielebarchiesi@0 89 $form_state[$form_info['cache location']] = ctools_cache_get($form_info['cache mechanism'], $form_info['cache key']);
danielebarchiesi@0 90 }
danielebarchiesi@0 91 }
danielebarchiesi@0 92
danielebarchiesi@0 93 $form_state['step'] = $step;
danielebarchiesi@0 94 $form_state['form_info'] = $form_info;
danielebarchiesi@0 95
danielebarchiesi@0 96 // Ensure we have form information for the current step.
danielebarchiesi@0 97 if (!isset($form_info['forms'][$step])) {
danielebarchiesi@0 98 return;
danielebarchiesi@0 99 }
danielebarchiesi@0 100
danielebarchiesi@0 101 // Ensure that whatever include file(s) were requested by the form info are
danielebarchiesi@0 102 // actually included.
danielebarchiesi@0 103 $info = $form_info['forms'][$step];
danielebarchiesi@0 104
danielebarchiesi@0 105 if (!empty($info['include'])) {
danielebarchiesi@0 106 if (is_array($info['include'])) {
danielebarchiesi@0 107 foreach ($info['include'] as $file) {
danielebarchiesi@0 108 ctools_form_include_file($form_state, $file);
danielebarchiesi@0 109 }
danielebarchiesi@0 110 }
danielebarchiesi@0 111 else {
danielebarchiesi@0 112 ctools_form_include_file($form_state, $info['include']);
danielebarchiesi@0 113 }
danielebarchiesi@0 114 }
danielebarchiesi@0 115
danielebarchiesi@0 116 // This tells drupal_build_form to apply our wrapper to the form. It
danielebarchiesi@0 117 // will give it buttons and the like.
danielebarchiesi@0 118 $form_state['wrapper_callback'] = 'ctools_wizard_wrapper';
danielebarchiesi@0 119 if (!isset($form_state['rerender'])) {
danielebarchiesi@0 120 $form_state['rerender'] = FALSE;
danielebarchiesi@0 121 }
danielebarchiesi@0 122
danielebarchiesi@0 123 $form_state['no_redirect'] = TRUE;
danielebarchiesi@0 124
danielebarchiesi@0 125 $output = drupal_build_form($info['form id'], $form_state);
danielebarchiesi@0 126
danielebarchiesi@0 127 if (empty($form_state['executed']) || !empty($form_state['rerender'])) {
danielebarchiesi@0 128 if (empty($form_state['title']) && !empty($info['title'])) {
danielebarchiesi@0 129 $form_state['title'] = $info['title'];
danielebarchiesi@0 130 }
danielebarchiesi@0 131
danielebarchiesi@0 132 if (!empty($form_state['ajax render'])) {
danielebarchiesi@0 133 // Any include files should already be included by this point:
danielebarchiesi@0 134 return $form_state['ajax render']($form_state, $output);
danielebarchiesi@0 135 }
danielebarchiesi@0 136
danielebarchiesi@0 137 // Automatically use the modal tool if set to true.
danielebarchiesi@0 138 if (!empty($form_state['modal']) && empty($form_state['modal return'])) {
danielebarchiesi@0 139 ctools_include('modal');
danielebarchiesi@0 140
danielebarchiesi@0 141 // This overwrites any previous commands.
danielebarchiesi@0 142 $form_state['commands'] = ctools_modal_form_render($form_state, $output);
danielebarchiesi@0 143 }
danielebarchiesi@0 144 }
danielebarchiesi@0 145
danielebarchiesi@0 146 if (!empty($form_state['executed'])) {
danielebarchiesi@0 147 // We use the plugins get_function format because it's powerful and
danielebarchiesi@0 148 // not limited to just functions.
danielebarchiesi@0 149 ctools_include('plugins');
danielebarchiesi@0 150
danielebarchiesi@0 151 if (isset($form_state['clicked_button']['#wizard type'])) {
danielebarchiesi@0 152 $type = $form_state['clicked_button']['#wizard type'];
danielebarchiesi@0 153 // If we have a callback depending upon the type of button that was
danielebarchiesi@0 154 // clicked, call it.
danielebarchiesi@0 155 if ($function = ctools_plugin_get_function($form_info, "$type callback")) {
danielebarchiesi@0 156 $function($form_state);
danielebarchiesi@0 157 }
danielebarchiesi@0 158
danielebarchiesi@0 159 // If auto-caching is on, we need to write the cache on next and
danielebarchiesi@0 160 // clear the cache on finish.
danielebarchiesi@0 161 if (!empty($form_info['auto cache'])) {
danielebarchiesi@0 162 if ($type == 'next') {
danielebarchiesi@0 163 ctools_include('cache');
danielebarchiesi@0 164 ctools_cache_set($form_info['cache mechanism'], $form_info['cache key'], $form_state[$form_info['cache location']]);
danielebarchiesi@0 165 }
danielebarchiesi@0 166 elseif ($type == 'finish') {
danielebarchiesi@0 167 ctools_include('cache');
danielebarchiesi@0 168 ctools_cache_clear($form_info['cache mechanism'], $form_info['cache key']);
danielebarchiesi@0 169 }
danielebarchiesi@0 170 }
danielebarchiesi@0 171
danielebarchiesi@0 172 // Set a couple of niceties:
danielebarchiesi@0 173 if ($type == 'finish') {
danielebarchiesi@0 174 $form_state['complete'] = TRUE;
danielebarchiesi@0 175 }
danielebarchiesi@0 176
danielebarchiesi@0 177 if ($type == 'cancel') {
danielebarchiesi@0 178 $form_state['cancel'] = TRUE;
danielebarchiesi@0 179 }
danielebarchiesi@0 180
danielebarchiesi@0 181 // If the modal is in use, some special code for it:
danielebarchiesi@0 182 if (!empty($form_state['modal']) && empty($form_state['modal return'])) {
danielebarchiesi@0 183 if ($type != 'next') {
danielebarchiesi@0 184 // Automatically dismiss the modal if we're not going to another form.
danielebarchiesi@0 185 ctools_include('modal');
danielebarchiesi@0 186 $form_state['commands'][] = ctools_modal_command_dismiss();
danielebarchiesi@0 187 }
danielebarchiesi@0 188 }
danielebarchiesi@0 189 }
danielebarchiesi@0 190
danielebarchiesi@0 191 if (empty($form_state['ajax'])) {
danielebarchiesi@0 192 // redirect, if one is set.
danielebarchiesi@0 193 if ($form_state['redirect']) {
danielebarchiesi@0 194 if (is_array($form_state['redirect'])) {
danielebarchiesi@0 195 call_user_func_array('drupal_goto', $form_state['redirect']);
danielebarchiesi@0 196 }
danielebarchiesi@0 197 else {
danielebarchiesi@0 198 drupal_goto($form_state['redirect']);
danielebarchiesi@0 199 }
danielebarchiesi@0 200 }
danielebarchiesi@0 201 }
danielebarchiesi@0 202 else if (isset($form_state['ajax next'])) {
danielebarchiesi@0 203 // Clear a few items off the form state so we don't double post:
danielebarchiesi@0 204 $next = $form_state['ajax next'];
danielebarchiesi@0 205 unset($form_state['ajax next']);
danielebarchiesi@0 206 unset($form_state['executed']);
danielebarchiesi@0 207 unset($form_state['post']);
danielebarchiesi@0 208 unset($form_state['next']);
danielebarchiesi@0 209 return ctools_wizard_multistep_form($form_info, $next, $form_state);
danielebarchiesi@0 210 }
danielebarchiesi@0 211
danielebarchiesi@0 212 // If the callbacks wanted to do something besides go to the next form,
danielebarchiesi@0 213 // it needs to have set $form_state['commands'] with something that can
danielebarchiesi@0 214 // be rendered.
danielebarchiesi@0 215 }
danielebarchiesi@0 216
danielebarchiesi@0 217 // Render ajax commands if we have any.
danielebarchiesi@0 218 if (isset($form_state['ajax']) && isset($form_state['commands']) && empty($form_state['modal return'])) {
danielebarchiesi@0 219 return ajax_render($form_state['commands']);
danielebarchiesi@0 220 }
danielebarchiesi@0 221
danielebarchiesi@0 222 // Otherwise, return the output.
danielebarchiesi@0 223 return $output;
danielebarchiesi@0 224 }
danielebarchiesi@0 225
danielebarchiesi@0 226 /**
danielebarchiesi@0 227 * Provide a wrapper around another form for adding multi-step information.
danielebarchiesi@0 228 */
danielebarchiesi@0 229 function ctools_wizard_wrapper($form, &$form_state) {
danielebarchiesi@0 230 $form_info = &$form_state['form_info'];
danielebarchiesi@0 231 $info = $form_info['forms'][$form_state['step']];
danielebarchiesi@0 232
danielebarchiesi@0 233 // Determine the next form from this step.
danielebarchiesi@0 234 // Create a form trail if we're supposed to have one.
danielebarchiesi@0 235 $trail = array();
danielebarchiesi@0 236 $previous = TRUE;
danielebarchiesi@0 237 foreach ($form_info['order'] as $id => $title) {
danielebarchiesi@0 238 if ($id == $form_state['step']) {
danielebarchiesi@0 239 $previous = FALSE;
danielebarchiesi@0 240 $class = 'wizard-trail-current';
danielebarchiesi@0 241 }
danielebarchiesi@0 242 elseif ($previous) {
danielebarchiesi@0 243 $not_first = TRUE;
danielebarchiesi@0 244 $class = 'wizard-trail-previous';
danielebarchiesi@0 245 $form_state['previous'] = $id;
danielebarchiesi@0 246 }
danielebarchiesi@0 247 else {
danielebarchiesi@0 248 $class = 'wizard-trail-next';
danielebarchiesi@0 249 if (!isset($form_state['next'])) {
danielebarchiesi@0 250 $form_state['next'] = $id;
danielebarchiesi@0 251 }
danielebarchiesi@0 252 if (empty($form_info['show trail'])) {
danielebarchiesi@0 253 break;
danielebarchiesi@0 254 }
danielebarchiesi@0 255 }
danielebarchiesi@0 256
danielebarchiesi@0 257 if (!empty($form_info['show trail'])) {
danielebarchiesi@0 258 if (!empty($form_info['free trail'])) {
danielebarchiesi@0 259 // ctools_wizard_get_path() returns results suitable for
danielebarchiesi@0 260 // $form_state['redirect] which can only be directly used in
danielebarchiesi@0 261 // drupal_goto. We have to futz a bit with it.
danielebarchiesi@0 262 $path = ctools_wizard_get_path($form_info, $id);
danielebarchiesi@0 263 $options = array();
danielebarchiesi@0 264 if (!empty($path[1])) {
danielebarchiesi@0 265 $options = $path[1];
danielebarchiesi@0 266 }
danielebarchiesi@0 267 $title = l($title, $path[0], $options);
danielebarchiesi@0 268 }
danielebarchiesi@0 269 $trail[] = '<span class="' . $class . '">' . $title . '</span>';
danielebarchiesi@0 270 }
danielebarchiesi@0 271 }
danielebarchiesi@0 272
danielebarchiesi@0 273 // Display the trail if instructed to do so.
danielebarchiesi@0 274 if (!empty($form_info['show trail'])) {
danielebarchiesi@0 275 ctools_add_css('wizard');
danielebarchiesi@0 276 $form['ctools_trail'] = array(
danielebarchiesi@0 277 '#markup' => theme(array('ctools_wizard_trail__' . $form_info['id'], 'ctools_wizard_trail'), array('trail' => $trail)),
danielebarchiesi@0 278 '#weight' => -1000,
danielebarchiesi@0 279 );
danielebarchiesi@0 280 }
danielebarchiesi@0 281
danielebarchiesi@0 282 if (empty($form_info['no buttons'])) {
danielebarchiesi@0 283 // Ensure buttons stay on the bottom.
danielebarchiesi@0 284 $form['buttons'] = array(
danielebarchiesi@0 285 '#type' => 'actions',
danielebarchiesi@0 286 '#weight' => 1000,
danielebarchiesi@0 287 );
danielebarchiesi@0 288
danielebarchiesi@0 289 $button_attributes = array();
danielebarchiesi@0 290 if (!empty($form_state['ajax']) && empty($form_state['modal'])) {
danielebarchiesi@0 291 $button_attributes = array('class' => array('ctools-use-ajax'));
danielebarchiesi@0 292 }
danielebarchiesi@0 293
danielebarchiesi@0 294 if (!empty($form_info['show back']) && isset($form_state['previous'])) {
danielebarchiesi@0 295 $form['buttons']['previous'] = array(
danielebarchiesi@0 296 '#type' => 'submit',
danielebarchiesi@0 297 '#value' => $form_info['back text'],
danielebarchiesi@0 298 '#next' => $form_state['previous'],
danielebarchiesi@0 299 '#wizard type' => 'next',
danielebarchiesi@0 300 '#weight' => -2000,
danielebarchiesi@0 301 '#limit_validation_errors' => array(),
danielebarchiesi@0 302 // hardcode the submit so that it doesn't try to save data.
danielebarchiesi@0 303 '#submit' => array('ctools_wizard_submit'),
danielebarchiesi@0 304 '#attributes' => $button_attributes,
danielebarchiesi@0 305 );
danielebarchiesi@0 306
danielebarchiesi@0 307 if (isset($form_info['no back validate']) || isset($info['no back validate'])) {
danielebarchiesi@0 308 $form['buttons']['previous']['#validate'] = array();
danielebarchiesi@0 309 }
danielebarchiesi@0 310 }
danielebarchiesi@0 311
danielebarchiesi@0 312 // If there is a next form, place the next button.
danielebarchiesi@0 313 if (isset($form_state['next']) || !empty($form_info['free trail'])) {
danielebarchiesi@0 314 $form['buttons']['next'] = array(
danielebarchiesi@0 315 '#type' => 'submit',
danielebarchiesi@0 316 '#value' => $form_info['next text'],
danielebarchiesi@0 317 '#next' => !empty($form_info['free trail']) ? $form_state['step'] : $form_state['next'],
danielebarchiesi@0 318 '#wizard type' => 'next',
danielebarchiesi@0 319 '#weight' => -1000,
danielebarchiesi@0 320 '#attributes' => $button_attributes,
danielebarchiesi@0 321 );
danielebarchiesi@0 322 }
danielebarchiesi@0 323
danielebarchiesi@0 324 // There are two ways the return button can appear. If this is not the
danielebarchiesi@0 325 // end of the form list (i.e, there is a next) then it's "update and return"
danielebarchiesi@0 326 // to be clear. If this is the end of the path and there is no next, we
danielebarchiesi@0 327 // call it 'Finish'.
danielebarchiesi@0 328
danielebarchiesi@0 329 // Even if there is no direct return path (some forms may not want you
danielebarchiesi@0 330 // leaving in the middle) the final button is always a Finish and it does
danielebarchiesi@0 331 // whatever the return action is.
danielebarchiesi@0 332 if (!empty($form_info['show return']) && !empty($form_state['next'])) {
danielebarchiesi@0 333 $form['buttons']['return'] = array(
danielebarchiesi@0 334 '#type' => 'submit',
danielebarchiesi@0 335 '#value' => $form_info['return text'],
danielebarchiesi@0 336 '#wizard type' => 'return',
danielebarchiesi@0 337 '#attributes' => $button_attributes,
danielebarchiesi@0 338 );
danielebarchiesi@0 339 }
danielebarchiesi@0 340 else if (empty($form_state['next']) || !empty($form_info['free trail'])) {
danielebarchiesi@0 341 $form['buttons']['return'] = array(
danielebarchiesi@0 342 '#type' => 'submit',
danielebarchiesi@0 343 '#value' => $form_info['finish text'],
danielebarchiesi@0 344 '#wizard type' => 'finish',
danielebarchiesi@0 345 '#attributes' => $button_attributes,
danielebarchiesi@0 346 );
danielebarchiesi@0 347 }
danielebarchiesi@0 348
danielebarchiesi@0 349 // If we are allowed to cancel, place a cancel button.
danielebarchiesi@0 350 if ((isset($form_info['cancel path']) && !isset($form_info['show cancel'])) || !empty($form_info['show cancel'])) {
danielebarchiesi@0 351 $form['buttons']['cancel'] = array(
danielebarchiesi@0 352 '#type' => 'submit',
danielebarchiesi@0 353 '#value' => $form_info['cancel text'],
danielebarchiesi@0 354 '#wizard type' => 'cancel',
danielebarchiesi@0 355 // hardcode the submit so that it doesn't try to save data.
danielebarchiesi@0 356 '#limit_validation_errors' => array(),
danielebarchiesi@0 357 '#submit' => array('ctools_wizard_submit'),
danielebarchiesi@0 358 '#attributes' => $button_attributes,
danielebarchiesi@0 359 );
danielebarchiesi@0 360 }
danielebarchiesi@0 361
danielebarchiesi@0 362 // Set up optional validate handlers.
danielebarchiesi@0 363 $form['#validate'] = array();
danielebarchiesi@0 364 if (function_exists($info['form id'] . '_validate')) {
danielebarchiesi@0 365 $form['#validate'][] = $info['form id'] . '_validate';
danielebarchiesi@0 366 }
danielebarchiesi@0 367 if (isset($info['validate']) && function_exists($info['validate'])) {
danielebarchiesi@0 368 $form['#validate'][] = $info['validate'];
danielebarchiesi@0 369 }
danielebarchiesi@0 370
danielebarchiesi@0 371 // Set up our submit handler after theirs. Since putting something here will
danielebarchiesi@0 372 // skip Drupal's autodetect, we autodetect for it.
danielebarchiesi@0 373
danielebarchiesi@0 374 // We make sure ours is after theirs so that they get to change #next if
danielebarchiesi@0 375 // the want to.
danielebarchiesi@0 376 $form['#submit'] = array();
danielebarchiesi@0 377 if (function_exists($info['form id'] . '_submit')) {
danielebarchiesi@0 378 $form['#submit'][] = $info['form id'] . '_submit';
danielebarchiesi@0 379 }
danielebarchiesi@0 380 if (isset($info['submit']) && function_exists($info['submit'])) {
danielebarchiesi@0 381 $form['#submit'][] = $info['submit'];
danielebarchiesi@0 382 }
danielebarchiesi@0 383 $form['#submit'][] = 'ctools_wizard_submit';
danielebarchiesi@0 384 }
danielebarchiesi@0 385
danielebarchiesi@0 386 if (!empty($form_state['ajax'])) {
danielebarchiesi@0 387 $params = ctools_wizard_get_path($form_state['form_info'], $form_state['step']);
danielebarchiesi@0 388 if (count($params) > 1) {
danielebarchiesi@0 389 $url = array_shift($params);
danielebarchiesi@0 390 $options = array();
danielebarchiesi@0 391
danielebarchiesi@0 392 $keys = array(0 => 'query', 1 => 'fragment');
danielebarchiesi@0 393 foreach ($params as $key => $value) {
danielebarchiesi@0 394 if (isset($keys[$key]) && isset($value)) {
danielebarchiesi@0 395 $options[$keys[$key]] = $value;
danielebarchiesi@0 396 }
danielebarchiesi@0 397 }
danielebarchiesi@0 398
danielebarchiesi@0 399 $params = array($url, $options);
danielebarchiesi@0 400 }
danielebarchiesi@0 401 $form['#action'] = call_user_func_array('url', $params);
danielebarchiesi@0 402 }
danielebarchiesi@0 403
danielebarchiesi@0 404 if (isset($info['wrapper']) && function_exists($info['wrapper'])) {
danielebarchiesi@0 405 $form = $info['wrapper']($form, $form_state);
danielebarchiesi@0 406 }
danielebarchiesi@0 407
danielebarchiesi@0 408 if (isset($form_info['wrapper']) && function_exists($form_info['wrapper'])) {
danielebarchiesi@0 409 $form = $form_info['wrapper']($form, $form_state);
danielebarchiesi@0 410 }
danielebarchiesi@0 411 return $form;
danielebarchiesi@0 412 }
danielebarchiesi@0 413
danielebarchiesi@0 414 /**
danielebarchiesi@0 415 * On a submit, go to the next form.
danielebarchiesi@0 416 */
danielebarchiesi@0 417 function ctools_wizard_submit(&$form, &$form_state) {
danielebarchiesi@0 418 if (isset($form_state['clicked_button']['#wizard type'])) {
danielebarchiesi@0 419 $type = $form_state['clicked_button']['#wizard type'];
danielebarchiesi@0 420
danielebarchiesi@0 421 // if AJAX enabled, we proceed slightly differently here.
danielebarchiesi@0 422 if (!empty($form_state['ajax'])) {
danielebarchiesi@0 423 if ($type == 'next') {
danielebarchiesi@0 424 $form_state['ajax next'] = $form_state['clicked_button']['#next'];
danielebarchiesi@0 425 }
danielebarchiesi@0 426 }
danielebarchiesi@0 427 else {
danielebarchiesi@0 428 if ($type == 'cancel' && isset($form_state['form_info']['cancel path'])) {
danielebarchiesi@0 429 $form_state['redirect'] = $form_state['form_info']['cancel path'];
danielebarchiesi@0 430 }
danielebarchiesi@0 431 else if ($type == 'next') {
danielebarchiesi@0 432 $form_state['redirect'] = ctools_wizard_get_path($form_state['form_info'], $form_state['clicked_button']['#next']);
danielebarchiesi@0 433 if (!empty($_GET['destination'])) {
danielebarchiesi@0 434 // We don't want drupal_goto redirect this request
danielebarchiesi@0 435 // back. ctools_wizard_get_path ensures that the destination is
danielebarchiesi@0 436 // carried over on subsequent pages.
danielebarchiesi@0 437 unset($_GET['destination']);
danielebarchiesi@0 438 }
danielebarchiesi@0 439 }
danielebarchiesi@0 440 else if (isset($form_state['form_info']['return path'])) {
danielebarchiesi@0 441 $form_state['redirect'] = $form_state['form_info']['return path'];
danielebarchiesi@0 442 }
danielebarchiesi@0 443 else if ($type == 'finish' && isset($form_state['form_info']['cancel path'])) {
danielebarchiesi@0 444 $form_state['redirect'] = $form_state['form_info']['cancel path'];
danielebarchiesi@0 445 }
danielebarchiesi@0 446 }
danielebarchiesi@0 447 }
danielebarchiesi@0 448 }
danielebarchiesi@0 449
danielebarchiesi@0 450 /**
danielebarchiesi@0 451 * Create a path from the form info and a given step.
danielebarchiesi@0 452 */
danielebarchiesi@0 453 function ctools_wizard_get_path($form_info, $step) {
danielebarchiesi@0 454 if (is_array($form_info['path'])) {
danielebarchiesi@0 455 foreach ($form_info['path'] as $id => $part) {
danielebarchiesi@0 456 $form_info['path'][$id] = str_replace('%step', $step, $form_info['path'][$id]);
danielebarchiesi@0 457 }
danielebarchiesi@0 458 $path = $form_info['path'];
danielebarchiesi@0 459 }
danielebarchiesi@0 460 else {
danielebarchiesi@0 461 $path = array(str_replace('%step', $step, $form_info['path']));
danielebarchiesi@0 462 }
danielebarchiesi@0 463
danielebarchiesi@0 464 // If destination is set, carry it over so it'll take effect when
danielebarchiesi@0 465 // saving. The submit handler will unset destination to avoid drupal_goto
danielebarchiesi@0 466 // redirecting us.
danielebarchiesi@0 467 if (!empty($_GET['destination'])) {
danielebarchiesi@0 468 // Ensure that options is an array.
danielebarchiesi@0 469 if (!isset($path[1]) || !is_array($path[1])) {
danielebarchiesi@0 470 $path[1] = array();
danielebarchiesi@0 471 }
danielebarchiesi@0 472 // Ensure that the query part of options is an array.
danielebarchiesi@0 473 $path[1] += array('query' => array());
danielebarchiesi@0 474 // Add the destination parameter, if not set already.
danielebarchiesi@0 475 $path[1]['query'] += drupal_get_destination();
danielebarchiesi@0 476 }
danielebarchiesi@0 477
danielebarchiesi@0 478 return $path;
danielebarchiesi@0 479 }
danielebarchiesi@0 480
danielebarchiesi@0 481 /**
danielebarchiesi@0 482 * Set default parameters and callbacks if none are given.
danielebarchiesi@0 483 * Callbacks follows pattern:
danielebarchiesi@0 484 * $form_info['id']_$hook
danielebarchiesi@0 485 * $form_info['id']_$form_info['forms'][$step_key]_$hook
danielebarchiesi@0 486 */
danielebarchiesi@0 487 function ctools_wizard_defaults(&$form_info) {
danielebarchiesi@0 488 $hook = $form_info['id'];
danielebarchiesi@0 489 $defaults = array(
danielebarchiesi@0 490 'show trail' => FALSE,
danielebarchiesi@0 491 'free trail' => FALSE,
danielebarchiesi@0 492 'show back' => FALSE,
danielebarchiesi@0 493 'show cancel' => FALSE,
danielebarchiesi@0 494 'show return' => FALSE,
danielebarchiesi@0 495 'next text' => t('Continue'),
danielebarchiesi@0 496 'back text' => t('Back'),
danielebarchiesi@0 497 'return text' => t('Update and return'),
danielebarchiesi@0 498 'finish text' => t('Finish'),
danielebarchiesi@0 499 'cancel text' => t('Cancel'),
danielebarchiesi@0 500 );
danielebarchiesi@0 501
danielebarchiesi@0 502 if (!empty($form_info['free trail'])) {
danielebarchiesi@0 503 $defaults['next text'] = t('Update');
danielebarchiesi@0 504 $defaults['finish text'] = t('Save');
danielebarchiesi@0 505 }
danielebarchiesi@0 506
danielebarchiesi@0 507 $form_info = $form_info + $defaults;
danielebarchiesi@0 508 // set form callbacks if they aren't defined
danielebarchiesi@0 509 foreach ($form_info['forms'] as $step => $params) {
danielebarchiesi@0 510 if (!$params['form id']) {
danielebarchiesi@0 511 $form_callback = $hook . '_' . $step . '_form';
danielebarchiesi@0 512 $form_info['forms'][$step]['form id'] = $form_callback;
danielebarchiesi@0 513 }
danielebarchiesi@0 514 }
danielebarchiesi@0 515
danielebarchiesi@0 516 // set button callbacks
danielebarchiesi@0 517 $callbacks = array(
danielebarchiesi@0 518 'back callback' => '_back',
danielebarchiesi@0 519 'next callback' => '_next',
danielebarchiesi@0 520 'return callback' => '_return',
danielebarchiesi@0 521 'cancel callback' => '_cancel',
danielebarchiesi@0 522 'finish callback' => '_finish',
danielebarchiesi@0 523 );
danielebarchiesi@0 524
danielebarchiesi@0 525 foreach ($callbacks as $key => $callback) {
danielebarchiesi@0 526 // never overwrite if explicity defined
danielebarchiesi@0 527 if (empty($form_info[$key])) {
danielebarchiesi@0 528 $wizard_callback = $hook . $callback;
danielebarchiesi@0 529 if (function_exists($wizard_callback)) {
danielebarchiesi@0 530 $form_info[$key] = $wizard_callback;
danielebarchiesi@0 531 }
danielebarchiesi@0 532 }
danielebarchiesi@0 533 }
danielebarchiesi@0 534 }