lib: Let the date-and-time input control behave as defined in HTML5

refs #6593
This commit is contained in:
Eric Lippmann 2014-09-03 14:40:58 +02:00
parent 906de4e679
commit 2025fb3a2f
2 changed files with 149 additions and 101 deletions

View File

@ -2,18 +2,30 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
use Zend_View_Helper_FormElement;
/** /**
* Helper to generate a "datetime" element * Render date-and-time input controls
*/ */
class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
{ {
/** /**
* Generate a 'datetime' element * Format date and time
*
* @param DateTime $dateTime
* @param bool $local
*
* @return string
*/
public function formatDate(DateTime $dateTime, $local)
{
$format = (bool) $local === true ? 'Y-m-d\TH:i:s' : DateTime::RFC3339;
return $dateTime->format($format);
}
/**
* Render the date-and-time input control
* *
* @param string $name The element name * @param string $name The element name
* @param int $value The default timestamp * @param DateTime $value The default timestamp
* @param array $attribs Attributes for the element tag * @param array $attribs Attributes for the element tag
* *
* @return string The element XHTML * @return string The element XHTML
@ -21,50 +33,41 @@ class Zend_View_Helper_FormDateTime extends Zend_View_Helper_FormElement
public function formDateTime($name, $value = null, $attribs = null) public function formDateTime($name, $value = null, $attribs = null)
{ {
$info = $this->_getInfo($name, $value, $attribs); $info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable extract($info); // name, id, value, attribs, options, listsep, disable
// Is it disabled? /** @var string $id */
/** @var bool $disable */
$disabled = ''; $disabled = '';
if ($disabled) { if ($disable) {
$disabled = ' disabled="disabled"'; $disabled = ' disabled="disabled"';
} }
if ($value instanceof DateTime) {
$jspicker = (isset($attribs['jspicker']) && $attribs['jspicker'] === true) ? true : false; // If value was valid, it's a DateTime object
$value = $this->formatDate($value, $attribs['local']);
if (isset($value) && !empty($value)) {
if ($jspicker) {
$value = ' value="' . $this->view->dateFormat()->format($value, $attribs['defaultFormat']) . '"';
} else {
$value = ' value="' . $this->view->dateFormat()->formatDateTime($value) . '"';
}
} else {
$value = '';
} }
$min = '';
// Build the element if (! empty($attribs['min'])) {
$xhtml = '<div class="datetime' . (($jspicker === true) ? ' input-group' : ''). '">'; $min = sprintf(' min="%s"', $this->formatDate($attribs['min'], $attribs['local']));
$xhtml .= '<input type="text" name="' . $name . '"'
. ' id="' . $name . '"'
. $value
. $disabled
. $this->_htmlAttribs($attribs);
if ($jspicker === true) {
$xhtml .= 'data-icinga-component="app/datetime"';
} }
unset($attribs['min']); // Unset min to not render it again in $this->_htmlAttribs($attribs)
$xhtml .= $this->getClosingBracket(); $max = '';
if (! empty($attribs['max'])) {
if ($jspicker === true) { $max = sprintf(' max="%s"', $this->formatDate($attribs['max'], $attribs['local']));
$xhtml .= '<span class="input-group-addon">'
. '<a href="#">'
. '<i class="icinga-icon-reschedule"></i>'
. '</a>'
. '</span>';
} }
unset($attribs['max']); // Unset max to not render it again in $this->_htmlAttribs($attribs)
$xhtml .= '</div>'; $type = $attribs['local'] === true ? 'datetime-local' : 'datetime';
unset($attribs['local']); // Unset local to not render it again in $this->_htmlAttribs($attribs)
return $xhtml; $html5 = sprintf(
'<input type="%s" name="%s" id="%s" value="%s"%s%s%s%s%s',
$type,
$this->view->escape($name),
$this->view->escape($id),
$this->view->escape($value),
$min,
$max,
$disabled,
$this->_htmlAttribs($attribs),
$this->getClosingBracket()
);
return $html5;
} }
} }

View File

