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.17 2006/06/22 09:43:00 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.      * @deprecated          Deprecated since release 3.2.2
  169.      * @return    void 
  170.      */
  171.     function setMainOptions($array)
  172.     {
  173.         $this->_options[0$array;
  174.  
  175.         if (empty($this->_elements)) {
  176.             $this->_nbElements = 2;
  177.             $this->_createElements();
  178.         }
  179.     // end func setMainOptions
  180.     
  181.     // }}}
  182.     // {{{ setSecOptions()
  183.     
  184.     /**
  185.      * Sets the options for the second select element. Deprecated. setOptions() should be used.
  186.      * The main _options array is initialized and the _setOptions function is called.
  187.      *
  188.      * @param     array     $array    Options for the second select element
  189.      *
  190.      * @access    public
  191.      * @deprecated          Deprecated since release 3.2.2
  192.      * @return    void 
  193.      */
  194.     function setSecOptions($array)
  195.     {
  196.         $this->_options[1$array;
  197.  
  198.         if (empty($this->_elements)) {
  199.             $this->_nbElements = 2;
  200.             $this->_createElements();
  201.         else {
  202.             // setDefaults has probably been called before this function
  203.             // check if all elements have been created
  204.             $totalNbElements = 2;
  205.             for ($i $this->_nbElements$i $totalNbElements$i ++{
  206.                 $this->_elements[=new HTML_QuickForm_select($inullarray()$this->getAttributes());
  207.                 $this->_nbElements++;
  208.             }
  209.         }
  210.         
  211.         $this->_setOptions();
  212.     // end func setSecOptions
  213.     
  214.     // }}}
  215.     // {{{ _setOptions()
  216.     
  217.     /**
  218.      * Sets the options for each select element
  219.      *
  220.      * @access    private
  221.      * @return    void 
  222.      */
  223.     function _setOptions()
  224.     {
  225.         $toLoad '';
  226.         foreach (array_keys($this->_elementsAS $key{
  227.             $array = eval("return isset(\$this->_options[{$key}]{$toLoad})? \$this->_options[{$key}]{$toLoad}: null;");
  228.             if (is_array($array)) {
  229.                 $select =$this->_elements[$key];
  230.                 $select->_options = array();
  231.                 $select->loadArray($array);
  232.  
  233.                 $value  is_array($v $select->getValue()) $v[0key($array);
  234.                 $toLoad .= '[\'' str_replace(array('\\''\'')array('\\\\''\\\'')$value'\']';
  235.             }
  236.         }
  237.     // end func _setOptions
  238.     
  239.     // }}}
  240.     // {{{ setValue()
  241.  
  242.     /**
  243.      * Sets values for group's elements
  244.      * 
  245.      * @param     array     $value    An array of 2 or more values, for the first,
  246.      *                                 the second, the third etc. select
  247.      *
  248.      * @access    public
  249.      * @return    void 
  250.      */
  251.     function setValue($value)
  252.     {
  253.         // fix for bug #6766. Hope this doesn't break anything more 
  254.         // after bug #7961. Forgot that _nbElements was used in
  255.         // _createElements() called in several places... 
  256.         $this->_nbElements max($this->_nbElementscount($value));
  257.         parent::setValue($value);
  258.         $this->_setOptions();
  259.     // end func setValue
  260.     
  261.     // }}}
  262.     // {{{ _createElements()
  263.  
  264.     /**
  265.      * Creates all the elements for the group
  266.      * 
  267.      * @access    private
  268.      * @return    void 
  269.      */
  270.     function _createElements()
  271.     {
  272.         for ($i = 0; $i $this->_nbElements$i++{
  273.             $this->_elements[=new HTML_QuickForm_select($inullarray()$this->getAttributes());
  274.         }
  275.     // end func _createElements
  276.  
  277.     // }}}
  278.     // {{{ toHtml()
  279.  
  280.     function toHtml()
  281.     {
  282.         $this->_js '';
  283.         if (!$this->_flagFrozen{
  284.             // set the onchange attribute for each element except last
  285.             $keys     array_keys($this->_elements);
  286.             $onChange = array();
  287.             for ($i = 0; $i count($keys- 1; $i++{
  288.                 $select =$this->_elements[$keys[$i]];
  289.                 $onChange[$i$select->getAttribute('onchange');
  290.                 $select->updateAttributes(
  291.                     array('onchange' => '_hs_swapOptions(this.form, \'' $this->_escapeString($this->getName()) '\', ' $keys[$i');' $onChange[$i])
  292.                 );
  293.             }
  294.             
  295.             // create the js function to call
  296.             if (!defined('HTML_QUICKFORM_HIERSELECT_EXISTS')) {
  297.                 $this->_js .= <<<JAVASCRIPT
  298. function _hs_findOptions(ary, keys)
  299. {
  300.     var key = keys.shift();
  301.     if (!key in ary) {
  302.         return {};
  303.     } else if (0 == keys.length) {
  304.         return ary[key];
  305.     } else {
  306.         return _hs_findOptions(ary[key], keys);
  307.     }
  308. }
  309.  
  310. function _hs_findSelect(form, groupName, selectIndex)
  311. {
  312.     if (groupName+'['+ selectIndex +']' in form) {
  313.         return form[groupName+'['+ selectIndex +']']; 
  314.     } else {
  315.         return form[groupName+'['+ selectIndex +'][]']; 
  316.     }
  317. }
  318.  
  319. function _hs_unescapeEntities(str)
  320. {
  321.     var div = document.createElement('div');
  322.     div.innerHTML = str;
  323.     return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
  324. }
  325.  
  326. function _hs_replaceOptions(ctl, optionList)
  327. {
  328.     var j = 0;
  329.     ctl.options.length = 0;
  330.     for (i in optionList) {
  331.         var optionText = (-1 == optionList[i].indexOf('&'))? optionList[i]: _hs_unescapeEntities(optionList[i]);
  332.         ctl.options[j++] = new Option(optionText, i, false, false);
  333.     }
  334. }
  335.  
  336. function _hs_setValue(ctl, value)
  337. {
  338.     var testValue = {};
  339.     if (value instanceof Array) {
  340.         for (var i = 0; i < value.length; i++) {
  341.             testValue[value[i]] = true;
  342.         }
  343.     } else {
  344.         testValue[value] = true;
  345.     }
  346.     for (var i = 0; i < ctl.options.length; i++) {
  347.         if (ctl.options[i].value in testValue) {
  348.             ctl.options[i].selected = true;
  349.         }
  350.     }
  351. }
  352.  
  353. function _hs_swapOptions(form, groupName, selectIndex)
  354. {
  355.     var hsValue = [];
  356.     for (var i = 0; i <= selectIndex; i++) {
  357.         hsValue[i] = _hs_findSelect(form, groupName, i).value;
  358.     }
  359.  
  360.     _hs_replaceOptions(_hs_findSelect(form, groupName, selectIndex + 1), 
  361.                        _hs_findOptions(_hs_options[groupName][selectIndex], hsValue));
  362.     if (selectIndex + 1 < _hs_options[groupName].length) {
  363.         _hs_swapOptions(form, groupName, selectIndex + 1);
  364.     }
  365. }
  366.  
  367. function _hs_onReset(form, groupNames)
  368. {
  369.     for (var i = 0; i < groupNames.length; i++) {
  370.         try {
  371.             for (var j = 0; j <= _hs_options[groupNames[i]].length; j++) {
  372.                 _hs_setValue(_hs_findSelect(form, groupNames[i], j), _hs_defaults[groupNames[i]][j]);
  373.                 if (j < _hs_options[groupNames[i]].length) {
  374.                     _hs_replaceOptions(_hs_findSelect(form, groupNames[i], j + 1), 
  375.                                        _hs_findOptions(_hs_options[groupNames[i]][j], _hs_defaults[groupNames[i]].slice(0, j + 1)));
  376.                 }
  377.             }
  378.         } catch (e) {
  379.             if (!(e instanceof TypeError)) {
  380.                 throw e;
  381.             }
  382.         }
  383.     }
  384. }
  385.  
  386. function _hs_setupOnReset(form, groupNames)
  387. {
  388.     setTimeout(function() { _hs_onReset(form, groupNames); }, 25);
  389. }
  390.  
  391. function _hs_onReload()
  392. {
  393.     var ctl;
  394.     for (var i = 0; i < document.forms.length; i++) {
  395.         for (var j in _hs_defaults) {
  396.             if (ctl = _hs_findSelect(document.forms[i], j, 0)) {
  397.                 for (var k = 0; k < _hs_defaults[j].length; k++) {
  398.                     _hs_setValue(_hs_findSelect(document.forms[i], j, k), _hs_defaults[j][k]);
  399.                 }
  400.             }
  401.         }
  402.     }
  403.  
  404.     if (_hs_prevOnload) {
  405.         _hs_prevOnload();
  406.     }
  407. }
  408.  
  409. var _hs_prevOnload = null;
  410. if (window.onload) {
  411.     _hs_prevOnload = window.onload;
  412. }
  413. window.onload = _hs_onReload;
  414.  
  415. var _hs_options = {};
  416. var _hs_defaults = {};
  417.  
  418. JAVASCRIPT;
  419.                 define('HTML_QUICKFORM_HIERSELECT_EXISTS'true);
  420.             }
  421.             // option lists
  422.             $jsParts = array();
  423.             for ($i = 1; $i $this->_nbElements$i++{
  424.                 $jsParts[$this->_convertArrayToJavascript($this->_options[$i]);
  425.             }
  426.             $this->_js .= "\n_hs_options['" $this->_escapeString($this->getName()) "'] = [\n" .
  427.                           implode(",\n"$jsParts.
  428.                           "\n];\n";
  429.             // default value; if we don't actually have any values yet just use
  430.             // the first option (for single selects) or empty array (for multiple)
  431.             $values = array();
  432.             foreach (array_keys($this->_elementsas $key{
  433.                 if (is_array($v $this->_elements[$key]->getValue())) {
  434.                     $values[count($v> 1? $v$v[0];
  435.                 else {
  436.                     // XXX: accessing the supposedly private _options array
  437.                     $values[$this->_elements[$key]->getMultiple(|| empty($this->_elements[$key]->_options[0])?
  438.                                 array():
  439.                                 $this->_elements[$key]->_options[0]['attr']['value'];
  440.                 }
  441.             }
  442.             $this->_js .= "_hs_defaults['" $this->_escapeString($this->getName()) "'] = " .
  443.                           $this->_convertArrayToJavascript($valuesfalse";\n";
  444.         }
  445.         include_once('HTML/QuickForm/Renderer/Default.php');
  446.         $renderer =new HTML_QuickForm_Renderer_Default();
  447.         $renderer->setElementTemplate('{element}');
  448.         parent::accept($renderer);
  449.  
  450.         if (!empty($onChange)) {
  451.             $keys     array_keys($this->_elements);
  452.             for ($i = 0; $i count($keys- 1; $i++{
  453.                 $this->_elements[$keys[$i]]->updateAttributes(array('onchange' => $onChange[$i]));
  454.             }
  455.         }
  456.         return (empty($this->_js)''"<script type=\"text/javascript\">\n//<![CDATA[\n" $this->_js "//]]>\n</script>".
  457.                $renderer->toHtml();
  458.     // end func toHtml
  459.  
  460.     // }}}
  461.     // {{{ accept()
  462.  
  463.     function accept(&$renderer$required = false$error = null)
  464.     {
  465.         $renderer->renderElement($this$required$error);
  466.     // end func accept
  467.  
  468.     // }}}
  469.     // {{{ onQuickFormEvent()
  470.  
  471.     function onQuickFormEvent($event$arg&$caller)
  472.     {
  473.         if ('updateValue' == $event{
  474.             // we need to call setValue() so that the secondary option
  475.             // matches the main option
  476.             return HTML_QuickForm_element::onQuickFormEvent($event$arg$caller);
  477.         else {
  478.             $ret = parent::onQuickFormEvent($event$arg$caller);
  479.             // add onreset handler to form to properly reset hierselect (see bug #2970)
  480.             if ('addElement' == $event{
  481.                 $onReset $caller->getAttribute('onreset');
  482.                 if (strlen($onReset)) {
  483.                     if (strpos($onReset'_hs_setupOnReset')) {
  484.                         $caller->updateAttributes(array('onreset' => str_replace('_hs_setupOnReset(this, ['"_hs_setupOnReset(this, ['" $this->_escapeString($this->getName()) "', "$onReset)));
  485.                     else {
  486.                         $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()) "']); } "));
  487.                     }
  488.                 else {
  489.                     $caller->updateAttributes(array('onreset' => "if (typeof _hs_setupOnReset != 'undefined') { return _hs_setupOnReset(this, ['" $this->_escapeString($this->getName()) "']); } "));
  490.                 }
  491.             }
  492.             return $ret;
  493.         }
  494.     // end func onQuickFormEvent
  495.  
  496.     // }}}
  497.     // {{{ _convertArrayToJavascript()
  498.  
  499.    /**
  500.     * Converts PHP array to its Javascript analog
  501.     *
  502.     * @access private
  503.     * @param  array     PHP array to convert
  504.     * @param  bool      Generate Javascript object literal (default, works like PHP's associative array) or array literal
  505.     * @return string    Javascript representation of the value
  506.     */
  507.     function _convertArrayToJavascript($array$assoc = true)
  508.     {
  509.         if (!is_array($array)) {
  510.             return $this->_convertScalarToJavascript($array);
  511.         else {
  512.             $items = array();
  513.             foreach ($array as $key => $val{
  514.                 $item $assoc"'" $this->_escapeString($key"': "'';
  515.                 if (is_array($val)) {
  516.                     $item .= $this->_convertArrayToJavascript($val$assoc);
  517.                 else {
  518.                     $item .= $this->_convertScalarToJavascript($val);
  519.                 }
  520.                 $items[$item;
  521.             }
  522.         }
  523.         $js implode(', '$items);
  524.         return $assoc'{ ' $js ' }''[' $js ']';
  525.     }
  526.     
  527.     // }}}
  528.     // {{{ _convertScalarToJavascript()
  529.  
  530.    /**
  531.     * Converts PHP's scalar value to its Javascript analog
  532.     *
  533.     * @access private
  534.     * @param  mixed     PHP value to convert
  535.     * @return string    Javascript representation of the value
  536.     */
  537.     function _convertScalarToJavascript($val)
  538.     {
  539.         if (is_bool($val)) {
  540.             return $val 'true' 'false';
  541.         elseif (is_int($val|| is_double($val)) {
  542.             return $val;
  543.         elseif (is_string($val)) {
  544.             return "'" $this->_escapeString($val"'";
  545.         elseif (is_null($val)) {
  546.             return 'null';
  547.         else {
  548.             // don't bother
  549.             return '{}';
  550.         }
  551.     }
  552.  
  553.     // }}}
  554.     // {{{ _escapeString()
  555.  
  556.    /**
  557.     * Quotes the string so that it can be used in Javascript string constants
  558.     *
  559.     * @access private
  560.     * @param  string 
  561.     * @return string 
  562.     */
  563.     function _escapeString($str)
  564.     {
  565.         return strtr($str,array(
  566.             "\r"    => '\r',
  567.             "\n"    => '\n',
  568.             "\t"    => '\t',
  569.             "'"     => "\\'",
  570.             '"'     => '\"',
  571.             '\\'    => '\\\\'
  572.         ));
  573.     }
  574.  
  575.     // }}}
  576. // end class HTML_QuickForm_hierselect
  577. ?>

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