'AJAX Example', 'page callback' => 'ajax_example_intro', 'access callback' => TRUE, 'expanded' => TRUE, ); // Change the description of a form element. $items['examples/ajax_example/simplest'] = array( 'title' => 'Simplest AJAX Example', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_simplest'), 'access callback' => TRUE, 'weight' => 0, ); // Generate a changing number of checkboxes. $items['examples/ajax_example/autocheckboxes'] = array( 'title' => 'Generate checkboxes', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_autocheckboxes'), 'access callback' => TRUE, 'weight' => 1, ); // Generate different textfields based on form state. $items['examples/ajax_example/autotextfields'] = array( 'title' => 'Generate textfields', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_autotextfields'), 'access callback' => TRUE, 'weight' => 2, ); // Submit a form without a page reload. $items['examples/ajax_example/submit_driven_ajax'] = array( 'title' => 'Submit-driven AJAX', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_submit_driven_ajax'), 'access callback' => TRUE, 'weight' => 3, ); // Repopulate a dropdown based on form state. $items['examples/ajax_example/dependent_dropdown'] = array( 'title' => 'Dependent dropdown', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_dependent_dropdown'), 'access callback' => TRUE, 'weight' => 4, ); // Repopulate a dropdown, but this time with graceful degredation. // See ajax_example_graceful_degradation.inc. $items['examples/ajax_example/dependent_dropdown_degrades'] = array( 'title' => 'Dependent dropdown (with graceful degradation)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_dependent_dropdown_degrades'), 'access callback' => TRUE, 'weight' => 5, 'file' => 'ajax_example_graceful_degradation.inc', ); // The above example as it appears to users with no javascript. $items['examples/ajax_example/dependent_dropdown_degrades_no_js'] = array( 'title' => 'Dependent dropdown with javascript off', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_dependent_dropdown_degrades', TRUE), 'access callback' => TRUE, 'file' => 'ajax_example_graceful_degradation.inc', 'weight' => 5, ); // Populate a form section based on input in another element. $items['examples/ajax_example/dynamic_sections'] = array( 'title' => 'Dynamic Sections (with graceful degradation)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_dynamic_sections'), 'access callback' => TRUE, 'weight' => 6, 'file' => 'ajax_example_graceful_degradation.inc', ); // The above example as it appears to users with no javascript. $items['examples/ajax_example/dynamic_sections_no_js'] = array( 'title' => 'Dynamic Sections w/JS turned off', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_dynamic_sections', TRUE), 'access callback' => TRUE, 'weight' => 6, 'file' => 'ajax_example_graceful_degradation.inc', ); // A classic multi-step wizard, but with no page reloads. // See ajax_example_graceful_degradation.inc. $items['examples/ajax_example/wizard'] = array( 'title' => 'Wizard (with graceful degradation)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_wizard'), 'access callback' => TRUE, 'file' => 'ajax_example_graceful_degradation.inc', 'weight' => 7, ); // The above example as it appears to users with no javascript. $items['examples/ajax_example/wizard_no_js'] = array( 'title' => 'Wizard w/JS turned off', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_wizard', TRUE), 'access callback' => TRUE, 'file' => 'ajax_example_graceful_degradation.inc', 'weight' => 7, ); // Add-more button that creates additional form elements. // See ajax_example_graceful_degradation.inc. $items['examples/ajax_example/add_more'] = array( 'title' => 'Add-more button (with graceful degradation)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_add_more'), 'access callback' => TRUE, 'file' => 'ajax_example_graceful_degradation.inc', 'weight' => 8, ); // The above example as it appears to users with no javascript. $items['examples/ajax_example/add_more_no_js'] = array( 'title' => 'Add-more button w/JS turned off', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_add_more', TRUE), 'access callback' => TRUE, 'file' => 'ajax_example_graceful_degradation.inc', 'weight' => 8, ); // Use the AJAX framework outside the context of a form using the use-ajax // class. See ajax_example_misc.inc. $items['examples/ajax_example/ajax_link'] = array( 'title' => 'Ajax Link ("use-ajax" class)', 'page callback' => 'ajax_example_render_link', 'access callback' => TRUE, 'file' => 'ajax_example_misc.inc', 'weight' => 9, ); // Use the AJAX framework outside the context of a form using a renderable // array of type link with the #ajax property. See ajax_example_misc.inc. $items['examples/ajax_example/ajax_link_renderable'] = array( 'title' => 'Ajax Link (Renderable Array)', 'page callback' => 'ajax_example_render_link_ra', 'access callback' => TRUE, 'file' => 'ajax_example_misc.inc', 'weight' => 9, ); // A menu callback is required when using ajax outside of the Form API. $items['ajax_link_callback'] = array( 'page callback' => 'ajax_link_response', 'access callback' => 'user_access', 'access arguments' => array('access content'), 'type' => MENU_CALLBACK, 'file' => 'ajax_example_misc.inc', ); // Use AJAX framework commands outside of the #ajax form property. // See ajax_example_advanced.inc. $items['examples/ajax_example/advanced_commands'] = array( 'title' => 'AJAX framework commands', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_advanced_commands'), 'access callback' => TRUE, 'file' => 'ajax_example_advanced.inc', 'weight' => 100, ); // Autocomplete examples. $items['examples/ajax_example/simple_autocomplete'] = array( 'title' => 'Autocomplete (simple)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_simple_autocomplete'), 'access arguments' => array('access user profiles'), 'file' => 'ajax_example_autocomplete.inc', 'weight' => 10, ); $items['examples/ajax_example/simple_user_autocomplete_callback'] = array( 'page callback' => 'ajax_example_simple_user_autocomplete_callback', 'file' => 'ajax_example_autocomplete.inc', 'type' => MENU_CALLBACK, 'access arguments' => array('access user profiles'), ); $items['examples/ajax_example/node_autocomplete'] = array( 'title' => 'Autocomplete (node with nid)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_unique_autocomplete'), 'access arguments' => array('access content'), 'file' => 'ajax_example_autocomplete.inc', 'weight' => 11, ); $items['examples/ajax_example/unique_node_autocomplete_callback'] = array( 'page callback' => 'ajax_example_unique_node_autocomplete_callback', 'file' => 'ajax_example_autocomplete.inc', 'type' => MENU_CALLBACK, 'access arguments' => array('access content'), ); $items['examples/ajax_example/node_by_author'] = array( 'title' => 'Autocomplete (node limited by author)', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_node_by_author_autocomplete'), 'access callback' => TRUE, 'file' => 'ajax_example_autocomplete.inc', 'weight' => 12, ); $items['examples/ajax_example/node_by_author_autocomplete'] = array( 'page callback' => 'ajax_example_node_by_author_node_autocomplete_callback', 'file' => 'ajax_example_autocomplete.inc', 'type' => MENU_CALLBACK, 'access arguments' => array('access content'), ); // This is the landing page for the progress bar example. It uses // drupal_get_form() in order to build the form. $items['examples/ajax_example/progressbar'] = array( 'title' => 'Progress bar example', 'page callback' => 'drupal_get_form', 'page arguments' => array('ajax_example_progressbar_form'), 'access arguments' => array('access content'), 'file' => 'ajax_example_progressbar.inc', ); // This is the callback route for the AJAX-based progress bar. $items['examples/ajax_example/progressbar/progress/%'] = array( 'title' => 'Progress bar progress', 'page callback' => 'ajax_example_progressbar_progress', 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'access arguments' => array('access content'), 'file' => 'ajax_example_progressbar.inc', ); return $items; } /** * A basic introduction page for the ajax_example module. */ function ajax_example_intro() { $markup = t('The AJAX example module provides many examples of AJAX including forms, links, and AJAX commands.'); $list[] = l(t('Simplest AJAX Example'), 'examples/ajax_example/simplest'); $list[] = l(t('Generate checkboxes'), 'examples/ajax_example/autocheckboxes'); $list[] = l(t('Generate textfields'), 'examples/ajax_example/autotextfields'); $list[] = l(t('Submit-driven AJAX'), 'examples/ajax_example/submit_driven_ajax'); $list[] = l(t('Dependent dropdown'), 'examples/ajax_example/dependent_dropdown'); $list[] = l(t('Dependent dropdown (with graceful degradation)'), 'examples/ajax_example/dependent_dropdown_degrades'); $list[] = l(t('Dynamic Sections w/JS turned off'), 'examples/ajax_example/dependent_dropdown_degrades_no_js'); $list[] = l(t('Wizard (with graceful degradation)'), 'examples/ajax_example/wizard'); $list[] = l(t('Wizard w/JS turned off'), 'examples/ajax_example/wizard_no_js'); $list[] = l(t('Add-more button (with graceful degradation)'), 'examples/ajax_example/add_more'); $list[] = l(t('Add-more button w/JS turned off'), 'examples/ajax_example/add_more_no_js'); $list[] = l(t('Ajax Link ("use-ajax" class)'), 'examples/ajax_example/ajax_link'); $list[] = l(t('Ajax Link (Renderable Array)'), 'examples/ajax_example/ajax_link_renderable'); $list[] = l(t('AJAX framework commands'), 'examples/ajax_example/advanced_commands'); $list[] = l(t('Autocomplete (simple)'), 'examples/ajax_example/simple_autocomplete'); $list[] = l(t('Autocomplete (node with nid)'), 'examples/ajax_example/node_autocomplete'); $list[] = l(t('Autocomplete (node limited by author)'), 'examples/ajax_example/node_by_author'); $variables['items'] = $list; $variables['type'] = 'ul'; $markup .= theme('item_list', $variables); return $markup; } /** * Basic AJAX callback example. * * Simple form whose ajax-enabled 'changethis' member causes a text change * in the description of the 'replace_textfield' member. * * See @link http://drupal.org/node/262422 Form API Tutorial @endlink */ function ajax_example_simplest($form, &$form_state) { $form = array(); $form['changethis'] = array( '#title' => t("Choose something and explain why"), '#type' => 'select', '#options' => array( 'one' => 'one', 'two' => 'two', 'three' => 'three', ), '#ajax' => array( // #ajax has two required keys: callback and wrapper. // 'callback' is a function that will be called when this element changes. 'callback' => 'ajax_example_simplest_callback', // 'wrapper' is the HTML id of the page element that will be replaced. 'wrapper' => 'replace_textfield_div', // There are also several optional keys - see ajax_example_autocheckboxes // below for details on 'method', 'effect' and 'speed' and // ajax_example_dependent_dropdown for 'event'. ), ); // This entire form element will be replaced whenever 'changethis' is updated. $form['replace_textfield'] = array( '#type' => 'textfield', '#title' => t("Why"), // The prefix/suffix provide the div that we're replacing, named by // #ajax['wrapper'] above. '#prefix' => '
', '#suffix' => '
', ); // An AJAX request calls the form builder function for every change. // We can change how we build the form based on $form_state. if (!empty($form_state['values']['changethis'])) { $form['replace_textfield']['#description'] = t("Say why you chose '@value'", array('@value' => $form_state['values']['changethis'])); } return $form; } /** * Callback for ajax_example_simplest. * * On an ajax submit, the form builder function is called again, then the $form * and $form_state are passed to this callback function so it can select which * portion of the form to send on to the client. * * @return array * Renderable array (the textfield element) */ function ajax_example_simplest_callback($form, $form_state) { // The form has already been submitted and updated. We can return the replaced // item as it is. return $form['replace_textfield']; } /** * Form manipulation through AJAX. * * AJAX-enabled select element causes replacement of a set of checkboxes * based on the selection. */ function ajax_example_autocheckboxes($form, &$form_state) { // Since the form builder is called after every AJAX request, we rebuild // the form based on $form_state. $num_checkboxes = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1; $form['howmany_select'] = array( '#title' => t('How many checkboxes do you want?'), '#type' => 'select', '#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4), '#default_value' => $num_checkboxes, '#ajax' => array( 'callback' => 'ajax_example_autocheckboxes_callback', 'wrapper' => 'checkboxes-div', // 'method' defaults to replaceWith, but valid values also include // append, prepend, before and after. // 'method' => 'replaceWith', // 'effect' defaults to none. Other valid values are 'fade' and 'slide'. // See ajax_example_autotextfields for an example of 'fade'. 'effect' => 'slide', // 'speed' defaults to 'slow'. You can also use 'fast' // or a number of milliseconds for the animation to last. // 'speed' => 'slow', // Don't show any throbber... 'progress' => array('type' => 'none'), ), ); $form['checkboxes_fieldset'] = array( '#title' => t("Generated Checkboxes"), // The prefix/suffix provide the div that we're replacing, named by // #ajax['wrapper'] above. '#prefix' => '
', '#suffix' => '
', '#type' => 'fieldset', '#description' => t('This is where we get automatically generated checkboxes'), ); for ($i = 1; $i <= $num_checkboxes; $i++) { $form['checkboxes_fieldset']["checkbox$i"] = array( '#type' => 'checkbox', '#title' => "Checkbox $i", ); } $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Callback for autocheckboxes. * * Callback element needs only select the portion of the form to be updated. * Since #ajax['callback'] return can be HTML or a renderable array (or an * array of commands), we can just return a piece of the form. * See @link ajax_example_advanced.inc AJAX Advanced Commands for more details * on AJAX framework commands. * * @return array * Renderable array (the checkboxes fieldset) */ function ajax_example_autocheckboxes_callback($form, $form_state) { return $form['checkboxes_fieldset']; } /** * Show/hide textfields based on AJAX-enabled checkbox clicks. */ function ajax_example_autotextfields($form, &$form_state) { $form['ask_first_name'] = array( '#type' => 'checkbox', '#title' => t('Ask me my first name'), '#ajax' => array( 'callback' => 'ajax_example_autotextfields_callback', 'wrapper' => 'textfields', 'effect' => 'fade', ), ); $form['ask_last_name'] = array( '#type' => 'checkbox', '#title' => t('Ask me my last name'), '#ajax' => array( 'callback' => 'ajax_example_autotextfields_callback', 'wrapper' => 'textfields', 'effect' => 'fade', ), ); $form['textfields'] = array( '#title' => t("Generated text fields for first and last name"), '#prefix' => '
', '#suffix' => '
', '#type' => 'fieldset', '#description' => t('This is where we put automatically generated textfields'), ); // Since checkboxes return TRUE or FALSE, we have to check that // $form_state has been filled as well as what it contains. if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) { $form['textfields']['first_name'] = array( '#type' => 'textfield', '#title' => t('First Name'), ); } if (!empty($form_state['values']['ask_last_name']) && $form_state['values']['ask_last_name']) { $form['textfields']['last_name'] = array( '#type' => 'textfield', '#title' => t('Last Name'), ); } $form['submit'] = array( '#type' => 'submit', '#value' => t('Click Me'), ); return $form; } /** * Callback for autotextfields. * * Selects the piece of the form we want to use as replacement text and returns * it as a form (renderable array). * * @return array * Renderable array (the textfields element) */ function ajax_example_autotextfields_callback($form, $form_state) { return $form['textfields']; } /** * A very basic form which with an AJAX-enabled submit. * * On submit, the markup in the #markup element is updated. */ function ajax_example_submit_driven_ajax($form, &$form_state) { $form['box'] = array( '#type' => 'markup', '#prefix' => '
', '#suffix' => '
', '#markup' => '

