/* ========================================================================
* DNCalendar - v1.0
* https://github.com/black-lotus/dnCalendar
* ========================================================================
* Copyright 2015 WPIC, Romdoni Agung Purbayanto
*
* ========================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================================
*/
(function ( $ ) {
$.fn.dnCalendar = function( options ) {
var self = $(this);
var settings = {};
// current date
var currDate = new Date();
// custom default date
var defDate = null;
// today date
var todayDate = new Date();
// week names
var weekNames = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
// used to check week names has already restructured
var weekNamesHasAlreadySorted = false;
/**
* move prototype of array
*/
Array.prototype.move = function (old_index, new_index) {
while (old_index < 0) {
old_index += this.length;
}
while (new_index < 0) {
new_index += this.length;
}
if (new_index >= this.length) {
var k = new_index - this.length;
while ((k--) + 1) {
this.push(undefined);
}
}
this.splice(new_index, 0, this.splice(old_index, 1)[0]);
return this; // for testing purposes
};
/**
* get selected day index of week
*
* @return int
*/
var getDayIndexOfWeek = function() {
for (var i = 0; i < weekNames.length; i++) {
if (weekNames[i] == settings.startWeek.toLowerCase()) {
return i;
}
}
return 0;
}
/**
* get total weeks in month
*
* @param int
* @param int, range 1..12
* @return int
*/
var weekCount = function(year, month_number) {
var firstOfMonth = new Date(year, month_number-1, 1);
var lastOfMonth = new Date(year, month_number, 0);
var used = firstOfMonth.getDay() + lastOfMonth.getDate();
return Math.ceil( used / 7);
}
/**
* get total weeks in month
*
* @param int
* @param int, range 1..12
* @return array[int][int]
*/
var getWeekOfMonth = function(month, year) {
var weeks = [],
firstDate = new Date(year, month, 1),
lastDate = new Date(year, month+1, 0),
numDays = lastDate.getDate(),
startDayWeek = getDayIndexOfWeek();
var lastDateOfPrevMonth = new Date(year, month, 0); // get last day of previous month
var prevDate = lastDateOfPrevMonth.getDate() - firstDate.getDay();
var firstDateOfNextMonth = new Date(year, month + 1, 1); // get fist day of next month
var nextDate = firstDateOfNextMonth.getDate();
var date = 1;
while (date <= numDays) {
var i = 0;
var tempWeek = [];
while (i < 7) {
// first column
if (weeks.length == 0) {
if (i >= firstDate.getDay()) {
tempWeek.push(date);
date++;
} else {
prevDate++;
tempWeek.push(prevDate);
}
} else {
if (date <= numDays) {
tempWeek.push(date);
date++;
} else {
tempWeek.push(nextDate++);
}
}
i++;
}
weeks.push(tempWeek);
}
// console.log("numDays", numDays);
return weeks;
}
/**
* sorting week of month by selected day
*
* @param array[int][int]
* @return array[int][int]
*/
var sortingBySelectedDay = function(weeks, month, year) {
var startDayWeek = getDayIndexOfWeek();
var lastDateOfPrevMonth = new Date(year, month, 0); // get last day of previous month
var prevDate = lastDateOfPrevMonth.getDate();
var lastDate = new Date(year, month+1, 0).getDate();
function isset(arr, val) {
var found = false;
for (var m = 0; m < arr.length; m++) {
if (arr[m] == val) {
found = true;
break;
}
}
return found;
}
// sorting when startDatWeek is greater than 0 (0 is sunday)
if (startDayWeek > 0) {
var newArr = [];
var nWeeks = weeks.length;
for (var i = 0; i < nWeeks; i++) {
var tempArr = [];
// first row
if (i == 0 && newArr.length == 0) {
// check first day is sunday
if (weeks[i][0] == 1) {
// calculate previous date
var startPrevDate = prevDate - (7 - startDayWeek - 1);
while (startPrevDate <= prevDate) {
tempArr.push(startPrevDate);
startPrevDate++;
}
// get next date
for (var j = 0; j < weeks[i].length; j++) {
if (tempArr.length < weeks[i].length) {
var val = weeks[i][j];
var isPush = isset(tempArr, val);
if (!isPush) {
tempArr.push(val);
}
}
}
} else {
for (var j = 0; j < weeks[i].length; j++) {
if (tempArr.length < weeks[i].length) {
if (typeof weeks[i][j + startDayWeek] !== 'undefined') {
tempArr.push(weeks[i][j + startDayWeek]);
} else {
if (typeof weeks[i + 1] !== 'undefined') {
for (var k = 0; k < weeks[i + 1].length; k++) {
if (tempArr.length < weeks[i].length) {
var val = weeks[i + 1][k];
var isPush = isset(tempArr, val);
if (!isPush) {
tempArr.push(val);
}
}
}
}
}
}
}
}
} else {
for (var newI = i; newI >= 0; newI--) {
var found = false;
for (var j = 0; j < weeks[newI].length; j++) {
var newArrRow = newArr.length - 1;
var newArrCol = newArr[newArrRow].length - 1;
if (newArr[newArrRow][newArrCol] == weeks[newI][j]) {
found = true;
}
if (found == true) {
if (typeof weeks[newI][j + startDayWeek] !== 'undefined') {
if (tempArr.length < weeks[newI].length) {
var val = weeks[newI][j + startDayWeek];
var isPush = isset(tempArr, val);
if (!isPush) {
/**
* Temporary bug fixes
* last date of next month wrong
*/
if (typeof tempArr[tempArr.length - 1] !== 'undefined') {
var lastIndexTempArr = tempArr[tempArr.length - 1];
if (lastIndexTempArr + 1 != val && lastIndexTempArr + 1 < lastDate) {
tempArr.push(lastIndexTempArr + 1);
} else {
tempArr.push(weeks[newI][j + startDayWeek]);
// console.log("first col ["+ newI +"]["+ (j + startDayWeek) +"] => " + val);
}
} else {
tempArr.push(weeks[newI][j + startDayWeek]);
// console.log("first col ["+ newI +"]["+ (j + startDayWeek) +"] => " + val);
}
// tempArr.push(weeks[newI][j + startDayWeek]);
// console.log("first col ["+ newI +"]["+ (j + startDayWeek) +"] => " + val);
}
}
} else {
if (typeof weeks[newI + 1] !== 'undefined') {
for (var k = 0; k < weeks[newI + 1].length; k++) {
if (tempArr.length < weeks[newI].length) {
var val = weeks[newI + 1][k];
var isPush = isset(tempArr, val);
if (!isPush) {
tempArr.push(val);
// console.log("next col ["+ (newI + 1) +"]["+ k +"] => " + val);
}
}
}
}
}
}
}
}
}
newArr.push(tempArr);
}
// check if last date is not found
var found = false;
for (var i = 1; i < newArr.length; i++) {
for (var j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] == lastDate) {
found = true;
break;
}
}
if (found == true) {
break;
}
}
var newArrRow = newArr.length - 1;
if (found == false) {
var newArrCol = newArr[newArrRow].length - 1;
var lastDateInNewArr = newArr[newArrRow][newArrCol];
var tempArr = [];
while (lastDateInNewArr < lastDate) {
lastDateInNewArr++;
tempArr.push(lastDateInNewArr);
}
if (tempArr.length < 7) {
var limit = 7 - tempArr.length;
var date = 1;
while (date <= limit) {
tempArr.push(date);
date++;
}
}
newArr.push(tempArr);
} else {
var newArrCol = newArr[newArrRow].length - 1;
var lastDateInNewArr = newArr[newArrRow][newArrCol];
var colLeft = 7 - (newArrCol + 1);
if (lastDateInNewArr > 7) {
lastDateInNewArr = 1;
} else {
lastDateInNewArr = lastDateInNewArr + 1;
}
while (colLeft > 0) {
newArr[newArrRow].push(lastDateInNewArr);
lastDateInNewArr++;
colLeft--;
}
// console.log("newArrCol", newArrCol);
// console.log("colLeft", colLeft);
}
return newArr;
}
return weeks;
}
/*
* draw calendar and give call back when date selected
*/
var draw = function() {
var m = currDate.getMonth(); // get month
var d = currDate.getDate(); // get date of month
var y = currDate.getFullYear(); // get full year
var dates = getWeekOfMonth(m, y);
for (var i = 0; i < dates.length; i++) {
var string = "";
for (var j = 0; j < dates[i].length; j++) {
string += dates[i][j] + " ";
}
// console.log(i + " => " + string);
}
// console.log("--------------------------------");
dates = sortingBySelectedDay(dates, m, y);
for (var i = 0; i < dates.length; i++) {
var string = "";
for (var j = 0; j < dates[i].length; j++) {
string += dates[i][j] + " ";
}
// console.log(i + " => " + string);
}
// get month name
var headerMonth = settings.monthNames[m];
if (settings.monthUseShortName == true) {
headerMonth = settings.monthNamesShort[m];
}
// create header label
var headerGroup = $("
");
headerGroup.append(""+ headerMonth + "
");
// determine prev link as false
var prevInactive = false;
// set prev link as true when minDate is exist and current date is less than or equal minDate
var minDate = null;
if (typeof settings.minDate !== 'undefined') {
var minDateArr = settings.minDate.split('-');
minDate = new Date(minDateArr[0], minDateArr[1] - 1, minDateArr[2]);
if (minDate.getFullYear() >= y) {
if (minDate.getMonth() >= m) {
prevInactive = true;
}
}
}
// determine prev link as false
var nextInactive = false;
// set next link as true when maxDate is exist and current date is greater than or equal maxDate
var maxDate = null;
if (typeof settings.maxDate !== 'undefined') {
var maxDateArr = settings.maxDate.split('-');
maxDate = new Date(maxDateArr[0], maxDateArr[1] - 1, maxDateArr[2]);
if (maxDate.getFullYear() <= y) {
if (maxDate.getMonth() <= m) {
nextInactive = true;
}
}
}
// create link group
var calendarLinksGroup = $("");
var prevLinkGroup = $("
");
var nextLinkGroup = $("
");
// disable prev link
if (prevInactive) {
prevLinkGroup.addClass("dncalendar-inactive");
prevLinkGroup.removeAttr("id");
}
// disable next link
if (nextInactive) {
nextLinkGroup.addClass("dncalendar-inactive");
nextLinkGroup.removeAttr("id");
}
// add link group into header
calendarLinksGroup.append(prevLinkGroup);
calendarLinksGroup.append(nextLinkGroup);
headerGroup.append(calendarLinksGroup);
var bodyGroup = $("");
var tableGroup = $("");
var weekName = settings.dayNames;
if (settings.dayUseShortName == true) {
weekName = settings.dayNamesShort;
}
// do not re-order day of week for second times
var dayIndex = getDayIndexOfWeek();
if (weekNamesHasAlreadySorted == false) {
// re-order week name based on startWeek settings
var oldIndex = null;
var newIndex = 0;
for (var i = 0; i < weekName.length; i++) {
if (i >= dayIndex) {
if (oldIndex == null) {
oldIndex = i;
}
weekName.move(oldIndex, newIndex);
oldIndex++;
newIndex++;
}
}
weekNamesHasAlreadySorted = true
}
// console.log("week after", weekName);
var sundayIndex = (dayIndex == 0) ? 0 : 7 - dayIndex;
var saturdayIndex = 6 - dayIndex;
var tableHeadGroup = $("");
var tableHeadRowGroup = $("
");
var weekNameLength = weekName.length;
for (var i = 0; i < weekNameLength; i++) {
tableHeadRowGroup.append(""+ weekName[i] +" | ");
}
tableHeadGroup.append(tableHeadRowGroup);
var tableBodyGroup = $("");
var totalWeeks = weekCount(y, m + 1);
// console.log("totalWeeks", totalWeeks);
var totalDaysInWeeks = 7;
var startDate = 1;
var firstDayOfMonth = new Date(y, m, 1); // get first day of month
var lastDayOfMonth = new Date(y, m + 1, 0); // get last day of month
var lastDateOfPrevMonth = new Date(y, m, 0); // get last day of previous month
var prevDate = lastDateOfPrevMonth.getDate() - firstDayOfMonth.getDay() + 1;
var firstDateOfNextMonth = new Date(y, m + 1, 1); // get fist day of next month
var nextDate = firstDateOfNextMonth.getDate();
var limitMinDate = 0;
if (minDate != null) {
limitMinDate = minDate.getDate();
}
var limitMaxDate = 0;
if (maxDate != null) {
limitMaxDate = maxDate.getDate();
}
var todayTitle = 'today';
var defaultDateTitle = 'default date';
if (typeof settings.dataTitles !== 'undefined') {
if (typeof settings.dataTitles.defaultDate !== 'undefined') {
defaultDateTitle = settings.dataTitles.defaultDate;
}
if (typeof settings.dataTitles.today !== 'undefined') {
todayTitle = settings.dataTitles.today;
}
}
var sundayIndex = (dayIndex == 0) ? 0 : 7 - dayIndex;
var saturdayIndex = (dayIndex == 0) ? 7 - 1 : 7 - (dayIndex + 1);
// console.log("sundayIndex", sundayIndex);
// console.log("saturdayIndex", saturdayIndex);
var nDates = dates.length;
for (var i = 0; i < nDates; i++) {
var tableBodyRowGroup = $("
");
var nDate = dates[i].length;
for (var j = 0; j < nDate; j++) {
var date = dates[i][j];
var month = m + 1;
var year = y;
var colDateClass = "";
var colDateDataAttr = "";
var showCalendarClick = true;
// check first row
if (i == 0) {
if (dates[i][j] > 7) {
showCalendarClick = false;
month = month - 1;
if (month <= 0) {
month = 12;
year = year - 1;
}
}
}
// check last row
if (i == nDates - 1) {
if (dates[i][j] <= 7) {
showCalendarClick = false;
month = month + 1;
if (month >= 12) {
month = 1;
year = year + 1;
}
}
}
// check date is today
if (todayDate.getFullYear() == year && (todayDate.getMonth() + 1) == month && todayDate.getDate() == date) {
colDateClass = ' today-date ';
colDateDataAttr = "data-title='"+ todayTitle +"'";
}
// check date is default date
if (defDate != null && defDate.getFullYear() == year && (defDate.getMonth() + 1) == month && defDate.getDate() == date) {
colDateClass = ' default-date ';
colDateDataAttr = "data-title='"+ defaultDateTitle +"'";
}
/*
if (j == sundayIndex || j == saturdayIndex) {
colDateClass += ' holiday ';
}
*/
// check date is noted
if (typeof settings.notes !== 'undefined') {
if (dateIsNotes(new Date(year, month - 1, date))) {
colDateClass += " note ";
}
}
var colDate = ""+ date +" | ";
if (minDate != null) {
var myCurrentDate = new Date(year, month - 1, date);
if (minDate > myCurrentDate) {
colDate = ""+ date +" | ";
}
}
if (maxDate != null) {
var myCurrentDate = new Date(year, month - 1, date);
if (maxDate < myCurrentDate) {
colDate = ""+ date +" | ";
}
}
tableBodyRowGroup.append(colDate);
}
tableBodyGroup.append(tableBodyRowGroup);
}
var notesGroup = "";
if (settings.showNotes) {
var notes = getNotesThisMonth();
var notesLength = notes.length;
if (notesLength > 0) {
notesGroup = $("");
for (var i = 0; i < notesLength; i++) {
var date = notes[i].date;
var noteList = notes[i].notes;
var noteListLength = noteList.length;
var list = "";
list += "";
list += ""+ date +" ";
if (noteListLength > 0) {
list += " : ";
for (var j = 0; j < noteListLength; j++) {
list += noteList[j];
if (noteListLength <= j) {
list += ", ";
}
}
}
list += "";
notesGroup.append(list);
}
}
}
tableGroup.append(tableHeadGroup);
tableGroup.append(tableBodyGroup);
bodyGroup.append(tableGroup);
self.html("");
self.append(headerGroup);
self.append(bodyGroup);
self.append(notesGroup);
}
var dateIsNotes = function(date) {
var notesLength = settings.notes.length;
for (var i = 0; i < notesLength; i++) {
var dateNote = settings.notes[i].date.split('-');
var nDate = new Date(dateNote[0], dateNote[1] - 1, dateNote[2]);
if ( nDate.getFullYear() == date.getFullYear() && nDate.getMonth() == date.getMonth() && nDate.getDate() == date.getDate() ) {
return true;
}
}
return false;
}
var getNotesThisMonth = function() {
var result = [];
var notesLength = settings.notes.length;
for (var i = 0; i < notesLength; i++) {
var dateNote = settings.notes[i].date.split('-');
var nDate = new Date(dateNote[0], dateNote[1] - 1, dateNote[2]);
if (nDate.getFullYear() == currDate.getFullYear() && nDate.getMonth() == currDate.getMonth()) {
var temp = {};
temp['date'] = nDate.getDate();
temp['notes'] = settings.notes[i].note;
result.push(temp);
}
}
return result;
}
var nextMonth = function() {
var firstDateOfNextMonth = new Date(currDate.getFullYear(), currDate.getMonth() + 1, 1); // get fist day of next month
var date = firstDateOfNextMonth.getDate();
var month = firstDateOfNextMonth.getMonth();
var year = firstDateOfNextMonth.getFullYear();
currDate = new Date(year, month, date);
draw();
}
var prevMonth = function() {
var firstDateOfPrevMonth = new Date(currDate.getFullYear(), currDate.getMonth() - 1, 1); // get fist day of previous month
var date = firstDateOfPrevMonth.getDate();
var month = firstDateOfPrevMonth.getMonth();
var year = firstDateOfPrevMonth.getFullYear();
currDate = new Date(year, month, date);
draw();
}
var triggerAction = function() {
$('body').on('click', '.calendarClick', function(){
var selectedDate = $(this).data('date');
var selectedMonth = $(this).data('month');
var selectedYear = $(this).data('year');
settings.dayClick.call(this, new Date(selectedYear, selectedMonth - 1, selectedDate), self);
});
$('body').on('click', '#dncalendar-prev-month', function() {
prevMonth();
});
$('body').on('click', '#dncalendar-next-month', function() {
nextMonth();
});
}
return {
build: function() {
settings = $.extend( {}, $.fn.dnCalendar.defaults, options );
// replace with defaultDate when exist
if (typeof settings.defaultDate !== 'undefined') {
var defaultDateArr = settings.defaultDate.split('-');
currDate = new Date(defaultDateArr[0], defaultDateArr[1] - 1, defaultDateArr[2]);
defDate = currDate;
}
draw();
triggerAction();
},
update: function(options) {
settings = $.extend(settings, options);
// replace with defaultDate when exist
if (typeof settings.defaultDate !== 'undefined') {
var defaultDateArr = settings.defaultDate.split('-');
currDate = new Date(defaultDateArr[0], defaultDateArr[1] - 1, defaultDateArr[2]);
defDate = currDate;
}
draw();
}
}
}
// plugin defaults
$.fn.dnCalendar.defaults = {
monthNames: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ],
monthNamesShort: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec' ],
dayNames: [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
dayNamesShort: [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ],
dayUseShortName: false,
monthUseShortName: false,
showNotes: false,
startWeek: 'sunday',
dayClick: function(date, view) {}
};
} ( jQuery ));