|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 00003 // +----------------------------------------------------------------------+ 00004 // | PHP version 4.0 | 00005 // +----------------------------------------------------------------------+ 00006 // | Copyright (c) 1997-2004 The PHP Group | 00007 // +----------------------------------------------------------------------+ 00008 // | This source file is subject to version 2.0 of the PHP license, | 00009 // | that is bundled with this package in the file LICENSE, and is | 00010 // | available at through the world-wide-web at | 00011 // | http://www.php.net/license/2_02.txt. | 00012 // | If you did not receive a copy of the PHP license and are unable to | 00013 // | obtain it through the world-wide-web, please send a note to | 00014 // | license@php.net so we can mail you a copy immediately. | 00015 // +----------------------------------------------------------------------+ 00016 // | Authors: Herim Vasquez <vasquezh@iro.umontreal.ca> | 00017 // | Bertrand Mansion <bmansion@mamasam.com> | 00018 // | Alexey Borzov <avb@php.net> 00019 // +----------------------------------------------------------------------+ 00020 // 00021 // $Id: hierselect.php,v 1.3 2010/12/14 17:35:24 moodlerobot Exp $ 00022 00023 require_once('HTML/QuickForm/group.php'); 00024 require_once('HTML/QuickForm/select.php'); 00025 00038 class HTML_QuickForm_hierselect extends HTML_QuickForm_group 00039 { 00040 // {{{ properties 00041 00084 var $_options = array(); 00085 00092 var $_nbElements = 0; 00093 00100 var $_js = ''; 00101 00102 // }}} 00103 // {{{ constructor 00104 00117 function HTML_QuickForm_hierselect($elementName=null, $elementLabel=null, $attributes=null, $separator=null) 00118 { 00119 $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes); 00120 $this->_persistantFreeze = true; 00121 if (isset($separator)) { 00122 $this->_separator = $separator; 00123 } 00124 $this->_type = 'hierselect'; 00125 $this->_appendName = true; 00126 } //end constructor 00127 00128 // }}} 00129 // {{{ setOptions() 00130 00140 function setOptions($options) 00141 { 00142 $this->_options = $options; 00143 00144 if (empty($this->_elements)) { 00145 $this->_nbElements = count($this->_options); 00146 $this->_createElements(); 00147 } else { 00148 // setDefaults has probably been called before this function 00149 // check if all elements have been created 00150 $totalNbElements = count($this->_options); 00151 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) { 00152 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 00153 $this->_nbElements++; 00154 } 00155 } 00156 00157 $this->_setOptions(); 00158 } // end func setMainOptions 00159 00160 // }}} 00161 // {{{ setMainOptions() 00162 00172 function setMainOptions($array) 00173 { 00174 $this->_options[0] = $array; 00175 00176 if (empty($this->_elements)) { 00177 $this->_nbElements = 2; 00178 $this->_createElements(); 00179 } 00180 } // end func setMainOptions 00181 00182 // }}} 00183 // {{{ setSecOptions() 00184 00195 function setSecOptions($array) 00196 { 00197 $this->_options[1] = $array; 00198 00199 if (empty($this->_elements)) { 00200 $this->_nbElements = 2; 00201 $this->_createElements(); 00202 } else { 00203 // setDefaults has probably been called before this function 00204 // check if all elements have been created 00205 $totalNbElements = 2; 00206 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) { 00207 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 00208 $this->_nbElements++; 00209 } 00210 } 00211 00212 $this->_setOptions(); 00213 } // end func setSecOptions 00214 00215 // }}} 00216 // {{{ _setOptions() 00217 00224 function _setOptions() 00225 { 00226 $toLoad = ''; 00227 foreach (array_keys($this->_elements) AS $key) { 00228 $array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;"); 00229 if (is_array($array)) { 00230 $select =& $this->_elements[$key]; 00231 $select->_options = array(); 00232 $select->loadArray($array); 00233 00234 $value = is_array($v = $select->getValue()) ? $v[0] : key($array); 00235 $toLoad .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $value) . '\']'; 00236 } 00237 } 00238 } // end func _setOptions 00239 00240 // }}} 00241 // {{{ setValue() 00242 00252 function setValue($value) 00253 { 00254 // fix for bug #6766. Hope this doesn't break anything more 00255 // after bug #7961. Forgot that _nbElements was used in 00256 // _createElements() called in several places... 00257 $this->_nbElements = max($this->_nbElements, count($value)); 00258 parent::setValue($value); 00259 $this->_setOptions(); 00260 } // end func setValue 00261 00262 // }}} 00263 // {{{ _createElements() 00264 00271 function _createElements() 00272 { 00273 for ($i = 0; $i < $this->_nbElements; $i++) { 00274 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 00275 } 00276 } // end func _createElements 00277 00278 // }}} 00279 // {{{ toHtml() 00280 00281 function toHtml() 00282 { 00283 $this->_js = ''; 00284 if (!$this->_flagFrozen) { 00285 // set the onchange attribute for each element except last 00286 $keys = array_keys($this->_elements); 00287 $onChange = array(); 00288 for ($i = 0; $i < count($keys) - 1; $i++) { 00289 $select =& $this->_elements[$keys[$i]]; 00290 $onChange[$i] = $select->getAttribute('onchange'); 00291 $select->updateAttributes( 00292 array('onchange' => '_hs_swapOptions(this.form, \'' . $this->_escapeString($this->getName()) . '\', ' . $keys[$i] . ');' . $onChange[$i]) 00293 ); 00294 } 00295 00296 // create the js function to call 00297 if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) { 00298 $this->_js .= <<<JAVASCRIPT 00299 function _hs_findOptions(ary, keys) 00300 { 00301 var key = keys.shift(); 00302 if (!key in ary) { 00303 return {}; 00304 } else if (0 == keys.length) { 00305 return ary[key]; 00306 } else { 00307 return _hs_findOptions(ary[key], keys); 00308 } 00309 } 00310 00311 function _hs_findSelect(form, groupName, selectIndex) 00312 { 00313 if (groupName+'['+ selectIndex +']' in form) { 00314 return form[groupName+'['+ selectIndex +']']; 00315 } else { 00316 return form[groupName+'['+ selectIndex +'][]']; 00317 } 00318 } 00319 00320 function _hs_unescapeEntities(str) 00321 { 00322 var div = document.createElement('div'); 00323 div.innerHTML = str; 00324 return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 00325 } 00326 00327 function _hs_replaceOptions(ctl, optionList) 00328 { 00329 var j = 0; 00330 ctl.options.length = 0; 00331 for (i in optionList) { 00332 var optionText = (-1 == optionList[i].indexOf('&'))? optionList[i]: _hs_unescapeEntities(optionList[i]); 00333 ctl.options[j++] = new Option(optionText, i, false, false); 00334 } 00335 } 00336 00337 function _hs_setValue(ctl, value) 00338 { 00339 var testValue = {}; 00340 if (value instanceof Array) { 00341 for (var i = 0; i < value.length; i++) { 00342 testValue[value[i]] = true; 00343 } 00344 } else { 00345 testValue[value] = true; 00346 } 00347 for (var i = 0; i < ctl.options.length; i++) { 00348 if (ctl.options[i].value in testValue) { 00349 ctl.options[i].selected = true; 00350 } 00351 } 00352 } 00353 00354 function _hs_swapOptions(form, groupName, selectIndex) 00355 { 00356 var hsValue = []; 00357 for (var i = 0; i <= selectIndex; i++) { 00358 hsValue[i] = _hs_findSelect(form, groupName, i).value; 00359 } 00360 00361 _hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1), 00362 _hs_findOptions(_hs_options[groupName][selectIndex], hsValue)); 00363 if (selectIndex + 1 < _hs_options[groupName].length) { 00364 _hs_swapOptions(form, groupName, selectIndex + 1); 00365 } 00366 } 00367 00368 function _hs_onReset(form, groupNames) 00369 { 00370 for (var i = 0; i < groupNames.length; i++) { 00371 try { 00372 for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) { 00373 _hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]); 00374 if (j < _hs_options[groupNames[i]].length) { 00375 _hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1), 00376 _hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1))); 00377 } 00378 } 00379 } catch (e) { 00380 if (!(e instanceof TypeError)) { 00381 throw e; 00382 } 00383 } 00384 } 00385 } 00386 00387 function _hs_setupOnReset(form, groupNames) 00388 { 00389 setTimeout(function() { _hs_onReset(form, groupNames); }, 25); 00390 } 00391 00392 function _hs_onReload() 00393 { 00394 var ctl; 00395 for (var i = 0; i < document.forms.length; i++) { 00396 for (var j in _hs_defaults) { 00397 if (ctl = _hs_findSelect(document.forms[i], j, 0)) { 00398 for (var k = 0; k < _hs_defaults[j].length; k++) { 00399 _hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]); 00400 } 00401 } 00402 } 00403 } 00404 00405 if (_hs_prevOnload) { 00406 _hs_prevOnload(); 00407 } 00408 } 00409 00410 var _hs_prevOnload = null; 00411 if (window.onload) { 00412 _hs_prevOnload = window.onload; 00413 } 00414 window.onload = _hs_onReload; 00415 00416 var _hs_options = {}; 00417 var _hs_defaults = {}; 00418 00419 JAVASCRIPT; 00420 define('HTML_QUICKFORM_HIERSELECT_EXISTS', true); 00421 } 00422 // option lists 00423 $jsParts = array(); 00424 for ($i = 1; $i < $this->_nbElements; $i++) { 00425 $jsParts[] = $this->_convertArrayToJavascript($this->_options[$i]); 00426 } 00427 $this->_js .= "\n_hs_options['" . $this->_escapeString($this->getName()) . "'] = [\n" . 00428 implode(",\n", $jsParts) . 00429 "\n];\n"; 00430 // default value; if we don't actually have any values yet just use 00431 // the first option (for single selects) or empty array (for multiple) 00432 $values = array(); 00433 foreach (array_keys($this->_elements) as $key) { 00434 if (is_array($v = $this->_elements[$key]->getValue())) { 00435 $values[] = count($v) > 1? $v: $v[0]; 00436 } else { 00437 // XXX: accessing the supposedly private _options array 00438 $values[] = $this->_elements[$key]->getMultiple() || empty($this->_elements[$key]->_options[0])? 00439 array(): 00440 $this->_elements[$key]->_options[0]['attr']['value']; 00441 } 00442 } 00443 $this->_js .= "_hs_defaults['" . $this->_escapeString($this->getName()) . "'] = " . 00444 $this->_convertArrayToJavascript($values, false) . ";\n"; 00445 } 00446 include_once('HTML/QuickForm/Renderer/Default.php'); 00447 $renderer = new HTML_QuickForm_Renderer_Default(); 00448 $renderer->setElementTemplate('{element}'); 00449 parent::accept($renderer); 00450 00451 if (!empty($onChange)) { 00452 $keys = array_keys($this->_elements); 00453 for ($i = 0; $i < count($keys) - 1; $i++) { 00454 $this->_elements[$keys[$i]]->updateAttributes(array('onchange' => $onChange[$i])); 00455 } 00456 } 00457 return (empty($this->_js)? '': "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>") . 00458 $renderer->toHtml(); 00459 } // end func toHtml 00460 00461 // }}} 00462 // {{{ accept() 00463 00464 function accept(&$renderer, $required = false, $error = null) 00465 { 00466 $renderer->renderElement($this, $required, $error); 00467 } // end func accept 00468 00469 // }}} 00470 // {{{ onQuickFormEvent() 00471 00472 function onQuickFormEvent($event, $arg, &$caller) 00473 { 00474 if ('updateValue' == $event) { 00475 // we need to call setValue() so that the secondary option 00476 // matches the main option 00477 return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller); 00478 } else { 00479 $ret = parent::onQuickFormEvent($event, $arg, $caller); 00480 // add onreset handler to form to properly reset hierselect (see bug #2970) 00481 if ('addElement' == $event) { 00482 $onReset = $caller->getAttribute('onreset'); 00483 if (strlen($onReset)) { 00484 if (strpos($onReset, '_hs_setupOnReset')) { 00485 $caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "', ", $onReset))); 00486 } else { 00487 $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()) . "']); } ")); 00488 } 00489 } else { 00490 $caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } ")); 00491 } 00492 } 00493 return $ret; 00494 } 00495 } // end func onQuickFormEvent 00496 00497 // }}} 00498 // {{{ _convertArrayToJavascript() 00499 00508 function _convertArrayToJavascript($array, $assoc = true) 00509 { 00510 if (!is_array($array)) { 00511 return $this->_convertScalarToJavascript($array); 00512 } else { 00513 $items = array(); 00514 foreach ($array as $key => $val) { 00515 $item = $assoc? "'" . $this->_escapeString($key) . "': ": ''; 00516 if (is_array($val)) { 00517 $item .= $this->_convertArrayToJavascript($val, $assoc); 00518 } else { 00519 $item .= $this->_convertScalarToJavascript($val); 00520 } 00521 $items[] = $item; 00522 } 00523 } 00524 $js = implode(', ', $items); 00525 return $assoc? '{ ' . $js . ' }': '[' . $js . ']'; 00526 } 00527 00528 // }}} 00529 // {{{ _convertScalarToJavascript() 00530 00538 function _convertScalarToJavascript($val) 00539 { 00540 if (is_bool($val)) { 00541 return $val ? 'true' : 'false'; 00542 } elseif (is_int($val) || is_double($val)) { 00543 return $val; 00544 } elseif (is_string($val)) { 00545 return "'" . $this->_escapeString($val) . "'"; 00546 } elseif (is_null($val)) { 00547 return 'null'; 00548 } else { 00549 // don't bother 00550 return '{}'; 00551 } 00552 } 00553 00554 // }}} 00555 // {{{ _escapeString() 00556 00564 function _escapeString($str) 00565 { 00566 return strtr($str,array( 00567 "\r" => '\r', 00568 "\n" => '\n', 00569 "\t" => '\t', 00570 "'" => "\\'", 00571 '"' => '\"', 00572 '\\' => '\\\\' 00573 )); 00574 } 00575 00576 // }}} 00577 } // end class HTML_QuickForm_hierselect 00578 ?>