<?php

/**
 * HTML QuickForm element for jsCalendar
 *
 * jsCalendar is a dynamic JavaScript/DHTML calendar which can be obtained from
 * http://www.dynarch.com/projects/calendar/
 *
 * The jsCalendar library itself was written by Mihai Bazon
 * (see the website above for licensing terms, and support)
 *
 * Example of PHP code:
 * <code>
 * require_once 'HTML/QuickForm.php';
 * require_once 'HTML/QuickForm/jscalendar.php';
 * $form = new HTML_QuickForm('calForm');
 *
 * // View DynArch's DHTML Calendar Widget documentation for exhaustive list
 * // of options
 * $options = array(
 *     'ifFormat' => '%Y/%m/%d',    // Input field format
 *     'callbacks' => array(        // Example of callback setup
 *         'onSelect' => 'myOnSelectHandler',
 *         'dateStatusFunc' => 'function (date) {return false;}',
 *     ),
 *     // 'button',                 // Auto-generate a button
 *     // 'button' => '',           // -or- also auto-generate a button
 *     // 'button' => 'myTrigger',  // -or- specify an ID for the trigger
 * );
 * $calendar =& $form->addElement('jscalendar', 'date', 'Date', $options);
 *
 * // Regular simple type configuration
 * // By the way: Setting daFormat ("display area format") will make the field
 * // to be hidden
 * $calendar->setConfig('daFormat', '%m/%d/%Y');
 *
 * // Callbacks configuration
 * $calendar->setConfig('onUpdate', 'myOnUpdateHandler', true);
 * $calendar->setConfig('onClick', 'function () {alert("Hello World!")}', true);
 *
 * // Auto-generate a button to open calendar
 * // (by default the calendar will open when clicking on the input field or
 * //  display area)
 * $calendar->setConfig('button');
 *
 * // Or you could pass an ID for the trigger instead
 * $calendar->setConfig('button', 'ID_of_my_popup_calendar_trigger');
 *
 * // You can also pass an array
 * $calendar->setConfig($options);
 *
 * // Allow multiple date selections (can also be passed in the attributes list
 * // or the $options in the constructor)
 * $calendar->setMultiple(true);
 *
 * // URL where you installed calendar's JavaScript files on your web server
 * // (Path must end with trailing slash /)
 * // You could also set $calendar->basePath
 * $GLOBALS['_HTML_QUICKFORM_JSCALENDAR_BASEPATH'] = 'js_library/jscalendar/';
 *
 * // Display this calendar in French
 * // Default language is English (en), and can be overwritten globally through
 * // $GLOBALS['_HTML_QUICKFORM_JSCALENDAR_LANG']
 * $calendar->lang = 'fr';
 *
 * // Continue with regular QuickForm setup and processing...
 * $form->display();
 * <code>
 *
 * PHP version 4 and 5
 *
 * LICENSE:
 *
 * Copyright (c) 2006-2007, Philippe Jausions / 11abacus
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   - Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of the 11abacus nor the names of its contributors may
 *     be used to endorse or promote products derived from this software
 *     without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @author       Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright    2006-2007 Philippe Jausions / 11abacus
 * @license      New BSD License http://www.opensource.org/licenses/bsd-license.html
 * @link         http://www.dynarch.com/projects/calendar/
 * @link         http://pear.11abacus.com/package/HTML_QuickForm_jscalendar
 * @package      HTML_QuickForm_jscalendar
 * @category     HTML
 */

/**
 * Required parent class
 */
require_once 'HTML/QuickForm.php';
require_once 
'HTML/QuickForm/text.php';

/**
 * We'll use the PHP_EOL constant
 *
 * @link http://pear.php.net/package/PHP_Compat
 */
if (!defined('PHP_EOL')) {
    require_once 
'PHP/Compat/Constant/PHP_EOL.php';
}

/**
 * We need PHP5's str_split()
 *
 * @link http://pear.php.net/package/PHP_Compat
 */
if (!function_exists('str_split')) {
    require_once 
'PHP/Compat/Function/str_split.php';
}

