* @since 1.0 */ class DateRangePicker extends \kartik\base\InputWidget { /** * @var string the javascript callback to be passed to the plugin constructor. * Note: a default value is set for this when you set `hideInput` to false, OR * you set `useWithAddon` to `true`. */ public $callback; /** * @var boolean whether to hide the input (e.g. when you want to show the date * range picker as a dropdown). If set to true, the input will be hidden. The plugin * will be initialized on a container element (default 'div'), using the container template. * A default `callback` will be setup in this case to display the selected range value within * the container. */ public $hideInput = false; /** * @var boolean whether you are using the picker with a input group addon. You can set it * to `true`, when `hideInput` is false, and you wish to show the picker position more * correctly at the input-group-addon icon. A default `callback` will be setup in this case * to generate the selected range value for the input. */ public $useWithAddon = false; /** * @var initialize all the list values set in `pluginOptions['ranges']` * and convert all values to yii\web\JsExpression */ public $initRangeExpr = true; /** * @var boolean show a preset dropdown. If set to true, this will automatically generate * a preset list of ranges for selection. Setting this to true will also automatically * set `initRangeExpr` to true. */ public $presetDropdown = false; /** * @var array the HTML attributes for the container, if hideInput is set * to true. The following special options are recognized: * `tag`: string, the HTML tag for rendering the container. Defaults to `div`. */ public $containerOptions = ['class' => 'drp-container input-group']; /** * @var array the template for rendering the container, when hideInput is set * to true. The special tag `{input}` will be replaced with the hidden form input. * In addition, the element with css class `range-value` will be replaced by the * calculated plugin value. The special tag `{value}` will be replaced with the * value of the hidden form input during initialization */ public $containerTemplate = <<< HTML {value} {input} HTML; /** * @inherit doc */ protected $_pluginName = 'daterangepicker'; /** * @var string locale language to be used for the plugin */ protected $eLang = ''; /** * @var string the pluginOptions format for the date time */ private $_format; /** * @var string the pluginOptions separator */ private $_separator; /** * Initializes the widget * * @throw InvalidConfigException */ public function init() { parent::init(); $this->_msgCat = 'kvdrp'; $this->initI18N(__DIR__); $this->initLocale(); if ($this->convertFormat && isset($this->pluginOptions['format'])) { $this->pluginOptions['format'] = static::convertDateFormat($this->pluginOptions['format']); } $this->_format = ArrayHelper::getValue($this->pluginOptions, 'format', 'YYYY-MM-DD'); $this->_separator = ArrayHelper::getValue($this->pluginOptions, 'separator', ' - '); if (!empty($this->value)) { $dates = explode($this->_separator, $this->value); if (count($dates) > 1) { $this->pluginOptions['startDate'] = $dates[0]; $this->pluginOptions['endDate'] = $dates[1]; } } $value = empty($this->value) ? '' : $this->value; $this->containerTemplate = str_replace('{value}', $value, $this->containerTemplate); $this->initRange(); $this->containerOptions['id'] = $this->options['id'] . '-container'; $this->registerAssets(); echo $this->renderInput(); } /** * Initialize locale settings */ protected function initLocale() { $this->setLanguage(''); if (empty($this->_langFile)) { return; } $localeSettings = ArrayHelper::getValue($this->pluginOptions, 'locale', []); $localeSettings += [ 'applyLabel' => Yii::t('kvdrp', 'Apply'), 'cancelLabel' => Yii::t('kvdrp', 'Cancel'), 'fromLabel' => Yii::t('kvdrp', 'From'), 'toLabel' => Yii::t('kvdrp', 'To'), 'weekLabel' => Yii::t('kvdrp', 'W'), 'customRangeLabel' => Yii::t('kvdrp', 'Custom Range'), 'daysOfWeek' => new JsExpression('moment.weekdaysMin()'), 'monthNames' => new JsExpression('moment.monthsShort()'), 'firstDay' => new JsExpression('moment.localeData()._week.dow') ]; $this->pluginOptions['locale'] = $localeSettings; } /** * Automatically convert the date format from PHP DateTime to Moment.js DateTime format * as required by bootstrap-daterangepicker plugin. * * @see http://php.net/manual/en/function.date.php * @see http://momentjs.com/docs/#/parsing/string-format/ * * @param string $format the PHP date format string * * @return string */ protected static function convertDateFormat($format) { return strtr($format, [ // meridian lowercase remains same // 'a' => 'a', // meridian uppercase remains same // 'A' => 'A', // second (with leading zeros) 's' => 'ss', // minute (with leading zeros) 'i' => 'mm', // hour in 12-hour format (no leading zeros) 'g' => 'h', // hour in 12-hour format (with leading zeros) 'h' => 'hh', // hour in 24-hour format (no leading zeros) 'G' => 'H', // hour in 24-hour format (with leading zeros) 'H' => 'HH', // day of the week locale 'w' => 'e', // day of the week ISO 'W' => 'E', // day of month (no leading zero) 'j' => 'D', // day of month (two digit) 'd' => 'DD', // day name short 'D' => 'DDD', // day name long 'l' => 'DDDD', // month of year (no leading zero) 'n' => 'M', // month of year (two digit) 'm' => 'MM', // month name short 'M' => 'MMM', // month name long 'F' => 'MMMM', // year (two digit) 'y' => 'YY', // year (four digit) 'Y' => 'YYYY', // unix timestamp 'U' => 'X', ]); } /** * Initializes the pluginOptions range list */ protected function initRange() { if (isset($dummyValidation)) { $msg = Yii::t('kvdrp', 'Select Date Range'); } if ($this->presetDropdown) { $this->initRangeExpr = true; $this->pluginOptions['ranges'] = [ Yii::t('kvdrp', "Today") => ["moment().startOf('day')", "moment()"], Yii::t('kvdrp', "Yesterday") => [ "moment().startOf('day').subtract(1,'days')", "moment().endOf('day').subtract(1,'days')" ], Yii::t('kvdrp', "Last {n} Days", ['n' => 7]) => [ "moment().startOf('day').subtract(6, 'days')", "moment()" ], Yii::t('kvdrp', "Last {n} Days", ['n' => 30]) => [ "moment().startOf('day').subtract(29, 'days')", "moment()" ], Yii::t('kvdrp', "This Month") => ["moment().startOf('month')", "moment().endOf('month')"], Yii::t('kvdrp', "Last Month") => [ "moment().subtract(1, 'month').startOf('month')", "moment().subtract(1, 'month').endOf('month')" ], ]; } if (!$this->initRangeExpr || empty($this->pluginOptions['ranges']) || !is_array($this->pluginOptions['ranges'])) { return; } $range = []; foreach ($this->pluginOptions['ranges'] as $key => $value) { if (!is_array($value) || empty($value[0]) || empty($value[1])) { throw new InvalidConfigException("Invalid settings for pluginOptions['ranges']. Each range value must be a two element array."); } $range[$key] = [static::parseJsExpr($value[0]), static::parseJsExpr($value[1])]; } $this->pluginOptions['ranges'] = $range; } /** * Parses and returns a JsExpression * * @param string|JsExpression $value * * @return JsExpression */ protected static function parseJsExpr($value) { return $value instanceof JsExpression ? $value : new JsExpression($value); } /** * Registers the needed client assets */ public function registerAssets() { $view = $this->getView(); MomentAsset::register($view); $input = 'jQuery("#' . $this->options['id'] . '")'; $id = $input; if ($this->hideInput) { $id = 'jQuery("#' . $this->containerOptions['id'] . '")'; } if (!empty($this->_langFile)) { LanguageAsset::register($view)->js[] = $this->_langFile; } DateRangePickerAsset::register($view); if (empty($this->callback)) { if ($this->hideInput) { $this->callback = <<< JS function(start, end) { var val = start.format('{$this->_format}') + '{$this->_separator}' + end.format('{$this->_format}'); {$id}.find('.range-value').html(val); {$input}.val(val); {$input}.trigger('change'); } JS; } elseif ($this->useWithAddon) { $id = "{$input}.closest('.input-group')"; $this->callback = <<< JS function(start, end) { var val = start.format('{$this->_format}') + '{$this->_separator}' + end.format('{$this->_format}'); {$input}.val(val); {$input}.trigger('change'); } JS; } else { $this->registerPlugin($this->_pluginName, $id); return; } } $this->registerPlugin($this->_pluginName, $id, null, $this->callback); } /** * Renders the input * * @return string */ protected function renderInput() { if (!$this->hideInput) { Html::addCssClass($this->options, 'form-control'); return $this->getInput('textInput'); } $tag = ArrayHelper::remove($this->containerOptions, 'tag', 'div'); $content = str_replace('{input}', $this->getInput('hiddenInput'), $this->containerTemplate); return Html::tag($tag, $content, $this->containerOptions); } }