form.inc 27.8 KB
Newer Older
1
<?php
2
3
// $Id$

4
5
6
7
8
9
10
/**
 * @defgroup form Form generation
 * @{
 * Functions to enable output of HTML forms and form elements.
 *
 * Drupal uses these functions to achieve consistency in its form presentation,
 * while at the same time simplifying code and reducing the amount of HTML that
11
12
13
14
15
 * must be explicitly generated by modules. See the
 * <a href="http://drupaldocs.org/api/head/file/contributions/docs/developer/topics/forms_api_reference.html">reference</a>
 * and the
 * <a href="http://drupaldocs.org/api/file/contributions/docs/developer/topics/forms_api.html">quickstart</a>
 * guide for more.
16
17
18
19
20
21
 */

/**
 * Check if the key is a property.
 */
function element_property($key) {
22
  return $key{0} == '#';
23
24
25
}

function element_properties($element) {
Steven Wittens's avatar
Steven Wittens committed
26
  return array_filter(array_keys((array) $element), 'element_property');
27
28
29
30
31
32
}

/**
 * Check if the key is a child.
 */
function element_child($key) {
33
  return $key{0} != '#';
34
35
36
}

function element_children($element) {
Steven Wittens's avatar
Steven Wittens committed
37
  return array_filter(array_keys((array) $element), 'element_child');
38
39
40
41
42
43
}

/**
 * Processes a form array, and produces the HTML output of a form.
 * If there is input in the $_POST['edit'] variable, this function
 * will attempt to validate it, using <code>drupal_validate_form</code>,
44
 * and then submit the form using <code>drupal_submit_form</code>.
45
46
47
48
49
50
51
52
53
54
 *
 * @param $form_id
 *   A unique string identifying the form. Allows each form to be themed.
 * @param $form
 *   An associative array containing the structure of the form.
 * @param $callback
 *   An optional callback that will be used in addition to the form_id.
 *
 */
function drupal_get_form($form_id, &$form, $callback = NULL) {
Dries Buytaert's avatar
Dries Buytaert committed
55
  global $form_values, $form_submitted;
56
  $form_values = array();
Dries Buytaert's avatar
Dries Buytaert committed
57
  $form_submitted = FALSE;
Steven Wittens's avatar
Steven Wittens committed
58

59
60
  $form['#type'] = 'form';
  if (isset($form['#token'])) {
61
62
63
64
65
    // Make sure that a private key is set:
    if (!variable_get('drupal_private_key', '')) {
      variable_set('drupal_private_key', mt_rand());
    }

Steven Wittens's avatar
Steven Wittens committed
66
67
    $form['form_token'] = array('#type' => 'hidden', '#value' => md5($_SERVER['REMOTE_ADDR'] . $form['#token'] . variable_get('drupal_private_key',
'')));
68
  }
Steven Wittens's avatar
Steven Wittens committed
69
70
  $form['form_id'] = array('#type' => 'hidden', '#default_value' => $form_id);

71
72
  $form = array_merge(_element_info('form'), $form);

Dries Buytaert's avatar
Dries Buytaert committed
73
74
  if (!isset($form['#validate'])) {
    if (function_exists($form_id .'_validate')) {
75
      $form['#validate'] = array($form_id .'_validate' => array());
Dries Buytaert's avatar
Dries Buytaert committed
76
77
    }
    elseif (function_exists($callback .'_validate')) {
78
      $form['#validate'] = array($callback .'_validate' => array());
Dries Buytaert's avatar
Dries Buytaert committed
79
80
81
    }
  }

82
83
  if (!isset($form['#submit'])) {
    if (function_exists($form_id .'_submit')) {
84
85
86
      // we set submit here so that it can be altered but use reference for
      // $form_values because it will change later
      $form['#submit'] = array($form_id .'_submit' => array($form_id, &$form_values));
Dries Buytaert's avatar
Dries Buytaert committed
87
    }
88
    elseif (function_exists($callback .'_submit')) {
89
      $form['#submit'] = array($callback .'_submit' => array($form_id, &$form_values));
Dries Buytaert's avatar
Dries Buytaert committed
90
91
92
    }
  }

93
94
  foreach (module_implements('form_alter') as $module) {
    $function = $module .'_form_alter';
95
    $function($form_id, $form);
96
97
  }

98
  $form = _form_builder($form_id, $form);
Steven Wittens's avatar
Steven Wittens committed
99

100
  if (!empty($_POST['edit']) && (($_POST['edit']['form_id'] == $form_id) || ($_POST['edit']['form_id'] == $callback))) {
101
    drupal_validate_form($form_id, $form, $callback);
Dries Buytaert's avatar
Dries Buytaert committed
102
    if ($form_submitted && !form_get_errors()) {
103
      drupal_submit_form($form_id, $form, $callback);
104
    }
105
106
107
  }

  if (function_exists('theme_' . $form_id)) {
108
    $form['#theme'] = $form_id;
109
110
  }
  elseif (function_exists('theme_' . $callback)) {
111
    $form['#theme'] = $callback;
112
113
114
115
116
117
118
  }
  return form_render($form);
}

