var CalendarViewType = {
CALENDAR: 1,
MONTH: 2,
YEAR: 3
};
var DAYS_IN_WEEK = 7;
var MONTHS_IN_YEAR = 12;
var MONTHS = [
'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December'
];
var MONTHS_ABBREVIATED = [
'Jan', 'Feb', 'Mar', 'Apr', 'May',
'Jun', 'Jul', 'Aug', 'Sep', 'Oct',
'Nov', 'Dec'
];
var DAYS_OF_WEEK = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
var getFirstOfMonthDate = function(dt) {
var dtStart = new Date(dt.getTime());
dtStart.setDate(1);
return dtStart;
};
var getLastOfMonthDate = function(dt) {
var dtEnd = new Date(dt.getTime());
dtEnd.setDate(1);
dtEnd.setMonth(dtEnd.getMonth() + 1);
dtEnd.setDate(dtEnd.getDate() - 1);
return dtEnd;
};
var getEndOfLastMonthDate = function(dt) {
var dtLast = getFirstOfMonthDate(dt);
dtLast.setDate(dtLast.getDate() - 1);
return dtLast;
}
var generateCalendar = function(dt) {
var dtStart = getFirstOfMonthDate(dt);
var dtEnd = getLastOfMonthDate(dt);
var dtEndLastMonth = getEndOfLastMonthDate(dt);
var calendar = [
_.range(
dtEndLastMonth.getDate() + 1 - dtStart.getDay(),
dtEndLastMonth.getDate() + 1
).concat(
_.range(1, DAYS_IN_WEEK - dtStart.getDay() + 1)
)
];
var dayCount = calendar[0][DAYS_IN_WEEK - 1] + 1;
while (dayCount <= dtEnd.getDate() - DAYS_IN_WEEK) {
var endDay = dayCount + DAYS_IN_WEEK;
calendar.push(_.range(dayCount, endDay));
dayCount = endDay;
}
calendar.push(
_.range(
dayCount, dtEnd.getDate() + 1
).concat(
_.range(1, DAYS_IN_WEEK - dtEnd.getDay())
)
);
return calendar;
};
var CalendarHeader = React.createClass({
render: function() {
return (
{this.props.title}
);
},
handleClickPrev: function() {
if (this.props.onClickPrev) {
this.props.onClickPrev();
}
},
handleClickNext: function() {
if (this.props.onClickNext) {
this.props.onClickNext();
}
},
handleClickHeader: function() {
if (this.props.onClickHeader) {
this.props.onClickHeader();
}
}
});
var YearGrid = React.createClass({
COLS_PER_ROW: 5,
render: function() {
var yearGrid = _.range(
this.props.startYear, this.props.startYear + this.props.range, this.COLS_PER_ROW
).map(function(startYear) {
return {this.renderRow(startYear, startYear + this.COLS_PER_ROW)}
;
}.bind(this));
},
renderRow: function(startYear, endYear) {
return _.range(startYear, endYear).map(function(year) {
return (
{year} |
)
}.bind(this));
},
handleClickYearWrapper: function(year) {
return function() {
this.handleClickYear(year)
}.bind(this);
},
handleClickYear: function(year) {
if (this.props.onClickYear) {
this.props.onClickYear(year);
}
}
});
var YearView = React.createClass({
YEAR_RANGE: 20,
getInitialState: function() {
return {
selectedDate: this.props.selectedDate,
viewingMonth: this.props.viewingMonth,
startYear: this.props.viewingYear - (this.props.viewingYear % this.YEAR_RANGE)
};
},
render: function() {
return (
);
},
handleClickPrev: function() {
this.setState({ viewingYear: this.state.viewingYear - this.YEAR_RANGE });
},
handleClickNext: function() {
this.setState({ viewingYear: this.state.viewingYear + this.YEAR_RANGE });
},
handleClickYear: function(year) {
if (this.props.onClickYear) {
this.props.onClickYear(month, year);
}
}
});
var MonthGrid = React.createClass({
COLS_PER_ROW: 3,
render: function() {
var monthGrid = _.range(0, MONTHS.length, this.COLS_PER_ROW).map(function(startCol) {
return {this.renderRow(startCol, startCol + this.COLS_PER_ROW)}
;
}.bind(this));
return ;
},
renderRow: function(startCol, endCol) {
return _.range(startCol, endCol).map(function(monthIndex) {
return (
{MONTHS_ABBREVIATED[monthIndex]} |
)
}.bind(this));
},
handleClickMonthWrapper: function(monthIndex) {
return function() {
this.handleClickMonth(monthIndex)
}.bind(this);
},
handleClickMonth: function(monthIndex) {
if (this.props.onClickMonth) {
this.props.onClickMonth(monthIndex);
}
}
});
var MonthView = React.createClass({
getInitialState: function() {
return {
selectedDate: this.props.selectedDate,
viewingMonth: this.props.viewingMonth,
viewingYear: this.props.viewingYear
};
},
render: function() {
return (
);
},
handleClickPrev: function() {
this.setState({viewingYear: this.state.viewingYear - 1});
},
handleClickNext: function() {
this.setState({viewingYear: this.state.viewingYear + 1});
},
handleClickHeader: function() {
if (this.props.onClickHeader) {
this.props.onClickHeader(this.state.viewingMonth, this.state.viewingYear);
}
},
handleClickMonth: function(month) {
if (this.props.onClickMonth) {
this.props.onClickMonth(month, this.state.viewingYear);
}
}
});
var DayOfWeekRow = React.createClass({
render: function() {
var daysRow = DAYS_OF_WEEK.map(function(day) {
return {day} | ;
});
return {daysRow}
;
}
});
var CalendarGrid = React.createClass({
render: function() {
var dt = new Date(this.props.year, this.props.month, 1);
var calendar = generateCalendar(dt);
var calendarRows = calendar.map(function(row, index) {
return {this.renderRow(row, index)}
;
}.bind(this));
return ;
},
renderRow: function(row, rowIndex) {
return row.map(function(day) {
return {day} | ;
});
}
});
var CalendarView = React.createClass({
getInitialState: function() {
return {
selectedDate: this.props.selectedDate,
viewingMonth: this.props.viewingMonth,
viewingYear: this.props.viewingYear
};
},
render: function() {
return (
);
},
handleClickPrev: function() {
var updatedMonth = this.state.viewingMonth - 1;
var updatedYear = this.state.viewingYear;
if (updatedMonth === -1) {
updatedMonth = MONTHS_IN_YEAR - 1;
updatedYear -= 1;
}
this.setState({viewingMonth: updatedMonth, viewingYear: updatedYear});
},
handleClickNext: function() {
var updatedMonth = this.state.viewingMonth + 1;
var updatedYear = this.state.viewingYear;
if (updatedMonth === MONTHS_IN_YEAR) {
updatedMonth %= MONTHS_IN_YEAR;
updatedYear += 1;
}
this.setState({viewingMonth: updatedMonth, viewingYear: updatedYear});
},
handleClickHeader: function() {
if (this.props.onClickHeader) {
this.props.onClickHeader(this.state.viewingMonth, this.state.viewingYear);
}
}
});
var CalendarWidget = React.createClass({
getInitialState: function() {
var today = new Date();
return {
selectedDate: today,
viewingMonth: today.getMonth(),
viewingYear: today.getFullYear(),
view: CalendarViewType.CALENDAR
};
},
render: function() {
var calendarView = null;
if (this.state.view === CalendarViewType.CALENDAR) {
calendarView = (
);
} else if (this.state.view === CalendarViewType.MONTH) {
calendarView = (
);
} else if (this.state.view === CalendarViewType.YEAR) {
calendarView = (
);
}
return {calendarView}
},
updateDate: function(day, month, year) {
},
showCalendarView: function(month, year) {
this.setState({view: CalendarViewType.CALENDAR, viewingMonth: month, viewingYear: year});
},
showMonthView: function(month, year) {
this.setState({view: CalendarViewType.MONTH, viewingMonth: month, viewingYear: year});
},
showYearView: function(month, year) {
this.setState({view: CalendarViewType.YEAR, viewingMonth: month, viewingYear: year});
}
});
React.render(
,
document.getElementById('calendar')
);