HTML_QuickForm
[ class tree: HTML_QuickForm ] [ index: HTML_QuickForm ] [ all elements ]

Source for file hierselect.php

Documentation is available at hierselect.php

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

Documentation generated on Mon, 11 Mar 2019 14:16:33 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.