home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / HTML / QuickForm / hierselect.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  19.9 KB  |  593 lines

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