Projet

Général

Profil

Paste
Télécharger (59,1 ko) Statistiques
| Branche: | Révision:

root / drupal7 / modules / simpletest / tests / form_test.module @ cd5c298a

1
<?php
2

    
3
/**
4
 * @file
5
 * Helper module for the form API tests.
6
 */
7

    
8
/**
9
 * Implements hook_menu().
10
 */
11
function form_test_menu() {
12
  $items['form-test/alter'] = array(
13
    'title' => 'Form altering test',
14
    'page callback' => 'drupal_get_form',
15
    'page arguments' => array('form_test_alter_form'),
16
    'access arguments' => array('access content'),
17
    'type' => MENU_CALLBACK,
18
  );
19
  $items['form-test/validate'] = array(
20
    'title' => 'Form validation handlers test',
21
    'page callback' => 'drupal_get_form',
22
    'page arguments' => array('form_test_validate_form'),
23
    'access arguments' => array('access content'),
24
    'type' => MENU_CALLBACK,
25
  );
26
  $items['form-test/validate-required'] = array(
27
    'title' => 'Form #required validation',
28
    'page callback' => 'drupal_get_form',
29
    'page arguments' => array('form_test_validate_required_form'),
30
    'access callback' => TRUE,
31
    'type' => MENU_CALLBACK,
32
  );
33
  $items['form-test/validate-required-no-title'] = array(
34
    'title' => 'Form #required validation without #title',
35
    'page callback' => 'drupal_get_form',
36
    'page arguments' => array('form_test_validate_required_form_no_title'),
37
    'access callback' => TRUE,
38
    'type' => MENU_CALLBACK,
39
  );
40
  $items['form-test/validate-no-token'] = array(
41
    'title' => 'Form validation without a CSRF token',
42
    'page callback' => 'drupal_get_form',
43
    'page arguments' => array('form_test_validate_no_token'),
44
    'access callback' => TRUE,
45
    'type' => MENU_CALLBACK,
46
  );
47
  $items['form-test/limit-validation-errors'] = array(
48
    'title' => 'Form validation with some error suppression',
49
    'page callback' => 'drupal_get_form',
50
    'page arguments' => array('form_test_limit_validation_errors_form'),
51
    'access arguments' => array('access content'),
52
    'type' => MENU_CALLBACK,
53
  );
54

    
55
  $items['form_test/tableselect/multiple-true'] = array(
56
    'title' => 'Tableselect checkboxes test',
57
    'page callback' => 'drupal_get_form',
58
    'page arguments' => array('_form_test_tableselect_multiple_true_form'),
59
    'access arguments' => array('access content'),
60
    'type' => MENU_CALLBACK,
61
  );
62
  $items['form_test/tableselect/multiple-false'] = array(
63
    'title' => 'Tableselect radio button test',
64
    'page callback' => 'drupal_get_form',
65
    'page arguments' => array('_form_test_tableselect_multiple_false_form'),
66
    'access arguments' => array('access content'),
67
    'type' => MENU_CALLBACK,
68
  );
69
  $items['form_test/tableselect/empty-text'] = array(
70
    'title' => 'Tableselect empty text test',
71
    'page callback' => 'drupal_get_form',
72
    'page arguments' => array('_form_test_tableselect_empty_form'),
73
    'access arguments' => array('access content'),
74
    'type' => MENU_CALLBACK,
75
  );
76
  $items['form_test/tableselect/advanced-select'] = array(
77
    'title' => 'Tableselect js_select tests',
78
    'page callback' => 'drupal_get_form',
79
    'page arguments' => array('_form_test_tableselect_js_select_form'),
80
    'access arguments' => array('access content'),
81
    'type' => MENU_CALLBACK,
82
  );
83

    
84
  $items['form_test/vertical-tabs'] = array(
85
    'title' => 'Vertical tabs tests',
86
    'page callback' => 'drupal_get_form',
87
    'page arguments' => array('_form_test_vertical_tabs_form'),
88
    'access arguments' => array('access content'),
89
    'type' => MENU_CALLBACK,
90
  );
91

    
92
  $items['form_test/form-storage'] = array(
93
    'title' => 'Form storage test',
94
    'page callback' => 'drupal_get_form',
95
    'page arguments' => array('form_test_storage_form'),
96
    'access arguments' => array('access content'),
97
    'type' => MENU_CALLBACK,
98
  );
99

    
100
  $items['form_test/form-storage-legacy'] = array(
101
    'title' => 'Emulate legacy AHAH-style ajax callback',
102
    'page callback' => 'form_test_storage_legacy_handler',
103
    'access arguments' => array('access content'),
104
    'type' => MENU_CALLBACK,
105
  );
106

    
107
  $items['form_test/form-storage-page-cache'] = array(
108
    'title' => 'Form storage with page cache test',
109
    'page callback' => 'drupal_get_form',
110
    'page arguments' => array('form_test_storage_page_cache_form'),
111
    'access arguments' => array('access content'),
112
    'type' => MENU_CALLBACK,
113
  );
114

    
115
  $items['form_test/wrapper-callback'] = array(
116
    'title' => 'Form wrapper callback test',
117
    'page callback' => 'form_test_wrapper_callback',
118
    'page arguments' => array('form_test_wrapper_callback_form'),
119
    'access arguments' => array('access content'),
120
    'type' => MENU_CALLBACK,
121
  );
122

    
123
  $items['form_test/form-state-values-clean'] = array(
124
    'title' => 'Form state values clearance test',
125
    'page callback' => 'drupal_get_form',
126
    'page arguments' => array('form_test_form_state_values_clean_form'),
127
    'access arguments' => array('access content'),
128
    'type' => MENU_CALLBACK,
129
  );
130

    
131
  $items['form_test/form-state-values-clean-advanced'] = array(
132
    'title' => 'Form state values clearance advanced test',
133
    'page callback' => 'drupal_get_form',
134
    'page arguments' => array('form_test_form_state_values_clean_advanced_form'),
135
    'access arguments' => array('access content'),
136
    'type' => MENU_CALLBACK,
137
  );
138

    
139
  $items['form-test/checkbox'] = array(
140
    'title' => t('Form test'),
141
    'page callback' => 'drupal_get_form',
142
    'page arguments' => array('_form_test_checkbox'),
143
    'access callback' => TRUE,
144
    'type' => MENU_CALLBACK,
145
  );
146
  $items['form-test/select'] = array(
147
    'title' => t('Select'),
148
    'page callback' => 'drupal_get_form',
149
    'page arguments' => array('form_test_select'),
150
    'access callback' => TRUE,
151
  );
152
  $items['form-test/checkboxes-radios'] = array(
153
    'title' => t('Checkboxes, Radios'),
154
    'page callback' => 'drupal_get_form',
155
    'page arguments' => array('form_test_checkboxes_radios'),
156
    'access callback' => TRUE,
157
  );
158

    
159
  $items['form-test/disabled-elements'] = array(
160
    'title' => t('Form test'),
161
    'page callback' => 'drupal_get_form',
162
    'page arguments' => array('_form_test_disabled_elements'),
163
    'access callback' => TRUE,
164
    'type' => MENU_CALLBACK,
165
  );
166

    
167
  $items['form-test/input-forgery'] = array(
168
    'title' => t('Form test'),
169
    'page callback' => 'drupal_get_form',
170
    'page arguments' => array('_form_test_input_forgery'),
171
    'access callback' => TRUE,
172
    'type' => MENU_CALLBACK,
173
  );
174

    
175
  $items['form-test/form-rebuild-preserve-values'] = array(
176
    'title' => 'Form values preservation during rebuild test',
177
    'page callback' => 'drupal_get_form',
178
    'page arguments' => array('form_test_form_rebuild_preserve_values_form'),
179
    'access arguments' => array('access content'),
180
    'type' => MENU_CALLBACK,
181
  );
182

    
183
  $items['form-test/redirect'] = array(
184
    'title' => 'Redirect test',
185
    'page callback' => 'drupal_get_form',
186
    'page arguments' => array('form_test_redirect'),
187
    'access callback' => TRUE,
188
    'type' => MENU_CALLBACK,
189
  );
190

    
191
  $items['form_test/form-labels'] = array(
192
    'title' => 'Form label test',
193
    'page callback' => 'drupal_get_form',
194
    'page arguments' => array('form_label_test_form'),
195
    'access arguments' => array('access content'),
196
    'type' => MENU_CALLBACK,
197
  );
198

    
199
  $items['form-test/state-persist'] = array(
200
    'title' => 'Form state persistence without storage',
201
    'page callback' => 'drupal_get_form',
202
    'page arguments' => array('form_test_state_persist'),
203
    'access callback' => TRUE,
204
    'type' => MENU_CALLBACK,
205
  );
206

    
207
  $items['form-test/clicked-button'] = array(
208
    'title' => 'Clicked button test',
209
    'page callback' => 'drupal_get_form',
210
    'page arguments' => array('form_test_clicked_button'),
211
    'access callback' => TRUE,
212
    'type' => MENU_CALLBACK,
213
  );
214

    
215
  if (module_exists('node')) {
216
    $items['form-test/two-instances-of-same-form'] = array(
217
      'title' => 'AJAX test with two form instances',
218
      'page callback' => 'form_test_two_instances',
219
      'access callback' => 'node_access',
220
      'access arguments' => array('create', 'page'),
221
      'file path' => drupal_get_path('module', 'node'),
222
      'file' => 'node.pages.inc',
223
      'type' => MENU_CALLBACK,
224
    );
225
  }
226
  $items['form-test/double-form'] = array(
227
    'title' => 'Double form test',
228
    'page callback' => 'form_test_double_form',
229
    'access callback' => TRUE,
230
    'type' => MENU_CALLBACK,
231
  );
232

    
233
  $items['form-test/load-include-menu'] = array(
234
    'title' => 'FAPI test loading includes',
235
    'page callback' => 'drupal_get_form',
236
    'page arguments' => array('form_test_load_include_menu'),
237
    'access callback' => TRUE,
238
    'file' => 'form_test.file.inc',
239
    'type' => MENU_CALLBACK,
240
  );
241

    
242
  $items['form-test/load-include-custom'] = array(
243
    'title' => 'FAPI test loading includes',
244
    'page callback' => 'drupal_get_form',
245
    'page arguments' => array('form_test_load_include_custom'),
246
    'access callback' => TRUE,
247
    'type' => MENU_CALLBACK,
248
  );
249
  $items['form-test/checkboxes-zero'] = array(
250
    'title' => 'FAPI test involving checkboxes and zero',
251
    'page callback' => 'drupal_get_form',
252
    'page arguments' => array('form_test_checkboxes_zero'),
253
    'access callback' => TRUE,
254
    'type' => MENU_CALLBACK,
255
  );
256

    
257
  return $items;
258
}
259

    
260
/**
261
 * Form submit handler to return form values as JSON.
262
 */
