Skip to content

Commit

Permalink
Upgrade date picker
Browse files Browse the repository at this point in the history
  • Loading branch information
jordisala1991 committed May 9, 2023
1 parent a9a93fb commit 0743d63
Show file tree
Hide file tree
Showing 191 changed files with 10,463 additions and 17,322 deletions.
42 changes: 42 additions & 0 deletions UPGRADE-2.0.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,48 @@
UPGRADE 2.0
===========

## Upgrade Date Picker

Since the begining, Sonata was using Eonasdan Bootstrap Datepicker in its version 3.1.3 to provide date picker capabilities.

Starting from 2.0 of `form-extensions`, the date picker library has been updated to latest version of
Eonasdan Tempus Dominus. It is the successor of Bootstrap Datepicker,
and its options are not compatible
with the previous version (but they look similar).

Previously all the options were configured using `dp_` prefix, now they are configured using `datepicker_options`.

This affects all the `Picker` types, including `DatePickerType`, `DateTimePickerType`, `DateRangePickerType` and `DateTimeRangePickerType`.

For example, the following code:

```php
$form->add('date', DatePickerType::class, [
'dp_use_current' => false,
'dp_min_date' => '2017-01-01',
'dp_max_date' => '2017-12-31',
]);
```

Should be replaced by:

```php
$form->add('date', DatePickerType::class, [
'datepicker_options' => [
'useCurrent' => false,
'restrictions' => [
'minDate' => '2017-01-01',
'maxDate' => '2017-12-31',
],
],
]);
```

All the options accepted by Tempus Dominus are available via `datepicker_options` and are well
documented on the official [docs](https://getdatepicker.com/6/options/).

You can also take a look at Sonata documentation for more information.

## Deprecations

All the deprecated code introduced on 1.x is removed on 2.0.
Expand Down
13 changes: 4 additions & 9 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@
// Any SCSS/CSS you require will output into a single css file (app.css in this case)
import '../scss/app.scss';

import moment from 'moment';
// eslint-disable-next-line import/no-unresolved
import DatePicker from '@symfony/stimulus-bridge/lazy-controller-loader?lazy=true!./controllers/datepicker_controller.js';

// Eonasdan Bootstrap DateTimePicker in its version 3 does not
// provide the scss or plain css, it only provides the less version
// of its source files, that's why it is not included it via npm.
import '../vendor/bootstrap-datetimepicker';
const { sonataApplication } = global;

// Create global moment variable to be used by the locale script.
// It expects moment to be available on the global scope
// in order to define the requested locale translations
global.moment = moment;
sonataApplication.register('datepicker', DatePicker);
141 changes: 141 additions & 0 deletions assets/js/controllers/datepicker_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*!
* This file is part of the Sonata Project package.
*
* (c) Thomas Rabaix <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { Controller } from '@hotwired/stimulus';
import { TempusDominus, Namespace, loadLocale } from '@eonasdan/tempus-dominus';
import { faFiveIcons } from '@eonasdan/tempus-dominus/dist/plugins/fa-five';

export default class extends Controller {
static outlets = ['datepicker'];

static values = {
options: Object,
};

#allowedLocales = [
'ar',
'ar-SA',
'de',
'es',
'fi',
'fr',
'it',
'nl',
'pl',
'ro',
'ru',
'sl',
'tr',
];

datePicker = null;

connect() {
const options = this.processOptions();
const locale = this.processLocale(options);

this.dispatchEvent('pre-connect', { options, locale });

this.datePicker = new TempusDominus(this.element, options);

if (locale !== null) {
import(`@eonasdan/tempus-dominus/dist/locales/${locale}`).then((data) => {
loadLocale(data);

this.datePicker.locale(data.name);
this.datePicker.updateOptions(options);

this.dispatchEvent('post-connect-changed-locale');
});
}

this.dispatchEvent('connect', { datePicker: this.datePicker });
}

datepickerOutletConnected(outlet, element) {
this.element.addEventListener(Namespace.events.change, (event) => {
outlet.datePicker.updateOptions({
restrictions: {
minDate: event.detail.date,
},
});
});

element.addEventListener(Namespace.events.change, (event) => {
this.datePicker.updateOptions({
restrictions: {
maxDate: event.detail.date,
},
});
});
}

processOptions() {
const options = this.optionsValue;
const { restrictions = {}, display = {} } = options;

if (options?.defaultDate) {
options.defaultDate = new Date(options.defaultDate);
}

if (options?.viewDate) {
options.viewDate = new Date(options.viewDate);
}

if (restrictions?.minDate) {
restrictions.minDate = new Date(restrictions.minDate);
}

if (restrictions?.maxDate) {
restrictions.maxDate = new Date(restrictions.maxDate);
}

if (restrictions?.disabledDates) {
restrictions.disabledDates = restrictions.disabledDates.map((date) => new Date(date));
}

if (restrictions?.enabledDates) {
restrictions.enabledDates = restrictions.enabledDates.map((date) => new Date(date));
}

if (!display?.icons) {
display.icons = faFiveIcons;
}

return options;
}

processLocale(options) {
const { localization: { locale } = {} } = options;

if (!locale) {
return null;
}

if (this.#allowedLocales.includes(locale)) {
return locale;
}

if (!locale.includes('-')) {
return null;
}

const localeCode = locale.split('-')[0];

if (this.#allowedLocales.includes(localeCode)) {
return localeCode;
}

return null;
}

dispatchEvent(name, payload) {
this.dispatch(name, { detail: payload, prefix: 'datepicker' });
}
}
Loading

0 comments on commit 0743d63

Please sign in to comment.