Календарь на AJAX и PHP

Календарь является неотъемлемой частью дизайна многих сайтах. Часто он представляет собой один из многочисленных плагинов JQuery для календаря. Но он также может быть реализован с помощью PHP.

Сегодня я покажу вам, как создать помесячный календарь с возможностью прокрутки (стрелками вправо и влево) месяцев с использованием технологии AJAX.

Помимо использования AJAX, этот календарь имеет еще одно важное преимущество – он может применяться для мобильных сайтов, так как имеет адаптивную основу.

Прежде чем мы перейдем к рассмотрению кода, я рекомендую вам посмотреть нашу демо-версию, чтобы вы имели представление о том, что мы собираемся сделать.

Предварительный просмотр

Предварительный просмотр

Демонстрация

Скачать источник

Структура папок

Для начала давайте четко определимся со структурой папок для всех файлов, которые мы будем создавать:

  • CSS - для всех файлов CSS;
  • изображения - для всех возможных изображений;
  • шаблоны - для всех файлов шаблонов.

Шаг 1. HTML

Я не собираюсь использовать какую-либо конкретную системы шаблонов (например, Smarty), я буду использовать только простые шаблоны HTML с собственными ключами.

Шаблоны / index.html:

<!DOCTYPE html>
	<html lang="en">
	<head>
	    <meta charset="utf-8" />
	    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
	    <title>PHP AJAX Calendar</title>
	 
	    <!-- add styles and scripts -->
	    <link href="css/styles.css" rel="stylesheet" type="text/css" />
	    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>

	</head>
	<body>
	    <div id="calendar">
	        __calendar__
	    </div>
	</body>
	</html>

Это очень простой шаблон для нашей индексной страницы, в нем мы задали базовый контейнер календаря.

Второй шаблон будет использоваться в качестве внутреннего контейнера:

Шаблоны / calendar.html:

<div class="navigation">
	    <a class="prev" href="index.php?month=__prev_month__" onclick="$('#calendar').load('index.php?month=__prev_month__&_r=' + Math.random()); return false;"></a>
	    <div class="title" >__cal_caption__</div>
	    <a class="next" href="index.php?month=__next_month__" onclick="$('#calendar').load('index.php?month=__next_month__&_r=' + Math.random()); return false;"></a>
	</div>
	 
	<table>
	    <tr>
	        <th class="weekday">sun</th>
	        <th class="weekday">mon</th>
	        <th class="weekday">tue</th>
	        <th class="weekday">wed</th>
	        <th class="weekday">thu</th>
	        <th class="weekday">fri</th>
	        <th class="weekday">sat</th>
	    </tr>
	    __cal_rows__
	</table>

Используем мы его потому, что при Ajax-запросах вовсе не обязательно выводить все значения, достаточно только внутреннего содержимого календаря.

Шаг 2 . PHP

Пора действовать.

index.php

// Устанавливаем текущий год, месяц и день
list($iNowYear, $iNowMonth, $iNowDay) = explode('-', date('Y-m-d'));
 
// Устанавливаем текущий год, месяц в зависимости от возможных параметров GET 
if (isset($_GET['month'])) {
    list($iMonth, $iYear) = explode('-', $_GET['month']);
    $iMonth = (int)$iMonth;
    $iYear = (int)$iYear;
} else {
    list($iMonth, $iYear) = explode('-', date('n-Y'));
}
 
// Получаем названия и количество дней в конкретном месяце
$iTimestamp = mktime(0, 0, 0, $iMonth, $iNowDay, $iYear);
list($sMonthName, $iDaysInMonth) = explode('-', date('F-t', $iTimestamp));
 
// Получаем предыдущий год и месяц 
$iPrevYear = $iYear;
$iPrevMonth = $iMonth - 1;
if ($iPrevMonth <= 0) {
    $iPrevYear--;
    $iPrevMonth = 12; // set to December
}
 
// Получаем следующий год и месяц
$iNextYear = $iYear;
$iNextMonth = $iMonth + 1;
if ($iNextMonth > 12) {
    $iNextYear++;
    $iNextMonth = 1;
}
 
// Получаем количество дней в предыдущем месяце
$iPrevDaysInMonth = (int)date('t', mktime(0, 0, 0, $iPrevMonth, $iNowDay, $iPrevYear));
 
// Получаем числовое представление дней недели от первого дня конкретного (текущего) месяца.
$iFirstDayDow = (int)date('w', mktime(0, 0, 0, $iMonth, 1, $iYear));
 
// С этого дня начинается предыдущий месяц 
$iPrevShowFrom = $iPrevDaysInMonth - $iFirstDayDow + 1;
 
// Если предыдущий месяц
$bPreviousMonth = ($iFirstDayDow > 0);
 
// Тогда первый день
$iCurrentDay = ($bPreviousMonth) ? $iPrevShowFrom : 1;
 
$bNextMonth = false;
$sCalTblRows = '';
 
