Skip to content

Instantly share code, notes, and snippets.

@jdavidbakr
Created May 22, 2015 16:22
Show Gist options
  • Save jdavidbakr/b3ca1c63d596758b8af3 to your computer and use it in GitHub Desktop.
Save jdavidbakr/b3ca1c63d596758b8af3 to your computer and use it in GitHub Desktop.
JavaScript: Calendar
/**
* This javascript draws a calendar object and updates the passed input elements with the value when a date is clicked.
*/
var monthNames = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
];
var dayNames = [
'Sun',
'Mon',
'Tue',
'Wed',
'Thu',
'Fri',
'Sat'
];
var datepicker = {
visible: false,
selected_date: null,
visible_input: null,
hidden_input: null,
calendar: null,
clear_event: null,
current_view: null,
current_view_date: null,
header: null,
activate: function(event, input) {
if(this.visible) {
this.cancel();
}
event.stopImmediatePropagation();
this.visible = true;
this.visible_input = input;
this.hidden_input = document.getElementById(input.getAttribute('rel'));
if(this.visible_input.value) {
this.selected_date = new Date(this.visible_input.value);
} else {
this.selected_date = new Date();
}
// Create the calendar object
this.calendar = document.createElement('div');
this.calendar.setAttribute('class','datepicker');
this.hidden_input.parentNode.insertBefore(this.calendar, this.hidden_input);
if(!this.clear_event) {
this.clear_event = this.cancel.bind(this);
}
// Initialize our view
this.current_view = 'days';
this.current_view_date = new Date(this.selected_date);
// Draw the calendar
this.draw();
// Add a click event to the document that closes our picker
document.addEventListener('click', this.clear_event);
// alert(this.selected_date);
return true;
},
draw: function() {
// Clear any existing view
this.calendar.innerHTML = '';
// Apply the header
this.header = document.createElement('div');
this.header.setAttribute('class','header');
this.calendar.appendChild(this.header);
var headerText;
switch(this.current_view) {
case 'days':
headerText = this.days_header();
this.draw_days();
break;
case 'months':
headerText = this.months_header();
this.draw_months();
break;
case 'years':
headerText = this.years_header();
this.draw_years();
break;
}
var title = document.createElement('div');
this.header.appendChild(title);
title.setAttribute('class','title');
var title_text = document.createElement('div');
title_text.setAttribute('class','titleText');
title_text.innerHTML = headerText;
title.appendChild(title_text);
title_text.addEventListener('click',this.change_view.bind(this));
// Navigation
var previous = document.createElement('div');
this.header.appendChild(previous);
previous.setAttribute('class','previous');
previous.addEventListener('click', this.previous.bind(this));
var next = document.createElement('div');
this.header.appendChild(next);
next.setAttribute('class','next');
next.addEventListener('click',this.next.bind(this));
},
days_header: function() {
return monthNames[this.current_view_date.getMonth()] + ' ' + (this.current_view_date.getFullYear());
},
months_header: function() {
return this.current_view_date.getFullYear();
},
years_header: function() {
var first_year = Math.floor(this.current_view_date.getFullYear()/20) * 20;
var last_year = first_year + 19;
return (first_year)+"-"+(last_year);
},
draw_days: function() {
var table = document.createElement('table');
table.setAttribute('class','days');
this.calendar.appendChild(table);
var titles = document.createElement('tr');
titles.setAttribute('class','titles');
table.appendChild(titles);
for (var i = 0; i < dayNames.length; i++) {
var th = document.createElement('td');
th.innerHTML = dayNames[i];
th.setAttribute('class','day');
titles.appendChild(th);
}
var current_date = new Date(this.current_view_date);
current_date.setDate(1);
var first_dow = current_date.getDay();
current_date.setDate(1 - first_dow);
var week = 0;
var tr;
while(week <= 6) {
var dow = current_date.getDay();
if(dow === 0) {
tr = document.createElement('tr');
tr.setAttribute('class','week');
table.appendChild(tr);
week++;
}
if(week <= 6) {
var td = document.createElement('td');
var td_class = 'day';
if(current_date.getMonth() != this.current_view_date.getMonth()) {
td_class += ' otherMonth';
}
if(current_date.getFullYear() == this.selected_date.getFullYear() &&
current_date.getDate() == this.selected_date.getDate() &&
current_date.getMonth() == this.selected_date.getMonth()) {
td_class += ' selected';
}
td.setAttribute('class',td_class);
td.setAttribute('date', current_date);
td.innerHTML = current_date.getDate();
tr.appendChild(td);
current_date.setDate(current_date.getDate() + 1);
td.addEventListener('click',this.select_date.bind(this));
}
}
},
select_date: function(e) {
e.stopImmediatePropagation();
var target = e.target;
var date = new Date(target.getAttribute('date'));
var actual_date = date.getFullYear()+'-';
if(date.getMonth() < 9) {
actual_date += '0';
}
actual_date += (date.getMonth()+1)+'-';
if(date.getDate() < 10) {
actual_date += '0';
}
actual_date += date.getDate();
var pretty_date = (date.getMonth() + 1) + '/' + date.getDate() + '/' + date.getFullYear();
this.hidden_input.value = actual_date;
this.visible_input.value = pretty_date;
this.cancel();
},
draw_months: function() {
var table = document.createElement('table');
table.setAttribute('class','months');
this.calendar.appendChild(table);
var tr;
for(var i = 0; i < monthNames.length; ++i) {
if(!i % 3) {
tr = document.createElement('tr');
table.appendChild(tr);
}
var td = document.createElement('td');
td.innerHTML = monthNames[i];
var td_class = 'month';
if(this.current_view_date.getFullYear() == this.selected_date.getFullYear() &&
this.current_view_date.getMonth() == i) {
td_class += ' selected';
}
td.setAttribute('class',td_class);
td.setAttribute('month',i);
td.addEventListener('click',this.select_month.bind(this));
tr.appendChild(td);
}
},
select_month: function(e) {
e.stopImmediatePropagation();
var target = e.target;
var month = target.getAttribute('month');
this.current_view_date.setDate(1);
this.current_view_date.setMonth(month);
this.current_view = 'days';
this.draw();
},
draw_years: function() {
var first_year = Math.floor(this.current_view_date.getFullYear()/20) * 20;
var table = document.createElement('table');
table.setAttribute('class','years');
this.calendar.appendChild(table);
var tr;
for(var i = 0; i < 20; ++i) {
if(!i % 4) {
tr = document.createElement('tr');
table.appendChild(tr);
}
var td = document.createElement('td');
td.innerHTML = first_year + i;
var td_class ='year';
if(first_year + i == this.selected_date.getFullYear()) {
td_class += ' selected';
}
td.setAttribute('class',td_class);
td.setAttribute('year',first_year + i);
td.addEventListener('click',this.select_year.bind(this));
tr.appendChild(td);
}
},
select_year: function(e) {
e.stopImmediatePropagation();
var target = e.target;
var year = target.getAttribute('year');
this.current_view_date.setYear(year);
this.current_view = 'months';
this.draw();
},
change_view: function(event) {
event.stopImmediatePropagation();
switch(this.current_view) {
case 'days':
this.current_view = 'months';
break;
case 'months':
this.current_view = 'years';
break;
}
this.draw();
},
cancel: function() {
// Do what we need to do to clear the visible calendar
var parent = this.calendar.parentNode;
parent.removeChild(this.calendar);
this.visible = false;
document.removeEventListener('click', this.clear_event);
},
previous: function(event) {
event.stopImmediatePropagation();
this.navigate(-1);
this.draw();
},
next: function(event) {
event.stopImmediatePropagation();
this.navigate(1);
this.draw();
},
navigate: function(amount) {
switch(this.current_view) {
case 'days':
this.current_view_date.setMonth(this.current_view_date.getMonth() + amount);
break;
case 'months':
this.current_view_date.setFullYear(this.current_view_date.getFullYear() + amount);
break;
case 'years':
this.current_view_date.setFullYear(this.current_view_date.getFullYear() + (amount * 20));
break;
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment