Skip to content

Commit

Permalink
Compatibility with jQuery 3.2, Today-button
Browse files Browse the repository at this point in the history
  • Loading branch information
sjaakp committed Dec 23, 2017
1 parent ec5df29 commit 82081d9
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 85 deletions.
30 changes: 10 additions & 20 deletions DatePicker.php
@@ -1,18 +1,16 @@
<?php
/**
* MIT licence
* Version 1.0
* Sjaak Priester, Amsterdam 04-06-2015.
* Version 1.1.0
* Sjaak Priester, Amsterdam 04-06-2015, 23-12-2017.
* Input widget to handle fuzzy dates. 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.
*/

namespace sjaakp\fuzzydate;

use Yii;
use yii\helpers\Html;
use yii\web\View;
use yii\widgets\InputWidget;
use yii\base\InvalidConfigException;

Expand Down Expand Up @@ -44,6 +42,14 @@ class DatePicker extends InputWidget {
*/
public $monthFormat = '%B';

/**
* @var string | array | null
* - If string: text for 'Today' button, will not be HTML encoded
* - If array: HTML options for button. Member with key 'content' is button text, will not be HTML encoded; other options will
* - If null, no 'Today'-button is displayed
*/
public $today = 'Today';


public function run() {
if (! $this->hasModel() || ! $this->attribute) {
Expand All @@ -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');

Expand Down
24 changes: 17 additions & 7 deletions README.md
Expand Up @@ -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'`.

Expand Down Expand Up @@ -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).

Expand Down Expand Up @@ -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()`.

Expand Down Expand Up @@ -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'
],
/// ..
Expand Down Expand Up @@ -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:

[
Expand All @@ -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.

Expand All @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions assets/fuzzy.css
Expand Up @@ -11,3 +11,9 @@
.ui-widget .input-sm {
font-size: 12px;
}
.fuzzy-month {
margin-left: -2px;
}
.fuzzy-today {
margin-left: .6em;
}
116 changes: 71 additions & 45 deletions assets/fuzzy_assist.js
Expand Up @@ -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');
}
Expand All @@ -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);
});

}
2 changes: 1 addition & 1 deletion assets/fuzzy_assist.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 33 additions & 12 deletions views/datePicker.php
@@ -1,11 +1,12 @@
<?php
/**
* MIT licence
* Version 1.0
* Version 1.1.0
* Sjaak Priester, Amsterdam 04-06-2015.
*/

use yii\helpers\Html;
use yii\helpers\ArrayHelper;
use yii\web\View;
use yii\jui\Spinner;
use yii\jui\DatePicker as JuiDatePicker;
Expand All @@ -18,10 +19,22 @@

$model = $widget->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');
}
?>

<div class="form-group">
Expand All @@ -38,21 +51,29 @@
'max' => $widget->maxYear
],
]) ?>
<?= Html::activeDropDownList($model, "{$attribute}[m]", $months, [
'prompt' => '',
'class' => 'fuzzy-month ' . $widget->controlClass,
]) ?>

<?= JuiDatePicker::widget([
'model' => $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',
],
]) ?>

<?= Html::activeDropDownList($model, "{$attribute}[m]", $months, [
'prompt' => '',
'class' => 'fuzzy-month ' . $widget->controlClass,
]) ?>

<?= Html::activeTextInput($model, "{$attribute}[d]", [
'size' => 2,
'class' => 'fuzzy-day ' . $widget->controlClass,
]) ?>

<?php if ($today): ?>
<?= Html::button($todayContent, $today) ?>
<?php endif; ?>

</div>
</div>

0 comments on commit 82081d9

Please sign in to comment.