263
function _form_test_submit_values_json($form, &$form_state) {
264
  drupal_json_output($form_state['values']);
265
  drupal_exit();
266
}
267

    
268
/**
269
 * Form builder for testing hook_form_alter() and hook_form_FORM_ID_alter().
270
 */
271
function form_test_alter_form($form, &$form_state) {
272
  // Elements can be added as needed for future testing needs, but for now,
273
  // we're only testing alter hooks that do not require any elements added by
274
  // this function.
275
  return $form;
276
}
277

    
278
/**
279
 * Implements hook_form_FORM_ID_alter() on behalf of block.module.
280
 */
281
function block_form_form_test_alter_form_alter(&$form, &$form_state) {
282
  drupal_set_message('block_form_form_test_alter_form_alter() executed.');
283
}
284

    
285
/**
286
 * Implements hook_form_alter().
287
 */
288
function form_test_form_alter(&$form, &$form_state, $form_id) {
289
  if ($form_id == 'form_test_alter_form') {
290
    drupal_set_message('form_test_form_alter() executed.');
291
  }
292
}
293

    
294
/**
295
 * Implements hook_form_FORM_ID_alter().
296
 */
297
function form_test_form_form_test_alter_form_alter(&$form, &$form_state) {
298
  drupal_set_message('form_test_form_form_test_alter_form_alter() executed.');
299
}
300

    
301
/**
302
 * Implements hook_form_FORM_ID_alter() on behalf of system.module.
303
 */
304
function system_form_form_test_alter_form_alter(&$form, &$form_state) {
305
  drupal_set_message('system_form_form_test_alter_form_alter() executed.');
306
}
307

    
308
/**
309
 * Form builder for testing drupal_validate_form().
310
 *
311
 * Serves for testing form processing and alterations by form validation
312
 * handlers, especially for the case of a validation error:
313
 * - form_set_value() should be able to alter submitted values in
314
 *   $form_state['values'] without affecting the form element.
315
 * - #element_validate handlers should be able to alter the $element in the form
316
 *   structure and the alterations should be contained in the rebuilt form.
317
 * - #validate handlers should be able to alter the $form and the alterations
318
 *   should be contained in the rebuilt form.
319
 */
320
function form_test_validate_form($form, &$form_state) {
321
  $form['name'] = array(
322
    '#type' => 'textfield',
323
    '#title' => 'Name',
324
    '#default_value' => '',
325
    '#element_validate' => array('form_test_element_validate_name'),
326
  );
327
  $form['submit'] = array(
328
    '#type' => 'submit',
329
    '#value' => 'Save',
330
  );
331

    
332
  // To simplify this test, enable form caching and use form storage to
333
  // remember our alteration.
334
  $form_state['cache'] = TRUE;
335

    
336
  return $form;
337
}
338

    
339
/**
340
 * Form element validation handler for 'name' in form_test_validate_form().
341
 */
342
function form_test_element_validate_name(&$element, &$form_state) {
343
  $triggered = FALSE;
344
  if ($form_state['values']['name'] == 'element_validate') {
345
    // Alter the form element.
346
    $element['#value'] = '#value changed by #element_validate';
347
    // Alter the submitted value in $form_state.
348
    form_set_value($element, 'value changed by form_set_value() in #element_validate', $form_state);
349

    
350
    $triggered = TRUE;
351
  }
352
  if ($form_state['values']['name'] == 'element_validate_access') {
353
    $form_state['storage']['form_test_name'] = $form_state['values']['name'];
354
    // Alter the form element.
355
    $element['#access'] = FALSE;
356

    
357
    $triggered = TRUE;
358
  }
359
  elseif (!empty($form_state['storage']['form_test_name'])) {
360
    // To simplify this test, just take over the element's value into $form_state.
361
    form_set_value($element, $form_state['storage']['form_test_name'], $form_state);
362

    
363
    $triggered = TRUE;
364
  }
365

    
366
  if ($triggered) {
367
    // Output the element's value from $form_state.
368
    drupal_set_message(t('@label value: @value', array('@label' => $element['#title'], '@value' => $form_state['values']['name'])));
369

    
370
    // Trigger a form validation error to see our changes.
371
    form_set_error('');
372
  }
373
}
374

    
375
/**
376
 * Form validation handler for form_test_validate_form().
377
 */
378
function form_test_validate_form_validate(&$form, &$form_state) {
379
  if ($form_state['values']['name'] == 'validate') {
380
    // Alter the form element.
381
    $form['name']['#value'] = '#value changed by #validate';
382
    // Alter the submitted value in $form_state.
383
    form_set_value($form['name'], 'value changed by form_set_value() in #validate', $form_state);
384
    // Output the element's value from $form_state.
385
    drupal_set_message(t('@label value: @value', array('@label' => $form['name']['#title'], '@value' => $form_state['values']['name'])));
386

    
387
    // Trigger a form validation error to see our changes.
388
    form_set_error('');
389
  }
390
}
391

    
392
/**
393
 * Form constructor to test the #required property.
394
 */
395
function form_test_validate_required_form($form, &$form_state) {
396
  $options = drupal_map_assoc(array('foo', 'bar'));
397

    
398
  $form['textfield'] = array(
399
    '#type' => 'textfield',
400
    '#title' => 'Textfield',
401
    '#required' => TRUE,
402
  );
403
  $form['checkboxes'] = array(
404
    '#type' => 'checkboxes',
405
    '#title' => 'Checkboxes',
406
    '#options' => $options,
407
    '#required' => TRUE,
408
  );
409
  $form['select'] = array(
410
    '#type' => 'select',
411
    '#title' => 'Select',
412
    '#options' => $options,
413
    '#required' => TRUE,
414
  );
415
  $form['radios'] = array(
416
    '#type' => 'radios',
417
    '#title' => 'Radios',
418
    '#options' => $options,
419
    '#required' => TRUE,
420
  );
421
  $form['radios_optional'] = array(
422
    '#type' => 'radios',
423
    '#title' => 'Radios (optional)',
424
    '#options' => $options,
425
  );
426
  $form['radios_optional_default_value_false'] = array(
427
    '#type' => 'radios',
428
    '#title' => 'Radios (optional, with a default value of FALSE)',
429
    '#options' => $options,
430
    '#default_value' => FALSE,
431
  );
432
  $form['actions'] = array('#type' => 'actions');
433
  $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Submit');
434
  return $form;
435
}
436

    
437
/**
438
 * Form submission handler for form_test_validate_required_form().
439
 */
440
function form_test_validate_required_form_submit($form, &$form_state) {
441
  drupal_set_message('The form_test_validate_required_form form was submitted successfully.');
442
}
443

    
444
/**
445
 * Form constructor to test the #required property without #title.
446
 */
447
function form_test_validate_required_form_no_title($form, &$form_state) {
448
  $form['textfield'] = array(
449
    '#type' => 'textfield',
450
    '#required' => TRUE,
451
  );
452
  $form['actions'] = array('#type' => 'actions');
453
  $form['actions']['submit'] = array('#type' => 'submit', '#value' => 'Submit');
454
  return $form;
455
}
456

    
457
/**
458
 * Form submission handler for form_test_validate_required_form_no_title().
459
 */
460
function form_test_validate_required_form_no_title_submit($form, &$form_state) {
461
  drupal_set_message('The form_test_validate_required_form_no_title form was submitted successfully.');
462
}
463

    
464
/**
465
 * Form builder for testing submission of a form without a CSRF token.
466
 */
467
function form_test_validate_no_token($form, &$form_state) {
468
  $form['submit'] = array(
469
    '#type' => 'submit',
470
    '#value' => 'Save',
471
  );
472

    
473
  $form['#token'] = FALSE;
474

    
475
  return $form;
476
}
477

    
478
/**
479
 * Form submission handler for form_test_validate_no_token().
480
 */
