Source for file advmultiselect.php
Documentation is available at advmultiselect.php
* Copyright (c) 2005-2008, Laurent Laville <pear@laurent-laville.org>
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the authors nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* @package HTML_QuickForm_advmultiselect
* @author Laurent Laville <pear@laurent-laville.org>
* @copyright 2005-2008 Laurent Laville
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @version CVS: $Id: advmultiselect.php,v 1.18 2008/04/26 17:37:00 farell Exp $
* @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
* @since File available since Release 0.4.0
require_once 'HTML/QuickForm/select.php';
* Element for HTML_QuickForm that emulate a multi-select.
* The HTML_QuickForm_advmultiselect package adds an element to the
* HTML_QuickForm package that is two select boxes next to each other
* emulating a multi-select.
* @package HTML_QuickForm_advmultiselect
* @author Laurent Laville <pear@laurent-laville.org>
* @copyright 2005-2008 Laurent Laville
* @license http://www.opensource.org/licenses/bsd-license.php BSD
* @version Release: @package_version@
* @link http://pear.php.net/package/HTML_QuickForm_advmultiselect
* @since Class available since Release 0.4.0
* Prefix function name in javascript move selections
* Postfix function name in javascript move selections
* Associative array of the multi select container attributes
* Associative array of the add button attributes
var $_addButtonAttributes;
* Associative array of the remove button attributes
var $_removeButtonAttributes;
* Associative array of the select all button attributes
var $_allButtonAttributes;
* Associative array of the select none button attributes
var $_noneButtonAttributes;
* Associative array of the toggle selection button attributes
var $_toggleButtonAttributes;
* Associative array of the move up button attributes
var $_upButtonAttributes;
* Associative array of the move up button attributes
var $_downButtonAttributes;
* Defines if both list (unselected, selected) will have their elements be
* arranged from lowest to highest (or reverse)
* depending on comparaison function.
* SORT_ASC is used to sort in ascending order
* SORT_DESC is used to sort in descending order
* @var string ('none' == false, 'asc' == SORT_ASC, 'desc' == SORT_DESC)
* Associative array of the unselected item box attributes
var $_attributesUnselected;
* Associative array of the selected item box attributes
var $_attributesSelected;
* Associative array of the internal hidden box attributes
* Default Element template string
var $_elementTemplate = '
<!-- BEGIN label_2 --><tr><th>{label_2}</th><!-- END label_2 -->
<!-- BEGIN label_3 --><th> </th><th>{label_3}</th></tr><!-- END label_3 -->
<td valign="top">{unselected}</td>
<td align="center">{add}{remove}</td>
<td valign="top">{selected}</td>
* Default Element stylesheet string
border-left: 1px solid #404040;
border-top: 1px solid #404040;
border-bottom: 1px solid #d4d0c8;
border-right: 1px solid #d4d0c8;
* Zend Engine 1 uses HTML_QuickForm_advmultiselect, while
* Zend Engine 2 uses __construct
* @param string $elementName Dual Select name attribute
* @param mixed $elementLabel Label(s) for the select boxes
* @param mixed $options Data to be used to populate options
* @param mixed $attributes Either a typical HTML attribute string or
* @param integer $sort Either SORT_ASC for auto ascending arrange,
* SORT_DESC for auto descending arrange, or
* NULL for no sort (append at end: default)
$options = null , $attributes = null ,
$this->HTML_QuickForm_select ($elementName, $elementLabel,
// add multiple selection attribute by default if missing
$this->updateAttributes (array ('multiple' => 'multiple'));
if (is_null($this->getAttribute ('size'))) {
// default size is ten item on each select box (left and right)
$this->updateAttributes (array ('size' => 10 ));
if (is_null($this->getAttribute ('style'))) {
// default width of each select box
$this->updateAttributes (array ('style' => 'width:100px;'));
$this->_tableAttributes = $this->getAttribute ('class');
if (is_null($this->_tableAttributes)) {
$attr = array ('border' => '0',
'cellpadding' => '10', 'cellspacing' => '0');
$attr = array ('class' => $this->_tableAttributes);
$this->_removeAttr ('class', $this->_attributes);
$this->_tableAttributes = $this->_getAttrString ($attr);
// set default add button attributes
// set default remove button attributes
// set default selectall button attributes
// set default selectnone button attributes
// set default toggle selection button attributes
// set default move up button attributes
// set default move up button attributes
// defines javascript functions names
// set select boxes sort order (none by default)
if ($sort === SORT_ASC ) {
} elseif ($sort === SORT_DESC ) {
* Sets the button attributes
* In <b>custom example 1</b>, the <i>add</i> and <i>remove</i> buttons
* have look set by the css class <i>inputCommand</i>.
* In <b>custom example 2</b>, the basic text <i>add</i> and <i>remove</i>
* buttons are now replaced by images.
* In <b>custom example 5</b>, we have ability to sort the selection list
* - <b>user-end</b>: with <i>Up</i> and <i>Down</i> buttons
* - <b>programming</b>: with the QF element constructor $sort option
* @param string $button Button identifier, either 'add', 'remove',
* 'all', 'none', 'toggle',
* @param mixed $attributes (optional) Either a typical HTML attribute string
* or an associative array
* @throws PEAR_Error $button argument
* is not a string, or not in range
* (add, remove, all, none, toggle, moveup, movedown)
* @example examples/qfams_custom_5.php
* Custom example 5: source code
* @link http://www.laurent-laville.org/img/qfams/screenshot/custom5.png
* Custom example 5: screenshot
* @example examples/qfams_custom_2.php
* Custom example 2: source code
* @link http://www.laurent-laville.org/img/qfams/screenshot/custom2.png
* Custom example 2: screenshot
* @example examples/qfams_custom_1.php
* Custom example 1: source code
* @link http://www.laurent-laville.org/img/qfams/screenshot/custom1.png
* Custom example 1: screenshot
return PEAR ::raiseError ('Argument 1 of ' .
'advmultiselect::setButtonAttributes is not a string');
$this->_addButtonAttributes
$this->_updateAttrArray ($this->_addButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_removeButtonAttributes
= array ('name' => 'remove',
$this->_updateAttrArray ($this->_removeButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_allButtonAttributes
'value' => ' Select All ',
$this->_updateAttrArray ($this->_allButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_noneButtonAttributes
= array ('name' => 'none',
'value' => ' Select None ',
$this->_updateAttrArray ($this->_noneButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_toggleButtonAttributes
= array ('name' => 'toggle',
'value' => ' Toggle Selection ',
$this->_updateAttrArray ($this->_toggleButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_upButtonAttributes
$this->_updateAttrArray ($this->_upButtonAttributes,
$this->_parseAttributes ($attributes));
$this->_downButtonAttributes
= array ('name' => 'down',
$this->_updateAttrArray ($this->_downButtonAttributes,
$this->_parseAttributes ($attributes));
return PEAR ::raiseError ('Argument 1 of ' .
'advmultiselect::setButtonAttributes has unexpected value');
* @param string $html The HTML surrounding select boxes and buttons
$this->_elementTemplate = $html;
* Sets JavaScript function name parts. Maybe usefull to avoid conflict names
* In <b>multiple example 1</b>, the javascript function prefix
* @param string $pref (optional) Prefix name
* @param string $post (optional) Postfix name
* @deprecated since version 1.3.0
* @example examples/qfams_multiple_1.php
* Multiple example 1: source code
* @link http://www.laurent-laville.org/img/qfams/screenshot/multiple1.png
* Multiple example 1: screenshot
function setJsElement($pref = null , $post = 'moveSelections')
$this->_jsPrefix = 'qfams';
$this->_jsPostfix = 'MoveSelection';
* Gets default element stylesheet for a single multi-select shape render
* In <b>custom example 4</b>, the template defined allows
* a single multi-select checkboxes shape. Useful when javascript is disabled
* (or when browser is not js compliant). In our example, no need to add
* javascript code, but css is mandatory.
* @param boolean $raw (optional) html output with style tags or just raw data
* @example qfams_custom_4.php
* Custom example 4: source code
* @link http://www.laurent-laville.org/img/qfams/screenshot/custom4.png
* Custom example 4: screenshot
$id = $this->getAttribute ('name');
$css = '<style type="text/css">' . PHP_EOL
. '<!--' . $css . '// -->' . PHP_EOL
* Returns the HTML generated for the advanced mutliple select component
if ($this->_flagFrozen) {
return $this->getFrozenHtml ();
$tabs = $this->_getTabs ();
if ($this->getComment () != '') {
$strHtml .= $tabs . '<!-- ' . $this->getComment () . " //-->" . PHP_EOL;
$selectId = $this->getName ();
$selectName = $this->getName () . '[]';
$selectNameFrom = $this->getName () . '-f[]';
$selectNameTo = $this->getName () . '-t[]';
// placeholder {unselected} existence determines if we will render
if (strpos($this->_elementTemplate, '{unselected}') === false ) {
// ... a single multi-select with checkboxes
$this->_jsPostfix = 'EditSelection';
$id = $this->getAttribute ('name');
$strHtmlSelected = $tab . '<div id="qfams_'. $id. '">' . PHP_EOL;
$unselected_count = count($this->_options);
foreach ($this->_options as $option) {
= array ('style', 'class', 'onmouseover', 'onmouseout');
$labelAttributes = array ();
foreach ($_labelAttributes as $attr) {
if (isset ($option['attr'][$attr])) {
$labelAttributes[$attr] = $option['attr'][$attr];
unset ($option['attr'][$attr]);
&& in_array((string) $option['attr']['value'], $this->_values)) {
// The items is *selected*
$checked = ' checked="checked"';
// The item is *unselected* so we want to put it
. $this->_getAttrString ($labelAttributes) . '>'
. '<input type="checkbox"'
. ' id="'. $selectId . $checkbox_id_suffix. '"'
. ' name="'. $selectName. '"'
. $this->_getAttrString ($option['attr'])
. ' />' . $option['text'] . '</label>'
$strHtmlSelected .= $tab . '</div>'. PHP_EOL;
// build the select all button with all its attributes
$jsName = $this->_jsPrefix . $this->_jsPostfix;
$attributes = array ('onclick' => $jsName .
"('". $selectId . "', 1);");
$this->_allButtonAttributes
= array_merge($this->_allButtonAttributes, $attributes);
$attrStrAll = $this->_getAttrString ($this->_allButtonAttributes);
$strHtmlAll = " <input$attrStrAll />". PHP_EOL;
// build the select none button with all its attributes
$attributes = array ('onclick' => $jsName .
"('". $selectId . "', 0);");
$this->_noneButtonAttributes
= array_merge($this->_noneButtonAttributes, $attributes);
$attrStrNone = $this->_getAttrString ($this->_noneButtonAttributes);
$strHtmlNone = " <input$attrStrNone />". PHP_EOL;
// build the toggle selection button with all its attributes
$attributes = array ('onclick' => $jsName .
"('". $selectId . "', 2);");
$this->_toggleButtonAttributes
$attrStrToggle = $this->_getAttrString ($this->_toggleButtonAttributes);
$strHtmlToggle = " <input$attrStrToggle />". PHP_EOL;
// default selection counters
$strHtmlSelectedCount = $selected_count . '/' . $unselected_count;
// ... or a dual multi-select
$this->_jsPostfix = 'MoveSelection';
$jsName = $this->_jsPrefix . $this->_jsPostfix;
// set name of Select From Box
$this->_attributesUnselected
= array ('id' => $selectId . '-f',
'name' => $selectNameFrom,
'ondblclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
" 'add', '{$this->_sort}') ");
= array_merge ($this->_attributes, $this->_attributesUnselected);
$attrUnselected = $this->_getAttrString ($this->_attributesUnselected);
// set name of Select To Box
= array ('id' => $selectId . '-t',
'ondblclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], ".
"this.form.elements['" . $selectName . "'], " .
"'remove', '{ $this->_sort}') ");
= array_merge ($this->_attributes, $this->_attributesSelected);
$attrSelected = $this->_getAttrString ($this->_attributesSelected);
// set name of Select hidden Box
= array ('name' => $selectName,
'style' => 'overflow: hidden; visibility: hidden; ' .
'width: 1px; height: 0;');
= array_merge ($this->_attributes, $this->_attributesHidden);
$attrHidden = $this->_getAttrString ($this->_attributesHidden);
// prepare option tables to be displayed as in POST order
$append = count ($this->_values);
$arrHtmlSelected = array_fill(0, $append, ' ');
$arrHtmlSelected = array();
$options = count($this->_options);
$arrHtmlUnselected = array ();
$arrHtmlHidden = array_fill(0, $options, ' ');
foreach ($this->_options as $option) {
if (is_array($this->_values)
&& in_array ((string) $option['attr']['value'],
$key = array_search($option['attr']['value'],
/** The items is *selected* so we want to put it
in the 'selected' multi-select */
$arrHtmlSelected[$key] = $option;
/** Add it to the 'hidden' multi-select
and set it as 'selected' */
$option['attr']['selected'] = 'selected';
$arrHtmlHidden[$key] = $option;
/** The item is *unselected* so we want to put it
in the 'unselected' multi-select */
$arrHtmlUnselected[] = $option;
// Add it to the hidden multi-select as 'unselected'
$arrHtmlHidden[$append] = $option;
$arrHtmlHidden = array();
// The 'unselected' multi-select which appears on the left
$unselected_count = count($arrHtmlUnselected);
if ($unselected_count == 0) {
$this->_attributesUnselected['disabled'] = 'disabled';
= array_merge ($this->_attributes, $this->_attributesUnselected);
$attrUnselected = $this->_getAttrString ($this->_attributesUnselected);
$strHtmlUnselected = "<select$attrUnselected>". PHP_EOL;
if ($unselected_count > 0) {
foreach ($arrHtmlUnselected as $data) {
. '<option' . $this->_getAttrString ($data['attr']) . '>'
. $data['text'] . '</option>' . PHP_EOL;
$strHtmlUnselected .= '<option value=""> </option>';
$strHtmlUnselected .= '</select>';
// The 'selected' multi-select which appears on the right
$selected_count = count($arrHtmlSelected);
if ($selected_count == 0) {
$this->_attributesSelected['disabled'] = 'disabled';
= array_merge ($this->_attributes, $this->_attributesSelected);
$attrSelected = $this->_getAttrString ($this->_attributesSelected);
$strHtmlSelected = "<select$attrSelected>". PHP_EOL;
if ($selected_count > 0) {
foreach ($arrHtmlSelected as $data) {
. '<option' . $this->_getAttrString ($data['attr']) . '>'
. $data['text'] . '</option>' . PHP_EOL;
$strHtmlSelected .= '<option value=""> </option>';
$strHtmlSelected .= '</select>';
// The 'hidden' multi-select
$strHtmlHidden = "<select$attrHidden>". PHP_EOL;
if (count($arrHtmlHidden) > 0) {
foreach ($arrHtmlHidden as $data) {
. '<option' . $this->_getAttrString ($data['attr']) . '>'
. $data['text'] . '</option>' . PHP_EOL;
$strHtmlHidden .= '</select>';
// build the remove button with all its attributes
= array('onclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
"'remove', '{ $this->_sort}'); return false; ");
= array_merge ($this->_removeButtonAttributes, $attributes);
$attrStrRemove = $this->_getAttrString ($this->_removeButtonAttributes);
$strHtmlRemove = "<input$attrStrRemove />". PHP_EOL;
// build the add button with all its attributes
= array('onclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
"'add', '{ $this->_sort}'); return false; ");
= array_merge ($this->_addButtonAttributes, $attributes);
$attrStrAdd = $this->_getAttrString ($this->_addButtonAttributes);
$strHtmlAdd = "<input$attrStrAdd />". PHP_EOL;
// build the select all button with all its attributes
= array('onclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
"'all', '{ $this->_sort}'); return false; ");
= array_merge ($this->_allButtonAttributes, $attributes);
$attrStrAll = $this->_getAttrString ($this->_allButtonAttributes);
$strHtmlAll = "<input$attrStrAll />". PHP_EOL;
// build the select none button with all its attributes
= array('onclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
"'none', '{ $this->_sort}'); return false; ");
= array_merge ($this->_noneButtonAttributes, $attributes);
$attrStrNone = $this->_getAttrString ($this->_noneButtonAttributes);
$strHtmlNone = "<input$attrStrNone />". PHP_EOL;
// build the toggle button with all its attributes
= array('onclick' => $jsName .
"this.form.elements['" . $selectNameFrom . "'], " .
"this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "'], " .
"'toggle', '{ $this->_sort}'); return false; ");
= array_merge ($this->_toggleButtonAttributes, $attributes);
$attrStrToggle = $this->_getAttrString ($this->_toggleButtonAttributes);
$strHtmlToggle = "<input$attrStrToggle />". PHP_EOL;
// build the move up button with all its attributes
= array('onclick' => "{ $this->_jsPrefix}MoveUp " .
"(this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "']); " .
= array_merge ($this->_upButtonAttributes, $attributes);
$attrStrUp = $this->_getAttrString ($this->_upButtonAttributes);
$strHtmlMoveUp = "<input$attrStrUp />". PHP_EOL;
// build the move down button with all its attributes
= array('onclick' => "{ $this->_jsPrefix}MoveDown " .
"(this.form.elements['" . $selectNameTo . "'], " .
"this.form.elements['" . $selectName . "']); " .
= array_merge ($this->_downButtonAttributes, $attributes);
$attrStrDown = $this->_getAttrString ($this->_downButtonAttributes);
$strHtmlMoveDown = "<input$attrStrDown />". PHP_EOL;
// default selection counters
$strHtmlSelectedCount = $selected_count;
$strHtmlUnselectedCount = $unselected_count;
$strHtmlSelectedCountId = $selectId .'_selected';
$strHtmlUnselectedCountId = $selectId .'_unselected';
// render all part of the multi select component with the template
$strHtml = $this->_elementTemplate;
// Prepare multiple labels
$labels = $this->getLabel ();
// render extra labels, if any
foreach ($labels as $key => $text) {
$key = is_int($key)? $key + 2: $key;
$strHtml = str_replace("{label_{ $key}}" , $text, $strHtml);
$strHtml = str_replace("<!-- BEGIN label_{ $key} -->" , '', $strHtml);
$strHtml = str_replace("<!-- END label_{ $key} -->" , '', $strHtml);
// clean up useless label tags
if (strpos($strHtml, '{label_')) {
$strHtml = preg_replace('/\s*<!-- BEGIN label_(\S+) -->'.
'.*<!-- END label_\1 -->\s*/i', '', $strHtml);
'{stylesheet}', '{javascript}',
'{unselected_count_id}', '{selected_count_id}',
'{unselected_count}', '{selected_count}',
'{unselected}', '{selected}',
'{all}', '{none}', '{toggle}',
$strHtmlUnselectedCountId, $strHtmlSelectedCountId,
$strHtmlUnselectedCount, $strHtmlSelectedCount,
$strHtmlUnselected, $strHtmlSelected . $strHtmlHidden,
$strHtmlAdd, $strHtmlRemove,
$strHtmlAll, $strHtmlNone, $strHtmlToggle,
$strHtmlMoveUp, $strHtmlMoveDown
$strHtml = str_replace ($placeHolders, $htmlElements, $strHtml);
* Returns the javascript code generated to handle this element
* @param boolean $raw (optional) html output with script tags or just raw data
function getElementJs($raw = true)
$js = '@data_dir@' . DIRECTORY_SEPARATOR
. '@package_name@' . DIRECTORY_SEPARATOR
$js = file_get_contents($js);
$js = '<script type="text/javascript">'
. PHP_EOL . '//<![CDATA['
if (class_exists('HTML_QuickForm')) {
HTML_QuickForm::registerElementType('advmultiselect',
'HTML/QuickForm/advmultiselect.php', 'HTML_QuickForm_advmultiselect');
Documentation generated on Sat, 26 Apr 2008 14:30:06 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.
|