142 lines
6.1 KiB
PHP
142 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace dokuwiki\plugin\luxtools;
|
|
|
|
/**
|
|
* Render the chronological calendar widget markup.
|
|
*/
|
|
class ChronologicalCalendarWidget
|
|
{
|
|
/**
|
|
* Render full calendar widget HTML for one month.
|
|
*
|
|
* @param int $year
|
|
* @param int $month
|
|
* @param string $baseNs
|
|
* @return string
|
|
*/
|
|
public static function render(int $year, int $month, string $baseNs = 'chronological'): string
|
|
{
|
|
if (!self::isValidMonth($year, $month)) return '';
|
|
|
|
$firstDayTs = mktime(0, 0, 0, $month, 1, $year);
|
|
$daysInMonth = (int)date('t', $firstDayTs);
|
|
$firstWeekday = (int)date('N', $firstDayTs); // 1..7 (Mon..Sun)
|
|
|
|
$monthCursor = \DateTimeImmutable::createFromFormat('!Y-n-j', sprintf('%04d-%d-1', $year, $month));
|
|
if (!($monthCursor instanceof \DateTimeImmutable)) return '';
|
|
|
|
$prevMonth = $monthCursor->sub(new \DateInterval('P1M'));
|
|
$nextMonth = $monthCursor->add(new \DateInterval('P1M'));
|
|
|
|
$monthStartDate = sprintf('%04d-%02d-01', $year, $month);
|
|
$monthDayId = ChronoID::dateToDayId($monthStartDate, $baseNs);
|
|
$monthId = $monthDayId !== null ? ChronoID::dayIdToMonthId($monthDayId, $baseNs) : null;
|
|
$yearId = $monthId !== null ? ChronoID::monthIdToYearId($monthId, $baseNs) : null;
|
|
|
|
$prevStartDate = $prevMonth->format('Y-m-d');
|
|
$prevDayId = ChronoID::dateToDayId($prevStartDate, $baseNs);
|
|
$prevMonthId = $prevDayId !== null ? ChronoID::dayIdToMonthId($prevDayId, $baseNs) : null;
|
|
|
|
$nextStartDate = $nextMonth->format('Y-m-d');
|
|
$nextDayId = ChronoID::dateToDayId($nextStartDate, $baseNs);
|
|
$nextMonthId = $nextDayId !== null ? ChronoID::dayIdToMonthId($nextDayId, $baseNs) : null;
|
|
|
|
$leadingEmpty = $firstWeekday - 1;
|
|
$totalCells = (int)ceil(($leadingEmpty + $daysInMonth) / 7) * 7;
|
|
|
|
$dayUrlTemplate = function_exists('wl') ? (string)wl('__LUXTOOLS_ID_RAW__') : '';
|
|
$monthUrlTemplate = $dayUrlTemplate;
|
|
$yearUrlTemplate = $dayUrlTemplate;
|
|
$ajaxUrl = defined('DOKU_BASE') ? (string)DOKU_BASE . 'lib/exe/ajax.php' : 'lib/exe/ajax.php';
|
|
|
|
$html = '<div class="luxtools-plugin luxtools-calendar" data-luxtools-calendar="1"'
|
|
. ' data-base-ns="' . hsc($baseNs) . '"'
|
|
. ' data-current-year="' . hsc((string)$year) . '"'
|
|
. ' data-current-month="' . hsc(sprintf('%02d', $month)) . '"'
|
|
. ' data-day-url-template="' . hsc($dayUrlTemplate) . '"'
|
|
. ' data-month-url-template="' . hsc($monthUrlTemplate) . '"'
|
|
. ' data-year-url-template="' . hsc($yearUrlTemplate) . '"'
|
|
. ' data-luxtools-ajax-url="' . hsc($ajaxUrl) . '"'
|
|
. ' data-prev-month-id="' . hsc((string)$prevMonthId) . '"'
|
|
. ' data-next-month-id="' . hsc((string)$nextMonthId) . '"'
|
|
. '>';
|
|
|
|
$html .= '<div class="luxtools-calendar-nav">';
|
|
$html .= '<div class="luxtools-calendar-nav-prev">';
|
|
$html .= '<button type="button" class="luxtools-calendar-nav-button" data-luxtools-dir="-12" aria-label="Previous year">⏮</button>';
|
|
$html .= '<button type="button" class="luxtools-calendar-nav-button" data-luxtools-dir="-1" aria-label="Previous month">◀</button>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="luxtools-calendar-title">';
|
|
$monthLabel = date('F', $firstDayTs);
|
|
if ($monthId !== null && function_exists('wl')) {
|
|
$html .= '<a class="luxtools-calendar-month-link" href="' . hsc((string)wl($monthId)) . '">' . hsc($monthLabel) . '</a>';
|
|
} else {
|
|
$html .= hsc($monthLabel);
|
|
}
|
|
$html .= ' ';
|
|
if ($yearId !== null && function_exists('wl')) {
|
|
$html .= '<a class="luxtools-calendar-year-link" href="' . hsc((string)wl($yearId)) . '">' . hsc((string)$year) . '</a>';
|
|
} else {
|
|
$html .= hsc((string)$year);
|
|
}
|
|
$html .= '</div>';
|
|
|
|
$html .= '<div class="luxtools-calendar-nav-next">';
|
|
$html .= '<button type="button" class="luxtools-calendar-nav-button" data-luxtools-dir="1" aria-label="Next month">▶</button>';
|
|
$html .= '<button type="button" class="luxtools-calendar-nav-button" data-luxtools-dir="12" aria-label="Next year">⏭</button>';
|
|
$html .= '</div>';
|
|
$html .= '</div>';
|
|
|
|
$html .= '<table class="luxtools-calendar-table">';
|
|
$html .= '<thead><tr>';
|
|
foreach (['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] as $weekday) {
|
|
$html .= '<th scope="col">' . hsc($weekday) . '</th>';
|
|
}
|
|
$html .= '</tr></thead><tbody>';
|
|
|
|
for ($cell = 0; $cell < $totalCells; $cell++) {
|
|
if ($cell % 7 === 0) $html .= '<tr>';
|
|
|
|
$dayNumber = $cell - $leadingEmpty + 1;
|
|
if ($dayNumber < 1 || $dayNumber > $daysInMonth) {
|
|
$html .= '<td class="luxtools-calendar-day luxtools-calendar-day-empty"></td>';
|
|
} else {
|
|
$date = sprintf('%04d-%02d-%02d', $year, $month, $dayNumber);
|
|
$dayId = ChronoID::dateToDayId($date, $baseNs);
|
|
|
|
$classes = 'luxtools-calendar-day';
|
|
|
|
$html .= '<td class="' . hsc($classes) . '" data-luxtools-date="' . hsc($date) . '">';
|
|
if ($dayId !== null && function_exists('html_wikilink')) {
|
|
$html .= (string)html_wikilink($dayId, (string)$dayNumber);
|
|
} else {
|
|
$html .= hsc((string)$dayNumber);
|
|
}
|
|
$html .= '</td>';
|
|
}
|
|
|
|
if ($cell % 7 === 6) $html .= '</tr>';
|
|
}
|
|
|
|
$html .= '</tbody></table>';
|
|
$html .= '<div class="luxtools-calendar-footer">';
|
|
$html .= '<button type="button" class="luxtools-calendar-nav-button luxtools-calendar-today-button" data-luxtools-today="1" aria-label="Current month">Today</button>';
|
|
$html .= '</div></div>';
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* @param int $year
|
|
* @param int $month
|
|
* @return bool
|
|
*/
|
|
public static function isValidMonth(int $year, int $month): bool
|
|
{
|
|
if ($year < 1) return false;
|
|
if ($month < 1 || $month > 12) return false;
|
|
return true;
|
|
}
|
|
}
|