Skip to content

Instantly share code, notes, and snippets.

@L2jLiga
Created December 1, 2017 12:31
Show Gist options
  • Save L2jLiga/7c08757044262c41facab52f3588b9c5 to your computer and use it in GitHub Desktop.
Save L2jLiga/7c08757044262c41facab52f3588b9c5 to your computer and use it in GitHub Desktop.
Simple calendar
.calendar__wrapper {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: calc(45px * 7);
margin: 0 25px 25px;
}
.calendar__item {
color: rgba(0,0,0,.5);
display: inline-flex;
flex-basis: calc(100% / 7);
height: 45px;
justify-content: center;
align-items: center;
}
.calendar__header {
width: calc(45px * 7);
margin: 25px 25px 10px;
border-bottom: 1px solid;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.calendar__button {
flex-basis: 15%;
text-align: left;
cursor: pointer;
background-color: rgba(126,126,126,.1);
}
.calendar__button-next {
text-align: right;
}
.calendar__month-label {
flex-basis: 40%;
text-align: center;
}
.calendar__item--actual {
color: black;
cursor: pointer;
}
.calendar__item--actual:not(.calendar__item--selected):hover {
background-color: rgba(15,72,23,.1);
}
.calendar__item--selected {
background-color: rgba(15,72,23,.3);
}
<!DOCTYPE html>
<meta charset="utf-8" />
<link rel="stylesheet" href="calendar.css" />
<div class="calendar">
<div class="calendar__header">
<div class="calendar__button calendar__button--prev"></div>
<div class="calendar__month-label"></div>
<div class="calendar__button calendar__button--next"></div>
</div>
<div class="calendar__wrapper"></div>
</div>
<script src="calendar.js"></script>
<script>
const whenSelect = (year, month, day) => {
alert(`Выбрано: ${day}.${month + 1}.${year}`);
}
calendar(whenSelect);
</script>
const calendar = (() => {
'use strict';
const months = ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'];
let initialDate = new Date();
initialDate.setMonth(initialDate.getMonth() - 1);
initialDate.setHours(0, 0, 0, 0);
let prevMonthButton = document.querySelector('.calendar__button--prev');
let monthLabel = document.querySelector('.calendar__month-label');
let nextMonthButton = document.querySelector('.calendar__button--next');
prevMonthButton.onclick = switchMonth.bind(this, true);
nextMonthButton.onclick = switchMonth.bind(this, false);
switchMonth();
/**
* Switch month and generate new calendar grid
* @param {Boolean} isPrevButton - Is pressed previous month button
* @return {void}
*/
function switchMonth(isPrevButton = false) {
let helperDate = new Date(initialDate);
if(isPrevButton) {
helperDate.setMonth(helperDate.getMonth() - 1);
nextMonthButton.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() - 2);
prevMonthButton.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() + 1);
monthLabel.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() + 1);
} else {
helperDate.setMonth(helperDate.getMonth() - 1);
prevMonthButton.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() + 2);
nextMonthButton.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() - 1);
monthLabel.innerHTML = months[helperDate.getMonth()];
helperDate.setMonth(helperDate.getMonth() + 1);
}
generateGrid(helperDate.getMonth(), helperDate.getFullYear());
}
function generateGrid(month, year) {
initialDate = new Date(year, month, 1);
let helperDate = new Date(initialDate.getFullYear(), initialDate.getMonth() + 1, 0);
let calendar = document.querySelector('.calendar__wrapper');
calendar.innerHTML = '';
buildOffset(generateOffsetBefore(initialDate.getDay()), calendar, true);
buildActualDays(generateActualDays(), calendar);
buildOffset(generateOffsetAfter(helperDate.getDay()), calendar, false);
/**
* Helper method for create calendar item
* @return {Node} Created element
*/
function createCalendarElement() {
let element = document.createElement('div');
element.classList.add('calendar__item');
return element;
}
/**
* Build offsets elements and append it into node
* @param {Array} offsetArray - Array with offset days
* @param {Node} node - Element which should contain this days
* @param {Boolean} isBeforeOffset - Is this offset before first day or not
* @return {void}
*/
function buildOffset(offsetArray, node, isBeforeOffset = false) {
let helperDate = new Date(initialDate);
let offsetDaysCount = offsetArray.length;
if(isBeforeOffset) {
let helperDate = new Date(initialDate.getFullYear(), initialDate.getMonth(), 0);
helperDate.setDate(helperDate.getDate() - offsetDaysCount);
for(; offsetDaysCount > 0; offsetDaysCount--) {
let offsetElement = createCalendarElement();
helperDate.setDate(helperDate.getDate() + 1);
offsetElement.innerHTML = helperDate.getDate();
node.append(offsetElement);
}
return;
}
for(; offsetDaysCount > 0; offsetDaysCount--) {
let offsetElement = createCalendarElement();
offsetElement.innerHTML = helperDate.getDate();
helperDate.setDate(helperDate.getDate() + 1);
node.append(offsetElement);
}
}
/**
* Build actual days
* @return {void}
*/
function buildActualDays(actualDays, node) {
actualDays.forEach(actualDay => {
let actualDayElement = createCalendarElement();
actualDayElement.innerHTML = actualDay.index;
actualDayElement.classList.add('calendar__item--actual');
actualDayElement.onclick = event => {
let lastSelected = findSelectedDay(actualDays);
if(lastSelected) {
lastSelected.select = false;
let lastSelectedDay = document.querySelectorAll('.calendar .calendar__item.calendar__item--actual')[lastSelected.index - 1];
lastSelectedDay.classList.remove('calendar__item--selected');
}
event.target.classList.add('calendar__item--selected');
actualDay.select = true;
// TODO: This you can parse your function
whenSelect(year, month, actualDay.index);
}
node.append(actualDayElement);
});
}
/**
* Helper method to find last selected day
* @param {Object[]} actualDays - Array which contains actual days
* @return {Object} Last selected day
*/
function findSelectedDay(actualDays) {
return actualDays.filter(day => day.select)[0];
}
/**
* Create array of objects with actual days, which included into month
* @return {Object[]} Array of included days into month
*/
function generateActualDays() {
let helperDate = new Date(year, month, 0);
let daysInMonth = helperDate.getDate();
let actualDays = new Array(daysInMonth);
for(; daysInMonth > 0; daysInMonth--) {
actualDays[daysInMonth] = {
index: daysInMonth,
select: false
}
}
return actualDays;
}
/**
* Create array with days which included in first week,
* but doesn't included in current month
* @param {Number} dayOfTheWeek - Day of the week from which month starts
* @return {Array} Days before first day
*/
function generateOffsetBefore(dayOfTheWeek) {
let daysBefore = dayOfTheWeek - 1;
if(daysBefore === -1) daysBefore = 5;
let offsetArray = new Array(daysBefore);
for(; daysBefore >= 0; daysBefore--) {
offsetArray[daysBefore] = daysBefore;
}
return offsetArray;
}
/**
* Create array with days which included in last week,
* but doesn't included in current month
* @param {Number} dayOfTheWeek - Day of the week from which month end
* @return {Array} Days after last day
*/
function generateOffsetAfter(dayOfTheWeek) {
let daysAfter = 7 - dayOfTheWeek;
let offsetArray = new Array(daysAfter);
for(; daysAfter >= 0; daysAfter--) {
offsetArray[daysAfter] = daysAfter;
}
return offsetArray;
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment