Source for file hierselect.php
Documentation is available at hierselect.php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// +----------------------------------------------------------------------+
// | Copyright (c) 1997-2004 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Authors: Herim Vasquez <vasquezh@iro.umontreal.ca> |
// | Bertrand Mansion <bmansion@mamasam.com> |
// | Alexey Borzov <avb@php.net>
// +----------------------------------------------------------------------+
// $Id: hierselect.php,v 1.15 2005/07/18 11:54:08 avb Exp $
require_once('HTML/QuickForm/group.php');
require_once('HTML/QuickForm/select.php');
* Class to dynamically create two or more HTML Select elements
* The first select changes the content of the second select and so on.
* This element is considered as a group. Selects will be named
* groupName[0], groupName[1], groupName[2]...
* @author Herim Vasquez <vasquezh@iro.umontreal.ca>
* @author Bertrand Mansion <bmansion@mamasam.com>
* Options for all the select elements
* Format is a bit more complex as we need to know which options
* are related to the ones in the previous select:
* $select1[1] = 'Classical';
* $select1[2] = 'Funeral doom';
* $select2[0][0] = 'Red Hot Chil Peppers';
* $select2[0][1] = 'The Pixies';
* $select2[1][0] = 'Wagner';
* $select2[1][1] = 'Strauss';
* $select2[2][0] = 'Pantheist';
* $select2[2][1] = 'Skepticism';
* // If only need two selects
* // - and using the depracated functions
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setMainOptions($select1);
* $sel->setSecOptions($select2);
* // - and using the new setOptions function
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setOptions(array($select1, $select2));
* // If you have a third select with prices for the cds
* $select3[0][0][0] = '15.00$';
* $select3[0][0][1] = '17.00$';
* $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:');
* $sel->setOptions(array($select1, $select2, $select3));
* Number of select elements on this group
* The javascript used to set and change the options
* @param string $elementName (optional)Input field name attribute
* @param string $elementLabel (optional)Input field label in form
* @param mixed $attributes (optional)Either a typical HTML attribute string
* or an associative array. Date format is passed along the attributes.
* @param mixed $separator (optional)Use a string for one separator,
* use an array to alternate the separators.
$this->HTML_QuickForm_element ($elementName, $elementLabel, $attributes);
$this->_persistantFreeze = true;
$this->_separator = $separator;
$this->_type = 'hierselect';
$this->_appendName = true;
* Initialize the array structure containing the options for each select element.
* Call the functions that actually do the magic.
* @param array $options Array of options defining each element
$this->_options = $options;
if (empty ($this->_elements)) {
$this->_nbElements = count($this->_options);
$this->_createElements ();
// setDefaults has probably been called before this function
// check if all elements have been created
$totalNbElements = count($this->_options);
for ($i = $this->_nbElements; $i < $totalNbElements; $i ++ ) {
} // end func setMainOptions
* Sets the options for the first select element. Deprecated. setOptions() should be used.
* @param array $array Options for the first select element
$this->_options[0 ] = $array;
if (empty ($this->_elements)) {
$this->_createElements ();
} // end func setMainOptions
* Sets the options for the second select element. Deprecated. setOptions() should be used.
* The main _options array is initialized and the _setOptions function is called.
* @param array $array Options for the second select element
$this->_options[1 ] = $array;
if (empty ($this->_elements)) {
$this->_createElements ();
// setDefaults has probably been called before this function
// check if all elements have been created
for ($i = $this->_nbElements; $i < $totalNbElements; $i ++ ) {
} // end func setSecOptions
* Sets the options for each select element
$array = eval (" return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;" );
$select = & $this->_elements[$key];
$select->_options = array ();
$select->loadArray ($array);
$value = is_array($v = $select->getValue ()) ? $v[0 ] : key($array);
$toLoad .= '[\'' . str_replace(array ('\\', '\''), array ('\\\\', '\\\''), $value) . '\']';
} // end func _setOptions
* Sets values for group's elements
* @param array $value An array of 2 or more values, for the first,
* the second, the third etc. select
$this->_nbElements = count($value);
parent ::setValue ($value);
* Creates all the elements for the group
function _createElements ()
for ($i = 0; $i < $this->_nbElements; $i++ ) {
} // end func _createElements
if (!$this->_flagFrozen) {
// set the onchange attribute for each element except last
for ($i = 0; $i < count($keys) - 1; $i++ ) {
$select = & $this->_elements[$keys[$i]];
$onChange[$i] = $select->getAttribute ('onchange');
$select->updateAttributes (
array ('onchange' => '_hs_swapOptions(this.form, \'' . $this->_escapeString ($this->getName ()) . '\', ' . $keys[$i] . ');' . $onChange[$i])
// create the js function to call
if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) {
$this->_js .= <<<JAVASCRIPT
function _hs_findOptions(ary, keys)
} else if (0 == keys.length) {
return _hs_findOptions(ary[key], keys);
function _hs_findSelect(form, groupName, selectIndex)
if (groupName+'['+ selectIndex +']' in form) {
return form[groupName+'['+ selectIndex +']'];
return form[groupName+'['+ selectIndex +'][]'];
function _hs_replaceOptions(ctl, optionList)
ctl.options[j++] = new Option(optionList[i], i, false, false);
function _hs_setValue(ctl, value)
if (value instanceof Array) {
for (var i = 0; i < value.length; i++) {
testValue[value[i]] = true;
for (var i = 0; i < ctl.options.length; i++) {
if (ctl.options[i].value in testValue) {
ctl.options[i].selected = true;
function _hs_swapOptions(form, groupName, selectIndex)
for (var i = 0; i <= selectIndex; i++) {
hsValue[i] = _hs_findSelect(form, groupName, i).value;
_hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1),
_hs_findOptions(_hs_options[groupName][selectIndex], hsValue));
if (selectIndex + 1 < _hs_options[groupName].length) {
_hs_swapOptions(form, groupName, selectIndex + 1);
function _hs_onReset(form, groupNames)
for (var i = 0; i < groupNames.length; i++) {
for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) {
_hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]);
if (j < _hs_options[groupNames[i]].length) {
_hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1),
_hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1)));
if (!(e instanceof TypeError)) {
function _hs_setupOnReset(form, groupNames)
setTimeout(function() { _hs_onReset(form, groupNames); }, 25);
for (var i = 0; i < document.forms.length; i++) {
for (var j in _hs_defaults) {
if (ctl = _hs_findSelect(document.forms[i], j, 0)) {
for (var k = 0; k < _hs_defaults[j].length; k++) {
_hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]);
var _hs_prevOnload = null;
_hs_prevOnload = window.onload;
window.onload = _hs_onReload;
define('HTML_QUICKFORM_HIERSELECT_EXISTS', true );
for ($i = 1; $i < $this->_nbElements; $i++ ) {
$jsParts[] = $this->_convertArrayToJavascript ($this->_options[$i]);
$this->_js .= "\n_hs_options['" . $this->_escapeString ($this->getName ()) . "'] = [\n" .
// default value; if we don't actually have any values yet just use
// the first option (for single selects) or empty array (for multiple)
if (is_array($v = $this->_elements[$key]->getValue ())) {
$values[] = count($v) > 1? $v: $v[0 ];
// XXX: accessing the supposedly private _options array
$values[] = $this->_elements[$key]->getMultiple () || empty ($this->_elements[$key]->_options [0 ])?
$this->_elements[$key]->_options [0 ]['attr']['value'];
$this->_js .= "_hs_defaults['" . $this->_escapeString ($this->getName ()) . "'] = " .
$this->_convertArrayToJavascript ($values, false ) . ";\n";
include_once('HTML/QuickForm/Renderer/Default.php');
$renderer->setElementTemplate ('{element}');
parent ::accept ($renderer);
for ($i = 0; $i < count($keys) - 1; $i++ ) {
$this->_elements[$keys[$i]]->updateAttributes (array ('onchange' => $onChange[$i]));
return (empty ($this->_js)? '': "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>") .
function accept(&$renderer, $required = false , $error = null )
$renderer->renderElement ($this, $required, $error);
// {{{ onQuickFormEvent()
if ('updateValue' == $event) {
// we need to call setValue() so that the secondary option
// matches the main option
$ret = parent ::onQuickFormEvent ($event, $arg, $caller);
// add onreset handler to form to properly reset hierselect (see bug #2970)
if ('addElement' == $event) {
$onReset = $caller->getAttribute ('onreset');
if (strpos($onReset, '_hs_setupOnReset')) {
$caller->updateAttributes (array ('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString ($this->getName ()) . "', ", $onReset)));
$caller->updateAttributes (array ('onreset' => " var temp = function() { {$onReset} } ; if (!temp()) { return false; } ; if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString ($this->getName ()) . "']); } "));
$caller->updateAttributes (array ('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString ($this->getName ()) . "']); } "));
} // end func onQuickFormEvent
// {{{ _convertArrayToJavascript()
* Converts PHP array to its Javascript analog
* @param array PHP array to convert
* @param bool Generate Javascript object literal (default, works like PHP's associative array) or array literal
* @return string Javascript representation of the value
function _convertArrayToJavascript ($array, $assoc = true )
return $this->_convertScalarToJavascript ($array);
foreach ($array as $key => $val) {
$item = $assoc? "'" . $this->_escapeString ($key) . "': ": '';
$item .= $this->_convertArrayToJavascript ($val, $assoc);
$item .= $this->_convertScalarToJavascript ($val);
return $assoc? '{ ' . $js . ' }': '[' . $js . ']';
// {{{ _convertScalarToJavascript()
* Converts PHP's scalar value to its Javascript analog
* @param mixed PHP value to convert
* @return string Javascript representation of the value
function _convertScalarToJavascript ($val)
return $val ? 'true' : 'false';
return "'" . $this->_escapeString ($val) . "'";
* Quotes the string so that it can be used in Javascript string constants
function _escapeString ($str)
} // end class HTML_QuickForm_hierselect
Documentation generated on Mon, 11 Mar 2019 14:16:33 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.
|