2012-11-22 02:24:56 +01:00
|
|
|
<?php
|
|
|
|
|
2014-02-12 18:02:05 +01:00
|
|
|
final class PHUITimelineView extends AphrontView {
|
2012-11-22 02:24:56 +01:00
|
|
|
|
|
|
|
private $events = array();
|
2012-12-11 23:02:12 +01:00
|
|
|
private $id;
|
2014-03-14 16:51:50 +01:00
|
|
|
private $shouldTerminate = false;
|
2014-12-02 22:10:29 +01:00
|
|
|
private $shouldAddSpacers = true;
|
|
|
|
private $pager;
|
2014-12-04 22:58:52 +01:00
|
|
|
private $renderData = array();
|
2014-12-11 19:27:28 +01:00
|
|
|
private $quoteTargetID;
|
|
|
|
private $quoteRef;
|
2012-12-11 23:02:12 +01:00
|
|
|
|
|
|
|
public function setID($id) {
|
|
|
|
$this->id = $id;
|
|
|
|
return $this;
|
|
|
|
}
|
2012-11-22 02:24:56 +01:00
|
|
|
|
2014-03-14 16:51:50 +01:00
|
|
|
public function setShouldTerminate($term) {
|
|
|
|
$this->shouldTerminate = $term;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-12-02 22:10:29 +01:00
|
|
|
public function setShouldAddSpacers($bool) {
|
|
|
|
$this->shouldAddSpacers = $bool;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setPager(AphrontCursorPagerView $pager) {
|
|
|
|
$this->pager = $pager;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getPager() {
|
|
|
|
return $this->pager;
|
|
|
|
}
|
|
|
|
|
2014-02-12 18:02:05 +01:00
|
|
|
public function addEvent(PHUITimelineEventView $event) {
|
2012-11-22 02:24:56 +01:00
|
|
|
$this->events[] = $event;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-12-04 22:58:52 +01:00
|
|
|
public function setRenderData(array $data) {
|
|
|
|
$this->renderData = $data;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2014-12-11 19:27:28 +01:00
|
|
|
public function setQuoteTargetID($quote_target_id) {
|
|
|
|
$this->quoteTargetID = $quote_target_id;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getQuoteTargetID() {
|
|
|
|
return $this->quoteTargetID;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function setQuoteRef($quote_ref) {
|
|
|
|
$this->quoteRef = $quote_ref;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getQuoteRef() {
|
|
|
|
return $this->quoteRef;
|
|
|
|
}
|
|
|
|
|
2012-11-22 02:24:56 +01:00
|
|
|
public function render() {
|
2014-12-02 22:10:29 +01:00
|
|
|
if ($this->getPager()) {
|
|
|
|
if ($this->id === null) {
|
|
|
|
$this->id = celerity_generate_unique_node_id();
|
|
|
|
}
|
|
|
|
Javelin::initBehavior(
|
|
|
|
'phabricator-show-older-transactions',
|
|
|
|
array(
|
|
|
|
'timelineID' => $this->id,
|
2014-12-04 22:58:52 +01:00
|
|
|
'renderData' => $this->renderData,
|
2014-12-02 22:10:29 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
$events = $this->buildEvents();
|
|
|
|
|
|
|
|
return phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'phui-timeline-view',
|
|
|
|
'id' => $this->id,
|
|
|
|
),
|
|
|
|
$events);
|
|
|
|
}
|
|
|
|
|
|
|
|
public function buildEvents() {
|
2014-02-12 18:02:05 +01:00
|
|
|
require_celerity_resource('phui-timeline-view-css');
|
2012-11-22 02:24:56 +01:00
|
|
|
|
2012-12-11 23:02:29 +01:00
|
|
|
$spacer = self::renderSpacer();
|
2012-12-11 23:01:35 +01:00
|
|
|
|
2014-02-14 19:23:07 +01:00
|
|
|
$hide = array();
|
|
|
|
$show = array();
|
|
|
|
|
2015-03-04 19:36:01 +01:00
|
|
|
// Bucket timeline events into events we'll hide by default (because they
|
|
|
|
// predate your most recent interaction with the object) and events we'll
|
|
|
|
// show by default.
|
2012-11-22 02:24:56 +01:00
|
|
|
foreach ($this->events as $event) {
|
2014-02-14 19:23:07 +01:00
|
|
|
if ($event->getHideByDefault()) {
|
|
|
|
$hide[] = $event;
|
|
|
|
} else {
|
|
|
|
$show[] = $event;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-04 19:36:01 +01:00
|
|
|
// If you've never interacted with the object, all the events will be shown
|
|
|
|
// by default. We may still need to paginate if there are a large number
|
|
|
|
// of events.
|
|
|
|
$more = (bool)$hide;
|
|
|
|
if ($this->getPager()) {
|
|
|
|
if ($this->getPager()->getHasMoreResults()) {
|
|
|
|
$more = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-14 19:23:07 +01:00
|
|
|
$events = array();
|
2015-03-04 19:36:01 +01:00
|
|
|
if ($more && $this->getPager()) {
|
2014-12-11 19:27:28 +01:00
|
|
|
$uri = $this->getPager()->getNextPageURI();
|
|
|
|
$uri->setQueryParam('quoteTargetID', $this->getQuoteTargetID());
|
|
|
|
$uri->setQueryParam('quoteRef', $this->getQuoteRef());
|
2014-12-04 23:55:18 +01:00
|
|
|
$events[] = javelin_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'sigil' => 'show-older-block',
|
|
|
|
'class' => 'phui-timeline-older-transactions-are-hidden',
|
|
|
|
),
|
|
|
|
array(
|
|
|
|
pht('Older changes are hidden. '),
|
|
|
|
' ',
|
|
|
|
javelin_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
2015-05-19 23:06:07 +02:00
|
|
|
'href' => (string)$uri,
|
2014-02-14 19:23:07 +01:00
|
|
|
'mustcapture' => true,
|
2014-12-02 22:10:29 +01:00
|
|
|
'sigil' => 'show-older-link',
|
2014-02-14 19:23:07 +01:00
|
|
|
),
|
2014-12-02 22:10:29 +01:00
|
|
|
pht('Show older changes.')),
|
2014-12-04 23:55:18 +01:00
|
|
|
));
|
2014-02-14 19:23:07 +01:00
|
|
|
|
2015-03-04 19:36:01 +01:00
|
|
|
if ($show) {
|
|
|
|
$events[] = $spacer;
|
|
|
|
}
|
2012-11-22 02:24:56 +01:00
|
|
|
}
|
2014-02-14 19:23:07 +01:00
|
|
|
|
|
|
|
if ($show) {
|
2015-07-25 01:04:44 +02:00
|
|
|
$this->prepareBadgeData($show);
|
2014-02-14 19:23:07 +01:00
|
|
|
$events[] = phutil_implode_html($spacer, $show);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($events) {
|
2014-12-02 22:10:29 +01:00
|
|
|
if ($this->shouldAddSpacers) {
|
|
|
|
$events = array($spacer, $events, $spacer);
|
|
|
|
}
|
2014-02-14 23:43:17 +01:00
|
|
|
} else {
|
|
|
|
$events = array($spacer);
|
2014-02-14 19:23:07 +01:00
|
|
|
}
|
2012-11-22 02:24:56 +01:00
|
|
|
|
2014-03-14 16:51:50 +01:00
|
|
|
if ($this->shouldTerminate) {
|
|
|
|
$events[] = self::renderEnder(true);
|
|
|
|
}
|
|
|
|
|
2014-12-02 22:10:29 +01:00
|
|
|
return $events;
|
2012-11-22 02:24:56 +01:00
|
|
|
}
|
|
|
|
|
2012-12-11 23:02:29 +01:00
|
|
|
public static function renderSpacer() {
|
2013-01-18 03:57:09 +01:00
|
|
|
return phutil_tag(
|
2012-12-11 23:02:29 +01:00
|
|
|
'div',
|
|
|
|
array(
|
2014-02-12 18:02:05 +01:00
|
|
|
'class' => 'phui-timeline-event-view '.
|
|
|
|
'phui-timeline-spacer',
|
2012-12-11 23:02:29 +01:00
|
|
|
),
|
|
|
|
'');
|
|
|
|
}
|
2014-03-14 16:51:50 +01:00
|
|
|
|
|
|
|
public static function renderEnder() {
|
|
|
|
return phutil_tag(
|
|
|
|
'div',
|
|
|
|
array(
|
|
|
|
'class' => 'phui-timeline-event-view '.
|
|
|
|
'the-worlds-end',
|
|
|
|
),
|
|
|
|
'');
|
|
|
|
}
|
|
|
|
|
2015-07-25 01:04:44 +02:00
|
|
|
private function prepareBadgeData(array $events) {
|
|
|
|
assert_instances_of($events, 'PHUITimelineEventView');
|
|
|
|
|
|
|
|
$viewer = $this->getUser();
|
|
|
|
$can_use_badges = PhabricatorApplication::isClassInstalledForViewer(
|
|
|
|
'PhabricatorBadgesApplication',
|
|
|
|
$viewer);
|
|
|
|
if (!$can_use_badges) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user_phid_type = PhabricatorPeopleUserPHIDType::TYPECONST;
|
|
|
|
$badge_edge_type = PhabricatorRecipientHasBadgeEdgeType::EDGECONST;
|
|
|
|
|
|
|
|
$user_phids = array();
|
|
|
|
foreach ($events as $key => $event) {
|
|
|
|
if (!$event->hasChildren()) {
|
|
|
|
// This is a minor event, so we don't have space to show badges.
|
|
|
|
unset($events[$key]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$author_phid = $event->getAuthorPHID();
|
|
|
|
if (!$author_phid) {
|
|
|
|
unset($events[$key]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (phid_get_type($author_phid) != $user_phid_type) {
|
|
|
|
// This is likely an application actor, like "Herald" or "Harbormaster".
|
|
|
|
// They can't have badges.
|
|
|
|
unset($events[$key]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user_phids[$author_phid] = $author_phid;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$user_phids) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$edges = id(new PhabricatorEdgeQuery())
|
|
|
|
->withSourcePHIDs($user_phids)
|
|
|
|
->withEdgeTypes(array($badge_edge_type));
|
|
|
|
$edges->execute();
|
|
|
|
|
|
|
|
$badge_phids = $edges->getDestinationPHIDs();
|
|
|
|
if (!$badge_phids) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$all_badges = id(new PhabricatorBadgesQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withPHIDs($badge_phids)
|
|
|
|
->execute();
|
|
|
|
$all_badges = mpull($all_badges, null, 'getPHID');
|
|
|
|
|
|
|
|
foreach ($events as $event) {
|
|
|
|
$author_phid = $event->getAuthorPHID();
|
|
|
|
$event_phids = $edges->getDestinationPHIDs(array($author_phid));
|
|
|
|
$badges = array_select_keys($all_badges, $event_phids);
|
|
|
|
|
|
|
|
// TODO: Pick the "best" badges in some smart way. For now, just pick
|
|
|
|
// the first two.
|
|
|
|
$badges = array_slice($badges, 0, 2);
|
|
|
|
foreach ($badges as $badge) {
|
|
|
|
$badge_view = id(new PHUIBadgeMiniView())
|
|
|
|
->setIcon($badge->getIcon())
|
|
|
|
->setQuality($badge->getQuality())
|
|
|
|
->setHeader($badge->getName())
|
2015-07-27 16:51:53 +02:00
|
|
|
->setTipDirection('E')
|
2015-07-25 01:04:44 +02:00
|
|
|
->setHref('/badges/view/'.$badge->getID());
|
|
|
|
|
|
|
|
$event->addBadge($badge_view);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-11-22 02:24:56 +01:00
|
|
|
}
|