Projet

Général

Profil

Paste
Télécharger (58,8 ko) Statistiques
| Branche: | Révision:

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

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

    
1008
  return $form;
1009
}
1010

    
1011
/**
1012
 * Menu callback; Invokes a form builder function with a wrapper callback.
1013
 */
1014
function form_test_wrapper_callback($form_id) {
1015
  $form_state = array(
1016
    'build_info' => array('args' => array()),
1017
    'wrapper_callback' => 'form_test_wrapper_callback_wrapper',
1018
  );
1019
  return drupal_build_form($form_id, $form_state);
1020
}
1021

    
1022
/**
1023
 * Form wrapper for form_test_wrapper_callback_form().
1024
 */
1025
function form_test_wrapper_callback_wrapper($form, &$form_state) {
1026
  $form['wrapper'] = array('#markup' => 'Form wrapper callback element output.');
1027
  return $form;
1028
}
1029

    
1030
/**
1031
 * Form builder for form wrapper callback test.
1032
 */
1033
function form_test_wrapper_callback_form($form, &$form_state) {
1034
  $form['builder'] = array('#markup' => 'Form builder element output.');
1035
  return $form;
1036
}
1037

    
1038
/**
1039
 * Form builder for form_state_values_clean() test.
1040
 */
1041
function form_test_form_state_values_clean_form($form, &$form_state) {
1042
  // Build an example form containing multiple submit and button elements; not
1043
  // only on the top-level.
1044
  $form = array('#tree' => TRUE);
1045
  $form['foo'] = array('#type' => 'submit', '#value' => t('Submit'));
1046
  $form['bar'] = array('#type' => 'submit', '#value' => t('Submit'));
1047
  $form['beer'] = array('#type' => 'value', '#value' => 1000);
1048
  $form['baz']['foo'] = array('#type' => 'button', '#value' => t('Submit'));
1049
  $form['baz']['baz'] = array('#type' => 'submit', '#value' => t('Submit'));
1050
  $form['baz']['beer'] = array('#type' => 'value', '#value' => 2000);
1051
  return $form;
1052
}
1053

    
1054
/**
1055
 * Form submit handler for form_state_values_clean() test form.
1056
 */
1057
function form_test_form_state_values_clean_form_submit($form, &$form_state) {
1058
  form_state_values_clean($form_state);
1059
  drupal_json_output($form_state['values']);
1060
  exit;
1061
}
1062

    
1063
/**
1064
 * Form constructor for the form_state_values_clean() test.
1065
 */
1066
function form_test_form_state_values_clean_advanced_form($form, &$form_state) {
1067
  // Build an example form containing a managed file and a submit form element.
1068
  $form['image'] = array(
1069
    '#type' => 'managed_file',
1070
    '#title' => t('Image'),
1071
    '#upload_location' => 'public://',
1072
    '#default_value' => 0,
1073
  );
1074
  $form['submit'] = array(
1075
    '#type' => 'submit',
1076
    '#value' => t('Submit'),
1077
  );
1078
  return $form;
1079
}
1080

    
1081
/**
1082
 * Form submission handler for form_test_form_state_values_clean_advanced_form().
1083
 */
1084
function form_test_form_state_values_clean_advanced_form_submit($form, &$form_state) {
1085
  form_state_values_clean($form_state);
1086
  print t('You WIN!');
1087
  exit;
1088
}
1089

    
1090
/**
1091
 * Build a form to test a checkbox.
1092
 */
