updated core to 7.58 (right after the site was hacked)
This commit is contained in:
12
sites/all/modules/examples/form_example/form_example.info
Normal file
12
sites/all/modules/examples/form_example/form_example.info
Normal file
@@ -0,0 +1,12 @@
|
||||
name = Form example
|
||||
description = Examples of using the Drupal Form API.
|
||||
package = Example modules
|
||||
core = 7.x
|
||||
files[] = form_example.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-01-10
|
||||
version = "7.x-1.x-dev"
|
||||
core = "7.x"
|
||||
project = "examples"
|
||||
datestamp = "1484076787"
|
||||
|
||||
234
sites/all/modules/examples/form_example/form_example.module
Normal file
234
sites/all/modules/examples/form_example/form_example.module
Normal file
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Examples demonstrating the Drupal Form API.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup form_example Example: Form API
|
||||
* @ingroup examples
|
||||
* @{
|
||||
* Examples demonstrating the Drupal Form API.
|
||||
*
|
||||
* The Form Example module is a part of the Examples for Developers Project
|
||||
* and provides various Drupal Form API Examples. You can download and
|
||||
* experiment with this code at the
|
||||
* @link http://drupal.org/project/examples Examples for Developers project page. @endlink
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*
|
||||
* Here we set up the URLs (menu entries) for the
|
||||
* form examples. Note that most of the menu items
|
||||
* have page callbacks and page arguments set, with
|
||||
* page arguments set to be functions in external files.
|
||||
*/
|
||||
function form_example_menu() {
|
||||
$items = array();
|
||||
$items['examples/form_example'] = array(
|
||||
'title' => 'Form Example',
|
||||
'page callback' => 'form_example_intro',
|
||||
'access callback' => TRUE,
|
||||
'expanded' => TRUE,
|
||||
);
|
||||
$items['examples/form_example/tutorial'] = array(
|
||||
'title' => 'Form Tutorial',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_1'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'A set of ten tutorials',
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
'type' => MENU_NORMAL_ITEM,
|
||||
);
|
||||
$items['examples/form_example/tutorial/1'] = array(
|
||||
'title' => '#1',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_1'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 1: Simplest form',
|
||||
'type' => MENU_DEFAULT_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/2'] = array(
|
||||
'title' => '#2',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_2'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 2: Form with a submit button',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/3'] = array(
|
||||
'title' => '#3',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_3'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 3: Fieldsets',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/4'] = array(
|
||||
'title' => '#4',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_4'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 4: Required fields',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/5'] = array(
|
||||
'title' => '#5',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_5'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 5: More element attributes',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/6'] = array(
|
||||
'title' => '#6',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_6'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 6: Form with a validate handler',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/7'] = array(
|
||||
'title' => '#7',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_7'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 7: Form with a submit handler',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/8'] = array(
|
||||
'title' => '#8',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_8'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 8: Basic multistep form',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/tutorial/9'] = array(
|
||||
'title' => '#9',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_9'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 9: Form with dynamically added new fields',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
'weight' => 9,
|
||||
);
|
||||
$items['examples/form_example/tutorial/10'] = array(
|
||||
'title' => '#10',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_10'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 10: Form with file upload',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
'weight' => 10,
|
||||
);
|
||||
$items['examples/form_example/tutorial/11'] = array(
|
||||
'title' => '#11',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_11'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Tutorial 11: generating a confirmation form',
|
||||
'type' => MENU_LOCAL_TASK,
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
'weight' => 11,
|
||||
);
|
||||
$items['examples/form_example/tutorial/11/confirm/%'] = array(
|
||||
'title' => 'Name Confirmation',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_tutorial_11_confirm_name', 5),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'Confirmation form for tutorial 11. Generated using the confirm_form function',
|
||||
'file' => 'form_example_tutorial.inc',
|
||||
);
|
||||
$items['examples/form_example/states'] = array(
|
||||
'title' => '#states example',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_states_form'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'How to use the #states attribute in FAPI',
|
||||
'file' => 'form_example_states.inc',
|
||||
);
|
||||
$items['examples/form_example/wizard'] = array(
|
||||
'title' => 'Extensible wizard example',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_wizard'),
|
||||
'access callback' => TRUE,
|
||||
'description' => 'A general approach to a wizard multistep form.',
|
||||
'file' => 'form_example_wizard.inc',
|
||||
);
|
||||
$items['examples/form_example/element_example'] = array(
|
||||
'title' => 'Element example',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'page arguments' => array('form_example_element_demo_form'),
|
||||
'access callback' => TRUE,
|
||||
'file' => 'form_example_elements.inc',
|
||||
'weight' => 100,
|
||||
);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Page callback for our general info page.
|
||||
*/
|
||||
function form_example_intro() {
|
||||
$markup = t('The form example module provides a tutorial, extensible multistep example, an element example, and a #states example');
|
||||
return array('#markup' => $markup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_help().
|
||||
*/
|
||||
function form_example_help($path, $arg) {
|
||||
switch ($path) {
|
||||
case 'examples/form_example/tutorial':
|
||||
// TODO: Update the URL.
|
||||
$help = t('This form example tutorial for Drupal 7 is the code from the <a href="http://drupal.org/node/262422">Handbook 10-step tutorial</a>');
|
||||
break;
|
||||
|
||||
case 'examples/form_example/element_example':
|
||||
$help = t('The Element Example shows how modules can provide their own Form API element types. Four different element types are demonstrated.');
|
||||
break;
|
||||
}
|
||||
if (!empty($help)) {
|
||||
return '<p>' . $help . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_element_info().
|
||||
*
|
||||
* To keep the various pieces of the example together in external files,
|
||||
* this just returns _form_example_elements().
|
||||
*/
|
||||
function form_example_element_info() {
|
||||
require_once 'form_example_elements.inc';
|
||||
return _form_example_element_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_theme().
|
||||
*
|
||||
* The only theme implementation is by the element example. To keep the various
|
||||
* parts of the example together, this actually returns
|
||||
* _form_example_element_theme().
|
||||
*/
|
||||
function form_example_theme($existing, $type, $theme, $path) {
|
||||
require_once 'form_example_elements.inc';
|
||||
return _form_example_element_theme($existing, $type, $theme, $path);
|
||||
}
|
||||
/**
|
||||
* @} End of "defgroup form_example".
|
||||
*/
|
||||
288
sites/all/modules/examples/form_example/form_example.test
Normal file
288
sites/all/modules/examples/form_example/form_example.test
Normal file
@@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test file for form_example module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default test case for the form_example module.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
class FormExampleTestCase extends DrupalWebTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Form Example',
|
||||
'description' => 'Various tests on the form_example module.' ,
|
||||
'group' => 'Examples',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable modules.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp('form_example');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test each tutorial.
|
||||
*/
|
||||
public function testTutorials() {
|
||||
// Tutorial #1
|
||||
$this->drupalGet('examples/form_example/tutorial');
|
||||
$this->assertText(t('#9'));
|
||||
|
||||
// #2
|
||||
$this->drupalPost('examples/form_example/tutorial/2', array('name' => t('name')), t('Submit'));
|
||||
|
||||
// #4
|
||||
$this->drupalPost('examples/form_example/tutorial/4',
|
||||
array('first' => t('firstname'), 'last' => t('lastname')), t('Submit'));
|
||||
$this->drupalPost('examples/form_example/tutorial/4', array(), t('Submit'));
|
||||
$this->assertText(t('First name field is required'));
|
||||
$this->assertText(t('Last name field is required'));
|
||||
|
||||
// #5
|
||||
$this->drupalPost('examples/form_example/tutorial/5',
|
||||
array('first' => t('firstname'), 'last' => t('lastname')), t('Submit'));
|
||||
$this->assertText(t('Please enter your first name'));
|
||||
$this->drupalPost('examples/form_example/tutorial/4', array(), t('Submit'));
|
||||
$this->assertText(t('First name field is required'));
|
||||
$this->assertText(t('Last name field is required'));
|
||||
|
||||
// #6
|
||||
$this->drupalPost(
|
||||
'examples/form_example/tutorial/6',
|
||||
array(
|
||||
'first' => t('firstname'),
|
||||
'last' => t('lastname'),
|
||||
'year_of_birth' => 1955,
|
||||
),
|
||||
t('Submit'));
|
||||
$this->assertNoText(t('Enter a year between 1900 and 2000'));
|
||||
$this->drupalPost(
|
||||
'examples/form_example/tutorial/6',
|
||||
array(
|
||||
'first' => t('firstname'),
|
||||
'last' => t('lastname'),
|
||||
'year_of_birth' => 1855,
|
||||
),
|
||||
t('Submit')
|
||||
);
|
||||
|
||||
$this->assertText(t('Enter a year between 1900 and 2000'));
|
||||
|
||||
// #7
|
||||
$this->drupalPost(
|
||||
'examples/form_example/tutorial/7',
|
||||
array(
|
||||
'first' => t('firstname'),
|
||||
'last' => t('lastname'),
|
||||
'year_of_birth' => 1955,
|
||||
),
|
||||
t('Submit')
|
||||
);
|
||||
$this->assertText(t('The form has been submitted. name="firstname lastname", year of birth=1955'));
|
||||
$this->drupalPost(
|
||||
'examples/form_example/tutorial/7',
|
||||
array(
|
||||
'first' => t('firstname'),
|
||||
'last' => t('lastname'),
|
||||
'year_of_birth' => 1855,
|
||||
),
|
||||
t('Submit')
|
||||
);
|
||||
|
||||
$this->assertText(t('Enter a year between 1900 and 2000'));
|
||||
|
||||
// Test tutorial #8.
|
||||
$this->drupalPost(
|
||||
'examples/form_example/tutorial/8',
|
||||
array(
|
||||
'first' => t('firstname'),
|
||||
'last' => t('lastname'),
|
||||
'year_of_birth' => 1955,
|
||||
),
|
||||
t('Next >>')
|
||||
);
|
||||
|
||||
$this->drupalPost(NULL, array('color' => t('green')), t('<< Back'));
|
||||
$this->drupalPost(NULL, array(), t('Next >>'));
|
||||
$this->drupalPost(NULL, array('color' => t('red')), t('Submit'));
|
||||
$this->assertText(t('The form has been submitted. name="firstname lastname", year of birth=1955'));
|
||||
$this->assertText(t('And the favorite color is red'));
|
||||
|
||||
// #9
|
||||
$url = 'examples/form_example/tutorial/9';
|
||||
for ($i = 1; $i <= 4; $i++) {
|
||||
if ($i > 1) {
|
||||
// Later steps of multistep form take NULL.
|
||||
$url = NULL;
|
||||
}
|
||||
$this->drupalPost(
|
||||
$url,
|
||||
array(
|
||||
"name[$i][first]" => "firstname $i",
|
||||
"name[$i][last]" => "lastname $i",
|
||||
"name[$i][year_of_birth]" => 1950 + $i,
|
||||
),
|
||||
t('Add another name')
|
||||
);
|
||||
$this->assertText(t('Name #@num', array('@num' => $i + 1)));
|
||||
}
|
||||
|
||||
// Now remove the last name added (#5).
|
||||
$this->drupalPost(NULL, array(), t('Remove latest name'));
|
||||
$this->assertNoText("Name #5");
|
||||
|
||||
$this->drupalPost(NULL, array(), t('Submit'));
|
||||
|
||||
$this->assertText('Form 9 has been submitted');
|
||||
for ($i = 1; $i <= 4; $i++) {
|
||||
$this->assertText(t('@num: firstname @num lastname @num (@year)', array('@num' => $i, '@year' => 1950 + $i)));
|
||||
}
|
||||
|
||||
// #10
|
||||
$url = 'examples/form_example/tutorial/10';
|
||||
|
||||
$this->drupalPost($url, array(), t('Submit'));
|
||||
$this->assertText(t('No file was uploaded.'));
|
||||
|
||||
// Get sample images.
|
||||
$images = $this->drupalGetTestFiles('image');
|
||||
foreach ($images as $image) {
|
||||
$this->drupalPost($url, array('files[file]' => drupal_realpath($image->uri)), t('Submit'));
|
||||
$this->assertText(t('The form has been submitted and the image has been saved, filename: @filename.', array('@filename' => $image->filename)));
|
||||
}
|
||||
|
||||
// #11: Confirmation form.
|
||||
// Try to submit without a name.
|
||||
$url = 'examples/form_example/tutorial/11';
|
||||
$this->drupalPost($url, array(), t('Submit'));
|
||||
$this->assertText('Name field is required.');
|
||||
|
||||
// Verify that we can enter a name and get the confirmation form.
|
||||
$this->drupalPost(
|
||||
$url,
|
||||
array('name' => t('name 1')), t('Submit')
|
||||
);
|
||||
$this->assertText(t('Is this really your name?'));
|
||||
$this->assertFieldById('edit-name', 'name 1');
|
||||
|
||||
// Check the 'yes' button.
|
||||
$confirmation_text = t("Confirmation form submission recieved. According to your submission your name is '@name'", array('@name' => 'name 1'));
|
||||
$url = 'examples/form_example/tutorial/11/confirm/name%201';
|
||||
$this->drupalPost($url, array(), t('This is my name'));
|
||||
$this->assertText($confirmation_text);
|
||||
|
||||
// Check the 'no' button.
|
||||
$this->drupalGet($url);
|
||||
$this->clickLink(t('Nope, not my name'));
|
||||
$this->assertNoText($confirmation_text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Wizard tutorial.
|
||||
*
|
||||
* @TODO improve this using drupal_form_submit
|
||||
*/
|
||||
public function testWizard() {
|
||||
// Check if the wizard is there.
|
||||
$this->drupalGet('examples/form_example/wizard');
|
||||
$this->assertText(t('Extensible wizard example'));
|
||||
|
||||
$first_name = $this->randomName(8);
|
||||
$last_name = $this->randomName(8);
|
||||
$city = $this->randomName(8);
|
||||
$aunts_name = $this->randomName(8);
|
||||
|
||||
// Submit the first step of the wizard.
|
||||
$options = array(
|
||||
'first_name' => $first_name,
|
||||
'last_name' => $last_name,
|
||||
);
|
||||
$this->drupalPost('examples/form_example/wizard', $options, t('Next'));
|
||||
|
||||
// A label city is created, and two buttons appear, Previous and Next.
|
||||
$this->assertText(t('Hint: Do not enter "San Francisco", and do not leave this out.'));
|
||||
|
||||
// Go back to the beginning and verify that the value is there.
|
||||
$this->drupalPost(NULL, array(), t('Previous'));
|
||||
$this->assertFieldByName('first_name', $first_name);
|
||||
$this->assertFieldByName('last_name', $last_name);
|
||||
|
||||
// Go next. We should keep our values.
|
||||
$this->drupalPost(NULL, array(), t('Next'));
|
||||
$this->assertText(t('Hint: Do not enter "San Francisco", and do not leave this out.'));
|
||||
|
||||
// Try "San Francisco".
|
||||
$this->drupalPost(NULL, array('city' => 'San Francisco'), t('Next'));
|
||||
$this->assertText(t('You were warned not to enter "San Francisco"'));
|
||||
|
||||
// Try the real city.
|
||||
$this->drupalPost(NULL, array('city' => $city), t('Next'));
|
||||
|
||||
// Enter the Aunt's name, but then the previous button.
|
||||
$this->drupalPost(NULL, array('aunts_name' => $aunts_name), t('Previous'));
|
||||
$this->assertFieldByName('city', $city);
|
||||
|
||||
// Go to first step and re-check all fields.
|
||||
$this->drupalPost(NULL, array(), t('Previous'));
|
||||
$this->assertFieldByName('first_name', $first_name);
|
||||
$this->assertFieldByName('last_name', $last_name);
|
||||
|
||||
// Re-check second step.
|
||||
$this->drupalPost(NULL, array(), t('Next'));
|
||||
$this->assertText(t('Hint: Do not enter "San Francisco", and do not leave this out.'));
|
||||
$this->assertFieldByName('city', $city);
|
||||
|
||||
// Re-check third step.
|
||||
$this->drupalPost(NULL, array(), t('Next'));
|
||||
$this->assertFieldByName('aunts_name', $aunts_name);
|
||||
|
||||
// Press finish and check for correct values.
|
||||
$this->drupalPost(NULL, array(), t('Finish'));
|
||||
|
||||
$this->assertRaw(t('[first_name] => @first_name', array('@first_name' => $first_name)));
|
||||
$this->assertRaw(t('[last_name] => @last_name', array('@last_name' => $last_name)));
|
||||
$this->assertRaw(t('[city] => @city', array('@city' => $city)));
|
||||
$this->assertRaw(t('[aunts_name] => @aunts_name', array('@aunts_name' => $aunts_name)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test the element_example form for correct behavior.
|
||||
*/
|
||||
public function testElementExample() {
|
||||
// Make one basic POST with a set of values and check for correct responses.
|
||||
$edit = array(
|
||||
'a_form_example_textfield' => $this->randomName(),
|
||||
'a_form_example_checkbox' => TRUE,
|
||||
'a_form_example_element_discrete[areacode]' => sprintf('%03d', rand(0, 999)),
|
||||
'a_form_example_element_discrete[prefix]' => sprintf('%03d', rand(0, 999)),
|
||||
'a_form_example_element_discrete[extension]' => sprintf('%04d', rand(0, 9999)),
|
||||
'a_form_example_element_combined[areacode]' => sprintf('%03d', rand(0, 999)),
|
||||
'a_form_example_element_combined[prefix]' => sprintf('%03d', rand(0, 999)),
|
||||
'a_form_example_element_combined[extension]' => sprintf('%04d', rand(0, 9999)),
|
||||
);
|
||||
$this->drupalPost('examples/form_example/element_example', $edit, t('Submit'));
|
||||
$this->assertText(t('a_form_example_textfield has value @value', array('@value' => $edit['a_form_example_textfield'])));
|
||||
$this->assertText(t('a_form_example_checkbox has value 1'));
|
||||
$this->assertPattern(t('/areacode.*!areacode/', array('!areacode' => $edit['a_form_example_element_discrete[areacode]'])));
|
||||
$this->assertPattern(t('/prefix.*!prefix/', array('!prefix' => $edit['a_form_example_element_discrete[prefix]'])));
|
||||
$this->assertPattern(t('/extension.*!extension/', array('!extension' => $edit['a_form_example_element_discrete[extension]'])));
|
||||
|
||||
$this->assertText(t('a_form_example_element_combined has value @value', array('@value' => $edit['a_form_example_element_combined[areacode]'] . $edit['a_form_example_element_combined[prefix]'] . $edit['a_form_example_element_combined[extension]'])));
|
||||
|
||||
// Now flip the checkbox and check for correct behavior.
|
||||
$edit['a_form_example_checkbox'] = FALSE;
|
||||
$this->drupalPost('examples/form_example/element_example', $edit, t('Submit'));
|
||||
$this->assertText(t('a_form_example_checkbox has value 0'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,531 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This is an example demonstrating how a module can define custom form and
|
||||
* render elements.
|
||||
*
|
||||
* Form elements are already familiar to anyone who uses Form API. They share
|
||||
* history with render elements, which are explained in the
|
||||
* @link render_example.module Render Example @endlink. Examples
|
||||
* of core form elements are 'textfield', 'checkbox' and 'fieldset'. Drupal
|
||||
* utilizes hook_elements() to define these FAPI types, and this occurs in
|
||||
* the core function system_elements().
|
||||
*
|
||||
* Each form element has a #type value that determines how it is treated by
|
||||
* the Form API and how it is ultimately rendered into HTML.
|
||||
* hook_element_info() allows modules to define new element types, and tells
|
||||
* the Form API what default values they should automatically be populated with.
|
||||
*
|
||||
* By implementing hook_element_info() in your own module, you can create custom
|
||||
* form (or render) elements with their own properties, validation and theming.
|
||||
*
|
||||
* In this example, we define a series of elements that range from trivial
|
||||
* (a renamed textfield) to more advanced (a telephone number field with each
|
||||
* portion separately validated).
|
||||
*
|
||||
* Since each element can use arbitrary properties (like #process or #dropthis)
|
||||
* it can be quite complicated to figure out what all the properties actually
|
||||
* mean. This example won't undertake the exhaustive task of explaining them
|
||||
* all, as that would probably be impossible.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @todo: Some additional magic things to explain:
|
||||
* - #process and process callback (and naming) (in forms)
|
||||
* - #value and value callback (and naming of the above)
|
||||
* - #theme and #theme_wrappers
|
||||
* - What is #return_value?
|
||||
* - system module provides the standard default elements.
|
||||
* - What are all the things that can be defined in hook_element_info() and
|
||||
* where do the defaults come from?
|
||||
* - Form elements that have a type that has a matching type in the element
|
||||
* array created by hook_element_info() get those items merged with them.
|
||||
* - #value_callback is called first by form_builder(). Its job is to figure
|
||||
* out what the actual value of the element, using #default_value or whatever.
|
||||
* - #process is then called to allow changes to the whole element (like adding
|
||||
* child form elements.)
|
||||
* - #return_value: chx: you need three different values for form API. You need
|
||||
* the default value (#default_value), the value for the element if it gets
|
||||
* checked )#return_value) and then #value which is either 0 or the
|
||||
* #return_value
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility function providing data for form_example_element_info().
|
||||
*
|
||||
* This defines several new form element types.
|
||||
*
|
||||
* - form_example_textfield: This is actually just a textfield, but provides
|
||||
* the new type. If more were to be done with it a theme function could be
|
||||
* provided.
|
||||
* - form_example_checkbox: Nothing more than a regular checkbox, but uses
|
||||
* an alternate theme function provided by this module.
|
||||
* - form_example_phonenumber_discrete: Provides a North-American style
|
||||
* three-part phonenumber where the value of the phonenumber is managed
|
||||
* as an array of three parts.
|
||||
* - form_example_phonenumber_combined: Provides a North-American style
|
||||
* three-part phonenumber where the actual value is managed as a 10-digit
|
||||
* string and only broken up into three parts for the user interface.
|
||||
*
|
||||
* form_builder() has significant discussion of #process and #value_callback.
|
||||
* See also hook_element_info().
|
||||
*
|
||||
* system_element_info() contains the Drupal default element types, which can
|
||||
* also be used as examples.
|
||||
*/
|
||||
function _form_example_element_info() {
|
||||
// form_example_textfield is a trivial element based on textfield that
|
||||
// requires only a definition and a theme function. In this case we provide
|
||||
// the theme function using the parent "textfield" theme function, but it
|
||||
// would by default be provided in hook_theme(), by a "form_example_textfield"
|
||||
// theme implementation, provided by default by the function
|
||||
// theme_form_example_textfield(). Note that the 'form_example_textfield'
|
||||
// element type is completely defined here. There is no further code required
|
||||
// for it.
|
||||
$types['form_example_textfield'] = array(
|
||||
// #input = TRUE means that the incoming value will be used to figure out
|
||||
// what #value will be.
|
||||
'#input' => TRUE,
|
||||
|
||||
// Use theme('textfield') to format this element on output.
|
||||
'#theme' => array('textfield'),
|
||||
|
||||
// Do not provide autocomplete.
|
||||
'#autocomplete_path' => FALSE,
|
||||
|
||||
// Allow theme('form_element') to control the markup surrounding this
|
||||
// value on output.
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
);
|
||||
|
||||
// form_example_checkbox is mostly a copy of the system-defined checkbox
|
||||
// element.
|
||||
$types['form_example_checkbox'] = array(
|
||||
// This is an HTML <input>.
|
||||
'#input' => TRUE,
|
||||
|
||||
// @todo: Explain #return_value.
|
||||
'#return_value' => TRUE,
|
||||
|
||||
// Our #process array will use the standard process functions used for a
|
||||
// regular checkbox.
|
||||
'#process' => array('form_process_checkbox', 'ajax_process_form'),
|
||||
|
||||
// Use theme('form_example_checkbox') to render this element on output.
|
||||
'#theme' => 'form_example_checkbox',
|
||||
|
||||
// Use theme('form_element') to provide HTML wrappers for this element.
|
||||
'#theme_wrappers' => array('form_element'),
|
||||
|
||||
// Place the title after the element (to the right of the checkbox).
|
||||
// This attribute affects the behavior of theme_form_element().
|
||||
'#title_display' => 'after',
|
||||
|
||||
// We use the default function name for the value callback, so it does not
|
||||
// have to be listed explicitly. The pattern for the default function name
|
||||
// is form_type_TYPENAME_value().
|
||||
// '#value_callback' => 'form_type_form_example_checkbox_value',
|
||||
);
|
||||
|
||||
// This discrete phonenumber element keeps its values as the separate elements
|
||||
// area code, prefix, extension.
|
||||
$types['form_example_phonenumber_discrete'] = array(
|
||||
// #input == TRUE means that the form value here will be used to determine
|
||||
// what #value will be.
|
||||
'#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. These are in addition to any
|
||||
// validation handlers that might.
|
||||
'#element_validate' => array('form_example_phonenumber_discrete_validate'),
|
||||
'#autocomplete_path' => FALSE,
|
||||
'#theme_wrappers' => array('form_example_inline_form_element'),
|
||||
);
|
||||
|
||||
// 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,
|
||||
'#value_callback' => 'form_example_phonenumber_combined_value',
|
||||
'#default_value' => array(
|
||||
'areacode' => '',
|
||||
'prefix' => '',
|
||||
'extension' => '',
|
||||
),
|
||||
'#theme_wrappers' => array('form_example_inline_form_element'),
|
||||
);
|
||||
return $types;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Value callback for form_example_phonenumber_combined.
|
||||
*
|
||||
* Builds the current combined value of the phone number only when the form
|
||||
* builder is not processing the input.
|
||||
*
|
||||
* @param array $element
|
||||
* Form element.
|
||||
* @param array $input
|
||||
* Input.
|
||||
* @param array $form_state
|
||||
* Form state.
|
||||
*
|
||||
* @return array
|
||||
* The modified element.
|
||||
*/
|
||||
function form_example_phonenumber_combined_value(&$element, $input = FALSE, $form_state = NULL) {
|
||||
if (!$form_state['process_input']) {
|
||||
$matches = array();
|
||||
$match = preg_match('/^(\d{3})(\d{3})(\d{4})$/', $element['#default_value'], $matches);
|
||||
if ($match) {
|
||||
// Get rid of the "all match" element.
|
||||
array_shift($matches);
|
||||
list($element['areacode'], $element['prefix'], $element['extension']) = $matches;
|
||||
}
|
||||
}
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value callback for form_example_checkbox element type.
|
||||
*
|
||||
* Copied from form_type_checkbox_value().
|
||||
*
|
||||
* @param array $element
|
||||
* The form element whose value is being populated.
|
||||
* @param mixed $input
|
||||
* The incoming input to populate the form element. If this is FALSE, meaning
|
||||
* there is no input, the element's default value should be returned.
|
||||
*
|
||||
* @return int
|
||||
* The value represented by the form element.
|
||||
*/
|
||||
function form_type_form_example_checkbox_value($element, $input = FALSE) {
|
||||
if ($input === FALSE) {
|
||||
return isset($element['#default_value']) ? $element['#default_value'] : 0;
|
||||
}
|
||||
else {
|
||||
return isset($input) ? $element['#return_value'] : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process callback for the discrete version of phonenumber.
|
||||
*/
|
||||
function form_example_phonenumber_discrete_process($element, &$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']['<element_name>']['areacode'],
|
||||
// $form_state['values']['<element_name>']['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.
|
||||
*
|
||||
* Uses regular expressions to 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, &$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']['<element_name>']['areacode'],
|
||||
// $form_state['values']['<element_name>']['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) {
|
||||
// Get rid of the "all match" element.
|
||||
array_shift($matches);
|
||||
list($element['areacode']['#default_value'], $element['prefix']['#default_value'], $element['extension']['#default_value']) = $matches;
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Phone number validation function for the combined phonenumber.
|
||||
*
|
||||
* Uses regular expressions to 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['areacode']['#value'] . $element['prefix']['#value'] . $element['extension']['#value'];
|
||||
form_set_value($element, $value, $form_state);
|
||||
return $element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by form_example_theme() to provide hook_theme().
|
||||
*
|
||||
* This is kept in this file so it can be with the theme functions it presents.
|
||||
* Otherwise it would get lonely.
|
||||
*/
|
||||
function _form_example_element_theme() {
|
||||
return array(
|
||||
'form_example_inline_form_element' => array(
|
||||
'render element' => 'element',
|
||||
'file' => 'form_example_elements.inc',
|
||||
),
|
||||
'form_example_checkbox' => array(
|
||||
'render element' => 'element',
|
||||
'file' => 'form_example_elements.inc',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Themes a custom checkbox.
|
||||
*
|
||||
* This doesn't actually do anything, but is here to show that theming can
|
||||
* be done here.
|
||||
*/
|
||||
function theme_form_example_checkbox($variables) {
|
||||
$element = $variables['element'];
|
||||
return theme('checkbox', $element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats child form elements as inline elements.
|
||||
*/
|
||||
function theme_form_example_inline_form_element($variables) {
|
||||
$element = $variables['element'];
|
||||
|
||||
// Add element #id for #type 'item'.
|
||||
if (isset($element['#markup']) && !empty($element['#id'])) {
|
||||
$attributes['id'] = $element['#id'];
|
||||
}
|
||||
// Add element's #type and #name as class to aid with JS/CSS selectors.
|
||||
$attributes['class'] = array('form-item');
|
||||
if (!empty($element['#type'])) {
|
||||
$attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
|
||||
}
|
||||
if (!empty($element['#name'])) {
|
||||
$attributes['class'][] = 'form-item-' . strtr($element['#name'],
|
||||
array(
|
||||
' ' => '-',
|
||||
'_' => '-',
|
||||
'[' => '-',
|
||||
']' => '',
|
||||
)
|
||||
);
|
||||
}
|
||||
// Add a class for disabled elements to facilitate cross-browser styling.
|
||||
if (!empty($element['#attributes']['disabled'])) {
|
||||
$attributes['class'][] = 'form-disabled';
|
||||
}
|
||||
$output = '<div' . drupal_attributes($attributes) . '>' . "\n";
|
||||
|
||||
// If #title is not set, we don't display any label or required marker.
|
||||
if (!isset($element['#title'])) {
|
||||
$element['#title_display'] = 'none';
|
||||
}
|
||||
$prefix = isset($element['#field_prefix']) ? '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ' : '';
|
||||
$suffix = isset($element['#field_suffix']) ? ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>' : '';
|
||||
|
||||
switch ($element['#title_display']) {
|
||||
case 'before':
|
||||
$output .= ' ' . theme('form_element_label', $variables);
|
||||
$output .= ' ' . '<div class="container-inline">' . $prefix . $element['#children'] . $suffix . "</div>\n";
|
||||
break;
|
||||
|
||||
case 'invisible':
|
||||
case 'after':
|
||||
$output .= ' ' . $prefix . $element['#children'] . $suffix;
|
||||
$output .= ' ' . theme('form_element_label', $variables) . "\n";
|
||||
break;
|
||||
|
||||
case 'none':
|
||||
case 'attribute':
|
||||
// Output no label and no required marker, only the children.
|
||||
$output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($element['#description'])) {
|
||||
$output .= ' <div class="description">' . $element['#description'] . "</div>\n";
|
||||
}
|
||||
|
||||
$output .= "</div>\n";
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Form content for examples/form_example/element_example.
|
||||
*
|
||||
* Simple form to demonstrate how to use the various new FAPI elements
|
||||
* we've defined.
|
||||
*/
|
||||
function form_example_element_demo_form($form, &$form_state) {
|
||||
$form['a_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['a_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['a_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' => '999',
|
||||
'prefix' => '999',
|
||||
'extension' => '9999',
|
||||
)
|
||||
),
|
||||
'#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['a_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),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
296
sites/all/modules/examples/form_example/form_example_states.inc
Normal file
296
sites/all/modules/examples/form_example/form_example_states.inc
Normal file
@@ -0,0 +1,296 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* An example of how to use the new #states Form API element, allowing
|
||||
* dynamic form behavior with very simple setup.
|
||||
*/
|
||||
|
||||
/**
|
||||
* States demo form.
|
||||
*
|
||||
* This form shows off the #states system by dynamically showing parts of the
|
||||
* form based on the state of other parts.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*
|
||||
* The basic idea is that you add a #states property to the element which is
|
||||
* to be changed based on some action elsewhere on the form. The #states
|
||||
* property lists a change which is to be made, and under what conditions
|
||||
* that change should be made.
|
||||
*
|
||||
* For example, in the 'tests_taken' form element below we have:
|
||||
* @code
|
||||
* '#states' => array(
|
||||
* 'visible' => array(
|
||||
* ':input[name="student_type"]' => array('value' => 'high_school'),
|
||||
* ),
|
||||
* ),
|
||||
* @endcode
|
||||
* Meaning that the element is to be made visible when the condition is met.
|
||||
* The condition is a combination of a jQuery selector (which selects the
|
||||
* element we want to test) and a condition for that element. In this case,
|
||||
* the condition is whether the return value of the 'student_type' element is
|
||||
* 'high_school'. If it is, this element will be visible.
|
||||
*
|
||||
* So the syntax is:
|
||||
* @code
|
||||
* '#states' => array(
|
||||
* 'action_to_take_on_this_form_element' => array(
|
||||
* 'jquery_selector_for_another_element' => array(
|
||||
* 'condition_type' => value,
|
||||
* ),
|
||||
* ),
|
||||
* ),
|
||||
* @endcode
|
||||
*
|
||||
* If you need an action to take place only when two different conditions are
|
||||
* true, then you add both of those conditions to the action. See the
|
||||
* 'country_writein' element below for an example.
|
||||
*
|
||||
* Note that the easiest way to select a textfield, checkbox, or select is with
|
||||
* the
|
||||
* @link http://api.jquery.com/input-selector/ ':input' jquery shortcut @endlink,
|
||||
* which selects any any of those.
|
||||
*
|
||||
* There are examples below of changing or hiding an element when a checkbox
|
||||
* is checked, when a textarea is filled, when a select has a given value.
|
||||
*
|
||||
* See drupal_process_states() for full documentation.
|
||||
*
|
||||
* @see forms_api_reference.html
|
||||
*/
|
||||
function form_example_states_form($form, &$form_state) {
|
||||
$form['student_type'] = array(
|
||||
'#type' => 'radios',
|
||||
'#options' => array(
|
||||
'high_school' => t('High School'),
|
||||
'undergraduate' => t('Undergraduate'),
|
||||
'graduate' => t('Graduate'),
|
||||
),
|
||||
'#title' => t('What type of student are you?'),
|
||||
);
|
||||
$form['high_school'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('High School Information'),
|
||||
// This #states rule says that the "high school" fieldset should only
|
||||
// be shown if the "student_type" form element is set to "High School".
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="student_type"]' => array('value' => 'high_school'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// High school information.
|
||||
$form['high_school']['tests_taken'] = array(
|
||||
'#type' => 'checkboxes',
|
||||
'#options' => drupal_map_assoc(array(t('SAT'), t('ACT'))),
|
||||
'#title' => t('What standardized tests did you take?'),
|
||||
// This #states rule says that this checkboxes array will be visible only
|
||||
// when $form['student_type'] is set to t('High School').
|
||||
// It uses the jQuery selector :input[name=student_type] to choose the
|
||||
// element which triggers the behavior, and then defines the "High School"
|
||||
// value as the one that triggers visibility.
|
||||
'#states' => array(
|
||||
// Action to take.
|
||||
'visible' => array(
|
||||
':input[name="student_type"]' => array('value' => 'high_school'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['high_school']['sat_score'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your SAT score:'),
|
||||
'#size' => 4,
|
||||
|
||||
// This #states rule limits visibility to when the $form['tests_taken']
|
||||
// 'SAT' checkbox is checked."
|
||||
'#states' => array(
|
||||
// Action to take.
|
||||
'visible' => array(
|
||||
':input[name="tests_taken[SAT]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['high_school']['act_score'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your ACT score:'),
|
||||
'#size' => 4,
|
||||
|
||||
// Set this element visible if the ACT checkbox above is checked.
|
||||
'#states' => array(
|
||||
// Action to take.
|
||||
'visible' => array(
|
||||
':input[name="tests_taken[ACT]"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Undergrad information.
|
||||
$form['undergraduate'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Undergraduate Information'),
|
||||
// This #states rule says that the "undergraduate" fieldset should only
|
||||
// be shown if the "student_type" form element is set to "Undergraduate".
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="student_type"]' => array('value' => 'undergraduate'),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['undergraduate']['how_many_years'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('How many years have you completed?'),
|
||||
// The options here are integers, but since all the action here happens
|
||||
// using the DOM on the client, we will have to use strings to work with
|
||||
// them.
|
||||
'#options' => array(
|
||||
1 => t('One'),
|
||||
2 => t('Two'),
|
||||
3 => t('Three'),
|
||||
4 => t('Four'),
|
||||
5 => t('Lots'),
|
||||
),
|
||||
);
|
||||
|
||||
$form['undergraduate']['comment'] = array(
|
||||
'#type' => 'item',
|
||||
'#description' => t("Wow, that's a long time."),
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
// Note that '5' must be used here instead of the integer 5.
|
||||
// The information is coming from the DOM as a string.
|
||||
':input[name="how_many_years"]' => array('value' => '5'),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['undergraduate']['school_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your college or university:'),
|
||||
);
|
||||
$form['undergraduate']['school_country'] = array(
|
||||
'#type' => 'select',
|
||||
'#options' => drupal_map_assoc(array(t('UK'), t('Other'))),
|
||||
'#title' => t('In what country is your college or university located?'),
|
||||
);
|
||||
$form['undergraduate']['country_writein'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#size' => 20,
|
||||
'#title' => t('Please enter the name of the country where your college or university is located.'),
|
||||
|
||||
// Only show this field if school_country is set to 'Other'.
|
||||
'#states' => array(
|
||||
// Action to take: Make visible.
|
||||
'visible' => array(
|
||||
':input[name="school_country"]' => array('value' => t('Other')),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['undergraduate']['thanks'] = array(
|
||||
'#type' => 'item',
|
||||
'#description' => t('Thanks for providing both your school and your country.'),
|
||||
'#states' => array(
|
||||
// Here visibility requires that two separate conditions be true.
|
||||
'visible' => array(
|
||||
':input[name="school_country"]' => array('value' => t('Other')),
|
||||
':input[name="country_writein"]' => array('filled' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['undergraduate']['go_away'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Done with form'),
|
||||
'#states' => array(
|
||||
// Here visibility requires that two separate conditions be true.
|
||||
'visible' => array(
|
||||
':input[name="school_country"]' => array('value' => t('Other')),
|
||||
':input[name="country_writein"]' => array('filled' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Graduate student information.
|
||||
$form['graduate'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Graduate School Information'),
|
||||
// This #states rule says that the "graduate" fieldset should only
|
||||
// be shown if the "student_type" form element is set to "Graduate".
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="student_type"]' => array('value' => 'graduate'),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['graduate']['more_info'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('Please describe your graduate studies'),
|
||||
);
|
||||
|
||||
$form['graduate']['info_provide'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Check here if you have provided information above'),
|
||||
'#disabled' => TRUE,
|
||||
'#states' => array(
|
||||
// Mark this checkbox checked if the "more_info" textarea has something
|
||||
// in it, if it's 'filled'.
|
||||
'checked' => array(
|
||||
':input[name="more_info"]' => array('filled' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['average'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Enter your average'),
|
||||
// To trigger a state when the same controlling element can have more than
|
||||
// one possible value, put all values in a higher-level array.
|
||||
'#states' => array(
|
||||
'visible' => array(
|
||||
':input[name="student_type"]' => array(
|
||||
array('value' => 'high_school'),
|
||||
array('value' => 'undergraduate'),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$form['expand_more_info'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('Check here if you want to add more information.'),
|
||||
);
|
||||
$form['more_info'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Additional Information'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => TRUE,
|
||||
|
||||
// Expand the expand_more_info fieldset if the box is checked.
|
||||
'#states' => array(
|
||||
'expanded' => array(
|
||||
':input[name="expand_more_info"]' => array('checked' => TRUE),
|
||||
),
|
||||
),
|
||||
);
|
||||
$form['more_info']['feedback'] = array(
|
||||
'#type' => 'textarea',
|
||||
'#title' => t('What do you have to say?'),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit your information'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for form_example_states_form().
|
||||
*/
|
||||
function form_example_states_form_submit($form, &$form_state) {
|
||||
drupal_set_message(t('Submitting values: @values', array('@values' => var_export($form_state['values'], TRUE))));
|
||||
}
|
||||
@@ -0,0 +1,934 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This is the Form API Tutorial from the handbook.
|
||||
*
|
||||
* It goes through several form examples of increasing complexity to demonstrate
|
||||
* Drupal 7 Form API.
|
||||
*
|
||||
* Links are provided inline for the related handbook pages.
|
||||
*
|
||||
* @see http://drupal.org/node/262422
|
||||
*/
|
||||
|
||||
/**
|
||||
* Main Form tutorial page.
|
||||
*
|
||||
* @see form_example_tutorial_1()
|
||||
* @see form_example_tutorial_2()
|
||||
* @see form_example_tutorial_3()
|
||||
* @see form_example_tutorial_4()
|
||||
* @see form_example_tutorial_5()
|
||||
* @see form_example_tutorial_6()
|
||||
* @see form_example_tutorial_7()
|
||||
* @see form_example_tutorial_8()
|
||||
* @see form_example_tutorial_9()
|
||||
* @see form_example_tutorial_10()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial() {
|
||||
return t('This is a set of form tutorials tied to the <a href="http://drupal.org/node/262422">Drupal handbook</a>.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tutorial Example 1.
|
||||
*
|
||||
* This first form function is from the
|
||||
* @link http://drupal.org/node/717722 Form Tutorial handbook page @endlink
|
||||
*
|
||||
* It just creates a very basic form with a textfield.
|
||||
*
|
||||
* This function is called the "form constructor function". It builds the form.
|
||||
* It takes a two arguments, $form and $form_state, but if drupal_get_form()
|
||||
* sends additional arguments, they will be provided after $form_state.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_1($form, &$form_state) {
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with nothing but a textfield'),
|
||||
);
|
||||
// This is the first form element. It's a textfield with a label, "Name"
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is Example 2, a basic form with a submit button.
|
||||
*
|
||||
* @see http://drupal.org/node/717726
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_2($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A simple form with a submit button'),
|
||||
);
|
||||
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
);
|
||||
|
||||
// Adds a simple submit button that refreshes the form and clears its
|
||||
// contents. This is the default behavior for forms.
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 3: A basic form with fieldsets.
|
||||
*
|
||||
* We establish a fieldset element and then place two text fields within
|
||||
* it, one for a first name and one for a last name. This helps us group
|
||||
* related content.
|
||||
*
|
||||
* Study the code below and you'll notice that we renamed the array of the first
|
||||
* and last name fields by placing them under the $form['name']
|
||||
* array. This tells Form API these fields belong to the $form['name'] fieldset.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_3($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with a fieldset'),
|
||||
);
|
||||
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name'),
|
||||
);
|
||||
$form['name']['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
);
|
||||
$form['name']['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 4: Basic form with required fields.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_4($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with required fields'),
|
||||
);
|
||||
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name'),
|
||||
// Make the fieldset collapsible.
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
// Make these fields required.
|
||||
$form['name']['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['name']['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 5: Basic form with additional element attributes.
|
||||
*
|
||||
* This demonstrates additional attributes of text form fields.
|
||||
*
|
||||
* See the
|
||||
* @link http://api.drupal.org/api/file/developer/topics/forms_api.html complete form reference @endlink
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_5($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with additional attributes'),
|
||||
'#description' => t('This one adds #default_value and #description'),
|
||||
);
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
$form['name']['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => "First name",
|
||||
'#description' => "Please enter your first name.",
|
||||
'#size' => 20,
|
||||
'#maxlength' => 20,
|
||||
);
|
||||
$form['name']['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 6: A basic form with a validate handler.
|
||||
*
|
||||
* From http://drupal.org/node/717736
|
||||
* @see form_example_tutorial_6_validate()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_6($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with a validation handler'),
|
||||
);
|
||||
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
$form['name']['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => "First name",
|
||||
'#description' => "Please enter your first name.",
|
||||
'#size' => 20,
|
||||
'#maxlength' => 20,
|
||||
);
|
||||
$form['name']['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
// New form field added to permit entry of year of birth.
|
||||
// The data entered into this field will be validated with
|
||||
// the default validation function.
|
||||
$form['year_of_birth'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => "Year of birth",
|
||||
'#description' => 'Format is "YYYY"',
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation handler for Tutorial 6.
|
||||
*
|
||||
* Now we add a handler/function to validate the data entered into the
|
||||
* "year of birth" field to make sure it's between the values of 1900
|
||||
* and 2000. If not, it displays an error. The value report is
|
||||
* $form_state['values'] (see http://drupal.org/node/144132#form-state).
|
||||
*
|
||||
* Notice the name of the function. It is simply the name of the form
|
||||
* followed by '_validate'. This is always the name of the default validation
|
||||
* function. An alternate list of validation functions could have been provided
|
||||
* in $form['#validate'].
|
||||
*
|
||||
* @see form_example_tutorial_6()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_6_validate($form, &$form_state) {
|
||||
$year_of_birth = $form_state['values']['year_of_birth'];
|
||||
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
|
||||
form_set_error('year_of_birth', t('Enter a year between 1900 and 2000.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 7: With a submit handler.
|
||||
*
|
||||
* From the handbook page:
|
||||
* http://drupal.org/node/717740
|
||||
*
|
||||
* @see form_example_tutorial_7_validate()
|
||||
* @see form_example_tutorial_7_submit()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_7($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with a submit handler'),
|
||||
);
|
||||
$form['name'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name'),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
$form['name']['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => "First name",
|
||||
'#description' => "Please enter your first name.",
|
||||
'#size' => 20,
|
||||
'#maxlength' => 20,
|
||||
);
|
||||
$form['name']['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['year_of_birth'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => "Year of birth",
|
||||
'#description' => 'Format is "YYYY"',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validation function for form_example_tutorial_7().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_7_validate($form, &$form_state) {
|
||||
$year_of_birth = $form_state['values']['year_of_birth'];
|
||||
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
|
||||
form_set_error('year_of_birth', t('Enter a year between 1900 and 2000.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for form_example_tutorial_7().
|
||||
*
|
||||
* Adds a submit handler/function to our form to send a successful
|
||||
* completion message to the screen.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_7_submit($form, &$form_state) {
|
||||
drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
|
||||
array(
|
||||
'@first' => $form_state['values']['first'],
|
||||
'@last' => $form_state['values']['last'],
|
||||
'@year_of_birth' => $form_state['values']['year_of_birth'],
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 8: A simple multistep form with a Next and a Back button.
|
||||
*
|
||||
* Handbook page: http://drupal.org/node/717750.
|
||||
*
|
||||
* For more extensive multistep forms, see
|
||||
* @link form_example_wizard.inc form_example_wizard.inc @endlink
|
||||
*
|
||||
*
|
||||
* Adds logic to our form builder to give it two pages.
|
||||
* The @link ajax_example_wizard AJAX Example's Wizard Example @endlink
|
||||
* gives an AJAX version of this same idea.
|
||||
*
|
||||
* @see form_example_tutorial_8_page_two()
|
||||
* @see form_example_tutorial_8_page_two_back()
|
||||
* @see form_example_tutorial_8_page_two_submit()
|
||||
* @see form_example_tutorial_8_next_submit()
|
||||
* @see form_example_tutorial.inc
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8($form, &$form_state) {
|
||||
|
||||
// Display page 2 if $form_state['page_num'] == 2
|
||||
if (!empty($form_state['page_num']) && $form_state['page_num'] == 2) {
|
||||
return form_example_tutorial_8_page_two($form, $form_state);
|
||||
}
|
||||
|
||||
// Otherwise we build page 1.
|
||||
$form_state['page_num'] = 1;
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A basic multistep form (page 1)'),
|
||||
);
|
||||
|
||||
$form['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#description' => "Please enter your first name.",
|
||||
'#size' => 20,
|
||||
'#maxlength' => 20,
|
||||
'#required' => TRUE,
|
||||
'#default_value' => !empty($form_state['values']['first']) ? $form_state['values']['first'] : '',
|
||||
);
|
||||
$form['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last name'),
|
||||
'#default_value' => !empty($form_state['values']['last']) ? $form_state['values']['last'] : '',
|
||||
);
|
||||
$form['year_of_birth'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => "Year of birth",
|
||||
'#description' => 'Format is "YYYY"',
|
||||
'#default_value' => !empty($form_state['values']['year_of_birth']) ? $form_state['values']['year_of_birth'] : '',
|
||||
);
|
||||
$form['next'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Next >>',
|
||||
'#submit' => array('form_example_tutorial_8_next_submit'),
|
||||
'#validate' => array('form_example_tutorial_8_next_validate'),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the form for the second page of form_example_tutorial_8().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8_page_two($form, &$form_state) {
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A basic multistep form (page 2)'),
|
||||
);
|
||||
|
||||
$form['color'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Favorite color'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => !empty($form_state['values']['color']) ? $form_state['values']['color'] : '',
|
||||
);
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
'#submit' => array('form_example_tutorial_8_page_two_submit'),
|
||||
);
|
||||
$form['back'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('<< Back'),
|
||||
'#submit' => array('form_example_tutorial_8_page_two_back'),
|
||||
// We won't bother validating the required 'color' field, since they
|
||||
// have to come back to this page to submit anyway.
|
||||
'#limit_validation_errors' => array(),
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate handler for the next button on first page.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8_next_validate($form, &$form_state) {
|
||||
$year_of_birth = $form_state['values']['year_of_birth'];
|
||||
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
|
||||
form_set_error('year_of_birth', t('Enter a year between 1900 and 2000.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for form_example_tutorial_8() next button.
|
||||
*
|
||||
* Capture the values from page one and store them away so they can be used
|
||||
* at final submit time.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8_next_submit($form, &$form_state) {
|
||||
|
||||
// Values are saved for each page.
|
||||
// to carry forward to subsequent pages in the form.
|
||||
// and we tell FAPI to rebuild the form.
|
||||
$form_state['page_values'][1] = $form_state['values'];
|
||||
|
||||
if (!empty($form_state['page_values'][2])) {
|
||||
$form_state['values'] = $form_state['page_values'][2];
|
||||
}
|
||||
|
||||
// When form rebuilds, it will look at this to figure which page to build.
|
||||
$form_state['page_num'] = 2;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Back button handler submit handler.
|
||||
*
|
||||
* Since #limit_validation_errors = array() is set, values from page 2
|
||||
* will be discarded. We load the page 1 values instead.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8_page_two_back($form, &$form_state) {
|
||||
$form_state['values'] = $form_state['page_values'][1];
|
||||
$form_state['page_num'] = 1;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* The page 2 submit handler.
|
||||
*
|
||||
* This is the final submit handler. Gather all the data together and output
|
||||
* it in a drupal_set_message().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_8_page_two_submit($form, &$form_state) {
|
||||
// Normally, some code would go here to alter the database with the data
|
||||
// collected from the form. Instead sets a message with drupal_set_message()
|
||||
// to validate that the code worked.
|
||||
$page_one_values = $form_state['page_values'][1];
|
||||
drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
|
||||
array(
|
||||
'@first' => $page_one_values['first'],
|
||||
'@last' => $page_one_values['last'],
|
||||
'@year_of_birth' => $page_one_values['year_of_birth'],
|
||||
)
|
||||
));
|
||||
|
||||
if (!empty($page_one_values['first2'])) {
|
||||
drupal_set_message(t('Second name: name="@first @last", year of birth=@year_of_birth',
|
||||
array(
|
||||
'@first' => $page_one_values['first2'],
|
||||
'@last' => $page_one_values['last2'],
|
||||
'@year_of_birth' => $page_one_values['year_of_birth2'],
|
||||
)
|
||||
));
|
||||
}
|
||||
drupal_set_message(t('And the favorite color is @color', array('@color' => $form_state['values']['color'])));
|
||||
|
||||
// If we wanted to redirect on submission, set $form_state['redirect']. For
|
||||
// simple redirects, the value can be a string of the path to redirect to. For
|
||||
// example, to redirect to /node, one would specify the following:
|
||||
//
|
||||
// $form_state['redirect'] = 'node';
|
||||
//
|
||||
// For more complex redirects, this value can be set to an array of options to
|
||||
// pass to drupal_goto(). For example, to redirect to /foo?bar=1#baz, one
|
||||
// would specify the following:
|
||||
//
|
||||
// @code
|
||||
// $form_state['redirect'] = array(
|
||||
// 'foo',
|
||||
// array(
|
||||
// 'query' => array('bar' => 1),
|
||||
// 'fragment' => 'baz',
|
||||
// ),
|
||||
// );
|
||||
// @endcode
|
||||
//
|
||||
// The first element in the array is the path to redirect to, and the second
|
||||
// element in the array is the array of options. For more information on the
|
||||
// available options, see http://api.drupal.org/url.
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 9: A form with a dynamically added new fields.
|
||||
*
|
||||
* This example adds default values so that when the form is rebuilt,
|
||||
* the form will by default have the previously-entered values.
|
||||
*
|
||||
* From handbook page http://drupal.org/node/717746.
|
||||
*
|
||||
* @see form_example_tutorial_9_add_name()
|
||||
* @see form_example_tutorial_9_remove_name()
|
||||
* @see form_example_tutorial_9_submit()
|
||||
* @see form_example_tutorial_9_validate()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_9($form, &$form_state) {
|
||||
|
||||
// We will have many fields with the same name, so we need to be able to
|
||||
// access the form hierarchically.
|
||||
$form['#tree'] = TRUE;
|
||||
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A form with dynamically added new fields'),
|
||||
);
|
||||
|
||||
if (empty($form_state['num_names'])) {
|
||||
$form_state['num_names'] = 1;
|
||||
}
|
||||
|
||||
// Build the number of name fieldsets indicated by $form_state['num_names']
|
||||
for ($i = 1; $i <= $form_state['num_names']; $i++) {
|
||||
$form['name'][$i] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Name #@num', array('@num' => $i)),
|
||||
'#collapsible' => TRUE,
|
||||
'#collapsed' => FALSE,
|
||||
);
|
||||
|
||||
$form['name'][$i]['first'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First name'),
|
||||
'#description' => t("Enter first name."),
|
||||
'#size' => 20,
|
||||
'#maxlength' => 20,
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['name'][$i]['last'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Enter Last name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
$form['name'][$i]['year_of_birth'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t("Year of birth"),
|
||||
'#description' => t('Format is "YYYY"'),
|
||||
);
|
||||
}
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
|
||||
// Adds "Add another name" button.
|
||||
$form['add_name'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Add another name'),
|
||||
'#submit' => array('form_example_tutorial_9_add_name'),
|
||||
);
|
||||
|
||||
// If we have more than one name, this button allows removal of the
|
||||
// last name.
|
||||
if ($form_state['num_names'] > 1) {
|
||||
$form['remove_name'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Remove latest name'),
|
||||
'#submit' => array('form_example_tutorial_9_remove_name'),
|
||||
// Since we are removing a name, don't validate until later.
|
||||
'#limit_validation_errors' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for "Add another name" button on form_example_tutorial_9().
|
||||
*
|
||||
* $form_state['num_names'] tells the form builder function how many name
|
||||
* fieldsets to build, so here we increment it.
|
||||
*
|
||||
* All elements of $form_state are persisted, so there's no need to use a
|
||||
* particular key, like the old $form_state['storage']. We can just use
|
||||
* $form_state['num_names'].
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_9_add_name($form, &$form_state) {
|
||||
// Everything in $form_state is persistent, so we'll just use
|
||||
// $form_state['add_name']
|
||||
$form_state['num_names']++;
|
||||
|
||||
// Setting $form_state['rebuild'] = TRUE causes the form to be rebuilt again.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for "Remove name" button on form_example_tutorial_9().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_9_remove_name($form, &$form_state) {
|
||||
if ($form_state['num_names'] > 1) {
|
||||
$form_state['num_names']--;
|
||||
}
|
||||
|
||||
// Setting $form_state['rebuild'] = TRUE causes the form to be rebuilt again.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate function for form_example_tutorial_9().
|
||||
*
|
||||
* Adds logic to validate the form to check the validity of the new fields,
|
||||
* if they exist.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_9_validate($form, &$form_state) {
|
||||
|
||||
for ($i = 1; $i <= $form_state['num_names']; $i++) {
|
||||
$year_of_birth = $form_state['values']['name'][$i]['year_of_birth'];
|
||||
|
||||
if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
|
||||
form_set_error("name][$i][year_of_birth", t('Enter a year between 1900 and 2000.'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for form_example_tutorial_9().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_9_submit($form, &$form_state) {
|
||||
$output = t("Form 9 has been submitted.");
|
||||
for ($i = 1; $i <= $form_state['num_names']; $i++) {
|
||||
$output .= t("@num: @first @last (@date)...",
|
||||
array(
|
||||
'@num' => $i,
|
||||
'@first' => $form_state['values']['name'][$i]['first'],
|
||||
'@last' => $form_state['values']['name'][$i]['last'],
|
||||
'@date' => $form_state['values']['name'][$i]['year_of_birth'],
|
||||
)
|
||||
) . ' ';
|
||||
}
|
||||
drupal_set_message($output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 10: A form with a file upload field.
|
||||
*
|
||||
* This example allows the user to upload a file to Drupal which is stored
|
||||
* physically and with a reference in the database.
|
||||
*
|
||||
* @see form_example_tutorial_10_submit()
|
||||
* @see form_example_tutorial_10_validate()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_10($form_state) {
|
||||
// If you are familiar with how browsers handle files, you know that
|
||||
// enctype="multipart/form-data" is required. Drupal takes care of that, so
|
||||
// you don't need to include it yourself.
|
||||
$form['file'] = array(
|
||||
'#type' => 'file',
|
||||
'#title' => t('Image'),
|
||||
'#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif'),
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate handler for form_example_tutorial_10().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_10_validate($form, &$form_state) {
|
||||
$file = file_save_upload('file', array(
|
||||
// Validates file is really an image.
|
||||
'file_validate_is_image' => array(),
|
||||
// Validate extensions.
|
||||
'file_validate_extensions' => array('png gif jpg jpeg'),
|
||||
));
|
||||
// If the file passed validation:
|
||||
if ($file) {
|
||||
// Move the file into the Drupal file system.
|
||||
if ($file = file_move($file, 'public://')) {
|
||||
// Save the file for use in the submit handler.
|
||||
$form_state['storage']['file'] = $file;
|
||||
}
|
||||
else {
|
||||
form_set_error('file', t("Failed to write the uploaded file to the site's file folder."));
|
||||
}
|
||||
}
|
||||
else {
|
||||
form_set_error('file', t('No file was uploaded.'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for form_example_tutorial_10().
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_10_submit($form, &$form_state) {
|
||||
$file = $form_state['storage']['file'];
|
||||
// We are done with the file, remove it from storage.
|
||||
unset($form_state['storage']['file']);
|
||||
// Make the storage of the file permanent.
|
||||
$file->status = FILE_STATUS_PERMANENT;
|
||||
// Save file status.
|
||||
file_save($file);
|
||||
// Set a response to the user.
|
||||
drupal_set_message(t('The form has been submitted and the image has been saved, filename: @filename.', array('@filename' => $file->filename)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 11: adding a confirmation form.
|
||||
*
|
||||
* This example generates a simple form that, when submitted, directs
|
||||
* the user to a confirmation form generated using the confirm_form function.
|
||||
* It asks the user to verify that the name they input was correct
|
||||
*
|
||||
* @see form_example_tutorial_11_submit()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_11($form, &$form_state) {
|
||||
// This form is identical to the one in example 2 except for one thing: We are
|
||||
// adding an #action tag to direct the form submission to a confirmation page.
|
||||
$form['description'] = array(
|
||||
'#type' => 'item',
|
||||
'#title' => t('A set of two forms that demonstrate the confirm_form function. This form has an explicit action to direct the form to a confirmation page'),
|
||||
);
|
||||
$form['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
'#required' => TRUE,
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => 'Submit',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for form_example_tutorial_11().
|
||||
*
|
||||
* Adds a submit handler/function to our form to redirect
|
||||
* the user to a confirmation page.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_11_submit($form, &$form_state) {
|
||||
// Simple submit function that changes the redirect of the form based on the
|
||||
// value of the name field.
|
||||
$name = $form_state['values']['name'];
|
||||
$form_state['redirect'] = 'examples/form_example/tutorial/11/confirm/' . urlencode($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example 11: A form generated with confirm_form().
|
||||
*
|
||||
* This function generates the confirmation form using the confirm_form()
|
||||
* function. If confirmed, it sets a drupal message to demonstrate it's success.
|
||||
*
|
||||
* @param string $name
|
||||
* The urlencoded name entered by the user.
|
||||
*
|
||||
* @see form_example_tutorial_11_confirm_name_submit()
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_11_confirm_name($form, $form_state, $name) {
|
||||
// confirm_form() returns a complete form array for confirming an action.
|
||||
// It has 7 arguments: $form, $question, $path, $description, $yes, $no, and
|
||||
// $name.
|
||||
// - $form: Additional elements to add to the form that will be available in
|
||||
// the submit handler.
|
||||
// - $question: What is the user confirming? This will be the title of the
|
||||
// page.
|
||||
// - $path: Where should the page go if the user hits cancel?
|
||||
// - $description = NULL: Additional text to display.
|
||||
// - $yes = NULL: Anchor text for the confirmation button. Defaults to
|
||||
// t('Confirm').
|
||||
// - $no = NULL: Anchor text for the cancel link. Defaults to t('Cancel').
|
||||
// - $name = 'confirm': The internal name used to refer to the confirmation
|
||||
// item.
|
||||
|
||||
|
||||
|
||||
// First we make a textfield for our user's name. confirm_form() allows us to
|
||||
// Add form elements to the confirmation form, so we'll take advangage of
|
||||
// that.
|
||||
$user_name_text_field = array(
|
||||
'name' => array(
|
||||
'#type' => 'textfield',
|
||||
// We don't want the user to be able to edit their name here.
|
||||
'#disabled' => TRUE,
|
||||
'#title' => t('Your name:'),
|
||||
'#value' => urldecode($name),
|
||||
),
|
||||
);
|
||||
|
||||
// The question to ask the user.
|
||||
$confirmation_question = t('Is this really your name?');
|
||||
|
||||
// If the user clicks 'no,' they're sent to this path.
|
||||
$cancel_path = 'examples/form_example/tutorial/11';
|
||||
|
||||
// Some helpful descriptive text.
|
||||
$description = t('Please verify whether or not you have input your name correctly. If you verify you will be sent back to the form and a message will be set. Otherwise you will be sent to the same page but with no message.');
|
||||
|
||||
// These are the text for our yes and no buttons.
|
||||
$yes_button = t('This is my name');
|
||||
$no_button = t('Nope, not my name');
|
||||
|
||||
// The name Form API will use to refer to our confirmation form.
|
||||
$confirm_name = 'confirm_example';
|
||||
|
||||
// Finally, call confirm_form() with our information, and then return the form
|
||||
// array it gives us.
|
||||
return confirm_form(
|
||||
$user_name_text_field,
|
||||
$confirmation_question,
|
||||
$cancel_path,
|
||||
$description,
|
||||
$yes_button,
|
||||
$no_button,
|
||||
$confirm_name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for form_example_tutorial_11_confirm_form().
|
||||
*
|
||||
* Adds a submit handler/function to the confirmation form
|
||||
* if this point is reached the submission has been confirmed
|
||||
* so we will set a message to demonstrate the success.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_tutorial_11_confirm_name_submit($form, &$form_state) {
|
||||
drupal_set_message(t("Confirmation form submission recieved. According to your submission your name is '@name'", array("@name" => $form_state['values']['name'])));
|
||||
$form_state['redirect'] = 'examples/form_example/tutorial/11';
|
||||
}
|
||||
325
sites/all/modules/examples/form_example/form_example_wizard.inc
Normal file
325
sites/all/modules/examples/form_example/form_example_wizard.inc
Normal file
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Extensible wizard form example.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extensible wizard form example.
|
||||
*
|
||||
* This is an example of a multistep form using a wizard style. It will include
|
||||
* the 'Previous' and 'Next' buttons when required, and a 'Finish' button at the
|
||||
* last stage of the form submission.
|
||||
*
|
||||
* This example is an extensible skeleton that can include (even
|
||||
* programmatically) more steps. The demonstration form includes three steps,
|
||||
* each step having its own validation functions.
|
||||
*
|
||||
* How to extend this example:
|
||||
* - Steps are defined in the _form_example_steps() function. Include or alter
|
||||
* the steps as you require.
|
||||
* - For each step, implement the corresponding 'form' function (see
|
||||
* 'form_example_wizard_personal_info' for the first step in this example.)
|
||||
* Each step is a regular form, and the wizard collects all the values of the
|
||||
* included forms.
|
||||
* - Optionally, you may include custom validation functions using the regular
|
||||
* validation hook (formname_validate). The wizard uses these validation
|
||||
* functions for each step.
|
||||
* - The most important customization step is to change the submit handler and
|
||||
* do whatever you want with the collected information. In this case, the
|
||||
* example just shows the collected values in the various steps.
|
||||
* @ingroup form_example
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the list of steps and their associated forms.
|
||||
*
|
||||
* This has been separated to clarify and easy the understanding of this
|
||||
* example. You should edit this function to include the steps your
|
||||
* wizard/multistep form requires.
|
||||
*
|
||||
* @return array
|
||||
* List of steps and their forms.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function _form_example_steps() {
|
||||
return array(
|
||||
1 => array(
|
||||
'form' => 'form_example_wizard_personal_info',
|
||||
),
|
||||
2 => array(
|
||||
'form' => 'form_example_wizard_location_info',
|
||||
),
|
||||
3 => array(
|
||||
'form' => 'form_example_wizard_other_info',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The primary formbuilder function for the wizard form.
|
||||
*
|
||||
* This is the form that you should call with drupal_get_form() from your code,
|
||||
* and it will include the rest of the step forms defined. You are not required
|
||||
* to change this function, as this will handle all the step actions for you.
|
||||
*
|
||||
* This form has two defined submit handlers to process the different steps:
|
||||
* - Previous: handles the way to get back one step in the wizard.
|
||||
* - Next: handles each step form submission,
|
||||
*
|
||||
* The third handler, the finish button handler, is the default form_submit
|
||||
* handler used to process the information.
|
||||
*
|
||||
* You are not required to change the next or previous handlers, but you must
|
||||
* change the form_example_wizard_submit handler to perform the operations you
|
||||
* need on the collected information.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard($form, &$form_state) {
|
||||
|
||||
// Initialize a description of the steps for the wizard.
|
||||
if (empty($form_state['step'])) {
|
||||
$form_state['step'] = 1;
|
||||
|
||||
// This array contains the function to be called at each step to get the
|
||||
// relevant form elements. It will also store state information for each
|
||||
// step.
|
||||
$form_state['step_information'] = _form_example_steps();
|
||||
}
|
||||
$step = &$form_state['step'];
|
||||
drupal_set_title(t('Extensible Wizard: Step @step', array('@step' => $step)));
|
||||
|
||||
// Call the function named in $form_state['step_information'] to get the
|
||||
// form elements to display for this step.
|
||||
$form = $form_state['step_information'][$step]['form']($form, $form_state);
|
||||
|
||||
// Show the 'previous' button if appropriate. Note that #submit is set to
|
||||
// a special submit handler, and that we use #limit_validation_errors to
|
||||
// skip all complaints about validation when using the back button. The
|
||||
// values entered will be discarded, but they will not be validated, which
|
||||
// would be annoying in a "back" button.
|
||||
if ($step > 1) {
|
||||
$form['prev'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Previous'),
|
||||
'#name' => 'prev',
|
||||
'#submit' => array('form_example_wizard_previous_submit'),
|
||||
'#limit_validation_errors' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
// Show the Next button only if there are more steps defined.
|
||||
if ($step < count($form_state['step_information'])) {
|
||||
// The Next button should be included on every step.
|
||||
$form['next'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Next'),
|
||||
'#name' => 'next',
|
||||
'#submit' => array('form_example_wizard_next_submit'),
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Just in case there are no more steps, we use the default submit handler
|
||||
// of the form wizard. Call this button Finish, Submit, or whatever you
|
||||
// want to show. When this button is clicked, the
|
||||
// form_example_wizard_submit handler will be called.
|
||||
$form['finish'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Finish'),
|
||||
);
|
||||
}
|
||||
|
||||
// Include each validation function defined for the different steps.
|
||||
if (function_exists($form_state['step_information'][$step]['form'] . '_validate')) {
|
||||
$form['next']['#validate'] = array($form_state['step_information'][$step]['form'] . '_validate');
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the "previous" button.
|
||||
*
|
||||
* This function:
|
||||
* - Stores away $form_state['values']
|
||||
* - Decrements the step counter
|
||||
* - Replaces $form_state['values'] with the values from the previous state.
|
||||
* - Forces form rebuild.
|
||||
*
|
||||
* You are not required to change this function.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_previous_submit($form, &$form_state) {
|
||||
$current_step = &$form_state['step'];
|
||||
$form_state['step_information'][$current_step]['stored_values'] = $form_state['input'];
|
||||
if ($current_step > 1) {
|
||||
$current_step--;
|
||||
$form_state['values'] = $form_state['step_information'][$current_step]['stored_values'];
|
||||
}
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the 'next' button.
|
||||
*
|
||||
* This function:
|
||||
* - Saves away $form_state['values']
|
||||
* - Increments the step count.
|
||||
* - Replace $form_state['values'] from the last time we were at this page
|
||||
* or with array() if we haven't been here before.
|
||||
* - Force form rebuild.
|
||||
*
|
||||
* You are not required to change this function.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_next_submit($form, &$form_state) {
|
||||
$current_step = &$form_state['step'];
|
||||
$form_state['step_information'][$current_step]['stored_values'] = $form_state['values'];
|
||||
|
||||
if ($current_step < count($form_state['step_information'])) {
|
||||
$current_step++;
|
||||
if (!empty($form_state['step_information'][$current_step]['stored_values'])) {
|
||||
$form_state['values'] = $form_state['step_information'][$current_step]['stored_values'];
|
||||
}
|
||||
else {
|
||||
$form_state['values'] = array();
|
||||
}
|
||||
// Force rebuild with next step.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The previous code was a 'skeleton' of a multistep wizard form. You are not
|
||||
* required to change a line on the previous code (apart from defining your own
|
||||
* steps in the _form_example_steps() function.
|
||||
*
|
||||
* All the code included from here is the content of the wizard, the steps of
|
||||
* the form.
|
||||
*
|
||||
* First, let's show the defined steps for the wizard example.
|
||||
* @ingroup form_example
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns form elements for the 'personal info' page of the wizard.
|
||||
*
|
||||
* This is the first step of the wizard, asking for two textfields: first name
|
||||
* and last name.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_personal_info($form, &$form_state) {
|
||||
$form = array();
|
||||
$form['first_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('First Name'),
|
||||
'#default_value' => !empty($form_state['values']['first_name']) ? $form_state['values']['first_name'] : '',
|
||||
);
|
||||
$form['last_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Last Name'),
|
||||
'#default_value' => !empty($form_state['values']['last_name']) ? $form_state['values']['last_name'] : '',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns form elements for the 'location info' page of the wizard.
|
||||
*
|
||||
* This is the second step of the wizard. This step asks for a textfield value:
|
||||
* a City. This step also includes a validation declared later.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_location_info($form, &$form_state) {
|
||||
$form = array();
|
||||
$form['city'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('City'),
|
||||
'#description' => t('Hint: Do not enter "San Francisco", and do not leave this out.'),
|
||||
'#required' => TRUE,
|
||||
'#default_value' => !empty($form_state['values']['city']) ? $form_state['values']['city'] : '',
|
||||
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation form for the 'location info' page of the wizard.
|
||||
*
|
||||
* This is the validation function for the second step of the wizard.
|
||||
* The city cannot be empty or be "San Francisco".
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_location_info_validate($form, &$form_state) {
|
||||
if ($form_state['values']['city'] == 'San Francisco') {
|
||||
form_set_error('city', t('You were warned not to enter "San Francisco"'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns form elements for the 'other info' page of the wizard.
|
||||
*
|
||||
* This is the third and last step of the example wizard.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_other_info($form, &$form_state) {
|
||||
$form = array();
|
||||
$form['aunts_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t("Your first cousin's aunt's Social Security number"),
|
||||
'#default_value' => !empty($form_state['values']['aunts_name']) ? $form_state['values']['aunts_name'] : '',
|
||||
);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wizard form submit handler.
|
||||
*
|
||||
* This function:
|
||||
* - Saves away $form_state['values']
|
||||
* - Process all the form values.
|
||||
*
|
||||
* And now comes the magic of the wizard, the function that should handle all
|
||||
* the inputs from the user on each different step.
|
||||
*
|
||||
* This demonstration handler just do a drupal_set_message() with the
|
||||
* information collected on each different step of the wizard.
|
||||
*
|
||||
* @ingroup form_example
|
||||
*/
|
||||
function form_example_wizard_submit($form, &$form_state) {
|
||||
$current_step = &$form_state['step'];
|
||||
$form_state['step_information'][$current_step]['stored_values'] = $form_state['values'];
|
||||
|
||||
// In this case we've completed the final page of the wizard, so process the
|
||||
// submitted information.
|
||||
drupal_set_message(t('This information was collected by this wizard:'));
|
||||
foreach ($form_state['step_information'] as $index => $value) {
|
||||
// Remove FAPI fields included in the values (form_token, form_id and
|
||||
// form_build_id. This is not required, you may access the values using
|
||||
// $value['stored_values'] but I'm removing them to make a more clear
|
||||
// representation of the collected information as the complete array will
|
||||
// be passed through drupal_set_message().
|
||||
unset($value['stored_values']['form_id']);
|
||||
unset($value['stored_values']['form_build_id']);
|
||||
unset($value['stored_values']['form_token']);
|
||||
|
||||
// Now show all the values.
|
||||
drupal_set_message(t('Step @num collected the following values: <pre>@result</pre>',
|
||||
array(
|
||||
'@num' => $index,
|
||||
'@result' => print_r($value['stored_values'], TRUE),
|
||||
)
|
||||
));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user