Issue #1858452 by Mile23: [meta] Examples projects without tests.
[project/examples.git] / ajax_example / ajax_example.module
1 <?php
2
3 /**
4 * @file
5 * AJAX Examples module file with basic examples.
6 */
7
8 /**
9 * @defgroup ajax_example Example: AJAX
10 * @ingroup examples
11 * @{
12 * These examples show basic AJAX concepts.
13 *
14 * General documentation is available at
15 * @link ajax AJAX Framework documentation @endlink and at the
16 * @link http://drupal.org/node/752056 AJAX Forms handbook page @endlink.
17 *
18 * The several examples here demonstrate basic AJAX usage.
19 */
20
21 // The Node Form Alter example needs to be in another file.
22 module_load_include('inc', 'ajax_example', 'ajax_example_node_form_alter');
23
24 /**
25 * Implements hook_menu().
26 *
27 * Sets up calls to drupal_get_form() for all our example cases.
28 *
29 * @see menu_example.module
30 * @see menu_example_menu()
31 */
32 function ajax_example_menu() {
33 $items = array();
34
35 $items['examples/ajax_example'] = array(
36 'title' => 'AJAX Example',
37 'page callback' => 'ajax_example_intro',
38 'access callback' => TRUE,
39 'expanded' => TRUE,
40 );
41
42 // Change the description of a form element.
43 $items['examples/ajax_example/simplest'] = array(
44 'title' => 'Simplest AJAX Example',
45 'page callback' => 'drupal_get_form',
46 'page arguments' => array('ajax_example_simplest'),
47 'access callback' => TRUE,
48 'weight' => 0,
49 );
50 // Generate a changing number of checkboxes.
51 $items['examples/ajax_example/autocheckboxes'] = array(
52 'title' => 'Generate checkboxes',
53 'page callback' => 'drupal_get_form',
54 'page arguments' => array('ajax_example_autocheckboxes'),
55 'access callback' => TRUE,
56 'weight' => 1,
57 );
58 // Generate different textfields based on form state.
59 $items['examples/ajax_example/autotextfields'] = array(
60 'title' => 'Generate textfields',
61 'page callback' => 'drupal_get_form',
62 'page arguments' => array('ajax_example_autotextfields'),
63 'access callback' => TRUE,
64 'weight' => 2,
65 );
66
67 // Submit a form without a page reload.
68 $items['examples/ajax_example/submit_driven_ajax'] = array(
69 'title' => 'Submit-driven AJAX',
70 'page callback' => 'drupal_get_form',
71 'page arguments' => array('ajax_example_submit_driven_ajax'),
72 'access callback' => TRUE,
73 'weight' => 3,
74 );
75
76 // Repopulate a dropdown based on form state.
77 $items['examples/ajax_example/dependent_dropdown'] = array(
78 'title' => 'Dependent dropdown',
79 'page callback' => 'drupal_get_form',
80 'page arguments' => array('ajax_example_dependent_dropdown'),
81 'access callback' => TRUE,
82 'weight' => 4,
83 );
84 // Repopulate a dropdown, but this time with graceful degredation.
85 // See ajax_example_graceful_degradation.inc.
86 $items['examples/ajax_example/dependent_dropdown_degrades'] = array(
87 'title' => 'Dependent dropdown (with graceful degradation)',
88 'page callback' => 'drupal_get_form',
89 'page arguments' => array('ajax_example_dependent_dropdown_degrades'),
90 'access callback' => TRUE,
91 'weight' => 5,
92 'file' => 'ajax_example_graceful_degradation.inc',
93 );
94 // The above example as it appears to users with no javascript.
95 $items['examples/ajax_example/dependent_dropdown_degrades_no_js'] = array(
96 'title' => 'Dependent dropdown with javascript off',
97 'page callback' => 'drupal_get_form',
98 'page arguments' => array('ajax_example_dependent_dropdown_degrades', TRUE),
99 'access callback' => TRUE,
100 'file' => 'ajax_example_graceful_degradation.inc',
101 'weight' => 5,
102 );
103
104 // Populate a form section based on input in another element.
105 $items['examples/ajax_example/dynamic_sections'] = array(
106 'title' => 'Dynamic Sections (with graceful degradation)',
107 'page callback' => 'drupal_get_form',
108 'page arguments' => array('ajax_example_dynamic_sections'),
109 'access callback' => TRUE,
110 'weight' => 6,
111 'file' => 'ajax_example_graceful_degradation.inc',
112 );
113 // The above example as it appears to users with no javascript.
114 $items['examples/ajax_example/dynamic_sections_no_js'] = array(
115 'title' => 'Dynamic Sections w/JS turned off',
116 'page callback' => 'drupal_get_form',
117 'page arguments' => array('ajax_example_dynamic_sections', TRUE),
118 'access callback' => TRUE,
119 'weight' => 6,
120 'file' => 'ajax_example_graceful_degradation.inc',
121 );
122
123 // A classic multi-step wizard, but with no page reloads.
124 // See ajax_example_graceful_degradation.inc.
125 $items['examples/ajax_example/wizard'] = array(
126 'title' => 'Wizard (with graceful degradation)',
127 'page callback' => 'drupal_get_form',
128 'page arguments' => array('ajax_example_wizard'),
129 'access callback' => TRUE,
130 'file' => 'ajax_example_graceful_degradation.inc',
131 'weight' => 7,
132 );
133 // The above example as it appears to users with no javascript.
134 $items['examples/ajax_example/wizard_no_js'] = array(
135 'title' => 'Wizard w/JS turned off',
136 'page callback' => 'drupal_get_form',
137 'page arguments' => array('ajax_example_wizard', TRUE),
138 'access callback' => TRUE,
139 'file' => 'ajax_example_graceful_degradation.inc',
140 'weight' => 7,
141 );
142
143 // Add-more button that creates additional form elements.
144 // See ajax_example_graceful_degradation.inc.
145 $items['examples/ajax_example/add_more'] = array(
146 'title' => 'Add-more button (with graceful degradation)',
147 'page callback' => 'drupal_get_form',
148 'page arguments' => array('ajax_example_add_more'),
149 'access callback' => TRUE,
150 'file' => 'ajax_example_graceful_degradation.inc',
151 'weight' => 8,
152 );
153 // The above example as it appears to users with no javascript.
154 $items['examples/ajax_example/add_more_no_js'] = array(
155 'title' => 'Add-more button w/JS turned off',
156 'page callback' => 'drupal_get_form',
157 'page arguments' => array('ajax_example_add_more', TRUE),
158 'access callback' => TRUE,
159 'file' => 'ajax_example_graceful_degradation.inc',
160 'weight' => 8,
161 );
162
163 // Use the AJAX framework outside the context of a form using the use-ajax
164 // class. See ajax_example_misc.inc.
165 $items['examples/ajax_example/ajax_link'] = array(
166 'title' => 'Ajax Link ("use-ajax" class)',
167 'page callback' => 'ajax_example_render_link',
168 'access callback' => TRUE,
169 'file' => 'ajax_example_misc.inc',
170 'weight' => 9,
171 );
172 // Use the AJAX framework outside the context of a form using a renderable
173 // array of type link with the #ajax property. See ajax_example_misc.inc.
174 $items['examples/ajax_example/ajax_link_renderable'] = array(
175 'title' => 'Ajax Link (Renderable Array)',
176 'page callback' => 'ajax_example_render_link_ra',
177 'access callback' => TRUE,
178 'file' => 'ajax_example_misc.inc',
179 'weight' => 9,
180 );
181 // A menu callback is required when using ajax outside of the Form API.
182 $items['ajax_link_callback'] = array(
183 'page callback' => 'ajax_link_response',
184 'access callback' => 'user_access',
185 'access arguments' => array('access content'),
186 'type' => MENU_CALLBACK,
187 'file' => 'ajax_example_misc.inc',
188 );
189
190 // Use AJAX framework commands outside of the #ajax form property.
191 // See ajax_example_advanced.inc.
192 $items['examples/ajax_example/advanced_commands'] = array(
193 'title' => 'AJAX framework commands',
194 'page callback' => 'drupal_get_form',
195 'page arguments' => array('ajax_example_advanced_commands'),
196 'access callback' => TRUE,
197 'file' => 'ajax_example_advanced.inc',
198 'weight' => 100,
199 );
200
201 // Autocomplete examples.
202 $items['examples/ajax_example/simple_autocomplete'] = array(
203 'title' => 'Autocomplete (simple)',
204 'page callback' => 'drupal_get_form',
205 'page arguments' => array('ajax_example_simple_autocomplete'),
206 'access arguments' => array('access user profiles'),
207 'file' => 'ajax_example_autocomplete.inc',
208 'weight' => 10,
209 );
210 $items['examples/ajax_example/simple_user_autocomplete_callback'] = array(
211 'page callback' => 'ajax_example_simple_user_autocomplete_callback',
212 'file' => 'ajax_example_autocomplete.inc',
213 'type' => MENU_CALLBACK,
214 'access arguments' => array('access user profiles'),
215 );
216 $items['examples/ajax_example/node_autocomplete'] = array(
217 'title' => 'Autocomplete (node with nid)',
218 'page callback' => 'drupal_get_form',
219 'page arguments' => array('ajax_example_unique_autocomplete'),
220 'access arguments' => array('access content'),
221 'file' => 'ajax_example_autocomplete.inc',
222 'weight' => 11,
223 );
224 $items['examples/ajax_example/unique_node_autocomplete_callback'] = array(
225 'page callback' => 'ajax_example_unique_node_autocomplete_callback',
226 'file' => 'ajax_example_autocomplete.inc',
227 'type' => MENU_CALLBACK,
228 'access arguments' => array('access content'),
229 );
230 $items['examples/ajax_example/node_by_author'] = array(
231 'title' => 'Autocomplete (node limited by author)',
232 'page callback' => 'drupal_get_form',
233 'page arguments' => array('ajax_example_node_by_author_autocomplete'),
234 'access callback' => TRUE,
235 'file' => 'ajax_example_autocomplete.inc',
236 'weight' => 12,
237 );
238 $items['examples/ajax_example/node_by_author_autocomplete'] = array(
239 'page callback' => 'ajax_example_node_by_author_node_autocomplete_callback',
240 'file' => 'ajax_example_autocomplete.inc',
241 'type' => MENU_CALLBACK,
242 'access arguments' => array('access content'),
243 );
244
245 return $items;
246 }
247
248 /**
249 * A basic introduction page for the ajax_example module.
250 */
251 function ajax_example_intro() {
252 $markup = t('The AJAX example module provides many examples of AJAX including forms, links, and AJAX commands.');
253
254 $list[] = l(t('Simplest AJAX Example'), 'examples/ajax_example/simplest');
255 $list[] = l(t('Generate checkboxes'), 'examples/ajax_example/autocheckboxes');
256 $list[] = l(t('Generate textfields'), 'examples/ajax_example/autotextfields');
257 $list[] = l(t('Submit-driven AJAX'), 'examples/ajax_example/submit_driven_ajax');
258 $list[] = l(t('Dependent dropdown'), 'examples/ajax_example/dependent_dropdown');
259 $list[] = l(t('Dependent dropdown (with graceful degradation)'), 'examples/ajax_example/dependent_dropdown_degrades');
260 $list[] = l(t('Dynamic Sections w/JS turned off'), 'examples/ajax_example/dependent_dropdown_degrades_no_js');
261 $list[] = l(t('Wizard (with graceful degradation)'), 'examples/ajax_example/wizard');
262 $list[] = l(t('Wizard w/JS turned off'), 'examples/ajax_example/wizard_no_js');
263 $list[] = l(t('Add-more button (with graceful degradation)'), 'examples/ajax_example/add_more');
264 $list[] = l(t('Add-more button w/JS turned off'), 'examples/ajax_example/add_more_no_js');
265 $list[] = l(t('Ajax Link ("use-ajax" class)'), 'examples/ajax_example/ajax_link');
266 $list[] = l(t('Ajax Link (Renderable Array)'), 'examples/ajax_example/ajax_link_renderable');
267 $list[] = l(t('AJAX framework commands'), 'examples/ajax_example/advanced_commands');
268 $list[] = l(t('Autocomplete (simple)'), 'examples/ajax_example/simple_autocomplete');
269 $list[] = l(t('Autocomplete (node with nid)'), 'examples/ajax_example/node_autocomplete');
270 $list[] = l(t('Autocomplete (node limited by author)'), 'examples/ajax_example/node_by_author');
271
272 $variables['items'] = $list;
273 $variables['type'] = 'ul';
274 $markup .= theme('item_list', $variables);
275
276 return $markup;
277 }
278
279 /**
280 * Basic AJAX callback example.
281 *
282 * Simple form whose ajax-enabled 'changethis' member causes a text change
283 * in the description of the 'replace_textfield' member.
284 *
285 * See @link http://drupal.org/node/262422 Form API Tutorial @endlink
286 */
287 function ajax_example_simplest($form, &$form_state) {
288 $form = array();
289 $form['changethis'] = array(
290 '#title' => t("Choose something and explain why"),
291 '#type' => 'select',
292 '#options' => array(
293 'one' => 'one',
294 'two' => 'two',
295 'three' => 'three',
296 ),
297 '#ajax' => array(
298 // #ajax has two required keys: callback and wrapper.
299 // 'callback' is a function that will be called when this element changes.
300 'callback' => 'ajax_example_simplest_callback',
301 // 'wrapper' is the HTML id of the page element that will be replaced.
302 'wrapper' => 'replace_textfield_div',
303 // There are also several optional keys - see ajax_example_autocheckboxes
304 // below for details on 'method', 'effect' and 'speed' and
305 // ajax_example_dependent_dropdown for 'event'.
306 ),
307 );
308
309 // This entire form element will be replaced whenever 'changethis' is updated.
310 $form['replace_textfield'] = array(
311 '#type' => 'textfield',
312 '#title' => t("Why"),
313 // The prefix/suffix provide the div that we're replacing, named by
314 // #ajax['wrapper'] above.
315 '#prefix' => '<div id="replace_textfield_div">',
316 '#suffix' => '</div>',
317 );
318
319 // An AJAX request calls the form builder function for every change.
320 // We can change how we build the form based on $form_state.
321 if (!empty($form_state['values']['changethis'])) {
322 $form['replace_textfield']['#description'] = t("Say why you chose '@value'", array('@value' => $form_state['values']['changethis']));
323 }
324 return $form;
325 }
326
327 /**
328 * Callback for ajax_example_simplest.
329 *
330 * On an ajax submit, the form builder function is called again, then the $form
331 * and $form_state are passed to this callback function so it can select which
332 * portion of the form to send on to the client.
333 *
334 * @return array
335 * Renderable array (the textfield element)
336 */
337 function ajax_example_simplest_callback($form, $form_state) {
338 // The form has already been submitted and updated. We can return the replaced
339 // item as it is.
340 return $form['replace_textfield'];
341 }
342
343 /**
344 * Form manipulation through AJAX.
345 *
346 * AJAX-enabled select element causes replacement of a set of checkboxes
347 * based on the selection.
348 */
349 function ajax_example_autocheckboxes($form, &$form_state) {
350 // Since the form builder is called after every AJAX request, we rebuild
351 // the form based on $form_state.
352 $num_checkboxes = !empty($form_state['values']['howmany_select']) ? $form_state['values']['howmany_select'] : 1;
353
354 $form['howmany_select'] = array(
355 '#title' => t('How many checkboxes do you want?'),
356 '#type' => 'select',
357 '#options' => array(1 => 1, 2 => 2, 3 => 3, 4 => 4),
358 '#default_value' => $num_checkboxes,
359 '#ajax' => array(
360 'callback' => 'ajax_example_autocheckboxes_callback',
361 'wrapper' => 'checkboxes-div',
362 // 'method' defaults to replaceWith, but valid values also include
363 // append, prepend, before and after.
364 // 'method' => 'replaceWith',
365 // 'effect' defaults to none. Other valid values are 'fade' and 'slide'.
366 // See ajax_example_autotextfields for an example of 'fade'.
367 'effect' => 'slide',
368 // 'speed' defaults to 'slow'. You can also use 'fast'
369 // or a number of milliseconds for the animation to last.
370 // 'speed' => 'slow',
371 // Don't show any throbber...
372 'progress' => array('type' => 'none'),
373 ),
374 );
375
376 $form['checkboxes_fieldset'] = array(
377 '#title' => t("Generated Checkboxes"),
378 // The prefix/suffix provide the div that we're replacing, named by
379 // #ajax['wrapper'] above.
380 '#prefix' => '<div id="checkboxes-div">',
381 '#suffix' => '</div>',
382 '#type' => 'fieldset',
383 '#description' => t('This is where we get automatically generated checkboxes'),
384 );
385
386 for ($i = 1; $i <= $num_checkboxes; $i++) {
387 $form['checkboxes_fieldset']["checkbox$i"] = array(
388 '#type' => 'checkbox',
389 '#title' => "Checkbox $i",
390 );
391 }
392
393 $form['submit'] = array(
394 '#type' => 'submit',
395 '#value' => t('Submit'),
396 );
397
398 return $form;
399 }
400
401 /**
402 * Callback for autocheckboxes.
403 *
404 * Callback element needs only select the portion of the form to be updated.
405 * Since #ajax['callback'] return can be HTML or a renderable array (or an
406 * array of commands), we can just return a piece of the form.
407 * See @link ajax_example_advanced.inc AJAX Advanced Commands for more details
408 * on AJAX framework commands.
409 *
410 * @return array
411 * Renderable array (the checkboxes fieldset)
412 */
413 function ajax_example_autocheckboxes_callback($form, $form_state) {
414 return $form['checkboxes_fieldset'];
415 }
416
417
418 /**
419 * Show/hide textfields based on AJAX-enabled checkbox clicks.
420 */
421 function ajax_example_autotextfields($form, &$form_state) {
422
423 $form['ask_first_name'] = array(
424 '#type' => 'checkbox',
425 '#title' => t('Ask me my first name'),
426 '#ajax' => array(
427 'callback' => 'ajax_example_autotextfields_callback',
428 'wrapper' => 'textfields',
429 'effect' => 'fade',
430 ),
431 );
432 $form['ask_last_name'] = array(
433 '#type' => 'checkbox',
434 '#title' => t('Ask me my last name'),
435 '#ajax' => array(
436 'callback' => 'ajax_example_autotextfields_callback',
437 'wrapper' => 'textfields',
438 'effect' => 'fade',
439 ),
440 );
441
442 $form['textfields'] = array(
443 '#title' => t("Generated text fields for first and last name"),
444 '#prefix' => '<div id="textfields">',
445 '#suffix' => '</div>',
446 '#type' => 'fieldset',
447 '#description' => t('This is where we put automatically generated textfields'),
448 );
449
450 // Since checkboxes return TRUE or FALSE, we have to check that
451 // $form_state has been filled as well as what it contains.
452 if (!empty($form_state['values']['ask_first_name']) && $form_state['values']['ask_first_name']) {
453 $form['textfields']['first_name'] = array(
454 '#type' => 'textfield',
455 '#title' => t('First Name'),
456 );
457 }
458 if (!empty($form_state['values']['ask_last_name']) && $form_state['values']['ask_last_name']) {
459 $form['textfields']['last_name'] = array(
460 '#type' => 'textfield',
461 '#title' => t('Last Name'),
462 );
463 }
464
465 $form['submit'] = array(
466 '#type' => 'submit',
467 '#value' => t('Click Me'),
468 );
469
470 return $form;
471 }
472
473 /**
474 * Callback for autotextfields.
475 *
476 * Selects the piece of the form we want to use as replacement text and returns
477 * it as a form (renderable array).
478 *
479 * @return array
480 * Renderable array (the textfields element)
481 */
482 function ajax_example_autotextfields_callback($form, $form_state) {
483 return $form['textfields'];
484 }
485
486
487 /**
488 * A very basic form which with an AJAX-enabled submit.
489 *
490 * On submit, the markup in the #markup element is updated.
491 */
492 function ajax_example_submit_driven_ajax($form, &$form_state) {
493 $form['box'] = array(
494 '#type' => 'markup',
495 '#prefix' => '<div id="box">',
496 '#suffix' => '</div>',
497 '#markup' => '<h1>Initial markup for box</h1>',
498 );
499
500 $form['submit'] = array(
501 '#type' => 'submit',
502 '#ajax' => array(
503 'callback' => 'ajax_example_submit_driven_callback',
504 'wrapper' => 'box',
505 ),
506 '#value' => t('Submit'),
507 );
508
509 return $form;
510 }
511
512 /**
513 * Callback for submit_driven example.
514 *
515 * Select the 'box' element, change the markup in it, and return it as a
516 * renderable array.
517 *
518 * @return array
519 * Renderable array (the box element)
520 */
521 function ajax_example_submit_driven_callback($form, $form_state) {
522 // In most cases, it is recomended that you put this logic in form generation
523 // rather than the callback. Submit driven forms are an exception, because
524 // you may not want to return the form at all.
525 $element = $form['box'];
526 $element['#markup'] = "Clicked submit ({$form_state['values']['op']}): " . date('c');
527 return $element;
528 }
529
530
531 /**
532 * AJAX-based dropdown example form.
533 *
534 * A form with a dropdown whose options are dependent on a
535 * choice made in a previous dropdown.
536 *
537 * On changing the first dropdown, the options in the second
538 * are updated.
539 */
540 function ajax_example_dependent_dropdown($form, &$form_state) {
541 // Get the list of options to populate the first dropdown.
542 $options_first = _ajax_example_get_first_dropdown_options();
543 // If we have a value for the first dropdown from $form_state['values'] we use
544 // this both as the default value for the first dropdown and also as a
545 // parameter to pass to the function that retrieves the options for the
546 // second dropdown.
547 $selected = isset($form_state['values']['dropdown_first']) ? $form_state['values']['dropdown_first'] : key($options_first);
548
549 $form['dropdown_first'] = array(
550 '#type' => 'select',
551 '#title' => 'Instrument Type',
552 '#options' => $options_first,
553 '#default_value' => $selected,
554 // Bind an ajax callback to the change event (which is the default for the
555 // select form type) of the first dropdown. It will replace the second
556 // dropdown when rebuilt.
557 '#ajax' => array(
558 // When 'event' occurs, Drupal will perform an ajax request in the
559 // background. Usually the default value is sufficient (eg. change for
560 // select elements), but valid values include any jQuery event,
561 // most notably 'mousedown', 'blur', and 'submit'.
562 // 'event' => 'change',
563 'callback' => 'ajax_example_dependent_dropdown_callback',
564 'wrapper' => 'dropdown-second-replace',
565 ),
566 );
567
568 $form['dropdown_second'] = array(
569 '#type' => 'select',
570 '#title' => $options_first[$selected] . ' ' . t('Instruments'),
571 // The entire enclosing div created here gets replaced when dropdown_first
572 // is changed.
573 '#prefix' => '<div id="dropdown-second-replace">',
574 '#suffix' => '</div>',
575 // When the form is rebuilt during ajax processing, the $selected variable
576 // will now have the new value and so the options will change.
577 '#options' => _ajax_example_get_second_dropdown_options($selected),
578 '#default_value' => isset($form_state['values']['dropdown_second']) ? $form_state['values']['dropdown_second'] : '',
579 );
580 $form['submit'] = array(
581 '#type' => 'submit',
582 '#value' => t('Submit'),
583 );
584 return $form;
585 }
586
587 /**
588 * Selects just the second dropdown to be returned for re-rendering.
589 *
590 * Since the controlling logic for populating the form is in the form builder
591 * function, all we do here is select the element and return it to be updated.
592 *
593 * @return array
594 * Renderable array (the second dropdown)
595 */
596 function ajax_example_dependent_dropdown_callback($form, $form_state) {
597 return $form['dropdown_second'];
598 }
599
600 /**
601 * Helper function to populate the first dropdown.
602 *
603 * This would normally be pulling data from the database.
604 *
605 * @return array
606 * Dropdown options.
607 */
608 function _ajax_example_get_first_dropdown_options() {
609 // drupal_map_assoc() just makes an array('String' => 'String'...).
610 return drupal_map_assoc(
611 array(
612 t('String'),
613 t('Woodwind'),
614 t('Brass'),
615 t('Percussion'),
616 )
617 );
618 }
619
620 /**
621 * Helper function to populate the second dropdown.
622 *
623 * This would normally be pulling data from the database.
624 *
625 * @param string $key
626 * This will determine which set of options is returned.
627 *
628 * @return array
629 * Dropdown options
630 */
631 function _ajax_example_get_second_dropdown_options($key = '') {
632 $options = array(
633 t('String') => drupal_map_assoc(
634 array(
635 t('Violin'),
636 t('Viola'),
637 t('Cello'),
638 t('Double Bass'),
639 )
640 ),
641 t('Woodwind') => drupal_map_assoc(
642 array(
643 t('Flute'),
644 t('Clarinet'),
645 t('Oboe'),
646 t('Bassoon'),
647 )
648 ),
649 t('Brass') => drupal_map_assoc(
650 array(
651 t('Trumpet'),
652 t('Trombone'),
653 t('French Horn'),
654 t('Euphonium'),
655 )
656 ),
657 t('Percussion') => drupal_map_assoc(
658 array(
659 t('Bass Drum'),
660 t('Timpani'),
661 t('Snare Drum'),
662 t('Tambourine'),
663 )
664 ),
665 );
666 if (isset($options[$key])) {
667 return $options[$key];
668 }
669 else {
670 return array();
671 }
672 }
673 /**
674 * @} End of "defgroup ajax_example".
675 */