15,9 → 15,10 |
// +----------------------------------------------------------------------+ |
// | Authors: Herim Vasquez <vasquezh@iro.umontreal.ca> | |
// | Bertrand Mansion <bmansion@mamasam.com> | |
// | Alexey Borzov <avb@php.net> |
// +----------------------------------------------------------------------+ |
// |
// $Id: hierselect.php,v 1.1 2005-03-30 08:50:33 jpm Exp $ |
// $Id: hierselect.php,v 1.2 2005-09-20 17:01:22 ddelon Exp $ |
|
require_once('HTML/QuickForm/group.php'); |
require_once('HTML/QuickForm/select.php'); |
97,11 → 98,6 |
* @access private |
*/ |
var $_js = ''; |
|
/** |
* The javascript array name |
*/ |
var $_jsArrayName = ''; |
|
// }}} |
// {{{ constructor |
159,7 → 155,6 |
} |
|
$this->_setOptions(); |
$this->_setJS(); |
} // end func setMainOptions |
|
// }}} |
213,7 → 208,6 |
} |
|
$this->_setOptions(); |
$this->_setJS(); |
} // end func setSecOptions |
|
// }}} |
229,16 → 223,14 |
{ |
$toLoad = ''; |
foreach (array_keys($this->_elements) AS $key) { |
if (eval("return isset(\$this->_options[{$key}]{$toLoad});") ) { |
$array = eval("return \$this->_options[{$key}]{$toLoad};"); |
if (is_array($array)) { |
$select =& $this->_elements[$key]; |
$select->_options = array(); |
$select->loadArray($array); |
$array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;"); |
if (is_array($array)) { |
$select =& $this->_elements[$key]; |
$select->_options = array(); |
$select->loadArray($array); |
|
$value = is_array($v = $select->getValue()) ? $v[0] : key($array); |
$toLoad .= '[\''.$value.'\']'; |
} |
$value = is_array($v = $select->getValue()) ? $v[0] : key($array); |
$toLoad .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $value) . '\']'; |
} |
} |
} // end func _setOptions |
279,132 → 271,177 |
} // end func _createElements |
|
// }}} |
// {{{ _setJS() |
|
/** |
* Set the JavaScript for each select element (excluding de main one). |
* |
* @access private |
* @return void |
*/ |
function _setJS() |
{ |
$this->_js = $js = ''; |
$this->_jsArrayName = 'hs_' . $this->getName(); |
for ($i = 1; $i < $this->_nbElements; $i++) { |
$this->_setJSArray($this->_jsArrayName, $this->_options[$i], $js); |
} |
} // end func _setJS |
|
// }}} |
// {{{ _setJSArray() |
|
/** |
* Recursively builds the JavaScript array defining the options that a select |
* element can have. |
* |
* @param string $grpName Group Name attribute |
* @param array $options Select element options |
* @param string $js JavaScript definition is build using this variable |
* @param string $optValue The value for the current JavaScript option |
* |
* @access private |
* @return void |
*/ |
function _setJSArray($grpName, $options, &$js, $optValue = '') |
{ |
if (is_array($options)) { |
$js = ''; |
// For a hierselect containing 3 elements: |
// if option 1 has been selected for the 1st element |
// and option 3 has been selected for the 2nd element, |
// then the javascript array containing the values to load |
// on the 3rd element will have the following name: grpName_1_3 |
$name = ($optValue === '') ? $grpName : $grpName.'_'.$optValue; |
foreach($options AS $k => $v) { |
$this->_setJSArray($name, $v, $js, $k); |
} |
|
// if $js !== '' add it to the JavaScript |
$this->_js .= ($js !== '') ? $name." = {\n".$js."\n}\n" : ''; |
$js = ''; |
} else { |
// $js empty means that we are adding the first element to the JavaScript. |
if ($js != '') { |
$js .= ",\n"; |
} |
$js .= '"'.$optValue.'":"'.$options.'"'; |
} |
} |
|
// }}} |
// {{{ toHtml() |
|
/** |
* Returns Html for the group |
* |
* @access public |
* @return string |
*/ |
function toHtml() |
{ |
if ($this->_flagFrozen) { |
$this->_js = ''; |
} else { |
// set the onchange attribute for each element |
$keys = array_keys($this->_elements); |
$nbElements = count($keys); |
$nbElementsUsingFnc = $nbElements - 1; // last element doesn't need it |
for ($i = 0; $i < $nbElementsUsingFnc; $i++) { |
$this->_js = ''; |
if (!$this->_flagFrozen) { |
// set the onchange attribute for each element except last |
$keys = array_keys($this->_elements); |
$onChange = array(); |
for ($i = 0; $i < count($keys) - 1; $i++) { |
$select =& $this->_elements[$keys[$i]]; |
$onChange[$i] = $select->getAttribute('onchange'); |
$select->updateAttributes( |
array('onChange' => 'swapOptions(this, \''.$this->getName().'\', '.$keys[$i].', '.$nbElements.', \''.$this->_jsArrayName.'\');') |
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 .= "function swapOptions(frm, grpName, eleIndex, nbElements, arName)\n" |
."{\n" |
." var n = \"\";\n" |
." var ctl;\n\n" |
." for (var i = 0; i < nbElements; i++) {\n" |
." ctl = frm.form[grpName+'['+i+']'];\n" |
." if (!ctl) {\n" |
." ctl = frm.form[grpName+'['+i+'][]'];\n" |
." }\n" |
." if (i <= eleIndex) {\n" |
." n += \"_\"+ctl.value;\n" |
." } else {\n" |
." ctl.length = 0;\n" |
." }\n" |
." }\n\n" |
." var t = eval(\"typeof(\"+arName + n +\")\");\n" |
." if (t != 'undefined') {\n" |
." var the_array = eval(arName+n);\n" |
." var j = 0;\n" |
." n = eleIndex + 1;\n" |
." ctl = frm.form[grpName+'['+ n +']'];\n" |
." if (!ctl) {\n" |
." ctl = frm.form[grpName+'['+ n +'][]'];\n" |
." }\n" |
." for (var i in the_array) {\n" |
." opt = new Option(the_array[i], i, false, false);\n" |
." ctl.options[j++] = opt;\n" |
." }\n" |
." }\n" |
." if (eleIndex+1 < nbElements) {\n" |
." swapOptions(frm, grpName, eleIndex+1, nbElements, arName);\n" |
." }\n" |
."}\n"; |
$this->_js .= <<<JAVASCRIPT |
function _hs_findOptions(ary, keys) |
{ |
var key = keys.shift(); |
if (!key in ary) { |
return {}; |
} else if (0 == keys.length) { |
return ary[key]; |
} else { |
return _hs_findOptions(ary[key], keys); |
} |
} |
|
function _hs_findSelect(form, groupName, selectIndex) |
{ |
if (groupName+'['+ selectIndex +']' in form) { |
return form[groupName+'['+ selectIndex +']']; |
} else { |
return form[groupName+'['+ selectIndex +'][]']; |
} |
} |
|
function _hs_replaceOptions(ctl, optionList) |
{ |
var j = 0; |
ctl.options.length = 0; |
for (i in optionList) { |
ctl.options[j++] = new Option(optionList[i], i, false, false); |
} |
} |
|
function _hs_setValue(ctl, value) |
{ |
var testValue = {}; |
if (value instanceof Array) { |
for (var i = 0; i < value.length; i++) { |
testValue[value[i]] = true; |
} |
} else { |
testValue[value] = 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) |
{ |
var hsValue = []; |
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++) { |
try { |
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))); |
} |
} |
} catch (e) { |
if (!(e instanceof TypeError)) { |
throw e; |
} |
} |
} |
} |
|
function _hs_setupOnReset(form, groupNames) |
{ |
setTimeout(function() { _hs_onReset(form, groupNames); }, 25); |
} |
|
function _hs_onReload() |
{ |
var ctl; |
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]); |
} |
} |
} |
} |
|
if (_hs_prevOnload) { |
_hs_prevOnload(); |
} |
} |
|
var _hs_prevOnload = null; |
if (window.onload) { |
_hs_prevOnload = window.onload; |
} |
window.onload = _hs_onReload; |
|
var _hs_options = {}; |
var _hs_defaults = {}; |
|
JAVASCRIPT; |
define('HTML_QUICKFORM_HIERSELECT_EXISTS', true); |
} |
// option lists |
$jsParts = array(); |
for ($i = 1; $i < $this->_nbElements; $i++) { |
$jsParts[] = $this->_convertArrayToJavascript($this->_options[$i]); |
} |
$this->_js .= "\n_hs_options['" . $this->_escapeString($this->getName()) . "'] = [\n" . |
implode(",\n", $jsParts) . |
"\n];\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) |
$values = array(); |
foreach (array_keys($this->_elements) as $key) { |
if (is_array($v = $this->_elements[$key]->getValue())) { |
$values[] = count($v) > 1? $v: $v[0]; |
} else { |
// XXX: accessing the supposedly private _options array |
$values[] = $this->_elements[$key]->getMultiple() || empty($this->_elements[$key]->_options[0])? |
array(): |
$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 =& new HTML_QuickForm_Renderer_Default(); |
$renderer->setElementTemplate('{element}'); |
parent::accept($renderer); |
return "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>" . |
|
if (!empty($onChange)) { |
$keys = array_keys($this->_elements); |
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>") . |
$renderer->toHtml(); |
} // end func toHtml |
|
411,15 → 448,6 |
// }}} |
// {{{ accept() |
|
/** |
* Accepts a renderer |
* |
* @param object An HTML_QuickForm_Renderer object |
* @param bool Whether a group is required |
* @param string An error message associated with a group |
* @access public |
* @return void |
*/ |
function accept(&$renderer, $required = false, $error = null) |
{ |
$renderer->renderElement($this, $required, $error); |
435,10 → 463,103 |
// matches the main option |
return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller); |
} else { |
return parent::onQuickFormEvent($event, $arg, $caller); |
$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 (strlen($onReset)) { |
if (strpos($onReset, '_hs_setupOnReset')) { |
$caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "', ", $onReset))); |
} else { |
$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()) . "']); } ")); |
} |
} else { |
$caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } ")); |
} |
} |
return $ret; |
} |
} // end func onQuickFormEvent |
|
// }}} |
// }}} |
// {{{ _convertArrayToJavascript() |
|
/** |
* Converts PHP array to its Javascript analog |
* |
* @access private |
* @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) |
{ |
if (!is_array($array)) { |
return $this->_convertScalarToJavascript($array); |
} else { |
$items = array(); |
foreach ($array as $key => $val) { |
$item = $assoc? "'" . $this->_escapeString($key) . "': ": ''; |
if (is_array($val)) { |
$item .= $this->_convertArrayToJavascript($val, $assoc); |
} else { |
$item .= $this->_convertScalarToJavascript($val); |
} |
$items[] = $item; |
} |
} |
$js = implode(', ', $items); |
return $assoc? '{ ' . $js . ' }': '[' . $js . ']'; |
} |
|
// }}} |
// {{{ _convertScalarToJavascript() |
|
/** |
* Converts PHP's scalar value to its Javascript analog |
* |
* @access private |
* @param mixed PHP value to convert |
* @return string Javascript representation of the value |
*/ |
function _convertScalarToJavascript($val) |
{ |
if (is_bool($val)) { |
return $val ? 'true' : 'false'; |
} elseif (is_int($val) || is_double($val)) { |
return $val; |
} elseif (is_string($val)) { |
return "'" . $this->_escapeString($val) . "'"; |
} elseif (is_null($val)) { |
return 'null'; |
} else { |
// don't bother |
return '{}'; |
} |
} |
|
// }}} |
// {{{ _escapeString() |
|
/** |
* Quotes the string so that it can be used in Javascript string constants |
* |
* @access private |
* @param string |
* @return string |
*/ |
function _escapeString($str) |
{ |
return strtr($str,array( |
"\r" => '\r', |
"\n" => '\n', |
"\t" => '\t', |
"'" => "\\'", |
'"' => '\"', |
'\\' => '\\\\' |
)); |
} |
|
// }}} |
} // end class HTML_QuickForm_hierselect |
?> |