1093
function _form_test_checkbox($form, &$form_state) {
1094
  // A required checkbox.
1095
  $form['required_checkbox'] = array(
1096
    '#type' => 'checkbox',
1097
    '#required' => TRUE,
1098
    '#title' => 'required_checkbox',
1099
  );
1100

    
1101
  // A disabled checkbox should get its default value back.
1102
  $form['disabled_checkbox_on'] = array(
1103
    '#type' => 'checkbox',
1104
    '#disabled' => TRUE,
1105
    '#return_value' => 'disabled_checkbox_on',
1106
    '#default_value' => 'disabled_checkbox_on',
1107
    '#title' => 'disabled_checkbox_on',
1108
  );
1109
  $form['disabled_checkbox_off'] = array(
1110
    '#type' => 'checkbox',
1111
    '#disabled' => TRUE,
1112
    '#return_value' => 'disabled_checkbox_off',
1113
    '#default_value' => NULL,
1114
    '#title' => 'disabled_checkbox_off',
1115
  );
1116

    
1117
  // A checkbox is active when #default_value == #return_value.
1118
  $form['checkbox_on'] = array(
1119
    '#type' => 'checkbox',
1120
    '#return_value' => 'checkbox_on',
1121
    '#default_value' => 'checkbox_on',
1122
    '#title' => 'checkbox_on',
1123
  );
1124

    
1125
  // But inactive in any other case.
1126
  $form['checkbox_off'] = array(
1127
    '#type' => 'checkbox',
1128
    '#return_value' => 'checkbox_off',
1129
    '#default_value' => 'checkbox_on',
1130
    '#title' => 'checkbox_off',
1131
  );
1132

    
1133
  // Checkboxes with a #return_value of '0' are supported.
1134
  $form['zero_checkbox_on'] = array(
1135
    '#type' => 'checkbox',
1136
    '#return_value' => '0',
1137
    '#default_value' => '0',
1138
    '#title' => 'zero_checkbox_on',
1139
  );
1140

    
1141
  // In that case, passing a #default_value != '0' means that the checkbox is off.
1142
  $form['zero_checkbox_off'] = array(
1143
    '#type' => 'checkbox',
1144
    '#return_value' => '0',
1145
    '#default_value' => '1',
1146
    '#title' => 'zero_checkbox_off',
1147
  );
1148

    
1149
  $form['submit'] = array(
1150
    '#type' => 'submit',
1151
    '#value' => t('Submit')
1152
  );
1153

    
1154
  return $form;
1155
}
1156

    
1157
/**
1158
 * Return the form values via JSON.
1159
 */
1160
function _form_test_checkbox_submit($form, &$form_state) {
1161
  drupal_json_output($form_state['values']);
1162
  exit();
1163
}
1164

    
1165
/**
1166
 * Builds a form to test #type 'select' validation.
1167
 */
1168
function form_test_select($form, &$form_state) {
1169
  $base = array(
1170
    '#type' => 'select',
1171
    '#options' => drupal_map_assoc(array('one', 'two', 'three')),
1172
  );
1173

    
1174
  $form['select'] = $base + array(
1175
    '#title' => '#default_value one',
1176
    '#default_value' => 'one',
1177
  );
1178
  $form['select_required'] = $base + array(
1179
    '#title' => '#default_value one, #required',
1180
    '#required' => TRUE,
1181
    '#default_value' => 'one',
1182
  );
1183
  $form['select_optional'] = $base + array(
1184
    '#title' => '#default_value one, not #required',
1185
    '#required' => FALSE,
1186
    '#default_value' => 'one',
1187
  );
1188
  $form['empty_value'] = $base + array(
1189
    '#title' => '#default_value one, #required, #empty_value 0',
1190
    '#required' => TRUE,
1191
    '#default_value' => 'one',
1192
    '#empty_value' => 0,
1193
  );
1194
  $form['empty_value_one'] = $base + array(
1195
    '#title' => '#default_value = #empty_value, #required',
1196
    '#required' => TRUE,
1197
    '#default_value' => 'one',
1198
    '#empty_value' => 'one',
1199
  );
1200

    
1201
  $form['no_default'] = $base + array(
1202
    '#title' => 'No #default_value, #required',
1203
    '#required' => TRUE,
1204
  );
1205
  $form['no_default_optional'] = $base + array(
1206
    '#title' => 'No #default_value, not #required',
1207
    '#required' => FALSE,
1208
    '#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.',
1209
  );
1210
  $form['no_default_optional_empty_value'] = $base + array(
1211
    '#title' => 'No #default_value, not #required, #empty_value empty string',
1212
    '#empty_value' => '',
1213
    '#required' => FALSE,
1214
    '#description' => 'Should result in an empty string (due to #empty_value), because it is optional.',
1215
  );
1216

    
1217
  $form['no_default_empty_option'] = $base + array(
1218
    '#title' => 'No #default_value, #required, #empty_option',
1219
    '#required' => TRUE,
1220
    '#empty_option' => '- Choose -',
1221
  );
1222
  $form['no_default_empty_option_optional'] = $base + array(
1223
    '#title' => 'No #default_value, not #required, #empty_option',
1224
    '#empty_option' => '- Dismiss -',
1225
    '#description' => 'Should result in an empty string (default of #empty_value), because it is optional.',
1226
  );
1227

    
1228
  $form['no_default_empty_value'] = $base + array(
1229
    '#title' => 'No #default_value, #required, #empty_value 0',
1230
    '#required' => TRUE,
1231
    '#empty_value' => 0,
1232
    '#description' => 'Should never result in 0.',
1233
  );
1234
  $form['no_default_empty_value_one'] = $base + array(
1235
    '#title' => 'No #default_value, #required, #empty_value one',
1236
    '#required' => TRUE,
1237
    '#empty_value' => 'one',
1238
    '#description' => 'A mistakenly assigned #empty_value contained in #options should not be valid.',
1239
  );
1240
  $form['no_default_empty_value_optional'] = $base + array(
1241
    '#title' => 'No #default_value, not #required, #empty_value 0',
1242
    '#required' => FALSE,
1243
    '#empty_value' => 0,
1244
    '#description' => 'Should result in 0, because it is optional.',
1245
  );
1246

    
1247
  $form['multiple'] = $base + array(
1248
    '#title' => '#multiple, #default_value two',
1249
    '#default_value' => array('two'),
1250
    '#multiple' => TRUE,
1251
  );
1252
  $form['multiple_no_default'] = $base + array(
1253
    '#title' => '#multiple, no #default_value',
1254
    '#multiple' => TRUE,
1255
  );
1256
  $form['multiple_no_default_required'] = $base + array(
1257
    '#title' => '#multiple, #required, no #default_value',
1258
    '#required' => TRUE,
1259
    '#multiple' => TRUE,
1260
  );
1261

    
1262
  $form['submit'] = array('#type' => 'submit', '#value' => 'Submit');
1263
  return $form;
1264
}
1265

    
1266
/**
1267
 * Form submit handler for form_test_select().
1268
 */