/**
 * Default global configurations (so you only need to set it once)
 */

/**
 * The base URL for the jsCalendar JavaScript files
 *
 * The URL must ends with a trailing slash (i.e. "/javascript/cal/")
 *
 * @global string $GLOBALS['_HTML_QUICKFORM_JSCALENDAR_BASEPATH']
 */
$GLOBALS['_HTML_QUICKFORM_JSCALENDAR_BASEPATH'] = '/jscalendar/';

/**
 * Default language
 *
 * 2-letter language code supported by jsCalendar
 *
 * @global string $GLOBALS['_HTML_QUICKFORM_JSCALENDAR_LANG']
 */
$GLOBALS['_HTML_QUICKFORM_JSCALENDAR_LANG'] = 'en';

/**
 * HTML Quickform element for jsCalendar
 *
 * jsCalendar is a dynamic JavaScript/HTML calendar which can be obtained from
 * http://www.dynarch.com/projects/calendar/
 *
 * The jsCalendar library itself was written by Mihai Bazon
 * (see the website above for licensing terms, and support)
 *
 * @author       Philippe Jausions <Philippe.Jausions@11abacus.com>
 * @copyright    2006-2007 11abacus
 * @license      New BSD License http://www.opensource.org/licenses/bsd-license.html
 * @link         http://www.dynarch.com/projects/calendar/
 * @link         http://pear.11abacus.com/package/HTML_QuickForm_jscalendar
 * @package      HTML_QuickForm_jscalendar
 * @category     HTML
 */
