Skip to content

Commit

Permalink
VS-4437: Adding backported functionalities to DatePicker (referenceDa…
Browse files Browse the repository at this point in the history
…te) (#821)

* Changes/Fixes:
- added idea files to .gitignore,
- fixes in README.md,
- added changes to helper and mixin
- some open questions and tests are missing as well,
- gitignore new line,
- readme. MD
- was importing and using _getAdjustedYear not properly, it was also not conventional,
- further, fix in parseDate
- 30+ tests shall be fixed
(Note: only 2 shall remain to be fixed, on it to fix them as well)

* More fixes in tests.

* Making the commit changeset smaller, seemingly removing not needed changes.

* Added test cases to keyboard-input.html cover the reference date related tests.
-  (Asynch tests are right now cannot be added, or at least needed to be transformed, refactored, and tested if this solution is working: Polymer/tools#1302, we need to have a specific version of Polymer as well)

* Fixed duplicate line mentioned in code review by Ugur (thanks).

* Small fixes:
- In the test cases the not used variable is removed,
- Added a presentation demo, to show how the reference date is working.

* Further fixes:
- date-picker-presentation-demos html fixed, used wrong identifiers (the previous example id-s),
- _parseDate was not always reachable, now it shall be reachable from vaadin-date-picker-mixin.html always,
- 11-31 is not a real date in date picker mixin, so fixed the test.

* Fixes:
- Asynch tests reworked (Ugur's idea around were good on assigning i18n values and how to input new values),
- Some minor changes were needed around asynchronousity and how to clean the old values when we have embedded test cases,
(I spent quite many hours today to figure out, but now all the tests are green, providing proper value)

Now all tests are working finally.

* Update demo/date-picker-presentation-demos.html

Adding better wording for the new example in presentation-demos.html

Co-authored-by: Ugur Saglam <106508695+ugur-vaadin@users.noreply.github.com>

* Update demo/date-picker-presentation-demos.html

Change Date to date in the presentation-demos.html, as it is more consistent, and follows naming conventions.

Co-authored-by: Ugur Saglam <106508695+ugur-vaadin@users.noreply.github.com>

Co-authored-by: Ugur Saglam <106508695+ugur-vaadin@users.noreply.github.com>
  • Loading branch information
czp13 and ugur-vaadin committed Jan 17, 2023
1 parent 0cf8eb7 commit feeeeb4
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 20 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
yarn.lock
coverage
analysis.json
.idea
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,22 +97,23 @@ To use the Material theme, import the correspondent file from the `theme/materia

1. Fork the `vaadin-date-picker` repository and clone it locally.

1. Make sure you have [npm](https://www.npmjs.com/) and [Bower](https://bower.io) installed.
2. Make sure you have [npm](https://www.npmjs.com/) and [Bower](https://bower.io)
and [Polymer](https://polymer-library.polymer-project.org/) installed.

1. When in the `vaadin-date-picker` directory, run `npm install` and then `bower install` to install dependencies.
3. When in the `vaadin-date-picker` directory, run `npm install` and then `bower install` to install dependencies.

1. Run `npm start`, browser will automatically open the component API documentation.
4. Run `npm start`, browser will automatically open the component API documentation.

1. You can also open demo or in-browser tests by adding **demo** or **test** to the URL, for example:
5. You can also open demo or in-browser tests by adding **demo** or **test** to the URL, for example:

- http://127.0.0.1:3000/components/vaadin-date-picker/demo
- http://127.0.0.1:3000/components/vaadin-date-picker/test


## Running tests from the command line

1. When in the `vaadin-date-picker` directory, run `polymer test`

1. When in the `vaadin-date-picker` directory, run `npm test` (this will execute:"test": "wct")
(tests will be fetched from the `test/basics.html` file)

## Following the coding style

Expand Down
16 changes: 16 additions & 0 deletions demo/date-picker-presentation-demos.html
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ <h3>Date picker with week numbers</h3>
</template>
</vaadin-demo-snippet>


<h3>Date picker with reference date</h3>
<p>Dates with 2-digit years will be interpreted according to the reference date, 1919-11-31 in this example. Therefore 70 will be interpreted as 1870, while 68 will be interpreted as 1968.</p>
<vaadin-demo-snippet id="date-picker-with-reference-date" when-defined="vaadin-date-picker">
<template preserve-content>
<vaadin-date-picker label="Label"></vaadin-date-picker>
<script>
window.addDemoReadyListener('#date-picker-with-reference-date', function(document) {
const datepicker = document.querySelector('vaadin-date-picker');
datepicker.set('i18n.referenceDate', '1919-11-31');
});
</script>
</template>
</vaadin-demo-snippet>


</template>
<script>
class DatePickerPresentationDemos extends DemoReadyEventEmitter(DatePickerDemo(Polymer.Element)) {
Expand Down
47 changes: 47 additions & 0 deletions src/vaadin-date-picker-helper.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,53 @@
return Math.floor((daysSinceFirstOfJanuary) / 7 + 1);
}

/**
* Calculate the year of the date based on the provided reference date.
* Gets a two-digit year and returns a full year.
* @param {!Date} referenceDate The date to act as basis in the calculation
* @param {!number} year Should be in the range of [0, 99]
* @param {number} month
* @param {number} day
* @return {!number} Adjusted year value
*/
static _getAdjustedYear(referenceDate, year, month = 0, day = 1) {
if (year > 99) {
throw new Error('The provided year cannot have more than 2 digits.');
}
if (year < 0) {
throw new Error('The provided year cannot be negative.');
}
// Year values up to 2 digits are parsed based on the reference date.
let adjustedYear = year + Math.floor(referenceDate.getFullYear() / 100) * 100;
if (referenceDate < new Date(adjustedYear - 50, month, day)) {
adjustedYear -= 100;
} else if (referenceDate > new Date(adjustedYear + 50, month, day)) {
adjustedYear += 100;
}
return adjustedYear;
}

/**
* Parse date string of one of the following date formats:
* - ISO 8601 `"YYYY-MM-DD"`
* - 6-digit extended ISO 8601 `"+YYYYYY-MM-DD"`, `"-YYYYYY-MM-DD"`
* @param {!string} str Date string to parse
* @return {Date} Parsed date
*/
static _parseDate(str) {
// Parsing with RegExp to ensure correct format
var parts = /^([-+]\d{1}|\d{2,4}|[-+]\d{6})-(\d{1,2})-(\d{1,2})$/.exec(str);
if (!parts) {
return;
}

var date = new Date(0, 0); // Wrong date (1900-01-01), but with midnight in local time
date.setFullYear(parseInt(parts[1], 10));
date.setMonth(parseInt(parts[2], 10) - 1);
date.setDate(parseInt(parts[3], 10));
return date;
}

/**
* Check if two dates are equal.
*
Expand Down
47 changes: 34 additions & 13 deletions src/vaadin-date-picker-mixin.html
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,22 @@
// Translation of the Cancel button text.
cancel: 'Cancel',
// Used for adjusting the year value when parsing dates with short years.
// The year values between 0 and 99 are evaluated and adjusted.
// Example: for a referenceDate of 1970-10-30;
// dateToBeParsed: 40-10-30, result: 1940-10-30
// dateToBeParsed: 80-10-30, result: 1980-10-30
// dateToBeParsed: 10-10-30, result: 2010-10-30
// Supported date format: ISO 8601 `"YYYY-MM-DD"` (default)
// The default value is the current date.
referenceDate: '',
// A function to format given `Object` as
// date string. Object is in the format `{ day: ..., month: ..., year: ... }`
// Note: The argument month is 0-based. This means that January = 0 and December = 11.
formatDate: d => {
// returns a string representation of the given
// object in 'MM/DD/YYYY' -format
formatDate(d) {
const yearStr = String(d.year).replace(/\d+/, (y) => '0000'.substr(y.length) + y);
return [d.month + 1, d.day, yearStr].join('/');
},
// A function to parse the given text to an `Object` in the format `{ day: ..., month: ..., year: ... }`.
Expand All @@ -211,8 +221,18 @@
value: () => {
return {
monthNames: [
'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October', 'November', 'December'
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
],
weekdays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
weekdaysShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
Expand All @@ -222,22 +242,24 @@
clear: 'Clear',
today: 'Today',
cancel: 'Cancel',
referenceDate: '',
formatDate: d => {
const yearStr = String(d.year).replace(/\d+/, y => '0000'.substr(y.length) + y);
return [d.month + 1, d.day, yearStr].join('/');
},
parseDate: text => {
parseDate(text) {
const parts = text.split('/');
const today = new Date();
let date, month = today.getMonth(), year = today.getFullYear();

if (parts.length === 3) {
month = parseInt(parts[0]) - 1;
date = parseInt(parts[1]);
year = parseInt(parts[2]);
if (parts[2].length < 3 && year >= 0) {
year += year < 50 ? 2000 : 1900;
const usedReferenceDate = this.referenceDate ? Vaadin.DatePickerHelper._parseDate(this.referenceDate) : new Date();
year = Vaadin.DatePickerHelper._getAdjustedYear(usedReferenceDate, year, month, date);
}
month = parseInt(parts[0]) - 1;
date = parseInt(parts[1]);
} else if (parts.length === 2) {
month = parseInt(parts[0]) - 1;
date = parseInt(parts[1]);
Expand All @@ -250,10 +272,10 @@
}
},
formatTitle: (monthName, fullYear) => {
return monthName + ' ' + fullYear;
}
return `${monthName} ${fullYear}`;
},
};
}
},
},

/**
Expand Down Expand Up @@ -1029,7 +1051,6 @@
get _overlayContent() {
return this.$.overlay.content.querySelector('#overlay-content');
}

/**
* Fired when the user commits a value change.
*
Expand Down
75 changes: 74 additions & 1 deletion test/keyboard-input.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<script src="../../webcomponentsjs/webcomponents-lite.js"></script>
<script src="common.js"></script>
<script src="../../iron-test-helpers/mock-interactions.js"></script>
<link rel="import" href="vaadin-date-picker-helper.html">
<link rel="import" href="../../test-fixture/test-fixture.html">

<link rel="import" href="../vaadin-date-picker.html">
Expand Down Expand Up @@ -517,11 +518,83 @@
expect(result.getDate()).to.equal(9);
});

it('should throw when passing a year < 0', () => {
expect(() => Vaadin.DatePickerHelper._getAdjustedYear(today, -1, 1, 1)).to.throw(Error);
});

it('should throw when passing a year >= 100', () => {
expect(() => Vaadin.DatePickerHelper._getAdjustedYear(today, 100, 1, 1)).to.throw(Error);
});

it('should parse with default day value when day is not provided', () => {
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1919, 11, 30), 70, 0)).to.equal(1870);
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1920, 0, 1), 70, 0)).to.equal(1970);
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1920, 0, 2), 70, 0)).to.equal(1970);
});

it('should parse with default month and day values when only year is provided', () => {
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1919, 11, 30), 70)).to.equal(1870);
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1920, 0, 1), 70)).to.equal(1970);
expect(Vaadin.DatePickerHelper._getAdjustedYear(new Date(1920, 0, 2), 70)).to.equal(1970);
});

it('should parse short year with current date as reference date', () => {
checkYearOffsets();
});

it('should parse short year with a custom reference date later in century', () => {
Object.assign(datepicker.i18n, {referenceDate: '1999-01-01'});
checkYearOffsets();
});

it('should parse short year with a custom reference date earlier in century', () => {
Object.assign(datepicker.i18n, {referenceDate: '2001-01-01'});
checkYearOffsets();
});

it('should parse short year with a custom reference date and ambiguous year difference', () => {
Object.assign(datepicker.i18n, {referenceDate: '2001-03-15'});
checkMonthAndDayOffset(0, 0, 0);
checkMonthAndDayOffset(0, -1, 0);
checkMonthAndDayOffset(0, 1, -100);
checkMonthAndDayOffset(-1, 0, 0);
checkMonthAndDayOffset(1, 0, -100);
});

function checkMonthAndDayOffset(monthOffsetToAdd, dayOffsetToAdd, expectedYearOffset) {
const referenceDate = new Date(datepicker.i18n.referenceDate);
const yearToTest = referenceDate.getFullYear() + 50;
target.value = '';
inputText(`${referenceDate.getMonth() + 1 + monthOffsetToAdd}/${referenceDate.getDate() + dayOffsetToAdd}/${
yearToTest % 100
}`);

const result = focusedDate();
expect(result.getFullYear()).to.equal(yearToTest + expectedYearOffset);
}

function checkYearOffsets() {
checkYearOffset(0, 0);
checkYearOffset(-49, 0);
checkYearOffset(49, 0);
checkYearOffset(-51, 100);
checkYearOffset(51, -100);
}

function checkYearOffset(offsetToAdd, expectedOffset) {
const referenceDateYear = datepicker.i18n.referenceDate
? new Date(datepicker.i18n.referenceDate).getFullYear()
: today.getFullYear();
const yearToTest = referenceDateYear + offsetToAdd;
target.value = '';
inputText(`6/20/${String(yearToTest).slice(2, 4)}`);
const result = focusedDate();
expect(result.getFullYear()).to.equal(yearToTest + expectedOffset);
}
});

describe('focus modes', () => {

var today;
var overlayContent;

beforeEach(() => overlayContent = getOverlayContent(datepicker));
Expand Down

0 comments on commit feeeeb4

Please sign in to comment.