Сделал виджет с переопределением 4 главных функций календаря в js
This commit is contained in:
383
backend/widgets/Calendar/assets/css/style.css
Normal file
383
backend/widgets/Calendar/assets/css/style.css
Normal file
@ -0,0 +1,383 @@
|
||||
.calendar-contain {
|
||||
position: relative;
|
||||
left: 0;
|
||||
right: 0;
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
max-width: 1920px;
|
||||
min-width: 450px;
|
||||
margin: 1rem auto;
|
||||
background-color: #f5f7f6;
|
||||
box-shadow: 5px 5px 72px rgba(30, 46, 50, 0.5);
|
||||
color: #040605;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.calendar-contain {
|
||||
margin: auto;
|
||||
top: 5%;
|
||||
}
|
||||
}
|
||||
|
||||
.title-bar {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
text-align: right;
|
||||
background: #f5f7f6;
|
||||
padding: 0.5rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.title-bar:after {
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.title-bar__burger {
|
||||
display: block;
|
||||
position: relative;
|
||||
float: left;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 38px;
|
||||
height: 30px;
|
||||
font-size: 0;
|
||||
text-indent: -9999px;
|
||||
appearance: none;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.title-bar__burger:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.burger__lines {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
top: 15px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
height: 1px;
|
||||
background: #040605;
|
||||
}
|
||||
|
||||
.burger__lines:before, .burger__lines:after {
|
||||
position: absolute;
|
||||
display: block;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #040605;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.burger__lines:before {
|
||||
top: -5px;
|
||||
}
|
||||
|
||||
.burger__lines:after {
|
||||
bottom: -5px;
|
||||
}
|
||||
|
||||
.title-bar__year {
|
||||
display: block;
|
||||
position: relative;
|
||||
float: left;
|
||||
font-size: 1rem;
|
||||
line-height: 30px;
|
||||
width: 43%;
|
||||
padding: 0 0.5rem;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.title-bar__year {
|
||||
width: 27%;
|
||||
}
|
||||
}
|
||||
|
||||
.title-bar__month {
|
||||
position: relative;
|
||||
/*float: center;*/
|
||||
font-size: 1rem;
|
||||
line-height: 30px;
|
||||
width: 22%;
|
||||
padding: 0 0.5rem;
|
||||
text-align: center;
|
||||
margin-right: 67px;
|
||||
word-spacing: 30px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.title-bar__month {
|
||||
width: 12%;
|
||||
}
|
||||
}
|
||||
|
||||
.title-bar__minimize, .title-bar__maximize, .title-bar__close {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.title-bar__minimize:before, .title-bar__maximize:before, .title-bar__close:before, .title-bar__minimize:after, .title-bar__maximize:after, .title-bar__close:after {
|
||||
top: 30%;
|
||||
right: 30%;
|
||||
bottom: 30%;
|
||||
left: 30%;
|
||||
content: " ";
|
||||
position: absolute;
|
||||
border-color: #8e8e8e;
|
||||
border-style: solid;
|
||||
border-width: 0 0 2px 0;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__controls {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
float: right;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__controls:before, .title-bar .title-bar__controls:after {
|
||||
content: none;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__minimize:before {
|
||||
border-bottom-width: 2px;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__maximize:before {
|
||||
border-width: 1px 1px 2px 1px;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__close:before, .title-bar .title-bar__close:after {
|
||||
bottom: 50%;
|
||||
top: 49.9%;
|
||||
}
|
||||
|
||||
.title-bar .title-bar__close:before {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.title-bar .title-bar__close:after {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.calendar__sidebar {
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
float: none;
|
||||
background: linear-gradient(120deg, #eff3f3, #e1e7e8);
|
||||
padding-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.calendar__sidebar {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar__sidebar .content {
|
||||
padding: 2rem 1.5rem 2rem 4rem;
|
||||
color: #040605;
|
||||
}
|
||||
|
||||
.sidebar__nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
margin-bottom: 0.9rem;
|
||||
padding: 0.7rem 1rem;
|
||||
background-color: #f5f7f6;
|
||||
}
|
||||
|
||||
.sidebar__nav-item {
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
margin-right: 23px;
|
||||
padding: 0;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.sidebar__list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.sidebar__list-item {
|
||||
margin: 1.2rem 0;
|
||||
color: #2d4338;
|
||||
font-weight: 100;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.list-item__time {
|
||||
display: inline-block;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.list-item__time {
|
||||
margin-right: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar__list-item--complete {
|
||||
color: rgba(4, 6, 5, 0.3);
|
||||
}
|
||||
|
||||
.sidebar__list-item--complete .list-item__time {
|
||||
color: rgba(4, 6, 5, 0.3);
|
||||
}
|
||||
|
||||
.sidebar__heading {
|
||||
font-size: 2.2rem;
|
||||
font-weight: bold;
|
||||
padding-left: 1rem;
|
||||
padding-right: 1rem;
|
||||
margin-bottom: 3rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.sidebar__heading span {
|
||||
float: right;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.calendar__heading-highlight {
|
||||
color: #2d444a;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.calendar__days {
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
float: none;
|
||||
min-height: 580px;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
/*padding: 0.8rem 0 1rem 1rem;*/
|
||||
background: #f5f7f6;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.calendar__days {
|
||||
width: 50%;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar__top-bar {
|
||||
background: #b8cad6;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex: 56px 0 0;
|
||||
max-height: 44px;
|
||||
box-shadow: 0px 5px 5px -5px rgba(34, 60, 80, 0.6);
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.top-bar__days {
|
||||
width: 100%;
|
||||
padding: 0 5px;
|
||||
color: #2d4338;
|
||||
font-weight: 100;
|
||||
-webkit-font-smoothing: subpixel-antialiased;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.calendar__week {
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
}
|
||||
|
||||
.calendar__day {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-flow: column wrap;
|
||||
|
||||
width: 100%;
|
||||
justify-content: space-around;
|
||||
/*padding: 1.9rem 0.2rem 0.2rem;*/
|
||||
}
|
||||
|
||||
|
||||
.calendar__date {
|
||||
/*margin: 25px;*/
|
||||
color: #040605;
|
||||
font-size: 1.7rem;
|
||||
font-weight: 600;
|
||||
line-height: 0.7;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.calendar__date {
|
||||
font-size: 2.3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar__week .inactive .calendar__date, .calendar__week .inactive .task-count {
|
||||
color: #c6c6c6;
|
||||
}
|
||||
|
||||
.calendar__week .today .calendar__date {
|
||||
color: #fd588a;
|
||||
}
|
||||
|
||||
.calendar__task {
|
||||
color: #040605;
|
||||
display: flex;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 55em) {
|
||||
.calendar__task {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar__task.calendar__task--today {
|
||||
color: #fd588a;
|
||||
}
|
||||
|
||||
|
||||
.danger {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.calendar__day:hover {
|
||||
color: #0a0a0a;
|
||||
background: #c2c2c2;
|
||||
cursor: pointer;
|
||||
}
|
||||
.calendar__day:active {
|
||||
background: #727272;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.active_day {
|
||||
background: #cdcfce;
|
||||
}
|
0
backend/widgets/Calendar/assets/js/script.js
Normal file
0
backend/widgets/Calendar/assets/js/script.js
Normal file
186
backend/widgets/Calendar/assets/js/src/CalendarHelper.js
Normal file
186
backend/widgets/Calendar/assets/js/src/CalendarHelper.js
Normal file
@ -0,0 +1,186 @@
|
||||
class CalendarHelper {
|
||||
|
||||
static build(date, dates = null) {
|
||||
const _daysNames = `<section class="calendar__top-bar">
|
||||
<span class="top-bar__days"> Mon </span>
|
||||
<span class="top-bar__days">Tue</span>
|
||||
<span class="top-bar__days">Wed</span>
|
||||
<span class="top-bar__days">Thu</span>
|
||||
<span class="top-bar__days">Fri</span>
|
||||
<span class="top-bar__days">Sat</span>
|
||||
<span class="top-bar__days">Sun</span>
|
||||
</section>`;
|
||||
|
||||
|
||||
let month = DateHelper.getMonth(date)
|
||||
|
||||
let html = `<section class="calendar__week">`, index = 1, indexRaw = 0;
|
||||
|
||||
for (let i = 0, dayNum = month[i]; i < month.length; i++, dayNum = month[i]) {
|
||||
let className = ``
|
||||
if (this._isInactive(dayNum, i)) {
|
||||
className = 'inactive'
|
||||
}
|
||||
let color = this._getColor(new Date(date.getFullYear(), date.getMonth(), dayNum), dates)
|
||||
html += this._getCalendarDay(dayNum, className, color)
|
||||
if ((i + 1) % 7 == 0) {
|
||||
|
||||
html += `</section><section class="calendar__week">`
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
html = removeExcessTagSection(html)
|
||||
|
||||
document.querySelector('.calendar__days').innerHTML = _daysNames + html
|
||||
|
||||
|
||||
function removeExcessTagSection(html) {
|
||||
return html.substr(0, html.length - 9)
|
||||
}
|
||||
}
|
||||
|
||||
static main(day = null) {
|
||||
let datePicker = document.querySelector('#date');
|
||||
let oldDate = datePicker.value.substr(0, 7);
|
||||
|
||||
let nameDateBoard = document.querySelector('.sidebar__heading');
|
||||
let contentBoard = document.querySelector('.sidebar__list');
|
||||
|
||||
this._updateContent(datePicker.value)
|
||||
.then(content => {
|
||||
|
||||
this._runBuild(DateHelper.stringToDate(datePicker.value), content)
|
||||
|
||||
datePicker.onchange = function (day = null) {
|
||||
let days = document.querySelectorAll('.calendar__day ')
|
||||
|
||||
for (let i = 0; i < days.length; i++) {
|
||||
if (days[i].classList.contains('active_day'))
|
||||
days[i].classList.remove('active_day')
|
||||
}
|
||||
|
||||
if (!CalendarHelper.isOldDatePicker(datePicker, oldDate)) {
|
||||
oldDate = datePicker.value.substr(0, 7);
|
||||
|
||||
CalendarHelper._updateContent(datePicker.value)
|
||||
.then(content => {
|
||||
|
||||
CalendarHelper.main(day)
|
||||
let date = new Date(datePicker.value);
|
||||
let monthName = date.toLocaleString('default', {month: 'long'});
|
||||
let dayWeekName = date.toLocaleString('default', {weekday: 'long'});
|
||||
nameDateBoard.innerHTML = `${dayWeekName} <br>${monthName} ${datePicker.value.substr(8, 2)}`;
|
||||
contentBoard.innerHTML = CalendarHelper._getHtmlContentForDate(content, datePicker.value)
|
||||
})
|
||||
|
||||
}
|
||||
let date = new Date(datePicker.value);
|
||||
let monthName = date.toLocaleString('default', {month: 'long'});
|
||||
let dayWeekName = date.toLocaleString('default', {weekday: 'long'});
|
||||
nameDateBoard.innerHTML = `${dayWeekName} <br>${monthName} ${datePicker.value.substr(8, 2)}`;
|
||||
contentBoard.innerHTML = CalendarHelper._getHtmlContentForDate(content, datePicker.value)
|
||||
}
|
||||
|
||||
let days = document.querySelectorAll('.calendar__day');
|
||||
|
||||
for (let i = 0; i < Object.keys(days).length; i++) {
|
||||
let dateDay = parseInt(days[i].textContent);
|
||||
if (day) {
|
||||
if (parseInt(day.textContent) == dateDay && !days[i].classList.contains('inactive')) {
|
||||
days[i].classList.add('active_day')
|
||||
}
|
||||
}
|
||||
|
||||
if (days[i].classList.contains('inactive')) {
|
||||
days[i].onclick = function () {
|
||||
let date = CalendarHelper._getFutureDate(datePicker.value, parseInt(days[i].textContent))
|
||||
datePicker.value = date;
|
||||
datePicker.onchange(this)
|
||||
}
|
||||
} else {
|
||||
days[i].onclick = function () {
|
||||
datePicker.value = datePicker.value.substr(0, 8) + DateHelper.intToDate(dateDay);
|
||||
datePicker.onchange(this)
|
||||
days[i].classList.add('active_day')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
static _getHtmlContentForDate(content, date) {
|
||||
/* making html content; Example: return "In this day Birthday of " +content['date']['user']; */
|
||||
}
|
||||
|
||||
|
||||
static _runBuild(date, content) {
|
||||
/*making something for dates from content = [date1, date2, ...]*/
|
||||
|
||||
this.build(date, content)
|
||||
}
|
||||
|
||||
static
|
||||
async _updateContent(date) {
|
||||
let monthNumber = date.substr(5, 2);
|
||||
return fetch('../ajax/get-birthday-by-month?' +
|
||||
'month=' + monthNumber)
|
||||
.then((res) => {
|
||||
return res.json()
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
static isOldDatePicker(datePicker, oldDate) {
|
||||
if (datePicker.value.substr(0, 7) == oldDate)
|
||||
return true;
|
||||
return false
|
||||
}
|
||||
|
||||
static _isInactive(numDay, i) {
|
||||
if (i < 8 && numDay !== i + 1) {
|
||||
return (numDay > i)
|
||||
} else {
|
||||
return (i - 8) > numDay
|
||||
}
|
||||
}
|
||||
|
||||
static _getCalendarDay(dayNum, className = ``, color = ``) {
|
||||
return `<div class="calendar__day ${className}">
|
||||
<span class="calendar__date ${color}">${dayNum}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
static _getColor(date, dates = null) {
|
||||
if (dates != null && dates.includes(DateHelper.dateToString(date))) {
|
||||
return 'success';
|
||||
}
|
||||
if ([6, 0].includes(date.getDay()))
|
||||
return;
|
||||
|
||||
return 'danger';
|
||||
}
|
||||
|
||||
static _getFutureDate(dat, value) {
|
||||
let date = new Date(dat);
|
||||
if (value < 8) {
|
||||
if (date.getMonth() == 11) {
|
||||
date = new Date(date.getFullYear() + 1, 0, value);
|
||||
} else {
|
||||
date = new Date(date.getFullYear(), date.getMonth() + 1, value);
|
||||
}
|
||||
} else {
|
||||
if (date.getMonth() == 0) {
|
||||
date = new Date(date.getFullYear() - 1, 11, value);
|
||||
} else {
|
||||
date = new Date(date.getFullYear(), date.getMonth() - 1, value);
|
||||
}
|
||||
}
|
||||
return date.getFullYear() + '-' + DateHelper.intToDate(date.getMonth() + 1) + '-' + DateHelper.intToDate(value);
|
||||
|
||||
}
|
||||
|
||||
}
|
87
backend/widgets/Calendar/assets/js/src/DateHelper.js
Normal file
87
backend/widgets/Calendar/assets/js/src/DateHelper.js
Normal file
@ -0,0 +1,87 @@
|
||||
class DateHelper {
|
||||
static getMonth(date) {
|
||||
date = this.nextMonth(date)
|
||||
date = this.prevDay(date)
|
||||
let days = [], last = date, quantity = this.getQuantity(date)
|
||||
for (let i = 0; i < (7 - last.getDay()) % 7; i++) {
|
||||
days.push((7 - last.getDay()) % 7 - i)
|
||||
}
|
||||
for (let i = 0; i < last.getDate(); i++) {
|
||||
days.push(last.getDate() - i)
|
||||
}
|
||||
date = this.prevMonth(date)
|
||||
date = this.nextMonth(date)
|
||||
date = this.prevDay(date)
|
||||
for (let i = 0, lenDays = quantity - days.length; i < lenDays; i++) {
|
||||
days.push(date.getDate() - i)
|
||||
}
|
||||
return days.reverse();
|
||||
}
|
||||
|
||||
static getQuantity(date) {
|
||||
if (this.isDayOff(date)) {
|
||||
return 42
|
||||
}
|
||||
if (this.prevDay(this.nextMonth(date)).getDate() == 28) {
|
||||
return 28;
|
||||
}
|
||||
return 35
|
||||
|
||||
}
|
||||
|
||||
static isDayOff(date) {
|
||||
return [6, 0].includes(new Date(date.getFullYear(), date.getMonth(), 1).getDay())
|
||||
}
|
||||
|
||||
static prevDay(date) {
|
||||
return new Date(date.getTime() - 1000 * 3600 * 24)
|
||||
}
|
||||
|
||||
static nextMonth(date) {
|
||||
if (this.isDecember(date)) {
|
||||
return new Date(date.getFullYear() + 1, 0, 1)
|
||||
}
|
||||
return new Date(date.getFullYear(), date.getMonth() + 1, 1)
|
||||
}
|
||||
|
||||
static prevMonth(date) {
|
||||
if (this.isJanuary(date)) {
|
||||
return new Date(date.getFullYear() - 1, 11, 1)
|
||||
}
|
||||
return new Date(date.getFullYear(), date.getMonth() - 1, 1)
|
||||
}
|
||||
|
||||
static isDecember(date) {
|
||||
return 11 == date.getMonth()
|
||||
}
|
||||
|
||||
static isJanuary(date) {
|
||||
return 0 == date.getMonth()
|
||||
}
|
||||
|
||||
static intToDate(number_date) {
|
||||
if (Math.floor(number_date / 10) === 0)
|
||||
number_date = '0' + number_date;
|
||||
return number_date
|
||||
}
|
||||
|
||||
static dateToString(date) {
|
||||
let year = date.getFullYear()
|
||||
let day = this.intToDate(date.getDate())
|
||||
let month = this.intToDate(this.isDecember(date) ? 0 : date.getMonth() + 1)
|
||||
return year + '-' + month + '-' + day
|
||||
}
|
||||
|
||||
static stringToDate(date) {
|
||||
let month = parseInt(date.substr(5, 2))
|
||||
return new Date(date.substr(0, 4), month, date.substr(7, 2))
|
||||
}
|
||||
|
||||
static getDates(array) {
|
||||
let dates = []
|
||||
for (let model of array) {
|
||||
dates.push(model['date'])
|
||||
}
|
||||
return dates
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user