updated core to 7.58 (right after the site was hacked)
This commit is contained in:
17
sites/all/modules/examples/ajax_example/ajax_example.css
Normal file
17
sites/all/modules/examples/ajax_example/ajax_example.css
Normal file
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* @file
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/* Hides the next button when not degrading to non-javascript browser */
|
||||
html.js .next-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Makes the next/choose button align to the right of the select control */
|
||||
.form-item-dropdown-first, .form-item-question-type-select {
|
||||
display: inline-block;
|
||||
}
|
12
sites/all/modules/examples/ajax_example/ajax_example.info
Normal file
12
sites/all/modules/examples/ajax_example/ajax_example.info
Normal file
@ -0,0 +1,12 @@
|
||||
name = AJAX Example
|
||||
description = An example module showing how to use Drupal AJAX forms
|
||||
package = Example modules
|
||||
core = 7.x
|
||||
files[] = ajax_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"
|
||||
|
56
sites/all/modules/examples/ajax_example/ajax_example.install
Normal file
56
sites/all/modules/examples/ajax_example/ajax_example.install
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* AJAX Examples install file schema for ajax_example_form_node_form_alter()
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_schema().
|
||||
*/
|
||||
function ajax_example_schema() {
|
||||
$schema['ajax_example_node_form_alter'] = array(
|
||||
'description' => 'Stores example settings for nodes.',
|
||||
'fields' => array(
|
||||
'nid' => array(
|
||||
'type' => 'int',
|
||||
'unsigned' => TRUE,
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'The {node}.nid to store settings.',
|
||||
),
|
||||
'example_1' => array(
|
||||
'type' => 'int',
|
||||
'not null' => TRUE,
|
||||
'default' => 0,
|
||||
'description' => 'Node Form Example 1 checkbox',
|
||||
),
|
||||
'example_2' => array(
|
||||
'type' => 'varchar',
|
||||
'length' => 256,
|
||||
'not null' => FALSE,
|
||||
'default' => '',
|
||||
'description' => 'Node Form Example 2 textfield',
|
||||
),
|
||||
),
|
||||
'primary key' => array('nid'),
|
||||
'foreign keys' => array(
|
||||
'dnv_node' => array(
|
||||
'table' => 'node',
|
||||
'columns' => array('nid' => 'nid'),
|
||||
),
|
||||
),
|
||||
);
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the new ajax_example_node_form_alter table.
|
||||
*/
|
||||
function ajax_example_update_7100() {
|
||||
if (!db_table_exists('ajax_example_node_form_alter')) {
|
||||
$schema = ajax_example_schema();
|
||||
db_create_table('ajax_example_node_form_alter', $schema['ajax_example_node_form_alter']);
|
||||
return st('Created table ajax_example_node_form_alter');
|
||||
}
|
||||
}
|
29
sites/all/modules/examples/ajax_example/ajax_example.js
Normal file
29
sites/all/modules/examples/ajax_example/ajax_example.js
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* @file
|
||||
* 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.
|
||||
Drupal.behaviors.enableFormItemsForAjaxForms = {
|
||||
attach: function() {
|
||||
// If ajax is enabled.
|
||||
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,
|
||||
// we have AJAX disabled but JS turned on, so use this to simulate.
|
||||
if (!Drupal.ajax) {
|
||||
$('html.js .next-button').show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
693
sites/all/modules/examples/ajax_example/ajax_example.module
Normal file
693
sites/all/modules/examples/ajax_example/ajax_example.module
Normal file
@ -0,0 +1,693 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* AJAX Examples module file with basic examples.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ajax_example Example: AJAX
|
||||
* @ingroup examples
|
||||
* @{
|
||||
* These examples show basic AJAX concepts.
|
||||
*
|
||||
* General documentation is available at
|
||||
* @link ajax AJAX Framework documentation @endlink and at the
|
||||
* @link http://drupal.org/node/752056 AJAX Forms handbook page @endlink.
|
||||
*
|
||||
* The several examples here demonstrate basic AJAX usage.
|
||||
*/
|
||||
|
||||
// The Node Form Alter example needs to be in another file.
|
||||
module_load_include('inc', 'ajax_example', 'ajax_example_node_form_alter');
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*
|
||||
* Sets up calls to drupal_get_form() for all our example cases.
|
||||
*
|
||||
* @see menu_example.module
|
||||
* @see menu_example_menu()
|
||||
*/
|
||||
function ajax_example_menu() {
|
||||
$items = array();
|
||||
|
||||
$items['examples/ajax_example'] = array(
|
||||
'title' => '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' => '<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 '@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' => '<div id="checkboxes-div">',
|
||||
'#suffix' => '</div>',
|
||||
'#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' => '<div id="textfields">',
|
||||
'#suffix' => '</div>',
|
||||
'#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' => '<div id="box">',
|
||||
'#suffix' => '</div>',
|
||||
'#markup' => '<h1>Initial markup for box</h1>',
|
||||
);
|
||||
|
||||
$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' => '<div id="dropdown-second-replace">',
|
||||
'#suffix' => '</div>',
|
||||
// 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".
|
||||
*/
|
75
sites/all/modules/examples/ajax_example/ajax_example.test
Normal file
75
sites/all/modules/examples/ajax_example/ajax_example.test
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Test ajax example module.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functional tests for AJAX Example module.
|
||||
*
|
||||
* @ingroup ajax_example
|
||||
*/
|
||||
class AjaxExampleTestCase extends DrupalWebTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Ajax example',
|
||||
'description' => 'Checks behavior of the Ajax Example',
|
||||
'group' => 'Examples',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable module.
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp('ajax_example');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the non-JS version of the "Dynamic Sections" example.
|
||||
*/
|
||||
public function testDynamicSectionsNoJs() {
|
||||
// The path to the example form.
|
||||
$path = 'examples/ajax_example/dynamic_sections_no_js';
|
||||
// Confirmation text for right and wrong answers.
|
||||
$wrong = t('Wrong answer. Try again. (Hint: The right answer is "George Washington".)');
|
||||
$right = t('You got the right answer: George Washington');
|
||||
// For each question style, choose some parameters.
|
||||
$params = array(
|
||||
t('Multiple Choice') => array(
|
||||
'value' => t('Abraham Lincoln'),
|
||||
'answer' => t('Abraham Lincoln'),
|
||||
'response' => $wrong,
|
||||
),
|
||||
t('True/False') => array(
|
||||
'value' => t('George Washington'),
|
||||
'answer' => t('George Washington'),
|
||||
'response' => $right,
|
||||
),
|
||||
t('Fill-in-the-blanks') => array(
|
||||
'value' => NULL,
|
||||
'answer' => t('George Washington'),
|
||||
'response' => $right,
|
||||
),
|
||||
);
|
||||
foreach ($params as $style => $q_and_a) {
|
||||
// Submit the initial form.
|
||||
$edit = array('question_type_select' => $style);
|
||||
$this->drupalPost($path, $edit, t('Choose'));
|
||||
$this->assertResponse(200, format_string('Question style "@style" selected.', array('@style' => $style)));
|
||||
// For convenience, make variables out of the entries in $QandA.
|
||||
extract($q_and_a);
|
||||
// Check for the expected input field.
|
||||
$this->assertFieldByName('question', $value);
|
||||
// Now, submit the dynamically generated form.
|
||||
$edit = array('question' => $answer);
|
||||
$this->drupalPost(NULL, $edit, t('Submit your answer'));
|
||||
$this->assertRaw($response, 'Dynamic form has been submitted.');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,400 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* AJAX Commands examples.
|
||||
*
|
||||
* This demonstrates each of the
|
||||
* new AJAX commands. This is consolidated into a dense page because
|
||||
* it's advanced material and because it would spread itself all over creation
|
||||
* otherwise.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Form to display the AJAX Commands.
|
||||
*/
|
||||
function ajax_example_advanced_commands($form, &$form_state) {
|
||||
$form = array();
|
||||
$form['intro'] = array(
|
||||
'#type' => 'markup',
|
||||
'#markup' => t("<div>Demonstrates how AJAX commands can be used.</div>"),
|
||||
);
|
||||
|
||||
// Shows the 'after' command with a callback generating commands.
|
||||
$form['after_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("This shows the Ajax 'after' command. Click to put something below the div that says 'Something can be inserted after this'"),
|
||||
);
|
||||
|
||||
$form['after_command_example_fieldset']['after_command_example'] = array(
|
||||
'#value' => t("AJAX 'After': Click to put something after the div"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_after_callback',
|
||||
),
|
||||
'#suffix' => "<div id='after_div'>Something can be inserted after this</div>
|
||||
<div id='after_status'>'After' Command Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the 'alert' command.
|
||||
$form['alert_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Demonstrates the AJAX 'alert' command. Click the button."),
|
||||
);
|
||||
$form['alert_command_example_fieldset']['alert_command_example'] = array(
|
||||
'#value' => t("AJAX 'Alert': Click to alert"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_alert_callback',
|
||||
),
|
||||
);
|
||||
|
||||
// Shows the 'append' command.
|
||||
$form['append_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("This shows the Ajax 'append' command. Click to put something below the div that says 'Something can be inserted after this'"),
|
||||
);
|
||||
|
||||
$form['append_command_example_fieldset']['append_command_example'] = array(
|
||||
'#value' => t("AJAX 'Append': Click to append something"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_append_callback',
|
||||
),
|
||||
'#suffix' => "<div id='append_div'>Something can be appended inside this div... </div>
|
||||
<div id='append_status'>'After' Command Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the 'before' command.
|
||||
$form['before_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("This shows the Ajax 'before' command."),
|
||||
);
|
||||
|
||||
$form['before_command_example_fieldset']['before_command_example'] = array(
|
||||
'#value' => t("AJAX 'before': Click to put something before the div"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_before_callback',
|
||||
),
|
||||
'#suffix' => "<div id='before_div'>Something can be inserted before this</div>
|
||||
<div id='before_status'>'before' Command Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the 'changed' command.
|
||||
$form['changed_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#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(
|
||||
'#title' => t("AJAX changed: If checked, div is marked as changed."),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => FALSE,
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_changed_callback',
|
||||
),
|
||||
'#suffix' => "<div id='changed_div'> <div id='changed_div_mark_this'>This div can be marked as changed or not.</div></div>
|
||||
<div id='changed_status'>Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the AJAX 'css' command.
|
||||
$form['css_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Demonstrates the AJAX 'css' command."),
|
||||
);
|
||||
|
||||
$form['css_command_example_fieldset']['css_command_example'] = array(
|
||||
'#title' => t("AJAX CSS: Choose the color you'd like the '#box' div to be."),
|
||||
'#type' => 'select',
|
||||
// '#default_value' => 'green',
|
||||
'#options' => array('green' => 'green', 'blue' => 'blue'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_css_callback',
|
||||
),
|
||||
'#suffix' => "<div id='css_div' style='height: 50px; width: 50px; border: 1px solid black'> box</div>
|
||||
<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(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Demonstrates the AJAX 'data' command."),
|
||||
);
|
||||
|
||||
$form['data_command_example_fieldset']['data_command_example'] = array(
|
||||
'#title' => t("AJAX data: Set a key/value pair on a selector."),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => 'color=green',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_data_callback',
|
||||
),
|
||||
'#suffix' => "<div id='data_div'>This div should have key='time'/value='a time string' attached.</div>
|
||||
<div id='data_status'>Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the AJAX 'html' command.
|
||||
$form['html_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Demonstrates the AJAX 'html' command."),
|
||||
);
|
||||
|
||||
$form['html_command_example_fieldset']['html_command_example'] = array(
|
||||
'#title' => t("AJAX html: Replace the HTML in a selector."),
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => 'new value',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_html_callback',
|
||||
),
|
||||
'#suffix' => "<div id='html_div'>Original contents</div>
|
||||
<div id='html_status'>Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the AJAX 'prepend' command.
|
||||
$form['prepend_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("This shows the AJAX 'prepend' command. Click to put something below the div that says 'Something can be inserted after this'"),
|
||||
);
|
||||
|
||||
$form['prepend_command_example_fieldset']['prepend_command_example'] = array(
|
||||
'#value' => t("AJAX 'prepend': Click to prepend something"),
|
||||
'#type' => 'submit',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_prepend_callback',
|
||||
),
|
||||
'#suffix' => "<div id='prepend_div'>Something can be prepended to this div... </div>
|
||||
<div id='prepend_status'>'After' Command Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Shows the AJAX 'remove' command.
|
||||
$form['remove_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Shows the Ajax 'remove' command."),
|
||||
);
|
||||
|
||||
$form['remove_command_example_fieldset']['remove_command_example'] = array(
|
||||
'#title' => t("AJAX 'remove': Check to remove text. Uncheck to add it back."),
|
||||
'#type' => 'checkbox',
|
||||
'#default_value' => FALSE,
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_remove_callback',
|
||||
),
|
||||
'#suffix' => "<div id='remove_div'><div id='remove_text'>text to be removed</div></div>
|
||||
<div id='remove_status'>'After' Command Status: Unknown</div>",
|
||||
);
|
||||
|
||||
// Show off the AJAX 'restripe' command. Also shows classic AJAX replacement
|
||||
// on the "how many rows" processing.
|
||||
$form['restripe_command_example_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t("Demonstrates the Ajax 'restripe' command."),
|
||||
);
|
||||
|
||||
$form['restripe_command_example_fieldset']['restripe_num_rows'] = array(
|
||||
'#type' => 'select',
|
||||
'#default_value' => !empty($form_state['values']['restripe_num_rows']) ? $form_state['values']['restripe_num_rows'] : 1,
|
||||
'#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_restripe_num_rows',
|
||||
'method' => 'replace',
|
||||
'wrapper' => 'restripe_table',
|
||||
),
|
||||
);
|
||||
$form['restripe_command_example_fieldset']['restripe_restripe'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("Restripe the table"),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_advanced_commands_restripe_callback',
|
||||
),
|
||||
'#suffix' => "<div id='restripe_div'>
|
||||
<table id='restripe_table' style='border: 1px solid black' >
|
||||
<tr id='table-first'><td>first row</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
<div id='restripe_status'>'Restripe' Command Status: Unknown</div>",
|
||||
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'after'.
|
||||
*
|
||||
* @see ajax_command_after()
|
||||
*/
|
||||
function ajax_example_advanced_commands_after_callback($form, $form_state) {
|
||||
$selector = '#after_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_after($selector, "New 'after'...");
|
||||
$commands[] = ajax_command_replace("#after_status", "<div id='after_status'>Updated after_command_example " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'alert'.
|
||||
*
|
||||
* @see ajax_command_alert()
|
||||
*/
|
||||
function ajax_example_advanced_commands_alert_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_alert("Alert requested at " . date('r'));
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'append'.
|
||||
*
|
||||
* @see ajax_command_append()
|
||||
*/
|
||||
function ajax_example_advanced_commands_append_callback($form, $form_state) {
|
||||
$selector = '#append_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_append($selector, "Stuff...");
|
||||
$commands[] = ajax_command_replace("#append_status", "<div id='append_status'>Updated append_command_example " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'before'.
|
||||
*
|
||||
* @see ajax_command_before()
|
||||
*/
|
||||
function ajax_example_advanced_commands_before_callback($form, $form_state) {
|
||||
$selector = '#before_div';
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_before($selector, "New 'before'...");
|
||||
$commands[] = ajax_command_replace("#before_status", "<div id='before_status'>Updated before_command_example " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'changed'.
|
||||
*
|
||||
* @see ajax_command_changed()
|
||||
*/
|
||||
function ajax_example_advanced_commands_changed_callback($form, $form_state) {
|
||||
$checkbox_value = $form_state['values']['changed_command_example'];
|
||||
$checkbox_value_string = $checkbox_value ? "TRUE" : "FALSE";
|
||||
$commands = array();
|
||||
if ($checkbox_value) {
|
||||
$commands[] = ajax_command_changed('#changed_div', '#changed_div_mark_this');
|
||||
}
|
||||
else {
|
||||
$commands[] = ajax_command_replace('#changed_div', "<div id='changed_div'> <div id='changed_div_mark_this'>This div can be marked as changed or not.</div></div>");
|
||||
}
|
||||
$commands[] = ajax_command_replace("#changed_status", "<div id='changed_status'>Updated changed_command_example to $checkbox_value_string: " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'css'.
|
||||
*
|
||||
* @see ajax_command_css()
|
||||
*/
|
||||
function ajax_example_advanced_commands_css_callback($form, $form_state) {
|
||||
$selector = '#css_div';
|
||||
$color = $form_state['values']['css_command_example'];
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_css($selector, array('background-color' => $color));
|
||||
$commands[] = ajax_command_replace("#css_status", "<div id='css_status'>Updated css_command_example to '{$color}' " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'data'.
|
||||
*
|
||||
* @see ajax_command_data()
|
||||
*/
|
||||
function ajax_example_advanced_commands_data_callback($form, $form_state) {
|
||||
$selector = '#data_div';
|
||||
$text = $form_state['values']['data_command_example'];
|
||||
list($key, $value) = preg_split('/=/', $text);
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_data($selector, $key, $value);
|
||||
$commands[] = ajax_command_replace("#data_status", "<div id='data_status'>Updated data_command_example with key=$key, value=$value; " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'html'.
|
||||
*
|
||||
* @see ajax_command_html()
|
||||
*/
|
||||
function ajax_example_advanced_commands_html_callback($form, $form_state) {
|
||||
$text = $form_state['values']['html_command_example'];
|
||||
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_html('#html_div', $text);
|
||||
$commands[] = ajax_command_replace("#html_status", "<div id='html_status'>Updated html_command_example with text=$text; " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'prepend'.
|
||||
*
|
||||
* @see ajax_command_prepend()
|
||||
*/
|
||||
function ajax_example_advanced_commands_prepend_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_prepend('#prepend_div', "Prepended Stuff...");
|
||||
$commands[] = ajax_command_replace("#prepend_status", "<div id='prepend_status'>Updated prepend_command_example " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'remove'.
|
||||
*
|
||||
* @see ajax_command_remove()
|
||||
*/
|
||||
function ajax_example_advanced_commands_remove_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$should_remove = $form_state['values']['remove_command_example'];
|
||||
$should_remove_string = $should_remove ? 'TRUE' : 'FALSE';
|
||||
if ($should_remove) {
|
||||
$commands[] = ajax_command_remove('#remove_text');
|
||||
}
|
||||
else {
|
||||
$commands[] = ajax_command_html('#remove_div', "<div id='remove_text'>text to be removed</div>");
|
||||
}
|
||||
$commands[] = ajax_command_replace("#remove_status", "<div id='remove_status'>Updated remove_command_example (value={$should_remove_string} " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'restripe'.
|
||||
*
|
||||
* Rebuilds the table with the selected number of rows.
|
||||
*/
|
||||
function ajax_example_advanced_commands_restripe_num_rows($form, $form_state) {
|
||||
$num_rows = $form_state['values']['restripe_num_rows'];
|
||||
$output = "<table id='restripe_table' style='border: 1px solid black'>";
|
||||
for ($i = 1; $i <= $num_rows; $i++) {
|
||||
$output .= "<tr><td>Row $i</td></tr>";
|
||||
}
|
||||
$output .= "</table>";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for 'restripe'.
|
||||
*
|
||||
* @see ajax_command_restripe()
|
||||
*/
|
||||
function ajax_example_advanced_commands_restripe_callback($form, $form_state) {
|
||||
$commands = array();
|
||||
$commands[] = ajax_command_restripe('#restripe_table');
|
||||
$commands[] = ajax_command_replace("#restripe_status", "<div id='restripe_status'>Restriped table " . date('r') . "</div>");
|
||||
return array('#type' => 'ajax', '#commands' => $commands);
|
||||
}
|
@ -0,0 +1,458 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* ajax_example_autocomplete.inc
|
||||
*
|
||||
* Demonstrates usage of the Form API's autocomplete features.
|
||||
*
|
||||
* This file provides three examples in increasing complexity:
|
||||
* - A simple username autocomplete (usernames are unique, so little effort is
|
||||
* required)
|
||||
* - A node title autocomplete (titles are not unique, so we have to find the
|
||||
* nid and stash it in the field)
|
||||
* - A username autocomplete that updates a node title autocomplete with a
|
||||
* changed #autocomplete_path so that the #autocomplete_path can have
|
||||
* context (the username to use in the search).
|
||||
*/
|
||||
|
||||
/**
|
||||
* A simple autocomplete form which just looks up usernames in the user table.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form.
|
||||
*
|
||||
* @return array
|
||||
* Form array.
|
||||
*/
|
||||
function ajax_example_simple_autocomplete($form, &$form_state) {
|
||||
|
||||
$form['info'] = array(
|
||||
'#markup' => '<div>' . t("This example does a simplest possible autocomplete by username. You'll need a few users on your system for it to make sense.") . '</div>',
|
||||
);
|
||||
|
||||
$form['user'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Choose a user (or a people, depending on your usage preference)'),
|
||||
// The autocomplete path is provided in hook_menu in ajax_example.module.
|
||||
'#autocomplete_path' => 'examples/ajax_example/simple_user_autocomplete_callback',
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a copy of user_autocomplete().
|
||||
*
|
||||
* It works simply by searching usernames (and of course in Drupal usernames
|
||||
* are unique, so can be used for identifying a record.)
|
||||
*
|
||||
* The returned $matches array has
|
||||
* * key: string which will be displayed once the autocomplete is selected
|
||||
* * value: the value which will is displayed in the autocomplete pulldown.
|
||||
*
|
||||
* In the simplest cases (see user_autocomplete()) these are the same, and
|
||||
* nothing needs to be done. However, more more complicated autocompletes
|
||||
* require more work. Here we demonstrate the difference by displaying the UID
|
||||
* along with the username in the dropdown.
|
||||
*
|
||||
* In the end, though, we'll be doing something with the value that ends up in
|
||||
* the textfield, so it needs to uniquely identify the record we want to access.
|
||||
* This is demonstrated in ajax_example_unique_autocomplete().
|
||||
*
|
||||
* @param string $string
|
||||
* The string that will be searched.
|
||||
*/
|
||||
function ajax_example_simple_user_autocomplete_callback($string = "") {
|
||||
$matches = array();
|
||||
if ($string) {
|
||||
$result = db_select('users')
|
||||
->fields('users', array('name', 'uid'))
|
||||
->condition('name', db_like($string) . '%', 'LIKE')
|
||||
->range(0, 10)
|
||||
->execute();
|
||||
foreach ($result as $user) {
|
||||
// In the simplest case (see user_autocomplete), the key and the value are
|
||||
// the same. Here we'll display the uid along with the username in the
|
||||
// dropdown.
|
||||
$matches[$user->name] = check_plain($user->name) . " (uid=$user->uid)";
|
||||
}
|
||||
}
|
||||
|
||||
drupal_json_output($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* An autocomplete form to look up nodes by title.
|
||||
*
|
||||
* An autocomplete form which looks up nodes by title in the node table,
|
||||
* but must keep track of the nid, because titles are certainly not guaranteed
|
||||
* to be unique.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*
|
||||
* * @return array
|
||||
* Form array.
|
||||
*/
|
||||
function ajax_example_unique_autocomplete($form, &$form_state) {
|
||||
|
||||
$form['info'] = array(
|
||||
'#markup' => '<div>' . t("This example does a node autocomplete by title. The difference between this and a username autocomplete is that the node title may not be unique, so we have to use the nid for uniqueness, placing it in a parseable location in the textfield.") . '</div>',
|
||||
);
|
||||
|
||||
$form['node'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Choose a node by title'),
|
||||
// The autocomplete path is provided in hook_menu in ajax_example.module.
|
||||
'#autocomplete_path' => 'examples/ajax_example/unique_node_autocomplete_callback',
|
||||
);
|
||||
|
||||
$form['actions'] = array(
|
||||
'#type' => 'actions',
|
||||
);
|
||||
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Node title validation handler.
|
||||
*
|
||||
* Validate handler to convert our string like "Some node title [3325]" into a
|
||||
* nid.
|
||||
*
|
||||
* In case the user did not actually use the autocomplete or have a valid string
|
||||
* there, we'll try to look up a result anyway giving it our best guess.
|
||||
*
|
||||
* Since the user chose a unique node, we must now use the same one in our
|
||||
* submit handler, which means we need to look in the string for the nid.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*/
|
||||
function ajax_example_unique_autocomplete_validate($form, &$form_state) {
|
||||
$title = $form_state['values']['node'];
|
||||
$matches = array();
|
||||
|
||||
// This preg_match() looks for the last pattern like [33334] and if found
|
||||
// extracts the numeric portion.
|
||||
$result = preg_match('/\[([0-9]+)\]$/', $title, $matches);
|
||||
if ($result > 0) {
|
||||
// If $result is nonzero, we found a match and can use it as the index into
|
||||
// $matches.
|
||||
$nid = $matches[$result];
|
||||
// Verify that it's a valid nid.
|
||||
$node = node_load($nid);
|
||||
if (empty($node)) {
|
||||
form_error($form['node'], t('Sorry, no node with nid %nid can be found', array('%nid' => $nid)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// BUT: Not everybody will have javascript turned on, or they might hit ESC
|
||||
// and not use the autocomplete values offered. In that case, we can attempt
|
||||
// to come up with a useful value. This is not absolutely necessary, and we
|
||||
// *could* just emit a form_error() as below.
|
||||
else {
|
||||
$nid = db_select('node')
|
||||
->fields('node', array('nid'))
|
||||
->condition('title', db_like($title) . '%', 'LIKE')
|
||||
->range(0, 1)
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
// Now, if we somehow found a nid, assign it to the node. If we failed, emit
|
||||
// an error.
|
||||
if (!empty($nid)) {
|
||||
$form_state['values']['node'] = $nid;
|
||||
}
|
||||
else {
|
||||
form_error($form['node'], t('Sorry, no node starting with %title can be found', array('%title' => $title)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for node lookup unique autocomplete example.
|
||||
*
|
||||
* Here the nid has already been placed in $form_state['values']['node'] by the
|
||||
* validation handler.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*/
|
||||
function ajax_example_unique_autocomplete_submit($form, &$form_state) {
|
||||
$node = node_load($form_state['values']['node']);
|
||||
drupal_set_message(t('You found node %nid with title %title', array('%nid' => $node->nid, '%title' => $node->title)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocomplete callback for nodes by title.
|
||||
*
|
||||
* Searches for a node by title, but then identifies it by nid, so the actual
|
||||
* returned value can be used later by the form.
|
||||
*
|
||||
* The returned $matches array has
|
||||
* - key: The title, with the identifying nid in brackets, like "Some node
|
||||
* title [3325]"
|
||||
* - value: the title which will is displayed in the autocomplete pulldown.
|
||||
*
|
||||
* Note that we must use a key style that can be parsed successfully and
|
||||
* unambiguously. For example, if we might have node titles that could have
|
||||
* [3325] in them, then we'd have to use a more restrictive token.
|
||||
*
|
||||
* @param string $string
|
||||
* The string that will be searched.
|
||||
*/
|
||||
function ajax_example_unique_node_autocomplete_callback($string = "") {
|
||||
$matches = array();
|
||||
if ($string) {
|
||||
$result = db_select('node')
|
||||
->fields('node', array('nid', 'title'))
|
||||
->condition('title', db_like($string) . '%', 'LIKE')
|
||||
->range(0, 10)
|
||||
->execute();
|
||||
foreach ($result as $node) {
|
||||
$matches[$node->title . " [$node->nid]"] = check_plain($node->title);
|
||||
}
|
||||
}
|
||||
|
||||
drupal_json_output($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search by title and author.
|
||||
*
|
||||
* In this example, we'll look up nodes by title, but we want only nodes that
|
||||
* have been authored by a particular user. That means that we'll have to make
|
||||
* an autocomplete function which takes a username as an argument, and use
|
||||
* #ajax to change the #autocomplete_path based on the selected user.
|
||||
*
|
||||
* Although the implementation of the validate handler may look complex, it's
|
||||
* just ambitious. The idea here is:
|
||||
* 1. Autcomplete to get a valid username.
|
||||
* 2. Use #ajax to update the node element with a #autocomplete_callback that
|
||||
* gives the context for the username.
|
||||
* 3. Do an autcomplete on the node field that is limited by the username.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*/
|
||||
function ajax_example_node_by_author_autocomplete($form, &$form_state) {
|
||||
|
||||
$form['intro'] = array(
|
||||
'#markup' => '<div>' . t("This example uses a user autocomplete to dynamically change a node title autocomplete using #ajax.
|
||||
This is a way to get past the fact that we have no other way to provide context to the autocomplete function.
|
||||
It won't work very well unless you have a few users who have created some content that you can search for.") . '</div>',
|
||||
);
|
||||
|
||||
$form['author'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Choose the username that authored nodes you are interested in'),
|
||||
// Since we just need simple user lookup, we can use the simplest function
|
||||
// of them all, user_autocomplete().
|
||||
'#autocomplete_path' => 'user/autocomplete',
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_node_by_author_ajax_callback',
|
||||
'wrapper' => 'autocomplete-by-node-ajax-replace',
|
||||
),
|
||||
);
|
||||
|
||||
// This form element with autocomplete will be replaced by #ajax whenever the
|
||||
// author changes, allowing the search to be limited by user.
|
||||
$form['node'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Choose a node by title'),
|
||||
'#prefix' => '<div id="autocomplete-by-node-ajax-replace">',
|
||||
'#suffix' => '</div>',
|
||||
'#disabled' => TRUE,
|
||||
);
|
||||
|
||||
// When the author changes in the author field, we'll change the
|
||||
// autocomplete_path to match.
|
||||
if (!empty($form_state['values']['author'])) {
|
||||
$author = user_load_by_name($form_state['values']['author']);
|
||||
if (!empty($author)) {
|
||||
$autocomplete_path = 'examples/ajax_example/node_by_author_autocomplete/' . $author->uid;
|
||||
$form['node']['#autocomplete_path'] = $autocomplete_path;
|
||||
$form['node']['#title'] = t('Choose a node title authored by %author', array('%author' => $author->name));
|
||||
$form['node']['#disabled'] = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
$form['actions'] = array(
|
||||
'#type' => 'actions',
|
||||
);
|
||||
|
||||
$form['actions']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback for author form element.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*/
|
||||
function ajax_example_node_by_author_ajax_callback($form, $form_state) {
|
||||
return $form['node'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate handler to convert our title string into a nid.
|
||||
*
|
||||
* In case the user did not actually use the autocomplete or have a valid string
|
||||
* there, we'll try to look up a result anyway giving it our best guess.
|
||||
*
|
||||
* Since the user chose a unique node, we must now use the same one in our
|
||||
* submit handler, which means we need to look in the string for the nid.
|
||||
*
|
||||
* This handler looks complex because it's ambitious (and tries to punt and
|
||||
* find a node if they've entered a valid username and part of a title), but
|
||||
* you *could* just do a form_error() if nothing were found, forcing people to
|
||||
* use the autocomplete to look up the relevant items.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*/
|
||||
function ajax_example_node_by_author_autocomplete_validate($form, &$form_state) {
|
||||
$title = $form_state['values']['node'];
|
||||
$author = $form_state['values']['author'];
|
||||
$matches = array();
|
||||
|
||||
// We must have a valid user.
|
||||
$account = user_load_by_name($author);
|
||||
if (empty($account)) {
|
||||
form_error($form['author'], t('You must choose a valid author username'));
|
||||
return;
|
||||
}
|
||||
// This preg_match() looks for the last pattern like [33334] and if found
|
||||
// extracts the numeric portion.
|
||||
$result = preg_match('/\[([0-9]+)\]$/', $title, $matches);
|
||||
if ($result > 0) {
|
||||
// If $result is nonzero, we found a match and can use it as the index into
|
||||
// $matches.
|
||||
$nid = $matches[$result];
|
||||
// Verify that it's a valid nid.
|
||||
$node = node_load($nid);
|
||||
if (empty($node)) {
|
||||
form_error($form['node'], t('Sorry, no node with nid %nid can be found', array('%nid' => $nid)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// BUT: Not everybody will have javascript turned on, or they might hit ESC
|
||||
// and not use the autocomplete values offered. In that case, we can attempt
|
||||
// to come up with a useful value. This is not absolutely necessary, and we
|
||||
// *could* just emit a form_error() as below. Here we'll find the *first*
|
||||
// matching title and assume that is adequate.
|
||||
else {
|
||||
$nid = db_select('node')
|
||||
->fields('node', array('nid'))
|
||||
->condition('uid', $account->uid)
|
||||
->condition('title', db_like($title) . '%', 'LIKE')
|
||||
->range(0, 1)
|
||||
->execute()
|
||||
->fetchField();
|
||||
}
|
||||
|
||||
// Now, if we somehow found a nid, assign it to the node. If we failed, emit
|
||||
// an error.
|
||||
if (!empty($nid)) {
|
||||
$form_state['values']['node'] = $nid;
|
||||
}
|
||||
else {
|
||||
form_error($form['node'], t('Sorry, no node starting with %title can be found', array('%title' => $title)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for node lookup unique autocomplete example.
|
||||
*
|
||||
* Here the nid has already been placed in $form_state['values']['node'] by the
|
||||
* validation handler.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form state.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*/
|
||||
function ajax_example_node_by_author_autocomplete_submit($form, &$form_state) {
|
||||
$node = node_load($form_state['values']['node']);
|
||||
$account = user_load($node->uid);
|
||||
drupal_set_message(t('You found node %nid with title !title_link, authored by !user_link',
|
||||
array(
|
||||
'%nid' => $node->nid,
|
||||
'!title_link' => l($node->title, 'node/' . $node->nid),
|
||||
'!user_link' => theme('username', array('account' => $account)),
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocomplete callback for nodes by title but limited by author.
|
||||
*
|
||||
* Searches for a node by title given the passed-in author username.
|
||||
*
|
||||
* The returned $matches array has
|
||||
* - key: The title, with the identifying nid in brackets, like "Some node
|
||||
* title [3325]"
|
||||
* - value: the title which will is displayed in the autocomplete pulldown.
|
||||
*
|
||||
* Note that we must use a key style that can be parsed successfully and
|
||||
* unambiguously. For example, if we might have node titles that could have
|
||||
* [3325] in them, then we'd have to use a more restrictive token.
|
||||
*
|
||||
* @param int $author_uid
|
||||
* The author username to limit the search.
|
||||
* @param string $string
|
||||
* The string that will be searched.
|
||||
*/
|
||||
function ajax_example_node_by_author_node_autocomplete_callback($author_uid, $string = "") {
|
||||
$matches = array();
|
||||
if ($author_uid > 0 && trim($string)) {
|
||||
$result = db_select('node')
|
||||
->fields('node', array('nid', 'title'))
|
||||
->condition('uid', $author_uid)
|
||||
->condition('title', db_like($string) . '%', 'LIKE')
|
||||
->range(0, 10)
|
||||
->execute();
|
||||
foreach ($result as $node) {
|
||||
$matches[$node->title . " [$node->nid]"] = check_plain($node->title);
|
||||
}
|
||||
}
|
||||
|
||||
drupal_json_output($matches);
|
||||
}
|
@ -0,0 +1,668 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Demonstrations of AJAX with graceful degradation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ajax_degradation_example Example: AJAX Graceful Degradation
|
||||
* @ingroup examples
|
||||
* @{
|
||||
* These examples show AJAX with graceful degradation when Javascript is not
|
||||
* available.
|
||||
*
|
||||
* In each of these the key idea is that the form is rebuilt different ways
|
||||
* depending on form input. In order to accomplish that, the formbuilder
|
||||
* function is in charge of almost all logic.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Dropdown form based on previous choices.
|
||||
*
|
||||
* 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. Gracefully degrades if no javascript.
|
||||
*
|
||||
* A bit of CSS and javascript is required. The CSS hides the "add more" button
|
||||
* 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 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
|
||||
* ways to call this form, one normal ($no_js_use = FALSE) and one simulating
|
||||
* Javascript disabled ($no_js_use = TRUE).
|
||||
*/
|
||||
function ajax_example_dependent_dropdown_degrades($form, &$form_state, $no_js_use = FALSE) {
|
||||
// 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);
|
||||
|
||||
// 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',
|
||||
);
|
||||
$form['#attached']['js'] = array(
|
||||
drupal_get_path('module', 'ajax_example') . '/ajax_example.js',
|
||||
);
|
||||
|
||||
$form['dropdown_first_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
);
|
||||
$form['dropdown_first_fieldset']['dropdown_first'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => 'Instrument Type',
|
||||
'#options' => $options_first,
|
||||
'#attributes' => array('class' => array('enabled-for-ajax')),
|
||||
|
||||
// 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',
|
||||
),
|
||||
);
|
||||
|
||||
// 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. This is for demonstration purposes only.
|
||||
if ($no_js_use) {
|
||||
unset($form['dropdown_first_fieldset']['dropdown_first']['#ajax']);
|
||||
}
|
||||
|
||||
// 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'),
|
||||
'#attributes' => array('class' => array('next-button')),
|
||||
);
|
||||
|
||||
$form['dropdown_second_fieldset'] = array(
|
||||
'#type' => 'fieldset',
|
||||
);
|
||||
$form['dropdown_second_fieldset']['dropdown_second'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => $options_first[$selected] . ' ' . t('Instruments'),
|
||||
'#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),
|
||||
// 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')),
|
||||
);
|
||||
|
||||
// Disable dropdown_second if a selection has not been made on dropdown_first.
|
||||
if (empty($form_state['values']['dropdown_first'])) {
|
||||
$form['dropdown_second_fieldset']['dropdown_second']['#disabled'] = TRUE;
|
||||
$form['dropdown_second_fieldset']['dropdown_second']['#description'] = t('You must make your choice on the first dropdown before changing this second one.');
|
||||
$form['dropdown_second_fieldset']['submit']['#disabled'] = TRUE;
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for ajax_example_dependent_dropdown_degrades().
|
||||
*/
|
||||
function ajax_example_dependent_dropdown_degrades_submit($form, &$form_state) {
|
||||
|
||||
// Now handle the case of the next, previous, and submit buttons.
|
||||
// only submit will result in actual submission, all others rebuild.
|
||||
switch ($form_state['triggering_element']['#value']) {
|
||||
case t('OK'):
|
||||
// Submit: We're done.
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects just the second dropdown to be returned for re-rendering.
|
||||
*
|
||||
* @return array
|
||||
* Renderable array (the second dropdown).
|
||||
*/
|
||||
function ajax_example_dependent_dropdown_degrades_first_callback($form, $form_state) {
|
||||
return $form['dropdown_second_fieldset']['dropdown_second'];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dynamically-enabled form with graceful no-JS degradation.
|
||||
*
|
||||
* Example of a form with portions dynamically enabled or disabled, but
|
||||
* with graceful degradation in the case of no javascript.
|
||||
*
|
||||
* The idea here is that certain parts of the form don't need to be displayed
|
||||
* unless a given option is selected, but then they should be displayed and
|
||||
* configured.
|
||||
*
|
||||
* The third $no_js_use argument is strictly for demonstrating operation
|
||||
* without javascript, without making the user/developer turn off javascript.
|
||||
*/
|
||||
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',
|
||||
);
|
||||
$form['#attached']['js'] = array(
|
||||
drupal_get_path('module', 'ajax_example') . '/ajax_example.js',
|
||||
);
|
||||
$form['description'] = array(
|
||||
'#type' => 'markup',
|
||||
'#markup' => '<div>' . t('This example demonstrates a form which dynamically creates various sections based on the configuration in the form.
|
||||
It deliberately allows graceful degradation to a non-javascript environment.
|
||||
In a non-javascript environment, the "Choose" button next to the select control
|
||||
is displayed; in a javascript environment it is hidden by the module CSS.
|
||||
<br/><br/>The basic idea here is that the form is built up based on
|
||||
the selection in the question_type_select field, and it is built the same
|
||||
whether we are in a javascript/AJAX environment or not.
|
||||
<br/><br/>
|
||||
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('examples/ajax_example/dynamic_sections'), '!non_ajax_link' => url('examples/ajax_example/dynamic_sections_no_js'))) . '</div>',
|
||||
);
|
||||
$form['question_type_select'] = array(
|
||||
'#type' => 'select',
|
||||
'#title' => t('Question style'),
|
||||
'#options' => drupal_map_assoc(
|
||||
array(
|
||||
t('Choose question style'),
|
||||
t('Multiple Choice'),
|
||||
t('True/False'),
|
||||
t('Fill-in-the-blanks'),
|
||||
)
|
||||
),
|
||||
'#ajax' => array(
|
||||
'wrapper' => 'questions-fieldset-wrapper',
|
||||
'callback' => 'ajax_example_dynamic_sections_select_callback',
|
||||
),
|
||||
);
|
||||
// The CSS for this module hides this next button if JS is enabled.
|
||||
$form['question_type_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Choose'),
|
||||
'#attributes' => array('class' => array('next-button')),
|
||||
// No need to validate when submitting this.
|
||||
'#limit_validation_errors' => array(),
|
||||
'#validate' => array(),
|
||||
);
|
||||
|
||||
// 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.
|
||||
if ($no_js_use) {
|
||||
// Remove the #ajax from the above, so ajax.js won't be loaded.
|
||||
unset($form['question_type_select']['#ajax']);
|
||||
}
|
||||
|
||||
// This fieldset just serves as a container for the part of the form
|
||||
// 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>',
|
||||
);
|
||||
if (!empty($form_state['values']['question_type_select'])) {
|
||||
|
||||
$form['questions_fieldset']['question'] = array(
|
||||
'#markup' => t('Who was the first president of the U.S.?'),
|
||||
);
|
||||
$question_type = $form_state['values']['question_type_select'];
|
||||
|
||||
switch ($question_type) {
|
||||
case t('Multiple Choice'):
|
||||
$form['questions_fieldset']['question'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Who was the first president of the United States'),
|
||||
'#options' => drupal_map_assoc(
|
||||
array(
|
||||
t('George Bush'),
|
||||
t('Adam McGuire'),
|
||||
t('Abraham Lincoln'),
|
||||
t('George Washington'),
|
||||
)
|
||||
),
|
||||
);
|
||||
break;
|
||||
|
||||
case t('True/False'):
|
||||
$form['questions_fieldset']['question'] = array(
|
||||
'#type' => 'radios',
|
||||
'#title' => t('Was George Washington the first president of the United States?'),
|
||||
'#options' => array(t('George Washington') => t("True"), 0 => t("False")),
|
||||
'#description' => t('Click "True" if you think George Washington was the first president of the United States.'),
|
||||
);
|
||||
break;
|
||||
|
||||
case t('Fill-in-the-blanks'):
|
||||
$form['questions_fieldset']['question'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Who was the first president of the United States'),
|
||||
'#description' => t('Please type the correct answer to the question.'),
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
$form['questions_fieldset']['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#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'];
|
||||
if ($answer !== t('George Washington')) {
|
||||
form_set_error('question', t('Wrong answer. Try again. (Hint: The right answer is "George Washington".)'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for ajax_example_dynamic_sections().
|
||||
*/
|
||||
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.
|
||||
switch ($form_state['triggering_element']['#value']) {
|
||||
case t('Submit your answer'):
|
||||
// Submit: We're done.
|
||||
$form_state['rebuild'] = FALSE;
|
||||
$answer = $form_state['values']['question'];
|
||||
|
||||
// Special handling for the checkbox.
|
||||
if ($answer == 1 && $form['questions_fieldset']['question']['#type'] == 'checkbox') {
|
||||
$answer = $form['questions_fieldset']['question']['#title'];
|
||||
}
|
||||
if ($answer === t('George Washington')) {
|
||||
drupal_set_message(t('You got the right answer: @answer', array('@answer' => $answer)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Sorry, your answer (@answer) is wrong', array('@answer' => $answer)));
|
||||
}
|
||||
return;
|
||||
|
||||
// Any other form element will cause rebuild of the form and present
|
||||
// it again.
|
||||
case t('Choose'):
|
||||
$form_state['values']['question_type_select'] = $form_state['input']['question_type_select'];
|
||||
// Fall through.
|
||||
default:
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the select element.
|
||||
*
|
||||
* This just selects and returns the questions_fieldset.
|
||||
*/
|
||||
function ajax_example_dynamic_sections_select_callback($form, $form_state) {
|
||||
return $form['questions_fieldset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Wizard form.
|
||||
*
|
||||
* This example is a classic wizard, where a different and sequential form
|
||||
* is presented on each step of the form.
|
||||
*
|
||||
* In the AJAX version, the form is replaced for each wizard section. In the
|
||||
* multistep version, it causes a new page load.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form.
|
||||
* @param bool $no_js_use
|
||||
* Used for this demonstration only. If true means that the form should be
|
||||
* built using a simulated no-javascript approach (ajax.js will not be
|
||||
* loaded.)
|
||||
*
|
||||
* @return array
|
||||
* Form array.
|
||||
*/
|
||||
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 with each submit.
|
||||
$form['#prefix'] = '<div id="wizard-form-wrapper">';
|
||||
$form['#suffix'] = '</div>';
|
||||
// We want to deal with hierarchical form values.
|
||||
$form['#tree'] = TRUE;
|
||||
$form['description'] = array(
|
||||
'#markup' => '<div>' . t('This example is a step-by-step wizard. The <a href="!ajax">AJAX version</a> does it without page reloads; the <a href="!multistep">multistep version</a> is the same code but simulates a non-javascript environment, showing it with page reloads.',
|
||||
array('!ajax' => url('examples/ajax_example/wizard'), '!multistep' => url('examples/ajax_example/wizard_no_js')))
|
||||
. '</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;
|
||||
|
||||
switch ($step) {
|
||||
case 1:
|
||||
$form['step1'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Step 1: Personal details'),
|
||||
);
|
||||
$form['step1']['name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your name'),
|
||||
'#default_value' => empty($form_state['values']['step1']['name']) ? '' : $form_state['values']['step1']['name'],
|
||||
'#required' => TRUE,
|
||||
);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$form['step2'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Step 2: Street address info'),
|
||||
);
|
||||
$form['step2']['address'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your street address'),
|
||||
'#default_value' => empty($form_state['values']['step2']['address']) ? '' : $form_state['values']['step2']['address'],
|
||||
'#required' => TRUE,
|
||||
);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
$form['step3'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Step 3: City info'),
|
||||
);
|
||||
$form['step3']['city'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Your city'),
|
||||
'#default_value' => empty($form_state['values']['step3']['city']) ? '' : $form_state['values']['step3']['city'],
|
||||
'#required' => TRUE,
|
||||
);
|
||||
break;
|
||||
}
|
||||
if ($step == 3) {
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("Submit your information"),
|
||||
);
|
||||
}
|
||||
if ($step < 3) {
|
||||
$form['next'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Next step'),
|
||||
'#ajax' => array(
|
||||
'wrapper' => 'wizard-form-wrapper',
|
||||
'callback' => 'ajax_example_wizard_callback',
|
||||
),
|
||||
);
|
||||
}
|
||||
if ($step > 1) {
|
||||
$form['prev'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t("Previous step"),
|
||||
|
||||
// Since all info will be discarded, don't validate on 'prev'.
|
||||
'#limit_validation_errors' => array(),
|
||||
// #submit is required to use #limit_validation_errors
|
||||
'#submit' => array('ajax_example_wizard_submit'),
|
||||
'#ajax' => array(
|
||||
'wrapper' => 'wizard-form-wrapper',
|
||||
'callback' => 'ajax_example_wizard_callback',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 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.
|
||||
if ($no_js_use) {
|
||||
// Remove the #ajax from the above, so ajax.js won't be loaded.
|
||||
// For demonstration only.
|
||||
unset($form['next']['#ajax']);
|
||||
unset($form['prev']['#ajax']);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wizard callback function.
|
||||
*
|
||||
* @param array $form
|
||||
* Form API form.
|
||||
* @param array $form_state
|
||||
* Form API form.
|
||||
*
|
||||
* @return array
|
||||
* Form array.
|
||||
*/
|
||||
function ajax_example_wizard_callback($form, $form_state) {
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit function for ajax_example_wizard.
|
||||
*
|
||||
* In AJAX this is only submitted when the final submit button is clicked,
|
||||
* but in the non-javascript situation, it is submitted with every
|
||||
* button click.
|
||||
*/
|
||||
function ajax_example_wizard_submit($form, &$form_state) {
|
||||
|
||||
// Save away the current information.
|
||||
$current_step = 'step' . $form_state['storage']['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 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])) {
|
||||
$form_state['values'][$step_name] = $form_state['storage']['values'][$step_name];
|
||||
}
|
||||
}
|
||||
if ($form_state['triggering_element']['#value'] == t('Previous step')) {
|
||||
$form_state['storage']['step']--;
|
||||
// Recover our values from $form_state['storage'] to pre-populate them.
|
||||
$step_name = 'step' . $form_state['storage']['step'];
|
||||
$form_state['values'][$step_name] = $form_state['storage']['values'][$step_name];
|
||||
}
|
||||
|
||||
// If they're done, submit.
|
||||
if ($form_state['triggering_element']['#value'] == t('Submit your information')) {
|
||||
$value_message = t('Your information has been submitted:') . ' ';
|
||||
foreach ($form_state['storage']['values'] as $step => $values) {
|
||||
$value_message .= "$step: ";
|
||||
foreach ($values as $key => $value) {
|
||||
$value_message .= "$key=$value, ";
|
||||
}
|
||||
}
|
||||
drupal_set_message($value_message);
|
||||
$form_state['rebuild'] = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we still have work to do.
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Form with 'add more' and 'remove' buttons.
|
||||
*
|
||||
* This example shows a button to "add more" - add another textfield, and
|
||||
* the corresponding "remove" button.
|
||||
*
|
||||
* It works equivalently with javascript or not, and does the same basic steps
|
||||
* either way.
|
||||
*
|
||||
* The basic idea is that we build the form based on the setting of
|
||||
* $form_state['num_names']. The custom submit functions for the "add-one"
|
||||
* and "remove-one" buttons increment and decrement $form_state['num_names']
|
||||
* and then force a rebuild of the form.
|
||||
*
|
||||
* The $no_js_use argument is simply for demonstration: When set, it prevents
|
||||
* '#ajax' from being set, thus making the example behave as if javascript
|
||||
* were disabled in the browser.
|
||||
*/
|
||||
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')))
|
||||
. '</div>',
|
||||
);
|
||||
|
||||
// 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'),
|
||||
// Set up the wrapper so that AJAX will be able to replace the fieldset.
|
||||
'#prefix' => '<div id="names-fieldset-wrapper">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
// Build the fieldset with the proper number of names. We'll use
|
||||
// $form_state['num_names'] to determine the number of textfields to build.
|
||||
if (empty($form_state['num_names'])) {
|
||||
$form_state['num_names'] = 1;
|
||||
}
|
||||
for ($i = 0; $i < $form_state['num_names']; $i++) {
|
||||
$form['names_fieldset']['name'][$i] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Name'),
|
||||
);
|
||||
}
|
||||
$form['names_fieldset']['add_name'] = array(
|
||||
'#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',
|
||||
),
|
||||
);
|
||||
if ($form_state['num_names'] > 1) {
|
||||
$form['names_fieldset']['remove_name'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Remove one'),
|
||||
'#submit' => array('ajax_example_add_more_remove_one'),
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_add_more_callback',
|
||||
'wrapper' => 'names-fieldset-wrapper',
|
||||
),
|
||||
);
|
||||
}
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#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.
|
||||
if ($no_js_use) {
|
||||
// Remove the #ajax from the above, so ajax.js won't be loaded.
|
||||
if (!empty($form['names_fieldset']['remove_name']['#ajax'])) {
|
||||
unset($form['names_fieldset']['remove_name']['#ajax']);
|
||||
}
|
||||
unset($form['names_fieldset']['add_name']['#ajax']);
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for both ajax-enabled buttons.
|
||||
*
|
||||
* Selects and returns the fieldset with the names in it.
|
||||
*/
|
||||
function ajax_example_add_more_callback($form, $form_state) {
|
||||
return $form['names_fieldset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the "add-one-more" button.
|
||||
*
|
||||
* Increments the max counter and causes a rebuild.
|
||||
*/
|
||||
function ajax_example_add_more_add_one($form, &$form_state) {
|
||||
$form_state['num_names']++;
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for the "remove one" button.
|
||||
*
|
||||
* Decrements the max counter and causes a form rebuild.
|
||||
*/
|
||||
function ajax_example_add_more_remove_one($form, &$form_state) {
|
||||
if ($form_state['num_names'] > 1) {
|
||||
$form_state['num_names']--;
|
||||
}
|
||||
$form_state['rebuild'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Final submit handler.
|
||||
*
|
||||
* 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',
|
||||
array(
|
||||
'@names' => implode(', ', $form_state['values']['names_fieldset']['name']),
|
||||
)
|
||||
);
|
||||
drupal_set_message($output);
|
||||
}
|
||||
/**
|
||||
* @} End of "defgroup ajax_degradation_example".
|
||||
*/
|
116
sites/all/modules/examples/ajax_example/ajax_example_misc.inc
Normal file
116
sites/all/modules/examples/ajax_example/ajax_example_misc.inc
Normal file
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* AJAX Miscellaneous Topics.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Demonstrates a clickable AJAX-enabled link using the 'use-ajax' class.
|
||||
*
|
||||
* Because of the 'use-ajax' class applied here, the link submission is done
|
||||
* without a page refresh.
|
||||
*
|
||||
* When using the AJAX framework outside the context of a form or a renderable
|
||||
* array of type 'link', you have to include ajax.js explicitly.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*
|
||||
* @ingroup ajax_example
|
||||
*/
|
||||
function ajax_example_render_link() {
|
||||
// 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 = t("
|
||||
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
|
||||
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>" . $explanation . "</div>";
|
||||
// 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 id='myDiv'></div><div>$link</div>";
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX-enabled link in a renderable array.
|
||||
*
|
||||
* Demonstrates a clickable AJAX-enabled link using a renderable array with the
|
||||
* #ajax property.
|
||||
*
|
||||
* A link that is constructed as a renderable array can have the #ajax property,
|
||||
* which ensures that the link submission is done without a page refresh. The
|
||||
* href of the link is used as the ajax callback, but it degrades gracefully
|
||||
* without JavaScript because if the 'nojs' portion of the href is not stripped
|
||||
* out by js, the callback will return content as required for a full page
|
||||
* reload.
|
||||
*
|
||||
* The necessary JavaScript file, ajax.js, will be included on the page
|
||||
* automatically.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*/
|
||||
function ajax_example_render_link_ra() {
|
||||
$explanation = "
|
||||
The link below has been rendered as an element with the #ajax property, so if
|
||||
javascript is enabled, ajax.js will try to submit it via an AJAX call instead
|
||||
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.";
|
||||
$build['my_div'] = array(
|
||||
'#markup' => $explanation . '<div id="myDiv"></div>',
|
||||
);
|
||||
$build['ajax_link'] = array(
|
||||
'#type' => 'link',
|
||||
'#title' => t('Click here'),
|
||||
// Note the /nojs portion of the href - if javascript is enabled,
|
||||
// this part will be stripped from the path before it is called.
|
||||
'#href' => 'ajax_link_callback/nojs/',
|
||||
'#id' => 'ajax_link',
|
||||
'#ajax' => array(
|
||||
'wrapper' => 'myDiv',
|
||||
'method' => 'html',
|
||||
),
|
||||
);
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for link example.
|
||||
*
|
||||
* Takes different logic paths based on whether Javascript was enabled.
|
||||
* If $type == 'ajax', it tells this function that ajax.js has rewritten
|
||||
* the URL and thus we are doing an AJAX and can return an array of commands.
|
||||
*
|
||||
* @param string $type
|
||||
* Either 'ajax' or 'nojs. Type is simply the normal URL argument to this URL.
|
||||
*
|
||||
* @return string|array
|
||||
* If $type == 'ajax', returns an array of AJAX Commands.
|
||||
* Otherwise, just returns the content, which will end up being a page.
|
||||
*
|
||||
* @ingroup ajax_example
|
||||
*/
|
||||
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);
|
||||
}
|
||||
else {
|
||||
$output = t("This is some content delivered via a page load.");
|
||||
return $output;
|
||||
}
|
||||
}
|
@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* This example shows how to use AJAX when altering a node form.
|
||||
*
|
||||
* It maintains a table parallel to the node table containing attributes
|
||||
* 'example_1' and 'example_2' which are displayed on the node form.
|
||||
* 'example_2' is displayed dynamically when example_1 is checked.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_form_FORM_ID_alter().
|
||||
*
|
||||
* Adds two fields to the node form, second only appears after first is enabled.
|
||||
*/
|
||||
function ajax_example_form_node_form_alter(&$form, &$form_state, $form_id) {
|
||||
$node = $form['#node'];
|
||||
$form['ajax_example_1'] = array(
|
||||
'#type' => 'checkbox',
|
||||
'#title' => t('AJAX Example 1'),
|
||||
'#description' => t('Enable to show second field.'),
|
||||
'#default_value' => $node->ajax_example['example_1'],
|
||||
'#ajax' => array(
|
||||
'callback' => 'ajax_example_form_node_callback',
|
||||
'wrapper' => 'ajax-example-form-node',
|
||||
'effect' => 'fade',
|
||||
),
|
||||
);
|
||||
$form['container'] = array(
|
||||
'#prefix' => '<div id="ajax-example-form-node">',
|
||||
'#suffix' => '</div>',
|
||||
);
|
||||
|
||||
// If the state values exist and 'ajax_example_1' state value is 1 or
|
||||
// if the state values don't exist and 'example1' variable is 1 then
|
||||
// display the ajax_example_2 field.
|
||||
if (!empty($form_state['values']['ajax_example_1']) && $form_state['values']['ajax_example_1'] == 1
|
||||
|| empty($form_state['values']) && $node->ajax_example['example_1']) {
|
||||
|
||||
$form['container']['ajax_example_2'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('AJAX Example 2'),
|
||||
'#description' => t('AJAX Example 2'),
|
||||
'#default_value' => empty($form_state['values']['ajax_example_2']) ? $node->ajax_example['example_2'] : $form_state['values']['ajax_example_2'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns changed part of the form.
|
||||
*
|
||||
* @return array
|
||||
* Form API array.
|
||||
*
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_form_node_callback($form, $form_state) {
|
||||
return $form['container'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_submit().
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_submit($node, $form, &$form_state) {
|
||||
$values = $form_state['values'];
|
||||
// Move the new data into the node object.
|
||||
$node->ajax_example['example_1'] = $values['ajax_example_1'];
|
||||
// Depending on the state of ajax_example_1; it may not exist.
|
||||
$node->ajax_example['example_2'] = isset($values['ajax_example_2']) ? $values['ajax_example_2'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_prepare().
|
||||
*
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_prepare($node) {
|
||||
if (empty($node->ajax_example)) {
|
||||
// Set default values, since this only runs when adding a new node.
|
||||
$node->ajax_example['example_1'] = 0;
|
||||
$node->ajax_example['example_2'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_load().
|
||||
*
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_load($nodes, $types) {
|
||||
$result = db_query('SELECT * FROM {ajax_example_node_form_alter} WHERE nid IN(:nids)', array(':nids' => array_keys($nodes)))->fetchAllAssoc('nid');
|
||||
|
||||
foreach ($nodes as &$node) {
|
||||
$node->ajax_example['example_1']
|
||||
= isset($result[$node->nid]->example_1) ?
|
||||
$result[$node->nid]->example_1 : 0;
|
||||
$node->ajax_example['example_2']
|
||||
= isset($result[$node->nid]->example_2) ?
|
||||
$result[$node->nid]->example_2 : '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_insert().
|
||||
*
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_insert($node) {
|
||||
if (isset($node->ajax_example)) {
|
||||
db_insert('ajax_example_node_form_alter')
|
||||
->fields(array(
|
||||
'nid' => $node->nid,
|
||||
'example_1' => $node->ajax_example['example_1'],
|
||||
'example_2' => $node->ajax_example['example_2'],
|
||||
))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_update().
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_update($node) {
|
||||
if (db_select('ajax_example_node_form_alter', 'a')->fields('a')->condition('nid', $node->nid, '=')->execute()->fetchAssoc()) {
|
||||
db_update('ajax_example_node_form_alter')
|
||||
->fields(array(
|
||||
'example_1' => $node->ajax_example['example_1'],
|
||||
'example_2' => $node->ajax_example['example_2'],
|
||||
))
|
||||
->condition('nid', $node->nid)
|
||||
->execute();
|
||||
}
|
||||
else {
|
||||
// Cleaner than doing it again.
|
||||
ajax_example_node_insert($node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_node_delete().
|
||||
* @see ajax_example_form_node_form_alter()
|
||||
*/
|
||||
function ajax_example_node_delete($node) {
|
||||
db_delete('ajax_example_node_form_alter')
|
||||
->condition('nid', $node->nid)
|
||||
->execute();
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Progress bar example.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_FORMID().
|
||||
*
|
||||
* Build a landing-page form for the progress bar example.
|
||||
*
|
||||
* @see https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#ajax_progress
|
||||
*/
|
||||
function ajax_example_progressbar_form($form, &$form_state) {
|
||||
$form_state['time'] = REQUEST_TIME;
|
||||
|
||||
// We make a DIV which the progress bar can occupy. You can see this in use
|
||||
// in ajax_example_progressbar_callback().
|
||||
$form['status'] = array(
|
||||
'#markup' => '<div id="progress-status"></div>',
|
||||
);
|
||||
|
||||
$form['submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Submit'),
|
||||
'#ajax' => array(
|
||||
// Here we set up our AJAX callback handler.
|
||||
'callback' => 'ajax_example_progressbar_callback',
|
||||
// Tell FormAPI about our progress bar.
|
||||
'progress' => array(
|
||||
'type' => 'bar',
|
||||
'message' => t('Execute..'),
|
||||
// Have the progress bar access this URL path.
|
||||
'url' => url('examples/ajax_example/progressbar/progress/' . $form_state['time']),
|
||||
// The time interval for the progress bar to check for updates.
|
||||
'interval' => 1000,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the progress bar execution status, as JSON.
|
||||
*
|
||||
* This is the menu handler for
|
||||
* examples/ajax_example/progressbar/progress/$time.
|
||||
*
|
||||
* This function is our wholly arbitrary job that we're checking the status for.
|
||||
* In this case, we're reading a system variable that is being updated by
|
||||
* ajax_example_progressbar_callback().
|
||||
*
|
||||
* We set up the AJAX progress bar to check the status every second, so this
|
||||
* will execute about once every second.
|
||||
*
|
||||
* The progress bar JavaScript accepts two values: message and percentage. We
|
||||
* set those in an array and in the end convert it JSON for sending back to the
|
||||
* client-side JavaScript.
|
||||
*
|
||||
* @param int $time
|
||||
* Timestamp.
|
||||
*
|
||||
* @see ajax_example_progressbar_callback()
|
||||
*/
|
||||
function ajax_example_progressbar_progress($time) {
|
||||
$progress = array(
|
||||
'message' => t('Starting execute...'),
|
||||
'percentage' => -1,
|
||||
);
|
||||
|
||||
$completed_percentage = variable_get('example_progressbar_' . $time, 0);
|
||||
|
||||
if ($completed_percentage) {
|
||||
$progress['message'] = t('Executing...');
|
||||
$progress['percentage'] = $completed_percentage;
|
||||
}
|
||||
|
||||
drupal_json_output($progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Our submit handler.
|
||||
*
|
||||
* This handler spends some time changing a variable and sleeping, and then
|
||||
* finally returns a form element which marks the #progress-status DIV as
|
||||
* completed.
|
||||
*
|
||||
* While this is occurring, ajax_example_progressbar_progress() will be called
|
||||
* a number of times by the client-sid JavaScript, which will poll the variable
|
||||
* being set here.
|
||||
*
|
||||
* @see ajax_example_progressbar_progress()
|
||||
*/
|
||||
function ajax_example_progressbar_callback($form, &$form_state) {
|
||||
$variable_name = 'example_progressbar_' . $form_state['time'];
|
||||
$commands = array();
|
||||
|
||||
variable_set($variable_name, 10);
|
||||
sleep(2);
|
||||
variable_set($variable_name, 40);
|
||||
sleep(2);
|
||||
variable_set($variable_name, 70);
|
||||
sleep(2);
|
||||
variable_set($variable_name, 90);
|
||||
sleep(2);
|
||||
variable_del($variable_name);
|
||||
|
||||
$commands[] = ajax_command_html('#progress-status', t('Executed.'));
|
||||
|
||||
return array(
|
||||
'#type' => 'ajax',
|
||||
'#commands' => $commands,
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user