Initial markup for box

', ); $form['submit'] = array( '#type' => 'submit', '#ajax' => array( 'callback' => 'ajax_example_submit_driven_callback', 'wrapper' => 'box', ), '#value' => t('Submit'), ); return $form; } /** * Callback for submit_driven example. * * Select the 'box' element, change the markup in it, and return it as a * renderable array. * * @return array * Renderable array (the box element) */ function ajax_example_submit_driven_callback($form, $form_state) { // In most cases, it is recommended that you put this logic in form generation // rather than the callback. Submit driven forms are an exception, because // you may not want to return the form at all. $element = $form['box']; $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c'); return $element; } /** * AJAX-based dropdown example form. * * A form with a dropdown whose options are dependent on a * choice made in a previous dropdown. * * On changing the first dropdown, the options in the second * are updated. */ function ajax_example_dependent_dropdown($form, &$form_state) { // Get the list of options to populate the first dropdown. $options_first = _ajax_example_get_first_dropdown_options(); // If we have a value for the first dropdown from $form_state['values'] we use // this both as the default value for the first dropdown and also as a // parameter to pass to the function that retrieves the options for the // second dropdown. $selected = isset($form_state['values']['dropdown_first']) ? $form_state['values']['dropdown_first'] : key($options_first); $form['dropdown_first'] = array( '#type' => 'select', '#title' => 'Instrument Type', '#options' => $options_first, '#default_value' => $selected, // Bind an ajax callback to the change event (which is the default for the // select form type) of the first dropdown. It will replace the second // dropdown when rebuilt. '#ajax' => array( // When 'event' occurs, Drupal will perform an ajax request in the // background. Usually the default value is sufficient (eg. change for // select elements), but valid values include any jQuery event, // most notably 'mousedown', 'blur', and 'submit'. // 'event' => 'change', 'callback' => 'ajax_example_dependent_dropdown_callback', 'wrapper' => 'dropdown-second-replace', ), ); $form['dropdown_second'] = array( '#type' => 'select', '#title' => $options_first[$selected] . ' ' . t('Instruments'), // The entire enclosing div created here gets replaced when dropdown_first // is changed. '#prefix' => '', // When the form is rebuilt during ajax processing, the $selected variable // will now have the new value and so the options will change. '#options' => _ajax_example_get_second_dropdown_options($selected), '#default_value' => isset($form_state['values']['dropdown_second']) ? $form_state['values']['dropdown_second'] : '', ); $form['submit'] = array( '#type' => 'submit', '#value' => t('Submit'), ); return $form; } /** * Selects just the second dropdown to be returned for re-rendering. * * Since the controlling logic for populating the form is in the form builder * function, all we do here is select the element and return it to be updated. * * @return array * Renderable array (the second dropdown) */ function ajax_example_dependent_dropdown_callback($form, $form_state) { return $form['dropdown_second']; } /** * Helper function to populate the first dropdown. * * This would normally be pulling data from the database. * * @return array * Dropdown options. */ function _ajax_example_get_first_dropdown_options() { // drupal_map_assoc() just makes an array('String' => 'String'...). return drupal_map_assoc( array( t('String'), t('Woodwind'), t('Brass'), t('Percussion'), ) ); } /** * Helper function to populate the second dropdown. * * This would normally be pulling data from the database. * * @param string $key * This will determine which set of options is returned. * * @return array * Dropdown options */ function _ajax_example_get_second_dropdown_options($key = '') { $options = array( t('String') => drupal_map_assoc( array( t('Violin'), t('Viola'), t('Cello'), t('Double Bass'), ) ), t('Woodwind') => drupal_map_assoc( array( t('Flute'), t('Clarinet'), t('Oboe'), t('Bassoon'), ) ), t('Brass') => drupal_map_assoc( array( t('Trumpet'), t('Trombone'), t('French Horn'), t('Euphonium'), ) ), t('Percussion') => drupal_map_assoc( array( t('Bass Drum'), t('Timpani'), t('Snare Drum'), t('Tambourine'), ) ), ); if (isset($options[$key])) { return $options[$key]; } else { return array(); } } /** * @} End of "defgroup ajax_example". */