class HTML_QuickForm_jscalendar extends HTML_QuickForm_text
{
    
/**
     * The URL where to find the editor
     *
     * Use forward slashes / only.
     * The URL must end with a trailing slash /
     *
     * @var string
     * @access public
     */
    
var $basePath;

    
/**
     * Language for the calendar
     *
     * 2-letter language code supported by jsCalendar
     *
     * @var string
     * @access public
     */
    
var $lang;

    
/**
     * Calendar theme
     *
     * Setting this variable to a theme will generate the output of a <link>
     * tag, however, since <link> tags are not supposed to be in the <body>
     * of an HTML document, it is not recommended to do so.
     *
     * <code>
     * $calendar =& $form->addElement('jscalendar', 'date', 'Date');
     * $calendar->theme = 'calendar-win2k-1';
     * </code>
     *
     * @var string
     * @access public
     */
    
var $theme;

    
/**
     * Whether to use the jsCalendar version stripped of its comment
     *
     * @var boolean
     * @access public
     */
    
var $stripped true;

    
/**
     * Configuration settings for the calendar
     *
     * If you set the "daFormat", the field will be hidden instead of directly
     * editable. If JavaScript is disabled on the web browser, a regular text
     * field is displayed.
     *
     * @var array
     * @access private
     */
    
var $_config = array(
        
'ifFormat'  => '%Y-%m-%d',
        
'callbacks' => array(),
        );

    
/**
     * To avoid any namespace collision in JavaScript
     *
     * @var string
     * @access public
     */
    
var $jsPrefix '';

    
/**
     * Value(s)
     *
     * @var       mixed
     * @access    private
     */
    
var $_values null;

    
/**
     * Class constructor
     *
     * @param   string  jsCalendar instance name
     * @param   string  jsCalendar instance label
     * @param   array   Config settings for jsCalendar
     *                  (see "Calendar.setup in details" in "DHTML Calendar
     *                   Widget" online documentation)
     * @param   string  Attributes for the text input form field
     * @access  public
     */
    
function HTML_QuickForm_jscalendar($elementName null,
                                       
$elementLabel null$options = array(),
                                       
$attributes null)
    {
        
$this->updateAttributes(array('type' => 'text'));
        
$this->HTML_QuickForm_text($elementName$elementLabel$attributes);
        
$this->_persistantFreeze true;
        
$this->_type 'jscalendar';

        if (
is_array($options)) {
            
$this->setConfig($options);
        }
    }

    
/**
     * Sets configuration for jsCalendar
     *
     * @param mixed an associated array of configuration value
     *              or the name of key of config setting
     * @param mixed Value of config setting (only used when $key is a scalar)
     * @param boolean $callback whether the other parameters should be
     *                          considered as settings for callbacks.
     * @access public
     */
    
function setConfig($key$value null$callback false)
    {
        if (
$callback) {
            if (
is_array($key)) {
                foreach (
$key as $k => $v) {
                    
$this->_config['callbacks'][$k] = $v;
                }
            } else {
                
$this->_config['callbacks'][$key] = $value;
            }
        } else {
            if (
is_array($key)) {
                
// Catch the "button" special option
                
$button array_search('button'$key);
                if (
$button !== false && is_numeric($button)) {
                    unset(
$key[$button]);
                    
$key['button'] = '';
                }

                
// Catch the "multiple" special option
                
$multiple array_search('multiple'$key);
                if (
$multiple !== false && is_numeric($multiple)) {
                    unset(
$key[$multiple]);
                    
$key['multiple'] = true;
                }
                if (
array_key_exists('multiple'$key)) {
                    
$this->setMultiple($key['multiple']);
                    unset(
$key['multiple']);
                }

                
$this->_config array_merge($this->_config$key);

            } elseif (
$key == 'multiple') {
                if (
is_null($value)) {
                    
$value true;
                }
                
$this->setMultiple($value);

            } else {
                
$this->_config[$key] = $value;
            }
        }
    }

    
/**
     * Sets the "multiple" attribute for the calendar
     *
     * @param boolean $multiple Whether the calendar supports multi-selections
     *
     * @return void
     * @access public
     * @see getMultiple();
     */
    
function setMultiple($multiple true)
    {
        if (
$multiple) {
            
$this->updateAttributes(array('multiple' => true));
        } else {
            
$this->removeAttribute('multiple');
        }
    }

    
/**
     * Returns the "multiple" attribute for the calendar
     *
     * @return boolean Returns TRUE if the calendar supports multi-selections,
     *                 FALSE otherwise
     * @access public
     * @see setMultiple();
     */
    
function getMultiple($multiple true)
    {
        return (boolean)
$this->getAttribute('multiple');
    }

    
/**
     * Returns the jsCalendar in HTML
     *
     * @access public
     * @return string
     */
    
function toHtml()
    {
        if (
$this->_flagFrozen) {
            return 
$this->getFrozenHtml();
        }
        
$name     $this->getAttribute('name');
        
$safeName preg_replace('/[^a-zA-Z0-9-_]/''___',
                                 
$this->jsPrefix.$name).'___calendar_';
        
$id       $this->getAttribute('id');
        if (
is_null($id)) {
            
$id $safeName.'field';
            
$this->updateAttributes(array('id' => $id));
        }
        
$id      preg_replace('/[^a-zA-Z0-9-_]/''___'$id);
        
$cname   $safeName.'trigger';
        
$html    '';
        
$jscript '';

        
$options $this->_config;

        if (!
defined('HTML_QUICKFORM_JSCALENDAR_LOADED')) {
            
// load jsCalendar
            
$basePath = (empty($this->basePath))
                        ? 
$GLOBALS['_HTML_QUICKFORM_JSCALENDAR_BASEPATH']
                        : 
$this->basePath;

            
$lang = (empty($this->lang))
                    ? 
$GLOBALS['_HTML_QUICKFORM_JSCALENDAR_LANG']
                    : 
$this->lang;

            if (
$this->stripped) {
                
$calendarFile 'calendar_stripped.js';
                
$calendarSetupFile 'calendar-setup_stripped.js';
            } else {
                
$calendarFile 'calendar.js';
                
$calendarSetupFile 'calendar-setup.js';
            }

            
$calendarLangFile 'lang/calendar-'.$lang.'.js';

            
$html '<script type="text/javascript" src="'
                   
.$basePath.$calendarFile.'"></script>'
                   
.PHP_EOL
                 
.'<script type="text/javascript" src="'
                   
.$basePath.$calendarLangFile.'"></script>'
                   
.PHP_EOL
                 
.'<script type="text/javascript" src="'
                   
.$basePath.$calendarSetupFile.'"></script>'
                   
.PHP_EOL;

            if (isset(
$this->theme)) {
                
$html .= '<link rel="stylesheet" type="text/css" href="'
                         
.$basePath.$this->theme.'.css" />';
            }

            
define('HTML_QUICKFORM_JSCALENDAR_LOADED'true);
        }

        
// Add binding to input field
        
$options['inputField'] = $id;

        
// Handle multiple selections
        
$multiple $this->getMultiple();

        
$attr $this->getAttributes();
        unset(
$attr['multiple']);

        
$value $this->getValue();
        if (!
$multiple) {
            
// Render the text field
            
$htmlField parent::toHtml();
            
$htmlValue htmlspecialchars($value);

        } else {
            
// We may use a textarea element to list the multiple dates
            // instead of a type="text" one
            
unset($attr['type']);

            
settype($value'array');
            
$htmlValue implode(PHP_EOLarray_map('htmlspecialchars',
                                                    
$value));
            
$tag = new HTML_Common($attr);
            
$tag->removeAttribute('value');

            if (empty(
$options['daFormat'])) {
                
$tag->setAttribute('onchange'$safeName.'onUserChange(this);');
            }

            
$htmlField '<textarea '.$tag->getAttributes(true).'>'
                         
.$htmlValue
                         
.'</textarea>';
        }

        
// Should a button be automatically added?
        
$generateButton false;
        if (
array_key_exists('button'$options)
            && empty(
$options['button'])) {

            
$generateButton true;
            
$options['button'] = $cname;
        }

        
// Add the element that will contain the actual data
        
if (isset($options['daFormat'])) {
            if (empty(
$options['displayArea'])) {
                
$options['displayArea'] = $safeName.'displayArea';
            }
            
$html .= '<noscript>'.$htmlField.'</noscript>'.PHP_EOL;
        } else {
            
$html .= $htmlField;
        }

        if (
$multiple) {
            
// Setup the "multiple" option of the calendar
            
$jsDate = array();

            foreach (
$value as $v) {
                
$date = ($v) ? strtotime($v) : false;
                if (
$date 0) {
                    
$jsDates[] = 'new Date('.$date.'000)';
                }
            }

            
$dateVarName $safeName.'multiple';
            
$jscript .= 'var '.$dateVarName.' = ['.implode(', '$jsDates).'];'
                        
.PHP_EOL;
            
$options['callbacks']['multiple'] = $dateVarName;

            
// Create our own onClose callback to handle multiple dates
            // selection
            
if (!isset($options['daFormat'])) {
                
$jscript .= 'function '.$safeName.'onUserChange(element)'
                            
.PHP_EOL
                            
.'{'.PHP_EOL
                            
.'    var j = 0;'.PHP_EOL
                            
.'    var d = 0;'.PHP_EOL
                            
.'    var value = "";'.PHP_EOL
                            
.'    var values = element.value.split(/[\n\r]/);'
                            
.PHP_EOL
                            
.'    '.$dateVarName.'.length = 0;'.PHP_EOL
                            
.'    for (var i = 0; i < values.length; ++i) {'
                            
.PHP_EOL
                            
.'        d = Date.parseDate(values[i], "'
                                                        
.$options['ifFormat']
                                                        .
'");'.PHP_EOL
                            
.'        if (values[i] == d.print("'
                                                        
.$options['ifFormat']
                                                        .
'")) {'.PHP_EOL
                            
.'            '.$dateVarName.'[j++] = d;'.PHP_EOL
                            
.'        }'.PHP_EOL
                            
.'    }'.PHP_EOL
                            
.'    '.$dateVarName
                                   
.'.sort(function (a, b) {return a.getTime() - b.getTime();});'
                                   
.PHP_EOL
                            
.'    for (i = 0; i < j; ++i) {'.PHP_EOL
                            
.'        value += '.$dateVarName.'[i].print("'
                                                
.$options['ifFormat']
                                                .
'") + "\n";'.PHP_EOL
                            
.'    }'.PHP_EOL
                            
.'    element.value = value;'.PHP_EOL
                            
.'}'.PHP_EOL;
            }

            
$onClose 'function (cal) {'.PHP_EOL
                       
.'    var html = "";'.PHP_EOL
                       
.'    var d;'.PHP_EOL
                       
.'    var j = 0;'.PHP_EOL
                       
.'    var value = "";'.PHP_EOL
                       
.'    '.$dateVarName.'.length = 0;'.PHP_EOL
                       
.'    for (var i in cal.multiple) {'.PHP_EOL
                       
.'        d = cal.multiple[i];'.PHP_EOL
                       
.'        if (d) {'.PHP_EOL
                       
.'            '.$dateVarName.'[j++] = d;'.PHP_EOL
                       
.'        }'.PHP_EOL
                       
.'    }'.PHP_EOL
                       
.'    '.$dateVarName.'.sort(function (a, b) {return a.getTime() - b.getTime();});'.PHP_EOL
                       
.'    for (i = 0; i < j; ++i) {'.PHP_EOL
                       
.'        d = '.$dateVarName.'[i];'.PHP_EOL
                       
.'        value += d.print("'.$options['ifFormat']
                                                .
'") + "\n";'
                                                  
.PHP_EOL;
            if (!empty(
$options['daFormat'])) {
                
$onClose .= '        html += "<span>" + d.print("'
                                                 
.$options['daFormat'].'")'
                                                 
.' + "<\/span>";'.PHP_EOL;
            }
            
$onClose .=  '    }'.PHP_EOL
                        
.'    var field = document.getElementById("'.$id.'");'
                              
.PHP_EOL
                        
.'    field.value = value;'.PHP_EOL;

            if (!empty(
$options['daFormat'])) {
                
$onClose .= '    var display = document.getElementById("'
                                
.$options['displayArea'].'");'.PHP_EOL
                            
.'    display.innerHTML = html;'.PHP_EOL;
            }

            
// Any user-registered onClose callback?
            
if (!empty($options['callbacks']['onClose'])) {
                
$callback $options['callbacks']['onClose'];
                if (
preg_match('/^function[ (]/'$callback)) {
                    
$jscript .= 'var '.$safeName.'callback_onClose = '
                                
.$callback.';'.PHP_EOL;
                    
$callback $safeName.'callback_onClose';
                }

                
$onClose .= '    if (typeof '.$callback.' == "function") {'
                            
.PHP_EOL
                            
.'        return '.$callback.'(cal);'.PHP_EOL
                            
.'    }'.PHP_EOL;
            }
            
$onClose .=  '    cal.hide();'.PHP_EOL
                        
.'    return true;'.PHP_EOL
                        
.'}';

            
$options['callbacks']['onClose'] = $onClose;
        }

        
// Enhanced experience for JavaScript-enabled web browsers

        // If an area is used to display a formatted value:
        
if (isset($options['daFormat'])) {

            if (
$multiple) {
                
$htmlValue str_replace(PHP_EOL'\n'$htmlValue);

                
$htmlDisplayValue '';
                foreach (
$value as $v) {
                    
$date = ($v) ? strtotime($v) : false;
                    if (
$date 0) {
                        
$displayValue strftime($options['daFormat'], $date);
                    } else {
                        
$displayValue $v;
                    }
                    
$htmlDisplayValue .= '<span>'
                                         
.htmlspecialchars($displayValue)
                                         .
'<\/span>';
                }
            } else {
                
$date = ($value) ? strtotime($value) : false;
                if (
$date 0) {
                    
$displayValue strftime($options['daFormat'], $date);
                } else {
                    
$displayValue $value;
                }
                
$htmlDisplayValue htmlspecialchars($displayValue);
            }

            
$htmlField '<input type="hidden" name="'.htmlspecialchars($name)
                         .
'" id="'.htmlspecialchars($id).'"'
                         
.' value="'.$htmlValue.'" />';

            unset(
$attr['name']);
            unset(
$attr['value']);
            unset(
$attr['type']);
            unset(
$attr['rows']);
            unset(
$attr['cols']);
            
$attr['id'] = $options['displayArea'];

            
$tag = new HTML_Common($attr);

            
$jscript .= 'document.write(\''.$htmlField
                                     
.'<span '.$tag->getAttributes(true).'>'
                                     
.$htmlDisplayValue
                                     
.'<\\/span>\');'
                     
.PHP_EOL;
        }

        if (
$generateButton) {
            
$jscript .= 'document.write(\'<input type="button" value="..." name="'
                     
.$cname.'" id="'.$cname.'" />\');'.PHP_EOL;

        } elseif (empty(
$options['button']) && empty($options['displayArea'])) {
            
$options['eventName'] = 'focus';
        }

        
$jscript .= 'Calendar.setup({'.$this->_jsSerialize($options).'});'
                 
.PHP_EOL;

        return 
$html
               
.'<script type="text/javascript">'.PHP_EOL
               
.'// <![CDATA['.PHP_EOL
               
.$jscript
               
.'// ]]>'.PHP_EOL
               
.'</script>'.PHP_EOL;
    }

    
/**
     * Returns the jsCalendar content in HTML
     *
     * @return string
     * @access public
     */
    
function getFrozenHtml()
    {
        
$value $this->getValue();
        if (!isset(
$this->_config['daFormat'])) {
            return (
is_array($value))
                   ? 
implode('<br />'.PHP_EOL$value)
                   : 
$value;
        }
        
$data = array();
        
settype($value'array');
        foreach (
$value as $v) {
            
$date = ($v) ? strtotime($v) : false;
            
$data[] = ($date 0)
                      ? 
strftime($this->_config['daFormat'], $date)
                      : 
$v;
        }
        return 
implode('<br />'.PHP_EOL$data);
    }

    
/**
     * Serializes into JavaScript
     *
     * @param  array  $data
     * @return string
     * @access protected
     */
    
function _jsSerialize($data$function false)
    {
        
$jstr '';
        foreach (
$data as $key => $val) {
            if (
is_bool($val)) {
                
$val = ($val) ? 'true' 'false';

            } elseif (
$function) {
                
// We're good like this...

            
} elseif ($key == 'callbacks') {
                if (empty(
$val)) {
                    continue;
                }
                
$callbacks $this->_jsSerialize($valtrue);
                if (
$jstr) {
                    
$jstr .= ', ';
                }
                
$jstr .= $callbacks;
                continue;

            } elseif (
is_array($val)) {
                
// Used for multiple dates - NOT a generic array Javascript
                // serializer!
                
$val '['.implode(', '$val).']';

            } elseif (!
is_numeric($val)) {
                
$val '"'.$val.'"';
            }
            if (
$jstr) {
                
$jstr .= ', ';
            }
            
$jstr .= $key.':'.$val;
        }
        return 
$jstr;
    }

    
/**
     * Sets the element's value
     *
     * @param     string|array  $value  Dates (in ifFormat)
     * @return    void
     * @access    public
     */
    
function setValue($value)
    {
        if (
$this->getMultiple()) {
            if (
is_string($value)) {
                
$value preg_split('/[\r\n]/'$value);
            }
            
settype($value'array');
            foreach (
$value as $i => $v) {
                
$v trim($v);
                if (
strlen($v)) {
                    
$value[$i] = $v;
                } else {
                    unset(
$value[$i]);
                }
            }
        } else {
            
parent::setValue($value);
        }
        
$this->_values $value;
    }

    
/**
     * Returns element value(s)
     *
     * @return    string|array
     * @access    public
     */
    
function getValue()
    {
        if (
$this->getMultiple()) {
            return (array)
$this->_values;
        }
        if (!
is_array($this->_values) || !$this->_values) {
            return 
$this->_values;
        }
        
reset($this->_values);
        return 
current($this->_values);
    }
}

/**
 * Register the element
 */
HTML_QuickForm::registerElementType('jscalendar',
                                    
'HTML/QuickForm/jscalendar.php',
                                    
'HTML_QuickForm_jscalendar');

?>