* @since 1.0 * @see http://www.malot.fr/bootstrap-datetimepicker/ */ class DateTimePicker extends \kartik\base\InputWidget { const CALENDAR_ICON = ''; const TYPE_INPUT = 1; const TYPE_COMPONENT_PREPEND = 2; const TYPE_COMPONENT_APPEND = 3; const TYPE_INLINE = 4; const TYPE_BUTTON = 5; /** * * @var string the markup type of widget markup * must be one of the TYPE constants. Defaults * to [[TYPE_COMPONENT_PREPEND]] */ public $type = self::TYPE_COMPONENT_PREPEND; /** * * @var string The size of the input - 'lg', 'md', 'sm', 'xs' */ public $size; /** * * @var array the HTML attributes for the button that is rendered for [[DateTimePicker::TYPE_BUTTON]]. * Defaults to `['class'=>'btn btn-default']`. The following special options are recognized: * - 'label': string the button label. Defaults to `` */ public $buttonOptions = [ ]; /** * * @var array the HTML attributes for the input tag. */ public $options = [ ]; /** * * @var mixed the calendar/time picker button configuration. * - if this is passed as a string, it will be displayed as is (will not be HTML encoded). * - if this is set to false, the picker button will not be displayed. * - if this is passed as an array (this is the DEFAULT) it will treat this as HTML attributes * for the button (to be displayed as a Bootstrap addon). The following special keys are recognized; * - icon - string, the bootstrap glyphicon name/suffix. Defaults to 'calendar'. * - title - string, the title to be displayed on hover. Defaults to 'Select date & time'. */ public $pickerButton = [ ]; /** * * @var mixed the calendar/time remove button configuration. * - if this is passed as a string, it will be displayed as is (will not be HTML encoded). * - if this is set to false, the remove button will not be displayed. * - if this is passed as an array (this is the DEFAULT) it will treat this as HTML attributes * for the button (to be displayed as a Bootstrap addon). The following special keys are recognized; * - icon - string, the bootstrap glyphicon name/suffix. Defaults to 'remove'. * - title - string, the title to be displayed on hover. Defaults to 'Clear field'. */ public $removeButton = [ ]; /** * * @var string identifier for the target DateTimePicker element */ private $_id; /** * * @var array the HTML options for the DateTimePicker container */ private $_container = [ ]; /** * Initializes the widget * * @throw InvalidConfigException */ public function init() { $this->_msgCat = 'kvdatetime'; parent::init (); if ($this->type < 1 || $this->type > 5 || ! is_int ( $this->type )) { throw new InvalidConfigException ( "Invalid value for the property 'type'. Must be an integer between 1 and 5." ); } $this->initI18N (); $s = DIRECTORY_SEPARATOR; $this->setLanguage ( 'bootstrap-datetimepicker.', __DIR__ . "{$s}assets{$s}" ); $this->parseDateFormat ( 'datetime' ); $this->_id = ($this->type == self::TYPE_INPUT) ? 'jQuery("#' . $this->options ['id'] . '")' : 'jQuery("#' . $this->options ['id'] . '").parent()'; $this->registerAssets (); echo $this->renderInput (); } /** * Renders the source input for the DateTimePicker plugin. * Graceful fallback to a normal HTML text input - in * case JQuery is not supported by the browser */ protected function renderInput() { if ($this->type == self::TYPE_INLINE) { if (empty ( $this->options ['readonly'] )) { $this->options ['readonly'] = true; } if (empty ( $this->options ['class'] )) { $this->options ['class'] = 'form-control input-sm text-center'; } } else { Html::addCssClass ( $this->options, 'form-control' ); } $input = $this->type == self::TYPE_BUTTON ? 'hiddenInput' : 'textInput'; return $this->parseMarkup ( $this->getInput ( $input ) ); } /** * Returns the addon to render * * @param array $options * the HTML attributes for the addon * @param string $type * whether the addon is the picker or remove * @return string */ protected function renderAddon(&$options, $type = 'picker') { if ($options === false) { return ''; } if (is_string ( $options )) { return $options; } Html::addCssClass ( $options, 'input-group-addon' ); $icon = ($type === 'picker') ? 'calendar' : 'remove'; $icon = ''; if (empty ( $options ['title'] )) { $title = ($type === 'picker') ? Yii::t ( 'kvdatetime', 'Select date & time' ) : Yii::t ( 'kvdatetime', 'Clear field' ); if ($title != false) { $options ['title'] = $title; } } return Html::tag ( 'span', $icon, $options ); } /** * Parses the input to render based on markup type * * @param string $input * @return string */ protected function parseMarkup($input) { $css = $this->disabled ? ' disabled' : ''; if ($this->type == self::TYPE_INPUT || $this->type == self::TYPE_INLINE) { if (isset ( $this->size )) { Html::addCssClass ( $this->options, 'input-' . $this->size . $css ); } } elseif ($this->type != self::TYPE_BUTTON && isset ( $this->size )) { Html::addCssClass ( $this->_container, 'input-group input-group-' . $this->size . $css ); } elseif ($this->type != self::TYPE_BUTTON) { Html::addCssClass ( $this->_container, 'input-group' . $css ); } if ($this->type == self::TYPE_INPUT) { return $input; } if ($this->type == self::TYPE_COMPONENT_PREPEND) { Html::addCssClass ( $this->_container, 'date' ); $addon = $this->renderAddon ( $this->pickerButton ) . $this->renderAddon ( $this->removeButton, 'remove' ); return Html::tag ( 'div', $addon . $input, $this->_container ); } if ($this->type == self::TYPE_COMPONENT_APPEND) { Html::addCssClass ( $this->_container, 'date' ); $addon = $this->renderAddon ( $this->removeButton, 'remove' ) . $this->renderAddon ( $this->pickerButton ); return Html::tag ( 'div', $input . $addon, $this->_container ); } if ($this->type == self::TYPE_BUTTON) { Html::addCssClass ( $this->_container, 'date' ); $label = ArrayHelper::remove ( $this->buttonOptions, 'label', self::CALENDAR_ICON ); if (! isset ( $this->buttonOptions ['disabled'] )) { $this->buttonOptions ['disabled'] = $this->disabled; } if (empty ( $this->buttonOptions ['class'] )) { $this->buttonOptions ['class'] = 'btn btn-default'; } $button = Html::button ( $label, $this->buttonOptions ); Html::addCssStyle ( $this->_container, 'display:block' ); return Html::tag ( 'span', "{$input}{$button}", $this->_container ); } if ($this->type == self::TYPE_INLINE) { $this->_id = $this->options ['id'] . '-inline'; $this->_container ['id'] = $this->_id; return Html::tag ( 'div', '', $this->_container ) . $input; } } /** * Registers the needed assets */ public function registerAssets() { if ($this->disabled) { return; } $view = $this->getView (); if (! empty ( $this->_langFile )) { DateTimePickerAsset::register ( $view )->js [] = $this->_langFile; } else { DateTimePickerAsset::register ( $view ); } $id = "jQuery('#" . $this->options ['id'] . "')"; if ($this->type == self::TYPE_INLINE) { $this->pluginOptions ['linkField'] = $this->options ['id']; if (! empty ( $this->pluginOptions ['format'] )) { $this->pluginOptions ['linkFormat'] = $this->pluginOptions ['format']; } } if ($this->type === self::TYPE_INPUT) { $this->registerPlugin ( 'datetimepicker' ); } else { $this->registerPlugin ( 'datetimepicker', "{$id}.parent()" ); } } }