Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
index 93ca092598..4ed222b3d7 100644
--- a/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
+++ b/src/applications/calendar/query/PhabricatorCalendarEventQuery.php
@@ -1,289 +1,290 @@
<?php
final class PhabricatorCalendarEventQuery
extends PhabricatorCursorPagedPolicyAwareQuery {
private $ids;
private $phids;
private $rangeBegin;
private $rangeEnd;
private $inviteePHIDs;
private $creatorPHIDs;
private $isCancelled;
private $generateGhosts = false;
public function setGenerateGhosts($generate_ghosts) {
$this->generateGhosts = $generate_ghosts;
return $this;
}
public function withIDs(array $ids) {
$this->ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withDateRange($begin, $end) {
$this->rangeBegin = $begin;
$this->rangeEnd = $end;
return $this;
}
public function withInvitedPHIDs(array $phids) {
$this->inviteePHIDs = $phids;
return $this;
}
public function withCreatorPHIDs(array $phids) {
$this->creatorPHIDs = $phids;
return $this;
}
public function withIsCancelled($is_cancelled) {
$this->isCancelled = $is_cancelled;
return $this;
}
protected function getDefaultOrderVector() {
return array('start', 'id');
}
public function getOrderableColumns() {
return array(
'start' => array(
'table' => $this->getPrimaryTableAlias(),
'column' => 'dateFrom',
'reverse' => true,
'type' => 'int',
'unique' => false,
),
) + parent::getOrderableColumns();
}
protected function getPagingValueMap($cursor, array $keys) {
$event = $this->loadCursorObject($cursor);
return array(
'start' => $event->getDateFrom(),
'id' => $event->getID(),
);
}
protected function loadPage() {
$table = new PhabricatorCalendarEvent();
$conn_r = $table->establishConnection('r');
$viewer = $this->getViewer();
$data = queryfx_all(
$conn_r,
'SELECT event.* FROM %T event %Q %Q %Q %Q %Q',
$table->getTableName(),
$this->buildJoinClause($conn_r),
$this->buildWhereClause($conn_r),
$this->buildGroupClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
$events = $table->loadAllFromArray($data);
foreach ($events as $event) {
$event->applyViewerTimezone($this->getViewer());
}
if (!$this->generateGhosts) {
return $events;
}
foreach ($events as $event) {
$sequence_start = 0;
$instance_count = null;
+ $duration = $event->getDateTo() - $event->getDateFrom();
if ($event->getIsRecurring()) {
$frequency = $event->getFrequencyUnit();
$modify_key = '+1 '.$frequency;
if ($this->rangeBegin && $this->rangeBegin > $event->getDateFrom()) {
- $max_date = $this->rangeBegin;
+ $max_date = $this->rangeBegin - $duration;
$date = $event->getDateFrom();
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
while ($date < $max_date) {
// TODO: optimize this to not loop through all off-screen events
$sequence_start++;
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
$date = $datetime->modify($modify_key)->format('U');
}
$start = $this->rangeBegin;
} else {
- $start = $event->getDateFrom();
+ $start = $event->getDateFrom() - $duration;
}
$date = $start;
$start_datetime = PhabricatorTime::getDateTimeFromEpoch(
$start,
$viewer);
if ($this->rangeEnd) {
$end = $this->rangeEnd;
$instance_count = $sequence_start;
while ($date < $end) {
$instance_count++;
$datetime = PhabricatorTime::getDateTimeFromEpoch($date, $viewer);
$datetime->modify($modify_key);
$date = $datetime->format('U');
}
} else {
$instance_count = $this->getRawResultLimit();
}
$sequence_start = max(1, $sequence_start);
$max_sequence = $sequence_start + $instance_count;
for ($index = $sequence_start; $index < $max_sequence; $index++) {
$events[] = $event->generateNthGhost($index, $viewer);
}
}
}
return $events;
}
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn_r) {
$parts = parent::buildJoinClauseParts($conn_r);
if ($this->inviteePHIDs !== null) {
$parts[] = qsprintf(
$conn_r,
'JOIN %T invitee ON invitee.eventPHID = event.phid
AND invitee.status != %s',
id(new PhabricatorCalendarEventInvitee())->getTableName(),
PhabricatorCalendarEventInvitee::STATUS_UNINVITED);
}
return $parts;
}
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'event.id IN (%Ld)',
$this->ids);
}
if ($this->phids) {
$where[] = qsprintf(
$conn_r,
'event.phid IN (%Ls)',
$this->phids);
}
if ($this->rangeBegin) {
$where[] = qsprintf(
$conn_r,
'event.dateTo >= %d OR event.isRecurring = 1',
$this->rangeBegin);
}
if ($this->rangeEnd) {
$where[] = qsprintf(
$conn_r,
'event.dateFrom <= %d',
$this->rangeEnd);
}
if ($this->inviteePHIDs !== null) {
$where[] = qsprintf(
$conn_r,
'invitee.inviteePHID IN (%Ls)',
$this->inviteePHIDs);
}
if ($this->creatorPHIDs) {
$where[] = qsprintf(
$conn_r,
'event.userPHID IN (%Ls)',
$this->creatorPHIDs);
}
if ($this->isCancelled !== null) {
$where[] = qsprintf(
$conn_r,
'event.isCancelled = %d',
(int)$this->isCancelled);
}
$where[] = $this->buildPagingClause($conn_r);
return $this->formatWhereClause($where);
}
protected function getPrimaryTableAlias() {
return 'event';
}
protected function shouldGroupQueryResultRows() {
if ($this->inviteePHIDs !== null) {
return true;
}
return parent::shouldGroupQueryResultRows();
}
protected function getApplicationSearchObjectPHIDColumn() {
return 'event.phid';
}
public function getQueryApplicationClass() {
return 'PhabricatorCalendarApplication';
}
protected function willFilterPage(array $events) {
$range_start = $this->rangeBegin;
$range_end = $this->rangeEnd;
foreach ($events as $key => $event) {
$event_start = $event->getDateFrom();
$event_end = $event->getDateTo();
if ($range_start && $event_end < $range_start) {
unset($events[$key]);
}
if ($range_end && $event_start > $range_end) {
unset($events[$key]);
}
}
$phids = array();
foreach ($events as $event) {
$phids[] = $event->getPHID();
}
if ($events) {
$invitees = id(new PhabricatorCalendarEventInviteeQuery())
->setViewer($this->getViewer())
->withEventPHIDs($phids)
->execute();
$invitees = mgroup($invitees, 'getEventPHID');
} else {
$invitees = array();
}
foreach ($events as $event) {
$event_invitees = idx($invitees, $event->getPHID(), array());
$event->attachInvitees($event_invitees);
}
$events = msort($events, 'getDateFrom');
return $events;
}
}
diff --git a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
index d454248935..24c77b096e 100644
--- a/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
+++ b/src/applications/calendar/query/PhabricatorCalendarEventSearchEngine.php
@@ -1,515 +1,514 @@
<?php
final class PhabricatorCalendarEventSearchEngine
extends PhabricatorApplicationSearchEngine {
private $calendarYear;
private $calendarMonth;
private $calendarDay;
public function getResultTypeDescription() {
return pht('Calendar Events');
}
public function getApplicationClassName() {
return 'PhabricatorCalendarApplication';
}
public function buildSavedQueryFromRequest(AphrontRequest $request) {
$saved = new PhabricatorSavedQuery();
$saved->setParameter(
'rangeStart',
$this->readDateFromRequest($request, 'rangeStart'));
$saved->setParameter(
'rangeEnd',
$this->readDateFromRequest($request, 'rangeEnd'));
$saved->setParameter(
'upcoming',
$this->readBoolFromRequest($request, 'upcoming'));
$saved->setParameter(
'invitedPHIDs',
$this->readUsersFromRequest($request, 'invited'));
$saved->setParameter(
'creatorPHIDs',
$this->readUsersFromRequest($request, 'creators'));
$saved->setParameter(
'isCancelled',
$request->getStr('isCancelled'));
$saved->setParameter(
'display',
$request->getStr('display'));
return $saved;
}
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
$query = id(new PhabricatorCalendarEventQuery())
->setGenerateGhosts(true);
$viewer = $this->requireViewer();
$timezone = new DateTimeZone($viewer->getTimezoneIdentifier());
$min_range = $this->getDateFrom($saved)->getEpoch();
$max_range = $this->getDateTo($saved)->getEpoch();
if ($this->isMonthView($saved) ||
$this->isDayView($saved)) {
list($start_year, $start_month, $start_day) =
$this->getDisplayYearAndMonthAndDay($saved);
$start_day = new DateTime(
"{$start_year}-{$start_month}-{$start_day}",
$timezone);
$next = clone $start_day;
if ($this->isMonthView($saved)) {
$next->modify('+1 month');
} else if ($this->isDayView($saved)) {
$next->modify('+6 day');
}
$display_start = $start_day->format('U');
$display_end = $next->format('U');
$preferences = $viewer->loadPreferences();
$pref_week_day = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
$start_of_week = $preferences->getPreference($pref_week_day, 0);
$end_of_week = ($start_of_week + 6) % 7;
$first_of_month = $start_day->format('w');
$last_of_month = id(clone $next)->modify('-1 day')->format('w');
if (!$min_range || ($min_range < $display_start)) {
$min_range = $display_start;
if ($this->isMonthView($saved) &&
$first_of_month !== $start_of_week) {
$interim_day_num = ($first_of_month + 7 - $start_of_week) % 7;
$min_range = id(clone $start_day)
->modify('-'.$interim_day_num.' days')
->format('U');
}
}
if (!$max_range || ($max_range > $display_end)) {
$max_range = $display_end;
if ($this->isMonthView($saved) &&
$last_of_month !== $end_of_week) {
$interim_day_num = ($end_of_week + 7 - $last_of_month) % 7;
$max_range = id(clone $next)
->modify('+'.$interim_day_num.' days')
->format('U');
}
}
}
if ($saved->getParameter('upcoming')) {
if ($min_range) {
$min_range = max(time(), $min_range);
} else {
$min_range = time();
}
}
if ($min_range || $max_range) {
$query->withDateRange($min_range, $max_range);
}
$invited_phids = $saved->getParameter('invitedPHIDs');
if ($invited_phids) {
$query->withInvitedPHIDs($invited_phids);
}
$creator_phids = $saved->getParameter('creatorPHIDs');
if ($creator_phids) {
$query->withCreatorPHIDs($creator_phids);
}
$is_cancelled = $saved->getParameter('isCancelled', 'active');
switch ($is_cancelled) {
case 'active':
$query->withIsCancelled(false);
break;
case 'cancelled':
$query->withIsCancelled(true);
break;
}
return $query;
}
public function buildSearchForm(
AphrontFormView $form,
PhabricatorSavedQuery $saved) {
$range_start = $this->getDateFrom($saved);
$e_start = null;
$range_end = $this->getDateTo($saved);
$e_end = null;
if (!$range_start->isValid()) {
$this->addError(pht('Start date is not valid.'));
$e_start = pht('Invalid');
}
if (!$range_end->isValid()) {
$this->addError(pht('End date is not valid.'));
$e_end = pht('Invalid');
}
$start_epoch = $range_start->getEpoch();
$end_epoch = $range_end->getEpoch();
if ($start_epoch && $end_epoch && ($start_epoch > $end_epoch)) {
$this->addError(pht('End date must be after start date.'));
$e_start = pht('Invalid');
$e_end = pht('Invalid');
}
$upcoming = $saved->getParameter('upcoming');
$is_cancelled = $saved->getParameter('isCancelled', 'active');
$display = $saved->getParameter('display', 'month');
$invited_phids = $saved->getParameter('invitedPHIDs', array());
$creator_phids = $saved->getParameter('creatorPHIDs', array());
$resolution_types = array(
'active' => pht('Active Events Only'),
'cancelled' => pht('Cancelled Events Only'),
'both' => pht('Both Cancelled and Active Events'),
);
$display_options = array(
'month' => pht('Month View'),
'day' => pht('Day View (beta)'),
'list' => pht('List View'),
);
$form
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('creators')
->setLabel(pht('Created By'))
->setValue($creator_phids))
->appendControl(
id(new AphrontFormTokenizerControl())
->setDatasource(new PhabricatorPeopleDatasource())
->setName('invited')
->setLabel(pht('Invited'))
->setValue($invited_phids))
->appendChild(
id(new AphrontFormDateControl())
->setLabel(pht('Occurs After'))
->setUser($this->requireViewer())
->setName('rangeStart')
->setError($e_start)
->setValue($range_start))
->appendChild(
id(new AphrontFormDateControl())
->setLabel(pht('Occurs Before'))
->setUser($this->requireViewer())
->setName('rangeEnd')
->setError($e_end)
->setValue($range_end))
->appendChild(
id(new AphrontFormCheckboxControl())
->addCheckbox(
'upcoming',
1,
pht('Show only upcoming events.'),
$upcoming))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Cancelled Events'))
->setName('isCancelled')
->setValue($is_cancelled)
->setOptions($resolution_types))
->appendChild(
id(new AphrontFormSelectControl())
->setLabel(pht('Display Options'))
->setName('display')
->setValue($display)
->setOptions($display_options));
}
protected function getURI($path) {
return '/calendar/'.$path;
}
protected function getBuiltinQueryNames() {
$names = array(
'month' => pht('Month View'),
'day' => pht('Day View'),
'upcoming' => pht('Upcoming Events'),
'all' => pht('All Events'),
);
return $names;
}
public function setCalendarYearAndMonthAndDay($year, $month, $day = null) {
$this->calendarYear = $year;
$this->calendarMonth = $month;
$this->calendarDay = $day;
return $this;
}
public function buildSavedQueryFromBuiltin($query_key) {
$query = $this->newSavedQuery();
$query->setQueryKey($query_key);
switch ($query_key) {
case 'month':
return $query->setParameter('display', 'month');
case 'day':
return $query->setParameter('display', 'day');
case 'upcoming':
return $query->setParameter('upcoming', true);
case 'all':
return $query;
}
return parent::buildSavedQueryFromBuiltin($query_key);
}
protected function getRequiredHandlePHIDsForResultList(
array $objects,
PhabricatorSavedQuery $query) {
$phids = array();
foreach ($objects as $event) {
$phids[$event->getUserPHID()] = 1;
}
return array_keys($phids);
}
protected function renderResultList(
array $events,
PhabricatorSavedQuery $query,
array $handles) {
if ($this->isMonthView($query)) {
return $this->buildCalendarView($events, $query, $handles);
} else if ($this->isDayView($query)) {
return $this->buildCalendarDayView($events, $query, $handles);
}
assert_instances_of($events, 'PhabricatorCalendarEvent');
$viewer = $this->requireViewer();
$list = new PHUIObjectItemListView();
foreach ($events as $event) {
- // $href = '/E'.$event->getID();
$from = phabricator_datetime($event->getDateFrom(), $viewer);
$to = phabricator_datetime($event->getDateTo(), $viewer);
$creator_handle = $handles[$event->getUserPHID()];
$item = id(new PHUIObjectItemView())
->setHeader($event->getName())
->setHref($event->getURI())
->addByline(pht('Creator: %s', $creator_handle->renderLink()))
->addAttribute(pht('From %s to %s', $from, $to))
->addAttribute(id(new PhutilUTF8StringTruncator())
->setMaximumGlyphs(64)
->truncateString($event->getDescription()));
$list->addItem($item);
}
return $list;
}
private function buildCalendarView(
array $statuses,
PhabricatorSavedQuery $query,
array $handles) {
$viewer = $this->requireViewer();
$now = time();
list($start_year, $start_month) =
$this->getDisplayYearAndMonthAndDay($query);
$now_year = phabricator_format_local_time($now, $viewer, 'Y');
$now_month = phabricator_format_local_time($now, $viewer, 'm');
$now_day = phabricator_format_local_time($now, $viewer, 'j');
if ($start_month == $now_month && $start_year == $now_year) {
$month_view = new PHUICalendarMonthView(
$this->getDateFrom($query),
$this->getDateTo($query),
$start_month,
$start_year,
$now_day);
} else {
$month_view = new PHUICalendarMonthView(
$this->getDateFrom($query),
$this->getDateTo($query),
$start_month,
$start_year);
}
$month_view->setUser($viewer);
$phids = mpull($statuses, 'getUserPHID');
foreach ($statuses as $status) {
$viewer_is_invited = $status->getIsUserInvited($viewer->getPHID());
$event = new AphrontCalendarEventView();
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
$event->setIsAllDay($status->getIsAllDay());
$event->setIcon($status->getIcon());
$name_text = $handles[$status->getUserPHID()]->getName();
$status_text = $status->getName();
$event->setUserPHID($status->getUserPHID());
$event->setDescription(pht('%s (%s)', $name_text, $status_text));
$event->setName($status_text);
$event->setURI($status->getURI());
// $event->setEventID($status->getID());
$event->setViewerIsInvited($viewer_is_invited);
$month_view->addEvent($event);
}
$month_view->setBrowseURI(
$this->getURI('query/'.$query->getQueryKey().'/'));
return $month_view;
}
private function buildCalendarDayView(
array $statuses,
PhabricatorSavedQuery $query,
array $handles) {
$viewer = $this->requireViewer();
list($start_year, $start_month, $start_day) =
$this->getDisplayYearAndMonthAndDay($query);
$day_view = id(new PHUICalendarDayView(
$this->getDateFrom($query),
$this->getDateTo($query),
$start_year,
$start_month,
$start_day))
->setQuery($query->getQueryKey());
$day_view->setUser($viewer);
$phids = mpull($statuses, 'getUserPHID');
foreach ($statuses as $status) {
if ($status->getIsCancelled()) {
continue;
}
$viewer_is_invited = $status->getIsUserInvited($viewer->getPHID());
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$status,
PhabricatorPolicyCapability::CAN_EDIT);
$event = new AphrontCalendarEventView();
$event->setCanEdit($can_edit);
$event->setEventID($status->getID());
$event->setEpochRange($status->getDateFrom(), $status->getDateTo());
$event->setIsAllDay($status->getIsAllDay());
$event->setIcon($status->getIcon());
$event->setViewerIsInvited($viewer_is_invited);
$event->setName($status->getName());
$event->setURI($status->getURI());
$day_view->addEvent($event);
}
$day_view->setBrowseURI(
$this->getURI('query/'.$query->getQueryKey().'/'));
return $day_view;
}
private function getDisplayYearAndMonthAndDay(
PhabricatorSavedQuery $query) {
$viewer = $this->requireViewer();
if ($this->calendarYear && $this->calendarMonth) {
$start_year = $this->calendarYear;
$start_month = $this->calendarMonth;
$start_day = $this->calendarDay ? $this->calendarDay : 1;
} else {
$epoch = $this->getDateFrom($query)->getEpoch();
if (!$epoch) {
$epoch = $this->getDateTo($query)->getEpoch();
if (!$epoch) {
$epoch = time();
}
}
if ($this->isMonthView($query)) {
$day = 1;
} else {
$day = phabricator_format_local_time($epoch, $viewer, 'd');
}
$start_year = phabricator_format_local_time($epoch, $viewer, 'Y');
$start_month = phabricator_format_local_time($epoch, $viewer, 'm');
$start_day = $day;
}
return array($start_year, $start_month, $start_day);
}
public function getPageSize(PhabricatorSavedQuery $saved) {
return $saved->getParameter('limit', 1000);
}
private function getDateFrom(PhabricatorSavedQuery $saved) {
return $this->getDate($saved, 'rangeStart');
}
private function getDateTo(PhabricatorSavedQuery $saved) {
return $this->getDate($saved, 'rangeEnd');
}
private function getDate(PhabricatorSavedQuery $saved, $key) {
$viewer = $this->requireViewer();
$wild = $saved->getParameter($key);
if ($wild) {
$value = AphrontFormDateControlValue::newFromWild($viewer, $wild);
} else {
$value = AphrontFormDateControlValue::newFromEpoch(
$viewer,
PhabricatorTime::getTodayMidnightDateTime($viewer)->format('U'));
$value->setEnabled(false);
}
$value->setOptional(true);
return $value;
}
private function isMonthView(PhabricatorSavedQuery $query) {
if ($this->isDayView($query)) {
return false;
}
if ($query->getParameter('display') == 'month') {
return true;
}
}
private function isDayView(PhabricatorSavedQuery $query) {
if ($query->getParameter('display') == 'day') {
return true;
}
if ($this->calendarDay) {
return true;
}
return false;
}
}
diff --git a/src/view/phui/calendar/PHUICalendarMonthView.php b/src/view/phui/calendar/PHUICalendarMonthView.php
index d222450316..ed0558fdce 100644
--- a/src/view/phui/calendar/PHUICalendarMonthView.php
+++ b/src/view/phui/calendar/PHUICalendarMonthView.php
@@ -1,582 +1,590 @@
<?php
final class PHUICalendarMonthView extends AphrontView {
private $rangeStart;
private $rangeEnd;
private $day;
private $month;
private $year;
private $events = array();
private $browseURI;
private $image;
private $error;
public function setBrowseURI($browse_uri) {
$this->browseURI = $browse_uri;
return $this;
}
private function getBrowseURI() {
return $this->browseURI;
}
public function addEvent(AphrontCalendarEventView $event) {
$this->events[] = $event;
return $this;
}
public function setImage($uri) {
$this->image = $uri;
return $this;
}
public function setInfoView(PHUIInfoView $error) {
$this->error = $error;
return $this;
}
public function __construct(
$range_start,
$range_end,
$month,
$year,
$day = null) {
$this->rangeStart = $range_start;
$this->rangeEnd = $range_end;
$this->day = $day;
$this->month = $month;
$this->year = $year;
}
public function render() {
if (empty($this->user)) {
throw new PhutilInvalidStateException('setUser');
}
$events = msort($this->events, 'getEpochStart');
$days = $this->getDatesInMonth();
$cell_lists = array();
require_celerity_resource('phui-calendar-month-css');
foreach ($days as $day) {
$day_number = $day->format('j');
$class = 'phui-calendar-month-day';
$weekday = $day->format('w');
$day->setTime(0, 0, 0);
$day_start_epoch = $day->format('U');
$day_end_epoch = id(clone $day)->modify('+1 day')->format('U');
$list_events = array();
$all_day_events = array();
foreach ($events as $event) {
if ($event->getEpochStart() >= $day_end_epoch) {
break;
}
if ($event->getEpochStart() < $day_end_epoch &&
$event->getEpochEnd() > $day_start_epoch) {
if ($event->getIsAllDay()) {
$all_day_events[] = $event;
} else {
$list_events[] = $event;
}
}
}
+ $max_daily = 15;
+ $counter = 0;
+
$list = new PHUICalendarListView();
$list->setUser($this->user);
foreach ($all_day_events as $item) {
- $list->addEvent($item);
+ if ($counter <= $max_daily) {
+ $list->addEvent($item);
+ }
+ $counter++;
}
foreach ($list_events as $item) {
- $list->addEvent($item);
+ if ($counter <= $max_daily) {
+ $list->addEvent($item);
+ }
}
$uri = $this->getBrowseURI();
$uri = $uri.$day->format('Y').'/'.
$day->format('m').'/'.
$day->format('d').'/';
$cell_lists[] = array(
'list' => $list,
'date' => $day,
'uri' => $uri,
'count' => count($all_day_events) + count($list_events),
'class' => $class,
);
}
$rows = array();
$cell_lists_by_week = array_chunk($cell_lists, 7);
foreach ($cell_lists_by_week as $week_of_cell_lists) {
$cells = array();
$max_count = $this->getMaxDailyEventsForWeek($week_of_cell_lists);
foreach ($week_of_cell_lists as $cell_list) {
$cells[] = $this->getEventListCell($cell_list, $max_count);
}
$rows[] = phutil_tag('tr', array(), $cells);
$cells = array();
foreach ($week_of_cell_lists as $cell_list) {
$cells[] = $this->getDayNumberCell($cell_list);
}
$rows[] = phutil_tag('tr', array(), $cells);
}
$header = $this->getDayNamesHeader();
$table = phutil_tag(
'table',
array('class' => 'phui-calendar-view'),
array(
$header,
$rows,
));
$warnings = $this->getQueryRangeWarning();
$box = id(new PHUIObjectBoxView())
->setHeader($this->renderCalendarHeader($this->getDateTime()))
->appendChild($table)
->setFormErrors($warnings);
if ($this->error) {
$box->setInfoView($this->error);
}
return $box;
}
private function getMaxDailyEventsForWeek($week_of_cell_lists) {
$max_count = 0;
foreach ($week_of_cell_lists as $cell_list) {
if ($cell_list['count'] > $max_count) {
$max_count = $cell_list['count'];
}
}
return $max_count;
}
private function getEventListCell($event_list, $max_count = 0) {
$list = $event_list['list'];
$class = $event_list['class'];
$uri = $event_list['uri'];
$count = $event_list['count'];
$viewer_is_invited = $list->getIsViewerInvitedOnList();
$event_count_badge = $this->getEventCountBadge($count, $viewer_is_invited);
$cell_day_secret_link = $this->getHiddenDayLink($uri, $max_count, 125);
$cell_data_div = phutil_tag(
'div',
array(
'class' => 'phui-calendar-month-cell-div',
),
array(
$cell_day_secret_link,
$event_count_badge,
$list,
));
return phutil_tag(
'td',
array(
'class' => 'phui-calendar-month-event-list '.$class,
),
$cell_data_div);
}
private function getDayNumberCell($event_list) {
$class = $event_list['class'];
$date = $event_list['date'];
$cell_day_secret_link = null;
$week_number = null;
if ($date) {
$uri = $event_list['uri'];
$cell_day_secret_link = $this->getHiddenDayLink($uri, 0, 25);
$cell_day = phutil_tag(
'a',
array(
'class' => 'phui-calendar-date-number',
'href' => $uri,
),
$date->format('j'));
if ($date->format('w') == 1) {
$week_number = phutil_tag(
'a',
array(
'class' => 'phui-calendar-week-number',
'href' => $uri,
),
$date->format('W'));
}
} else {
$cell_day = null;
}
if ($date && $date->format('j') == $this->day &&
$date->format('m') == $this->month) {
$today_class = 'phui-calendar-today-slot phui-calendar-today';
} else {
$today_class = 'phui-calendar-today-slot';
}
if ($this->isDateInCurrentWeek($date)) {
$today_class .= ' phui-calendar-this-week';
}
$last_week_day = 6;
if ($date->format('w') == $last_week_day) {
$today_class .= ' last-weekday';
}
$today_slot = phutil_tag (
'div',
array(
'class' => $today_class,
),
null);
$cell_div = phutil_tag(
'div',
array(
'class' => 'phui-calendar-month-cell-div',
),
array(
$cell_day_secret_link,
$week_number,
$cell_day,
$today_slot,
));
return phutil_tag(
'td',
array(
'class' => 'phui-calendar-date-number-container '.$class,
),
$cell_div);
}
private function isDateInCurrentWeek($date) {
list($week_start_date, $week_end_date) = $this->getThisWeekRange();
if ($date->format('U') < $week_end_date->format('U') &&
$date->format('U') >= $week_start_date->format('U')) {
return true;
}
return false;
}
private function getEventCountBadge($count, $viewer_is_invited) {
$class = 'phui-calendar-month-count-badge';
if ($viewer_is_invited) {
$class = $class.' viewer-invited-day-badge';
}
$event_count = null;
if ($count > 0) {
$event_count = phutil_tag(
'div',
array(
'class' => $class,
),
$count);
}
return phutil_tag(
'div',
array(
'class' => 'phui-calendar-month-event-count',
),
$event_count);
}
private function getHiddenDayLink($uri, $count, $max_height) {
// approximately the height of the tallest cell
$height = 18 * $count + 5;
$height = ($height > $max_height) ? $height : $max_height;
$height_style = 'height: '.$height.'px';
return phutil_tag(
'a',
array(
'class' => 'phui-calendar-month-secret-link',
'style' => $height_style,
'href' => $uri,
),
null);
}
private function getDayNamesHeader() {
list($week_start, $week_end) = $this->getWeekStartAndEnd();
$weekday_names = array(
$this->getDayHeader(pht('Sun'), pht('Sunday'), true),
$this->getDayHeader(pht('Mon'), pht('Monday')),
$this->getDayHeader(pht('Tue'), pht('Tuesday')),
$this->getDayHeader(pht('Wed'), pht('Wednesday')),
$this->getDayHeader(pht('Thu'), pht('Thursday')),
$this->getDayHeader(pht('Fri'), pht('Friday')),
$this->getDayHeader(pht('Sat'), pht('Saturday'), true),
);
$sorted_weekday_names = array();
for ($i = $week_start; $i < ($week_start + 7); $i++) {
$sorted_weekday_names[] = $weekday_names[$i % 7];
}
return phutil_tag(
'tr',
array('class' => 'phui-calendar-day-of-week-header'),
$sorted_weekday_names);
}
private function getDayHeader($short, $long, $is_weekend = false) {
$class = null;
if ($is_weekend) {
$class = 'weekend-day-header';
}
$day = array();
$day[] = phutil_tag(
'span',
array(
'class' => 'long-weekday-name',
),
$long);
$day[] = phutil_tag(
'span',
array(
'class' => 'short-weekday-name',
),
$short);
return phutil_tag(
'th',
array(
'class' => $class,
),
$day);
}
private function renderCalendarHeader(DateTime $date) {
$button_bar = null;
// check for a browseURI, which means we need "fancy" prev / next UI
$uri = $this->getBrowseURI();
if ($uri) {
list($prev_year, $prev_month) = $this->getPrevYearAndMonth();
$prev_uri = $uri.$prev_year.'/'.$prev_month.'/';
list($next_year, $next_month) = $this->getNextYearAndMonth();
$next_uri = $uri.$next_year.'/'.$next_month.'/';
$button_bar = new PHUIButtonBarView();
$left_icon = id(new PHUIIconView())
->setIconFont('fa-chevron-left bluegrey');
$left = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::GREY)
->setHref($prev_uri)
->setTitle(pht('Previous Month'))
->setIcon($left_icon);
$right_icon = id(new PHUIIconView())
->setIconFont('fa-chevron-right bluegrey');
$right = id(new PHUIButtonView())
->setTag('a')
->setColor(PHUIButtonView::GREY)
->setHref($next_uri)
->setTitle(pht('Next Month'))
->setIcon($right_icon);
$button_bar->addButton($left);
$button_bar->addButton($right);
}
$header = id(new PHUIHeaderView())
->setHeader($date->format('F Y'));
if ($button_bar) {
$header->setButtonBar($button_bar);
}
if ($this->image) {
$header->setImage($this->image);
}
return $header;
}
private function getQueryRangeWarning() {
$errors = array();
$range_start_epoch = $this->rangeStart->getEpoch();
$range_end_epoch = $this->rangeEnd->getEpoch();
$month_start = $this->getDateTime();
$month_end = id(clone $month_start)->modify('+1 month');
$month_start = $month_start->format('U');
$month_end = $month_end->format('U') - 1;
if (($range_start_epoch != null &&
$range_start_epoch < $month_end &&
$range_start_epoch > $month_start) ||
($range_end_epoch != null &&
$range_end_epoch < $month_end &&
$range_end_epoch > $month_start)) {
$errors[] = pht('Part of the month is out of range');
}
if (($this->rangeEnd->getEpoch() != null &&
$this->rangeEnd->getEpoch() < $month_start) ||
($this->rangeStart->getEpoch() != null &&
$this->rangeStart->getEpoch() > $month_end)) {
$errors[] = pht('Month is out of query range');
}
return $errors;
}
private function getNextYearAndMonth() {
$next = $this->getDateTime();
$next->modify('+1 month');
return array(
$next->format('Y'),
$next->format('m'),
);
}
private function getPrevYearAndMonth() {
$prev = $this->getDateTime();
$prev->modify('-1 month');
return array(
$prev->format('Y'),
$prev->format('m'),
);
}
/**
* Return a DateTime object representing the first moment in each day in the
* month, according to the user's locale.
*
* @return list List of DateTimes, one for each day.
*/
private function getDatesInMonth() {
$user = $this->user;
$timezone = new DateTimeZone($user->getTimezoneIdentifier());
$month = $this->month;
$year = $this->year;
list($next_year, $next_month) = $this->getNextYearAndMonth();
$end_date = new DateTime("{$next_year}-{$next_month}-01", $timezone);
list($start_of_week, $end_of_week) = $this->getWeekStartAndEnd();
$days_in_month = id(clone $end_date)->modify('-1 day')->format('d');
$first_month_day_date = new DateTime("{$year}-{$month}-01", $timezone);
$last_month_day_date = id(clone $end_date)->modify('-1 day');
$first_weekday_of_month = $first_month_day_date->format('w');
$last_weekday_of_month = $last_month_day_date->format('w');
$day_date = id(clone $first_month_day_date);
$num_days_display = $days_in_month;
if ($start_of_week !== $first_weekday_of_month) {
$interim_start_num = ($first_weekday_of_month + 7 - $start_of_week) % 7;
$num_days_display += $interim_start_num;
$day_date->modify('-'.$interim_start_num.' days');
}
if ($end_of_week !== $last_weekday_of_month) {
$interim_end_day_num = ($end_of_week - $last_weekday_of_month + 7) % 7;
$num_days_display += $interim_end_day_num;
$end_date->modify('+'.$interim_end_day_num.' days');
}
$days = array();
for ($day = 1; $day <= $num_days_display; $day++) {
$day_epoch = $day_date->format('U');
$end_epoch = $end_date->format('U');
if ($day_epoch >= $end_epoch) {
break;
} else {
$days[] = clone $day_date;
}
$day_date->modify('+1 day');
}
return $days;
}
private function getTodayMidnight() {
$viewer = $this->getUser();
$today = new DateTime('@'.time());
$today->setTimeZone($viewer->getTimeZone());
$today->setTime(0, 0, 0);
return $today;
}
private function getThisWeekRange() {
list($week_start, $week_end) = $this->getWeekStartAndEnd();
$today = $this->getTodayMidnight();
$date_weekday = $today->format('w');
$days_from_week_start = ($date_weekday + 7 - $week_start) % 7;
$days_to_week_end = 7 - $days_from_week_start;
$modify = '-'.$days_from_week_start.' days';
$week_start_date = id(clone $today)->modify($modify);
$modify = '+'.$days_to_week_end.' days';
$week_end_date = id(clone $today)->modify($modify);
return array($week_start_date, $week_end_date);
}
private function getWeekStartAndEnd() {
$preferences = $this->user->loadPreferences();
$pref_week_start = PhabricatorUserPreferences::PREFERENCE_WEEK_START_DAY;
$week_start = $preferences->getPreference($pref_week_start, 0);
$week_end = ($week_start + 6) % 7;
return array($week_start, $week_end);
}
private function getDateTime() {
$user = $this->user;
$timezone = new DateTimeZone($user->getTimezoneIdentifier());
$month = $this->month;
$year = $this->year;
$date = new DateTime("{$year}-{$month}-01 ", $timezone);
return $date;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 2, 7:37 AM (23 h, 13 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
431724
Default Alt Text
(39 KB)

Event Timeline