481
function form_test_validate_no_token_submit($form, &$form_state) {
482
  drupal_set_message('The form_test_validate_no_token form has been submitted successfully.');
483
}
484

    
485
/**
486
 * Builds a simple form with a button triggering partial validation.
487
 */
488
function form_test_limit_validation_errors_form($form, &$form_state) {
489
  $form['title'] = array(
490
    '#type' => 'textfield',
491
    '#title' => 'Title',
492
    '#required' => TRUE,
493
  );
494

    
495
  $form['test'] = array(
496
    '#title' => 'Test',
497
    '#type' => 'textfield',
498
    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
499
  );
500
  $form['test_numeric_index'] = array(
501
    '#tree' => TRUE,
502
  );
503
  $form['test_numeric_index'][0] = array(
504
    '#title' => 'Test (numeric index)',
505
    '#type' => 'textfield',
506
    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
507
  );
508

    
509
  $form['test_substring'] = array(
510
    '#tree' => TRUE,
511
  );
512
  $form['test_substring']['foo'] = array(
513
    '#title' => 'Test (substring) foo',
514
    '#type' => 'textfield',
515
    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
516
  );
517
  $form['test_substring']['foobar'] = array(
518
    '#title' => 'Test (substring) foobar',
519
    '#type' => 'textfield',
520
    '#element_validate' => array('form_test_limit_validation_errors_element_validate_test'),
521
  );
522

    
523
  $form['actions']['partial'] = array(
524
    '#type' => 'submit',
525
    '#limit_validation_errors' => array(array('test')),
526
    '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
527
    '#value' => t('Partial validate'),
528
  );
529
  $form['actions']['partial_numeric_index'] = array(
530
    '#type' => 'submit',
531
    '#limit_validation_errors' => array(array('test_numeric_index', 0)),
532
    '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
533
    '#value' => t('Partial validate (numeric index)'),
534
  );
535
  $form['actions']['substring'] = array(
536
    '#type' => 'submit',
537
    '#limit_validation_errors' => array(array('test_substring', 'foo')),
538
    '#submit' => array('form_test_limit_validation_errors_form_partial_submit'),
539
    '#value' => t('Partial validate (substring)'),
540
  );
541
  $form['actions']['full'] = array(
542
    '#type' => 'submit',
543
    '#value' => t('Full validate'),
544
  );
545
  return $form;
546
}
547

    
548
/**
549
 * Form element validation handler for the 'test' element.
550
 */
551
function form_test_limit_validation_errors_element_validate_test(&$element, &$form_state) {
552
  if ($element['#value'] == 'invalid') {
553
    form_error($element, t('@label element is invalid', array('@label' => $element['#title'])));
554
  }
555
}
556

    
557
/**
558
 * Form submit handler for the partial validation submit button.
559
 */
560
function form_test_limit_validation_errors_form_partial_submit($form, $form_state) {
561
  // The title has not been validated, thus its value - in case of the test case
562
  // an empty string - may not be set.
563
  if (!isset($form_state['values']['title']) && isset($form_state['values']['test'])) {
564
    drupal_set_message('Only validated values appear in the form values.');
565
  }
566
}
567

    
568
/**
569
 * Create a header and options array. Helper function for callbacks.
570
 */
571
function _form_test_tableselect_get_data() {
572
  $header = array(
573
    'one' => t('One'),
574
    'two' => t('Two'),
575
    'three' => t('Three'),
576
    'four' => t('Four'),
577
  );
578

    
579
  $options['row1'] = array(
580
    'one' => 'row1col1',
581
    'two' => t('row1col2'),
582
    'three' => t('row1col3'),
583
    'four' => t('row1col4'),
584
  );
585

    
586
  $options['row2'] = array(
587
    'one' => 'row2col1',
588
    'two' => t('row2col2'),
589
    'three' => t('row2col3'),
590
    'four' => t('row2col4'),
591
  );
592

    
593
  $options['row3'] = array(
594
    'one' => 'row3col1',
595
    'two' => t('row3col2'),
596
    'three' => t('row3col3'),
597
    'four' => t('row3col4'),
598
  );
599

    
600
  return array($header, $options);
601
}
602

    
603
/**
604
 * Build a form to test the tableselect element.
605
 *
606
 * @param $form_state
607
 *   The form_state
608
 * @param $element_properties
609
 *   An array of element properties for the tableselect element.
610
 *
611
 * @return
612
 *   A form with a tableselect element and a submit button.
613
 */
614
function _form_test_tableselect_form_builder($form, $form_state, $element_properties) {
615
  list($header, $options) = _form_test_tableselect_get_data();
616

    
617
  $form['tableselect'] = $element_properties;
618

    
619
  $form['tableselect'] += array(
620
    '#prefix' => '<div id="tableselect-wrapper">',
621
    '#suffix' => '</div>',
622
    '#type' => 'tableselect',
623
    '#header' => $header,
624
    '#options' => $options,
625
    '#multiple' => FALSE,
626
    '#empty' => t('Empty text.'),
627
    '#ajax' => array(
628
      'callback' => '_form_test_tableselect_ajax_callback',
629
      'wrapper' => 'tableselect-wrapper',
630
    ),
631
  );
632

    
633
  $form['submit'] = array(
634
    '#type' => 'submit',
635
    '#value' => t('Submit'),
636
  );
637

    
638
  return $form;
639
}
640

    
641
/**
642
 * Test the tableselect #multiple = TRUE functionality.
643
 */
644
function _form_test_tableselect_multiple_true_form($form, $form_state) {
645
  return _form_test_tableselect_form_builder($form, $form_state, array('#multiple' => TRUE));
646
}
647

    
648
/**
649
 * Process the tableselect #multiple = TRUE submitted values.
650
 */
651
function _form_test_tableselect_multiple_true_form_submit($form, &$form_state) {
652
  $selected = $form_state['values']['tableselect'];
653
  foreach ($selected as $key => $value) {
654
    drupal_set_message(t('Submitted: @key = @value', array('@key' => $key, '@value' => $value)));
655
  }
656
}
657

    
658
/**
659
 * Test the tableselect #multiple = FALSE functionality.
660
 */
661
function _form_test_tableselect_multiple_false_form($form, $form_state) {
662
  return _form_test_tableselect_form_builder($form, $form_state, array('#multiple' => FALSE));
663
}
664

    
665
/**
666
 * Process the tableselect #multiple = FALSE submitted values.
667
 */
668
function _form_test_tableselect_multiple_false_form_submit($form, &$form_state) {
669
  drupal_set_message(t('Submitted: @value', array('@value' => $form_state['values']['tableselect'])));
670
}
671

    
672
/**
673
 * Test functionality of the tableselect #empty property.
674
 */
675
function _form_test_tableselect_empty_form($form, $form_state) {
676
  return _form_test_tableselect_form_builder($form, $form_state, array('#options' => array()));
677
}
678

    
679
/**
680
 * Test functionality of the tableselect #js_select property.
681
 */
682
function _form_test_tableselect_js_select_form($form, $form_state, $action) {
683
  switch ($action) {
684
    case 'multiple-true-default':
685
      $options = array('#multiple' => TRUE);
686
      break;
687

    
688
    case 'multiple-false-default':
689
      $options = array('#multiple' => FALSE);
690
      break;
691

    
692
    case 'multiple-true-no-advanced-select':
693
      $options = array('#multiple' => TRUE, '#js_select' => FALSE);
694
      break;
695

    
696
    case 'multiple-false-advanced-select':
697
      $options = array('#multiple' => FALSE, '#js_select' => TRUE);
698
      break;
699
  }
700

    
701
  return _form_test_tableselect_form_builder($form, $form_state, $options);
702
}
703

    
704
/**
705
 * Tests functionality of vertical tabs.
706
 */
707
function _form_test_vertical_tabs_form($form, &$form_state) {
708
  $form['vertical_tabs'] = array(
709
    '#type' => 'vertical_tabs',
710
  );
711
  $form['tab1'] = array(
712
    '#type' => 'fieldset',
713
    '#title' => t('Tab 1'),
714
    '#collapsible' => TRUE,
715
    '#group' => 'vertical_tabs',
716
  );
717
  $form['tab1']['field1'] = array(
718
    '#title' => t('Field 1'),
719
    '#type' => 'textfield',
720
  );
721
  $form['tab2'] = array(
722
    '#type' => 'fieldset',
723
    '#title' => t('Tab 2'),
724
    '#collapsible' => TRUE,
725
    '#group' => 'vertical_tabs',
726
  );
727
  $form['tab2']['field2'] = array(
728
    '#title' => t('Field 2'),
729
    '#type' => 'textfield',
730
  );
731
  return $form;
732
}
733

    
734
/**
735
* Ajax callback that returns the form element.
736
*/
737
function _form_test_tableselect_ajax_callback($form, &$form_state) {
738
  return $form['tableselect'];
739
}
740

    
741
/**
742
 * A multistep form for testing the form storage.
743
 *
744
 * It uses two steps for editing a virtual "thing". Any changes to it are saved
745
 * in the form storage and have to be present during any step. By setting the
746
 * request parameter "cache" the form can be tested with caching enabled, as
747
 * it would be the case, if the form would contain some #ajax callbacks.
748
 *
749
 * @see form_test_storage_form_submit()
750
 */
