diff --git a/DatePicker.php b/DatePicker.php index 39a1100..ae09444 100644 --- a/DatePicker.php +++ b/DatePicker.php @@ -1,8 +1,8 @@ hasModel() || ! $this->attribute) { @@ -57,22 +63,6 @@ public function run() { $view->registerJs("fuzzyReg();"); - $id = Html::getInputId($this->model, $this->attribute); - $val = Html::getAttributeValue($this->model, $this->attribute); - - if ($val && is_array($val)) { - $y = $val['y']; - if ($y) { - $m = $val['m']; - if (! $m) $m = 'null'; - $d = $val['d']; - if (! $d) $d = 'null'; - - // Call this after initializing jQuery-objects - $view->registerJs("fuzzySet('$id', $y, $m, $d);", View::POS_LOAD); - } - } - if (! $this->minYear) $this->minYear = date('Y'); if (! $this->maxYear) $this->maxYear = date('Y'); diff --git a/README.md b/README.md index 1f6fbb3..ad98b5a 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,13 @@ Yii2 Fuzzydate Often, when working with dates, data are incomplete. For instance, one might know that a person is born in 1980, or in April, 1980, but not on which day exactly. -I call these dates *fuzzy dates*. Here are a few classes to work with them in the Yii 2.0 PHP framework. +I call these dates *fuzzy dates*. Here are a few classes to work with them in the Yii 2.x PHP framework. ## Fuzzy date representation ## ### In the database ### -In the database each fuzzy date is represented by **two** 'normal' dates. The field names of the two dates is derived from the attribute name of the fuzzy date, by appending `'1'` and `'2'` respectively. +In the database each fuzzy date is represented by **two** 'normal' dates. The field names of the two dates are derived from the attribute name of the fuzzy date, by appending `'1'` and `'2'` respectively. So, if the attribute name of the fuzzy date is `'born'`, the fields representing is in the database would be `'born1'` and `'born2'`. @@ -81,7 +81,7 @@ The preferred way to install **Yii2 Fuzzydate** is through [Composer](https://ge Or run: -`$ php composer.phar require sjaakp/yii2-fuzzydate "*"` +`composer require sjaakp/yii2-fuzzydate "*"` You can manually install **Yii2 Fuzzydate** by [downloading the source in ZIP-format](https://github.com/sjaakp/yii2-fuzzydate/archive/master.zip). @@ -119,7 +119,7 @@ A class `Hero` with fuzzy date attributes `'born'` and `'died'` should have data // ... } -After that, class `Hero` has two 'virtual attributes, `'born'`, and `'died'`. +After that, class `Hero` has two 'virtual attributes', `'born'`, and `'died'`. **Notice:** Don't forget to declare the attributes *safe* in the method `rules()`. @@ -150,7 +150,7 @@ Use this by setting it as component in the application's configuration file (of 'components' => [ // ... other components ... - [ + 'formatter' => [ 'class' => 'sjaakp\fuzzydate\Formatter' ], /// .. @@ -196,7 +196,7 @@ The text `'fuzzyDate'` is case independent. `'fuzzydate'` works as well. #### $fuzzyDateFormat #### - - if string: `'short'`, `'medium'`, `'long'`, or `'full'`. **Formatter** tries to figure out the formatting of a fuzzy date based on the formatting of a standard date. With most locales, this works OK, however with some locales the results are less satisfying. +- if string: `'short'`, `'medium'`, `'long'`, or `'full'`. **Formatter** tries to figure out the formatting of a fuzzy date based on the formatting of a standard date. With most locales, this works OK, however with some locales the results are less satisfying. - if array: the keys are `'full'`, `'month'`, and `'year'`, corresponding to the granularity of the fuzzy date. The values are [ICU date formats](http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax "ICU user guide"). Example: [ @@ -221,7 +221,7 @@ Formats a fuzzy date, as delivered by a Model with a **FuzzyDateBehavior**. ## DatePicker ## -This is an input widget to handle fuzzy dates. It consists of a spin control for the year, a dropdown list for the month, and a datepicker for the day. Both month and day can be blank, indicating an incomplete date. +This is an input widget to handle fuzzy dates. It consists of a spin control for the year, a dropdown list for the month, a datepicker for the day, and optionally a 'Today'-button. Both month and day can be blank, indicating an incomplete date. **DatePicker** has all the attributes and methods of an [**InputWidget**](http://www.yiiframework.com/doc-2.0/yii-widgets-inputwidget.html "Yii 2.0 API") plus the following. @@ -245,6 +245,16 @@ Sets the format of the month names in the dropdown list. These are format strings from PHP's [strftime()](http://php.net/manual/en/function.strftime.php "PHP API") function. +#### $today #### + +Options for the 'Today'-button. + +- If `string`: the text for the 'Today'-button. This will not be HTML-encoded before it's rendered. +- If `array`: HTML options for the 'Today'-button. The arry value with the key `'content'` will be displayed as text and will not be HTML-encoded; other options will. +- If `null`: no 'Today'-button is rendered. + +Default: `'Today'`. + ### Usage ### Use **DatePicker** like any other InputWidget. Example: diff --git a/assets/fuzzy.css b/assets/fuzzy.css index f83a24b..233528e 100644 --- a/assets/fuzzy.css +++ b/assets/fuzzy.css @@ -11,3 +11,9 @@ .ui-widget .input-sm { font-size: 12px; } +.fuzzy-month { + margin-left: -2px; +} +.fuzzy-today { + margin-left: .6em; +} diff --git a/assets/fuzzy_assist.js b/assets/fuzzy_assist.js index 774fa13..7e1e2df 100644 --- a/assets/fuzzy_assist.js +++ b/assets/fuzzy_assist.js @@ -2,14 +2,20 @@ /*jslint nomen: true, unparam: true, white: true */ /** * MIT licence - * Version 1.0 - * Sjaak Priester, Amsterdam 04-06-2015. + * Version 1.1.0 + * Sjaak Priester, Amsterdam 04-06-2015, 19-12-2017. */ -function fuzzyEnable(elmt_id, bEnable) { + +/** + * + * @param elmt_id element id, prepended by '#' + * @param bEnable + */ +function fuzzyEnableElement(elmt_id, bEnable) { "use strict"; - var elmt = $('#' + elmt_id); + var elmt = $(elmt_id); if (bEnable) { elmt.removeAttr('disabled'); } @@ -19,69 +25,89 @@ function fuzzyEnable(elmt_id, bEnable) { } } -function fuzzySet(base_id, y, m, d) { +/** + * + * @param elmt input element + * @param yy year (hack for first spin step after empty y) + */ +function fuzzyEnable(elmt, yy) { "use strict"; - if (y) { - fuzzyEnable(base_id + '-m', true); - - if (m) { - var min_date = new Date(y, m - 1, 1), - max_date = new Date(y, m, 0), - max_day = max_date.getDate(), - curr_date = d ? new Date(y, m - 1, d > max_day ? max_day : d) : null; - - fuzzyEnable(base_id + '-d', true); + var base_id = '#' + elmt.id.slice(0, -1), + y = yy || $(base_id + 'y').val(), + m = $(base_id + 'm').val(), + d = $(base_id + 'd').val(); - $('#' + base_id + '-d').datepicker('option', { - minDate: min_date, - maxDate: max_date, - defaultDate: curr_date - }) - .datepicker('setDate', curr_date) - ; - } - else { - fuzzyEnable(base_id + '-d', false); - } + if (!!y) { + fuzzyEnableElement(base_id + 'm', true); // if year not null, enable month + fuzzyEnableElement(base_id + 'd', !!m); // and enable day, if month is also not null } else { - fuzzyEnable(base_id + '-m', false); - fuzzyEnable(base_id + '-d', false); + fuzzyEnableElement(base_id + 'm', false); // if year is null disable month + fuzzyEnableElement(base_id + 'd', false); // and disable day } } -function fuzzyUpd(elmt, yy) { - "use strict"; - - var base_id = elmt.id.slice(0, -2), - y = yy || $('#' + base_id + '-y').val(), - m = $('#' + base_id + '-m').val(), - d = $('#' + base_id + '-d').val(); - - fuzzySet(base_id, y, m, d); -} - function fuzzyReg() { "use strict"; $('.fuzzy-year').on('input spin',function(e, ui) { - fuzzyUpd(this, ui.value); + fuzzyEnable(this, ui.value); }) .keydown( function(e) { if (e.which === 8 || e.which === 46) { $(this).val(''); - fuzzyUpd(this); + fuzzyEnable(this); } } - ); + ).each(function(i, elmt) { + fuzzyEnable(elmt); + }); + $('.fuzzy-month').change(function(e) { - fuzzyUpd(this); + fuzzyEnable(this); }); + $('.fuzzy-day').keydown( function(e) { if (e.which === 8 || e.which === 46) { - $(this).datepicker('setDate',null) - .datepicker('option','defaultDate',null); + $(this).val(''); + $('#' + this.id.slice(0, -1) + 'p').datepicker('setDate', null); } + }) + .focus( function(e) { + var base_id = '#' + this.id.slice(0, -1), + y = $(base_id + 'y').val(), + m = $(base_id + 'm').val(), + d = $(base_id + 'd').val(), + min_date = new Date(y, m - 1, 1), + max_date = new Date(y, m, 0), + max_day = max_date.getDate(), + curr_date = d ? new Date(y, m - 1, d > max_day ? max_day : d) : null, + day_elmt = this; + + $(base_id + 'p').datepicker('option', { + minDate: min_date, + maxDate: max_date, + defaultDate: curr_date, + dateFormat: 'yy-m-d', + hideIfNoPrevNext: true, + + onSelect: function(d, inst) { + var dd = d.split('-'); + $(day_elmt).val(dd[2]); + } + + }).datepicker('show'); }); + + $('.fuzzy-today').click(function(e) { + var base_id = '#' + this.id.slice(0, -1), + d = new Date(); + + $(base_id + 'y').val(d.getFullYear()); + $(base_id + 'm').val(d.getMonth() + 1); + $(base_id + 'd').val(d.getDate()); + fuzzyEnable(this); + }); + } diff --git a/assets/fuzzy_assist.min.js b/assets/fuzzy_assist.min.js index 3ebcd35..ecb141d 100644 --- a/assets/fuzzy_assist.min.js +++ b/assets/fuzzy_assist.min.js @@ -1 +1 @@ -function fuzzyEnable(elmt_id,bEnable){"use strict";var elmt=$("#"+elmt_id);if(bEnable){elmt.removeAttr("disabled")}else{elmt.val("");elmt.attr("disabled","disabled")}}function fuzzySet(base_id,y,m,d){"use strict";if(y){fuzzyEnable(base_id+"-m",true);if(m){var min_date=new Date(y,m-1,1),max_date=new Date(y,m,0),max_day=max_date.getDate(),curr_date=d?new Date(y,m-1,d>max_day?max_day:d):null;fuzzyEnable(base_id+"-d",true);$("#"+base_id+"-d").datepicker("option",{minDate:min_date,maxDate:max_date,defaultDate:curr_date}).datepicker("setDate",curr_date)}else{fuzzyEnable(base_id+"-d",false)}}else{fuzzyEnable(base_id+"-m",false);fuzzyEnable(base_id+"-d",false)}}function fuzzyUpd(elmt,yy){"use strict";var base_id=elmt.id.slice(0,-2),y=yy||$("#"+base_id+"-y").val(),m=$("#"+base_id+"-m").val(),d=$("#"+base_id+"-d").val();fuzzySet(base_id,y,m,d)}function fuzzyReg(){"use strict";$(".fuzzy-year").on("input spin",function(e,ui){fuzzyUpd(this,ui.value)}).keydown(function(e){if(e.which===8||e.which===46){$(this).val("");fuzzyUpd(this)}});$(".fuzzy-month").change(function(e){fuzzyUpd(this)});$(".fuzzy-day").keydown(function(e){if(e.which===8||e.which===46){$(this).datepicker("setDate",null).datepicker("option","defaultDate",null)}})} \ No newline at end of file +function fuzzyEnableElement(elmt_id,bEnable){"use strict";var elmt=$(elmt_id);if(bEnable){elmt.removeAttr("disabled")}else{elmt.val("");elmt.attr("disabled","disabled")}}function fuzzyEnable(elmt,yy){"use strict";var base_id="#"+elmt.id.slice(0,-1),y=yy||$(base_id+"y").val(),m=$(base_id+"m").val(),d=$(base_id+"d").val();if(!!y){fuzzyEnableElement(base_id+"m",true);fuzzyEnableElement(base_id+"d",!!m)}else{fuzzyEnableElement(base_id+"m",false);fuzzyEnableElement(base_id+"d",false)}}function fuzzyReg(){"use strict";$(".fuzzy-year").on("input spin",function(e,ui){fuzzyEnable(this,ui.value)}).keydown(function(e){if(e.which===8||e.which===46){$(this).val("");fuzzyEnable(this)}}).each(function(i,elmt){fuzzyEnable(elmt)});$(".fuzzy-month").change(function(e){fuzzyEnable(this)});$(".fuzzy-day").keydown(function(e){if(e.which===8||e.which===46){$(this).val("");$("#"+this.id.slice(0,-1)+"p").datepicker("setDate",null)}}).focus(function(e){var base_id="#"+this.id.slice(0,-1),y=$(base_id+"y").val(),m=$(base_id+"m").val(),d=$(base_id+"d").val(),min_date=new Date(y,m-1,1),max_date=new Date(y,m,0),max_day=max_date.getDate(),curr_date=d?new Date(y,m-1,d>max_day?max_day:d):null,day_elmt=this;$(base_id+"p").datepicker("option",{minDate:min_date,maxDate:max_date,defaultDate:curr_date,dateFormat:"yy-m-d",hideIfNoPrevNext:true,onSelect:function(d,inst){var dd=d.split("-");$(day_elmt).val(dd[2])}}).datepicker("show")});$(".fuzzy-today").click(function(e){var base_id="#"+this.id.slice(0,-1),d=new Date;$(base_id+"y").val(d.getFullYear());$(base_id+"m").val(d.getMonth()+1);$(base_id+"d").val(d.getDate());fuzzyEnable(this)})} \ No newline at end of file diff --git a/views/datePicker.php b/views/datePicker.php index 26cf2af..1410068 100644 --- a/views/datePicker.php +++ b/views/datePicker.php @@ -1,11 +1,12 @@ model; $attribute = $widget->attribute; +$inputId = Html::getInputId($model, $attribute); setlocale(LC_ALL, Yii::$app->language); // need this for strftime() $months = []; for ($m = 1; $m <= 12; $m++) $months[$m] = strftime($widget->monthFormat, mktime(0, 0, 0, $m, 1)); + +$today = $widget->today; +$todayContent = ''; +if (is_string($today)) $today = [ + 'content' => $today, + 'class' => 'btn btn-default btn-xs fuzzy-today', +]; +if ($today) { + $today['id'] = $inputId . '-t'; + $todayContent = ArrayHelper::remove($today, 'content', 'Today'); +} ?>
@@ -38,21 +51,29 @@ 'max' => $widget->maxYear ], ]) ?> - '', - 'class' => 'fuzzy-month ' . $widget->controlClass, - ]) ?> + $model, - 'attribute' => "{$attribute}[d]", - 'dateFormat' => 'd', + 'attribute' => "{$attribute}[p]", 'options' => [ - 'class' => 'fuzzy-day ' . $widget->controlClass, - 'size' => 2, - ], - 'clientOptions' => [ - 'hideIfNoPrevNext' => true, + 'class' => $widget->controlClass, + 'style' => 'visibility:hidden;width:0;padding-left:0;padding-right:0;border-width:0', ], ]) ?> + + '', + 'class' => 'fuzzy-month ' . $widget->controlClass, + ]) ?> + + 2, + 'class' => 'fuzzy-day ' . $widget->controlClass, + ]) ?> + + + + +