TRUE, '#theme' => array('textfield'), '#autocomplete_path' => FALSE, ); $types['form_example_checkbox'] = array( '#input' => TRUE, '#return_value' => TRUE, '#process' => array('form_expand_ahah'), // #theme is the default theme('form_example_checkbox'), provided by // this module. // This also depends on the existence of // form_type_form_example_checkbox_value(), which is provided by this // module. Since this is not a default textfield-derived element, it // needs its own value callback. ); // This discrete phonenumber element keeps its values as the separate elements // area code, prefix, extension. $types['form_example_phonenumber_discrete'] = array( '#input' => TRUE, // #process is an array of callback functions executed when this element is // processed. Here it provides the child form elements which define // areacode, prefix, and extension. '#process' => array('form_example_phonenumber_discrete_process'), // validation handlers for this element '#element_validate' => array('form_example_phonenumber_discrete_validate'), '#autocomplete_path' => FALSE, ); // Define form_example_phonenumber_combined, which combines the phone // number into a single validated text string. $types['form_example_phonenumber_combined'] = array( '#input' => TRUE, '#process' => array('form_example_phonenumber_combined_process'), '#element_validate' => array('form_example_phonenumber_combined_validate'), '#autocomplete_path' => FALSE, '#default_value' => array( 'areacode' => '', 'prefix' => '', 'extension' => '', ), ); return $types; } /** * Helper function to determine the value for an form_example_checkbox. * * Required for the element type 'form_example_checkbox' to work. * Copied from form.inc. * * @param $form * The form element whose value is being populated. * @param $edit * The incoming POST data to populate the form element. If this is FALSE, * the element's default value should be returned. * @return * The data that will appear in the $form_state['values'] collection * for this element. Return nothing to use the default. */ function form_type_form_example_checkbox_value($form, $edit = FALSE) { if ($edit !== FALSE) { if (empty($form['#disabled'])) { return !empty($edit) ? $form['#return_value'] : 0; } else { return $form['#default_value']; } } } /** * Process callback for the discrete version of phonenumber. */ function form_example_phonenumber_discrete_process($element, $edit, &$form_state, $complete_form) { // #tree = TRUE means that the values in $form_state['values'] will be stored // hierarchically. In this case, the parts of the element will appear in // $form_state['values'] as // $form_state['values']['']['areacode'], // $form_state['values']['']['prefix'], // etc. This technique is preferred when an element has member form // elements. $element['#tree'] = TRUE; // Normal FAPI field definitions, except that #value is defined. $element['areacode'] = array( '#type' => 'textfield', '#size' => 3, '#maxlength' => 3, '#value' => $element['#value']['areacode'], '#required' => TRUE, '#prefix' => '(', '#suffix' => ')', ); $element['prefix'] = array( '#type' => 'textfield', '#size' => 3, '#maxlength' => 3, '#required' => TRUE, '#value' => $element['#value']['prefix'], ); $element['extension'] = array( '#type' => 'textfield', '#size' => 4, '#maxlength' => 4, '#value' => $element['#value']['extension'], ); return $element; } /** * Validation handler for the discrete version of the phone number. * * Using regular expressions, we check that: * - the area code is a three digit number * - the prefix is numeric 3-digit number * - the extension is a numeric 4-digit number * * Any problems are shown on the form element using form_error(). */ function form_example_phonenumber_discrete_validate($element, &$form_state) { if (isset($element['#value']['areacode'])) { if (0 == preg_match('/^\d{3}$/', $element['#value']['areacode'])) { form_error($element['areacode'], t('The area code is invalid.')); } } if (isset($element['#value']['prefix'])) { if (0 == preg_match('/^\d{3}$/', $element['#value']['prefix'])) { form_error($element['prefix'], t('The prefix is invalid.')); } } if (isset($element['#value']['extension'])) { if (0 == preg_match('/^\d{4}$/', $element['#value']['extension'])) { form_error($element['extension'], t('The extension is invalid.')); } } return $element; } /** * Process callback for the combined version of the phonenumber element. */ function form_example_phonenumber_combined_process($element, $edit, &$form_state, $complete_form) { // #tree = TRUE means that the values in $form_state['values'] will be stored // hierarchically. In this case, the parts of the element will appear in // $form_state['values'] as // $form_state['values']['']['areacode'], // $form_state['values']['']['prefix'], // etc. This technique is preferred when an element has member form // elements. $element['#tree'] = TRUE; // Normal FAPI field definitions, except that #value is defined. $element['areacode'] = array( '#type' => 'textfield', '#size' => 3, '#maxlength' => 3, '#required' => TRUE, '#prefix' => '(', '#suffix' => ')', ); $element['prefix'] = array( '#type' => 'textfield', '#size' => 3, '#maxlength' => 3, '#required' => TRUE, ); $element['extension'] = array( '#type' => 'textfield', '#size' => 4, '#maxlength' => 4, '#required' => TRUE, ); $matches = array(); $match = preg_match('/^(\d{3})(\d{3})(\d{4})$/', $element['#default_value'], $matches); if ($match) { array_shift($matches); // get rid of the "all match" element list($element['areacode']['#default_value'], $element['prefix']['#default_value'], $element['extension']['#default_value']) = $matches; } return $element; } /** * Combined version validation function. * * Using regular expressions, we check that: * - the area code is a three digit number * - the prefix is numeric 3-digit number * - the extension is a numeric 4-digit number * * Any problems are shown on the form element using form_error(). * * The combined value is then updated in the element. */ function form_example_phonenumber_combined_validate($element, &$form_state) { $lengths = array( 'areacode' => 3, 'prefix' => 3, 'extension' => 4, ); foreach ($lengths as $member => $length) { $regex = '/^\d{' . $length . '}$/'; if (!empty($element['#value'][$member]) && 0 == preg_match($regex, $element['#value'][$member])) { form_error($element[$member], t('@member is invalid', array('@member' => $member))); } } // Consolidate into the three parts into one combined value. $value = $element['#value']['areacode'] . $element['#value']['prefix'] . $element['#value']['extension']; form_set_value($element, $value, $form_state); return $element; } /** * Called by form_example_theme() to provide hook_theme(). */ function _form_example_element_theme() { return array( 'form_example_checkbox' => array( 'arguments' => array('element'), 'file' => 'form_example_elements.inc', ), 'form_example_phonenumber_discrete' => array( 'arguments' => array('element'), 'file' => 'form_example_elements.inc', ), 'form_example_phonenumber_combined' => array( 'arguments' => array('element'), 'file' => 'form_example_elements.inc', ), ); } /** * Theme function for form_example_checkbox type. */ function theme_form_example_checkbox($element) { return theme('checkbox', $element); } /** * Theme function to format the discrete version. * * We use the container-inline class so that all three of the HTML elements * are placed next to each other, rather than on separate lines. */ function theme_form_example_phonenumber_discrete($element) { // #children represents all the sublevels elements already rendered in HTML. // Here it contains the three parts of the 'phonenumber' element type ('areacode', 'prefix' and 'extension'). return theme('form_element', $element, '
' . $element['#children'] . '
'); } /** * Theme function to format the combined version. * * We use the container-inline class so that all three of the HTML elements * are placed next to each other, rather than on separate lines. */ function theme_form_example_phonenumber_combined($element) { // #children represents all the sublevels elements already rendered in HTML. // Here it contains the three parts of the 'phonenumber' element type ('areacode', 'prefix' and 'extension'). return theme('form_element', $element, '
' . $element['#children'] . '
'); } /** * This is a simple form to demonstrate how to use the various new FAPI elements * we've defined. */ function form_example_element_demo_form() { $form['form_example_textfield'] = array( '#type' => 'form_example_textfield', '#title' => t('Form Example textfield'), '#default_value' => variable_get('form_example_textfield', ''), '#description' => t('form_example_textfield is a new type, but it is actually uses the system-provided functions of textfield'), ); $form['form_example_checkbox'] = array( '#type' => 'form_example_checkbox', '#title' => t('Form Example checkbox'), '#default_value' => variable_get('form_example_checkbox', FALSE), '#description' => t('Nothing more than a regular checkbox but with a theme provided by this module.') ); $form['form_example_element_discrete'] = array( '#type' => 'form_example_phonenumber_discrete', '#title' => t('Discrete phone number'), '#default_value' => variable_get('form_example_element_discrete', array('areacode' => '', 'prefix' => '', 'extension' => '')), '#description' => t('A phone number : areacode (XXX), prefix (XXX) and extension (XXXX). This one uses a "discrete" element type, one which stores the three parts of the telephone number separately.'), ); $form['form_example_element_combined'] = array( '#type' => 'form_example_phonenumber_combined', '#title' => t('Combined phone number'), '#default_value' => variable_get('form_example_element_combined', '0000000000'), '#description' => t('form_example_element_combined one uses a "combined" element type, one with a single 10-digit value which is broken apart when needed.'), ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Submit handler for form_example_element_demo_form(). */ function form_example_element_demo_form_submit($form, &$form_state) { // Exclude unnecessary elements. unset($form_state['values']['submit'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token'], $form_state['values']['form_build_id']); foreach ($form_state['values'] as $key => $value) { variable_set($key, $value); drupal_set_message(t('%name has value %value', array('%name' => $key, '%value' => print_r($value, TRUE)))); } }