751
function form_test_storage_form($form, &$form_state) {
752
  if ($form_state['rebuild']) {
753
    $form_state['input'] = array();
754
  }
755
  // Initialize
756
  if (empty($form_state['storage'])) {
757
    if (empty($form_state['input'])) {
758
      $_SESSION['constructions'] = 0;
759
    }
760
    // Put the initial thing into the storage
761
    $form_state['storage'] = array(
762
      'thing' => array(
763
        'title' => 'none',
764
        'value' => '',
765
      ),
766
    );
767
  }
768
  // Count how often the form is constructed.
769
  $_SESSION['constructions']++;
770
  drupal_set_message("Form constructions: " . $_SESSION['constructions']);
771

    
772
  $form['title'] = array(
773
    '#type' => 'textfield',
774
    '#title' => 'Title',
775
    '#default_value' => $form_state['storage']['thing']['title'],
776
    '#required' => TRUE,
777
  );
778
  $form['value'] = array(
779
    '#type' => 'textfield',
780
    '#title' => 'Value',
781
    '#default_value' => $form_state['storage']['thing']['value'],
782
    '#element_validate' => array('form_test_storage_element_validate_value_cached'),
783
  );
784
  $form['continue_button'] = array(
785
    '#type' => 'button',
786
    '#value' => 'Reset',
787
    // Rebuilds the form without keeping the values.
788
  );
789
  $form['continue_submit'] = array(
790
    '#type' => 'submit',
791
    '#value' => 'Continue submit',
792
    '#submit' => array('form_storage_test_form_continue_submit'),
793
  );
794
  $form['submit'] = array(
795
    '#type' => 'submit',
796
    '#value' => 'Save',
797
  );
798

    
799
  if (isset($_REQUEST['cache'])) {
800
    // Manually activate caching, so we can test that the storage keeps working
801
    // when it's enabled.
802
    $form_state['cache'] = TRUE;
803
  }
804

    
805
  if (isset($_REQUEST['immutable'])) {
806
    $form_state['build_info']['immutable'] = TRUE;
807
  }
808

    
809
  return $form;
810
}
811

    
812
/**
813
 * Emulate legacy AHAH-style ajax callback.
814
 *
815
 * Drupal 6 AHAH callbacks used to operate directly on forms retrieved using
816
 * form_get_cache and stored using form_set_cache after manipulation. This
817
 * callback helps testing whether form_set_cache prevents resaving of immutable
818
 * forms.
819
 */
820
function form_test_storage_legacy_handler($form_build_id) {
821
  $form_state = array();
822
  $form = form_get_cache($form_build_id, $form_state);
823

    
824
  drupal_json_output(array(
825
    'form' => $form,
826
    'form_state' => $form_state,
827
  ));
828

    
829
  $form['#poisoned'] = TRUE;
830
  $form_state['poisoned'] = TRUE;
831

    
832
  form_set_cache($form_build_id, $form, $form_state);
833
}
834

    
835
/**
836
 * Form element validation handler for 'value' element in form_test_storage_form().
837
 *
838
 * Tests updating of cached form storage during validation.
839
 */
840
function form_test_storage_element_validate_value_cached($element, &$form_state) {
841
  // If caching is enabled and we receive a certain value, change the storage.
842
  // This presumes that another submitted form value triggers a validation error
843
  // elsewhere in the form. Form API should still update the cached form storage
844
  // though.
845
  if (isset($_REQUEST['cache']) && $form_state['values']['value'] == 'change_title') {
846
    $form_state['storage']['thing']['changed'] = TRUE;
847
  }
848
}
849

    
850
/**
851
 * Form submit handler to continue multi-step form.
852
 */
853
function form_storage_test_form_continue_submit($form, &$form_state) {
854
  $form_state['storage']['thing']['title'] = $form_state['values']['title'];
855
  $form_state['storage']['thing']['value'] = $form_state['values']['value'];
856
  $form_state['rebuild'] = TRUE;
857
}
858

    
859
/**
860
 * Form submit handler to finish multi-step form.
861
 */
862
function form_test_storage_form_submit($form, &$form_state) {
863
  drupal_set_message("Title: " . check_plain($form_state['values']['title']));
864
  drupal_set_message("Form constructions: " . $_SESSION['constructions']);
865
  if (isset($form_state['storage']['thing']['changed'])) {
866
    drupal_set_message("The thing has been changed.");
867
  }
868
  $form_state['redirect'] = 'node';
869
}
870

    
871
/**
872
 * A simple form for testing form storage when page caching is enabled.
873
 */
874
function form_test_storage_page_cache_form($form, &$form_state) {
875
  $form['title'] = array(
876
    '#type' => 'textfield',
877
    '#title' => 'Title',
878
    '#required' => TRUE,
879
  );
880

    
881
  $form['test_build_id_old'] = array(
882
    '#type' => 'item',
883
    '#title' => 'Old build id',
884
    '#markup' => 'No old build id',
885
  );
886

    
887
  $form['submit'] = array(
888
    '#type' => 'submit',
889
    '#value' => 'Save',
890
  );
891

    
892
  $form['rebuild'] = array(
893
    '#type' => 'submit',
894
    '#value' => 'Rebuild',
895
    '#submit' => array('form_test_storage_page_cache_rebuild'),
896
  );
897

    
898
  $form['#after_build'] = array('form_test_storage_page_cache_old_build_id');
899
  $form_state['cache'] = TRUE;
900

    
901
  return $form;
902
}
903

    
904
/**
905
 * Form element #after_build callback: output the old form build-id.
906
 */
907
function form_test_storage_page_cache_old_build_id($form) {
908
  if (isset($form['#build_id_old'])) {
909
    $form['test_build_id_old']['#markup'] = check_plain($form['#build_id_old']);
910
  }
911
  return $form;
912
}
913

    
914
/**
915
 * Form submit callback: Rebuild the form and continue.
916
 */
917
function form_test_storage_page_cache_rebuild($form, &$form_state) {
918
  $form_state['rebuild'] = TRUE;
919
}
920

    
921
/**
922
 * A simple form for testing form caching.
923
 */
924
function form_test_cache_form($form, &$form_state) {
925
  $form['title'] = array(
926
    '#type' => 'textfield',
927
    '#title' => 'Title',
928
    '#required' => TRUE,
929
  );
930

    
931
  $form['submit'] = array(
932
    '#type' => 'submit',
933
    '#value' => 'Save',
934
  );
935

    
936
  return $form;
937
}
938

    
939
/**
940
 * A form for testing form labels and required marks.
941
 */
942
function form_label_test_form() {
943
  $form['form_checkboxes_test'] = array(
944
    '#type' => 'checkboxes',
945
    '#title' => t('Checkboxes test'),
946
    '#options' => array(
947
      'first-checkbox' => t('First checkbox'),
948
      'second-checkbox' => t('Second checkbox'),
949
      'third-checkbox' => t('Third checkbox'),
950
      '0' => t('0'),
951
    ),
952
  );
953
  $form['form_radios_test'] = array(
954
    '#type' => 'radios',
955
    '#title' => t('Radios test'),
956
    '#options' => array(
957
      'first-radio' => t('First radio'),
958
      'second-radio' => t('Second radio'),
959
      'third-radio' => t('Third radio'),
960
      '0' => t('0'),
961
    ),
962
    // Test #field_prefix and #field_suffix placement.
963
    '#field_prefix' => '<span id="form-test-radios-field-prefix">' . t('Radios #field_prefix element') . '</span>',
964
    '#field_suffix' => '<span id="form-test-radios-field-suffix">' . t('Radios #field_suffix element') . '</span>',
965
  );
966
  $form['form_checkbox_test'] = array(
967
    '#type' => 'checkbox',
968
    '#title' => t('Checkbox test'),
969
  );
970
  $form['form_textfield_test_title_and_required'] = array(
971
    '#type' => 'textfield',
972
    '#title' => t('Textfield test for required with title'),
973
    '#required' => TRUE,
974
  );
975
  $form['form_textfield_test_no_title_required'] = array(
976
    '#type' => 'textfield',
977
    // We use an empty title, since not setting #title suppresses the label
978
    // and required marker.
979
    '#title' => '',
980
    '#required' => TRUE,
981
  );
982
  $form['form_textfield_test_title'] = array(
983
    '#type' => 'textfield',
984
    '#title' => t('Textfield test for title only'),
985
    // Not required.
986
    // Test #prefix and #suffix placement.
987
    '#prefix' => '<div id="form-test-textfield-title-prefix">' . t('Textfield #prefix element') . '</div>',
988
    '#suffix' => '<div id="form-test-textfield-title-suffix">' . t('Textfield #suffix element') . '</div>',
989
  );
990
  $form['form_textfield_test_title_after'] = array(
991
    '#type' => 'textfield',
992
    '#title' => t('Textfield test for title after element'),
993
    '#title_display' => 'after',
994
  );
995
  $form['form_textfield_test_title_invisible'] = array(
996
    '#type' => 'textfield',
997
    '#title' => t('Textfield test for invisible title'),
998
    '#title_display' => 'invisible',
999
  );
1000
  // Textfield test for title set not to display.
1001
  $form['form_textfield_test_title_no_show'] = array(
1002
    '#type' => 'textfield',
1003
  );
1004
  // Checkboxes & radios with title as attribute.
1005
  $form['form_checkboxes_title_attribute'] = array(
1006
    '#type' => 'checkboxes',
1007
    '#title' => 'Checkboxes test',
1008
    '#options' => array(
1009
      'first-checkbox' => 'First checkbox',
1010
      'second-checkbox' => 'Second checkbox',
1011
    ),
1012
    '#title_display' => 'attribute',
1013
    '#required' => TRUE,
1014
  );
1015
  $form['form_radios_title_attribute'] = array(
1016
    '#type' => 'radios',
1017
    '#title' => 'Radios test',
1018
    '#options' => array(
1019
      'first-radio' => 'First radio',
1020
      'second-radio' => 'Second radio',
1021
    ),
1022
    '#title_display' => 'attribute',
1023
    '#required' => TRUE,
1024
  );
1025

    
1026
  return $form;
1027
}
1028

    
1029
/**
1030
 * Menu callback; Invokes a form builder function with a wrapper callback.
1031
 */
