[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4: */ 3 // +----------------------------------------------------------------------+ 4 // | PHP version 4.0 | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 1997-2004 The PHP Group | 7 // +----------------------------------------------------------------------+ 8 // | This source file is subject to version 2.0 of the PHP license, | 9 // | that is bundled with this package in the file LICENSE, and is | 10 // | available at through the world-wide-web at | 11 // | http://www.php.net/license/2_02.txt. | 12 // | If you did not receive a copy of the PHP license and are unable to | 13 // | obtain it through the world-wide-web, please send a note to | 14 // | [email protected] so we can mail you a copy immediately. | 15 // +----------------------------------------------------------------------+ 16 // | Authors: Herim Vasquez <[email protected]> | 17 // | Bertrand Mansion <[email protected]> | 18 // | Alexey Borzov <[email protected]> 19 // +----------------------------------------------------------------------+ 20 // 21 // $Id$ 22 23 require_once('HTML/QuickForm/group.php'); 24 require_once('HTML/QuickForm/select.php'); 25 26 /** 27 * Class to dynamically create two or more HTML Select elements 28 * The first select changes the content of the second select and so on. 29 * This element is considered as a group. Selects will be named 30 * groupName[0], groupName[1], groupName[2]... 31 * 32 * @author Herim Vasquez <[email protected]> 33 * @author Bertrand Mansion <[email protected]> 34 * @version 1.0 35 * @since PHP4.04pl1 36 * @access public 37 */ 38 class HTML_QuickForm_hierselect extends HTML_QuickForm_group 39 { 40 // {{{ properties 41 42 /** 43 * Options for all the select elements 44 * 45 * Format is a bit more complex as we need to know which options 46 * are related to the ones in the previous select: 47 * 48 * Ex: 49 * // first select 50 * $select1[0] = 'Pop'; 51 * $select1[1] = 'Classical'; 52 * $select1[2] = 'Funeral doom'; 53 * 54 * // second select 55 * $select2[0][0] = 'Red Hot Chil Peppers'; 56 * $select2[0][1] = 'The Pixies'; 57 * $select2[1][0] = 'Wagner'; 58 * $select2[1][1] = 'Strauss'; 59 * $select2[2][0] = 'Pantheist'; 60 * $select2[2][1] = 'Skepticism'; 61 * 62 * // If only need two selects 63 * // - and using the depracated functions 64 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:'); 65 * $sel->setMainOptions($select1); 66 * $sel->setSecOptions($select2); 67 * 68 * // - and using the new setOptions function 69 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:'); 70 * $sel->setOptions(array($select1, $select2)); 71 * 72 * // If you have a third select with prices for the cds 73 * $select3[0][0][0] = '15.00$'; 74 * $select3[0][0][1] = '17.00$'; 75 * etc 76 * 77 * // You can now use 78 * $sel =& $form->addElement('hierselect', 'cds', 'Choose CD:'); 79 * $sel->setOptions(array($select1, $select2, $select3)); 80 * 81 * @var array 82 * @access private 83 */ 84 var $_options = array(); 85 86 /** 87 * Number of select elements on this group 88 * 89 * @var int 90 * @access private 91 */ 92 var $_nbElements = 0; 93 94 /** 95 * The javascript used to set and change the options 96 * 97 * @var string 98 * @access private 99 */ 100 var $_js = ''; 101 102 // }}} 103 // {{{ constructor 104 105 /** 106 * Class constructor 107 * 108 * @param string $elementName (optional)Input field name attribute 109 * @param string $elementLabel (optional)Input field label in form 110 * @param mixed $attributes (optional)Either a typical HTML attribute string 111 * or an associative array. Date format is passed along the attributes. 112 * @param mixed $separator (optional)Use a string for one separator, 113 * use an array to alternate the separators. 114 * @access public 115 * @return void 116 */ 117 function HTML_QuickForm_hierselect($elementName=null, $elementLabel=null, $attributes=null, $separator=null) 118 { 119 $this->HTML_QuickForm_element($elementName, $elementLabel, $attributes); 120 $this->_persistantFreeze = true; 121 if (isset($separator)) { 122 $this->_separator = $separator; 123 } 124 $this->_type = 'hierselect'; 125 $this->_appendName = true; 126 } //end constructor 127 128 // }}} 129 // {{{ setOptions() 130 131 /** 132 * Initialize the array structure containing the options for each select element. 133 * Call the functions that actually do the magic. 134 * 135 * @param array $options Array of options defining each element 136 * 137 * @access public 138 * @return void 139 */ 140 function setOptions($options) 141 { 142 $this->_options = $options; 143 144 if (empty($this->_elements)) { 145 $this->_nbElements = count($this->_options); 146 $this->_createElements(); 147 } else { 148 // setDefaults has probably been called before this function 149 // check if all elements have been created 150 $totalNbElements = count($this->_options); 151 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) { 152 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 153 $this->_nbElements++; 154 } 155 } 156 157 $this->_setOptions(); 158 } // end func setMainOptions 159 160 // }}} 161 // {{{ setMainOptions() 162 163 /** 164 * Sets the options for the first select element. Deprecated. setOptions() should be used. 165 * 166 * @param array $array Options for the first select element 167 * 168 * @access public 169 * @deprecated Deprecated since release 3.2.2 170 * @return void 171 */ 172 function setMainOptions($array) 173 { 174 $this->_options[0] = $array; 175 176 if (empty($this->_elements)) { 177 $this->_nbElements = 2; 178 $this->_createElements(); 179 } 180 } // end func setMainOptions 181 182 // }}} 183 // {{{ setSecOptions() 184 185 /** 186 * Sets the options for the second select element. Deprecated. setOptions() should be used. 187 * The main _options array is initialized and the _setOptions function is called. 188 * 189 * @param array $array Options for the second select element 190 * 191 * @access public 192 * @deprecated Deprecated since release 3.2.2 193 * @return void 194 */ 195 function setSecOptions($array) 196 { 197 $this->_options[1] = $array; 198 199 if (empty($this->_elements)) { 200 $this->_nbElements = 2; 201 $this->_createElements(); 202 } else { 203 // setDefaults has probably been called before this function 204 // check if all elements have been created 205 $totalNbElements = 2; 206 for ($i = $this->_nbElements; $i < $totalNbElements; $i ++) { 207 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 208 $this->_nbElements++; 209 } 210 } 211 212 $this->_setOptions(); 213 } // end func setSecOptions 214 215 // }}} 216 // {{{ _setOptions() 217 218 /** 219 * Sets the options for each select element 220 * 221 * @access private 222 * @return void 223 */ 224 function _setOptions() 225 { 226 $toLoad = ''; 227 foreach (array_keys($this->_elements) AS $key) { 228 $array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;"); 229 if (is_array($array)) { 230 $select =& $this->_elements[$key]; 231 $select->_options = array(); 232 $select->loadArray($array); 233 234 $value = is_array($v = $select->getValue()) ? $v[0] : key($array); 235 $toLoad .= '[\'' . str_replace(array('\\', '\''), array('\\\\', '\\\''), $value) . '\']'; 236 } 237 } 238 } // end func _setOptions 239 240 // }}} 241 // {{{ setValue() 242 243 /** 244 * Sets values for group's elements 245 * 246 * @param array $value An array of 2 or more values, for the first, 247 * the second, the third etc. select 248 * 249 * @access public 250 * @return void 251 */ 252 function setValue($value) 253 { 254 // fix for bug #6766. Hope this doesn't break anything more 255 // after bug #7961. Forgot that _nbElements was used in 256 // _createElements() called in several places... 257 $this->_nbElements = max($this->_nbElements, count($value)); 258 parent::setValue($value); 259 $this->_setOptions(); 260 } // end func setValue 261 262 // }}} 263 // {{{ _createElements() 264 265 /** 266 * Creates all the elements for the group 267 * 268 * @access private 269 * @return void 270 */ 271 function _createElements() 272 { 273 for ($i = 0; $i < $this->_nbElements; $i++) { 274 $this->_elements[] = new HTML_QuickForm_select($i, null, array(), $this->getAttributes()); 275 } 276 } // end func _createElements 277 278 // }}} 279 // {{{ toHtml() 280 281 function toHtml() 282 { 283 $this->_js = ''; 284 if (!$this->_flagFrozen) { 285 // set the onchange attribute for each element except last 286 $keys = array_keys($this->_elements); 287 $onChange = array(); 288 for ($i = 0; $i < count($keys) - 1; $i++) { 289 $select =& $this->_elements[$keys[$i]]; 290 $onChange[$i] = $select->getAttribute('onchange'); 291 $select->updateAttributes( 292 array('onchange' => '_hs_swapOptions(this.form, \'' . $this->_escapeString($this->getName()) . '\', ' . $keys[$i] . ');' . $onChange[$i]) 293 ); 294 } 295 296 // create the js function to call 297 if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) { 298 $this->_js .= <<<JAVASCRIPT 299 function _hs_findOptions(ary, keys) 300 { 301 var key = keys.shift(); 302 if (!key in ary) { 303 return {}; 304 } else if (0 == keys.length) { 305 return ary[key]; 306 } else { 307 return _hs_findOptions(ary[key], keys); 308 } 309 } 310 311 function _hs_findSelect(form, groupName, selectIndex) 312 { 313 if (groupName+'['+ selectIndex +']' in form) { 314 return form[groupName+'['+ selectIndex +']']; 315 } else { 316 return form[groupName+'['+ selectIndex +'][]']; 317 } 318 } 319 320 function _hs_unescapeEntities(str) 321 { 322 var div = document.createElement('div'); 323 div.innerHTML = str; 324 return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; 325 } 326 327 function _hs_replaceOptions(ctl, optionList) 328 { 329 var j = 0; 330 ctl.options.length = 0; 331 for (i in optionList) { 332 var optionText = (-1 == optionList[i].indexOf('&'))? optionList[i]: _hs_unescapeEntities(optionList[i]); 333 ctl.options[j++] = new Option(optionText, i, false, false); 334 } 335 } 336 337 function _hs_setValue(ctl, value) 338 { 339 var testValue = {}; 340 if (value instanceof Array) { 341 for (var i = 0; i < value.length; i++) { 342 testValue[value[i]] = true; 343 } 344 } else { 345 testValue[value] = true; 346 } 347 for (var i = 0; i < ctl.options.length; i++) { 348 if (ctl.options[i].value in testValue) { 349 ctl.options[i].selected = true; 350 } 351 } 352 } 353 354 function _hs_swapOptions(form, groupName, selectIndex) 355 { 356 var hsValue = []; 357 for (var i = 0; i <= selectIndex; i++) { 358 hsValue[i] = _hs_findSelect(form, groupName, i).value; 359 } 360 361 _hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1), 362 _hs_findOptions(_hs_options[groupName][selectIndex], hsValue)); 363 if (selectIndex + 1 < _hs_options[groupName].length) { 364 _hs_swapOptions(form, groupName, selectIndex + 1); 365 } 366 } 367 368 function _hs_onReset(form, groupNames) 369 { 370 for (var i = 0; i < groupNames.length; i++) { 371 try { 372 for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) { 373 _hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]); 374 if (j < _hs_options[groupNames[i]].length) { 375 _hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1), 376 _hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1))); 377 } 378 } 379 } catch (e) { 380 if (!(e instanceof TypeError)) { 381 throw e; 382 } 383 } 384 } 385 } 386 387 function _hs_setupOnReset(form, groupNames) 388 { 389 setTimeout(function() { _hs_onReset(form, groupNames); }, 25); 390 } 391 392 function _hs_onReload() 393 { 394 var ctl; 395 for (var i = 0; i < document.forms.length; i++) { 396 for (var j in _hs_defaults) { 397 if (ctl = _hs_findSelect(document.forms[i], j, 0)) { 398 for (var k = 0; k < _hs_defaults[j].length; k++) { 399 _hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]); 400 } 401 } 402 } 403 } 404 405 if (_hs_prevOnload) { 406 _hs_prevOnload(); 407 } 408 } 409 410 var _hs_prevOnload = null; 411 if (window.onload) { 412 _hs_prevOnload = window.onload; 413 } 414 window.onload = _hs_onReload; 415 416 var _hs_options = {}; 417 var _hs_defaults = {}; 418 419 JAVASCRIPT; 420 define('HTML_QUICKFORM_HIERSELECT_EXISTS', true); 421 } 422 // option lists 423 $jsParts = array(); 424 for ($i = 1; $i < $this->_nbElements; $i++) { 425 $jsParts[] = $this->_convertArrayToJavascript($this->_options[$i]); 426 } 427 $this->_js .= "\n_hs_options['" . $this->_escapeString($this->getName()) . "'] = [\n" . 428 implode(",\n", $jsParts) . 429 "\n];\n"; 430 // default value; if we don't actually have any values yet just use 431 // the first option (for single selects) or empty array (for multiple) 432 $values = array(); 433 foreach (array_keys($this->_elements) as $key) { 434 if (is_array($v = $this->_elements[$key]->getValue())) { 435 $values[] = count($v) > 1? $v: $v[0]; 436 } else { 437 // XXX: accessing the supposedly private _options array 438 $values[] = $this->_elements[$key]->getMultiple() || empty($this->_elements[$key]->_options[0])? 439 array(): 440 $this->_elements[$key]->_options[0]['attr']['value']; 441 } 442 } 443 $this->_js .= "_hs_defaults['" . $this->_escapeString($this->getName()) . "'] = " . 444 $this->_convertArrayToJavascript($values, false) . ";\n"; 445 } 446 include_once('HTML/QuickForm/Renderer/Default.php'); 447 $renderer = new HTML_QuickForm_Renderer_Default(); 448 $renderer->setElementTemplate('{element}'); 449 parent::accept($renderer); 450 451 if (!empty($onChange)) { 452 $keys = array_keys($this->_elements); 453 for ($i = 0; $i < count($keys) - 1; $i++) { 454 $this->_elements[$keys[$i]]->updateAttributes(array('onchange' => $onChange[$i])); 455 } 456 } 457 return (empty($this->_js)? '': "<script type=\"text/javascript\">\n//<![CDATA[\n" . $this->_js . "//]]>\n</script>") . 458 $renderer->toHtml(); 459 } // end func toHtml 460 461 // }}} 462 // {{{ accept() 463 464 function accept(&$renderer, $required = false, $error = null) 465 { 466 $renderer->renderElement($this, $required, $error); 467 } // end func accept 468 469 // }}} 470 // {{{ onQuickFormEvent() 471 472 function onQuickFormEvent($event, $arg, &$caller) 473 { 474 if ('updateValue' == $event) { 475 // we need to call setValue() so that the secondary option 476 // matches the main option 477 return HTML_QuickForm_element::onQuickFormEvent($event, $arg, $caller); 478 } else { 479 $ret = parent::onQuickFormEvent($event, $arg, $caller); 480 // add onreset handler to form to properly reset hierselect (see bug #2970) 481 if ('addElement' == $event) { 482 $onReset = $caller->getAttribute('onreset'); 483 if (strlen($onReset)) { 484 if (strpos($onReset, '_hs_setupOnReset')) { 485 $caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, [', "_hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "', ", $onReset))); 486 } else { 487 $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()) . "']); } ")); 488 } 489 } else { 490 $caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" . $this->_escapeString($this->getName()) . "']); } ")); 491 } 492 } 493 return $ret; 494 } 495 } // end func onQuickFormEvent 496 497 // }}} 498 // {{{ _convertArrayToJavascript() 499 500 /** 501 * Converts PHP array to its Javascript analog 502 * 503 * @access private 504 * @param array PHP array to convert 505 * @param bool Generate Javascript object literal (default, works like PHP's associative array) or array literal 506 * @return string Javascript representation of the value 507 */ 508 function _convertArrayToJavascript($array, $assoc = true) 509 { 510 if (!is_array($array)) { 511 return $this->_convertScalarToJavascript($array); 512 } else { 513 $items = array(); 514 foreach ($array as $key => $val) { 515 $item = $assoc? "'" . $this->_escapeString($key) . "': ": ''; 516 if (is_array($val)) { 517 $item .= $this->_convertArrayToJavascript($val, $assoc); 518 } else { 519 $item .= $this->_convertScalarToJavascript($val); 520 } 521 $items[] = $item; 522 } 523 } 524 $js = implode(', ', $items); 525 return $assoc? '{ ' . $js . ' }': '[' . $js . ']'; 526 } 527 528 // }}} 529 // {{{ _convertScalarToJavascript() 530 531 /** 532 * Converts PHP's scalar value to its Javascript analog 533 * 534 * @access private 535 * @param mixed PHP value to convert 536 * @return string Javascript representation of the value 537 */ 538 function _convertScalarToJavascript($val) 539 { 540 if (is_bool($val)) { 541 return $val ? 'true' : 'false'; 542 } elseif (is_int($val) || is_double($val)) { 543 return $val; 544 } elseif (is_string($val)) { 545 return "'" . $this->_escapeString($val) . "'"; 546 } elseif (is_null($val)) { 547 return 'null'; 548 } else { 549 // don't bother 550 return '{}'; 551 } 552 } 553 554 // }}} 555 // {{{ _escapeString() 556 557 /** 558 * Quotes the string so that it can be used in Javascript string constants 559 * 560 * @access private 561 * @param string 562 * @return string 563 */ 564 function _escapeString($str) 565 { 566 return strtr($str,array( 567 "\r" => '\r', 568 "\n" => '\n', 569 "\t" => '\t', 570 "'" => "\\'", 571 '"' => '\"', 572 '\\' => '\\\\' 573 )); 574 } 575 576 // }}} 577 } // end class HTML_QuickForm_hierselect 578 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |