Сделал виджет с переопределением 4 главных функций календаря в js

This commit is contained in:
maxim 2021-09-10 17:39:40 +03:00
parent de47ccec77
commit 125bddde21
12 changed files with 1009 additions and 5 deletions

View File

@ -0,0 +1,32 @@
<?php
namespace backend\modules\calendar\controllers;
use backend\modules\card\models\UserCardSearch;
use Yii;
use yii\helpers\ArrayHelper;
use yii\web\Response;
class AjaxController extends \yii\web\Controller
{
public function actionGetBirthdayByMonth($month )
{
$searchModel = new UserCardSearch();
$models = $searchModel->search(Yii::$app->request->queryParams)->getModels();
$models_array = ArrayHelper::toArray($models, [
'backend\modules\card\models\UserCard' => [
'id',
'dob',
'fio'
],
]);
$response = Yii::$app->response;
$response->format = Response::FORMAT_JSON;
$response->getHeaders()->set('Content-Type', 'application/json; charset=utf-8');
$response->content = json_encode(
$models_array
);
return $response;
}
}?>

View File

@ -3,7 +3,6 @@
namespace backend\modules\calendar\controllers; namespace backend\modules\calendar\controllers;
use backend\modules\card\models\UserCardSearch; use backend\modules\card\models\UserCardSearch;
use common\classes\Debug;
use Yii; use Yii;
use yii\data\ArrayDataProvider; use yii\data\ArrayDataProvider;
use yii\filters\AccessControl; use yii\filters\AccessControl;
@ -43,6 +42,14 @@ class CalendarController extends Controller
* Renders the index view for the module * Renders the index view for the module
* @return string * @return string
*/ */
public function actionAlternative(){
$searchModel = new UserCardSearch();
$dataProvider = $searchModel->search(['month'=>date('m', strtotime('2019-07-03'))]);
return $this->render('alternative', [
'dataProvider' => $dataProvider
]);
}
public function actionIndex() public function actionIndex()
{ {
$searchModel = new UserCardSearch(); $searchModel = new UserCardSearch();

View File

@ -0,0 +1,80 @@
<?php
use yii\helpers\Html;
$this->title = 'Календарь ДР';
?>
<?= \backend\widgets\Calendar::widget([
'button' => Html::a('<i class="fas fa-long-arrow-alt-left"></i> Назад',
Yii::$app->request->referrer, ['class' => 'btn btn-primary',]),
'runBuild' => "function (date, content){
this.build(date, content)
}",
'updateContent' => "function(date){
let monthNumber = date.substr(5, 2);
return fetch('../ajax/get-birthday-by-month?' +
'month=' + monthNumber)
.then((res) => {
return res.json()
})
}",
'getColor' => "function (date, dates = null) {
for (let contentDate of dates) {
if (contentDate['dob'].substr(8, 2) == DateHelper.intToDate(date.getDate())) {
return 'success';
}
}
}",
'getHtmlContentForDate' => 'function (content, date) {
let flag = false
let html = `<table class="table table-striped table-bordered">
<thead>
<tr>
<th>#</th>
<th>ФИО</th>
<th>Дата рождения</th>
<th class="action-column">&nbsp;</th>
</tr>
</thead><tbody>`;
for (let i = 1; i <= content.length; i++) {
let model = content[i - 1];
if (model["dob"].substr(8, 2) == date.substr(8, 2)) {
flag = true;
html += `<tr data-key="${model["id"]}">`
html += `<td>${i}</td>`
html += `<td>${model["fio"]}</td>`
html += `<td>${model["dob"]}</td>`
html += `<td><a href="/secure/calendar/calendar/view?id=${model["id"]}" title="Просмотр" aria-label="Просмотр" data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1.125em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<path fill="currentColor"
d="M573 241C518 136 411 64 288 64S58 136 3 241a32 32 0 000 30c55 105 162 177 285 177s230-72 285-177a32 32 0 000-30zM288 400a144 144 0 11144-144 144 144 0 01-144 144zm0-240a95 95 0 00-25 4 48 48 0 01-67 67 96 96 0 1092-71z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/update?id=${model["id"]}" title="Редактировать" aria-label="Редактировать"
data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor"
d="M498 142l-46 46c-5 5-13 5-17 0L324 77c-5-5-5-12 0-17l46-46c19-19 49-19 68 0l60 60c19 19 19 49 0 68zm-214-42L22 362 0 484c-3 16 12 30 28 28l122-22 262-262c5-5 5-13 0-17L301 100c-4-5-12-5-17 0zM124 340c-5-6-5-14 0-20l154-154c6-5 14-5 20 0s5 14 0 20L144 340c-6 5-14 5-20 0zm-36 84h48v36l-64 12-32-31 12-65h36v48z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/delete?id=${model["id"]}" title="Удалить" aria-label="Удалить" data-pjax="0"
data-confirm="Вы уверены, что хотите удалить этот элемент?" data-method="post">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:.875em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path fill="currentColor"
d="M32 464a48 48 0 0048 48h288a48 48 0 0048-48V128H32zm272-256a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zM432 32H312l-9-19a24 24 0 00-22-13H167a24 24 0 00-22 13l-9 19H16A16 16 0 000 48v32a16 16 0 0016 16h416a16 16 0 0016-16V48a16 16 0 00-16-16z"></path>
</svg>
</a>
</td>`
html += `</tr>`
}
}
html += `</tbody></table>`
if (flag) return html;
return "empty"
}'
]) ?>

