mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-14 02:42:40 +01:00
Modernize Countdown somewhat
Summary: Far from perfect, but better? Test Plan: {F51153} {F51154} {F51155} Reviewers: btrahan, chad Reviewed By: chad CC: aran Differential Revision: https://secure.phabricator.com/D6533
This commit is contained in:
parent
5f78a6953f
commit
974997f6bc
15 changed files with 424 additions and 230 deletions
|
@ -1407,7 +1407,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'javelin-behavior-countdown-timer' =>
|
'javelin-behavior-countdown-timer' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/3c52aac2/rsrc/js/application/countdown/timer.js',
|
'uri' => '/res/13d40efa/rsrc/js/application/countdown/timer.js',
|
||||||
'type' => 'js',
|
'type' => 'js',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
@ -3100,7 +3100,7 @@ celerity_register_resource_map(array(
|
||||||
),
|
),
|
||||||
'phabricator-countdown-css' =>
|
'phabricator-countdown-css' =>
|
||||||
array(
|
array(
|
||||||
'uri' => '/res/0f646281/rsrc/css/application/countdown/timer.css',
|
'uri' => '/res/c4a30296/rsrc/css/application/countdown/timer.css',
|
||||||
'type' => 'css',
|
'type' => 'css',
|
||||||
'requires' =>
|
'requires' =>
|
||||||
array(
|
array(
|
||||||
|
|
|
@ -1000,6 +1000,8 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCountdownPHIDTypeCountdown' => 'applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php',
|
'PhabricatorCountdownPHIDTypeCountdown' => 'applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php',
|
||||||
'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php',
|
'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php',
|
||||||
'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php',
|
'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php',
|
||||||
|
'PhabricatorCountdownSearchEngine' => 'applications/countdown/query/PhabricatorCountdownSearchEngine.php',
|
||||||
|
'PhabricatorCountdownView' => 'applications/countdown/view/PhabricatorCountdownView.php',
|
||||||
'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php',
|
'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php',
|
||||||
'PhabricatorCountedToggleButtonsExample' => 'applications/uiexample/examples/PhabricatorCountedToggleButtonsExample.php',
|
'PhabricatorCountedToggleButtonsExample' => 'applications/uiexample/examples/PhabricatorCountedToggleButtonsExample.php',
|
||||||
'PhabricatorCrumbView' => 'view/layout/PhabricatorCrumbView.php',
|
'PhabricatorCrumbView' => 'view/layout/PhabricatorCrumbView.php',
|
||||||
|
@ -2995,10 +2997,16 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
|
'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO',
|
||||||
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownEditController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCountdownListController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownListController' =>
|
||||||
|
array(
|
||||||
|
0 => 'PhabricatorCountdownController',
|
||||||
|
1 => 'PhabricatorApplicationSearchResultsControllerInterface',
|
||||||
|
),
|
||||||
'PhabricatorCountdownPHIDTypeCountdown' => 'PhabricatorPHIDType',
|
'PhabricatorCountdownPHIDTypeCountdown' => 'PhabricatorPHIDType',
|
||||||
'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'PhabricatorCountdownRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
'PhabricatorCountdownRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
||||||
|
'PhabricatorCountdownSearchEngine' => 'PhabricatorApplicationSearchEngine',
|
||||||
|
'PhabricatorCountdownView' => 'AphrontTagView',
|
||||||
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
|
'PhabricatorCountdownViewController' => 'PhabricatorCountdownController',
|
||||||
'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample',
|
'PhabricatorCountedToggleButtonsExample' => 'PhabricatorUIExample',
|
||||||
'PhabricatorCrumbView' => 'AphrontView',
|
'PhabricatorCrumbView' => 'AphrontView',
|
||||||
|
|
|
@ -38,7 +38,7 @@ final class PhabricatorApplicationCountdown extends PhabricatorApplication {
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/countdown/' => array(
|
'/countdown/' => array(
|
||||||
''
|
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||||
=> 'PhabricatorCountdownListController',
|
=> 'PhabricatorCountdownListController',
|
||||||
'(?P<id>[1-9]\d*)/'
|
'(?P<id>[1-9]\d*)/'
|
||||||
=> 'PhabricatorCountdownViewController',
|
=> 'PhabricatorCountdownViewController',
|
||||||
|
|
|
@ -5,22 +5,27 @@
|
||||||
*/
|
*/
|
||||||
abstract class PhabricatorCountdownController extends PhabricatorController {
|
abstract class PhabricatorCountdownController extends PhabricatorController {
|
||||||
|
|
||||||
public function buildSideNavView() {
|
public function buildSideNavView($for_app = false) {
|
||||||
$user = $this->getRequest()->getUser();
|
$user = $this->getRequest()->getUser();
|
||||||
|
|
||||||
$nav = new AphrontSideNavFilterView();
|
$nav = new AphrontSideNavFilterView();
|
||||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||||
|
|
||||||
$nav->addFilter('', pht('All Countdowns'),
|
if ($for_app) {
|
||||||
$this->getApplicationURI(''));
|
$nav->addFilter('create', pht('Create Countdown'));
|
||||||
$nav->addFilter('', pht('Create Countdown'),
|
}
|
||||||
$this->getApplicationURI('edit/'));
|
|
||||||
|
id(new PhabricatorCountdownSearchEngine())
|
||||||
|
->setViewer($user)
|
||||||
|
->addNavigationItems($nav->getMenu());
|
||||||
|
|
||||||
|
$nav->selectFilter(null);
|
||||||
|
|
||||||
return $nav;
|
return $nav;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildApplicationMenu() {
|
public function buildApplicationMenu() {
|
||||||
return $this->buildSideNavView()->getMenu();
|
return $this->buildSideNavView($for_app = true)->getMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function buildApplicationCrumbs() {
|
public function buildApplicationCrumbs() {
|
||||||
|
|
|
@ -20,6 +20,11 @@ final class PhabricatorCountdownDeleteController
|
||||||
$countdown = id(new PhabricatorCountdownQuery())
|
$countdown = id(new PhabricatorCountdownQuery())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($this->id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
if (!$countdown) {
|
if (!$countdown) {
|
||||||
|
|
|
@ -15,25 +15,22 @@ final class PhabricatorCountdownEditController
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$action_label = pht('Create Countdown');
|
|
||||||
|
|
||||||
if ($this->id) {
|
if ($this->id) {
|
||||||
$countdown = id(new PhabricatorCountdownQuery())
|
$countdown = id(new PhabricatorCountdownQuery())
|
||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withIDs(array($this->id))
|
->withIDs(array($this->id))
|
||||||
|
->requireCapabilities(
|
||||||
|
array(
|
||||||
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
|
))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
// If no countdown is found
|
// If no countdown is found
|
||||||
if (!$countdown) {
|
if (!$countdown) {
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (($countdown->getAuthorPHID() != $user->getPHID())
|
|
||||||
&& $user->getIsAdmin() == false) {
|
|
||||||
return new Aphront403Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
$action_label = pht('Update Countdown');
|
|
||||||
} else {
|
} else {
|
||||||
$countdown = new PhabricatorCountdown();
|
$countdown = new PhabricatorCountdown();
|
||||||
$countdown->setEpoch(time());
|
$countdown->setEpoch(time());
|
||||||
|
@ -87,9 +84,31 @@ final class PhabricatorCountdownEditController
|
||||||
$display_epoch = $request->getStr('epoch');
|
$display_epoch = $request->getStr('epoch');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$crumbs = $this->buildApplicationCrumbs();
|
||||||
|
|
||||||
|
$cancel_uri = '/countdown/';
|
||||||
|
if ($countdown->getID()) {
|
||||||
|
$cancel_uri = '/countdown/'.$countdown->getID().'/';
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName('C'.$countdown->getID())
|
||||||
|
->setHref($cancel_uri));
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Edit')));
|
||||||
|
$submit_label = pht('Save Changes');
|
||||||
|
} else {
|
||||||
|
$crumbs->addCrumb(
|
||||||
|
id(new PhabricatorCrumbView())
|
||||||
|
->setName(pht('Create Countdown')));
|
||||||
|
$submit_label = pht('Create Countdown');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setAction($request->getRequestURI()->getPath())
|
->setAction($request->getRequestURI()->getPath())
|
||||||
|
->setFlexible(true)
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('Title'))
|
->setLabel(pht('Title'))
|
||||||
|
@ -97,7 +116,7 @@ final class PhabricatorCountdownEditController
|
||||||
->setName('title'))
|
->setName('title'))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextControl())
|
id(new AphrontFormTextControl())
|
||||||
->setLabel(pht('End date'))
|
->setLabel(pht('End Date'))
|
||||||
->setValue($display_epoch)
|
->setValue($display_epoch)
|
||||||
->setName('epoch')
|
->setName('epoch')
|
||||||
->setCaption(pht('Examples: '.
|
->setCaption(pht('Examples: '.
|
||||||
|
@ -105,31 +124,20 @@ final class PhabricatorCountdownEditController
|
||||||
'June 8 2011, 5 PM.')))
|
'June 8 2011, 5 PM.')))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormSubmitControl())
|
id(new AphrontFormSubmitControl())
|
||||||
->addCancelButton('/countdown/')
|
->addCancelButton($cancel_uri)
|
||||||
->setValue($action_label));
|
->setValue($submit_label));
|
||||||
|
|
||||||
$panel = id(new AphrontPanelView())
|
|
||||||
->setWidth(AphrontPanelView::WIDTH_FORM)
|
|
||||||
->setHeader($action_label)
|
|
||||||
->setNoBackground()
|
|
||||||
->appendChild($form);
|
|
||||||
|
|
||||||
$crumbs = $this
|
|
||||||
->buildApplicationCrumbs()
|
|
||||||
->addCrumb(
|
|
||||||
id(new PhabricatorCrumbView())
|
|
||||||
->setName($action_label)
|
|
||||||
->setHref($this->getApplicationURI('edit/')));
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
array(
|
array(
|
||||||
$crumbs,
|
$crumbs,
|
||||||
$error_view,
|
$error_view,
|
||||||
$panel,
|
$form,
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'title' => pht('Edit Countdown'),
|
'title' => pht('Edit Countdown'),
|
||||||
'device' => true,
|
'device' => true,
|
||||||
|
'dust' => true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,107 +1,69 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
|
||||||
* @group countdown
|
|
||||||
*/
|
|
||||||
final class PhabricatorCountdownListController
|
final class PhabricatorCountdownListController
|
||||||
extends PhabricatorCountdownController {
|
extends PhabricatorCountdownController
|
||||||
|
implements PhabricatorApplicationSearchResultsControllerInterface {
|
||||||
|
|
||||||
|
private $queryKey;
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willProcessRequest(array $data) {
|
||||||
|
$this->queryKey = idx($data, 'queryKey');
|
||||||
|
}
|
||||||
|
|
||||||
public function processRequest() {
|
public function processRequest() {
|
||||||
|
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$user = $request->getUser();
|
$controller = id(new PhabricatorApplicationSearchController($request))
|
||||||
|
->setQueryKey($this->queryKey)
|
||||||
|
->setSearchEngine(new PhabricatorCountdownSearchEngine())
|
||||||
|
->setNavigation($this->buildSideNavView());
|
||||||
|
|
||||||
$pager = new AphrontCursorPagerView();
|
return $this->delegateToController($controller);
|
||||||
$pager->readFromRequest($request);
|
|
||||||
|
|
||||||
$query = id(new PhabricatorCountdownQuery())
|
|
||||||
->setViewer($user);
|
|
||||||
|
|
||||||
$countdowns = $query->executeWithCursorPager($pager);
|
|
||||||
|
|
||||||
$phids = mpull($countdowns, 'getAuthorPHID');
|
|
||||||
$handles = $this->loadViewerHandles($phids);
|
|
||||||
|
|
||||||
$rows = array();
|
|
||||||
foreach ($countdowns as $timer) {
|
|
||||||
$edit_button = null;
|
|
||||||
$delete_button = null;
|
|
||||||
if ($user->getIsAdmin() ||
|
|
||||||
($user->getPHID() == $timer->getAuthorPHID())) {
|
|
||||||
$edit_button = phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'class' => 'small button grey',
|
|
||||||
'href' => '/countdown/edit/'.$timer->getID().'/'
|
|
||||||
),
|
|
||||||
pht('Edit'));
|
|
||||||
|
|
||||||
$delete_button = javelin_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'class' => 'small button grey',
|
|
||||||
'href' => '/countdown/delete/'.$timer->getID().'/',
|
|
||||||
'sigil' => 'workflow'
|
|
||||||
),
|
|
||||||
pht('Delete'));
|
|
||||||
}
|
|
||||||
$rows[] = array(
|
|
||||||
$timer->getID(),
|
|
||||||
$handles[$timer->getAuthorPHID()]->renderLink(),
|
|
||||||
phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => '/countdown/'.$timer->getID().'/',
|
|
||||||
),
|
|
||||||
$timer->getTitle()),
|
|
||||||
phabricator_datetime($timer->getEpoch(), $user),
|
|
||||||
$edit_button,
|
|
||||||
$delete_button,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$table = new AphrontTableView($rows);
|
public function renderResultsList(
|
||||||
$table->setHeaders(
|
array $countdowns,
|
||||||
array(
|
PhabricatorSavedQuery $query) {
|
||||||
pht('ID'),
|
assert_instances_of($countdowns, 'PhabricatorCountdown');
|
||||||
pht('Author'),
|
|
||||||
pht('Title'),
|
|
||||||
pht('End Date'),
|
|
||||||
'',
|
|
||||||
''
|
|
||||||
));
|
|
||||||
|
|
||||||
$table->setColumnClasses(
|
$viewer = $this->getRequest()->getUser();
|
||||||
array(
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
'wide pri',
|
|
||||||
null,
|
|
||||||
'action',
|
|
||||||
'action',
|
|
||||||
));
|
|
||||||
|
|
||||||
$panel = id(new AphrontPanelView())
|
$this->loadHandles(mpull($countdowns, 'getAuthorPHID'));
|
||||||
->appendChild($table)
|
|
||||||
->setHeader(pht('Countdowns'))
|
|
||||||
->setNoBackground()
|
|
||||||
->appendChild($pager);
|
|
||||||
|
|
||||||
$crumbs = $this
|
|
||||||
->buildApplicationCrumbs()
|
|
||||||
->addCrumb(
|
|
||||||
id(new PhabricatorCrumbView())
|
|
||||||
->setName(pht('All Countdowns'))
|
|
||||||
->setHref($this->getApplicationURI()));
|
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
$list = new PhabricatorObjectItemListView();
|
||||||
array(
|
$list->setUser($viewer);
|
||||||
$crumbs,
|
foreach ($countdowns as $countdown) {
|
||||||
$panel
|
$id = $countdown->getID();
|
||||||
),
|
|
||||||
array(
|
$item = id(new PhabricatorObjectItemView())
|
||||||
'title' => pht('Countdown'),
|
->setObjectName("C{$id}")
|
||||||
'device' => true,
|
->setHeader($countdown->getTitle())
|
||||||
));
|
->setHref($this->getApplicationURI("{$id}/"))
|
||||||
|
->addByline(
|
||||||
|
pht(
|
||||||
|
'Created by %s',
|
||||||
|
$this->getHandle($countdown->getAuthorPHID())->renderLink()));
|
||||||
|
|
||||||
|
$epoch = $countdown->getEpoch();
|
||||||
|
if ($epoch >= time()) {
|
||||||
|
$item->addIcon(
|
||||||
|
'none',
|
||||||
|
pht('Ends %s', phabricator_datetime($epoch, $viewer)));
|
||||||
|
} else {
|
||||||
|
$item->addIcon(
|
||||||
|
'delete',
|
||||||
|
pht('Ended %s', phabricator_datetime($epoch, $viewer)));
|
||||||
|
$item->setDisabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$list->addItem($item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $list;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,72 +27,90 @@ final class PhabricatorCountdownViewController
|
||||||
return new Aphront404Response();
|
return new Aphront404Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
require_celerity_resource('phabricator-countdown-css');
|
$countdown_view = id(new PhabricatorCountdownView())
|
||||||
|
->setUser($user)
|
||||||
|
->setCountdown($countdown)
|
||||||
|
->setHeadless(true);
|
||||||
|
|
||||||
$chrome_visible = $request->getBool('chrome', true);
|
$id = $countdown->getID();
|
||||||
$chrome_new = $chrome_visible ? false : null;
|
$title = $countdown->getTitle();
|
||||||
$chrome_link = phutil_tag(
|
|
||||||
'a',
|
|
||||||
array(
|
|
||||||
'href' => $request->getRequestURI()->alter('chrome', $chrome_new),
|
|
||||||
'class' => 'phabricator-timer-chrome-link',
|
|
||||||
),
|
|
||||||
$chrome_visible ? pht('Disable Chrome') : pht('Enable Chrome'));
|
|
||||||
|
|
||||||
$container = celerity_generate_unique_node_id();
|
|
||||||
$content = hsprintf(
|
|
||||||
'<div class="phabricator-timer" id="%s">
|
|
||||||
<h1 class="phabricator-timer-header">%s · %s</h1>
|
|
||||||
<div class="phabricator-timer-pane">
|
|
||||||
<table class="phabricator-timer-table">
|
|
||||||
<tr>
|
|
||||||
<th>%s</th>
|
|
||||||
<th>%s</th>
|
|
||||||
<th>%s</th>
|
|
||||||
<th>%s</th>
|
|
||||||
</tr>
|
|
||||||
<tr>%s%s%s%s</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
%s
|
|
||||||
</div>',
|
|
||||||
$container,
|
|
||||||
$countdown->getTitle(),
|
|
||||||
phabricator_datetime($countdown->getEpoch(), $user),
|
|
||||||
pht('Days'),
|
|
||||||
pht('Hours'),
|
|
||||||
pht('Minutes'),
|
|
||||||
pht('Seconds'),
|
|
||||||
javelin_tag('td', array('sigil' => 'phabricator-timer-days'), ''),
|
|
||||||
javelin_tag('td', array('sigil' => 'phabricator-timer-hours'), ''),
|
|
||||||
javelin_tag('td', array('sigil' => 'phabricator-timer-minutes'), ''),
|
|
||||||
javelin_tag('td', array('sigil' => 'phabricator-timer-seconds'), ''),
|
|
||||||
$chrome_link);
|
|
||||||
|
|
||||||
Javelin::initBehavior('countdown-timer', array(
|
|
||||||
'timestamp' => $countdown->getEpoch(),
|
|
||||||
'container' => $container,
|
|
||||||
));
|
|
||||||
|
|
||||||
$panel = $content;
|
|
||||||
|
|
||||||
$crumbs = $this
|
$crumbs = $this
|
||||||
->buildApplicationCrumbs()
|
->buildApplicationCrumbs()
|
||||||
->addCrumb(
|
->addCrumb(
|
||||||
id(new PhabricatorCrumbView())
|
id(new PhabricatorCrumbView())
|
||||||
->setName($countdown->getTitle())
|
->setName("C{$id}"));
|
||||||
->setHref($this->getApplicationURI($this->id.'/')));
|
|
||||||
|
$header = id(new PhabricatorHeaderView())
|
||||||
|
->setHeader($title);
|
||||||
|
|
||||||
|
$actions = $this->buildActionListView($countdown);
|
||||||
|
$properties = $this->buildPropertyListView($countdown);
|
||||||
|
|
||||||
|
$content = array(
|
||||||
|
$crumbs,
|
||||||
|
$header,
|
||||||
|
$actions,
|
||||||
|
$properties,
|
||||||
|
$countdown_view,
|
||||||
|
);
|
||||||
|
|
||||||
return $this->buildApplicationPage(
|
return $this->buildApplicationPage(
|
||||||
|
$content,
|
||||||
array(
|
array(
|
||||||
($chrome_visible ? $crumbs : ''),
|
'title' => $title,
|
||||||
$panel,
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'title' => pht('Countdown: %s', $countdown->getTitle()),
|
|
||||||
'chrome' => $chrome_visible,
|
|
||||||
'device' => true,
|
'device' => true,
|
||||||
|
'dust' => true,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildActionListView(PhabricatorCountdown $countdown) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$id = $countdown->getID();
|
||||||
|
|
||||||
|
$view = id(new PhabricatorActionListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
|
$viewer,
|
||||||
|
$countdown,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
|
|
||||||
|
$view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setIcon('edit')
|
||||||
|
->setName(pht('Edit Countdown'))
|
||||||
|
->setHref($this->getApplicationURI("edit/{$id}/"))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(!$can_edit));
|
||||||
|
|
||||||
|
$view->addAction(
|
||||||
|
id(new PhabricatorActionView())
|
||||||
|
->setIcon('delete')
|
||||||
|
->setName(pht('Delete Countdown'))
|
||||||
|
->setHref($this->getApplicationURI("delete/{$id}/"))
|
||||||
|
->setDisabled(!$can_edit)
|
||||||
|
->setWorkflow(true));
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildPropertyListView(PhabricatorCountdown $countdown) {
|
||||||
|
$request = $this->getRequest();
|
||||||
|
$viewer = $request->getUser();
|
||||||
|
|
||||||
|
$this->loadHandles(array($countdown->getAuthorPHID()));
|
||||||
|
|
||||||
|
$view = id(new PhabricatorPropertyListView())
|
||||||
|
->setUser($viewer);
|
||||||
|
|
||||||
|
$view->addProperty(
|
||||||
|
pht('Author'),
|
||||||
|
$this->getHandle($countdown->getAuthorPHID())->renderLink());
|
||||||
|
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ final class PhabricatorCountdownQuery
|
||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
private $authorPHIDs;
|
private $authorPHIDs;
|
||||||
|
private $upcoming;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -25,6 +26,11 @@ final class PhabricatorCountdownQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withUpcoming($upcoming) {
|
||||||
|
$this->upcoming = true;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new PhabricatorCountdown();
|
$table = new PhabricatorCountdown();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
|
@ -69,6 +75,13 @@ final class PhabricatorCountdownQuery
|
||||||
$this->authorPHIDs);
|
$this->authorPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->upcoming) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'epoch >= %d',
|
||||||
|
time());
|
||||||
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownSearchEngine
|
||||||
|
extends PhabricatorApplicationSearchEngine {
|
||||||
|
|
||||||
|
public function buildSavedQueryFromRequest(AphrontRequest $request) {
|
||||||
|
$saved = new PhabricatorSavedQuery();
|
||||||
|
$saved->setParameter(
|
||||||
|
'authorPHIDs',
|
||||||
|
array_values($request->getArr('authors')));
|
||||||
|
|
||||||
|
$saved->setParameter('upcoming', $request->getBool('upcoming'));
|
||||||
|
|
||||||
|
return $saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) {
|
||||||
|
$query = id(new PhabricatorCountdownQuery());
|
||||||
|
|
||||||
|
$author_phids = $saved->getParameter('authorPHIDs', array());
|
||||||
|
if ($author_phids) {
|
||||||
|
$query->withAuthorPHIDs($author_phids);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($saved->getParameter('upcoming')) {
|
||||||
|
$query->withUpcoming(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSearchForm(
|
||||||
|
AphrontFormView $form,
|
||||||
|
PhabricatorSavedQuery $saved_query) {
|
||||||
|
$phids = $saved_query->getParameter('authorPHIDs', array());
|
||||||
|
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||||
|
->setViewer($this->requireViewer())
|
||||||
|
->loadHandles();
|
||||||
|
$author_tokens = mpull($handles, 'getFullName', 'getPHID');
|
||||||
|
|
||||||
|
$upcoming = $saved_query->getParameter('upcoming');
|
||||||
|
|
||||||
|
$form
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormTokenizerControl())
|
||||||
|
->setDatasource('/typeahead/common/users/')
|
||||||
|
->setName('authors')
|
||||||
|
->setLabel(pht('Authors'))
|
||||||
|
->setValue($author_tokens))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormCheckboxControl())
|
||||||
|
->addCheckbox(
|
||||||
|
'upcoming',
|
||||||
|
1,
|
||||||
|
pht('Show only countdowns that are still counting down.'),
|
||||||
|
$upcoming));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getURI($path) {
|
||||||
|
return '/countdown/'.$path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBuiltinQueryNames() {
|
||||||
|
$names = array(
|
||||||
|
'upcoming' => pht('Upcoming'),
|
||||||
|
'all' => pht('All'),
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($this->requireViewer()->getPHID()) {
|
||||||
|
$names['authored'] = pht('Authored');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $names;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function buildSavedQueryFromBuiltin($query_key) {
|
||||||
|
|
||||||
|
$query = $this->newSavedQuery();
|
||||||
|
$query->setQueryKey($query_key);
|
||||||
|
|
||||||
|
switch ($query_key) {
|
||||||
|
case 'all':
|
||||||
|
return $query;
|
||||||
|
case 'authored':
|
||||||
|
return $query->setParameter(
|
||||||
|
'authorPHIDs',
|
||||||
|
array($this->requireViewer()->getPHID()));
|
||||||
|
case 'upcoming':
|
||||||
|
return $query->setParameter('upcoming', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::buildSavedQueryFromBuiltin($query_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,27 +19,11 @@ final class PhabricatorCountdownRemarkupRule
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function renderObjectEmbed($object, $handle, $options) {
|
protected function renderObjectEmbed($object, $handle, $options) {
|
||||||
require_celerity_resource('javelin-behavior-countdown-timer');
|
$viewer = $this->getEngine()->getConfig('viewer');
|
||||||
|
|
||||||
$prefix = 'phabricator-timer-';
|
return id(new PhabricatorCountdownView())
|
||||||
$counter = phutil_tag(
|
->setCountdown($object)
|
||||||
'span',
|
->setUser($viewer);
|
||||||
array(
|
|
||||||
'id' => $object->getPHID(),
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
javelin_tag('span', array('sigil' => $prefix.'days'), ''), 'd',
|
|
||||||
javelin_tag('span', array('sigil' => $prefix.'hours'), ''), 'h',
|
|
||||||
javelin_tag('span', array('sigil' => $prefix.'minutes'), ''), 'm',
|
|
||||||
javelin_tag('span', array('sigil' => $prefix.'seconds'), ''), 's',
|
|
||||||
));
|
|
||||||
|
|
||||||
Javelin::initBehavior('countdown-timer', array(
|
|
||||||
'timestamp' => $object->getEpoch(),
|
|
||||||
'container' => $object->getPHID(),
|
|
||||||
));
|
|
||||||
|
|
||||||
return $counter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,11 +29,14 @@ final class PhabricatorCountdown
|
||||||
return PhabricatorPolicies::POLICY_USER;
|
return PhabricatorPolicies::POLICY_USER;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -( PhabricatorPolicyInterface Implementation )------------------------- */
|
|
||||||
|
/* -( PhabricatorPolicyInterface )----------------------------------------- */
|
||||||
|
|
||||||
|
|
||||||
public function getCapabilities() {
|
public function getCapabilities() {
|
||||||
return array(
|
return array(
|
||||||
PhabricatorPolicyCapability::CAN_VIEW
|
PhabricatorPolicyCapability::CAN_VIEW,
|
||||||
|
PhabricatorPolicyCapability::CAN_EDIT,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +44,8 @@ final class PhabricatorCountdown
|
||||||
switch ($capability) {
|
switch ($capability) {
|
||||||
case PhabricatorPolicyCapability::CAN_VIEW:
|
case PhabricatorPolicyCapability::CAN_VIEW:
|
||||||
return $this->getViewPolicy();
|
return $this->getViewPolicy();
|
||||||
|
case PhabricatorPolicyCapability::CAN_EDIT:
|
||||||
|
return PhabricatorPolicies::POLICY_NOONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
78
src/applications/countdown/view/PhabricatorCountdownView.php
Normal file
78
src/applications/countdown/view/PhabricatorCountdownView.php
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorCountdownView extends AphrontTagView {
|
||||||
|
|
||||||
|
private $countdown;
|
||||||
|
private $headless;
|
||||||
|
|
||||||
|
|
||||||
|
public function setHeadless($headless) {
|
||||||
|
$this->headless = $headless;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setCountdown(PhabricatorCountdown $countdown) {
|
||||||
|
$this->countdown = $countdown;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getTagContent() {
|
||||||
|
$countdown = $this->countdown;
|
||||||
|
|
||||||
|
require_celerity_resource('phabricator-countdown-css');
|
||||||
|
|
||||||
|
$header = null;
|
||||||
|
if (!$this->headless) {
|
||||||
|
$header = phutil_tag(
|
||||||
|
'div',
|
||||||
|
array(
|
||||||
|
'class' => 'phabricator-timer-header',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
"C".$countdown->getID(),
|
||||||
|
' ',
|
||||||
|
phutil_tag(
|
||||||
|
'a',
|
||||||
|
array(
|
||||||
|
'href' => '/countdown/'.$countdown->getID(),
|
||||||
|
),
|
||||||
|
$countdown->getTitle()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$container = celerity_generate_unique_node_id();
|
||||||
|
$content = hsprintf(
|
||||||
|
'<div class="phabricator-timer" id="%s">
|
||||||
|
%s
|
||||||
|
<table class="phabricator-timer-table">
|
||||||
|
<tr>
|
||||||
|
<th>%s</th>
|
||||||
|
<th>%s</th>
|
||||||
|
<th>%s</th>
|
||||||
|
<th>%s</th>
|
||||||
|
</tr>
|
||||||
|
<tr>%s%s%s%s</tr>
|
||||||
|
</table>
|
||||||
|
</div>',
|
||||||
|
$container,
|
||||||
|
$header,
|
||||||
|
pht('Days'),
|
||||||
|
pht('Hours'),
|
||||||
|
pht('Minutes'),
|
||||||
|
pht('Seconds'),
|
||||||
|
javelin_tag('td', array('sigil' => 'phabricator-timer-days'), '-'),
|
||||||
|
javelin_tag('td', array('sigil' => 'phabricator-timer-hours'), '-'),
|
||||||
|
javelin_tag('td', array('sigil' => 'phabricator-timer-minutes'), '-'),
|
||||||
|
javelin_tag('td', array('sigil' => 'phabricator-timer-seconds'), '-'));
|
||||||
|
|
||||||
|
Javelin::initBehavior('countdown-timer', array(
|
||||||
|
'timestamp' => $countdown->getEpoch(),
|
||||||
|
'container' => $container,
|
||||||
|
));
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,29 +3,33 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.phabricator-timer {
|
.phabricator-timer {
|
||||||
width: 80%;
|
width: 90%;
|
||||||
margin: 0 auto;
|
margin: 12px auto;
|
||||||
margin-top: 2em;
|
border: 1px solid #666666;
|
||||||
margin-bottom: 2em;
|
border-radius: 4px;
|
||||||
background: #efefef;
|
background: #ffffff;
|
||||||
border-top: 1px solid #cccccc;
|
box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
|
||||||
|
}
|
||||||
|
|
||||||
|
.phabricator-remarkup .phabricator-timer {
|
||||||
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-timer-header {
|
.phabricator-timer-header {
|
||||||
padding: 8px;
|
font-size: 14px;
|
||||||
background: #dfdfdf;
|
font-weight: bold;
|
||||||
}
|
padding: 4px 8px;
|
||||||
|
background: #f0f0f0;
|
||||||
.phabricator-timer-pane {
|
border-radius: 4px 4px 0 0;
|
||||||
padding: 8px 2em;
|
border-bottom: 1px solid #d7d7d7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-timer-table {
|
.phabricator-timer-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
margin: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-timer-table th {
|
.phabricator-timer-table th {
|
||||||
font-weight: bold;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
width: 10%;
|
width: 10%;
|
||||||
|
@ -35,11 +39,13 @@
|
||||||
.phabricator-timer-table td {
|
.phabricator-timer-table td {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 4em;
|
font-size: 36px;
|
||||||
|
overflow: hidden;
|
||||||
|
line-height: auto;
|
||||||
|
height: auto;
|
||||||
|
line-height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phabricator-timer-chrome-link {
|
.phabricator-timer-table small {
|
||||||
float: right;
|
color: #999999;
|
||||||
padding: 3px 6px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,29 +19,35 @@ JX.behavior('countdown-timer', function(config) {
|
||||||
var hours = 0;
|
var hours = 0;
|
||||||
var minutes = 0;
|
var minutes = 0;
|
||||||
var seconds = 0;
|
var seconds = 0;
|
||||||
|
var partial = 0;
|
||||||
|
|
||||||
var current_timestamp = Math.round(new Date() / 1000);
|
var current_timestamp = +new Date();
|
||||||
var delta = config.timestamp - current_timestamp;
|
|
||||||
|
var delta = (config.timestamp * 1000) - current_timestamp;
|
||||||
|
|
||||||
if (delta > 0) {
|
if (delta > 0) {
|
||||||
days = Math.floor(delta/86400);
|
days = Math.floor(delta / 86400000);
|
||||||
delta -= days * 86400;
|
delta -= days * 86400000;
|
||||||
|
|
||||||
hours = Math.floor(delta/3600);
|
hours = Math.floor(delta / 3600000);
|
||||||
delta -= hours * 3600;
|
delta -= hours * 3600000;
|
||||||
|
|
||||||
minutes = Math.floor(delta / 60);
|
minutes = Math.floor(delta / 60000);
|
||||||
delta -= minutes * 60;
|
delta -= minutes * 60000;
|
||||||
|
|
||||||
seconds = delta;
|
seconds = Math.floor(delta / 1000);
|
||||||
|
delta -= seconds * 1000;
|
||||||
|
|
||||||
setTimeout(calculateTimeLeft, 1000);
|
partial = Math.floor(delta / 100) || '0';
|
||||||
|
|
||||||
|
setTimeout(calculateTimeLeft, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
setComponent('days', days);
|
setComponent('days', days);
|
||||||
setComponent('hours', hours);
|
setComponent('hours', hours);
|
||||||
setComponent('minutes', minutes);
|
setComponent('minutes', minutes);
|
||||||
setComponent('seconds', seconds);
|
setComponent('seconds', [seconds, JX.$N('small', {}, ['.', partial])]);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue