diff options
Diffstat (limited to 'vendor/gipfl/calendar')
-rw-r--r-- | vendor/gipfl/calendar/composer.json | 32 | ||||
-rw-r--r-- | vendor/gipfl/calendar/src/Calendar.php | 246 | ||||
-rw-r--r-- | vendor/gipfl/calendar/src/Widget/CalendarMonth.php | 177 | ||||
-rw-r--r-- | vendor/gipfl/calendar/src/Widget/CalendarMonthSummary.php | 278 |
4 files changed, 733 insertions, 0 deletions
diff --git a/vendor/gipfl/calendar/composer.json b/vendor/gipfl/calendar/composer.json new file mode 100644 index 0000000..5e84ef6 --- /dev/null +++ b/vendor/gipfl/calendar/composer.json @@ -0,0 +1,32 @@ +{ + "name": "gipfl/calendar", + "type": "library", + "description": "Calendar Utils", + "keywords": ["calendar"], + "homepage": "https://github.com/gipfl/calendar", + "authors": [ + { + "name": "Thomas Gelf", + "email": "thomas@gelf.net" + } + ], + "config": { + "sort-packages": true + }, + "require": { + "php": ">=5.4.0", + "gipfl/format": ">=0.3", + "gipfl/icingaweb2": ">=0.4.0", + "gipfl/translation": ">=0.1.1" + }, + "autoload": { + "psr-4": { + "gipfl\\Calendar\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "gipfl\\Tests\\Calendar\\": "tests" + } + } +} diff --git a/vendor/gipfl/calendar/src/Calendar.php b/vendor/gipfl/calendar/src/Calendar.php new file mode 100644 index 0000000..e81227c --- /dev/null +++ b/vendor/gipfl/calendar/src/Calendar.php @@ -0,0 +1,246 @@ +<?php + +namespace gipfl\Calendar; + +use gipfl\Format\LocalTimeFormat; +use InvalidArgumentException; + +class Calendar +{ + const FIRST_IS_MONDAY = 1; + const FIRST_IS_SUNDAY = 0; + + protected $firstOfWeek; + + protected $weekDays = []; + + protected $shortWeekDays = []; + + protected $timeFormat; + + public function __construct($firstOfWeek = self::FIRST_IS_MONDAY) + { + $this->timeFormat = new LocalTimeFormat(); + $this->setFirstOfWeek($firstOfWeek); + } + + public function firstOfWeekIsMonday() + { + return $this->firstOfWeek === self::FIRST_IS_MONDAY; + } + + public function firstOfWeekIsSunday() + { + return $this->firstOfWeek === self::FIRST_IS_SUNDAY; + } + + public function setFirstOfWeek($firstOfWeek) + { + if ($firstOfWeek === self::FIRST_IS_SUNDAY || $firstOfWeek === self::FIRST_IS_MONDAY) { + if ($firstOfWeek !== $this->firstOfWeek) { + $this->firstOfWeek = $firstOfWeek; + $this->prepareWeekDays(); + } + + return $this; + } else { + throw new InvalidArgumentException( + "First day of week has to be either 0 or 1, got '$firstOfWeek'" + ); + } + } + + protected function prepareWeekDays() + { + if ($this->firstOfWeekIsSunday()) { + $start = '2019-02-03'; + } else { + $start = '2019-02-04'; + } + + for ($i = 0; $i < 7; $i++) { + $day = strtotime("$start +{$i}days"); + $this->weekDays[] = $this->timeFormat->getWeekdayName($day); + $this->shortWeekDays[] = $this->timeFormat->getShortWeekdayName($day); + } + } + + public function listWeekDayNames() + { + return $this->weekDays; + } + + public function listShortWeekDayNames() + { + return $this->shortWeekDays; + } + + /** + * Either 'N' or 'w', depending on the first day of week + * + * @return string + */ + protected function getDowFormat() + { + if ($this->firstOfWeekIsMonday()) { + // N -> 1-7 (Mo-Su) + return 'N'; + } else { + // w -> 0-6 (Su-Sa) + return 'w'; + } + } + + /** + * @param $time + * @return int + */ + protected function getWeekDay($time) + { + return (int) date($this->getDowFormat(), $time); + } + + /** + * @param int $now + * @return array + */ + public function getDaysForWeek($now) + { + $formatDow = $this->getDowFormat(); + $today = date('Y-m-d', $now); + $day = $this->getFirstDayOfWeek($today); + $weekday = (int) date($formatDow, strtotime($day)); + $week = [$weekday => $day]; + for ($i = 1; $i < 7; $i++) { + $day = date('Y-m-d', strtotime("$day +1day")); + $weekday = (int) date($formatDow, strtotime($day)); + $week[$weekday] = $day; + } + + return $week; + } + + /** + * @param int $now + * @return array + */ + public function getWorkingDaysForWeek($now) + { + $formatDow = $this->getDowFormat(); + $today = date('Y-m-d', $now); + $day = $this->getFirstDayOfWeek($today, self::FIRST_IS_MONDAY); + $weekday = (int) date($formatDow, strtotime($day)); + $week = [$weekday => $day]; + for ($i = 1; $i < 5; $i++) { + $day = date('Y-m-d', strtotime("$day +1day")); + $weekday = (int) date($formatDow, strtotime($day)); + $week[$weekday] = $day; + } + + return $week; + } + + /** + * @param string $day + * @param int $firstOfWeek + * @return string + */ + public function getFirstDayOfWeek($day, $firstOfWeek = null) + { + if ($firstOfWeek === null) { + $firstOfWeek = $this->firstOfWeek; + } + $dow = $this->getWeekDay(strtotime($day)); + if ($dow > $firstOfWeek) { + $sub = $dow - $firstOfWeek; + return date('Y-m-d', strtotime("$day -{$sub}day")); + } else { + return $day; + } + } + + /** + * @param string $day + * @param int $firstOfWeek + * @return string + */ + protected function getLastDayOfWeek($day, $firstOfWeek = null) + { + if ($firstOfWeek === null) { + $firstOfWeek = $this->firstOfWeek; + } + $dow = $this->getWeekDay(strtotime($day)); + $lastOfWeek = $firstOfWeek + 6; + if ($dow < $lastOfWeek) { + $add = $lastOfWeek - $dow; + return static::expressionToDate(static::incDay($day, $add)); + } else { + return $day; + } + } + + public function getWeekOfTheYear($day) + { + $time = strtotime($day); + // 0 = Sunday + if ($this->firstOfWeekIsSunday() && $this->getWeekDay($time) === 0) { + if (substr($time, 4, 6) === '-12-31') { + return (int) date('W', strtotime(static::decDay($day))); + } else { + return (int) date('W', strtotime(static::incDay($day))); + } + } else { + return (int) date('W', $time); + } + } + + /** + * @param int $now + * @return array + */ + public function getWeeksForMonth($now) + { + $first = date('Y-m-01', $now); + $last = date('Y-m-d', strtotime("$first +1month -1day")); + + $formatDow = $this->getDowFormat(); + $end = $this->getLastDayOfWeek($last); + $day = $this->getFirstDayOfWeek($first); + $formerWeekOfTheYear = 0; + $weeks = []; + while ($day <= $end) { + $weekOfTheYear = $this->getWeekOfTheYear($day); + if ($weekOfTheYear !== $formerWeekOfTheYear) { + $weeks[$weekOfTheYear] = []; + $week = & $weeks[$weekOfTheYear]; + } + + $weekday = (int) date($formatDow, strtotime($day)); + $week[$weekday] = $day; + $day = date('Y-m-d', strtotime("$day +1day")); + $formerWeekOfTheYear = $weekOfTheYear; + } + + return $weeks; + } + + protected static function expressionToDate($expression) + { + return date('Y-m-d', strtotime($expression)); + } + + /** + * @param string $day + * @param int $increment days to add + * @return string + */ + protected static function incDay($day, $increment = 1) + { + return sprintf('%s +%dday', $day, $increment); + } + + protected static function decDay($day, $decrement = 1) + { + return sprintf('%s -%dday', $day, $decrement); + } +} diff --git a/vendor/gipfl/calendar/src/Widget/CalendarMonth.php b/vendor/gipfl/calendar/src/Widget/CalendarMonth.php new file mode 100644 index 0000000..2fe1c5b --- /dev/null +++ b/vendor/gipfl/calendar/src/Widget/CalendarMonth.php @@ -0,0 +1,177 @@ +<?php + +namespace gipfl\Calendar\Widget; + +use gipfl\Calendar\Calendar; +use gipfl\Format\LocalTimeFormat; +use gipfl\IcingaWeb2\Link; +use gipfl\IcingaWeb2\Url; +use gipfl\Translation\TranslationHelper; +use ipl\Html\BaseHtmlElement; +use ipl\Html\Html; +use ipl\Html\HtmlElement; + +/** + * WARNING: API will change + */ +class CalendarMonth extends BaseHtmlElement +{ + use TranslationHelper; + + protected $tag = 'div'; + + protected $defaultAttributes = [ + 'id' => 'calendar-wrap' + ]; + + /** @var Calendar */ + protected $calendar; + + /** @var int */ + protected $now; + + /** @var Url */ + protected $url; + + /** @var HtmlElement */ + protected $days = []; + + protected $timeFormatter; + + public function __construct(Calendar $calendar, Url $url, $now) + { + $this->now = $now; + $this->url = $url; + $this->calendar = $calendar; + $this->timeFormatter = new LocalTimeFormat(); + } + + protected function dayRow() + { + return Html::tag('ul', ['class' => 'days']); + } + + /** + * @param $day + * @return HtmlElement + */ + protected function getDay($day) + { + $this->ensureAssembled(); + return $this->days[$day]; + } + + protected function hasDay($day) + { + $this->ensureAssembled(); + + return isset($this->days[$day]); + } + + protected function createDay($day) + { + $title = (int) substr($day, -2); + + if ($title === 1) { + $title = sprintf( + '%d %s', + $title, + $this->timeFormatter->getShortMonthName(strtotime($day)) + ); + } + $li = Html::tag( + 'li', + ['class' => 'day'], + Html::tag('div', ['class' => 'date'], $title) + ); + + $this->days[$day] = $li; + + return $li; + } + + public function addEvent($time, $text) + { + $day = date('Y-m-d', $time); + if (! $this->hasDay($day)) { + return $this; + } + // $this->getDay($day)->add(Html::tag('div', ['class' => 'event'], [ + $this->getDay($day)->add(Html::tag('a', ['class' => 'event', 'href' => '#'], [ + Html::tag('div', [ + 'class' => 'event-time', + 'title' => date('Y-m-d H:i:s') + ], date('H:i', $time)), + Html::tag('div', ['class' => 'event-desc'], $text) + ])); + + return $this; + } + + protected function getFormerMonth() + { + $first = date('Y-m-01', $this->now); + + return date('Y-m-d', strtotime("$first -1month")); + } + + protected function getNextMonth() + { + $first = date('Y-m-01', $this->now); + + return date('Y-m-d', strtotime("$first +1month")); + } + + protected function getNavigationLinks() + { + return Html::tag('div', ['class' => 'calendar-navigation'], [ + Link::create('<', $this->url->with('day', $this->getFormerMonth())), + Link::create('>', $this->url->with('day', $this->getNextMonth())), + ]); + } + + protected function assemble() + { + $now = $this->now; + $today = date('Y-m-d', $now); + + $this->add( + Html::tag('header', [ + $this->getNavigationLinks(), + Html::tag('h1', date('F Y', $now)) + ]) + ); + + $calendar = Html::tag('div', ['class' => 'calendar']); + $calendar->add($this->weekdaysHeader()); + $thisMonth = substr($today, 0, 7); + + foreach ($this->calendar->getWeeksForMonth($now) as $cw => $week) { + $weekRow = $this->dayRow(); + $weekRow->add( + Html::tag('li', [ + 'class' => 'weekName' + ], Html::tag('span', sprintf($this->translate('Week %s'), $cw))) + ); + foreach ($week as $day) { + $weekRow->add($this->createDay($day)); + if (substr($day, 0, 7) !== $thisMonth) { + $this->getDay($day)->addAttributes(['class' => 'other-month']); + } + } + $calendar->add($weekRow); + } + + $this->add($calendar); + } + + protected function weekdaysHeader() + { + $ul = Html::tag('ul', ['class' => 'weekdays']); + foreach ($this->calendar->listWeekDayNames() as $weekday) { + $ul->add(Html::tag('li', $this->translate($weekday))); + } + + return $ul; + } +} diff --git a/vendor/gipfl/calendar/src/Widget/CalendarMonthSummary.php b/vendor/gipfl/calendar/src/Widget/CalendarMonthSummary.php new file mode 100644 index 0000000..950530f --- /dev/null +++ b/vendor/gipfl/calendar/src/Widget/CalendarMonthSummary.php @@ -0,0 +1,278 @@ +<?php + +namespace gipfl\Calendar\Widget; + +use gipfl\Calendar\Calendar; +use gipfl\Format\LocalTimeFormat; +use gipfl\IcingaWeb2\Link; +use gipfl\IcingaWeb2\Url; +use gipfl\Translation\TranslationHelper; +use ipl\Html\HtmlElement; +use ipl\Html\Table; + +class CalendarMonthSummary extends Table +{ + use TranslationHelper; + + protected $defaultAttributes = [ + 'data-base-target' => '_next', + 'class' => 'calendar', + ]; + + protected $today; + + protected $year; + + protected $month; + + protected $strMonth; + + protected $strToday; + + protected $days = []; + + /** @var Calendar|null */ + protected $calendar; + + protected $showWeekNumbers = true; + + protected $showOtherMonth = false; + + protected $showGrayFuture = true; + + protected $title; + + protected $color = '255, 128, 0'; + + protected $forcedMax; + + protected $timeFormat; + + public function __construct($year, $month) + { + $this->year = $year; + $this->month = $month; + $this->strMonth = sprintf('%d-%02d', $year, $month); + $this->strToday = date('Y-m-d'); + $this->timeFormat = new LocalTimeFormat(); + } + + public function setBaseColorRgb($red, $green, $blue) + { + $this->color = sprintf('%d, %d, %d', $red, $green, $blue); + + return $this; + } + + public function setCalendar(Calendar $calendar) + { + $this->calendar = $calendar; + + return $this; + } + + public function getCalendar() + { + if ($this->calendar === null) { + $this->calendar = new Calendar(); + } + + return $this->calendar; + } + + public function addEvents($events, Url $baseUrl) + { + if (empty($events)) { + return $this; + } + + if ($this->forcedMax === null) { + $max = max($events); + } else { + $max = $this->forcedMax; + } + + if ($max === 0 || $max === null) { + return $this; + } + + foreach ($events as $day => $count) { + if (! $this->hasDay($day)) { + continue; + } + + if (! $this->showOtherMonth && $this->dayIsInThisMonth($day)) { + continue; + } + + $text = (int) substr($day, -2); + + $link = Link::create($text, $baseUrl->with('day', $day)); + $alpha = $count / $max; + + if ($alpha > 0.4) { + $link->addAttributes(['style' => 'color: white;']); + } + $link->addAttributes([ + 'title' => sprintf('%d events', $count), + 'style' => sprintf( + 'background-color: rgba(%s, %.2F);', + $this->color, + $alpha + ) + ]); + + $this->getDay($day)->setContent($link); + } + + return $this; + } + + public function markNow($now = null) + { + if ($now === null) { + $now = time(); + } + $this->today = date('Y-m-d', $now); + + return $this; + } + + public function setTitle($title) + { + $this->title = $title; + + return $this; + } + + protected function getTitle() + { + if ($this->title === null) { + $this->title = $this->getMonthName() . ' ' . $this->year; + } + + return $this->title; + } + + public function forceMax($max) + { + $this->forcedMax = $max; + + return $this; + } + + protected function getMonthAsTimestamp() + { + return strtotime($this->strMonth . '-01'); + } + + protected function assemble() + { + $this->setCaption($this->getTitle()); + $this->getHeader()->add($this->createWeekdayHeader()); + $calendar = $this->getCalendar(); + foreach ($calendar->getWeeksForMonth($this->getMonthAsTimestamp()) as $cw => $week) { + $weekRow = $this->weekRow($cw); + foreach ($week as $wDay => $day) { + $dayElement = $this->createDay($day); + $otherMonth = $this->dayIsInThisMonth($day); + if ($wDay < 1 || $wDay > 5) { + $dayElement->addAttributes(['class' => 'weekend']); + } + $weekRow->add($dayElement); + } + $this->add($weekRow); + } + } + + /** + * @param $day + * @return HtmlElement + */ + protected function getDay($day) + { + $this->ensureAssembled(); + + return $this->days[$day]; + } + + protected function hasDay($day) + { + $this->ensureAssembled(); + + return isset($this->days[$day]); + } + + protected function dayIsInThisMonth($day) + { + return substr($day, 0, 7) !== $this->strMonth; + } + + protected function createDay($day) + { + $otherMonth = $this->dayIsInThisMonth($day); + $title = (int) substr($day, -2); + if ($otherMonth && ! $this->showOtherMonth) { + $title = ''; + } + $td = Table::td($title); + $this->days[$day] = $td; + + if ($otherMonth) { + $td->addAttributes(['class' => 'other-month']); + } elseif ($this->showGrayFuture && $day > $this->strToday) { + $td->addAttributes(['class' => 'future-day']); + } + + // TODO: today VS strToday?! + if ($day === $this->today) { + $td->addAttributes(['class' => 'today']); + } + + return $td; + } + + protected function weekRow($cw) + { + $row = Table::tr(); + + if ($this->showWeekNumbers) { + $row->add(Table::th(sprintf('%02d', $cw), [ + 'title' => sprintf($this->translate('Calendar Week %d'), $cw) + ])); + } + + return $row; + } + + protected function getMonthName() + { + return $this->timeFormat->getMonthName($this->getMonthAsTimestamp()); + } + + protected function createWeekdayHeader() + { + $calendar = $this->getCalendar(); + $cols = $calendar->listShortWeekDayNames(); + $row = Table::tr(); + if ($this->showWeekNumbers) { + $row->add(Table::th('')); + } + if ($calendar->firstOfWeekIsMonday()) { + $weekend = [6 => true, 7 => true]; + } else { + $weekend = [1 => true, 7 => true]; + } + $wDay = 0; + foreach ($cols as $day) { + $wDay++; + $col = Table::th($day); + if (isset($weekend[$wDay])) { + $col->addAttributes(['class' => 'weekend']); + } + $row->add($col); + } + + return $row; + } +} |