1032
function form_test_wrapper_callback($form_id) {
1033
  $form_state = array(
1034
    'build_info' => array('args' => array()),
1035
    'wrapper_callback' => 'form_test_wrapper_callback_wrapper',
1036
  );
1037
  return drupal_build_form($form_id, $form_state);
1038
}
1039

    
1040
/**
1041
 * Form wrapper for form_test_wrapper_callback_form().
1042
 */
1043
function form_test_wrapper_callback_wrapper($form, &$form_state) {
1044
  $form['wrapper'] = array('#markup' => 'Form wrapper callback element output.');
1045
  return $form;
1046
}
1047

    
1048
/**
1049
 * Form builder for form wrapper callback test.
1050
 */
1051
function form_test_wrapper_callback_form($form, &$form_state) {
1052
  $form['builder'] = array('#markup' => 'Form builder element output.');
1053
  return $form;
1054
}
1055

    
1056
/**
1057
 * Form builder for form_state_values_clean() test.
1058
 */
1059
function form_test_form_state_values_clean_form($form, &$form_state) {
1060
  // Build an example form containing multiple submit and button elements; not
1061
  // only on the top-level.
1062
  $form = array('#tree' => TRUE);
1063
  $form['foo'] = array('#type' => 'submit', '#value' => t('Submit'));
1064
  $form['bar'] = array('#type' => 'submit', '#value' => t('Submit'));
1065
  $form['beer'] = array('#type' => 'value', '#value' => 1000);
1066
  $form['baz']['foo'] = array('#type' => 'button', '#value' => t('Submit'));
1067
  $form['baz']['baz'] = array('#type' => 'submit', '#value' => t('Submit'));
1068
  $form['baz']['beer'] = array('#type' => 'value', '#value' => 2000);
1069
  return $form;
1070
}
1071

    
1072
/**
1073
 * Form submit handler for form_state_values_clean() test form.
1074
 */
1075
function form_test_form_state_values_clean_form_submit($form, &$form_state) {
1076
  form_state_values_clean($form_state);
1077
  drupal_json_output($form_state['values']);
1078
  exit;
1079
}
1080

    
1081
/**
1082
 * Form constructor for the form_state_values_clean() test.
1083
 */
1084
function form_test_form_state_values_clean_advanced_form($form, &$form_state) {
1085
  // Build an example form containing a managed file and a submit form element.
1086
  $form['image'] = array(
1087
    '#type' => 'managed_file',
1088
    '#title' => t('Image'),
1089
    '#upload_location' => 'public://',
1090
    '#default_value' => 0,
1091
  );
1092
  $form['submit'] = array(
1093
    '#type' => 'submit',
1094
    '#value' => t('Submit'),
1095
  );
1096
  return $form;
1097
}
1098

    
1099
/**
1100
 * Form submission handler for form_test_form_state_values_clean_advanced_form().
1101
 */
1102
function form_test_form_state_values_clean_advanced_form_submit($form, &$form_state) {
1103
  form_state_values_clean($form_state);
1104
  print t('You WIN!');
1105
  exit;
1106
}
1107

    
1108
/**
1109
 * Build a form to test a checkbox.
1110
 */
1111
function _form_test_checkbox($form, &$form_state) {
1112
  // A required checkbox.
1113
  $form['required_checkbox'] = array(
1114
    '#type' => 'checkbox',
1115
    '#required' => TRUE,
1116
    '#title' => 'required_checkbox',
1117
  );
1118

    
1119
  // A disabled checkbox should get its default value back.
1120
  $form['disabled_checkbox_on'] = array(
1121
    '#type' => 'checkbox',
1122
    '#disabled' => TRUE,
1123
    '#return_value' => 'disabled_checkbox_on',
1124
    '#default_value' => 'disabled_checkbox_on',
1125
    '#title' => 'disabled_checkbox_on',
1126
  );
1127
  $form['disabled_checkbox_off'] = array(
1128
    '#type' => 'checkbox',
1129
    '#disabled' => TRUE,
1130
    '#return_value' => 'disabled_checkbox_off',
1131
    '#default_value' => NULL,
1132
    '#title' => 'disabled_checkbox_off',
1133
  );
1134

    
1135
  // A checkbox is active when #default_value == #return_value.
1136
  $form['checkbox_on'] = array(
1137
    '#type' => 'checkbox',
1138
    '#return_value' => 'checkbox_on',
1139
    '#default_value' => 'checkbox_on',
1140
    '#title' => 'checkbox_on',
1141
  );
1142

    
1143
  // But inactive in any other case.
1144
  $form['checkbox_off'] = array(
1145
    '#type' => 'checkbox',
1146
    '#return_value' => 'checkbox_off',
1147
    '#default_value' => 'checkbox_on',
1148
    '#title' => 'checkbox_off',
1149
  );
1150

    
1151
  // Checkboxes with a #return_value of '0' are supported.
1152
  $form['zero_checkbox_on'] = array(
1153
    '#type' => 'checkbox',
1154
    '#return_value' => '0',
1155
    '#default_value' => '0',
1156
    '#title' => 'zero_checkbox_on',
1157
  );
1158

    
1159
  // In that case, passing a #default_value != '0' means that the checkbox is off.
1160
  $form['zero_checkbox_off'] = array(
1161
    '#type' => 'checkbox',
1162
    '#return_value' => '0',
1163
    '#default_value' => '1',
1164
    '#title' => 'zero_checkbox_off',
1165
  );
1166

    
1167
  $form['submit'] = array(
1168
    '#type' => 'submit',
1169
    '#value' => t('Submit')
1170
  );
1171

    
1172
  return $form;
1173
}
1174

    
1175
/**
1176
 * Return the form values via JSON.
1177
 */
1178
function _form_test_checkbox_submit($form, &$form_state) {
1179
  drupal_json_output($form_state['values']);
1180
  exit();
1181
}
1182

    
1183
/**
1184
 * Builds a form to test #type 'select' validation.
1185
 */
1186
function form_test_select($form, &$form_state) {
1187
  $base = array(
1188
    '#type' => 'select',
1189
    '#options' => drupal_map_assoc(array('one', 'two', 'three')),
1190
  );
1191

    
1192
  $form['select'] = $base + array(
1193
    '#title' => '#default_value one',
1194
    '#default_value' => 'one',
1195
  );
1196
  $form['select_required'] = $base + array(
1197
    '#title' => '#default_value one, #required',
1198
    '#required' => TRUE,
1199
    '#default_value' => 'one',
1200
  );
1201
  $form['select_optional'] = $base + array(
1202
    '#title' => '#default_value one, not #required',
1203
    '#required' => FALSE,
1204
    '#default_value' => 'one',
1205
  );
1206
  $form['empty_value'] = $base + array(
1207
    '#title' => '#default_value one, #required, #empty_value 0',
1208
    '#required' => TRUE,
1209
    '#default_value' => 'one',
1210
    '#empty_value' => 0,
1211
  );
1212
  $form['empty_value_one'] = $base + array(
1213
    '#title' => '#default_value = #empty_value, #required',
1214
    '#required' => TRUE,
1215
    '#default_value' => 'one',
1216
    '#empty_value' => 'one',
1217
  );
1218

    
1219
  $form['no_default'] = $base + array(
1220
    '#title' => 'No #default_value, #required',
1221
    '#required' => TRUE,
1222
  );
1223
  $form['no_default_optional'] = $base + array(
1224
    '#title' => 'No #default_value, not #required',
1225
    '#required' => FALSE,
1226
    '#description' => 'Should result in "one", because it is not required and there is no #empty_value requested, so default browser behavior of preselecting first option is in effect.',
1227
  );
1228
  $form['no_default_optional_empty_value'] = $base + array(
1229
    '#title' => 'No #default_value, not #required, #empty_value empty string',
1230
    '#empty_value' => '',
1231
    '#required' => FALSE,
1232
    '#description' => 'Should result in an empty string (due to #empty_value), because it is optional.',
1233
  );
1234

    
1235
  $form['no_default_empty_option'] = $base + array(
1236
    '#title' => 'No #default_value, #required, #empty_option',
1237
    '#required' => TRUE,
1238
    '#empty_option' => '- Choose -',
1239
  );
1240
  $form['no_default_empty_option_optional'] = $base + array(
1241
    '#title' => 'No #default_value, not #required, #empty_option',
1242
    '#empty_option' => '- Dismiss -',
1243
    '#description' => 'Should result in an empty string (default of #empty_value), because it is optional.',
1244
  );
1245

    
1246
  $form['no_default_empty_value'] = $base + array(
1247
    '#title' => 'No #default_value, #required, #empty_value 0',
1248
    '#required' => TRUE,
1249
    '#empty_value' => 0,
1250
    '#description' => 'Should never result in 0.',
1251
  );
1252
  $form['no_default_empty_value_one'] = $base + array(
1253
    '#title' => 'No #default_value, #required, #empty_value one',
1254
    '#required' => TRUE,
1255
    '#empty_value' => 'one',
1256
    '#description' => 'A mistakenly assigned #empty_value contained in #options should not be valid.',
1257
  );
1258
  $form['no_default_empty_value_optional'] = $base + array(
1259
    '#title' => 'No #default_value, not #required, #empty_value 0',
1260
    '#required' => FALSE,
1261
    '#empty_value' => 0,
1262
    '#description' => 'Should result in 0, because it is optional.',
1263
  );
1264

    
1265
  $form['multiple'] = $base + array(
1266
    '#title' => '#multiple, #default_value two',
1267
    '#default_value' => array('two'),
1268
    '#multiple' => TRUE,
1269
  );
1270
  $form['multiple_no_default'] = $base + array(
1271
    '#title' => '#multiple, no #default_value',
1272
    '#multiple' => TRUE,
1273
  );
1274
  $form['multiple_no_default_required'] = $base + array(
1275
    '#title' => '#multiple, #required, no #default_value',
1276
    '#required' => TRUE,
1277
    '#multiple' => TRUE,
1278
  );
1279

    
1280
  $form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
1281
  return $form;
1282
}
1283

    
1284
/**
1285
 * Form submit handler for form_test_select().
1286
 */