1269
function form_test_select_submit($form, &$form_state) {
1270
  drupal_json_output($form_state['values']);
1271
  exit();
1272
}
1273

    
1274
/**
1275
 * Form constructor to test expansion of #type checkboxes and radios.
1276
 */
1277
function form_test_checkboxes_radios($form, &$form_state, $customize = FALSE) {
1278
  $form['#submit'] = array('_form_test_submit_values_json');
1279

    
1280
  // Expand #type checkboxes, setting custom element properties for some but not
1281
  // all options.
1282
  $form['checkboxes'] = array(
1283
    '#type' => 'checkboxes',
1284
    '#title' => 'Checkboxes',
1285
    '#options' => array(
1286
      0 => 'Zero',
1287
      'foo' => 'Foo',
1288
      1 => 'One',
1289
      'bar' => 'Bar',
1290
      '>' => 'Special Char',
1291
    ),
1292
  );
1293
  if ($customize) {
1294
    $form['checkboxes'] += array(
1295
      'foo' => array(
1296
        '#description' => 'Enable to foo.',
1297
      ),
1298
      1 => array(
1299
        '#weight' => 10,
1300
      ),
1301
    );
1302
  }
1303

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

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

    
1330
  return $form;
1331
}
1332

    
1333
/**
1334
 * Build a form to test disabled elements.
1335
 */