@ -4,100 +4,145 @@
namespace Icinga\Web\Form\Element; namespace Icinga\Web\Form\Element;
use Icinga\Web\Form\Validator\DateTimeValidator; use DateTime;
use Zend_Form_Element_Text;
use Zend_Form_Element; use Zend_Form_Element;
use Icinga\Util\DateTimeFactory; use Icinga\Web\Form\Validator\DateTimeValidator;
/** /**
* Datetime form element which returns the input as Unix timestamp after the input has been proven valid. Utilizes * A date-and-time input control
* DateTimeFactory to ensure time zone awareness
* *
* @see isValid() * @method DateTime getValue()
*/ */
class DateTimePicker extends Zend_Form_Element_Text class DateTimePicker extends Zend_Form_Element
{ {
/** /**
* Default format used my js picker * Disable default decorators
*
* \Icinga\Web\Form sets default decorators for elements.
* *
* @var string
*/
public $defaultFormat = 'Y-m-d H:i:s';
/**
* JS picker support on or off
* @var bool * @var bool
*
* @see \Icinga\Web\Form::__construct() For default element decorators.
*/ */
public $jspicker = true; protected $_disableLoadDefaultDecorators = true;
/** /**
* View helper to use * Form view helper to use for rendering
*
* @var string * @var string
*/ */
public $helper = 'formDateTime'; public $helper = 'formDateTime';
/** /**
* The validator used for datetime validation * @var bool
* @var DateTimeValidator
*/ */
private $dateValidator; protected $local = true;
/** /**
* Valid formats to check user input against * The expected lower bound for the elements value
* @var array
*/
public $patterns = array();
/**
* Create a new DateTimePicker
* *
* @param array|string|\Zend_Config $spec * @var DateTime|null
* @param null $options
* @see Zend_Form_Element::__construct()
*/ */
public function __construct($spec, $options = null) protected $min;
/**
* The expected upper bound for the elements
*
* @var DateTime|null
*/
protected $max;
/**
* (non-PHPDoc)
* @see \Zend_Form_Element::init() For the method documentation.
*/
public function init()
{ {
parent::__construct($spec, $options); $this->addValidator(
new DateTimeValidator($this->local), true // true for breaking the validator chain on failure
);
if ($this->min !== null) {
$this->addValidator('GreaterThan', true, array('min' => $this->min));
}
if ($this->max !== null) {
$this->addValidator('LessThan', true, array('max' => $this->max));
}
}
$this->patterns[] = $this->defaultFormat; public function setLocal($local)
{
$this->local = (bool) $local;
return $this;
}
$this->dateValidator = new DateTimeValidator($this->patterns); public function getLocal()
$this->addValidator($this->dateValidator); {
return $this->local;
} }
/** /**
* Validate filtered date/time strings * Set the expected lower bound for the elements value
* *
* Expects one or more valid formats being set in $this->patterns. Sets element value as Unix timestamp * @param DateTime $min
* if the input is considered valid. Utilizes DateTimeFactory to ensure time zone awareness. *
* @return $this
*/
public function setMin(DateTime $min)
{
$this->min = $min;
return $this;
}
/**
* Get the expected lower bound for the elements value
*
* @return DateTime|null
*/
public function getMin()
{
return $this->min;
}
/**
* Set the expected upper bound for the elements value
*
* @param DateTime $max
*
* @return $this
*/
public function setMax(DateTime $max)
{
$this->max = $max;
return $this;
}
/**
* Get the expected upper bound for the elements value
*
* @return DateTime|null
*/
public function getMax()
{
return $this->max;
}
/**
* Is the date and time valid?
*
* @param string|DateTime $value
* @param mixed $context
* *
* @param string $value
* @param mixed $context
* @return bool * @return bool
*/ */
public function isValid($value, $context = null) public function isValid($value, $context = null)
{ {
// Overwrite the internal validator to use if (! parent::isValid($value, $context)) {
if (!parent::isValid($value, $context)) {
return false; return false;
} }
$pattern = $this->dateValidator->getValidPattern(); if (! $value instanceof DateTime) {
if (!$pattern) { $format = $this->local === true ? 'Y-m-d\TH:i:s' : DateTime::RFC3339;
$this->setValue($value); $this->setValue(DateTime::createFromFormat($format, $value));
return true;
} }
$this->setValue(DateTimeFactory::parse($value, $pattern)->getTimestamp());
return true; return true;
} }
public function enableJsPicker()
{
$this->jspicker = true;
}
public function disableJsPicker()
{
$this->jspicker = false;
}
} }