1287
function form_test_select_submit($form, &$form_state) {
1288
  drupal_json_output($form_state['values']);
1289
  exit();
1290
}
1291

    
1292
/**
1293
 * Form constructor to test expansion of #type checkboxes and radios.
1294
 */
1295
function form_test_checkboxes_radios($form, &$form_state, $customize = FALSE) {
1296
  $form['#submit'] = array('_form_test_submit_values_json');
1297

    
1298
  // Expand #type checkboxes, setting custom element properties for some but not
1299
  // all options.
1300
  $form['checkboxes'] = array(
1301
    '#type' => 'checkboxes',
1302
    '#title' => 'Checkboxes',
1303
    '#options' => array(
1304
      0 => 'Zero',
1305
      'foo' => 'Foo',
1306
      1 => 'One',
1307
      'bar' => 'Bar',
1308
      '>' => 'Special Char',
1309
    ),
1310
  );
1311
  if ($customize) {
1312
    $form['checkboxes'] += array(
1313
      'foo' => array(
1314
        '#description' => 'Enable to foo.',
1315
      ),
1316
      1 => array(
1317
        '#weight' => 10,
1318
      ),
1319
    );
1320
  }
1321

    
1322
  // Expand #type radios, setting custom element properties for some but not
1323
  // all options.
1324
  $form['radios'] = array(
1325
    '#type' => 'radios',
1326
    '#title' => 'Radios',
1327
    '#options' => array(
1328
      0 => 'Zero',
1329
      'foo' => 'Foo',
1330
      1 => 'One',
1331
      'bar' => 'Bar',
1332
      '>' => 'Special Char',
1333
    ),
1334
  );
1335
  if ($customize) {
1336
    $form['radios'] += array(
1337
      'foo' => array(
1338
        '#description' => 'Enable to foo.',
1339
      ),
1340
      1 => array(
1341
        '#weight' => 10,
1342
      ),
1343
    );
1344
  }
1345

    
1346
  $form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
1347

    
1348
  return $form;
1349
}
1350

    
1351
/**
1352
 * Build a form to test disabled elements.
1353
 */
1354
function _form_test_disabled_elements($form, &$form_state) {
1355
  // Elements that take a simple default value.
1356
  foreach (array('textfield', 'textarea', 'hidden') as $type) {
1357
    $form[$type] = array(
1358
      '#type' => $type,
1359
      '#title' => $type,
1360
      '#default_value' => $type,
1361
      '#test_hijack_value' => 'HIJACK',
1362
      '#disabled' => TRUE,
1363
    );
1364
  }
1365

    
1366
  // Multiple values option elements.
1367
  foreach (array('checkboxes', 'select') as $type) {
1368
    $form[$type . '_multiple'] = array(
1369
      '#type' => $type,
1370
      '#title' => $type . ' (multiple)',
1371
      '#options' => array(
1372
        'test_1' => 'Test 1',
1373
        'test_2' => 'Test 2',
1374
      ),
1375
      '#multiple' => TRUE,
1376
      '#default_value' => array('test_2' => 'test_2'),
1377
      // The keys of #test_hijack_value need to match the #name of the control.
1378
      // @see FormsTestCase::testDisabledElements()
1379
      '#test_hijack_value' => $type == 'select' ? array('' => 'test_1') : array('test_1' => 'test_1'),
1380
      '#disabled' => TRUE,
1381
    );
1382
  }
1383

    
1384
  // Single values option elements.
1385
  foreach (array('radios', 'select') as $type) {
1386
    $form[$type . '_single'] = array(
1387
      '#type' => $type,
1388
      '#title' => $type . ' (single)',
1389
      '#options' => array(
1390
        'test_1' => 'Test 1',
1391
        'test_2' => 'Test 2',
1392
      ),
1393
      '#multiple' => FALSE,
1394
      '#default_value' => 'test_2',
1395
      '#test_hijack_value' => 'test_1',
1396
      '#disabled' => TRUE,
1397
    );
1398
  }
1399

    
1400
  // Checkbox and radio.
1401
  foreach (array('checkbox', 'radio') as $type) {
1402
    $form[$type . '_unchecked'] = array(
1403
      '#type' => $type,
1404
      '#title' => $type . ' (unchecked)',
1405
      '#return_value' => 1,
1406
      '#default_value' => 0,
1407
      '#test_hijack_value' => 1,
1408
      '#disabled' => TRUE,
1409
    );
1410
    $form[$type . '_checked'] = array(
1411
      '#type' => $type,
1412
      '#title' => $type . ' (checked)',
1413
      '#return_value' => 1,
1414
      '#default_value' => 1,
1415
      '#test_hijack_value' => NULL,
1416
      '#disabled' => TRUE,
1417
    );
1418
  }
1419

    
1420
  // Weight.
1421
  $form['weight'] = array(
1422
    '#type' => 'weight',
1423
    '#title' => 'weight',
1424
    '#default_value' => 10,
1425
    '#test_hijack_value' => 5,
1426
    '#disabled' => TRUE,
1427
  );
1428

    
1429
  // Date.
1430
  $form['date'] = array(
1431
    '#type' => 'date',
1432
    '#title' => 'date',
1433
    '#disabled' => TRUE,
1434
    '#default_value' => array(
1435
      'day' => 19,
1436
      'month' => 11,
1437
      'year' => 1978,
1438
    ),
1439
    '#test_hijack_value' => array(
1440
      'day' => 20,
1441
      'month' => 12,
1442
      'year' => 1979,
1443
    ),
1444
  );
1445

    
1446
  // The #disabled state should propagate to children.
1447
  $form['disabled_container'] = array(
1448
    '#disabled' => TRUE,
1449
  );
1450
  foreach (array('textfield', 'textarea', 'hidden') as $type) {
1451
    $form['disabled_container']['disabled_container_' . $type] = array(
1452
      '#type' => $type,
1453
      '#title' => $type,
1454
      '#default_value' => $type,
1455
      '#test_hijack_value' => 'HIJACK',
1456
    );
1457
  }
1458

    
1459
  // Text format.
1460
  $form['text_format'] = array(
1461
    '#type' => 'text_format',
1462
    '#title' => 'Text format',
1463
    '#disabled' => TRUE,
1464
    '#default_value' => 'Text value',
1465
    '#format' => 'plain_text',
1466
    '#expected_value' => array(
1467
      'value' => 'Text value',
1468
      'format' => 'plain_text',
1469
    ),
1470
    '#test_hijack_value' => array(
1471
      'value' => 'HIJACK',
1472
      'format' => 'filtered_html',
1473
    ),
1474
  );
1475

    
1476
  // Password fields.
1477
  $form['password'] = array(
1478
    '#type' => 'password',
1479
    '#title' => 'Password',
1480
    '#disabled' => TRUE,
1481
  );
1482
  $form['password_confirm'] = array(
1483
    '#type' => 'password_confirm',
1484
    '#title' => 'Password confirm',
1485
    '#disabled' => TRUE,
1486
  );
1487

    
1488
  // Files.
1489
  $form['file'] = array(
1490
    '#type' => 'file',
1491
    '#title' => 'File',
1492
    '#disabled' => TRUE,
1493
  );
1494
  $form['managed_file'] = array(
1495
    '#type' => 'managed_file',
1496
    '#title' => 'Managed file',
1497
    '#disabled' => TRUE,
1498
  );
1499

    
1500
  // Buttons.
1501
  $form['image_button'] = array(
1502
    '#type' => 'image_button',
1503
    '#value' => 'Image button',
1504
    '#disabled' => TRUE,
1505
  );
1506
  $form['button'] = array(
1507
    '#type' => 'button',
1508
    '#value' => 'Button',
1509
    '#disabled' => TRUE,
1510
  );
1511
  $form['submit_disabled'] = array(
1512
    '#type' => 'submit',
1513
    '#value' => 'Submit',
1514
    '#disabled' => TRUE,
1515
  );
1516

    
1517
  $form['submit'] = array(
1518
    '#type' => 'submit',
1519
    '#value' => t('Submit'),
1520
  );
1521

    
1522
  return $form;
1523
}
1524

    
1525
/**
1526
 * Return the form values via JSON.
1527
 */
