#988850 by threewestwinds, rfay: Improving documentation for AJAX Example.
authorRandy Fay
Mon, 13 Dec 2010 20:28:52 +0000 (20:28 +0000)
committerRandy Fay
Mon, 13 Dec 2010 20:28:52 +0000 (20:28 +0000)
ajax_example/ajax_example.css
ajax_example/ajax_example.js
ajax_example/ajax_example.module
ajax_example/ajax_example_advanced.inc
ajax_example/ajax_example_graceful_degradation.inc
ajax_example/ajax_example_misc.inc

index 8e9973e..7791259 100644 (file)
@@ -1,9 +1,11 @@
 /* $Id$ */
 
-/**
-  * @file
-  *   CSS for ajax_example
-  *
+/*
+ * @file ajax_example.css
+ *   CSS for ajax_example.
+ *
+ * See @link ajax_example_dependent_dropdown_degrades @endlink for
+ * details on what this file does. It is not used in any other example.
  */
  
 /* hide the next button when not degrading to non-javascript browser */
index 9944ff3..80ca557 100644 (file)
@@ -1,5 +1,14 @@
 // $Id$
 
+/*
+ * @file ajax_example.js
+ *   JavaScript for ajax_example.
+ *
+ * See @link ajax_example_dependent_dropdown_degrades @endlink for
+ * details on what this file does. It is not used in any other example.
+ * 
+ */
+
 (function($) {
 
   // Re-enable form elements that are disabled for non-ajax situations.
@@ -9,8 +18,7 @@
     if (Drupal.ajax) {
       $('.enabled-for-ajax').removeAttr('disabled');
     }
-    
-    
+
     // Below is only for the demo case of showing with js turned off.
     // It overrides the behavior of the CSS that would normally turn off
     // the 'ok' button when JS is enabled. Here, for demonstration purposes,
@@ -21,5 +29,4 @@
   }
   };
 
-
 })(jQuery);
index 7c4a37a..908c7b3 100644 (file)
@@ -24,6 +24,8 @@
  * Set up calls to drupal_get_form() for all our example cases.
  *
  * Implements hook_menu().