1336
function _form_test_disabled_elements($form, &$form_state) {
1337
  // Elements that take a simple default value.
1338
  foreach (array('textfield', 'textarea', 'hidden') as $type) {
1339
    $form[$type] = array(
1340
      '#type' => $type,
1341
      '#title' => $type,
1342
      '#default_value' => $type,
1343
      '#test_hijack_value' => 'HIJACK',
1344
      '#disabled' => TRUE,
1345
    );
1346
  }
1347

    
1348
  // Multiple values option elements.
1349
  foreach (array('checkboxes', 'select') as $type) {
1350
    $form[$type . '_multiple'] = array(
1351
      '#type' => $type,
1352
      '#title' => $type . ' (multiple)',
1353
      '#options' => array(
1354
        'test_1' => 'Test 1',
1355
        'test_2' => 'Test 2',
1356
      ),
1357
      '#multiple' => TRUE,
1358
      '#default_value' => array('test_2' => 'test_2'),
1359
      // The keys of #test_hijack_value need to match the #name of the control.
1360
      // @see FormsTestCase::testDisabledElements()
1361
      '#test_hijack_value' => $type == 'select' ? array('' => 'test_1') : array('test_1' => 'test_1'),
1362
      '#disabled' => TRUE,
1363
    );
1364
  }
1365

    
1366
  // Single values option elements.
1367
  foreach (array('radios', 'select') as $type) {
1368
    $form[$type . '_single'] = array(
1369
      '#type' => $type,
1370
      '#title' => $type . ' (single)',
1371
      '#options' => array(
1372
        'test_1' => 'Test 1',
1373
        'test_2' => 'Test 2',
1374
      ),
1375
      '#multiple' => FALSE,
1376
      '#default_value' => 'test_2',
1377
      '#test_hijack_value' => 'test_1',
1378
      '#disabled' => TRUE,
1379
    );
1380
  }
1381

    
1382
  // Checkbox and radio.
1383
  foreach (array('checkbox', 'radio') as $type) {
1384
    $form[$type . '_unchecked'] = array(
1385
      '#type' => $type,
1386
      '#title' => $type . ' (unchecked)',
1387
      '#return_value' => 1,
1388
      '#default_value' => 0,
1389
      '#test_hijack_value' => 1,
1390
      '#disabled' => TRUE,
1391
    );
1392
    $form[$type . '_checked'] = array(
1393
      '#type' => $type,
1394
      '#title' => $type . ' (checked)',
1395
      '#return_value' => 1,
1396
      '#default_value' => 1,
1397
      '#test_hijack_value' => NULL,
1398
      '#disabled' => TRUE,
1399
    );
1400
  }
1401

    
1402
  // Weight.
1403
  $form['weight'] = array(
1404
    '#type' => 'weight',
1405
    '#title' => 'weight',
1406
    '#default_value' => 10,
1407
    '#test_hijack_value' => 5,
1408
    '#disabled' => TRUE,
1409
  );
1410

    
1411
  // Date.
1412
  $form['date'] = array(
1413
    '#type' => 'date',
1414
    '#title' => 'date',
1415
    '#disabled' => TRUE,
1416
    '#default_value' => array(
1417
      'day' => 19,
1418
      'month' => 11,
1419
      'year' => 1978,
1420
    ),
1421
    '#test_hijack_value' => array(
1422
      'day' => 20,
1423
      'month' => 12,
1424
      'year' => 1979,
1425
    ),
1426
  );
1427

    
1428
  // The #disabled state should propagate to children.
1429
  $form['disabled_container'] = array(
1430
    '#disabled' => TRUE,
1431
  );
1432
  foreach (array('textfield', 'textarea', 'hidden') as $type) {
1433
    $form['disabled_container']['disabled_container_' . $type] = array(
1434
      '#type' => $type,
1435
      '#title' => $type,
1436
      '#default_value' => $type,
1437
      '#test_hijack_value' => 'HIJACK',
1438
    );
1439
  }
1440

    
1441
  // Text format.
1442
  $form['text_format'] = array(
1443
    '#type' => 'text_format',
1444
    '#title' => 'Text format',
1445
    '#disabled' => TRUE,
1446
    '#default_value' => 'Text value',
1447
    '#format' => 'plain_text',
1448
    '#expected_value' => array(
1449
      'value' => 'Text value',
1450
      'format' => 'plain_text',
1451
    ),
1452
    '#test_hijack_value' => array(
1453
      'value' => 'HIJACK',
1454
      'format' => 'filtered_html',
1455
    ),
1456
  );
1457

    
1458
  // Password fields.
1459
  $form['password'] = array(
1460
    '#type' => 'password',
1461
    '#title' => 'Password',
1462
    '#disabled' => TRUE,
1463
  );
1464
  $form['password_confirm'] = array(
1465
    '#type' => 'password_confirm',
1466
    '#title' => 'Password confirm',
1467
    '#disabled' => TRUE,
1468
  );
1469

    
1470
  // Files.
1471
  $form['file'] = array(
1472
    '#type' => 'file',
1473
    '#title' => 'File',
1474
    '#disabled' => TRUE,
1475
  );
1476
  $form['managed_file'] = array(
1477
    '#type' => 'managed_file',
1478
    '#title' => 'Managed file',
1479
    '#disabled' => TRUE,
1480
  );
1481

    
1482
  // Buttons.
1483
  $form['image_button'] = array(
1484
    '#type' => 'image_button',
1485
    '#value' => 'Image button',
1486
    '#disabled' => TRUE,
1487
  );
1488
  $form['button'] = array(
1489
    '#type' => 'button',
1490
    '#value' => 'Button',
1491
    '#disabled' => TRUE,
1492
  );
1493
  $form['submit_disabled'] = array(
1494
    '#type' => 'submit',
1495
    '#value' => 'Submit',
1496
    '#disabled' => TRUE,
1497
  );
1498

    
1499
  $form['submit'] = array(
1500
    '#type' => 'submit',
1501
    '#value' => t('Submit'),
1502
  );
1503

    
1504
  return $form;
1505
}
1506

    
1507
/**
1508
 * Return the form values via JSON.
1509
 */