// Генерируем строки календаря
for ($i = 0; $i < 6; $i++) { // 6-weeks range
    $sCalTblRows .= '<tr>';
    for ($j = 0; $j < 7; $j++) { // 7 days a week
 
        $sClass = '';
        if ($iNowYear == $iYear && $iNowMonth == $iMonth && $iNowDay == $iCurrentDay && !$bPreviousMonth && !$bNextMonth) {
            $sClass = 'today';
        } elseif (!$bPreviousMonth && !$bNextMonth) {
            $sClass = 'current';
        }
        $sCalTblRows .= '<td class="'.$sClass.'"><a href="javascript: void(0)">'.$iCurrentDay.'</a></td>';
 
        // Следующий день
        $iCurrentDay++;
        if ($bPreviousMonth && $iCurrentDay > $iPrevDaysInMonth) {
            $bPreviousMonth = false;
            $iCurrentDay = 1;
        }
        if (!$bPreviousMonth && !$bNextMonth && $iCurrentDay > $iDaysInMonth) {
            $bNextMonth = true;
            $iCurrentDay = 1;
        }
    }
    $sCalTblRows .= '</tr>';
}
 
// Готовим замену ключей и генерируем календарь
$aKeys = array(
    '__prev_month__' => "{$iPrevMonth}-{$iPrevYear}",
    '__next_month__' => "{$iNextMonth}-{$iNextYear}",
    '__cal_caption__' => $sMonthName . ', ' . $iYear,
    '__cal_rows__' => $sCalTblRows,
);
$sCalendarItself = strtr(file_get_contents('templates/calendar.html'), $aKeys);
 
// AJAX-запрос – выводит календарь
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH'] =='XMLHttpRequest' && isset($_GET['month'])) {
    header('Content-Type: text/html; charset=utf-8');
    echo $sCalendarItself;
    exit;
}
 
$aVariables = array(
    '__calendar__' => $sCalendarItself,
);
echo strtr(file_get_contents('templates/index.html'), $aVariables);

Я старался комментировать почти каждую строку кода, чтобы вы могли понять весь процесс. Вначале мы делаем расчет текущей даты и запрашиваемой даты.

Затем генерируем строки календаря (в днях), и, наконец, после этого заменяем ключи шаблона на собственные значения.

Через запрос Ajax мы выводим только внутреннее содержание ($sCalendarItself), в противном случае - мы показываем всю страницу.

Шаг 3. CSS

На данный момент, наш календарь не выглядит презентабельно, потому что это всего лишь голый HTML-код. Давайте украсим его.

CSS / styles.css

/* стили календаря */
#calendar {
    -moz-user-select: none;
    border: 1px solid #EEEEEE;
    border-radius: 6px 6px 6px 6px;
    color: #333333;
    font-family: Arial,sans-serif;
    font-size: 1.1em;
    margin: 10px auto;
    padding: 0.4em;
    width: 90%;
}
#calendar .navigation {
    background-color: #CC0000;
    border: 1px solid #E3A1A1;
    border-radius: 6px 6px 6px 6px;
    color: #FFFFFF;
    font-weight: bold;
    padding: 1px;
    position: relative;
}
#calendar .navigation .title {
    background: none repeat scroll 0 0 transparent;
    border-color: rgba(0, 0, 0, 0);
    color: inherit;
    line-height: 1.8em;
    margin: 0 2.3em;
    text-align: center;
}
#calendar .navigation .prev, #calendar .navigation .next {
    background-image: url(../images/nav.png);
    height: 24px;
    opacity: 0.9;
    position: absolute;
    top: 4px;
    width: 24px;
}
#calendar .navigation .prev {
    background-position: 0 0;
    left: 4px;
}
#calendar .navigation .next {
    background-position: -24px 0;
    right: 4px;
}
#calendar .navigation .prev:hover, #calendar .navigation .next:hover {
    opacity: 1;
}
#calendar table {
    border-collapse: collapse;
    font-size: 0.9em;
    table-layout: fixed;
    width: 100%;
}
#calendar table th {
    border: 0 none;
    font-weight: bold;
    padding: 0.7em 0.3em;
    text-align: center;
}
#calendar table td {
    border: 0 none;
    padding: 1px;
}
#calendar table td a {
    background-color: #EEEEEE;
    border: 1px solid #D8DCDF;
    color: #004276;
    display: block;
    font-weight: normal;
    opacity: 0.7;
    padding: 0.2em;
    text-align: right;
    text-decoration: none;
}
#calendar table td a:hover {
    background-color: #F6F6F6;
    border: 1px solid #CDD5DA;
    color: #111111;
}
#calendar table td.current a {
    font-weight: bold;
    opacity: 1;
}
#calendar table td.today a {
    background-color: #FBF8EE;
    border: 1px solid #FCD3A1;
    color: #444444;
    font-weight: bold;
    opacity: 1;
}

Шаг 4. Изображения

В стилях нашего календаря используется только одно небольшое изображение: nav.png

Демонстрация

Скачать источник

Заключение

Вот и все на сегодня, мы только что создали стильный адаптивный календарь.

Спасибо за Ваше внимание. Если вам действительно понравилось то, что мы сделали сегодня - поделитесь со своими друзьями ссылками используемыми ниже.