+ * See @link menu_example.module Menu Example @endlink for more details on
+ * hook_menu().
  */
 function ajax_example_menu() {
   $items = array();
@@ -34,6 +36,8 @@ function ajax_example_menu() {
     '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',
@@ -41,7 +45,7 @@ function ajax_example_menu() {
     'access callback' => TRUE,
     'weight' => 0,
   );
-  // Automatically generate checkboxes
+  // Generate a changing number of checkboxes.
   $items['examples/ajax_example/autocheckboxes'] = array(
     'title' => 'Generate checkboxes',
     'page callback' => 'drupal_get_form',
@@ -49,8 +53,7 @@ function ajax_example_menu() {
     'access callback' => TRUE,
     'weight' => 1,
   );
-
-    // Automatically generate textfields
+  // Generate different textfields based on form state.
   $items['examples/ajax_example/autotextfields'] = array(
     'title' => 'Generate textfields',
     'page callback' => 'drupal_get_form',
@@ -59,6 +62,7 @@ function ajax_example_menu() {
     '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',
@@ -67,6 +71,7 @@ function ajax_example_menu() {
     'weight' => 3,
   );
 
+  // Repopulate a dropdown based on form state.
   $items['examples/ajax_example/dependent_dropdown'] = array(
     'title' => 'Dependent dropdown',
     'page callback' => 'drupal_get_form',
@@ -74,6 +79,8 @@ function ajax_example_menu() {
     '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',
@@ -82,6 +89,7 @@ function ajax_example_menu() {
     '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',
@@ -91,6 +99,7 @@ function ajax_example_menu() {
     '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',
@@ -99,6 +108,7 @@ function ajax_example_menu() {
     'weight' => 6,
     'file' => 'ajax_example_graceful_degradation.inc',
   );
+  // The  above example as it appears to users with no javascript.
   $items['ajax_example/dynamic_sections_no_js'] = array(
     'title' => 'Dynamic Sections w/JS turned off',
     'page callback' => 'drupal_get_form',
@@ -108,7 +118,8 @@ function ajax_example_menu() {
     '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',
@@ -117,6 +128,7 @@ function ajax_example_menu() {
     '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',
@@ -126,6 +138,8 @@ function ajax_example_menu() {
     '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',
@@ -134,6 +148,7 @@ function ajax_example_menu() {
     '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',
@@ -143,15 +158,8 @@ function ajax_example_menu() {
     'weight' => 8,
   );
 
-  $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' => 10,
-  );
-
+  // Use the AJAX framework outside the context of a form.
+  // See ajax_example_misc.inc.
   $items['examples/ajax_example/ajax_link'] = array(
     'title' => 'Ajax Link',
     'page callback' => 'ajax_example_render_link',
@@ -159,7 +167,7 @@ function ajax_example_menu() {
     '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',
@@ -168,6 +176,17 @@ function ajax_example_menu() {
     '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' => 10,
+  );
+
   return $items;
 }
 
@@ -184,6 +203,7 @@ function ajax_example_intro() {
 /**
  * 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();
@@ -196,35 +216,43 @@ function ajax_example_simplest($form, &$form_state) {
       '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 with an updated value.
-  // However, it has to have the prefix/suffix to work right, as the entire
-  // div is replaced.
-  // In this example, the description is dynamically updated during form
-  // rebuild.
-
+  // 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' => '<div id="replace_textfield_div">',
     '#suffix' => '</div>',
   );
 
+  // 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") .  " '{$form_state['values']['changethis']}'";
   }
   return $form;
 }
+
 /**
  * Callback for ajax_example_simplest.
  *
- * The form item 'replace_textfield' has already been processed and changed
- * when the form was submitted and rebuilt during the AJAX call, so now
- * we just return the piece of the form that changed.
+ * 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 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
@@ -232,14 +260,14 @@ function ajax_example_simplest_callback($form, $form_state) {
   return $form['replace_textfield'];
 }
 
-
 /**
  * AJAX-enabled select element causes replacement of a set of checkboxes
  * based on the selection.
  */
 function ajax_example_autocheckboxes($form, &$form_state) {
-
-  $default = !empty($form_state['values']['howmany']) ? $form_state['values']['howmany'] : 1;
+  // Since the form builder is called after every AJAX request, we rebuild
+  // the form based on $form_state.
+  $default = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
 
   $form['howmany_select'] = array(
     '#title' => t('How many checkboxes do you want?'),
@@ -249,10 +277,16 @@ function ajax_example_autocheckboxes($form, &$form_state) {
     '#ajax' => array(
       'callback' => 'ajax_example_autocheckboxes_callback',
       'wrapper' => 'checkboxes-div',
-      'method' => 'replace',
-      'effect' => 'fade',
+      //'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',
     ),
-
   );
 
 
@@ -286,11 +320,16 @@ function ajax_example_autocheckboxes($form, &$form_state) {
  * 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 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.
  */
@@ -312,7 +351,6 @@ function ajax_example_autotextfields($form, &$form_state) {
       'callback' => 'ajax_example_autotextfields_callback',
       'wrapper' => 'textfields',
       'effect' => 'fade',
-
     ),
   );
 
@@ -324,7 +362,9 @@ function ajax_example_autotextfields($form, &$form_state) {
     '#description' => t('This is where we put automatically generated textfields'),
   );
 
-   if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) {
+  // 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'),
@@ -337,17 +377,14 @@ function ajax_example_autotextfields($form, &$form_state) {
     );
   }
 
-
   $form['submit'] = array(
     '#type' => 'submit',
     '#value' => t('Click Me'),
   );
 
-
   return $form;
 }
 
-
 /**
  * Selects the piece of the form we want to use as replacement text and returns
  * it as a form (renderable array).
@@ -388,8 +425,13 @@ function ajax_example_submit_driven_ajax($form, &$form_state) {
 /**
  * Select the 'box' element, change the markup in it, and return it as a
  * renderable array.
+ *
+ * @return renderable array (the box element)
  */
 function ajax_example_submit_driven_callback($form, $form_state) {
+  // In most cases, it is recomended 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;
@@ -404,9 +446,9 @@ function ajax_example_submit_driven_callback($form, $form_state) {
  * are updated.
  */
 function ajax_example_dependent_dropdown($form, &$form_state) {
-  // get the list of options to populate the first dropdown
+  // 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
+  // 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.
@@ -416,10 +458,15 @@ function ajax_example_dependent_dropdown($form, &$form_state) {
     '#title' => 'First Dropdown',
     '#options' => $options_first,
     '#default_value' => $selected,
-    // bind an ajax callback to the change event (which is the default for the
+    // 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',
     ),
@@ -440,15 +487,14 @@ function ajax_example_dependent_dropdown($form, &$form_state) {
     '#type' => 'submit',
     '#value' => t('Submit'),
   );
-
   return $form;
 }
 
 /**
  * Selects just the second dropdown to be returned for re-rendering
  *
- * The version here has been re-loaded with a different set of options and
- * is sent back to the page to be updated.
+ * 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 renderable array (the second dropdown)
  */
@@ -456,7 +502,6 @@ 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.
index 68929f3..5c10048 100644 (file)
@@ -87,7 +87,7 @@ function ajax_example_advanced_commands($form, &$form_state) {
   // Shows the 'changed' command.
   $form['changed_command_example_fieldset'] = array(
     '#type' => 'fieldset',
-    '#title' => t("Demonstrates the AJAX 'changed' command. If region is 'changed', it's marked with CSS. This example also puts an asterisk by changed content."),
+    '#title' => t("Demonstrates the AJAX 'changed' command. If region is 'changed', it is marked with CSS. This example also puts an asterisk by changed content."),
   );
 
   $form['changed_command_example_fieldset']['changed_command_example'] = array(
@@ -119,7 +119,6 @@ function ajax_example_advanced_commands($form, &$form_state) {
                   <div id='css_status'>Status: Unknown</div>"
   );
 
-
   // Shows the AJAX 'data' command. But there is no use of this information,
   // as this would require a javascript client to use the data.
   $form['data_command_example_fieldset'] = array(
index 358619e..e8c76e3 100644 (file)
  * available.
  *
  * In each of these the key idea is that the form is rebuilt different ways
- * depending on form input. So the formbuilder function is in charge of
- * almost all logic.
+ * depending on form input. In order to accomplish that, the formbuilder function
+ * is in charge of almost all logic.
  *
  * @see ajax
  *
  * @}
-*/
+ */
 
 
 
@@ -35,7 +35,7 @@
  * if javascript is not enabled. The Javascript snippet is really only used
  * to enable us to present the form in degraded mode without forcing the user
  * to turn off Javascript.  Both of these are loaded by using the
- * #attached FAPI property, so it's a good example of how to use that.
+ * #attached FAPI property, so it is a good example of how to use that.
  *
  * The extra argument $no_js_use is here only to allow presentation of this
  * form as if Javascript were not enabled. ajax_example_menu() provides two
  * @ingroup ajax_degradation_examples
  */
 function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_use = FALSE) {
-  // get the list of options to populate the first dropdown
+  // 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
+  // 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.
@@ -74,9 +74,9 @@ function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_us
     '#options' => $options_first,
     '#attributes' => array('class' => array('enabled-for-ajax')),
 
-    // 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.
+    // The '#ajax' property allows us to bind a callback to the server whenever this
+    // form element changes. See ajax_example_autocheckboxes and
+    // ajax_example_dependent_dropdown in ajax_example.module for more details.
     '#ajax' => array(
       'callback' => 'ajax_example_dependent_dropdown_degrades_first_callback',
       'wrapper' => 'dropdown-second-replace',
@@ -91,7 +91,8 @@ function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_us
     unset($form['dropdown_first_fieldset']['dropdown_first']['#ajax']);
   }
 
-  // The CSS for this module hides this next button if JS is enabled.
+  // Since we don't know if the user has js or not, we always need to output
+  // this element, then hide it with with css if javascript is enabled.
   $form['dropdown_first_fieldset']['continue_to_second'] = array(
     '#type' => 'submit',
     '#value' => t('Choose'),
@@ -107,17 +108,14 @@ function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_us
     '#prefix' => '<div id="dropdown-second-replace">',
     '#suffix' => '</div>',
     '#attributes' => array('class' => array('enabled-for-ajax')),
-
-    // when the form is rebuilt during processing (either AJAX or multistep),
+    // When the form is rebuilt during processing (either AJAX or multistep),
     // the $selected variable will now have the new value and so the options
     // will change.
     '#options' => _ajax_example_get_second_dropdown_options($selected),
   );
-
   $form['dropdown_second_fieldset']['submit'] = array(
     '#type' => 'submit',
     '#value' => t('OK'),
-
     // This class allows attached js file to override the disabled attribute,
     // since it's not necessary in ajax-enabled form.
     '#attributes' => array('class' => array('enabled-for-ajax')),
@@ -130,7 +128,6 @@ function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_us
     $form['dropdown_second_fieldset']['submit']['#disabled'] = TRUE;
   }
 
-
   return $form;
 }
 
@@ -146,7 +143,6 @@ function ajax_example_dependent_dropdown_degrades_submit($form, &$form_state) {
       drupal_set_message(t('Your values have been submitted. dropdown_first=@first, dropdown_second=@second', array('@first' => $form_state['values']['dropdown_first'], '@second' => $form_state['values']['dropdown_second'])));
       return;
   }
-
   // 'Choose' or anything else will cause rebuild of the form and present
   // it again.
   $form_state['rebuild'] = TRUE;
@@ -162,7 +158,6 @@ function ajax_example_dependent_dropdown_degrades_first_callback($form, $form_st
 }
 
 
-
 /**
  * Example of a form with portions dynamically enabled or disabled, but
  * with graceful degradation in the case of no javascript.
@@ -183,7 +178,6 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
   // Attach the CSS and JS we need to show this with and without javascript.
   // Without javascript we need an extra "Choose" button, and this is
   // hidden when we have javascript enabled.
-
   $form['#attached']['css'] = array(
     drupal_get_path('module', 'ajax_example') . '/ajax_example.css',
   );
@@ -203,7 +197,6 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
       Try the <a href="!ajax_link">AJAX version</a> and the <a href="!non_ajax_link">simulated-non-AJAX version</a>.
     ', array('!ajax_link' => url('ajax_example/dynamic_sections'), '!non_ajax_link' => url('ajax_example/dynamic_sections_no_js') )) . '</div>',
   );
-
   $form['question_type_select'] = array(
     '#type' => 'select',
     '#title' => t('Question style'),
@@ -226,7 +219,6 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
   // actually turning off javascript in the browser. Removing the #ajax
   // element turns off AJAX behaviors on that element and as a result
   // ajax.js doesn't get loaded.
-
   if ($no_js_use) {
     // Remove the #ajax from the above, so ajax.js won't be loaded.
     unset($form['question_type_select']['#ajax']);
@@ -236,7 +228,6 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
   // that gets rebuilt.
   $form['questions_fieldset'] = array(
     '#type' => 'fieldset',
-
     // These provide the wrapper referred to in #ajax['wrapper'] above.
     '#prefix' => '<div id="questions-fieldset-wrapper">',
     '#suffix' => '</div>',
@@ -273,7 +264,6 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
           '#description' => t('Please type the correct answer to the question.'),
         );
         break;
-
     }
 
     $form['questions_fieldset']['submit'] = array(
@@ -281,13 +271,11 @@ function ajax_example_dynamic_sections($form, &$form_state, $no_js_use = FALSE)
       '#value' => t('Submit your answer'),
     );
   }
-
   return $form;
 }
 
 /**
  * Validation function for ajax_example_dynamic_sections().
- *
  */
 function ajax_example_dynamic_sections_validate($form, &$form_state) {
   $answer = $form_state['values']['question'];
@@ -303,7 +291,7 @@ function ajax_example_dynamic_sections_submit($form, &$form_state) {
   // This is only executed when a button is pressed, not when the AJAXified
   // select is changed.
   // Now handle the case of the next, previous, and submit buttons.
-  // only submit will result in actual submission, all others rebuild.
+  // Only submit will result in actual submission, all others rebuild.
   switch($form_state['triggering_element']['#value']) {
     case t('Submit your answer'): // Submit: We're done.
       $form_state['rebuild'] = FALSE;
@@ -342,7 +330,7 @@ function ajax_example_dynamic_sections_select_callback($form, $form_state) {
  * This example is a classic wizard, where a different and sequential form
  * is presented on each step of the form.
  *
- * In the AJAX version, form is replaced for each wizard section. In the
+ * In the AJAX version, the form is replaced for each wizard section. In the
  * multistep version, it causes a new page load.
  *
  * @param $form
@@ -359,7 +347,7 @@ function ajax_example_dynamic_sections_select_callback($form, $form_state) {
 function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) {
 
   // Provide a wrapper around the entire form, since we'll replace the whole
-  // thing.
+  // thing with each submit.
   $form['#prefix'] = '<div id="wizard-form-wrapper">';
   $form['#suffix'] = '</div>';
   $form['#tree'] = TRUE; // We want to deal with hierarchical form values.
@@ -370,6 +358,8 @@ function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) {
     . '</div>',
   );
 
+  // $form_state['storage'] has no specific drupal meaning, but it is
+  // traditional to keep variables for multistep forms there.
   $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step'];
   $form_state['storage']['step'] = $step;
 
@@ -399,6 +389,7 @@ function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) {
         '#required' => TRUE,
       );
       break;
+
     case 3:
       $form['step3'] = array(
         '#type' => 'fieldset',
@@ -426,7 +417,6 @@ function ajax_example_wizard($form, &$form_state, $no_js_use = FALSE) {
         'wrapper' => 'wizard-form-wrapper',
         'callback' => 'ajax_example_wizard_callback',
       ),
-
     );
   }
   if ($step > 1) {
@@ -476,12 +466,14 @@ function ajax_example_wizard_submit($form, &$form_state) {
 
   // Save away the current information.
   $current_step = 'step' . $form_state['storage']['step'];
-  $form_state['storage']['values'][$current_step] = $form_state['values'][$current_step];
+  if (!empty($form_state['values'][$current_step])) {
+    $form_state['storage']['values'][$current_step] = $form_state['values'][$current_step];
+  }
 
   // Increment or decrement the step as needed. Recover values if they exist.
   if ($form_state['triggering_element']['#value'] == t('Next step')) {
     $form_state['storage']['step']++;
-    // If values had already been entered for this step, recover them from
+    // If values have already been entered for this step, recover them from
     // $form_state['storage'] to pre-populate them.
     $step_name = 'step' . $form_state['storage']['step'];
     if (!empty($form_state['storage']['values'][$step_name])) {
@@ -510,13 +502,10 @@ function ajax_example_wizard_submit($form, &$form_state) {
   }
 
   // Otherwise, we still have work to do.
-
   $form_state['rebuild'] = TRUE;
 }
 
 
-//// AJAX add-more example, with graceful degradation.
-
 /**
  * This example shows a button to "add more" - add another textfield, and
  * the corresponding "remove" button.
@@ -538,7 +527,6 @@ function ajax_example_wizard_submit($form, &$form_state) {
  */
 
 function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) {
-
   $form['description'] = array(
     '#markup' => '<div>' . t('This example shows an add-more and a remove-last button. The <a href="!ajax">AJAX version</a> does it without page reloads; the <a href="!multistep">non-js version</a> is the same code but simulates a non-javascript environment, showing it with page reloads.',
       array('!ajax' => url('examples/ajax_example/add_more'), '!multistep' => url('examples/ajax_example/add_more_no_js')))
@@ -548,7 +536,6 @@ function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) {
   // Because we have many fields with the same values, we have to set
   // #tree to be able to access them.
   $form['#tree'] = TRUE;
-
   $form['names_fieldset'] = array(
     '#type' => 'fieldset',
     '#title' => t('People coming to the picnic'),
@@ -572,6 +559,8 @@ function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) {
     '#type' => 'submit',
     '#value' => t('Add one more'),
     '#submit' => array('ajax_example_add_more_add_one'),
+    // See the examples in ajax_example.module for more details on the
+    // properties of #ajax.
     '#ajax' => array(
       'callback' => 'ajax_example_add_more_callback',
       'wrapper' => 'names-fieldset-wrapper',
@@ -593,16 +582,13 @@ function ajax_example_add_more($form, &$form_state, $no_js_use = FALSE) {
     '#value' => t('Submit'),
   );
 
-
   // This simply allows us to demonstrate no-javascript use without
   // actually turning off javascript in the browser. Removing the #ajax
   // element turns off AJAX behaviors on that element and as a result
   // ajax.js doesn't get loaded.
-  // For demonstration only! You don't need this. It's just so you don't
-  // have to turn off javascript in your browser to test.
+  // For demonstration only! You don't need this.
   if ($no_js_use) {
     // Remove the #ajax from the above, so ajax.js won't be loaded.
-    // For demonstration only.
     if (!empty($form['names_fieldset']['remove_name']['#ajax'])) {
       unset($form['names_fieldset']['remove_name']['#ajax']);
     }
@@ -624,7 +610,7 @@ function ajax_example_add_more_callback($form, $form_state) {
 /**
  * Submit handler for the "add-one-more" button.
  *
- * It just increments the max counter and then causes a rebuild.
+ * It just increments the max counter and causes a rebuild.
  */
 function ajax_example_add_more_add_one($form, &$form_state) {
   $form_state['num_names']++;
@@ -646,7 +632,7 @@ function ajax_example_add_more_remove_one($form, &$form_state) {
 /**
  * Final submit handler.
  *
- * Reports to us what values were finally set.
+ * Reports what values were finally set.
  */
 function ajax_example_add_more_submit($form, &$form_state) {
   $output = t('These people are coming to the picnic: @names',
index 6c8a43e..ad77b36 100644 (file)
  * Demonstrates a clickable AJAX-enabled link.
  *
  * Because of the 'use-ajax' class applied here, the link submission is done
- * via AJAX.
+ * without a page refresh.
  *
- * This will not work if ajax.js is not loaded on the page.
+ * When using the AJAX framework outside the context of a form, you have to
+ * include ajax.js explicitly.
  * @return unknown_type
  */
 function ajax_example_render_link() {
-  drupal_add_js('misc/ajax.js');
+  // drupal_add_library is invoked automatically when a form element has the
+  // '#ajax' property, but since we are not rendering a form here, we have to
+  // do it ourselves.
+  drupal_add_library('system', 'drupal.ajax');
   $explanation = "
 The link below has the <i>use-ajax</i> class applied to it, so if
 javascript is enabled, ajax.js will try to submit it via an AJAX call instead
@@ -26,6 +30,9 @@ of a normal page load. The URL also contains the '/nojs/' magic string, which
 is stripped if javascript is enabled, allowing the server code to tell by the
 URL whether JS was enabled or not, letting it do different things based on that.";
   $output = "<div>" . t($explanation);
+  // The use-ajax class is special, so that the link will call without causing
+  // a page reload. Note the /nojs portion of the path - if javascript is
+  // enabled, this part will be stripped from the path before it is called.
   $link = l(t('Click here'), 'ajax_link_callback/nojs/', array('attributes' => array('class' => array('use-ajax'))));
   $output .= "<div>$link</div><div id='myDiv'></div>";
   return $output;
@@ -49,6 +56,8 @@ function ajax_link_response($type = 'ajax') {
   if ($type == 'ajax') {
     $output = t("This is some content delivered via AJAX");
     $commands = array();
+    // See ajax_example_advanced.inc for more details on the available commands
+    // and how to use them.
     $commands[] = ajax_command_append('#myDiv', $output);
     $page = array('#type' => 'ajax', '#commands' => $commands);
     ajax_deliver($page);