1510
function _form_test_disabled_elements_submit($form, &$form_state) {
1511
  drupal_json_output($form_state['values']);
1512
  exit();
1513
}
1514

    
1515
/**
1516
 * Build a form to test input forgery of enabled elements.
1517
 */
1518
function _form_test_input_forgery($form, &$form_state) {
1519
  // For testing that a user can't submit a value not matching one of the
1520
  // allowed options.
1521
  $form['checkboxes'] = array(
1522
    '#type' => 'checkboxes',
1523
    '#options' => array(
1524
      'one' => 'One',
1525
      'two' => 'Two',
1526
    ),
1527
  );
1528

    
1529
  $form['submit'] = array(
1530
    '#type' => 'submit',
1531
    '#value' => t('Submit'),
1532
  );
1533
  return $form;
1534
}
1535

    
1536
/**
1537
 * Return the form values via JSON.
1538
 */
1539
function _form_test_input_forgery_submit($form, &$form_state) {
1540
  drupal_json_output($form_state['values']);
1541
  exit();
1542
}
1543

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

    
1605
/**
1606
 * Button submit handler for form_test_form_rebuild_preserve_values_form().
1607
 */
1608
function form_test_form_rebuild_preserve_values_form_add_more($form, &$form_state) {
1609
  // Rebuild, to test preservation of input values.
1610
  $form_state['storage']['add_more'] = TRUE;
1611
  $form_state['rebuild'] = TRUE;
1612
}
1613

    
1614
/**
1615
 * Form submit handler for form_test_form_rebuild_preserve_values_form().
1616
 */
1617
function form_test_form_rebuild_preserve_values_form_submit($form, &$form_state) {
1618
  // Finish the workflow. Do not rebuild.
1619
  drupal_set_message(t('Form values: %values', array('%values' => var_export($form_state['values'], TRUE))));
1620
}
1621

    
1622
/**
1623
 * Form constructor for testing form state persistence.
1624
 */
1625
function form_test_state_persist($form, &$form_state) {
1626
  $form['title'] = array(
1627
    '#type' => 'textfield',
1628
    '#title' => 'title',
1629
    '#default_value' => 'DEFAULT',
1630
    '#required' => TRUE,
1631
  );
1632
  $form_state['value'] = 'State persisted.';
1633

    
1634
  $form['submit'] = array(
1635
    '#type' => 'submit',
1636
    '#value' => t('Submit'),
1637
  );
1638
  return $form;
1639
}
1640

    
1641
/**
1642
 * Submit handler.
1643
 *
1644
 * @see form_test_state_persist()
1645
 */
1646
function form_test_state_persist_submit($form, &$form_state) {
1647
  drupal_set_message($form_state['value']);
1648
  $form_state['rebuild'] = TRUE;
1649
}
1650

    
1651
/**
1652
 * Implements hook_form_FORM_ID_alter().
1653
 *
1654
 * @see form_test_state_persist()
1655
 */