function drupal_validate_form($form_id, &$form, $callback = NULL) {
  global $form_values;

119
120
  if (isset($form['#token'])) {
    if ($form_values['form_token'] != md5($_SERVER['REMOTE_ADDR'] . $form['#token'] . variable_get('drupal_private_key', ''))) {
121
122
123
124
125
      // setting this error will cause the form to fail validation
      form_set_error('form_token', t('Validation error, please try again.  If this error persists, please contact the site administrator.'));
    }
  }

126
  _form_validate($form, $form_id);
127
128
}

129
function drupal_submit_form($form_id, $form, $callback = NULL) {
130
131
  global $form_values;

132
  if (isset($form['#submit'])) {
133
134
135
    foreach ($form['#submit'] as $function => $args) {
      if (function_exists($function)) {
        call_user_func_array($function, $args);
Dries Buytaert's avatar
Dries Buytaert committed
136
137
      }
    }
138
139
140
  }
}

141
function _form_validate($elements, $form_id = NULL) {
142
  /* Validate the current input */
143
  if (!$elements['#validated'] && ($elements['#input'] || isset($form_id))) {
144
145
146
147
    // An empty checkbox returns 0, an empty textfield returns '' so we use empty().
    // Unfortunately, empty('0') returns TRUE so we need a special check for the '0' string.
    if ($elements['#required'] && empty($elements['#value']) && $elements['#value'] !== '0') {
      form_error($elements, t('%name field is required', array('%name' => $elements['#title'])));
148
    }
Dries Buytaert's avatar
Dries Buytaert committed
149
    if (isset($elements['#validate'])) {
150
151
152
153
154
      foreach ($elements['#validate'] as $function => $args) {
        $args = array_merge(array($elements), $args);
        // for the full form we hand over a copy of $form_values
        if (isset($form_id)) {
          $args = array_merge(array($form_id, $GLOBALS['form_values']), $args);
155
        }
156
157
        if (function_exists($function))  {
          call_user_func_array($function, $args);
158
159
160
        }
      }
    }
161
    $elements['#validated'] = TRUE;
162
  }
163
164
165
166
167
168
169

  // Recurse through all children.
  foreach (element_children($elements) as $key) {
    if (isset($elements[$key]) && $elements[$key]) {
      _form_validate($elements[$key]);
    }
  }
170
171
}

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
 * File an error against a form element. If the name of the element is
 * edit[foo][bar] then you may pass either foo or foo][bar as $name
 * foo will set an error for all its children.
 */
function form_set_error($name = NULL, $message = NULL) {
  static $form = array();
  if (isset($name) && !isset($form[$name])) {
    $form[$name] = $message;
    drupal_set_message($message, 'error');
  }
  return $form;
}

/**
 * Return an associative array of all errors.
 */
function form_get_errors() {
  $form = form_set_error();
  if (!empty($form)) {
    return $form;
  }
}

/**
 * Return the error message filed against the form with the specified name.
 */
function form_get_error($element) {
  $form = form_set_error();
  $key = $element['#parents'][0];
  if (isset($form[$key])) {
    return $form[$key];
  }
  $key = implode('][', $element['#parents']);
  if (isset($form[$key])) {
    return $form[$key];
  }
}

211
212
213
214
/**
 * Flag an element as having an error.
 */
function form_error(&$element, $message) {
215
  $element['#error'] = TRUE;
216
  form_set_error(implode('][', $element['#parents']), $message);
217
218
219
220
221
222
223
}

/**
 * Adds some required properties to each form element, which are used internally in the form api.
 * This function also automatically assigns the value property from the $edit array, provided the
 * element doesn't already have an assigned value.
 */
224
function _form_builder($form_id, $form) {
225
  global $form_values;
Dries Buytaert's avatar
Dries Buytaert committed
226
  global $form_submitted;
227
  /* Use element defaults */
228
  if ((!empty($form['#type'])) && ($info = _element_info($form['#type']))) {
229
230
231
    $form += $info;
  }

232
  if ($form['#input']) {
233
234
235
236
237
238
    if (!isset($form['#name'])) {
      $form['#name'] = 'edit[' . implode('][', $form['#parents']) . ']';
    }
    if (!isset($form['#id'])) {
      $form['#id'] =  'edit-' . implode('-', $form['#parents']);
    }
239

240
    $posted = (isset($_POST['edit']) && ($_POST['edit']['form_id'] == $form_id));
241
242
    $edit = $posted ? $_POST['edit'] : array();
    $ref =& $form_values;
243
    foreach ($form['#parents'] as $parent) {
244
245
246
      $edit = isset($edit[$parent]) ? $edit[$parent] : NULL;
      $ref =& $ref[$parent];
    }
247
    if (!isset($form['#value'])) {
248
249
250
251
252
253
254
255
256
257
258
      if ($posted) {
        if (isset($edit)) {
          $form['#value'] = $edit; // normal element
        }
        elseif (isset($form['#return_value'])) {
          $form['#value'] = 0; // checkbox unchecked
        }
      }
      if (!isset($form['#value'])) {
        $form['#value'] = $form['#default_value'];
      }
259
    }
Dries Buytaert's avatar
Dries Buytaert committed
260
    if (isset($form['#form_submitted'])) {
261
      if ($_POST[$form['#name']] == $form['#value']) {
Dries Buytaert's avatar
Dries Buytaert committed
262
        $form_submitted = $form_submitted || $form['#form_submitted'];
263
264
265
      }
    }

266
    $ref = $form['#value'];
267
268
269
  }

  // Allow for elements to expand to multiple elements. Radios, checkboxes and files for instance.
270
  if (isset($form['#process']) && !$form['#processed']) {
271
272
273
    foreach ($form['#process'] as $process => $args) {
      if (function_exists($process)) {
        $form = call_user_func($process, array_merge($form, $args));
274
275
      }
    }
276
    $form['#processed'] = TRUE;
277
278
279
280
281
  }

  // Recurse through all child elements.
  $count  = 0;
  foreach (element_children($form) as $key) {
Steven Wittens's avatar
Steven Wittens committed
282
    // don't squash an existing tree value
283
284
285
    if (!isset($form[$key]['#tree'])) {
      $form[$key]['#tree'] = $form['#tree'];
    }
Steven Wittens's avatar
Steven Wittens committed
286

287
288
289
290
291
292
293
294
295
296
297
    // don't squash existing parents value
    if (!isset($form[$key]['#parents'])) {
      if ($form[$key]['#tree']) {
        if (!$form['#tree']) {
          // begin tree
          $form[$key]['#parents'] = array($key);
        }
        else {
          //continue tree
          $form[$key]['#parents'] = array_merge($form['#parents'], array($key));
        }
298
299
      }
      else {
300
301
        // no tree
        $form[$key]['#parents'] = array($key);
302
      }
Steven Wittens's avatar
Steven Wittens committed
303
304
    }

305
    # Assign a decimal placeholder weight, to preserve original array order
306
307
308
    if (!isset($form[$key]['#weight'])) {
      $form[$key]['#weight'] = $count/1000;
    }
309
    $form[$key] = _form_builder($form_id, $form[$key]);
310
311
312
    $count++;
  }

313
314
315
  if (function_exists($form['#after_build']) && !isset($form['#after_build_done'])) {
    $form = call_user_func($form['#after_build'], $form, $form_values);
    $form['#after_build_done'] = TRUE;
Steven Wittens's avatar
Steven Wittens committed
316
  }
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337

  return $form;
}

/**
 * Renders a HTML form given an form tree.  Recursively iterates over each of
 * each of the form elements generating HTML code.  This function is usually
 * called from within a theme.  To render a form from within a module, use
 * <code>drupal_get_form()</code>.
 *
 * @param $elements
 *   The form tree describing the form.
 * @return
 *   The rendered HTML form.
 */
function form_render(&$elements) {
  $content = '';
  if (is_array($elements)) {
    uasort($elements, "_form_sort");
  }

338
  if (!$elements['#children']) {
339
    /* render all the children using a theme function */
340
341
342
343
344
345
    if ($elements['#theme'] && !$elements['#theme_used']) {
      $elements['#theme_used'] = TRUE;
      $previous_type = $elements['#type'];
      $elements['#type'] = 'markup';
      $content = theme($elements['#theme'], $elements);
      $elements['#type'] = $previous_type;
346
347
348
349
350
351
352
353
354
    }
    /* render each of the children using form_render and concatenate them */
    if (!$content) {
      foreach (element_children($elements) as $key) {
        $content .= form_render($elements[$key]);
      }
    }
  }
  if ($content) {
355
    $elements['#children'] = $content;
356
357
358
  }

  /* Call the form element renderer */
359
360
361
  if (!$elements['#printed']) {
    $content = theme(($elements['#type']) ? $elements['#type']: 'markup', $elements);
    $elements['#printed'] = TRUE;
362
363
  }

364
365
366
  if ($content) {
    return $elements['#prefix'] . $content . $elements['#suffix'];
  }
367
368
369
370
371
372
}

/**
 * Function used by uasort in form render to sort form via weight.
 */
function _form_sort($a, $b) {
373
  if ($a['#weight'] == $b['#weight']) {
374
375
    return 0;
  }
376
  return ($a['#weight'] < $b['#weight']) ? -1 : 1;
377
378
379
380
381
382
383
}

/**
 * Retrieve the default properties for the defined element type.
 */
function _element_info($type, $refresh = null) {
  static $cache;
Steven Wittens's avatar
Steven Wittens committed
384
385

  $parents = array();
386
  $basic_defaults = array(
387
388
389
    '#description' => NULL,
    '#attributes' => array(),
    '#required' => FALSE,
Steven Wittens's avatar
Steven Wittens committed
390
391
    '#tree' => FALSE,
    '#parents' => $parents
392
393
394
395
396
397
  );
  if ($refresh || !is_array($cache)) {
    $cache = array();
    foreach (module_implements('elements') as $module) {
      $elements = module_invoke($module, 'elements');
      if (is_array($elements)) {
398
        $cache = array_merge_recursive($cache, $elements);
399
400
401
402
      }
    }
    if (sizeof($cache)) {
      foreach ($cache as $element_type => $info) {
403
        $cache[$element_type] = array_merge_recursive($basic_defaults, $info);
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
      }
    }
  }

  return $cache[$type];
}

/**
 * Format a dropdown menu or scrolling selection box.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : title, value, options, description, extra, multiple, required
 * @return
 *   A themed HTML string representing the form element.
 *
 * It is possible to group options together; to do this, change the format of
 * $options to an associative array in which the keys are group labels, and the
 * values are associative arrays in the normal $options format.
 */
function theme_select($element) {
  $select = '';
426
  foreach ($element['#options'] as $key => $choice) {
427
428
429
    if (is_array($choice)) {
      $select .= '<optgroup label="'. $key .'">';
      foreach ($choice as $key => $choice) {
430
        $select .= '<option value="'. $key .'"'. (is_array($element['#value']) ? (in_array($key, $element['#value']) ? ' selected="selected"' : '') : ($element['#value'] == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>';
431
432
433
434
      }
      $select .= '</optgroup>';
    }
    else {
435
      $select .= '<option value="'. $key .'"'. (is_array($element['#value']) ? (in_array($key, $element['#value']) ? ' selected="selected"' : '') : ($element['#value'] == $key ? ' selected="selected"' : '')) .'>'. check_plain($choice) .'</option>';
436
437
    }
  }
Steven Wittens's avatar
Steven Wittens committed
438
  return theme('form_element', $element['#title'], '<select name="'. $element['#name'] .''. ($element['#multiple'] ? '[]' : '') .'"'. ($element['#multiple'] ? ' multiple="multiple" ' : '') . drupal_attributes($element['#attributes']) .' id="' . $element['#id'] .'">'. $select .'</select>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
439
440
441
442
443
444
445
446
447
448
449
450
}

/**
 * Format a group of form items.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : attributes, title, description, children, collapsible, collapsed
 * @return
 *   A themed HTML string representing the form item group.
 */
function theme_fieldset($element) {
451
  if ($element['#collapsible']) {
452
453
    drupal_add_js('misc/collapse.js');

454
455
456
    $element['#attributes']['class'] .= ' collapsible';
    if ($element['#collapsed']) {
     $element['#attributes']['class'] .= ' collapsed';
457
458
459
    }
  }

460
  return '<fieldset' . drupal_attributes($element['#attributes']) .'>' . ($element['#title'] ? '<legend>'. $element['#title'] .'</legend>' : '') . $element['#children'] . $element['#value'] . ($element['#description'] ? '<div class="description">'. $element['#description'] .'</div>' : '') . "</fieldset>\n";
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475

}


/**
 * Format a radio button.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : required, return_value, value, attributes, title, description
 * @return
 *   A themed HTML string representing the form item group.
 */
function theme_radio($element) {
  $output = '<input type="radio" ';
476
  $output .= 'class="'. _form_get_class('form-radio', $element['#required'], form_get_error($element)) .'" ';
477
478
479
480
481
482
  $output .= 'name="' . $element['#name'] .'" ';
  $output .= 'value="'. $element['#return_value'] .'" ';
  $output .= ($element['#value'] == $element['#return_value']) ? ' checked="checked" ' : ' ';
  $output .= drupal_attributes($element['#attributes']) .' />';
  if (!is_null($element['#title'])) {
    $output = '<label class="option">'. $output .' '. $element['#title'] .'</label>';
483
  }
484
  return theme('form_element', NULL, $output, $element['#description'], $element['#name'], $element['#required'], form_get_error($element));
485
486
487
488
489
490
491
492
493
494
495
496
}

/**
 * Format a set of radio buttons.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : title, value, options, description, required and attributes.
 * @return
 *   A themed HTML string representing the radio button set.
 */
function theme_radios($element) {
497
  if ($element['#title'] || $element['#description']) {
498
    return theme('form_element', $element['#title'], $element['#children'], $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
499
500
  }
  else {
501
    return $element['#children'];
502
503
504
505
  }
}

/**
506
 * Format a date selection element.
507
508
509
510
511
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : title, value, options, description, required and attributes.
 * @return
512
 *   A themed HTML string representing the date selection boxes.
513
514
 */
function theme_date($element) {
515
  $output = '<div class="container-inline">' . $element['#children'] . '</div>';
516
  return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
517
518
519
}

/**
520
 * Roll out a single date element.
521
522
523
 */
function expand_date($element) {
  // Default to current date
524
525
  if (!isset($element['#value'])) {
    $element['#value'] = array('day' => format_date(time(), 'custom', 'j'),
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
                            'month' => format_date(time(), 'custom', 'n'),
                            'year' => format_date(time(), 'custom', 'Y'));
  }

  // Determine the order of day, month, year in the site's chosen date format.
  $format = variable_get('date_format_short', 'm/d/Y');
  $sort = array();
  $sort['day'] = max(strpos($format, 'd'), strpos($format, 'j'));
  $sort['month'] = max(strpos($format, 'm'), strpos($format, 'M'));
  $sort['year'] = strpos($format, 'Y');
  asort($sort);
  $order = array_keys($sort);

  // Output multi-selector for date
  foreach ($order as $type) {
    switch ($type) {
      case 'day':
        $options = drupal_map_assoc(range(1, 31));
        break;
      case 'month':
546
        $options = drupal_map_assoc(range(1, 12), 'map_month');
547
548
549
550
551
        break;
      case 'year':
        $options = drupal_map_assoc(range(1900, 2050));
        break;
    }
Steven Wittens's avatar
Steven Wittens committed
552
    $element[$type] = array('#type' => 'select', '#value' => $element['#value'][$type], '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#options' => $options,  '#tree' => TRUE);
553
554
555
556
557
  }

  return $element;
}

558
559
560
561
562
563
/**
 * Helper function for usage with drupal_map_assoc to display month names.
 */
function map_month($month) {
  return format_date(gmmktime(0, 0, 0, $month, 2, 1970), 'custom', 'M', 0);
}
564
565

/**
566
 * Roll out a single radios element
567
 * to a list of radios, using the options array as index.
568
569
 */
function expand_radios($element) {
570
571
  if (count($element['#options']) > 0) {
    foreach ($element['#options'] as $key => $choice) {
572
      if (!$element[$key]) {
573
        $element[$key] = array('#type' => 'radio', '#title' => $choice, '#return_value' => $key, '#default_value' => $element['#default_value'], '#attributes' => $element['#attributes'], '#parents' => $element['#parents'], '#spawned' => TRUE);
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
      }
    }
  }
  return $element;
}


/**
 * Format a form item.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used :  title, value, description, required, error
 * @return
 *   A themed HTML string representing the form item.
 */
function theme_item($element) {
591
  return theme('form_element', $element['#title'], $element['#value'] . $element['#children'], $element['#description'], $element['#id'], $element['#required'], $element['#error']);
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
}


/**
 * Format a checkbox.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used :  title, value, return_value, description, required
 * @return
 *   A themed HTML string representing the checkbox.
 */
function theme_checkbox($element) {
  $checkbox = '<input ';
  $checkbox .= 'type="checkbox" ';
607
  $checkbox .= 'class="'. _form_get_class('form-checkbox', $element['#required'], form_get_error($element)) . '" ';
608
609
610
611
612
613
614
615
  $checkbox .= 'name="'. $element['#name'] .'" ';
  $checkbox .= 'id="'. $element['#id'].'" ' ;
  $checkbox .= 'value="'. $element['#return_value'] .'" ';
  $checkbox .= ($element['#value'] == $element['#return_value']) ? ' checked="checked" ' : ' ';
  $checkbox .= drupal_attributes($element['#attributes']) . ' />';

  if (!is_null($element['#title'])) {
    $checkbox = '<label class="option">'. $checkbox .' '. $element['#title'] .'</label>';
616
617
  }

618
  return theme('form_element', NULL, $checkbox, $element['#description'], $element['#name'], $element['#required'], form_get_error($element));
619
620
621
622
623
624
625
626
627
628
629
}

/**
 * Format a set of checkboxes.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 * @return
 *   A themed HTML string representing the checkbox set.
 */
function theme_checkboxes($element) {
630
  if ($element['#title'] || $element['#description']) {
631
    return theme('form_element', $element['#title'], $element['#children'], $element['#description'], 'edit-'. $element['#name'], $element['#required'], form_get_error($element));
632
633
  }
  else {
634
    return $element['#children'];
635
636
637
638
  }
}

function expand_checkboxes($element) {
639
  $value = is_array($element['#value']) ? $element['#value'] : array();
Steven Wittens's avatar
Steven Wittens committed
640
  $element['#tree'] = TRUE;
641
642
643
  if (count($element['#options']) > 0) {
    if (!isset($element['#default_value']) || $element['#default_value'] == 0) {
      $element['#default_value'] = array();
644
    }
645
    foreach ($element['#options'] as $key => $choice) {
646
      if (!isset($element[$key])) {
Steven Wittens's avatar
Steven Wittens committed
647
        $element[$key] = array('#type' => 'checkbox', '#processed' => TRUE, '#title' => $choice, '#default_value' => in_array($key, $value), '#attributes' => $element['#attributes']);
648
649
650
651
652
653
654
655
656
657
658
659
      }
    }
  }
  return $element;
}


function theme_submit($element) {
  return theme('button', $element);
}

function theme_button($element) {
660
  return '<input type="submit" class="form-'. $element['#button_type'] .'" name="'. $element['#name'] .'" value="'. check_plain($element['#value']) .'" '. drupal_attributes($element['#attributes']) ." />\n";
661
662
663
664
665
666
667
668
669
670
671
672
}

/**
 * Format a hidden form field.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used :  value, edit
 * @return
 *   A themed HTML string representing the hidden form field.
 */
function theme_hidden($element) {
673
  return '<input type="hidden" name="'. $element['#name'] . '" id="' . $element['#id'] . '" value="'. check_plain($element['#value']) ."\" " . drupal_attributes($element['#attributes']) ." />\n";
674
675
676
677
678
679
680
681
682
683
684
685
}

/**
 * Format a textfield.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used :  title, value, description, size, maxlength, required, attributes autocomplete_path
 * @return
 *   A themed HTML string representing the textfield.
 */
function theme_textfield($element) {
686
687
  $size = $element['#size'] ? ' size="' . $element['#size'] . '"' : '';
  if ($element['#autocomplete_path']) {
688
689
    drupal_add_js('misc/autocomplete.js');
    $class = ' form-autocomplete';
690
    $extra =  '<input class="autocomplete" type="hidden" id="'. $element['#id'] .'-autocomplete" value="'. check_url(url($element['#autocomplete_path'], NULL, NULL, TRUE)) .'" disabled="disabled" />';
691
692
  }

693
694
  $output = '<input type="text" maxlength="'. $element['#maxlength'] .'" class="'. _form_get_class("form-text$class", $element['#required'], form_get_error($element)) .'" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $size .' value="'. check_plain($element['#value']) .'"'. drupal_attributes($element['#attributes']) .' />';
  return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element)). $extra;
695
696
697
698
699
700
701
702
703
704
705
706
707
}

/**
 * Format a form.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : action, method, attributes, children
 * @return
 *   A themed HTML string representing the form.
 */
function theme_form($element) {
  // Anonymous div to satisfy XHTML compliancy.
708
709
  $action = $element['#action'] ? 'action="' . check_url($element['#action']) . '" ' : '';
  return '<form '. $action . ' method="'. $element['#method'] .'" '. drupal_attributes($element['#attributes']) .">\n<div>". $element['#children'] ."\n</div></form>\n";
710
711
712
713
714
715
716
717
718
719
720
721
722
}


/**
 * Format a textarea.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : title, value, description, rows, cols, required, attributes
 * @return
 *   A themed HTML string representing the textarea.
 */
function theme_textarea($element) {
723
  $cols = $element['#cols'] ? ' cols="'. $element['#cols'] .'"' : '';
724

725
  return theme('form_element', $element['#title'], '<textarea'. $cols .' rows="'. $element['#rows'] .'" name="'. $element['#name'] .'" id="' . $element['#id'] .'" class="'. _form_get_class('textarea', $element['#required'], form_get_error($element)) .'"'. drupal_attributes($element['#attributes']) .'>'. check_plain($element['#value']) .'</textarea>', $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
}

/**
 * Format HTML markup for use in forms.
 *
 * This is used in more advanced forms, such as theme selection and filter format.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used : prefix, value, children and suffix.
 * @return
 *   A themed HTML string representing the HTML markup.
 */

function theme_markup($element) {
741
  return $element['#value'] . $element['#children'];
742
743
744
745
746
747
748
749
750
751
752
753
754
755
}



/**
* Format a password field.
*
* @param $element
*   An associative array containing the properties of the element.
*   Properties used :  title, value, description, size, maxlength, required, attributes
* @return
*   A themed HTML string representing the form.
*/
function theme_password($element) {
756
  $size = $element['#size'] ? ' size="'. $element['#size'] .'" ' : '';
757

758
  $output = '<input type="password" maxlength="'. $element['#maxlength'] .'" class="'. _form_get_class("form-text $class", $element['#required'], form_get_error($element)) .'" name="'. $element['#name'] .'" id="'. $element['#id'] .'" '. $size . drupal_attributes($element['#attributes']) .' />';
759

760
  return theme('form_element', $element['#title'], $output, $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
761
762
763
764
765
766
767
768
769
770
771
772
}

/**
 * Format a weight selection menu.
 *
 * @param $element
 *   An associative array containing the properties of the element.
 *   Properties used :  title, delta, description
 * @return
 *   A themed HTML string representing the form.
 */
function theme_weight($element) {
773
  for ($n = (-1 * $element['#delta']); $n <= $element['#delta']; $n++) {
774
775
    $weights[$n] = $n;
  }
776
777
  $element['#options'] = $weights;
  $element['#type'] = 'select';
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801

  return form_render($element);
}

/**
 * Format a file upload field.
 *
 * @param $title
 *   The label for the file upload field.
 * @param $name
 *   The internal name used to refer to the field.
 * @param $size
 *   A measure of the visible size of the field (passed directly to HTML).
 * @param $description
 *   Explanatory text to display after the form item.
 * @param $required
 *   Whether the user must upload a file to the field.
 * @return
 *   A themed HTML string representing the field.
 *
 * For assistance with handling the uploaded file correctly, see the API
 * provided by file.inc.
 */
function theme_file($element) {
802
  return theme('form_element', $element['#title'], '<input type="file" class="'. _form_get_class('form-file', $element['#required'], form_get_error($element)) .'" name="'. $element['#name'] .'" id="'. form_clean_id($element['#id']) .'" size="'. $element['#size'] ."\" />\n", $element['#description'], $element['#id'], $element['#required'], form_get_error($element));
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
}
function _form_get_class($name, $required, $error) {
  return $name. ($required ? ' required' : '') . ($error ? ' error' : '');
}

/**
 * Remove invalid characters from an HTML ID attribute string
 *
 * @param $id
 *   The ID to clean
 * @return
 *   The cleaned ID
 */
function form_clean_id($id = NULL) {
  $id = str_replace('][', '-', $id);
  return $id;
}

/**
 * @} End of "defgroup form".
 */