I'd like to know how I can refactor my JS code for usability. Currently my JavaScript uses some HTML to build out a simple calendar with the following functionality:
a. opens into the current month with today's date highlighted
b. allows you to view next and previous month
My goal was to build out a calendar with the previously mentioned functionality while also having the ability to accept an array of event objects to populate the calendar. Currently, my calendar does NOT accept an array of event objects but that feature will be for another time.
My goal with your help is to refactor the calendar to be less repetitive and more like functional programming.
You can view my Github with the HTML and CSS.
var createMonth = {
createMonthYearLabel: function () {
var me = this;
// create the label that appears on top of the calendar
var currentMonth = me.currentMonth; // the index of the current month ex. 0
var currentMonthName = me.months[ currentMonth ]; // get the name of current month ex. January
var monthYear = me.currentMonthYear = currentMonthName + " " + currentYear; // create ex. January 2016
me.$monthYearSpan.innerHTML = monthYear;
},
createDaysInMonth: function () {
var me = this;
var currentYear = me.currentYear,
currentMonth = me.currentMonth,
currentDateFull = new Date(currentYear, currentMonth);
var totalDaysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate(); // all days in a month
var firstDay = new Date(currentYear, currentMonth, 1);
firstDay = /[A-Za-z]{3}/.exec( firstDay )[0]; // day of the week when the month first begins ex. Tue
var totalNumOfRows = 6; // using 6 rows to show an entire calendar month
var dayCounter = 0;
var daysOfWeek = [ 'Sun', 'Mon', 'Tue', 'Wed','Thu','Fri', 'Sat' ];
var setFirstDayOfMonth; // to be set once to true
for (var i = 0; i < totalNumOfRows; i++) {
var $row = me.$monthTable.insertRow( i ); // creating a row
daysOfWeek.forEach( function( day, index ){ // iterating through the days of the week
var $cell = $row.insertCell( index ); // adding a cell to a row
if ( day === firstDay && !setFirstDayOfMonth ) { // if first day of month not set & day equals first day
// happens once for setting first day of month
dayCounter++;
setFirstDayOfMonth = true;
$cell.innerHTML = dayCounter;
if ( me.currentMonthYear === me.todayMonthYear ) {
if ( dayCounter === me.todayDate ) {
$cell.className = 'today'; // in case the first day of the month is today
}
}
return;
}
if ( dayCounter === 0 || dayCounter === totalDaysInMonth ) {
// creating empty squares with no dates / placeholders
$cell.innerHTML = "";
$cell.className = 'nil';
return; // dayCounter will not be triggered on empty days
}
if ( dayCounter > 0 ) {
dayCounter++;
$cell.innerHTML = dayCounter;
if ( me.currentMonthYear === me.todayMonthYear ) {
if ( dayCounter === me.todayDate ) {
$cell.className = 'today'; // in case the first day of the month is today
}
}
}
});
};
}
};
function createCalendar () {
var me = this;
me.prevBtn = document.getElementsByClassName('left button')[0]; // left arrow on calendar
me.nextBtn = document.getElementsByClassName('right button')[0]; // right arrow on calendar
me.$monthYearSpan = document.getElementsByClassName('month-year')[0]; // month-year title
me.$monthTable = document.getElementsByClassName('current')[0]; // table
me.months = [ 'January', 'Feburary', 'March', 'April', 'May','June','July','August','September','October','November','December' ];
me.todayDateFull = new Date();
me.currentYear = me.todayDateFull.getFullYear();
me.currentMonth = me.todayDateFull.getMonth();
me.todayDate = me.todayDateFull.getDate();
me.currentMonthName = me.months[ me.currentMonth ]; // get the name of current month ex. January
me.todayMonthYear = me.currentMonthName + " " + me.currentYear;
var createMonthYearLabel = createMonth.createMonthYearLabel,
createDaysInMonth = createMonth.createDaysInMonth;
createMonthYearLabel.call( me );
createDaysInMonth.call( me );
prevBtn.onclick = function () { // goes back in time
var me = this;
me.$monthYearSpan.innerHTML = "";
me.$monthTable.innerHTML = "";
if ( me.currentMonth === 0 ) {
// decrease the year
me.currentMonth = 11;
me.currentYear--;
} else {
me.currentMonth--;
}
createMonthYearLabel.call( me );
createDaysInMonth.call( me );
}.bind( me );
nextBtn.onclick = function () { // goes forward in time
var me = this;
me.$monthYearSpan.innerHTML = "";
me.$monthTable.innerHTML = "";
if ( me.currentMonth === 11 ) {
// increase the year
me.currentMonth = 0;
me.currentYear++;
} else {
me.currentMonth++;
}
createMonthYearLabel.call( me );
createDaysInMonth.call( me );
}.bind( me );
}
createCalendar();
body {
background: #e0e0e0e;
}
#cal {
-webkit-box-shadow: 0px 3px 3px rgba(0, 0, 0, 0.25);
margin: 50px auto;
font: 13px/1.5 "Helvetica Neue", Helvatica, Arial, san-serif;
display:table; /* centers the entire calendar */
}
#cal .header {
cursor: default;
background: #cd310d;
background: -webit-gradient(linear, left top, left bottom, from(#b32b0c) to(#cd310d));
height: 55px;
position: relative;
color:#fff;
-webkit-border-top-left-radius: 5px;
-webkit-border-top-right-radius: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
font-weight: bold;
text-shadow: 0px -1px 0 #87260C;
text-transform: uppercase;
}
#cal .header span {
display: inline-block;
line-height: 55px; /* centers item horizontal */
}
#cal .header .hook {
width: 9px;
height: 28px;
position: absolute;
bottom: 60%;
border-radius: 10px;
-webkit-border-radius: 10px;
background: #ececec;
background: -moz-linear-gradient(right top, #fff, #827e7d);
background: -webkit-gradient(linear, right top, right bottom, from(#fff), to(#827e7d));
box-shadow:0px -1px 2px rgba(0, 0, 0, 0.65 );
-moz-box-shadow:0px -1px 2px rgba(0, 0, 0, 0.65 );
-webkit-box-shadow:0px -1px 2px rgba(0, 0, 0, 0.65 );
}
.right.hook {
right: 15%;
}
.left.hook {
left: 15%;
}
#cal .header .button {
width: 24px;
text-align: center;
position: absolute;
}
#cal .header .left.button {
left: 0;
-webkit-border-top-left-radius: 5px;
border-top-left-radius: 5px;
border-right: 1px solid #ae2a0c;
}
#cal .header .right.button {
right: 0;
top: 0;
border-left: 1px solid #ae2a0c;
-webkit-border-top-right-radius: 5px;
-moz-border-radius-topright: 5px;
border-top-right-radius: 5px;
}
#cal .header .button:hover {
background: -moz-linear-gradient(top, #d94215, #bb330f);
background: -webkit-gradient(linear, left top, left bottom, from(#d94215), to(#bb330f));
}
#cal .header .month-year {
letter-spacing: 1px;
width: 100%;
text-align: center;
}
#cal table {
background: #fff;
border-collapse: collapse;
width: 100%;
}
#cal td {
color: #2b2b2b;
width: 80px;
height: 65px;
line-height: 30px;
text-align: center;
border: 1px solid #e6e6e6;
cursor: default;
}
#cal #days td {
height: 26px;
line-height: 26px;
text-transform: uppercase;
font-size: 90%;
color: #9e9e9e;
}
#cal #days td:not(:last-child) {
border-right: 1px solid #fff;
}
#cal #cal-frame td.today {
background: #ededed;
color: black;
border: 0;
}
#cal #cal-frame td:not(.nil):hover {
color: #fff;
text-shadow: #6C1A07 0px -1px;
background: #cd310d;
background: -webkit-linear-gradient(top, #b32b0c, #cd310d);
background: -moz-linear-gradient(linear, left top, left bottom, from(b32b0c), to(#cd310d));
-moz-box-shadow: 0px 0px 0px;
-webkit-box-shadow: 0px 0px 0px;
}
#cal #cal-frame td span {
font-size: 80%;
position: relative;
}
#cal #cal-frame td span:first-child {
bottom: 5px;
}
#cal #cal-frame td span:last-child {
top: 5px;
}
#cal #cal-frame .curr {
float: left;
}
#cal #cal-frame table.temp {
position: absolute;
}
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Calendar Widget</title>
</head>
<body>
<div id="cal">
<div class="header">
<span class="left button" id="prev">⟨</span>
<span class="left hook"></span>
<span class="month-year" id="label"></span>
<span class="right hook"></span>
<span class="right button" id="prev">⟩</span>
</div>
<table id="days">
<tr>
<td>Sunday</td>
<td>Monday</td>
<td>Tuesday</td>
<td>Wednesday</td>
<td>Thursday</td>
<td>Friday</td>
<td>Saturday</td>
</tr>
</table>
<div id="cal-frame">
<table class="current"></table>
</div>
</div>
</body>
</html>
<html>
tag or something? \$\endgroup\$<html>
tag and end with the</html>
tag (or I guess<!DOCTYPE html>
works too, but I normally use<html>
) \$\endgroup\$<html>
. The doctype is not technically part of the HTML document, but tells the browser which rendering mode it should use for the page, e.g. Quirks Mode, Standards Mode, etc. The doctype tag is not an HTML tag. \$\endgroup\$