mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
Build a basic calendar view
Summary: This is a very small step toward building a Status and possibly an Oncall tool. Build a calendar view which renders months. Much of my hesitance to bang these tools out is that dealing with dates/calendaring is basically horrible, so I'm trying to ease into it. This calendar is locale-aware and all that jazz. Test Plan: - See: https://secure.phabricator.com/file/view/PHID-FILE-c07a9c663a7d040d2529/ - Verified that months have the right number of days, today is the right day of the week, months begin on the day after previous months end on, etc. Reviewed By: aran Reviewers: jungejason, tuomaspelkonen, aran Commenters: cwbeck, jungejason CC: blair, aran, epriestley, cwbeck, jungejason Differential Revision: 791
This commit is contained in:
parent
fa49c6c52d
commit
e35d72f489
10 changed files with 316 additions and 0 deletions
|
@ -16,6 +16,15 @@ celerity_register_resource_map(array(
|
|||
),
|
||||
'disk' => '/rsrc/css/aphront/attached-file-view.css',
|
||||
),
|
||||
'aphront-calendar-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/7036c676/rsrc/css/aphront/calendar-view.css',
|
||||
'type' => 'css',
|
||||
'requires' =>
|
||||
array(
|
||||
),
|
||||
'disk' => '/rsrc/css/aphront/calendar-view.css',
|
||||
),
|
||||
'aphront-contextbar-view-css' =>
|
||||
array(
|
||||
'uri' => '/res/3e2f3045/rsrc/css/aphront/context-bar.css',
|
||||
|
|
|
@ -15,6 +15,7 @@ phutil_register_library_map(array(
|
|||
'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration',
|
||||
'AphrontAttachedFileView' => 'view/control/attachedfile',
|
||||
'AphrontCSRFException' => 'aphront/exception/csrf',
|
||||
'AphrontCalendarMonthView' => 'applications/calendar/view/month',
|
||||
'AphrontContextBarView' => 'view/layout/contextbar',
|
||||
'AphrontController' => 'aphront/controller',
|
||||
'AphrontCrumbsView' => 'view/layout/crumbs',
|
||||
|
@ -301,6 +302,8 @@ phutil_register_library_map(array(
|
|||
'ManiphestView' => 'applications/maniphest/view/base',
|
||||
'Phabricator404Controller' => 'applications/base/controller/404',
|
||||
'PhabricatorAuthController' => 'applications/auth/controller/base',
|
||||
'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/browse',
|
||||
'PhabricatorCalendarController' => 'applications/calendar/controller/base',
|
||||
'PhabricatorConduitAPIController' => 'applications/conduit/controller/api',
|
||||
'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/token',
|
||||
'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog',
|
||||
|
@ -664,6 +667,7 @@ phutil_register_library_map(array(
|
|||
'AphrontAjaxResponse' => 'AphrontResponse',
|
||||
'AphrontAttachedFileView' => 'AphrontView',
|
||||
'AphrontCSRFException' => 'AphrontException',
|
||||
'AphrontCalendarMonthView' => 'AphrontView',
|
||||
'AphrontContextBarView' => 'AphrontView',
|
||||
'AphrontCrumbsView' => 'AphrontView',
|
||||
'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration',
|
||||
|
@ -873,6 +877,8 @@ phutil_register_library_map(array(
|
|||
'ManiphestView' => 'AphrontView',
|
||||
'Phabricator404Controller' => 'PhabricatorController',
|
||||
'PhabricatorAuthController' => 'PhabricatorController',
|
||||
'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController',
|
||||
'PhabricatorCalendarController' => 'PhabricatorController',
|
||||
'PhabricatorConduitAPIController' => 'PhabricatorConduitController',
|
||||
'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO',
|
||||
'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO',
|
||||
|
|
|
@ -356,6 +356,10 @@ class AphrontDefaultApplicationConfiguration
|
|||
'preview/$' => 'PhrictionDocumentPreviewController',
|
||||
'diff/(?P<id>\d+)/$' => 'PhrictionDiffController',
|
||||
),
|
||||
|
||||
'/calendar/' => array(
|
||||
'$' => 'PhabricatorCalendarBrowseController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
abstract class PhabricatorCalendarController extends PhabricatorController {
|
||||
|
||||
public function buildStandardPageResponse($view, array $data) {
|
||||
|
||||
$page = $this->buildStandardPageView();
|
||||
|
||||
$page->setApplicationName('Calendar');
|
||||
$page->setBaseURI('/calendar/');
|
||||
$page->setTitle(idx($data, 'title'));
|
||||
|
||||
// Unicode has a calendar character but it's in some distant code plane,
|
||||
// use "keyboard" since it looks vaguely similar.
|
||||
$page->setGlyph("\xE2\x8C\xA8");
|
||||
|
||||
$page->appendChild($view);
|
||||
$page->setTabs(
|
||||
array(
|
||||
),
|
||||
idx($data, 'tab'));
|
||||
|
||||
$response = new AphrontWebpageResponse();
|
||||
return $response->setContent($page->render());
|
||||
}
|
||||
|
||||
}
|
15
src/applications/calendar/controller/base/__init__.php
Normal file
15
src/applications/calendar/controller/base/__init__.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'aphront/response/webpage');
|
||||
phutil_require_module('phabricator', 'applications/base/controller/base');
|
||||
|
||||
phutil_require_module('phutil', 'utils');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorCalendarController.php');
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
class PhabricatorCalendarBrowseController
|
||||
extends PhabricatorCalendarController {
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$months = array();
|
||||
for ($ii = 1; $ii <= 12; $ii++) {
|
||||
$month_view = new AphrontCalendarMonthView($ii, 2011);
|
||||
$month_view->setUser($user);
|
||||
$months[] = '<div style="padding: 2em;">';
|
||||
$months[] = $month_view;
|
||||
$months[] = '</div>';
|
||||
}
|
||||
|
||||
return $this->buildStandardPageResponse(
|
||||
$months,
|
||||
array(
|
||||
'title' => 'Calendar',
|
||||
));
|
||||
}
|
||||
}
|
13
src/applications/calendar/controller/browse/__init__.php
Normal file
13
src/applications/calendar/controller/browse/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'applications/calendar/controller/base');
|
||||
phutil_require_module('phabricator', 'applications/calendar/view/month');
|
||||
|
||||
|
||||
phutil_require_source('PhabricatorCalendarBrowseController.php');
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2011 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
final class AphrontCalendarMonthView extends AphrontView {
|
||||
|
||||
private $user;
|
||||
private $month;
|
||||
private $year;
|
||||
|
||||
public function setUser(PhabricatorUser $user) {
|
||||
$this->user = $user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __construct($month, $year) {
|
||||
$this->month = $month;
|
||||
$this->year = $year;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
if (empty($this->user)) {
|
||||
throw new Exception("Call setUser() before render()!");
|
||||
}
|
||||
|
||||
$days = $this->getDatesInMonth();
|
||||
|
||||
require_celerity_resource('aphront-calendar-view-css');
|
||||
|
||||
$first = reset($days);
|
||||
$empty = $first->format('w');
|
||||
|
||||
$markup = array();
|
||||
|
||||
for ($ii = 0; $ii < $empty; $ii++) {
|
||||
$markup[] = null;
|
||||
}
|
||||
|
||||
foreach ($days as $day) {
|
||||
$markup[] =
|
||||
'<div class="aphront-calendar-day-of-month">'.
|
||||
$day->format('j').
|
||||
'</div>';
|
||||
}
|
||||
|
||||
$table = array();
|
||||
$rows = array_chunk($markup, 7);
|
||||
foreach ($rows as $row) {
|
||||
$table[] = '<tr>';
|
||||
while (count($row) < 7) {
|
||||
$row[] = null;
|
||||
}
|
||||
foreach ($row as $cell) {
|
||||
$table[] = '<td>'.$cell.'</td>';
|
||||
}
|
||||
$table[] = '</tr>';
|
||||
}
|
||||
$table =
|
||||
'<table class="aphront-calendar-view">'.
|
||||
'<tr class="aphront-calendar-month-year-header">'.
|
||||
'<th colspan="7">'.$first->format('F Y').'</th>'.
|
||||
'</tr>'.
|
||||
'<tr class="aphront-calendar-day-of-week-header">'.
|
||||
'<th>Sun</th>'.
|
||||
'<th>Mon</th>'.
|
||||
'<th>Tue</th>'.
|
||||
'<th>Wed</th>'.
|
||||
'<th>Thu</th>'.
|
||||
'<th>Fri</th>'.
|
||||
'<th>Sat</th>'.
|
||||
'</tr>'.
|
||||
implode("\n", $table).
|
||||
'</table>';
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
// Find the year and month numbers of the following month, so we can
|
||||
// determine when this month ends.
|
||||
$next_year = $year;
|
||||
$next_month = $month + 1;
|
||||
if ($next_month == 13) {
|
||||
$next_year = $year + 1;
|
||||
$next_month = 1;
|
||||
}
|
||||
|
||||
$end_date = new DateTime("{$next_year}-{$next_month}-01", $timezone);
|
||||
$end_epoch = $end_date->format('U');
|
||||
|
||||
$days = array();
|
||||
for ($day = 1; $day <= 31; $day++) {
|
||||
$day_date = new DateTime("{$year}-{$month}-{$day}", $timezone);
|
||||
$day_epoch = $day_date->format('U');
|
||||
if ($day_epoch >= $end_epoch) {
|
||||
break;
|
||||
} else {
|
||||
$days[] = $day_date;
|
||||
}
|
||||
}
|
||||
|
||||
return $days;
|
||||
}
|
||||
}
|
13
src/applications/calendar/view/month/__init__.php
Normal file
13
src/applications/calendar/view/month/__init__.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
/**
|
||||
* This file is automatically generated. Lint this module to rebuild it.
|
||||
* @generated
|
||||
*/
|
||||
|
||||
|
||||
|
||||
phutil_require_module('phabricator', 'infrastructure/celerity/api');
|
||||
phutil_require_module('phabricator', 'view/base');
|
||||
|
||||
|
||||
phutil_require_source('AphrontCalendarMonthView.php');
|
41
webroot/rsrc/css/aphront/calendar-view.css
Normal file
41
webroot/rsrc/css/aphront/calendar-view.css
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @provides aphront-calendar-view-css
|
||||
*/
|
||||
|
||||
.aphront-calendar-view {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #fdfdfd;
|
||||
border: 2px solid #003366;
|
||||
}
|
||||
|
||||
tr.aphront-calendar-month-year-header th {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
padding: .5em;
|
||||
color: white;
|
||||
background: #003366;
|
||||
}
|
||||
|
||||
tr.aphront-calendar-day-of-week-header th {
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
padding: .25em;
|
||||
color: white;
|
||||
background: #3366BB;
|
||||
}
|
||||
|
||||
table.aphront-calendar-view td {
|
||||
border: 1px solid #dfdfdf;
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
table.aphront-calendar-view td div {
|
||||
min-height: 70px;
|
||||
}
|
||||
|
||||
.aphront-calendar-day-of-month {
|
||||
text-align: right;
|
||||
color: #666666;
|
||||
}
|
Loading…
Reference in a new issue