[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/lib/pear/HTML/QuickForm/ -> hierselect.php (source)

   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  ?>


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1