1528
function _form_test_disabled_elements_submit($form, &$form_state) {
1529
  drupal_json_output($form_state['values']);
1530
  exit();
1531
}
1532

    
1533
/**
1534
 * Build a form to test input forgery of enabled elements.
1535
 */
1536
function _form_test_input_forgery($form, &$form_state) {
1537
  // For testing that a user can't submit a value not matching one of the
1538
  // allowed options.
1539
  $form['checkboxes'] = array(
1540
    '#type' => 'checkboxes',
1541
    '#options' => array(
1542
      'one' => 'One',
1543
      'two' => 'Two',
1544
    ),
1545
  );
1546

    
1547
  $form['submit'] = array(
1548
    '#type' => 'submit',
1549
    '#value' => t('Submit'),
1550
  );
1551
  return $form;
1552
}
1553

    
1554
/**
1555
 * Return the form values via JSON.
1556
 */
1557
function _form_test_input_forgery_submit($form, &$form_state) {
1558
  drupal_json_output($form_state['values']);
1559
  exit();
1560
}
1561

    
1562
/**
1563
 * Form builder for testing preservation of values during a rebuild.
1564
 */
1565
function form_test_form_rebuild_preserve_values_form($form, &$form_state) {
1566
  // Start the form with two checkboxes, to test different defaults, and a
1567
  // textfield, to test more than one element type.
1568
  $form = array(
1569
    'checkbox_1_default_off' => array(
1570
      '#type' => 'checkbox',
1571
      '#title' => t('This checkbox defaults to unchecked.'),
1572
      '#default_value' => FALSE,
1573
    ),
1574
    'checkbox_1_default_on' => array(
1575
      '#type' => 'checkbox',
1576
      '#title' => t('This checkbox defaults to checked.'),
1577
      '#default_value' => TRUE,
1578
    ),
1579
    'text_1' => array(
1580
      '#type' => 'textfield',
1581
      '#title' => t('This textfield has a non-empty default value.'),
1582
      '#default_value' => 'DEFAULT 1',
1583
    ),
1584
  );
1585
  // Provide an 'add more' button that rebuilds the form with an additional two
1586
  // checkboxes and a textfield. The test is to make sure that the rebuild
1587
  // triggered by this button preserves the user input values for the initial
1588
  // elements and initializes the new elements with the correct default values.
1589
  if (empty($form_state['storage']['add_more'])) {
1590
    $form['add_more'] = array(
1591
      '#type' => 'submit',
1592
      '#value' => 'Add more',
1593
      '#submit' => array('form_test_form_rebuild_preserve_values_form_add_more'),
1594
    );
1595
  }
1596
  else {
1597
    $form += array(
1598
      'checkbox_2_default_off' => array(
1599
        '#type' => 'checkbox',
1600
        '#title' => t('This checkbox defaults to unchecked.'),
1601
        '#default_value' => FALSE,
1602
      ),
1603
      'checkbox_2_default_on' => array(
1604
        '#type' => 'checkbox',
1605
        '#title' => t('This checkbox defaults to checked.'),
1606
        '#default_value' => TRUE,
1607
      ),
1608
      'text_2' => array(
1609
        '#type' => 'textfield',
1610
        '#title' => t('This textfield has a non-empty default value.'),
1611
        '#default_value' => 'DEFAULT 2',
1612
      ),
1613
    );
1614
  }
1615
  // A submit button that finishes the form workflow (does not rebuild).
1616
  $form['submit'] = array(
1617
    '#type' => 'submit',
1618
    '#value' => 'Submit',
1619
  );
1620
  return $form;
1621
}
1622

    
1623
/**
1624
 * Button submit handler for form_test_form_rebuild_preserve_values_form().
1625
 */
1626
function form_test_form_rebuild_preserve_values_form_add_more($form, &$form_state) {
1627
  // Rebuild, to test preservation of input values.
1628
  $form_state['storage']['add_more'] = TRUE;
1629
  $form_state['rebuild'] = TRUE;
1630
}
1631

    
1632
/**
1633
 * Form submit handler for form_test_form_rebuild_preserve_values_form().
1634
 */
1635
function form_test_form_rebuild_preserve_values_form_submit($form, &$form_state) {
1636
  // Finish the workflow. Do not rebuild.
1637
  drupal_set_message(t('Form values: %values', array('%values' => var_export($form_state['values'], TRUE))));
1638
}
1639

    
1640
/**
1641
 * Form constructor for testing form state persistence.
1642
 */
1643
function form_test_state_persist($form, &$form_state) {
1644
  $form['title'] = array(
1645
    '#type' => 'textfield',
1646
    '#title' => 'title',
1647
    '#default_value' => 'DEFAULT',
1648
    '#required' => TRUE,
1649
  );
1650
  $form_state['value'] = 'State persisted.';
1651

    
1652
  $form['submit'] = array(
1653
    '#type' => 'submit',
1654
    '#value' => t('Submit'),
1655
  );
1656
  return $form;
1657
}
1658

    
1659
/**
1660
 * Submit handler.
1661
 *
1662
 * @see form_test_state_persist()
1663
 */
1664
function form_test_state_persist_submit($form, &$form_state) {
1665
  drupal_set_message($form_state['value']);
1666
  $form_state['rebuild'] = TRUE;
1667
}
1668

    
1669
/**
1670
 * Implements hook_form_FORM_ID_alter().
1671
 *
1672
 * @see form_test_state_persist()
1673
 */
1674
function form_test_form_form_test_state_persist_alter(&$form, &$form_state) {
1675
  // Simulate a form alter implementation inserting form elements that enable
1676
  // caching of the form, e.g. elements having #ajax.
1677
  if (!empty($_REQUEST['cache'])) {
1678
    $form_state['cache'] = TRUE;
1679
  }
1680
}
1681

    
1682
/**
1683
 * Form builder to test programmatic form submissions.
1684
 */
1685
function form_test_programmatic_form($form, &$form_state) {
1686
  $form['textfield'] = array(
1687
    '#title' => 'Textfield',
1688
    '#type' => 'textfield',
1689
  );
1690

    
1691
  $form['checkboxes'] = array(
1692
    '#type' => 'checkboxes',
1693
    '#options' => array(
1694
      1 => 'First checkbox',
1695
      2 => 'Second checkbox',
1696
    ),
1697
    // Both checkboxes are selected by default so that we can test the ability
1698
    // of programmatic form submissions to uncheck them.
1699
    '#default_value' => array(1, 2),
1700
  );
1701

    
1702
  // This is used to test that programmatic form submissions can bypass #access
1703
  // restrictions.
1704
  $form['textfield_no_access'] = array(
1705
    '#type' => 'textfield',
1706
    '#title' => 'Textfield no access',
1707
    '#default_value' => 'default value',
1708
    '#access' => FALSE,
1709
  );
1710

    
1711
  $form['field_to_validate'] = array(
1712
    '#type' => 'radios',
1713
    '#title' => 'Field to validate (in the case of limited validation)',
1714
    '#description' => 'If the form is submitted by clicking the "Submit with limited validation" button, then validation can be limited based on the value of this radio button.',
1715
    '#options' => array(
1716
      'all' => 'Validate all fields',
1717
      'textfield' => 'Validate the "Textfield" field',
1718
      'field_to_validate' => 'Validate the "Field to validate" field',
1719
    ),
1720
    '#default_value' => 'all',
1721
  );
1722

    
1723
  // The main submit button for the form.
1724
  $form['submit'] = array(
1725
    '#type' => 'submit',
1726
    '#value' => 'Submit',
1727
  );
1728
  // A secondary submit button that allows validation to be limited based on
1729
  // the value of the above radio selector.
1730
  $form['submit_limit_validation'] = array(
1731
    '#type' => 'submit',
1732
    '#value' => 'Submit with limited validation',
1733
    // Use the same submit handler for this button as for the form itself.
1734
    // (This must be set explicitly or otherwise the form API will ignore the
1735
    // #limit_validation_errors property.)
1736
    '#submit' => array('form_test_programmatic_form_submit'),
1737
  );
1738
  if (!empty($form_state['input']['field_to_validate']) && $form_state['input']['field_to_validate'] != 'all') {
1739
    $form['submit_limit_validation']['#limit_validation_errors'] = array(
1740
      array($form_state['input']['field_to_validate']),
1741
    );
1742
  }
1743

    
1744
  return $form;
1745
}
1746

    
1747
/**
1748
 * Form validation handler for programmatic form submissions.
1749
 *
1750
 * To test that the validation handler is correctly executed, the field value is
1751
 * explicitly required here.
1752
 */
