Source for file dualselect.php
Documentation is available at dualselect.php
* Usage example for HTML_QuickForm2 package: custom element and renderer plugin
* The example demonstrates a custom element with special rendering needs and
* shows how it can be output via a renderer plugin. The example element is
* a (much) simpler version of HTML_QuickForm_advmultiselect.
* It also demonstrates how to plug in element's javascript and how to use
* client-side validation with custom element.
require_once 'HTML/QuickForm2.php';
require_once 'HTML/QuickForm2/Element/Select.php';
require_once 'HTML/QuickForm2/Renderer.php';
require_once 'HTML/QuickForm2/Renderer/Plugin.php';
* This element can be used instead of a normal multiple select. It renders as
* two multiple selects and two buttons for moving options between them.
* The values that end up in the "to" select are considered selected.
protected $attributes = array ('multiple' => 'multiple');
if ('multiple' == $name && 'multiple' != $value) {
"Required 'multiple' attribute cannot be changed"
parent ::onAttributeChange ($name, $value);
"<table class=\"dualselect\" id=\"{id}\">\n" .
" <td style=\"vertical-align: top;\">{select_from}</td>\n" .
" <td style=\"vertical-align: middle;\">{button_from_to}<br />{button_to_from}</td>\n" .
" <td style=\"vertical-align: top;\">{select_to}</td>\n" .
public function render(HTML_QuickForm2_Renderer $renderer)
// render as a normal select when frozen
$renderer->renderElement ($this);
$jsBuilder = $renderer->getJavascriptBuilder ();
$jsBuilder->addLibrary ('dualselect', 'dualselect.js', 'js/',
dirname(__FILE__ ) . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR );
$keepSorted = empty ($this->data['keepSorted'])? 'false': 'true';
$jsBuilder->addElementJavascript (" qf.elements.dualselect.init('{$this->getId()}', { $keepSorted});" );
// Fall back to using the Default renderer if custom one does not have a plugin
if ($renderer->methodExists ('renderDualSelect')) {
$renderer->renderDualSelect ($this);
$renderer->renderElement ($this);
" _{$name}" , array ('id' => "{ $id}-from" ) + $this->attributes
$name, array ('id' => "{ $id}-to" ) + $this->attributes
// We don't do optgroups here
$value = $option['attr']['value'];
unset ($option['attr']['value']);
if (in_array($value, $strValues, true )) {
$selectTo->addOption ($option['text'], $value,
empty ($option['attr'])? null: $option['attr']);
$selectFrom->addOption ($option['text'], $value,
empty ($option['attr'])? null: $option['attr']);
'button', "{ $name}_fromto" ,
array ('type' => 'button', 'id' => "{ $id}-fromto" ) +
(empty ($this->data['from_to']['attributes'])? array (): self ::prepareAttributes ($this->data['from_to']['attributes'])),
array ('content' => (empty ($this->data['from_to']['content'])? ' >> ': $this->data['from_to']['content']))
'button', "{ $name}_tofrom" ,
array ('type' => 'button', 'id' => "{ $id}-tofrom" ) +
(empty ($this->data['to_from']['attributes'])? array (): self ::prepareAttributes ($this->data['to_from']['attributes'])),
array ('content' => (empty ($this->data['to_from']['content'])? ' << ': $this->data['to_from']['content']))
'select_from' => $selectFrom->__toString (), 'select_to' => $selectTo->__toString (),
'button_from_to' => $buttonFromTo->__toString (), 'button_to_from' => $buttonToFrom->__toString ()
* Returns Javascript code for getting the element's value
* All options in "to" select are considered dualselect's values,
* we need to use an implementation different from that for a standard
* select-multiple. When returning a parameter for getContainerValue()
* we should also provide the element's name.
* @param bool Whether it should return a parameter for qf.form.getContainerValue()
return " {name: '{$this->getName()}[]', value: qf.elements.dualselect.getValue('{ $this->getId()}-to')}";
return " qf.elements.dualselect.getValue('{$this->getId()}-to')";
return array ("{ $id}-from" , "{ $id}-to" , "{ $id}-fromto" , "{ $id}-tofrom" );
* Renderer plugin for outputting dualselect
* A plugin is needed since we want to control outputting the selects and
* buttons via the template. Also default template contains placeholders for
public function setRenderer(HTML_QuickForm2_Renderer $renderer)
if (empty ($this->renderer->templatesForClass ['html_quickform2_element_dualselect'])) {
$this->renderer->templatesForClass ['html_quickform2_element_dualselect'] = <<<TPL
<qf:required><span class="required">* </span></qf:required>
<qf:label><label for="{id}-from" class="element">{label}</label></qf:label>
<div class="element<qf:error> error</qf:error>">
<qf:error><span class="error">{error}<br /></span></qf:error>
<table class="dualselect" id="{id}">
<td style="vertical-align: top;">{select_from}</td>
<td style="vertical-align: middle;">{button_from_to}<br />{button_to_from}</td>
<td style="vertical-align: top;">{select_to}</td>
$elTpl = $this->renderer->prepareTemplate ($this->renderer->findTemplate ($element), $element);
foreach ($element->toArray () as $k => $v) {
// Now we register both the element and the renderer plugin
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
/* Set up custom font and form width */
font-family: Arial,sans-serif;
/* Use default styles included with the package */
if ('@data_dir@' != '@' . 'data_dir@') {
$filename = '@data_dir@/HTML_QuickForm2/quickform.css';
<title>HTML_QuickForm2 dualselect example: custom element and renderer plugin</title>
4 => "Afghanistan", 8 => "Albania", 12 => "Algeria", 20 => "Andorra", 24 => "Angola", 28 => "Antigua and Barbuda", 32 => "Argentina", 51 => "Armenia", 36 => "Australia", 40 => "Austria",
31 => "Azerbaijan", 44 => "Bahamas", 48 => "Bahrain", 50 => "Bangladesh", 52 => "Barbados", 112 => "Belarus", 56 => "Belgium", 84 => "Belize", 204 => "Benin", 64 => "Bhutan",
68 => "Bolivia", 70 => "Bosnia and Herzegovina", 72 => "Botswana", 76 => "Brazil", 96 => "Brunei Darussalam", 100 => "Bulgaria", 854 => "Burkina Faso", 108 => "Burundi", 116 => "Cambodia", 120 => "Cameroon",
124 => "Canada", 132 => "Cape Verde", 140 => "Central African Republic", 148 => "Chad", 152 => "Chile", 156 => "China", 170 => "Colombia", 174 => "Comoros", 178 => "Congo", 180 => "Congo, Democratic Republic of",
184 => "Cook Islands", 188 => "Costa Rica", 384 => "Cote D'Ivoire", 191 => "Croatia", 192 => "Cuba", 196 => "Cyprus", 203 => "Czech Republic", 208 => "Denmark", 262 => "Djibouti", 212 => "Dominica",
214 => "Dominican Republic", 218 => "Ecuador", 818 => "Egypt", 222 => "El Salvador", 226 => "Equatorial Guinea", 232 => "Eritrea", 233 => "Estonia", 231 => "Ethiopia", 242 => "Fiji", 246 => "Finland",
250 => "France", 266 => "Gabon", 270 => "Gambia", 268 => "Georgia", 276 => "Germany", 288 => "Ghana", 300 => "Greece", 308 => "Grenada", 320 => "Guatemala", 324 => "Guinea",
624 => "Guinea-Bissau", 328 => "Guyana", 332 => "Haiti", 336 => "Holy See (Vatican City State)", 340 => "Honduras", 348 => "Hungary", 352 => "Iceland", 356 => "India", 360 => "Indonesia", 364 => "Iran",
368 => "Iraq", 372 => "Ireland", 376 => "Israel", 380 => "Italy", 388 => "Jamaica", 392 => "Japan", 400 => "Jordan", 398 => "Kazakhstan", 404 => "Kenya", 296 => "Kiribati",
408 => "Korea, Democratic People's Republic of", 410 => "Korea, Republic of", 414 => "Kuwait", 417 => "Kyrgyz Republic", 418 => "Laos", 428 => "Latvia", 422 => "Lebanon", 426 => "Lesotho", 430 => "Liberia", 434 => "Libya",
438 => "Liechtenstein", 440 => "Lithuania", 442 => "Luxembourg", 807 => "Macedonia", 450 => "Madagascar", 454 => "Malawi", 458 => "Malaysia", 462 => "Maldives", 466 => "Mali", 470 => "Malta",
584 => "Marshall Islands", 474 => "Martinique", 478 => "Mauritania", 480 => "Mauritius", 484 => "Mexico", 583 => "Micronesia", 498 => "Moldova", 492 => "Monaco", 496 => "Mongolia", 499 => "Montenegro",
504 => "Morocco", 508 => "Mozambique", 104 => "Myanmar", 516 => "Namibia", 520 => "Nauru", 524 => "Nepal", 528 => "Netherlands", 554 => "New Zealand", 558 => "Nicaragua", 562 => "Niger",
566 => "Nigeria", 570 => "Niue", 578 => "Norway", 512 => "Oman", 586 => "Pakistan", 585 => "Palau", 591 => "Panama", 598 => "Papua New Guinea", 600 => "Paraguay", 604 => "Peru",
608 => "Philippines", 616 => "Poland", 620 => "Portugal", 634 => "Qatar", 642 => "Romania", 643 => "Russian Federation", 646 => "Rwanda", 882 => "Samoa", 674 => "San Marino", 678 => "Sao Tome and Principe",
682 => "Saudi Arabia", 686 => "Senegal", 688 => "Serbia", 690 => "Seychelles", 694 => "Sierra Leone", 702 => "Singapore", 703 => "Slovakia", 705 => "Slovenia", 90 => "Solomon Islands", 706 => "Somalia",
710 => "South Africa", 724 => "Spain", 144 => "Sri Lanka", 659 => "St. Kitts and Nevis", 662 => "St. Lucia", 670 => "St. Vincent and the Grenadines", 736 => "Sudan", 740 => "Suriname", 748 => "Swaziland", 752 => "Sweden",
756 => "Switzerland", 760 => "Syria", 158 => "Taiwan", 762 => "Tajikistan", 834 => "Tanzania", 764 => "Thailand", 626 => "Timor-Leste", 768 => "Togo", 776 => "Tonga", 780 => "Trinidad and Tobago",
788 => "Tunisia", 792 => "Turkey", 795 => "Turkmenistan", 798 => "Tuvalu", 800 => "Uganda", 804 => "Ukraine", 784 => "United Arab Emirates", 826 => "United Kingdom of Great Britain & N. Ireland", 840 => "United States of America", 858 => "Uruguay",
860 => "Uzbekistan", 548 => "Vanuatu", 862 => "Venezuela", 704 => "Viet Nam", 732 => "Western Sahara", 887 => "Yemen", 894 => "Zambia", 716 => "Zimbabwe"
'destinations' => array (4 , 148 , 180 , 368 , 706 , 736 , 716 )
$fs = $form->addElement ('fieldset')
->setLabel ('A custom "dualselect" element using a renderer plugin for output');
'dualselect', 'destinations',
array ('size' => 10 , 'style' => 'width: 215px; font-size: 90%'),
'from_to' => array ('content' => ' >> ', 'attributes' => array ('style' => 'font-size: 90%')),
'to_from' => array ('content' => ' << ', 'attributes' => array ('style' => 'font-size: 90%')),
'Popular travel destinations:',
$ds->addRule ('required', 'Select at least two destinations', 2 ,
$fs->addElement ('checkbox', 'doFreeze', null , array ('content' => 'Freeze dualselect on form submit'));
$fs->addElement ('submit', 'testSubmit', array ('value' => 'Submit form'));
// outputting form values
if ('POST' == $_SERVER['REQUEST_METHOD']) {
$value = $form->getValue ();
if (!empty ($value['doFreeze'])) {
$form->render ($renderer);
echo $renderer->getJavascriptBuilder ()->getLibraries (true , true );
Documentation generated on Wed, 10 Apr 2019 08:56:08 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|