1656
function form_test_form_form_test_state_persist_alter(&$form, &$form_state) {
1657
  // Simulate a form alter implementation inserting form elements that enable
1658
  // caching of the form, e.g. elements having #ajax.
1659
  if (!empty($_REQUEST['cache'])) {
1660
    $form_state['cache'] = TRUE;
1661
  }
1662
}
1663

    
1664
/**
1665
 * Form builder to test programmatic form submissions.
1666
 */
1667
function form_test_programmatic_form($form, &$form_state) {
1668
  $form['textfield'] = array(
1669
    '#title' => 'Textfield',
1670
    '#type' => 'textfield',
1671
  );
1672

    
1673
  $form['checkboxes'] = array(
1674
    '#type' => 'checkboxes',
1675
    '#options' => array(
1676
      1 => 'First checkbox',
1677
      2 => 'Second checkbox',
1678
    ),
1679
    // Both checkboxes are selected by default so that we can test the ability
1680
    // of programmatic form submissions to uncheck them.
1681
    '#default_value' => array(1, 2),
1682
  );
1683

    
1684
  // This is used to test that programmatic form submissions can bypass #access
1685
  // restrictions.
1686
  $form['textfield_no_access'] = array(
1687
    '#type' => 'textfield',
1688
    '#title' => 'Textfield no access',
1689
    '#default_value' => 'default value',
1690
    '#access' => FALSE,
1691
  );
1692

    
1693
  $form['field_to_validate'] = array(
1694
    '#type' => 'radios',
1695
    '#title' => 'Field to validate (in the case of limited validation)',
1696
    '#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.',
1697
    '#options' => array(
1698
      'all' => 'Validate all fields',
1699
      'textfield' => 'Validate the "Textfield" field',
1700
      'field_to_validate' => 'Validate the "Field to validate" field',
1701
    ),
1702
    '#default_value' => 'all',
1703
  );
1704

    
1705
  // The main submit button for the form.
1706
  $form['submit'] = array(
1707
    '#type' => 'submit',
1708
    '#value' => 'Submit',
1709
  );
1710
  // A secondary submit button that allows validation to be limited based on
1711
  // the value of the above radio selector.
1712
  $form['submit_limit_validation'] = array(
1713
    '#type' => 'submit',
1714
    '#value' => 'Submit with limited validation',
1715
    // Use the same submit handler for this button as for the form itself.
1716
    // (This must be set explicitly or otherwise the form API will ignore the
1717
    // #limit_validation_errors property.)
1718
    '#submit' => array('form_test_programmatic_form_submit'),
1719
  );
1720
  if (!empty($form_state['input']['field_to_validate']) && $form_state['input']['field_to_validate'] != 'all') {
1721
    $form['submit_limit_validation']['#limit_validation_errors'] = array(
1722
      array($form_state['input']['field_to_validate']),
1723
    );
1724
  }
1725

    
1726
  return $form;
1727
}
1728

    
1729
/**
1730
 * Form validation handler for programmatic form submissions.
1731
 *
1732
 * To test that the validation handler is correctly executed, the field value is
1733
 * explicitly required here.
1734
 */
1735
function form_test_programmatic_form_validate($form, &$form_state) {
1736
  if (empty($form_state['values']['textfield'])) {
1737
    form_set_error('textfield', t('Textfield is required.'));
1738
  }
1739
}
1740

    
1741
/**
1742
 * Form submit handler for programmatic form submissions.
1743
 *
1744
 * To test that the submission handler is correctly executed, we store the
1745
 * submitted values in a place we can access from the caller context.
1746
 */
1747
function form_test_programmatic_form_submit($form, &$form_state) {
1748
  $form_state['storage']['programmatic_form_submit'] = $form_state['values'];
1749
}
1750

    
1751
/**
1752
 * Form builder to test button click detection.
1753
 */
