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

Documentation generated on Fri, 05 Oct 2007 16:30:29 -0400 by phpDocumentor 1.4.0. PEAR Logo Copyright © PHP Group 2004.