From ecab894e92c7b01d6b0d224428081f5fa5c3de0c Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Tue, 15 Sep 2015 21:56:32 +0100 Subject: [PATCH 1/3] [DatePicker] implement custom DateTimeFormat --- src/date-picker/calendar-toolbar.jsx | 48 +++---- src/date-picker/date-display.jsx | 24 ++-- src/utils/date-time.js | 206 +++++++++++++++++++-------- 3 files changed, 179 insertions(+), 99 deletions(-) diff --git a/src/date-picker/calendar-toolbar.jsx b/src/date-picker/calendar-toolbar.jsx index 9a459d453fd31d..4c7edaec797342 100644 --- a/src/date-picker/calendar-toolbar.jsx +++ b/src/date-picker/calendar-toolbar.jsx @@ -9,6 +9,24 @@ const SlideInTransitionGroup = require('../transition-groups/slide-in'); const ThemeManager = require('../styles/theme-manager'); const DefaultRawTheme = require('../styles/raw-themes/light-raw-theme'); +const styles = { + root: { + position: 'relative', + padding: 0, + backgroundColor: 'inherit', + }, + title: { + position: 'absolute', + top: 17, + lineHeight: '14px', + fontSize: 14, + height: 14, + width: '100%', + fontWeight: '500', + textAlign: 'center', + }, +}; + const CalendarToolbar = React.createClass({ contextTypes: { muiTheme: React.PropTypes.object, @@ -62,31 +80,11 @@ const CalendarToolbar = React.createClass({ } }, - _styles() { - return { - root: { - position: 'relative', - padding: 0, - backgroundColor: 'inherit', - }, - - title: { - position: 'absolute', - top: '17px', - lineHeight: '14px', - fontSize: '14px', - height: '14px', - width: '100%', - fontWeight: '500', - textAlign: 'center', - }, - }; - }, - render() { - let month = DateTime.getFullMonth(this.props.displayDate); - let year = this.props.displayDate.getFullYear(); - let styles = this._styles(); + const dateTimeFormated = new DateTime.DateTimeFormat('en-US', { + month: 'long', + year: 'numeric', + }).format(this.props.displayDate); const nextButtonIcon = this.state.muiTheme.isRtl ? : ; const prevButtonIcon = this.state.muiTheme.isRtl ? : ; @@ -96,7 +94,7 @@ const CalendarToolbar = React.createClass({ -
{month} {year}
+
{dateTimeFormated}
diff --git a/src/date-picker/date-display.jsx b/src/date-picker/date-display.jsx index 53f335aa68f2ee..b8cca8748551d7 100644 --- a/src/date-picker/date-display.jsx +++ b/src/date-picker/date-display.jsx @@ -85,12 +85,6 @@ const DateDisplay = React.createClass({ padding: 20, }, - month: { - display: isLandscape ? 'block' : undefined, - marginLeft: isLandscape ? undefined : 8, - marginTop: isLandscape ? 5 : undefined, - }, - monthDay: { root: { display: 'inline-block', @@ -135,11 +129,14 @@ const DateDisplay = React.createClass({ style, ...other, } = this.props; - let dayOfWeek = DateTime.getDayOfWeek(this.props.selectedDate); - let month = DateTime.getShortMonth(this.props.selectedDate); - let day = this.props.selectedDate.getDate(); - let year = this.props.selectedDate.getFullYear(); - let styles = this.getStyles(); + const year = this.props.selectedDate.getFullYear(); + const styles = this.getStyles(); + + const dateTimeFormated = new DateTime.DateTimeFormat('en-US', { + month: 'short', + weekday: 'short', + day: '2-digit', + }).format(this.props.selectedDate); return (
@@ -153,11 +150,10 @@ const DateDisplay = React.createClass({ style={styles.monthDay.root} direction={this.state.transitionDirection}>
- {dayOfWeek}, - {month} {day} + {dateTimeFormated}
diff --git a/src/utils/date-time.js b/src/utils/date-time.js index 9554057523b1a1..303d0836b8a376 100644 --- a/src/utils/date-time.js +++ b/src/utils/date-time.js @@ -1,19 +1,154 @@ + +function DateTimeFormat(locale, options) { + this.options = options; + + if (process.env.NODE_ENV !== 'production' && locale !== 'en-US') { + console.warn('Wrong usage of DateTimeFormat'); + } + + this.format = function(date) { + let output; + + if (options.month === 'short' && + options.weekday === 'short' && + options.day === '2-digit') { + + const day = date.getDay(); + switch (day) { + case 0: + output = 'Sun'; + break; + case 1: + output = 'Mon'; + break; + case 2: + output = 'Tue'; + break; + case 3: + output = 'Wed'; + break; + case 4: + output = 'Thu'; + break; + case 5: + output = 'Fri'; + break; + case 6: + output = 'Sat'; + break; + } + + output += ', '; + + const month = date.getMonth(); + switch (month) { + case 0: + output += 'Jan'; + break; + case 1: + output += 'Feb'; + break; + case 2: + output += 'Mar'; + break; + case 3: + output += 'Apr'; + break; + case 4: + output += 'May'; + break; + case 5: + output += 'Jun'; + break; + case 6: + output += 'Jul'; + break; + case 7: + output += 'Aug'; + break; + case 8: + output += 'Sep'; + break; + case 9: + output += 'Oct'; + break; + case 10: + output += 'Nov'; + break; + case 11: + output += 'Dec'; + break; + } + + output += ' ' + date.getDate() + } else if (options.month === 'long' + && options.year === 'numeric') { + + switch (date.getMonth()) { + case 0: + output = 'January'; + break; + case 1: + output = 'February'; + break; + case 2: + output = 'March'; + break; + case 3: + output = 'April'; + break; + case 4: + output = 'May'; + break; + case 5: + output = 'June'; + break; + case 6: + output = 'July'; + break; + case 7: + output = 'August'; + break; + case 8: + output = 'September'; + break; + case 9: + output = 'October'; + break; + case 10: + output = 'November'; + break; + case 11: + output = 'December'; + break; + } + + output += ' ' + date.getFullYear(); + } else if (process.env.NODE_ENV !== 'production') { + console.warn('Wrong usage of DateTimeFormat'); + } + + return output; + }; +} + module.exports = { + DateTimeFormat: DateTimeFormat, addDays(d, days) { - let newDate = this.clone(d); + const newDate = this.clone(d); newDate.setDate(d.getDate() + days); return newDate; }, addMonths(d, months) { - let newDate = this.clone(d); + const newDate = this.clone(d); newDate.setMonth(d.getMonth() + months); return newDate; }, addYears(d, years) { - let newDate = this.clone(d); + const newDate = this.clone(d); newDate.setFullYear(d.getFullYear() + years); return newDate; }, @@ -23,7 +158,7 @@ module.exports = { }, cloneAsDate(d) { - let clonedDate = this.clone(d); + const clonedDate = this.clone(d); clonedDate.setHours(0, 0, 0, 0); return clonedDate; }, @@ -41,55 +176,6 @@ module.exports = { return new Date(d.getFullYear(), d.getMonth(), 1); }, - getFullMonth(d) { - let month = d.getMonth(); - switch (month) { - case 0: return 'January'; - case 1: return 'February'; - case 2: return 'March'; - case 3: return 'April'; - case 4: return 'May'; - case 5: return 'June'; - case 6: return 'July'; - case 7: return 'August'; - case 8: return 'September'; - case 9: return 'October'; - case 10: return 'November'; - case 11: return 'December'; - } - }, - - getShortMonth(d) { - let month = d.getMonth(); - switch (month) { - case 0: return 'Jan'; - case 1: return 'Feb'; - case 2: return 'Mar'; - case 3: return 'Apr'; - case 4: return 'May'; - case 5: return 'Jun'; - case 6: return 'Jul'; - case 7: return 'Aug'; - case 8: return 'Sep'; - case 9: return 'Oct'; - case 10: return 'Nov'; - case 11: return 'Dec'; - } - }, - - getDayOfWeek(d) { - let dow = d.getDay(); - switch (dow) { - case 0: return 'Sun'; - case 1: return 'Mon'; - case 2: return 'Tue'; - case 3: return 'Wed'; - case 4: return 'Thu'; - case 5: return 'Fri'; - case 6: return 'Sat'; - } - }, - getWeekArray(d) { let dayArray = []; let daysInMonth = this.getDaysInMonth(d); @@ -120,9 +206,9 @@ module.exports = { }, format(date) { - let m = date.getMonth() + 1; - let d = date.getDate(); - let y = date.getFullYear(); + const m = date.getMonth() + 1; + const d = date.getDate(); + const y = date.getFullYear(); return m + '/' + d + '/' + y; }, @@ -134,15 +220,15 @@ module.exports = { }, isBeforeDate(d1, d2) { - let date1 = this.cloneAsDate(d1); - let date2 = this.cloneAsDate(d2); + const date1 = this.cloneAsDate(d1); + const date2 = this.cloneAsDate(d2); return (date1.getTime() < date2.getTime()); }, isAfterDate(d1, d2) { - let date1 = this.cloneAsDate(d1); - let date2 = this.cloneAsDate(d2); + const date1 = this.cloneAsDate(d1); + const date2 = this.cloneAsDate(d2); return (date1.getTime() > date2.getTime()); }, From 1db8cfc2ac99368f461070e21586ae7240086965 Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Tue, 15 Sep 2015 22:44:19 +0100 Subject: [PATCH 2/3] [DatePicker] add proporty needed for Intl --- .../pages/components/date-picker.jsx | 21 ++++ src/date-picker/calendar-toolbar.jsx | 13 +- src/date-picker/calendar.jsx | 10 ++ src/date-picker/date-display.jsx | 8 +- src/date-picker/date-picker-dialog.jsx | 24 +++- src/date-picker/date-picker.jsx | 9 ++ src/utils/date-time.js | 119 ++---------------- 7 files changed, 88 insertions(+), 116 deletions(-) diff --git a/docs/src/app/components/pages/components/date-picker.jsx b/docs/src/app/components/pages/components/date-picker.jsx index ea8ff269571d3a..abf7f4384d233a 100644 --- a/docs/src/app/components/pages/components/date-picker.jsx +++ b/docs/src/app/components/pages/components/date-picker.jsx @@ -29,6 +29,27 @@ export default class DatePickerPage extends React.Component { { name: 'Props', infoArray: [ + { + name: 'DateTimeFormat', + type: 'func', + header: 'default: custom one that only support en-US locale', + desc: 'Constructor for time formatting. Follow this specificaction: ' + + 'ECMAScript Internationalization API 1.0 (ECMA-402).', + }, + { + name: 'locale', + type: 'string', + header: 'default: en-US', + desc: 'Locale used for formating date. If you are not using the default value, ' + + 'you have to provide a DateTimeFormat that support it. You can use Intl.DateTimeFormat' + + ' if it\'s supported by your environment. https://github.com/andyearnshaw/Intl.js is a good polyfill.', + }, + { + name: 'wording', + type: 'object', + header: 'default: {ok: \'OK\', cancel: \'Cancel\' }', + desc: 'Wording used inside the button of the dialog.', + }, { name: 'autoOk', type: 'bool', diff --git a/src/date-picker/calendar-toolbar.jsx b/src/date-picker/calendar-toolbar.jsx index 4c7edaec797342..4c77da739a1b3b 100644 --- a/src/date-picker/calendar-toolbar.jsx +++ b/src/date-picker/calendar-toolbar.jsx @@ -1,5 +1,4 @@ const React = require('react'); -const DateTime = require('../utils/date-time'); const IconButton = require('../icon-button'); const Toolbar = require('../toolbar/toolbar'); const ToolbarGroup = require('../toolbar/toolbar-group'); @@ -44,6 +43,8 @@ const CalendarToolbar = React.createClass({ }, propTypes: { + DateTimeFormat: React.PropTypes.func.isRequired, + locale: React.PropTypes.string.isRequired, displayDate: React.PropTypes.object.isRequired, nextMonth: React.PropTypes.bool, onMonthChange: React.PropTypes.func, @@ -81,10 +82,16 @@ const CalendarToolbar = React.createClass({ }, render() { - const dateTimeFormated = new DateTime.DateTimeFormat('en-US', { + const { + DateTimeFormat, + locale, + displayDate, + } = this.props + + const dateTimeFormated = new DateTimeFormat(locale, { month: 'long', year: 'numeric', - }).format(this.props.displayDate); + }).format(displayDate); const nextButtonIcon = this.state.muiTheme.isRtl ? : ; const prevButtonIcon = this.state.muiTheme.isRtl ? : ; diff --git a/src/date-picker/calendar.jsx b/src/date-picker/calendar.jsx index 7288ae25b1a6e6..f554ac4176a271 100644 --- a/src/date-picker/calendar.jsx +++ b/src/date-picker/calendar.jsx @@ -34,6 +34,8 @@ const Calendar = React.createClass({ }, propTypes: { + DateTimeFormat: React.PropTypes.func.isRequired, + locale: React.PropTypes.string.isRequired, disableYearSelection: React.PropTypes.bool, initialDate: React.PropTypes.object, isActive: React.PropTypes.bool, @@ -133,10 +135,16 @@ const Calendar = React.createClass({ }; const weekTitleDayStyle = this.prepareStyles(styles.weekTitleDay); + const { + DateTimeFormat, + locale, + } = this.props; return ( , @@ -123,7 +141,7 @@ const DatePickerDialog = React.createClass({ actions.push( Date: Wed, 16 Sep 2015 19:43:27 +0100 Subject: [PATCH 3/3] [DatePicker] add example with fr --- .../pages/components/date-picker.jsx | 17 ++++++++++----- .../components/raw-code/date-picker-code.txt | 7 +++++++ src/date-picker/calendar-toolbar.jsx | 4 ++-- src/date-picker/date-display.jsx | 6 +++--- src/utils/date-time.js | 2 -- test/date-picker/calendar-spec.js | 21 +++++++++++++++++++ 6 files changed, 45 insertions(+), 12 deletions(-) diff --git a/docs/src/app/components/pages/components/date-picker.jsx b/docs/src/app/components/pages/components/date-picker.jsx index abf7f4384d233a..bab5121b19ad12 100644 --- a/docs/src/app/components/pages/components/date-picker.jsx +++ b/docs/src/app/components/pages/components/date-picker.jsx @@ -32,7 +32,7 @@ export default class DatePickerPage extends React.Component { { name: 'DateTimeFormat', type: 'func', - header: 'default: custom one that only support en-US locale', + header: 'default: custom function defined inside utils/date-time.js that only supports en-US locale', desc: 'Constructor for time formatting. Follow this specificaction: ' + 'ECMAScript Internationalization API 1.0 (ECMA-402).', }, @@ -40,15 +40,15 @@ export default class DatePickerPage extends React.Component { name: 'locale', type: 'string', header: 'default: en-US', - desc: 'Locale used for formating date. If you are not using the default value, ' + - 'you have to provide a DateTimeFormat that support it. You can use Intl.DateTimeFormat' + + desc: 'Locale used for formatting date. If you are not using the default value, ' + + 'you have to provide a DateTimeFormat that supports it. You can use Intl.DateTimeFormat' + ' if it\'s supported by your environment. https://github.com/andyearnshaw/Intl.js is a good polyfill.', }, { - name: 'wording', + name: 'wordings', type: 'object', header: 'default: {ok: \'OK\', cancel: \'Cancel\' }', - desc: 'Wording used inside the button of the dialog.', + desc: 'Wordings used inside the button of the dialog.', }, { name: 'autoOk', @@ -216,6 +216,13 @@ export default class DatePickerPage extends React.Component { maxDate={this.state.maxDate} showYearSelector={this.state.showYearSelector} /> + +
+ + diff --git a/src/date-picker/calendar-toolbar.jsx b/src/date-picker/calendar-toolbar.jsx index 4c77da739a1b3b..5756a2381c43aa 100644 --- a/src/date-picker/calendar-toolbar.jsx +++ b/src/date-picker/calendar-toolbar.jsx @@ -88,7 +88,7 @@ const CalendarToolbar = React.createClass({ displayDate, } = this.props - const dateTimeFormated = new DateTimeFormat(locale, { + const dateTimeFormatted = new DateTimeFormat(locale, { month: 'long', year: 'numeric', }).format(displayDate); @@ -101,7 +101,7 @@ const CalendarToolbar = React.createClass({ -
{dateTimeFormated}
+
{dateTimeFormatted}
diff --git a/src/date-picker/date-display.jsx b/src/date-picker/date-display.jsx index 6fbb075a13b37d..275450ba977599 100644 --- a/src/date-picker/date-display.jsx +++ b/src/date-picker/date-display.jsx @@ -134,7 +134,7 @@ const DateDisplay = React.createClass({ const year = this.props.selectedDate.getFullYear(); const styles = this.getStyles(); - const dateTimeFormated = new DateTimeFormat(locale, { + const dateTimeFormatted = new DateTimeFormat(locale, { month: 'short', weekday: 'short', day: '2-digit', @@ -152,10 +152,10 @@ const DateDisplay = React.createClass({ style={styles.monthDay.root} direction={this.state.transitionDirection}>
- {dateTimeFormated} + {dateTimeFormatted}
diff --git a/src/utils/date-time.js b/src/utils/date-time.js index e714f65dd04265..6359e6e7518cd1 100644 --- a/src/utils/date-time.js +++ b/src/utils/date-time.js @@ -6,8 +6,6 @@ const monthLongList = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; function DateTimeFormat(locale, options) { - this.options = options; - if (process.env.NODE_ENV !== 'production' && locale !== 'en-US') { console.warn('Wrong usage of DateTimeFormat. The ' + locale +' locale is not supported.'); } diff --git a/test/date-picker/calendar-spec.js b/test/date-picker/calendar-spec.js index caaa03c74bfd1b..d1e5fc372ec48c 100644 --- a/test/date-picker/calendar-spec.js +++ b/test/date-picker/calendar-spec.js @@ -7,6 +7,7 @@ import Calendar from 'date-picker/calendar'; import CalendarToolbar from 'date-picker/calendar-toolbar'; import IconButton from 'icon-button'; import injectTheme from '../fixtures/inject-theme'; +import DateTime from 'utils/date-time'; const TestUtils = React.addons.TestUtils; @@ -25,6 +26,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -42,6 +45,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); let renderedCalendarToolbar = @@ -58,6 +63,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -74,6 +81,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); let prevMonthButton = ReactDOM.findDOMNode( @@ -94,6 +103,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); let nextMonthButton = ReactDOM.findDOMNode( @@ -115,6 +126,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -131,6 +144,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -147,6 +162,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -162,6 +179,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( ); @@ -181,6 +200,8 @@ describe(`Calendar`, () => { let render = TestUtils.renderIntoDocument( );