View File

@ -4,9 +4,10 @@
/* @var $dataProvider yii\data\ActiveDataProvider */ /* @var $dataProvider yii\data\ActiveDataProvider */
use yii\grid\GridView; use yii\grid\GridView;
use yii\helpers\Html;
use yii\widgets\Pjax; use yii\widgets\Pjax;
?> ?>
<div style="display: flex;align-items: flex-start;">
<p> <p>
<select id="options" class="btn btn-secondary dropdown-toggle"> <select id="options" class="btn btn-secondary dropdown-toggle">
<option selected="selected" value="?month=00">Выберите месяц</option> <option selected="selected" value="?month=00">Выберите месяц</option>
@ -25,7 +26,9 @@ use yii\widgets\Pjax;
<option value="?month=12">декабрь</option> <option value="?month=12">декабрь</option>
</select> </select>
</p> </p>
<?=Html::a('Календарь дней рождений '.Html::tag('i', null, ['class' => 'far fa-calendar-alt']),
['alternative'], ['class' => 'btn btn-success', 'style' => 'margin-left: 10px'])?>
</div>
<?php <?php
Pjax::begin(['id' => 'reload']); Pjax::begin(['id' => 'reload']);
echo GridView::widget([ echo GridView::widget([

View File

@ -6,7 +6,6 @@ use common\classes\Debug;
use Yii; use Yii;
use yii\base\Model; use yii\base\Model;
use yii\data\ActiveDataProvider; use yii\data\ActiveDataProvider;
use backend\modules\card\models\UserCard;
/** /**
* UserCardSearch represents the model behind the search form of `backend\modules\card\models\UserCard`. * UserCardSearch represents the model behind the search form of `backend\modules\card\models\UserCard`.
@ -64,6 +63,10 @@ class UserCardSearch extends UserCard
$query->where(['deleted_at' => null]); $query->where(['deleted_at' => null]);
if (isset($params['month'])) {
$query->andFilterWhere(['=', 'MONTH(dob)', $params['month']]);
}
// grid filtering conditions // grid filtering conditions
$query->andFilterWhere([ $query->andFilterWhere([
'id' => $this->id, 'id' => $this->id,

View File

@ -291,6 +291,9 @@
text-align: center; text-align: center;
display: flex; display: flex;
flex: 56px 0 0; 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 { .top-bar__days {
@ -299,7 +302,7 @@
color: #2d4338; color: #2d4338;
font-weight: 100; font-weight: 100;
-webkit-font-smoothing: subpixel-antialiased; -webkit-font-smoothing: subpixel-antialiased;
font-size: 1rem; font-size: 18px;
} }
.calendar__week { .calendar__week {

View File

@ -0,0 +1,17 @@
<?php
namespace backend\widgets;
use yii\web\AssetBundle;
class AppAsset extends AssetBundle
{
public $sourcePath = '@backend/widgets/Calendar/assets';
public $baseUrl = '@web';
public $css = ['css/style.css'];
public $js = [
'js/script.js',
'js/src/CalendarHelper.js',
'js/src/DateHelper.js'
];
}

View File

@ -0,0 +1,203 @@
<?php
namespace backend\widgets;
use yii\base\Widget;
use yii\helpers\Html;
use yii\helpers\Url;
class Calendar extends Widget
{
public $button;
public $runBuild = 'function (date, content){
this.build(date, content)
}';
public $updateContent = "function(){
let monthNumber = date.substr(5, 2);
return fetch('../ajax/get-birthday-by-month?' +
'month=' + monthNumber)
.then((res) => {
return res.json()
})
}";
public $getColor = "function (date, dates = null) {
for (let contentDate of dates) {
if (contentDate['dob'].substr(8, 2) == DateHelper.intToDate(date.getDate())) {
return 'success';
}
}
}";
public $getHtmlContentForDate = 'function (content, date) {
console.log(content)
let flag = false
let html = `<table class="table table-striped table-bordered">
<thead>
<tr>
<th>#</th>
<th>ФИО</th>
<th>Дата рождения</th>
<th class="action-column">&nbsp;</th>
</tr>
</thead><tbody>`;
for (let i = 1; i <= content.length; i++) {
let model = content[i - 1];
if (model["dob"].substr(8, 2) == date.substr(8, 2)) {
flag = true;
html += `<tr data-key="${model["id"]}">`
html += `<td>${i}</td>`
html += `<td>${model["fio"]}</td>`
html += `<td>${model["dob"]}</td>`
html += `<td><a href="/secure/calendar/calendar/view?id=${model["id"]}" title="Просмотр" aria-label="Просмотр" data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1.125em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<path fill="currentColor"
d="M573 241C518 136 411 64 288 64S58 136 3 241a32 32 0 000 30c55 105 162 177 285 177s230-72 285-177a32 32 0 000-30zM288 400a144 144 0 11144-144 144 144 0 01-144 144zm0-240a95 95 0 00-25 4 48 48 0 01-67 67 96 96 0 1092-71z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/update?id=${model["id"]}" title="Редактировать" aria-label="Редактировать"
data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor"
d="M498 142l-46 46c-5 5-13 5-17 0L324 77c-5-5-5-12 0-17l46-46c19-19 49-19 68 0l60 60c19 19 19 49 0 68zm-214-42L22 362 0 484c-3 16 12 30 28 28l122-22 262-262c5-5 5-13 0-17L301 100c-4-5-12-5-17 0zM124 340c-5-6-5-14 0-20l154-154c6-5 14-5 20 0s5 14 0 20L144 340c-6 5-14 5-20 0zm-36 84h48v36l-64 12-32-31 12-65h36v48z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/delete?id=${model["id"]}" title="Удалить" aria-label="Удалить" data-pjax="0"
data-confirm="Вы уверены, что хотите удалить этот элемент?" data-method="post">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:.875em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path fill="currentColor"
d="M32 464a48 48 0 0048 48h288a48 48 0 0048-48V128H32zm272-256a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zM432 32H312l-9-19a24 24 0 00-22-13H167a24 24 0 00-22 13l-9 19H16A16 16 0 000 48v32a16 16 0 0016 16h416a16 16 0 0016-16V48a16 16 0 00-16-16z"></path>
</svg>
</a>
</td>`
html += `</tr>`
}
}
html += `</tbody></table>`
if (flag) return html;
return "empty"
}';
/*
CalendarHelper._updateContent = async function(){
let monthNumber = date.substr(5, 2);
return fetch('../ajax/get-birthday-by-month?' +
'month=' + monthNumber)
.then((res) => {
return res.json()
})
}
CalendarHelper._getColor = function (date, dates = null) {
for (let contentDate of dates) {
if (contentDate['dob'].substr(8, 2) == DateHelper.intToDate(date.getDate())) {
return 'success';
}
}
}
CalendarHelper._getHtmlContentForDate = function (content, date) {
console.log(content)
let flag = false
let html = `<table class="table table-striped table-bordered">
<thead>
<tr>
<th>#</th>
<th>ФИО<th>
<a href="/secure/calendar/calendar/index?UserCardSearch%5Bfio%5D=&amp;UserCardSearch%5Bdob%5D=2003-07-18&amp;sort=dob"
data-sort="dob">Дата рождения</a></th>
<th class="action-column">&nbsp;</th>
</tr>
</thead><tbody>`;
for (let i = 1; i <= content.length; i++) {
let model = content[i - 1];
if (model['dob'].substr(8, 2) == date.substr(8, 2)) {
flag = true;
html += `<tr data-key="${model['id']}">`
html += `<td>${i}</td>`
html += `<td>${model['fio']}</td>`
html += `<td>${model['dob']}</td>`
html += `<td><a href="/secure/calendar/calendar/view?id=${model['id']}" title="Просмотр" aria-label="Просмотр" data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1.125em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
<path fill="currentColor"
d="M573 241C518 136 411 64 288 64S58 136 3 241a32 32 0 000 30c55 105 162 177 285 177s230-72 285-177a32 32 0 000-30zM288 400a144 144 0 11144-144 144 144 0 01-144 144zm0-240a95 95 0 00-25 4 48 48 0 01-67 67 96 96 0 1092-71z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/update?id=${model['id']}" title="Редактировать" aria-label="Редактировать"
data-pjax="0">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:1em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path fill="currentColor"
d="M498 142l-46 46c-5 5-13 5-17 0L324 77c-5-5-5-12 0-17l46-46c19-19 49-19 68 0l60 60c19 19 19 49 0 68zm-214-42L22 362 0 484c-3 16 12 30 28 28l122-22 262-262c5-5 5-13 0-17L301 100c-4-5-12-5-17 0zM124 340c-5-6-5-14 0-20l154-154c6-5 14-5 20 0s5 14 0 20L144 340c-6 5-14 5-20 0zm-36 84h48v36l-64 12-32-31 12-65h36v48z"></path>
</svg>
</a> <a href="/secure/calendar/calendar/delete?id=${model['id']}" title="Удалить" aria-label="Удалить" data-pjax="0"
data-confirm="Вы уверены, что хотите удалить этот элемент?" data-method="post">
<svg aria-hidden="true"
style="display:inline-block;font-size:inherit;height:1em;overflow:visible;vertical-align:-.125em;width:.875em"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
<path fill="currentColor"
d="M32 464a48 48 0 0048 48h288a48 48 0 0048-48V128H32zm272-256a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zm-96 0a16 16 0 0132 0v224a16 16 0 01-32 0zM432 32H312l-9-19a24 24 0 00-22-13H167a24 24 0 00-22 13l-9 19H16A16 16 0 000 48v32a16 16 0 0016 16h416a16 16 0 0016-16V48a16 16 0 00-16-16z"></path>
</svg>
</a>
</td>`
html += `</tr>`
}
}
html += `</tbody></table>`
if (flag) return html;
return "empty"
}
*/
public function init()
{
parent::init();
$view = $this->getView();
AppAsset::register($view);
}
public function run()
{
echo Html::beginTag('section', ['class' => 'calendar-contain']);
echo Html::beginTag('aside', ['class' => 'calendar__sidebar']);
echo Html::beginTag('section', ['class' => 'title-bar']);
echo $this->button;
echo Html::input('date', null, date('Y-m-d'), ['class' => 'form-control', 'id' => 'date',]);
echo Html::endTag('section');
echo Html::tag('h2', date('l') . '<br>' . date('F d'), ['class' => 'sidebar__heading']);
echo Html::beginTag('ul', ['class' => 'sidebar__list']);
echo Html::endTag('ul');
echo Html::endTag('aside');
echo Html::beginTag('section', ['class' => 'calendar__days']);
echo Html::endTag('section');
echo Html::endTag('section');
$this->view->registerJs('
CalendarHelper._runBuild = ' . $this->runBuild . ';
CalendarHelper._getHtmlContentForDate = ' . $this->getHtmlContentForDate . ';
CalendarHelper._updateContent = async ' . $this->updateContent . ';
CalendarHelper._getColor = ' . $this->getColor . ';
CalendarHelper.main()'
);
}
}
?>
<script>
</script>

View 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;
}

View 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);
}
}

View 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
}
}