Skip to content

Commit

Permalink
lib: Let the date-and-time input control behave as defined in HTML5
Browse files Browse the repository at this point in the history
refs #6593
  • Loading branch information
lippserd committed Sep 3, 2014
1 parent 906de4e commit 2025fb3
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 96 deletions.
91 changes: 47 additions & 44 deletions application/views/helpers/FormDateTime.php
Expand Up @@ -2,69 +2,72 @@
// {{{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
{
/**
* 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 int $value The default timestamp
* @param DateTime $value The default timestamp
* @param array $attribs Attributes for the element tag
*
* @return string The element XHTML
*/
public function formDateTime($name, $value = null, $attribs = null)
{
$info = $this->_getInfo($name, $value, $attribs);
extract($info); // name, value, attribs, options, listsep, disable
// Is it disabled?
extract($info); // name, id, value, attribs, options, listsep, disable
/** @var string $id */
/** @var bool $disable */
$disabled = '';
if ($disabled) {
if ($disable) {
$disabled = ' disabled="disabled"';
}

$jspicker = (isset($attribs['jspicker']) && $attribs['jspicker'] === true) ? true : false;

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 = '';
if ($value instanceof DateTime) {
// If value was valid, it's a DateTime object
$value = $this->formatDate($value, $attribs['local']);
}

// Build the element
$xhtml = '<div class="datetime' . (($jspicker === true) ? ' input-group' : ''). '">';

$xhtml .= '<input type="text" name="' . $name . '"'
. ' id="' . $name . '"'
. $value
. $disabled
. $this->_htmlAttribs($attribs);

if ($jspicker === true) {
$xhtml .= 'data-icinga-component="app/datetime"';
$min = '';
if (! empty($attribs['min'])) {
$min = sprintf(' min="%s"', $this->formatDate($attribs['min'], $attribs['local']));
}

$xhtml .= $this->getClosingBracket();

if ($jspicker === true) {
$xhtml .= '<span class="input-group-addon">'
. '<a href="#">'
. '<i class="icinga-icon-reschedule"></i>'
. '</a>'
. '</span>';
unset($attribs['min']); // Unset min to not render it again in $this->_htmlAttribs($attribs)
$max = '';
if (! empty($attribs['max'])) {
$max = sprintf(' max="%s"', $this->formatDate($attribs['max'], $attribs['local']));
}

$xhtml .= '</div>';

return $xhtml;
unset($attribs['max']); // Unset max to not render it again in $this->_htmlAttribs($attribs)
$type = $attribs['local'] === true ? 'datetime-local' : 'datetime';
unset($attribs['local']); // Unset local to not render it again in $this->_htmlAttribs($attribs)
$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;
}
}
149 changes: 97 additions & 52 deletions library/Icinga/Web/Form/Element/DateTimePicker.php
Expand Up @@ -4,100 +4,145 @@

namespace Icinga\Web\Form\Element;

use Icinga\Web\Form\Validator\DateTimeValidator;
use Zend_Form_Element_Text;
use DateTime;
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
* DateTimeFactory to ensure time zone awareness
* A date-and-time input control
*
* @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 bool
*
* @see \Icinga\Web\Form::__construct() For default element decorators.
*/
protected $_disableLoadDefaultDecorators = true;

/**
* Form view helper to use for rendering
*
* @var string
*/
public $defaultFormat = 'Y-m-d H:i:s';
public $helper = 'formDateTime';

/**
* JS picker support on or off
* @var bool
*/
public $jspicker = true;
protected $local = true;

/**
* View helper to use
* @var string
* The expected lower bound for the element’s value
*
* @var DateTime|null
*/
public $helper = 'formDateTime';
protected $min;

/**
* The validator used for datetime validation
* @var DateTimeValidator
* The expected upper bound for the element’s
*
* @var DateTime|null
*/
private $dateValidator;
protected $max;

/**
* Valid formats to check user input against
* @var array
* (non-PHPDoc)
* @see \Zend_Form_Element::init() For the method documentation.
*/
public $patterns = array();
public function init()
{
$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));
}
}

public function setLocal($local)
{
$this->local = (bool) $local;
return $this;
}

public function getLocal()
{
return $this->local;
}

/**
* Create a new DateTimePicker
* Set the expected lower bound for the element’s value
*
* @param DateTime $min
*
* @param array|string|\Zend_Config $spec
* @param null $options
* @see Zend_Form_Element::__construct()
* @return $this
*/
public function __construct($spec, $options = null)
public function setMin(DateTime $min)
{
parent::__construct($spec, $options);
$this->min = $min;
return $this;
}

/**
* Get the expected lower bound for the element’s value
*
* @return DateTime|null
*/
public function getMin()
{
return $this->min;
}

$this->patterns[] = $this->defaultFormat;
/**
* Set the expected upper bound for the element’s value
*
* @param DateTime $max
*
* @return $this
*/
public function setMax(DateTime $max)
{
$this->max = $max;
return $this;
}

$this->dateValidator = new DateTimeValidator($this->patterns);
$this->addValidator($this->dateValidator);
/**
* Get the expected upper bound for the element’s value
*
* @return DateTime|null
*/
public function getMax()
{
return $this->max;
}

/**
* Validate filtered date/time strings
* Is the date and time valid?
*
* Expects one or more valid formats being set in $this->patterns. Sets element value as Unix timestamp
* if the input is considered valid. Utilizes DateTimeFactory to ensure time zone awareness.
* @param string|DateTime $value
* @param mixed $context
*
* @param string $value
* @param mixed $context
* @return bool
*/
public function isValid($value, $context = null)
{
// Overwrite the internal validator to use

if (!parent::isValid($value, $context)) {
if (! parent::isValid($value, $context)) {
return false;
}
$pattern = $this->dateValidator->getValidPattern();
if (!$pattern) {
$this->setValue($value);
return true;
if (! $value instanceof DateTime) {
$format = $this->local === true ? 'Y-m-d\TH:i:s' : DateTime::RFC3339;
$this->setValue(DateTime::createFromFormat($format, $value));
}
$this->setValue(DateTimeFactory::parse($value, $pattern)->getTimestamp());
return true;
}

public function enableJsPicker()
{
$this->jspicker = true;
}

public function disableJsPicker()
{
$this->jspicker = false;
}
}

0 comments on commit 2025fb3

Please sign in to comment.