1754
function form_test_clicked_button($form, &$form_state) {
1755
  // A single text field. In IE, when a form has only one non-button input field
1756
  // and the ENTER key is pressed while that field has focus, the form is
1757
  // submitted without any information identifying the button responsible for
1758
  // the submission. In other browsers, the form is submitted as though the
1759
  // first button were clicked.
1760
  $form['text'] = array(
1761
    '#title' => 'Text',
1762
    '#type' => 'textfield',
1763
  );
1764

    
1765
  // Loop through each path argument, addding buttons based on the information
1766
  // in the argument. For example, if the path is
1767
  // form-test/clicked-button/s/i/rb, then 3 buttons are added: a 'submit', an
1768
  // 'image_button', and a 'button' with #access=FALSE. This enables form.test
1769
  // to test a variety of combinations.
1770
  $i=0;
1771
  $args = array_slice(arg(), 2);
1772
  foreach ($args as $arg) {
1773
    $name = 'button' . ++$i;
1774
    // 's', 'b', or 'i' in the argument define the button type wanted.
1775
    if (strpos($arg, 's') !== FALSE) {
1776
      $type = 'submit';
1777
    }
1778
    elseif (strpos($arg, 'b') !== FALSE) {
1779
      $type = 'button';
1780
    }
1781
    elseif (strpos($arg, 'i') !== FALSE) {
1782
      $type = 'image_button';
1783
    }
1784
    else {
1785
      $type = NULL;
1786
    }
1787
    if (isset($type)) {
1788
      $form[$name] = array(
1789
        '#type' => $type,
1790
        '#name' => $name,
1791
      );
1792
      // Image buttons need a #src; the others need a #value.
1793
      if ($type == 'image_button') {
1794
        $form[$name]['#src'] = 'misc/druplicon.png';
1795
      }
1796
      else {
1797
        $form[$name]['#value'] = $name;
1798
      }
1799
      // 'r' for restricted, so we can test that button click detection code
1800
      // correctly takes #access security into account.
1801
      if (strpos($arg, 'r') !== FALSE) {
1802
        $form[$name]['#access'] = FALSE;
1803
      }
1804
    }
1805
  }
1806

    
1807
  return $form;
1808
}
1809

    
1810
/**
1811
 * Form validation handler for the form_test_clicked_button() form.
1812
 */
1813
function form_test_clicked_button_validate($form, &$form_state) {
1814
  if (isset($form_state['triggering_element'])) {
1815
    drupal_set_message(t('The clicked button is %name.', array('%name' => $form_state['triggering_element']['#name'])));
1816
  }
1817
  else {
1818
    drupal_set_message('There is no clicked button.');
1819
  }
1820
}
1821

    
1822
/**
1823
 * Form submit handler for the form_test_clicked_button() form.
1824
 */
1825
function form_test_clicked_button_submit($form, &$form_state) {
1826
  drupal_set_message('Submit handler for form_test_clicked_button executed.');
1827
}
1828

    
1829
/**
1830
 * Form builder to detect form redirect.
1831
 */
1832
function form_test_redirect($form, &$form_state) {
1833
  $form['redirection'] = array(
1834
    '#type' => 'checkbox',
1835
    '#title' => t('Use redirection'),
1836
  );
1837
  $form['destination'] = array(
1838
    '#type' => 'textfield',
1839
    '#title' => t('Redirect destination'),
1840
    '#states' => array(
1841
      'visible' => array(
1842
        ':input[name="redirection"]' => array('checked' => TRUE),
1843
      ),
1844
    ),
1845
  );
1846
  $form['submit'] = array(
1847
    '#type' => 'submit',
1848
    '#value' => t('Submit'),
1849
  );
1850

    
1851
  return $form;
1852
}
1853

    
1854
/**
1855
 * Form submit handler to test different redirect behaviours.
1856
 */
1857
function form_test_redirect_submit(&$form, &$form_state) {
1858
  if (!empty($form_state['values']['redirection'])) {
1859
    $form_state['redirect'] = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
1860
  }
1861
  else {
1862
    $form_state['redirect'] = FALSE;
1863
  }
1864
}
1865

    
1866
/**
1867
 * Implements hook_form_FORM_ID_alter() for the registration form.
1868
 */
1869
function form_test_form_user_register_form_alter(&$form, &$form_state) {
1870
  $form['test_rebuild'] = array(
1871
    '#type' => 'submit',
1872
    '#value' => t('Rebuild'),
1873
    '#submit' => array('form_test_user_register_form_rebuild'),
1874
  );
1875
  // If requested, add the test field by attaching the node page form.
1876
  if (!empty($_REQUEST['field'])) {
1877
    $node = (object)array('type' => 'page');
1878
    field_attach_form('node', $node, $form, $form_state);
1879
  }
1880
}
1881

    
1882
/**
1883
 * Submit callback that just lets the form rebuild.
1884
 */
