diff --git a/src/applications/diffusion/controller/DiffusionLintController.php b/src/applications/diffusion/controller/DiffusionLintController.php
index 585bc7b27..dc4471b97 100644
--- a/src/applications/diffusion/controller/DiffusionLintController.php
+++ b/src/applications/diffusion/controller/DiffusionLintController.php
@@ -1,228 +1,227 @@
getRequest();
$user = $this->getRequest()->getUser();
$drequest = $this->diffusionRequest;
if ($request->getStr('lint') !== null) {
$controller = new DiffusionLintDetailsController($request);
$controller->setDiffusionRequest($drequest);
return $this->delegateToController($controller);
}
$owners = array();
if (!$drequest) {
if (!$request->getArr('owner')) {
$owners[$user->getPHID()] = $user->getFullName();
} else {
$phids = $request->getArr('owner');
$phid = reset($phids);
$handles = $this->loadViewerHandles(array($phid));
$owners[$phid] = $handles[$phid]->getFullName();
}
}
$codes = $this->loadLintCodes(array_keys($owners));
if ($codes && !$drequest) {
$branches = id(new PhabricatorRepositoryBranch())->loadAllWhere(
'id IN (%Ld)',
array_unique(ipull($codes, 'branchID')));
$repositories = id(new PhabricatorRepository())->loadAllWhere(
'id IN (%Ld)',
array_unique(mpull($branches, 'getRepositoryID')));
$drequests = array();
foreach ($branches as $id => $branch) {
$drequests[$id] = DiffusionRequest::newFromDictionary(array(
'repository' => $repositories[$branch->getRepositoryID()],
'branch' => $branch->getName(),
));
}
}
$rows = array();
foreach ($codes as $code) {
if (!$this->diffusionRequest) {
$drequest = $drequests[$code['branchID']];
}
$rows[] = array(
hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'lint',
'lint' => $code['code'],
)),
$code['n']),
hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'browse',
'lint' => $code['code'],
)),
$code['files']),
hsprintf(
'%s',
$drequest->generateURI(array('action' => 'lint')),
$drequest->getCallsign()),
phutil_escape_html(ArcanistLintSeverity::getStringForSeverity(
$code['maxSeverity'])),
phutil_escape_html($code['code']),
phutil_escape_html($code['maxName']),
phutil_escape_html($code['maxDescription']),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
'Problems',
'Files',
'Repository',
'Severity',
'Code',
'Name',
'Example',
))
->setColumnVisibility(array(true, true, !$this->diffusionRequest))
->setColumnClasses(array('n', 'n', '', '', 'pri', '', ''));
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$link = null;
if ($this->diffusionRequest) {
$link = hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'lint',
'lint' => '',
)),
pht('Switch to List View'));
} else {
$form = id(new AphrontFormView())
->setUser($user)
->setMethod('GET')
->appendChild(
id(new AphrontFormTokenizerControl())
->setDatasource('/typeahead/common/users/')
->setLimit(1)
->setName('owner')
->setLabel('Owner')
->setValue($owners))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue('Filter'));
$content[] = id(new AphrontListFilterView())->appendChild($form);
}
$content[] = id(new AphrontPanelView())
->setHeader(pht('%d Lint Message(s)', array_sum(ipull($codes, 'n'))))
->setCaption($link)
->appendChild($table);
$title = array('Lint');
if ($this->diffusionRequest) {
$title[] = $drequest->getCallsign();
$content = $this->buildSideNav('lint', false)->appendChild($content);
}
return $this->buildStandardPageResponse(
$content,
array('title' => $title));
}
private function loadLintCodes(array $owner_phids) {
$drequest = $this->diffusionRequest;
$conn = id(new PhabricatorRepository())->establishConnection('r');
$where = array('1 = 1');
if ($drequest) {
$branch = $drequest->loadBranch();
if (!$branch) {
return array();
}
$where[] = qsprintf($conn, 'branchID = %d', $branch->getID());
if ($drequest->getPath() != '') {
$is_dir = (substr($drequest->getPath(), -1) == '/');
$where[] = qsprintf(
$conn,
'path '.($is_dir ? 'LIKE %>' : '= %s'),
'/'.$drequest->getPath());
}
}
if ($owner_phids) {
$packages = id(new PhabricatorOwnersOwner())
->loadAllWhere('userPHID IN (%Ls)', $owner_phids);
if (!$packages) {
return array();
}
$paths = id(new PhabricatorOwnersPath())
->loadAllWhere('packageID IN (%Ld)', array_keys($packages));
if (!$paths) {
return array();
}
$repositories = id(new PhabricatorRepository())->loadAllWhere(
'phid IN (%Ls)',
array_unique(mpull($paths, 'getRepositoryPHID')));
$repositories = mpull($repositories, 'getID', 'getPHID');
$branches = id(new PhabricatorRepositoryBranch())->loadAllWhere(
'repositoryID IN (%Ld)',
$repositories);
$branches = mgroup($branches, 'getRepositoryID');
$or = array();
foreach ($paths as $path) {
$branch = idx($branches, $repositories[$path->getRepositoryPHID()]);
if ($branch) {
$or[] = qsprintf(
$conn,
'(branchID IN (%Ld) AND path LIKE %>)',
array_keys($branch),
$path->getPath());
}
}
if (!$or) {
return array();
}
$where[] = '('.implode(' OR ', $or).')';
}
return queryfx_all(
$conn,
'SELECT
branchID,
code,
MAX(severity) AS maxSeverity,
MAX(name) AS maxName,
MAX(description) AS maxDescription,
COUNT(DISTINCT path) AS files,
COUNT(*) AS n
FROM %T
WHERE %Q
GROUP BY branchID, code
ORDER BY n DESC',
PhabricatorRepository::TABLE_LINTMESSAGE,
implode(' AND ', $where));
}
}
diff --git a/src/applications/diffusion/controller/DiffusionLintDetailsController.php b/src/applications/diffusion/controller/DiffusionLintDetailsController.php
index c8cc96901..355958459 100644
--- a/src/applications/diffusion/controller/DiffusionLintDetailsController.php
+++ b/src/applications/diffusion/controller/DiffusionLintDetailsController.php
@@ -1,142 +1,141 @@
getRequest()->getInt('offset', 0);
$drequest = $this->getDiffusionRequest();
$branch = $drequest->loadBranch();
$messages = $this->loadLintMessages($branch, $limit, $offset);
$is_dir = (substr('/'.$drequest->getPath(), -1) == '/');
$rows = array();
foreach ($messages as $message) {
$path = hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'lint',
'path' => $message['path'],
)),
substr($message['path'], strlen($drequest->getPath()) + 1));
$line = hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'browse',
'path' => $message['path'],
'line' => $message['line'],
'commit' => $branch->getLintCommit(),
)),
$message['line']);
$rows[] = array(
$path,
$line,
phutil_escape_html(ArcanistLintSeverity::getStringForSeverity(
$message['severity'])),
phutil_escape_html($message['name']),
phutil_escape_html($message['description']),
);
}
$table = id(new AphrontTableView($rows))
->setHeaders(array(
'Path',
'Line',
'Severity',
'Name',
'Description',
))
->setColumnClasses(array('', 'n', '', '', ''))
->setColumnVisibility(array($is_dir));
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'lint',
));
$pager = id(new AphrontPagerView())
->setPageSize($limit)
->setOffset($offset)
->setHasMorePages(count($messages) >= $limit)
->setURI($this->getRequest()->getRequestURI(), 'offset');
$lint = $drequest->getLint();
$link = hsprintf(
'%s',
$drequest->generateURI(array(
'action' => 'lint',
'lint' => null,
)),
pht('Switch to Grouped View'));
$content[] = id(new AphrontPanelView())
->setHeader(
($lint != '' ? phutil_escape_html($lint)." \xC2\xB7 " : '').
pht('%d Lint Message(s)', count($messages)))
->setCaption($link)
->appendChild($table)
->appendChild($pager);
$nav = $this->buildSideNav('lint', false);
$nav->appendChild($content);
return $this->buildStandardPageResponse(
$nav,
array('title' => array(
'Lint',
$drequest->getRepository()->getCallsign(),
)));
}
private function loadLintMessages(
PhabricatorRepositoryBranch $branch,
$limit,
$offset) {
$drequest = $this->getDiffusionRequest();
if (!$branch) {
return array();
}
$conn = $branch->establishConnection('r');
$where = array();
if ($drequest->getPath() != '') {
$is_dir = (substr($drequest->getPath(), -1) == '/');
$where[] = qsprintf(
$conn,
'path '.($is_dir ? 'LIKE %>' : '= %s'),
'/'.$drequest->getPath());
}
if ($drequest->getLint() != '') {
$where[] = qsprintf(
$conn,
'code = %s',
$drequest->getLint());
}
return queryfx_all(
$conn,
'SELECT *
FROM %T
WHERE branchID = %d
AND %Q
ORDER BY path, code, line
LIMIT %d OFFSET %d',
PhabricatorRepository::TABLE_LINTMESSAGE,
$branch->getID(),
implode(' AND ', $where),
$limit,
$offset);
}
}
diff --git a/src/applications/pholio/application/PhabricatorApplicationPholio.php b/src/applications/pholio/application/PhabricatorApplicationPholio.php
index 83e754ea8..742aab946 100644
--- a/src/applications/pholio/application/PhabricatorApplicationPholio.php
+++ b/src/applications/pholio/application/PhabricatorApplicationPholio.php
@@ -1,67 +1,51 @@
[1-9]\d*)' => 'PholioMockViewController',
'/pholio/' => array(
'' => 'PholioMockListController',
'view/(?P\w+)/' => 'PholioMockListController',
'new/' => 'PholioMockEditController',
'edit/(?P\d+)/' => 'PholioMockEditController',
'comment/(?P\d+)/' => 'PholioMockCommentController',
),
);
}
}
diff --git a/src/applications/pholio/constants/PholioConstants.php b/src/applications/pholio/constants/PholioConstants.php
index 40b133558..387a82337 100644
--- a/src/applications/pholio/constants/PholioConstants.php
+++ b/src/applications/pholio/constants/PholioConstants.php
@@ -1,21 +1,5 @@
setBaseURI(new PhutilURI($this->getApplicationURI()));
$nav->addLabel('Create');
$nav->addFilter('new', pht('Create Mock'));
$nav->addLabel('Mocks');
$nav->addFilter('view/all', pht('All Mocks'));
return $nav;
}
}
diff --git a/src/applications/pholio/controller/PholioMockCommentController.php b/src/applications/pholio/controller/PholioMockCommentController.php
index 31d1c798b..b61502a61 100644
--- a/src/applications/pholio/controller/PholioMockCommentController.php
+++ b/src/applications/pholio/controller/PholioMockCommentController.php
@@ -1,74 +1,58 @@
id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$mock = id(new PholioMockQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$mock) {
return new Aphront404Response();
}
$mock_uri = '/M'.$mock->getID();
$comment = $request->getStr('comment');
if (!strlen($comment)) {
$dialog = id(new AphrontDialogView())
->setUser($user)
->setTitle(pht('Empty Comment'))
->appendChild('You did not provide a comment!')
->addCancelButton($mock_uri);
return id(new AphrontDialogResponse())->setDialog($dialog);
}
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_WEB,
array(
'ip' => $request->getRemoteAddr(),
));
$xaction = id(new PholioTransaction())
->setTransactionType(PholioTransactionType::TYPE_NONE)
->setComment($comment);
id(new PholioMockEditor())
->setActor($user)
->setContentSource($content_source)
->applyTransactions($mock, array($xaction));
return id(new AphrontRedirectResponse())->setURI($mock_uri);
}
}
diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php
index da4285b39..1118cba58 100644
--- a/src/applications/pholio/controller/PholioMockEditController.php
+++ b/src/applications/pholio/controller/PholioMockEditController.php
@@ -1,232 +1,216 @@
id = idx($data, 'id');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
if ($this->id) {
$mock = id(new PholioMockQuery())
->setViewer($user)
->requireCapabilities(
array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
))
->withIDs(array($this->id))
->executeOne();
if (!$mock) {
return new Aphront404Response();
}
$title = pht('Edit Mock');
$is_new = false;
} else {
$mock = new PholioMock();
$mock->setAuthorPHID($user->getPHID());
$mock->setViewPolicy(PhabricatorPolicies::POLICY_USER);
$title = pht('Create Mock');
$is_new = true;
}
$e_name = true;
$e_images = true;
$errors = array();
$v_name = $mock->getName();
$v_desc = $mock->getDescription();
$v_view = $mock->getViewPolicy();
if ($request->isFormPost()) {
$xactions = array();
$type_name = PholioTransactionType::TYPE_NAME;
$type_desc = PholioTransactionType::TYPE_DESCRIPTION;
$type_view = PholioTransactionType::TYPE_VIEW_POLICY;
$v_name = $request->getStr('name');
$v_desc = $request->getStr('description');
$v_view = $request->getStr('can_view');
$xactions[$type_name] = $v_name;
$xactions[$type_desc] = $v_desc;
$xactions[$type_view] = $v_view;
if (!strlen($request->getStr('name'))) {
$e_name = 'Required';
$errors[] = pht('You must name the mock.');
}
$images = array();
if ($is_new) {
// TODO: Make this transactional and allow edits?
$files = array();
$file_phids = $request->getArr('file_phids');
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer($user)
->withPHIDs($file_phids)
->execute();
}
if (!$files) {
$e_images = 'Required';
$errors[] = pht('You must add at least one image to the mock.');
} else {
$mock->setCoverPHID(head($files)->getPHID());
}
$sequence = 0;
foreach ($files as $file) {
$image = new PholioImage();
$image->setFilePHID($file->getPHID());
$image->setSequence($sequence++);
$images[] = $image;
}
}
if (!$errors) {
$content_source = PhabricatorContentSource::newForSource(
PhabricatorContentSource::SOURCE_WEB,
array(
'ip' => $request->getRemoteAddr(),
));
foreach ($xactions as $type => $value) {
$xactions[$type] = id(new PholioTransaction())
->setTransactionType($type)
->setNewValue($value);
}
$mock->openTransaction();
$editor = id(new PholioMockEditor())
->setContentSource($content_source)
->setActor($user);
$editor->applyTransactions($mock, $xactions);
if ($images) {
foreach ($images as $image) {
// TODO: Move into editor?
$image->setMockID($mock->getID());
$image->save();
}
}
$mock->saveTransaction();
return id(new AphrontRedirectResponse())
->setURI('/M'.$mock->getID());
}
}
if ($errors) {
$error_view = id(new AphrontErrorView())
->setTitle(pht('Form Errors'))
->setErrors($errors);
} else {
$error_view = null;
}
if ($this->id) {
$submit = id(new AphrontFormSubmitControl())
->addCancelButton('/M'.$this->id)
->setValue(pht('Save'));
} else {
$submit = id(new AphrontFormSubmitControl())
->addCancelButton($this->getApplicationURI())
->setValue(pht('Create'));
}
$policies = id(new PhabricatorPolicyQuery())
->setViewer($user)
->setObject($mock)
->execute();
// NOTE: Make this show up correctly on the rendered form.
$mock->setViewPolicy($v_view);
$form = id(new AphrontFormView())
->setUser($user)
->setFlexible(true)
->appendChild(
id(new AphrontFormTextControl())
->setName('name')
->setValue($v_name)
->setLabel(pht('Name'))
->setError($e_name))
->appendChild(
id(new PhabricatorRemarkupControl())
->setName('description')
->setValue($v_desc)
->setLabel(pht('Description'))
->setUser($user))
->appendChild(
id(new AphrontFormDragAndDropUploadControl($request))
->setName('file_phids')
->setLabel(pht('Images'))
->setError($e_images))
->appendChild(
id(new AphrontFormPolicyControl())
->setUser($user)
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
->setPolicyObject($mock)
->setPolicies($policies)
->setName('can_view'))
->appendChild($submit);
$header = id(new PhabricatorHeaderView())
->setHeader($title);
$content = array(
$header,
$error_view,
$form,
);
$nav = $this->buildSideNav();
$nav->selectFilter(null);
$nav->appendChild($content);
return $this->buildApplicationPage(
$nav,
array(
'title' => $title,
));
}
}
diff --git a/src/applications/pholio/controller/PholioMockListController.php b/src/applications/pholio/controller/PholioMockListController.php
index 272f44c6e..943eab946 100644
--- a/src/applications/pholio/controller/PholioMockListController.php
+++ b/src/applications/pholio/controller/PholioMockListController.php
@@ -1,78 +1,62 @@
view = idx($data, 'view');
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$query = id(new PholioMockQuery())
->setViewer($user);
$nav = $this->buildSideNav();
$filter = $nav->selectFilter('view/'.$this->view, 'view/all');
switch ($filter) {
case 'view/all':
default:
$title = 'All Mocks';
break;
}
$pager = new AphrontCursorPagerView();
$pager->readFromRequest($request);
$mocks = $query->executeWithCursorPager($pager);
$board = new PhabricatorPinboardView();
foreach ($mocks as $mock) {
$board->addItem(
id(new PhabricatorPinboardItemView())
->setHeader($mock->getName())
->setURI('/M'.$mock->getID()));
}
$header = id(new PhabricatorHeaderView())
->setHeader($title);
$content = array(
$header,
$board,
$pager,
);
$nav->appendChild($content);
return $this->buildApplicationPage(
$nav,
array(
'title' => $title,
));
}
}
diff --git a/src/applications/pholio/controller/PholioMockViewController.php b/src/applications/pholio/controller/PholioMockViewController.php
index 0d9b93816..e21c1ac4f 100644
--- a/src/applications/pholio/controller/PholioMockViewController.php
+++ b/src/applications/pholio/controller/PholioMockViewController.php
@@ -1,333 +1,317 @@
id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$mock = id(new PholioMockQuery())
->setViewer($user)
->withIDs(array($this->id))
->executeOne();
if (!$mock) {
return new Aphront404Response();
}
$xactions = id(new PholioTransactionQuery())
->withMockIDs(array($mock->getID()))
->execute();
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$mock->getPHID());
$phids = array();
$phids[] = $mock->getAuthorPHID();
foreach ($xactions as $xaction) {
$phids[] = $xaction->getAuthorPHID();
foreach ($xaction->getRequiredHandlePHIDs() as $hphid) {
$phids[] = $hphid;
}
}
foreach ($subscribers as $subscriber) {
$phids[] = $subscriber;
}
$this->loadHandles($phids);
$engine = id(new PhabricatorMarkupEngine())
->setViewer($user);
$engine->addObject($mock, PholioMock::MARKUP_FIELD_DESCRIPTION);
foreach ($xactions as $xaction) {
$engine->addObject($xaction, PholioTransaction::MARKUP_FIELD_COMMENT);
}
$engine->process();
$title = 'M'.$mock->getID().' '.$mock->getName();
$header = id(new PhabricatorHeaderView())
->setHeader($title);
$actions = $this->buildActionView($mock);
$properties = $this->buildPropertyView($mock, $engine, $subscribers);
$carousel =
''.
'Carousel Goes Here
';
$xaction_view = $this->buildTransactionView($xactions, $engine);
$add_comment = $this->buildAddCommentView($mock);
$content = array(
$header,
$actions,
$properties,
$carousel,
$xaction_view,
$add_comment,
);
return $this->buildApplicationPage(
$content,
array(
'title' => $title,
'device' => true,
));
}
private function buildActionView(PholioMock $mock) {
$user = $this->getRequest()->getUser();
$actions = id(new PhabricatorActionListView())
->setUser($user)
->setObject($mock);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$user,
$mock,
PhabricatorPolicyCapability::CAN_EDIT);
$actions->addAction(
id(new PhabricatorActionView())
->setIcon('edit')
->setName(pht('Edit Mock'))
->setHref($this->getApplicationURI('/edit/'.$mock->getID()))
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
return $actions;
}
private function buildPropertyView(
PholioMock $mock,
PhabricatorMarkupEngine $engine,
array $subscribers) {
$user = $this->getRequest()->getUser();
$properties = new PhabricatorPropertyListView();
$properties->addProperty(
pht('Author'),
$this->getHandle($mock->getAuthorPHID())->renderLink());
$properties->addProperty(
pht('Created'),
phabricator_datetime($mock->getDateCreated(), $user));
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
$user,
$mock);
$properties->addProperty(
pht('Visible To'),
$descriptions[PhabricatorPolicyCapability::CAN_VIEW]);
if ($subscribers) {
$sub_view = array();
foreach ($subscribers as $subscriber) {
$sub_view[] = $this->getHandle($subscriber)->renderLink();
}
$sub_view = implode(', ', $sub_view);
} else {
$sub_view = ''.pht('None').'';
}
$properties->addProperty(
pht('Subscribers'),
$sub_view);
$properties->addTextContent(
$engine->getOutput($mock, PholioMock::MARKUP_FIELD_DESCRIPTION));
return $properties;
}
private function buildAddCommentView(PholioMock $mock) {
$user = $this->getRequest()->getUser();
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
$title = $is_serious
? pht('Add Comment')
: pht('History Beckons');
$header = id(new PhabricatorHeaderView())
->setHeader($title);
$action = $is_serious
? pht('Add Comment')
: pht('Answer The Call');
$form = id(new AphrontFormView())
->setUser($user)
->setAction($this->getApplicationURI('/comment/'.$mock->getID().'/'))
->setWorkflow(true)
->setFlexible(true)
->appendChild(
id(new PhabricatorRemarkupControl())
->setName('comment')
->setLabel(pht('Comment'))
->setUser($user))
->appendChild(
id(new AphrontFormSubmitControl())
->setValue($action));
return array(
$header,
$form,
);
}
private function buildTransactionView(
array $xactions,
PhabricatorMarkupEngine $engine) {
assert_instances_of($xactions, 'PholioTransaction');
$view = new PhabricatorTimelineView();
foreach ($xactions as $xaction) {
$author = $this->getHandle($xaction->getAuthorPHID());
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$xaction_visible = true;
$title = null;
$type = $xaction->getTransactionType();
switch ($type) {
case PholioTransactionType::TYPE_NONE:
$title = pht(
'%s added a comment.',
$author->renderLink());
break;
case PholioTransactionType::TYPE_NAME:
if ($old === null) {
$xaction_visible = false;
break;
}
$title = pht(
'%s renamed this mock from "%s" to "%s".',
$author->renderLink(),
phutil_escape_html($old),
phutil_escape_html($new));
break;
case PholioTransactionType::TYPE_DESCRIPTION:
if ($old === null) {
$xaction_visible = false;
break;
}
// TODO: Show diff, like Maniphest.
$title = pht(
'%s updated the description of this mock. '.
'The old description was: %s',
$author->renderLink(),
phutil_escape_html($old));
break;
case PholioTransactionType::TYPE_VIEW_POLICY:
if ($old === null) {
$xaction_visible = false;
break;
}
// TODO: Render human-readable.
$title = pht(
'%s changed the visibility of this mock from "%s" to "%s".',
$author->renderLink(),
phutil_escape_html($old),
phutil_escape_html($new));
break;
case PholioTransactionType::TYPE_SUBSCRIBERS:
$rem = array_diff($old, $new);
$add = array_diff($new, $old);
$add_l = array();
foreach ($add as $phid) {
$add_l[] = $this->getHandle($phid)->renderLink();
}
$add_l = implode(', ', $add_l);
$rem_l = array();
foreach ($rem as $phid) {
$rem_l[] = $this->getHandle($phid)->renderLink();
}
$rem_l = implode(', ', $rem_l);
if ($add && $rem) {
$title = pht(
'%s edited subscriber(s), added %d: %s; removed %d: %s.',
$author->renderLink(),
$add_l,
count($add),
$rem_l,
count($rem));
} else if ($add) {
$title = pht(
'%s added %d subscriber(s): %s.',
$author->renderLink(),
count($add),
$add_l);
} else if ($rem) {
$title = pht(
'%s removed %d subscribers: %s.',
$author->renderLink(),
count($rem),
$rem_l);
}
break;
default:
throw new Exception("Unknown transaction type '{$type}'!");
}
if (!$xaction_visible) {
// Some transactions aren't useful to human viewers, like
// the initial transactions which set the mock's name and description.
continue;
}
$event = id(new PhabricatorTimelineEventView())
->setUserHandle($author);
$event->setTitle($title);
if (strlen($xaction->getComment())) {
$event->appendChild(
$engine->getOutput(
$xaction,
PholioTransaction::MARKUP_FIELD_COMMENT));
}
$view->addEvent($event);
}
return $view;
}
}
diff --git a/src/applications/pholio/editor/PholioMockEditor.php b/src/applications/pholio/editor/PholioMockEditor.php
index b988db2bf..582fb1e61 100644
--- a/src/applications/pholio/editor/PholioMockEditor.php
+++ b/src/applications/pholio/editor/PholioMockEditor.php
@@ -1,328 +1,312 @@
contentSource = $content_source;
return $this;
}
public function getContentSource() {
return $this->contentSource;
}
public function applyTransactions(PholioMock $mock, array $xactions) {
assert_instances_of($xactions, 'PholioTransaction');
$actor = $this->requireActor();
if (!$this->contentSource) {
throw new Exception(
"Call setContentSource() before applyTransactions()!");
}
$is_new = !$mock->getID();
$comments = array();
foreach ($xactions as $xaction) {
if (strlen($xaction->getComment())) {
$comments[] = $xaction->getComment();
}
$type = $xaction->getTransactionType();
if ($type == PholioTransactionType::TYPE_DESCRIPTION) {
$comments[] = $xaction->getNewValue();
}
}
$mentioned_phids = PhabricatorMarkupEngine::extractPHIDsFromMentions(
$comments);
$subscribe_phids = $mentioned_phids;
// Attempt to subscribe the actor.
$subscribe_phids[] = $actor->getPHID();
if ($subscribe_phids) {
if ($mock->getID()) {
$old_subs = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$mock->getPHID());
} else {
$old_subs = array();
}
$new_subs = array_merge($old_subs, $mentioned_phids);
$xaction = id(new PholioTransaction())
->setTransactionType(PholioTransactionType::TYPE_SUBSCRIBERS)
->setOldValue($old_subs)
->setNewValue($new_subs);
array_unshift($xactions, $xaction);
}
foreach ($xactions as $xaction) {
$xaction->setContentSource($this->contentSource);
$xaction->setAuthorPHID($actor->getPHID());
}
foreach ($xactions as $key => $xaction) {
$has_effect = $this->applyTransaction($mock, $xaction);
if (!$has_effect) {
unset($xactions[$key]);
}
}
if (!$xactions) {
return;
}
$mock->openTransaction();
$mock->save();
foreach ($xactions as $xaction) {
$xaction->setMockID($mock->getID());
$xaction->save();
}
// Apply ID/PHID-dependent transactions.
foreach ($xactions as $xaction) {
$type = $xaction->getTransactionType();
switch ($type) {
case PholioTransactionType::TYPE_SUBSCRIBERS:
$subeditor = id(new PhabricatorSubscriptionsEditor())
->setObject($mock)
->setActor($this->requireActor())
->subscribeExplicit($xaction->getNewValue())
->save();
break;
}
}
$mock->saveTransaction();
$this->sendMail($mock, $xactions, $is_new, $mentioned_phids);
PholioIndexer::indexMock($mock);
return $this;
}
private function sendMail(
PholioMock $mock,
array $xactions,
$is_new,
array $mentioned_phids) {
$subscribed_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$mock->getPHID());
$email_to = array(
$mock->getAuthorPHID(),
$this->requireActor()->getPHID(),
);
$email_cc = $subscribed_phids;
$phids = array_merge($email_to, $email_cc);
$handles = id(new PhabricatorObjectHandleData($phids))
->setViewer($this->requireActor())
->loadHandles();
$mock_id = $mock->getID();
$name = $mock->getName();
$original_name = $mock->getOriginalName();
$thread_id = 'pholio-mock-'.$mock->getPHID();
$mail_tags = $this->getMailTags($mock, $xactions);
$body = new PhabricatorMetaMTAMailBody();
$body->addRawSection('lorem ipsum');
$mock_uri = PhabricatorEnv::getProductionURI('/M'.$mock->getID());
$body->addTextSection(pht('MOCK DETAIL'), $mock_uri);
$reply_handler = $this->buildReplyHandler($mock);
$template = id(new PhabricatorMetaMTAMail())
->setSubject("M{$mock_id}: {$name}")
->setSubjectPrefix($this->getMailSubjectPrefix())
->setVarySubjectPrefix('[edit/create?]')
->setFrom($this->requireActor()->getPHID())
->addHeader('Thread-Topic', "M{$mock_id}: {$original_name}")
->setThreadID($thread_id, $is_new)
->setRelatedPHID($mock->getPHID())
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
->setIsBulk(true)
->setMailTags($mail_tags)
->setBody($body->render());
// TODO
// ->setParentMessageID(...)
$mails = $reply_handler->multiplexMail(
$template,
array_select_keys($handles, $email_to),
array_select_keys($handles, $email_cc));
foreach ($mails as $mail) {
$mail->saveAndSend();
}
$template->addTos($email_to);
$template->addCCs($email_cc);
return $template;
}
private function getMailTags(PholioMock $mock, array $xactions) {
assert_instances_of($xactions, 'PholioTransaction');
$tags = array();
return $tags;
}
public function buildReplyHandler(PholioMock $mock) {
$handler_object = new PholioReplyHandler();
$handler_object->setMailReceiver($mock);
return $handler_object;
}
private function getMailSubjectPrefix() {
return PhabricatorEnv::getEnvConfig('metamta.pholio.subject-prefix');
}
private function applyTransaction(
PholioMock $mock,
PholioTransaction $xaction) {
$type = $xaction->getTransactionType();
$old = null;
switch ($type) {
case PholioTransactionType::TYPE_NONE:
$old = null;
break;
case PholioTransactionType::TYPE_NAME:
$old = $mock->getName();
break;
case PholioTransactionType::TYPE_DESCRIPTION:
$old = $mock->getDescription();
break;
case PholioTransactionType::TYPE_VIEW_POLICY:
$old = $mock->getViewPolicy();
break;
case PholioTransactionType::TYPE_SUBSCRIBERS:
$old = PhabricatorSubscribersQuery::loadSubscribersForPHID(
$mock->getPHID());
break;
default:
throw new Exception("Unknown transaction type '{$type}'!");
}
$xaction->setOldValue($old);
if (!$this->transactionHasEffect($mock, $xaction)) {
return false;
}
switch ($type) {
case PholioTransactionType::TYPE_NONE:
break;
case PholioTransactionType::TYPE_NAME:
$mock->setName($xaction->getNewValue());
if ($mock->getOriginalName() === null) {
$mock->setOriginalName($xaction->getNewValue());
}
break;
case PholioTransactionType::TYPE_DESCRIPTION:
$mock->setDescription($xaction->getNewValue());
break;
case PholioTransactionType::TYPE_VIEW_POLICY:
$mock->setViewPolicy($xaction->getNewValue());
break;
case PholioTransactionType::TYPE_SUBSCRIBERS:
// This applies later.
break;
default:
throw new Exception("Unknown transaction type '{$type}'!");
}
return true;
}
private function transactionHasEffect(
PholioMock $mock,
PholioTransaction $xaction) {
$effect = false;
$old = $xaction->getOldValue();
$new = $xaction->getNewValue();
$type = $xaction->getTransactionType();
switch ($type) {
case PholioTransactionType::TYPE_NONE:
case PholioTransactionType::TYPE_NAME:
case PholioTransactionType::TYPE_DESCRIPTION:
case PholioTransactionType::TYPE_VIEW_POLICY:
$effect = ($old !== $new);
break;
case PholioTransactionType::TYPE_SUBSCRIBERS:
$old = nonempty($old, array());
$old_map = array_fill_keys($old, true);
$filtered = $old;
foreach ($new as $phid) {
if ($mock->getAuthorPHID() == $phid) {
// The author may not be explicitly subscribed.
continue;
}
if (isset($old_map[$phid])) {
// This PHID was already subscribed.
continue;
}
$filtered[] = $phid;
}
$old = array_keys($old_map);
$new = array_values($filtered);
$xaction->setOldValue($old);
$xaction->setNewValue($new);
$effect = ($old !== $new);
break;
default:
throw new Exception("Unknown transaction type '{$type}'!");
}
if (!$effect) {
if (strlen($xaction->getComment())) {
$xaction->setTransactionType(PholioTransactionType::TYPE_NONE);
$effect = true;
}
}
return $effect;
}
}
diff --git a/src/applications/pholio/indexer/PholioIndexer.php b/src/applications/pholio/indexer/PholioIndexer.php
index a95401ed4..2a87de40c 100644
--- a/src/applications/pholio/indexer/PholioIndexer.php
+++ b/src/applications/pholio/indexer/PholioIndexer.php
@@ -1,44 +1,28 @@
setPHID($mock->getPHID());
$doc->setDocumentType(phid_get_type($mock->getPHID()));
$doc->setDocumentTitle($mock->getName());
$doc->setDocumentCreated($mock->getDateCreated());
$doc->setDocumentModified($mock->getDateModified());
$doc->addField(
PhabricatorSearchField::FIELD_BODY,
$mock->getDescription());
$doc->addRelationship(
PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR,
$mock->getAuthorPHID(),
PhabricatorPHIDConstants::PHID_TYPE_USER,
$mock->getDateCreated());
self::reindexAbstractDocument($doc);
}
}
diff --git a/src/applications/pholio/mail/PholioReplyHandler.php b/src/applications/pholio/mail/PholioReplyHandler.php
index e2ceb2c7d..47cd9f24b 100644
--- a/src/applications/pholio/mail/PholioReplyHandler.php
+++ b/src/applications/pholio/mail/PholioReplyHandler.php
@@ -1,59 +1,43 @@
getDefaultPrivateReplyHandlerEmailAddress($handle, 'M');
}
public function getPublicReplyHandlerEmailAddress() {
return $this->getDefaultPublicReplyHandlerEmailAddress('M');
}
public function getReplyHandlerDomain() {
return PhabricatorEnv::getEnvConfig(
'metamta.pholio.reply-handler-domain');
}
public function getReplyHandlerInstructions() {
if ($this->supportsReplies()) {
// TODO: Implement.
return null;
return "Reply to comment.";
} else {
return null;
}
}
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
// TODO: Implement this.
return null;
}
}
diff --git a/src/applications/pholio/query/PholioMockQuery.php b/src/applications/pholio/query/PholioMockQuery.php
index 1964a1959..5aa6a5911 100644
--- a/src/applications/pholio/query/PholioMockQuery.php
+++ b/src/applications/pholio/query/PholioMockQuery.php
@@ -1,88 +1,72 @@
ids = $ids;
return $this;
}
public function withPHIDs(array $phids) {
$this->phids = $phids;
return $this;
}
public function withAuthorPHIDs(array $author_phids) {
$this->authorPHIDs = $author_phids;
return $this;
}
public function loadPage() {
$table = new PholioMock();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
}
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
$where[] = $this->buildPagingClause($conn_r);
if ($this->ids) {
$where[] = qsprintf(
$conn_r,
'id IN (%Ld)',
$this->ids);
}
if ($this->phids) {
$where[] = qsprintf(
$conn_r,
'phid IN (%Ls)',
$this->phids);
}
if ($this->authorPHIDs) {
$where[] = qsprintf(
$conn_r,
'authorPHID in (%Ls)',
$this->authorPHIDs);
}
return $this->formatWhereClause($where);
}
}
diff --git a/src/applications/pholio/query/PholioTransactionQuery.php b/src/applications/pholio/query/PholioTransactionQuery.php
index 376e49ddd..28761bbc8 100644
--- a/src/applications/pholio/query/PholioTransactionQuery.php
+++ b/src/applications/pholio/query/PholioTransactionQuery.php
@@ -1,64 +1,48 @@
mockIDs = $ids;
return $this;
}
public function execute() {
$table = new PholioTransaction();
$conn_r = $table->establishConnection('r');
$data = queryfx_all(
$conn_r,
'SELECT * FROM %T x %Q %Q %Q',
$table->getTableName(),
$this->buildWhereClause($conn_r),
$this->buildOrderClause($conn_r),
$this->buildLimitClause($conn_r));
return $table->loadAllFromArray($data);
}
private function buildWhereClause(AphrontDatabaseConnection $conn_r) {
$where = array();
if ($this->mockIDs) {
$where[] = qsprintf(
$conn_r,
'mockID IN (%Ld)',
$this->mockIDs);
}
return $this->formatWhereClause($where);
}
private function buildOrderClause(AphrontDatabaseConnection $conn_r) {
return 'ORDER BY id ASC';
}
}
diff --git a/src/applications/pholio/storage/PholioDAO.php b/src/applications/pholio/storage/PholioDAO.php
index ba49bc747..e755e3317 100644
--- a/src/applications/pholio/storage/PholioDAO.php
+++ b/src/applications/pholio/storage/PholioDAO.php
@@ -1,28 +1,12 @@
getMarkupText($field));
return 'M:'.$hash;
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getDescription();
}
public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
return $output;
}
public function shouldUseMarkupCache($field) {
return (bool)$this->getID();
}
}
diff --git a/src/applications/pholio/storage/PholioMock.php b/src/applications/pholio/storage/PholioMock.php
index 3e8274a5d..177771c95 100644
--- a/src/applications/pholio/storage/PholioMock.php
+++ b/src/applications/pholio/storage/PholioMock.php
@@ -1,113 +1,97 @@
true,
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNewPHID('MOCK');
}
public function save() {
if (!$this->getMailKey()) {
$this->setMailKey(Filesystem::readRandomCharacters(20));
}
return parent::save();
}
/* -( PhabricatorSubscribableInterface Implementation )-------------------- */
public function isAutomaticallySubscribed($phid) {
return ($this->authorPHID == $phid);
}
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return PhabricatorPolicies::POLICY_NOONE;
}
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return ($viewer->getPHID() == $this->getAuthorPHID());
}
/* -( PhabricatorMarkupInterface )----------------------------------------- */
public function getMarkupFieldKey($field) {
$hash = PhabricatorHash::digest($this->getMarkupText($field));
return 'M:'.$hash;
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getDescription();
}
public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
return $output;
}
public function shouldUseMarkupCache($field) {
return (bool)$this->getID();
}
}
diff --git a/src/applications/pholio/storage/PholioPixelComment.php b/src/applications/pholio/storage/PholioPixelComment.php
index 3a2b23564..f7284333a 100644
--- a/src/applications/pholio/storage/PholioPixelComment.php
+++ b/src/applications/pholio/storage/PholioPixelComment.php
@@ -1,62 +1,46 @@
getID();
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getComment();
}
public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
return $output;
}
public function shouldUseMarkupCache($field) {
return ($this->getID() && $this->getTransactionID());
}
}
diff --git a/src/applications/pholio/storage/PholioTransaction.php b/src/applications/pholio/storage/PholioTransaction.php
index d7f3bbff4..60515ee4a 100644
--- a/src/applications/pholio/storage/PholioTransaction.php
+++ b/src/applications/pholio/storage/PholioTransaction.php
@@ -1,122 +1,106 @@
array(
'oldValue' => self::SERIALIZATION_JSON,
'newValue' => self::SERIALIZATION_JSON,
'metadata' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}
public function setContentSource(PhabricatorContentSource $content_source) {
$this->contentSource = $content_source->serialize();
return $this;
}
public function getContentSource() {
return PhabricatorContentSource::newFromSerialized($this->contentSource);
}
public function getRequiredHandlePHIDs() {
switch ($this->getTransactionType()) {
case PholioTransactionType::TYPE_SUBSCRIBERS:
return array_merge(
$this->getOldValue(),
$this->getNewValue());
default:
return array();
}
}
/* -( PhabricatorSubscribableInterface Implementation )-------------------- */
public function isAutomaticallySubscribed($phid) {
return ($this->authorPHID == $phid);
}
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
}
public function getPolicy($capability) {
switch ($capability) {
case PhabricatorPolicyCapability::CAN_VIEW:
return $this->getViewPolicy();
case PhabricatorPolicyCapability::CAN_EDIT:
return PhabricatorPolicies::POLICY_NOONE;
}
}
public function hasAutomaticCapbility($capability, PhabricatorUser $viewer) {
return ($viewer->getPHID() == $this->getAuthorPHID());
}
/* -( PhabricatorMarkupInterface )----------------------------------------- */
public function getMarkupFieldKey($field) {
return 'MX:'.$this->getID();
}
public function newMarkupEngine($field) {
return PhabricatorMarkupEngine::newMarkupEngine(array());
}
public function getMarkupText($field) {
return $this->getComment();
}
public function didMarkupText($field, $output, PhutilMarkupEngine $engine) {
return $output;
}
public function shouldUseMarkupCache($field) {
return (bool)$this->getID();
}
}
diff --git a/src/applications/uiexample/examples/PhabricatorTimelineExample.php b/src/applications/uiexample/examples/PhabricatorTimelineExample.php
index 8b7f3bb7c..5003532d9 100644
--- a/src/applications/uiexample/examples/PhabricatorTimelineExample.php
+++ b/src/applications/uiexample/examples/PhabricatorTimelineExample.php
@@ -1,103 +1,87 @@
PhabricatorTimelineView to comments and transactions.';
}
public function renderExample() {
$request = $this->getRequest();
$user = $request->getUser();
$handle = PhabricatorObjectHandleData::loadOneHandle(
$user->getPHID(),
$user);
$events = array();
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('A major event.')
->appendChild('This is a major timeline event.');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('A minor event.');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->appendChild('A major event with no title.');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Another minor event.');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle);
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Major Red Event')
->appendChild('This event is red!')
->addClass('phabricator-timeline-red');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Minor Red Event')
->addClass('phabricator-timeline-red');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Minor Not-Red Event');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Minor Red Event')
->addClass('phabricator-timeline-red');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Minor Not-Red Event');
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Unstyled event')
->appendChild('This event disables standard title and content styling.')
->setDisableStandardTitleStyle(true)
->setDisableStandardContentStyle(true);
$events[] = id(new PhabricatorTimelineEventView())
->setUserHandle($handle)
->setTitle('Major Green Event')
->appendChild('This event is green!')
->addClass('phabricator-timeline-green');
$timeline = id(new PhabricatorTimelineView());
foreach ($events as $event) {
$timeline->addEvent($event);
}
return $timeline;
}
}
diff --git a/src/view/layout/PhabricatorTagView.php b/src/view/layout/PhabricatorTagView.php
index f923c5b7a..165ed2b9f 100644
--- a/src/view/layout/PhabricatorTagView.php
+++ b/src/view/layout/PhabricatorTagView.php
@@ -1,183 +1,167 @@
type = $type;
switch ($type) {
case self::TYPE_OBJECT:
$this->setBackgroundColor(self::COLOR_OBJECT);
break;
case self::TYPE_PERSON:
$this->setBackgroundColor(self::COLOR_PERSON);
break;
}
return $this;
}
public function setBarColor($bar_color) {
$this->barColor = $bar_color;
return $this;
}
public function setDotColor($dot_color) {
$this->dotColor = $dot_color;
return $this;
}
public function setBackgroundColor($background_color) {
$this->backgroundColor = $background_color;
return $this;
}
public function setPHID($phid) {
$this->phid = $phid;
return $this;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function setHref($href) {
$this->href = $href;
return $this;
}
public function setClosed($closed) {
$this->closed = $closed;
return $this;
}
public function render() {
if (!$this->type) {
throw new Exception("You must call setType() before render()!");
}
require_celerity_resource('phabricator-tag-view-css');
$classes = array(
'phabricator-tag-view',
'phabricator-tag-type-'.$this->type,
);
if ($this->closed) {
$classes[] = 'phabricator-tag-state-closed';
}
$color = null;
if ($this->backgroundColor) {
$color = 'phabricator-tag-color-'.$this->backgroundColor;
}
if ($this->dotColor) {
$dotcolor = 'phabricator-tag-color-'.$this->dotColor;
$dot = phutil_render_tag(
'span',
array(
'class' => 'phabricator-tag-dot '.$dotcolor,
),
'');
} else {
$dot = null;
}
$content = phutil_render_tag(
'span',
array(
'class' => 'phabricator-tag-core '.$color,
),
$dot.phutil_escape_html($this->name));
if ($this->barColor) {
$barcolor = 'phabricator-tag-color-'.$this->barColor;
$bar = phutil_render_tag(
'span',
array(
'class' => 'phabricator-tag-bar '.$barcolor,
),
'');
$classes[] = 'phabricator-tag-view-has-bar';
} else {
$bar = null;
}
return phutil_render_tag(
$this->href ? 'a' : 'span',
array(
'href' => $this->href,
'class' => implode(' ', $classes),
),
$bar.$content);
}
public static function getTagTypes() {
return array(
self::TYPE_PERSON,
self::TYPE_OBJECT,
self::TYPE_STATE,
);
}
public static function getColors() {
return array(
self::COLOR_RED,
self::COLOR_REDORANGE,
self::COLOR_ORANGE,
self::COLOR_YELLOW,
self::COLOR_BLUE,
self::COLOR_MAGENTA,
self::COLOR_GREEN,
self::COLOR_BLACK,
self::COLOR_GREY,
self::COLOR_WHITE,
self::COLOR_OBJECT,
self::COLOR_PERSON,
);
}
}
diff --git a/src/view/layout/PhabricatorTimelineEventView.php b/src/view/layout/PhabricatorTimelineEventView.php
index 6bc755c56..1a57d8a92 100644
--- a/src/view/layout/PhabricatorTimelineEventView.php
+++ b/src/view/layout/PhabricatorTimelineEventView.php
@@ -1,143 +1,127 @@
userHandle = $handle;
return $this;
}
public function setTitle($title) {
$this->title = $title;
return $this;
}
public function addClass($class) {
$this->classes[] = $class;
return $this;
}
public function setDisableStandardTitleStyle($disable) {
$this->disableStandardTitleStyle = $disable;
return $this;
}
public function setDisableStandardContentStyle($disable) {
$this->disableStandardContentStyle = $disable;
return $this;
}
public function render() {
$content = $this->renderChildren();
$title = $this->title;
if (($title === null) && !strlen($content)) {
$title = '';
}
if ($title !== null) {
$title_classes = array();
$title_classes[] = 'phabricator-timeline-title';
if (!$this->disableStandardTitleStyle) {
$title_classes[] = 'phabricator-timeline-standard-title';
}
$title = phutil_render_tag(
'div',
array(
'class' => implode(' ', $title_classes),
),
$title);
}
$wedge = phutil_render_tag(
'div',
array(
'class' => 'phabricator-timeline-wedge phabricator-timeline-border',
),
'');
$image_uri = $this->userHandle->getImageURI();
$image = phutil_render_tag(
'div',
array(
'style' => 'background-image: url('.$image_uri.')',
'class' => 'phabricator-timeline-image',
),
'');
$content_classes = array();
$content_classes[] = 'phabricator-timeline-content';
if (!$this->disableStandardContentStyle) {
$content_classes[] = 'phabricator-timeline-standard-content';
}
$classes = array();
$classes[] = 'phabricator-timeline-event-view';
$classes[] = 'phabricator-timeline-border';
if ($content) {
$classes[] = 'phabricator-timeline-major-event';
$content = phutil_render_tag(
'div',
array(
'class' => implode(' ', $content_classes),
),
phutil_render_tag(
'div',
array(
'class' => 'phabricator-timeline-inner-content',
),
$title.
phutil_render_tag(
'div',
array(
'class' => 'phabricator-timeline-core-content',
),
$content)));
$content = $image.$wedge.$content;
} else {
$classes[] = 'phabricator-timeline-minor-event';
$content = phutil_render_tag(
'div',
array(
'class' => implode(' ', $content_classes),
),
$image.$wedge.$title);
}
return phutil_render_tag(
'div',
array(
'class' => implode(' ', $this->classes),
),
phutil_render_tag(
'div',
array(
'class' => implode(' ', $classes),
),
$content));
}
}
diff --git a/src/view/layout/PhabricatorTimelineView.php b/src/view/layout/PhabricatorTimelineView.php
index 12116d3c9..91773e100 100644
--- a/src/view/layout/PhabricatorTimelineView.php
+++ b/src/view/layout/PhabricatorTimelineView.php
@@ -1,51 +1,35 @@
events[] = $event;
return $this;
}
public function render() {
require_celerity_resource('phabricator-timeline-view-css');
$events = array();
foreach ($this->events as $event) {
$events[] = phutil_render_tag(
'div',
array(
'class' => 'phabricator-timeline-event-view '.
'phabricator-timeline-spacer',
),
'');
$events[] = $this->renderSingleView($event);
}
return phutil_render_tag(
'div',
array(
'class' => 'phabricator-timeline-view',
),
implode('', $events));
}
}