1753
function form_test_programmatic_form_validate($form, &$form_state) {
1754
  if (empty($form_state['values']['textfield'])) {
1755
    form_set_error('textfield', t('Textfield is required.'));
1756
  }
1757
}
1758

    
1759
/**
1760
 * Form submit handler for programmatic form submissions.
1761
 *
1762
 * To test that the submission handler is correctly executed, we store the
1763
 * submitted values in a place we can access from the caller context.
1764
 */
1765
function form_test_programmatic_form_submit($form, &$form_state) {
1766
  $form_state['storage']['programmatic_form_submit'] = $form_state['values'];
1767
}
1768

    
1769
/**
1770
 * Form builder to test button click detection.
1771
 */
1772
function form_test_clicked_button($form, &$form_state) {
1773
  // A single text field. In IE, when a form has only one non-button input field
1774
  // and the ENTER key is pressed while that field has focus, the form is
1775
  // submitted without any information identifying the button responsible for
1776
  // the submission. In other browsers, the form is submitted as though the
1777
  // first button were clicked.
1778
  $form['text'] = array(
1779
    '#title' => 'Text',
1780
    '#type' => 'textfield',
1781
  );
1782

    
1783
  // Loop through each path argument, addding buttons based on the information
1784
  // in the argument. For example, if the path is
1785
  // form-test/clicked-button/s/i/rb, then 3 buttons are added: a 'submit', an
1786
  // 'image_button', and a 'button' with #access=FALSE. This enables form.test
1787
  // to test a variety of combinations.
1788
  $i=0;
1789
  $args = array_slice(arg(), 2);
1790
  foreach ($args as $arg) {
1791
    $name = 'button' . ++$i;
1792
    // 's', 'b', or 'i' in the argument define the button type wanted.
1793
    if (strpos($arg, 's') !== FALSE) {
1794
      $type = 'submit';
1795
    }
1796
    elseif (strpos($arg, 'b') !== FALSE) {
1797
      $type = 'button';
1798
    }
1799
    elseif (strpos($arg, 'i') !== FALSE) {
1800
      $type = 'image_button';
1801
    }
1802
    else {
1803
      $type = NULL;
1804
    }
1805
    if (isset($type)) {
1806
      $form[$name] = array(
1807
        '#type' => $type,
1808
        '#name' => $name,
1809
      );
1810
      // Image buttons need a #src; the others need a #value.
1811
      if ($type == 'image_button') {
1812
        $form[$name]['#src'] = 'misc/druplicon.png';
1813
      }
1814
      else {
1815
        $form[$name]['#value'] = $name;
1816
      }
1817
      // 'r' for restricted, so we can test that button click detection code
1818
      // correctly takes #access security into account.
1819
      if (strpos($arg, 'r') !== FALSE) {
1820
        $form[$name]['#access'] = FALSE;
1821
      }
1822
    }
1823
  }
1824

    
1825
  return $form;
1826
}
1827

    
1828
/**
1829
 * Form validation handler for the form_test_clicked_button() form.
1830
 */
1831
function form_test_clicked_button_validate($form, &$form_state) {
1832
  if (isset($form_state['triggering_element'])) {
1833
    drupal_set_message(t('The clicked button is %name.', array('%name' => $form_state['triggering_element']['#name'])));
1834
  }
1835
  else {
1836
    drupal_set_message('There is no clicked button.');
1837
  }
1838
}
1839

    
1840
/**
1841
 * Form submit handler for the form_test_clicked_button() form.
1842
 */
1843
function form_test_clicked_button_submit($form, &$form_state) {
1844
  drupal_set_message('Submit handler for form_test_clicked_button executed.');
1845
}
1846

    
1847
/**
1848
 * Form builder to detect form redirect.
1849
 */
1850
function form_test_redirect($form, &$form_state) {
1851
  $form['redirection'] = array(
1852
    '#type' => 'checkbox',
1853
    '#title' => t('Use redirection'),
1854
  );
1855
  $form['destination'] = array(
1856
    '#type' => 'textfield',
1857
    '#title' => t('Redirect destination'),
1858
    '#states' => array(
1859
      'visible' => array(
1860
        ':input[name="redirection"]' => array('checked' => TRUE),
1861
      ),
1862
    ),
1863
  );
1864
  $form['submit'] = array(
1865
    '#type' => 'submit',
1866
    '#value' => t('Submit'),
1867
  );
1868

    
1869
  return $form;
1870
}
1871

    
1872
/**
1873
 * Form submit handler to test different redirect behaviours.
1874
 */
1875
function form_test_redirect_submit(&$form, &$form_state) {
1876
  if (!empty($form_state['values']['redirection'])) {
1877
    $form_state['redirect'] = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
1878
  }
1879
  else {
1880
    $form_state['redirect'] = FALSE;
1881
  }
1882
}
1883

    
1884
/**
1885
 * Implements hook_form_FORM_ID_alter() for the registration form.
1886
 */
1887
function form_test_form_user_register_form_alter(&$form, &$form_state) {
1888
  $form['test_rebuild'] = array(
1889
    '#type' => 'submit',
1890
    '#value' => t('Rebuild'),
1891
    '#submit' => array('form_test_user_register_form_rebuild'),
1892
  );
1893
  // If requested, add the test field by attaching the node page form.
1894
  if (!empty($_REQUEST['field'])) {
1895
    $node = (object)array('type' => 'page');
1896
    field_attach_form('node', $node, $form, $form_state);
1897
  }
1898
}
1899

    
1900
/**
1901
 * Submit callback that just lets the form rebuild.
1902
 */
1903
function form_test_user_register_form_rebuild($form, &$form_state) {
1904
  drupal_set_message('Form rebuilt.');
1905
  $form_state['rebuild'] = TRUE;
1906
}
1907

    
1908
/**
1909
 * Menu callback that returns two instances of the node form.
1910
 */
1911
function form_test_two_instances() {
1912
  global $user;
1913
  $node1 = (object) array(
1914
    'uid' => $user->uid,
1915
    'name' => (isset($user->name) ? $user->name : ''),
1916
    'type' => 'page',
1917
    'language' => LANGUAGE_NONE,
1918
  );
1919
  $node2 = clone($node1);
1920
  $return['node_form_1'] = drupal_get_form('page_node_form', $node1);
1921
  $return['node_form_2'] = drupal_get_form('page_node_form', $node2);
1922
  return $return;
1923
}
1924

    
1925
/**
1926
 * Menu callback for testing custom form includes.
1927
 */
1928
function form_test_load_include_custom($form, &$form_state) {
1929
  $form['button'] = array(
1930
    '#type' => 'submit',
1931
    '#value' => t('Save'),
1932
    '#submit' => array('form_test_load_include_submit'),
1933
  );
1934
  // Specify the include file and enable form caching. That way the form is
1935
  // cached when it is submitted, but needs to find the specified submit handler
1936
  // in the include.
1937
  // Filename is a bit weird here: modules/simpletest/tests/form_test.file.inc
1938
  form_load_include($form_state, 'inc', 'form_test', 'form_test.file');
1939
  $form_state['cache'] = TRUE;
1940
  return $form;
1941
}
1942

    
1943
function form_test_checkbox_type_juggling($form, $form_state, $default_value, $return_value) {
1944
  $form['checkbox'] = array(
1945
    '#type' => 'checkbox',
1946
    '#return_value' => $return_value,
1947
    '#default_value' => $default_value,
1948
  );
1949
  return $form;
1950
}
1951

    
1952
function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) {
1953
  $form['checkbox_off'] = array(
1954
    '#type' => 'checkboxes',
1955
    '#options' => array('foo', 'bar', 'baz'),
1956
  );
1957
  $form['checkbox_zero_default'] = array(
1958
    '#type' => 'checkboxes',
1959
    '#options' => array('foo', 'bar', 'baz'),
1960
    '#default_value' => array(0),
1961
  );
1962
  $form['checkbox_string_zero_default'] = array(
1963
    '#type' => 'checkboxes',
1964
    '#options' => array('foo', 'bar', 'baz'),
1965
    '#default_value' => array('0'),
1966
  );
1967
  $form['submit'] = array(
1968
    '#type' => 'submit',
1969
    '#value' => 'Save',
1970
  );
1971
  if ($json) {
1972
    $form['#submit'][] = '_form_test_checkbox_submit';
1973
  }
1974
  else {
1975
    $form['#submit'][] = '_form_test_checkboxes_zero_no_redirect';
1976
  }
1977
  return $form;
1978
}
1979

    
1980
function _form_test_checkboxes_zero_no_redirect($form, &$form_state) {
1981
  $form_state['redirect'] = FALSE;
1982
}
1983

    
1984
/**
1985
 * Menu callback returns two instances of the same form.
1986
 */
1987
function form_test_double_form() {
1988
  return array(
1989
    'form1' => drupal_get_form('form_test_html_id'),
1990
    'form2' => drupal_get_form('form_test_html_id'),
1991
  );
1992
}
1993

    
1994
/**
1995
 * Builds a simple form to test duplicate HTML IDs.
1996
 */
1997
function form_test_html_id($form, &$form_state) {
1998
  $form['name'] = array(
1999
    '#type' => 'textfield',
2000
    '#title' => 'name',
2001
    '#required' => TRUE,
2002
  );
2003
  $form['submit'] = array(
2004
    '#type' => 'submit',
2005
    '#value' => 'Save',
2006
  );
2007
  return $form;
2008
}