1885
function form_test_user_register_form_rebuild($form, &$form_state) {
1886
  drupal_set_message('Form rebuilt.');
1887
  $form_state['rebuild'] = TRUE;
1888
}
1889

    
1890
/**
1891
 * Menu callback that returns two instances of the node form.
1892
 */
1893
function form_test_two_instances() {
1894
  global $user;
1895
  $node1 = (object) array(
1896
    'uid' => $user->uid,
1897
    'name' => (isset($user->name) ? $user->name : ''),
1898
    'type' => 'page',
1899
    'language' => LANGUAGE_NONE,
1900
  );
1901
  $node2 = clone($node1);
1902
  $return['node_form_1'] = drupal_get_form('page_node_form', $node1);
1903
  $return['node_form_2'] = drupal_get_form('page_node_form', $node2);
1904
  return $return;
1905
}
1906

    
1907
/**
1908
 * Menu callback for testing custom form includes.
1909
 */
1910
function form_test_load_include_custom($form, &$form_state) {
1911
  $form['button'] = array(
1912
    '#type' => 'submit',
1913
    '#value' => t('Save'),
1914
    '#submit' => array('form_test_load_include_submit'),
1915
  );
1916
  // Specify the include file and enable form caching. That way the form is
1917
  // cached when it is submitted, but needs to find the specified submit handler
1918
  // in the include.
1919
  // Filename is a bit weird here: modules/simpletest/tests/form_test.file.inc
1920
  form_load_include($form_state, 'inc', 'form_test', 'form_test.file');
1921
  $form_state['cache'] = TRUE;
1922
  return $form;
1923
}
1924

    
1925
function form_test_checkbox_type_juggling($form, $form_state, $default_value, $return_value) {
1926
  $form['checkbox'] = array(
1927
    '#type' => 'checkbox',
1928
    '#return_value' => $return_value,
1929
    '#default_value' => $default_value,
1930
  );
1931
  return $form;
1932
}
1933

    
1934
function form_test_checkboxes_zero($form, &$form_state, $json = TRUE) {
1935
  $form['checkbox_off'] = array(
1936
    '#type' => 'checkboxes',
1937
    '#options' => array('foo', 'bar', 'baz'),
1938
  );
1939
  $form['checkbox_zero_default'] = array(
1940
    '#type' => 'checkboxes',
1941
    '#options' => array('foo', 'bar', 'baz'),
1942
    '#default_value' => array(0),
1943
  );
1944
  $form['checkbox_string_zero_default'] = array(
1945
    '#type' => 'checkboxes',
1946
    '#options' => array('foo', 'bar', 'baz'),
1947
    '#default_value' => array('0'),
1948
  );
1949
  $form['submit'] = array(
1950
    '#type' => 'submit',
1951
    '#value' => 'Save',
1952
  );
1953
  if ($json) {
1954
    $form['#submit'][] = '_form_test_checkbox_submit';
1955
  }
1956
  else {
1957
    $form['#submit'][] = '_form_test_checkboxes_zero_no_redirect';
1958
  }
1959
  return $form;
1960
}
1961

    
1962
function _form_test_checkboxes_zero_no_redirect($form, &$form_state) {
1963
  $form_state['redirect'] = FALSE;
1964
}
1965

    
1966
/**
1967
 * Menu callback returns two instances of the same form.
1968
 */
1969
function form_test_double_form() {
1970
  return array(
1971
    'form1' => drupal_get_form('form_test_html_id'),
1972
    'form2' => drupal_get_form('form_test_html_id'),
1973
  );
1974
}
1975

    
1976
/**
1977
 * Builds a simple form to test duplicate HTML IDs.
1978
 */
1979
function form_test_html_id($form, &$form_state) {
1980
  $form['name'] = array(
1981
    '#type' => 'textfield',
1982
    '#title' => 'name',
1983
    '#required' => TRUE,
1984
  );
1985
  $form['submit'] = array(
1986
    '#type' => 'submit',
1987
    '#value' => 'Save',
1988
  );
1989
  return $form;
1990
}