Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/diffusion/controller/home/DiffusionHomeController.php b/src/applications/diffusion/controller/home/DiffusionHomeController.php
index bf816fb50f..448c9f316e 100644
--- a/src/applications/diffusion/controller/home/DiffusionHomeController.php
+++ b/src/applications/diffusion/controller/home/DiffusionHomeController.php
@@ -1,163 +1,163 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionHomeController extends DiffusionController {
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$shortcuts = id(new PhabricatorRepositoryShortcut())->loadAll();
if ($shortcuts) {
$shortcuts = msort($shortcuts, 'getSequence');
$rows = array();
foreach ($shortcuts as $shortcut) {
$rows[] = array(
phutil_render_tag(
'a',
array(
'href' => $shortcut->getHref(),
),
phutil_escape_html($shortcut->getName())),
phutil_escape_html($shortcut->getDescription()),
);
}
$shortcut_table = new AphrontTableView($rows);
$shortcut_table->setHeaders(
array(
'Link',
'',
));
$shortcut_table->setColumnClasses(
array(
'pri',
'wide',
));
$shortcut_panel = new AphrontPanelView();
$shortcut_panel->setHeader('Shortcuts');
$shortcut_panel->appendChild($shortcut_table);
} else {
$shortcut_panel = null;
}
$repository = new PhabricatorRepository();
$repositories = $repository->loadAll();
- foreach ($repositories as $key => $repository) {
- if (!$repository->isTracked()) {
- unset($repositories[$key]);
+ foreach ($repositories as $key => $repo) {
+ if (!$repo->isTracked()) {
+ unset($repo[$key]);
}
}
$repository_ids = mpull($repositories, 'getID');
$summaries = array();
$commits = array();
if ($repository_ids) {
$summaries = queryfx_all(
$repository->establishConnection('r'),
'SELECT * FROM %T WHERE repositoryID IN (%Ld)',
PhabricatorRepository::TABLE_SUMMARY,
$repository_ids);
$summaries = ipull($summaries, null, 'repositoryID');
$commit_ids = array_filter(ipull($summaries, 'lastCommitID'));
if ($commit_ids) {
$commit = new PhabricatorRepositoryCommit();
$commits = $commit->loadAllWhere('id IN (%Ld)', $commit_ids);
$commits = mpull($commits, null, 'getRepositoryID');
}
}
$rows = array();
foreach ($repositories as $repository) {
$id = $repository->getID();
$commit = idx($commits, $id);
$size = idx(idx($summaries, $id, array()), 'size', 0);
$date = '-';
$time = '-';
if ($commit) {
$date = phabricator_date($commit->getEpoch(), $user);
$time = phabricator_time($commit->getEpoch(), $user);
}
$rows[] = array(
phutil_render_tag(
'a',
array(
'href' => '/diffusion/'.$repository->getCallsign().'/',
),
phutil_escape_html($repository->getName())),
phutil_escape_html($repository->getDetail('description')),
PhabricatorRepositoryType::getNameForRepositoryType(
$repository->getVersionControlSystem()),
$size ? number_format($size) : '-',
$commit
? DiffusionView::linkCommit(
$repository,
$commit->getCommitIdentifier())
: '-',
$date,
$time,
);
}
$table = new AphrontTableView($rows);
$table->setHeaders(
array(
'Repository',
'Description',
'VCS',
'Commits',
'Last',
'Date',
'Time',
));
$table->setColumnClasses(
array(
'pri',
'wide',
'',
'n',
'n',
'',
'right',
));
$panel = new AphrontPanelView();
$panel->setHeader('Browse Repositories');
$panel->appendChild($table);
$crumbs = $this->buildCrumbs();
return $this->buildStandardPageResponse(
array(
$crumbs,
$shortcut_panel,
$panel,
),
array(
'title' => 'Diffusion',
));
}
}
diff --git a/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
index 14e09dafcf..5183448e02 100644
--- a/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
+++ b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php
@@ -1,302 +1,302 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DiffusionHistoryTableView extends DiffusionView {
private $history;
private $handles = array();
private $isHead;
private $parents;
public function setHistory(array $history) {
$this->history = $history;
return $this;
}
public function setHandles(array $handles) {
$this->handles = $handles;
return $this;
}
public function getRequiredHandlePHIDs() {
$phids = array();
foreach ($this->history as $item) {
$data = $item->getCommitData();
if ($data) {
if ($data->getCommitDetail('authorPHID')) {
$phids[$data->getCommitDetail('authorPHID')] = true;
}
}
}
return array_keys($phids);
}
public function setParents(array $parents) {
$this->parents = $parents;
return $this;
}
public function setIsHead($is_head) {
$this->isHead = $is_head;
return $this;
}
public function render() {
$drequest = $this->getDiffusionRequest();
$handles = $this->handles;
$graph = null;
if ($this->parents) {
$graph = $this->renderGraph();
}
$rows = array();
$ii = 0;
foreach ($this->history as $history) {
$epoch = $history->getEpoch();
if ($epoch) {
$date = date('M j, Y', $epoch);
$time = date('g:i A', $epoch);
} else {
$date = null;
$time = null;
}
$data = $history->getCommitData();
$author_phid = null;
if ($data) {
$author_phid = $data->getCommitDetail('authorPHID');
}
if ($author_phid && isset($handles[$author_phid])) {
$author = $handles[$author_phid]->renderLink();
} else {
$author = phutil_escape_html($history->getAuthorName());
}
$rows[] = array(
$this->linkBrowse(
$drequest->getPath(),
array(
'commit' => $history->getCommitIdentifier(),
)),
$graph ? $graph[$ii++] : null,
self::linkCommit(
$drequest->getRepository(),
$history->getCommitIdentifier()),
$this->linkChange(
$history->getChangeType(),
$history->getFileType(),
null,
$history->getCommitIdentifier()),
$date,
$time,
$author,
AphrontTableView::renderSingleDisplayLine(
phutil_escape_html($history->getSummary())),
// TODO: etc etc
);
}
$view = new AphrontTableView($rows);
$view->setHeaders(
array(
'Browse',
'',
'Commit',
'Change',
'Date',
'Time',
'Author',
'Details',
));
$view->setColumnClasses(
array(
'',
'threads',
'n',
'',
'',
'right',
'',
'wide',
));
$view->setColumnVisibility(
array(
true,
$graph ? true : false,
));
return $view->render();
}
/**
* Draw a merge/branch graph from the parent revision data. We're basically
* building up a bunch of strings like this:
*
* ^
* |^
* o|
* |o
* o
*
* ...which form an ASCII representation of the graph we eventaully want to
* draw.
*
* NOTE: The actual implementation is black magic.
*/
private function renderGraph() {
// This keeps our accumulated information about each line of the
// merge/branch graph.
$graph = array();
// This holds the next commit we're looking for in each column of the
// graph.
$threads = array();
// This is the largest number of columns any row has, i.e. the width of
// the graph.
$count = 0;
foreach ($this->history as $key => $history) {
$joins = array();
$splits = array();
$parent_list = $this->parents[$history->getCommitIdentifier()];
// Look for some thread which has this commit as the next commit. If
// we find one, this commit goes on that thread. Otherwise, this commit
// goes on a new thread.
$line = '';
$found = false;
$pos = count($threads);
for ($n = 0; $n < $count; $n++) {
if (empty($threads[$n])) {
$line .= ' ';
continue;
}
if ($threads[$n] == $history->getCommitIdentifier()) {
if ($found) {
$line .= ' ';
$joins[] = $n;
unset($threads[$n]);
} else {
$line .= 'o';
$found = true;
$pos = $n;
}
} else {
// We render a "|" for any threads which have a commit that we haven't
// seen yet, this is later drawn as a vertical line.
$line .= '|';
}
}
// If we didn't find the thread this commit goes on, start a new thread.
// We use "o" to mark the commit for the rendering engine, or "^" to
// indicate that there's nothing after it so the line from the commit
// upward should not be drawn.
if (!$found) {
if ($this->isHead) {
$line .= '^';
} else {
$line .= 'o';
foreach ($graph as $k => $meta) {
// Go back across all the lines we've already drawn and add a
// "|" to the end, since this is connected to some future commit
// we don't know about.
for ($jj = strlen($meta['line']); $jj <= $count; $jj++) {
$graph[$k]['line'] .= '|';
}
}
}
}
// Update the next commit on this thread to the commit's first parent.
// This might have the effect of making a new thread.
$threads[$pos] = head($parent_list);
// If we made a new thread, increase the thread count.
$count = max($pos + 1, $count);
// Now, deal with splits (merges). I picked this terms opposite to the
// underlying repository term to confuse you.
foreach (array_slice($parent_list, 1) as $parent) {
$found = false;
// Try to find the other parent(s) in our existing threads. If we find
// them, split to that thread.
- foreach ($threads as $n => $thread_commit) {
+ foreach ($threads as $idx => $thread_commit) {
if ($thread_commit == $parent) {
$found = true;
- $splits[] = $n;
+ $splits[] = $idx;
}
}
// If we didn't find the parent, we don't know about it yet. Find the
// first free thread and add it as the "next" commit in that thread.
// This might create a new thread.
if (!$found) {
for ($n = 0; $n < $count; $n++) {
if (empty($threads[$n])) {
break;
}
}
$threads[$n] = $parent;
$splits[] = $n;
$count = max($n + 1, $count);
}
}
$graph[] = array(
'line' => $line,
'split' => $splits,
'join' => $joins,
);
}
// Render into tags for the behavior.
foreach ($graph as $k => $meta) {
$graph[$k] = javelin_render_tag(
'div',
array(
'sigil' => 'commit-graph',
'meta' => $meta,
),
'');
}
Javelin::initBehavior(
'diffusion-commit-graph',
array(
'count' => $count,
));
return $graph;
}
}
diff --git a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php
index b497c4a509..b94dbd262f 100644
--- a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php
+++ b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php
@@ -1,628 +1,628 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @group maniphest
*/
final class ManiphestTransactionDetailView extends ManiphestView {
private $transactions;
private $handles;
private $markupEngine;
private $forEmail;
private $preview;
private $commentNumber;
private $rangeSpecification;
private $renderSummaryOnly;
private $renderFullSummary;
private $user;
private $auxiliaryFields;
public function setAuxiliaryFields(array $fields) {
$this->auxiliaryFields = mpull($fields, null, 'getAuxiliaryKey');
return $this;
}
public function getAuxiliaryField($key) {
return idx($this->auxiliaryFields, $key);
}
public function setTransactionGroup(array $transactions) {
$this->transactions = $transactions;
return $this;
}
public function setHandles(array $handles) {
$this->handles = $handles;
return $this;
}
public function setMarkupEngine(PhutilMarkupEngine $engine) {
$this->markupEngine = $engine;
return $this;
}
public function setPreview($preview) {
$this->preview = $preview;
return $this;
}
public function setRenderSummaryOnly($render_summary_only) {
$this->renderSummaryOnly = $render_summary_only;
return $this;
}
public function getRenderSummaryOnly() {
return $this->renderSummaryOnly;
}
public function setRenderFullSummary($render_full_summary) {
$this->renderFullSummary = $render_full_summary;
return $this;
}
public function getRenderFullSummary() {
return $this->renderFullSummary;
}
public function setCommentNumber($comment_number) {
$this->commentNumber = $comment_number;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function setRangeSpecification($range) {
$this->rangeSpecification = $range;
return $this;
}
public function getRangeSpecification() {
return $this->rangeSpecification;
}
public function renderForEmail($with_date) {
$this->forEmail = true;
$transaction = reset($this->transactions);
$author = $this->renderHandles(array($transaction->getAuthorPHID()));
$action = null;
$descs = array();
$comments = null;
foreach ($this->transactions as $transaction) {
list($verb, $desc, $classes) = $this->describeAction($transaction);
if ($desc === null) {
continue;
}
if ($action === null) {
$action = $verb;
}
$desc = $author.' '.$desc.'.';
if ($with_date) {
// NOTE: This is going into a (potentially multi-recipient) email so
// we can't use a single user's timezone preferences. Use the server's
// instead, but make the timezone explicit.
$datetime = date('M jS \a\t g:i A T', $transaction->getDateCreated());
$desc = "On {$datetime}, {$desc}";
}
$descs[] = $desc;
if ($transaction->hasComments()) {
$comments = $transaction->getComments();
}
}
$descs = implode("\n", $descs);
if ($comments) {
$descs .= "\n".$comments;
}
foreach ($this->transactions as $transaction) {
$supplemental = $this->renderSupplementalInfoForEmail($transaction);
if ($supplemental) {
$descs .= "\n\n".$supplemental;
}
}
$this->forEmail = false;
return array($action, $descs);
}
public function render() {
if (!$this->user) {
throw new Exception("Call setUser() before render()!");
}
$handles = $this->handles;
$transactions = $this->transactions;
require_celerity_resource('maniphest-transaction-detail-css');
$comment_transaction = null;
foreach ($this->transactions as $transaction) {
if ($transaction->hasComments()) {
$comment_transaction = $transaction;
break;
}
}
$any_transaction = reset($transactions);
$author = $this->handles[$any_transaction->getAuthorPHID()];
$more_classes = array();
$descs = array();
foreach ($transactions as $transaction) {
list($verb, $desc, $classes) = $this->describeAction($transaction);
if ($desc === null) {
continue;
}
$more_classes = array_merge($more_classes, $classes);
$full_summary = null;
if ($this->getRenderFullSummary()) {
$full_summary = $this->renderFullSummary($transaction);
}
$descs[] = javelin_render_tag(
'div',
array(
'sigil' => 'maniphest-transaction-description',
),
$author->renderLink().' '.$desc.'.'.$full_summary);
}
if ($this->getRenderSummaryOnly()) {
return implode("\n", $descs);
}
if ($comment_transaction && $comment_transaction->hasComments()) {
$comments = $comment_transaction->getCache();
if (!strlen($comments)) {
$comments = $comment_transaction->getComments();
if (strlen($comments)) {
$comments = $this->markupEngine->markupText($comments);
$comment_transaction->setCache($comments);
if ($comment_transaction->getID() && !$this->preview) {
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$comment_transaction->save();
unset($unguarded);
}
}
}
$comment_block =
'<div class="maniphest-transaction-comments phabricator-remarkup">'.
$comments.
'</div>';
} else {
$comment_block = null;
}
$source_transaction = nonempty($comment_transaction, $any_transaction);
$xaction_view = id(new PhabricatorTransactionView())
->setUser($this->user)
->setImageURI($author->getImageURI())
->setContentSource($source_transaction->getContentSource())
->setActions($descs);
foreach ($more_classes as $class) {
$xaction_view->addClass($class);
}
if ($this->preview) {
$xaction_view->setIsPreview($this->preview);
} else {
$xaction_view->setEpoch($any_transaction->getDateCreated());
if ($this->commentNumber) {
$anchor_name = 'comment-'.$this->commentNumber;
$anchor_text = 'T'.$any_transaction->getTaskID().'#'.$anchor_name;
$xaction_view->setAnchor($anchor_name, $anchor_text);
}
}
$xaction_view->appendChild($comment_block);
return $xaction_view->render();
}
private function renderSupplementalInfoForEmail($transaction) {
$handles = $this->handles;
$type = $transaction->getTransactionType();
$new = $transaction->getNewValue();
$old = $transaction->getOldValue();
switch ($type) {
case ManiphestTransactionType::TYPE_DESCRIPTION:
return "NEW DESCRIPTION\n ".trim($new)."\n\n".
"PREVIOUS DESCRIPTION\n ".trim($old);
case ManiphestTransactionType::TYPE_ATTACH:
$old_raw = nonempty($old, array());
$new_raw = nonempty($new, array());
$attach_types = array(
PhabricatorPHIDConstants::PHID_TYPE_DREV,
PhabricatorPHIDConstants::PHID_TYPE_FILE,
);
- foreach ($attach_types as $type) {
- $old = array_keys(idx($old_raw, $type, array()));
- $new = array_keys(idx($new_raw, $type, array()));
+ foreach ($attach_types as $attach_type) {
+ $old = array_keys(idx($old_raw, $attach_type, array()));
+ $new = array_keys(idx($new_raw, $attach_type, array()));
if ($old != $new) {
break;
}
}
$added = array_diff($new, $old);
if (!$added) {
break;
}
$links = array();
foreach (array_select_keys($handles, $added) as $handle) {
$links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI());
}
$links = implode("\n", $links);
- switch ($type) {
+ switch ($attach_type) {
case PhabricatorPHIDConstants::PHID_TYPE_DREV:
$title = 'ATTACHED REVISIONS';
break;
case PhabricatorPHIDConstants::PHID_TYPE_FILE:
$title = 'ATTACHED FILES';
break;
}
return $title."\n".$links;
default:
break;
}
return null;
}
private function describeAction($transaction) {
$verb = null;
$desc = null;
$classes = array();
$handles = $this->handles;
$type = $transaction->getTransactionType();
$author_phid = $transaction->getAuthorPHID();
$new = $transaction->getNewValue();
$old = $transaction->getOldValue();
switch ($type) {
case ManiphestTransactionType::TYPE_TITLE:
$verb = 'Retitled';
$desc = 'changed the title from '.$this->renderString($old).
' to '.$this->renderString($new);
break;
case ManiphestTransactionType::TYPE_DESCRIPTION:
$verb = 'Edited';
if ($this->forEmail || $this->getRenderFullSummary()) {
$desc = 'updated the task description';
} else {
$desc = 'updated the task description; '.
$this->renderExpandLink($transaction);
}
break;
case ManiphestTransactionType::TYPE_NONE:
$verb = 'Commented On';
$desc = 'added a comment';
break;
case ManiphestTransactionType::TYPE_OWNER:
if ($transaction->getAuthorPHID() == $new) {
$verb = 'Claimed';
$desc = 'claimed this task';
$classes[] = 'claimed';
} else if (!$new) {
$verb = 'Up For Grabs';
$desc = 'placed this task up for grabs';
$classes[] = 'upforgrab';
} else if (!$old) {
$verb = 'Assigned';
$desc = 'assigned this task to '.$this->renderHandles(array($new));
$classes[] = 'assigned';
} else {
$verb = 'Reassigned';
$desc = 'reassigned this task from '.
$this->renderHandles(array($old)).
' to '.
$this->renderHandles(array($new));
$classes[] = 'reassigned';
}
break;
case ManiphestTransactionType::TYPE_CCS:
if ($this->preview) {
$verb = 'Changed CC';
$desc = 'changed CCs..';
break;
}
$added = array_diff($new, $old);
$removed = array_diff($old, $new);
if ($added && !$removed) {
$verb = 'Added CC';
if (count($added) == 1) {
$desc = 'added '.$this->renderHandles($added).' to CC';
} else {
$desc = 'added CCs: '.$this->renderHandles($added);
}
} else if ($removed && !$added) {
$verb = 'Removed CC';
if (count($removed) == 1) {
$desc = 'removed '.$this->renderHandles($removed).' from CC';
} else {
$desc = 'removed CCs: '.$this->renderHandles($removed);
}
} else {
$verb = 'Changed CC';
$desc = 'changed CCs, added: '.$this->renderHandles($added).'; '.
'removed: '.$this->renderHandles($removed);
}
break;
case ManiphestTransactionType::TYPE_PROJECTS:
if ($this->preview) {
$verb = 'Changed Projects';
$desc = 'changed projects..';
break;
}
$added = array_diff($new, $old);
$removed = array_diff($old, $new);
if ($added && !$removed) {
$verb = 'Added Project';
if (count($added) == 1) {
$desc = 'added project '.$this->renderHandles($added);
} else {
$desc = 'added projects: '.$this->renderHandles($added);
}
} else if ($removed && !$added) {
$verb = 'Removed Project';
if (count($removed) == 1) {
$desc = 'removed project '.$this->renderHandles($removed);
} else {
$desc = 'removed projectss: '.$this->renderHandles($removed);
}
} else {
$verb = 'Changed Projects';
$desc = 'changed projects, added: '.$this->renderHandles($added).'; '.
'removed: '.$this->renderHandles($removed);
}
break;
case ManiphestTransactionType::TYPE_STATUS:
if ($new == ManiphestTaskStatus::STATUS_OPEN) {
if ($old) {
$verb = 'Reopened';
$desc = 'reopened this task';
$classes[] = 'reopened';
} else {
$verb = 'Created';
$desc = 'created this task';
$classes[] = 'created';
}
} else if ($new == ManiphestTaskStatus::STATUS_CLOSED_SPITE) {
$verb = 'Spited';
$desc = 'closed this task out of spite';
$classes[] = 'spited';
} else if ($new == ManiphestTaskStatus::STATUS_CLOSED_DUPLICATE) {
$verb = 'Merged';
$desc = 'closed this task as a duplicate';
$classes[] = 'duplicate';
} else {
$verb = 'Closed';
$full = idx(ManiphestTaskStatus::getTaskStatusMap(), $new, '???');
$desc = 'closed this task as "'.$full.'"';
$classes[] = 'closed';
}
break;
case ManiphestTransactionType::TYPE_PRIORITY:
$old_name = ManiphestTaskPriority::getTaskPriorityName($old);
$new_name = ManiphestTaskPriority::getTaskPriorityName($new);
if ($old == ManiphestTaskPriority::PRIORITY_TRIAGE) {
$verb = 'Triaged';
$desc = 'triaged this task as "'.$new_name.'" priority';
} else if ($old > $new) {
$verb = 'Lowered Priority';
$desc = 'lowered the priority of this task from "'.$old_name.'" to '.
'"'.$new_name.'"';
} else {
$verb = 'Raised Priority';
$desc = 'raised the priority of this task from "'.$old_name.'" to '.
'"'.$new_name.'"';
}
if ($new == ManiphestTaskPriority::PRIORITY_UNBREAK_NOW) {
$classes[] = 'unbreaknow';
}
break;
case ManiphestTransactionType::TYPE_ATTACH:
if ($this->preview) {
$verb = 'Changed Attached';
$desc = 'changed attachments..';
break;
}
$old_raw = nonempty($old, array());
$new_raw = nonempty($new, array());
foreach (array(
PhabricatorPHIDConstants::PHID_TYPE_DREV,
PhabricatorPHIDConstants::PHID_TYPE_TASK,
- PhabricatorPHIDConstants::PHID_TYPE_FILE) as $type) {
- $old = array_keys(idx($old_raw, $type, array()));
- $new = array_keys(idx($new_raw, $type, array()));
+ PhabricatorPHIDConstants::PHID_TYPE_FILE) as $attach_type) {
+ $old = array_keys(idx($old_raw, $attach_type, array()));
+ $new = array_keys(idx($new_raw, $attach_type, array()));
if ($old != $new) {
break;
}
}
$added = array_diff($new, $old);
$removed = array_diff($old, $new);
$add_desc = $this->renderHandles($added);
$rem_desc = $this->renderHandles($removed);
- switch ($type) {
+ switch ($attach_type) {
case PhabricatorPHIDConstants::PHID_TYPE_DREV:
$singular = 'Differential Revision';
$plural = 'Differential Revisions';
break;
case PhabricatorPHIDConstants::PHID_TYPE_FILE:
$singular = 'file';
$plural = 'files';
break;
case PhabricatorPHIDConstants::PHID_TYPE_TASK:
$singular = 'Maniphest Task';
$plural = 'Maniphest Tasks';
$dependency = true;
break;
}
if ($added && !$removed) {
$verb = 'Attached';
if (count($added) == 1) {
$desc = 'attached '.$singular.': '.$add_desc;
} else {
$desc = 'attached '.$plural.': '.$add_desc;
}
} else if ($removed && !$added) {
$verb = 'Detached';
if (count($removed) == 1) {
$desc = 'detached '.$singular.': '.$rem_desc;
} else {
$desc = 'detached '.$plural.': '.$rem_desc;
}
} else {
$verb = 'Changed Attached';
$desc = 'changed attached '.$plural.', added: '.$add_desc.'; '.
'removed: '.$rem_desc;
}
break;
case ManiphestTransactionType::TYPE_AUXILIARY:
$aux_key = $transaction->getMetadataValue('aux:key');
$aux_field = $this->getAuxiliaryField($aux_key);
$verb = null;
if ($aux_field) {
$verb = $aux_field->renderTransactionEmailVerb($transaction);
}
if ($verb === null) {
if ($old === null) {
$verb = "Set Field";
} else if ($new === null) {
$verb = "Removed Field";
} else {
$verb = "Updated Field";
}
}
$desc = null;
if ($aux_field) {
$use_field = $aux_field;
} else {
$use_field = id(new ManiphestAuxiliaryFieldDefaultSpecification())
->setFieldType(
ManiphestAuxiliaryFieldDefaultSpecification::TYPE_STRING);
}
$desc = $use_field->renderTransactionDescription(
$transaction,
$this->forEmail
? ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_TEXT
: ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_HTML);
break;
default:
return array($type, ' brazenly '.$type."'d", $classes);
}
return array($verb, $desc, $classes);
}
private function renderFullSummary($transaction) {
switch ($transaction->getTransactionType()) {
case ManiphestTransactionType::TYPE_DESCRIPTION:
$id = $transaction->getID();
$old_text = wordwrap($transaction->getOldValue(), 80);
$new_text = wordwrap($transaction->getNewValue(), 80);
$engine = new PhabricatorDifferenceEngine();
$changeset = $engine->generateChangesetFromFileContent($old_text,
$new_text);
$whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL;
$parser = new DifferentialChangesetParser();
$parser->setChangeset($changeset);
$parser->setRenderingReference($id);
$parser->setWhitespaceMode($whitespace_mode);
$spec = $this->getRangeSpecification();
list($range_s, $range_e, $mask) =
DifferentialChangesetParser::parseRangeSpecification($spec);
$output = $parser->render($range_s, $range_e, $mask);
return $output;
}
return null;
}
private function renderExpandLink($transaction) {
$id = $transaction->getID();
Javelin::initBehavior('maniphest-transaction-expand');
return javelin_render_tag(
'a',
array(
'href' => '/maniphest/task/descriptionchange/'.$id.'/',
'sigil' => 'maniphest-expand-transaction',
'mustcapture' => true,
),
'show details');
}
private function renderHandles($phids) {
$links = array();
foreach ($phids as $phid) {
if ($this->forEmail) {
$links[] = $this->handles[$phid]->getName();
} else {
$links[] = $this->handles[$phid]->renderLink();
}
}
return implode(', ', $links);
}
private function renderString($string) {
if ($this->forEmail) {
return '"'.$string.'"';
} else {
return '"'.phutil_escape_html($string).'"';
}
}
}
diff --git a/src/infrastructure/celerity/controller/CelerityResourceController.php b/src/infrastructure/celerity/controller/CelerityResourceController.php
index fac5a3c9fe..4ef21895f1 100644
--- a/src/infrastructure/celerity/controller/CelerityResourceController.php
+++ b/src/infrastructure/celerity/controller/CelerityResourceController.php
@@ -1,143 +1,143 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Delivers CSS and JS resources to the browser. This controller handles all
* ##/res/## requests, and manages caching, package construction, and resource
* preprocessing.
*
* @group celerity
*/
final class CelerityResourceController extends AphrontController {
private $path;
private $hash;
private $package;
public function willProcessRequest(array $data) {
$this->path = $data['path'];
$this->hash = $data['hash'];
$this->package = !empty($data['package']);
}
public function processRequest() {
$path = $this->path;
// Sanity checking to keep this from exposing anything sensitive.
$path = preg_replace('@(//|\\.\\.)@', '', $path);
$matches = null;
if (!preg_match('/\.(css|js)$/', $path, $matches)) {
throw new Exception("Only CSS and JS resources may be served.");
}
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) &&
!PhabricatorEnv::getEnvConfig('celerity.force-disk-reads')) {
// Return a "304 Not Modified". We don't care about the value of this
// field since we never change what resource is served by a given URI.
return $this->makeResponseCacheable(new Aphront304Response());
}
$type = $matches[1];
$root = dirname(phutil_get_library_root('phabricator'));
if ($this->package) {
$map = CelerityResourceMap::getInstance();
$paths = $map->resolvePackage($this->hash);
if (!$paths) {
return new Aphront404Response();
}
try {
$data = array();
- foreach ($paths as $path) {
- $data[] = Filesystem::readFile($root.'/webroot/'.$path);
+ foreach ($paths as $package_path) {
+ $data[] = Filesystem::readFile($root.'/webroot/'.$package_path);
}
$data = implode("\n\n", $data);
} catch (Exception $ex) {
return new Aphront404Response();
}
} else {
try {
$data = Filesystem::readFile($root.'/webroot/'.$path);
} catch (Exception $ex) {
return new Aphront404Response();
}
}
$response = new AphrontFileResponse();
$data = $this->minifyData($data, $type);
$response->setContent($data);
switch ($type) {
case 'css':
$response->setMimeType("text/css; charset=utf-8");
break;
case 'js':
$response->setMimeType("text/javascript; charset=utf-8");
break;
}
return $this->makeResponseCacheable($response);
}
private function makeResponseCacheable(AphrontResponse $response) {
$response->setCacheDurationInSeconds(60 * 60 * 24 * 30);
$response->setLastModified(time());
return $response;
}
private function minifyData($data, $type) {
if (!PhabricatorEnv::getEnvConfig('celerity.minify')) {
return $data;
}
switch ($type) {
case 'css':
// Remove comments.
$data = preg_replace('@/\*.*?\*/@s', '', $data);
// Remove whitespace around symbols.
$data = preg_replace('@\s*([{}:;,])\s+@', '\1', $data);
// Remove unnecessary semicolons.
$data = preg_replace('@;}@', '}', $data);
// Replace #rrggbb with #rgb when possible.
$data = preg_replace(
'@#([a-f0-9])\1([a-f0-9])\2([a-f0-9])\3@i',
'#\1\2\3',
$data);
$data = trim($data);
break;
case 'js':
$root = dirname(phutil_get_library_root('phabricator'));
$bin = $root.'/externals/javelin/support/jsxmin/jsxmin';
if (@file_exists($bin)) {
$future = new ExecFuture("{$bin} __DEV__:0");
$future->write($data);
list($err, $result) = $future->resolve();
if (!$err) {
$data = $result;
}
}
break;
}
return $data;
}
}
diff --git a/src/view/control/table/AphrontTableView.php b/src/view/control/table/AphrontTableView.php
index f48d8507b8..c958d95fc7 100644
--- a/src/view/control/table/AphrontTableView.php
+++ b/src/view/control/table/AphrontTableView.php
@@ -1,274 +1,274 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class AphrontTableView extends AphrontView {
protected $data;
protected $headers;
protected $rowClasses = array();
protected $columnClasses = array();
protected $zebraStripes = true;
protected $noDataString;
protected $className;
protected $columnVisibility = array();
protected $sortURI;
protected $sortParam;
protected $sortSelected;
protected $sortReverse;
protected $sortValues;
public function __construct(array $data) {
$this->data = $data;
}
public function setHeaders(array $headers) {
$this->headers = $headers;
return $this;
}
public function setColumnClasses(array $column_classes) {
$this->columnClasses = $column_classes;
return $this;
}
public function setRowClasses(array $row_classes) {
$this->rowClasses = $row_classes;
return $this;
}
public function setNoDataString($no_data_string) {
$this->noDataString = $no_data_string;
return $this;
}
public function setClassName($class_name) {
$this->className = $class_name;
return $this;
}
public function setZebraStripes($zebra_stripes) {
$this->zebraStripes = $zebra_stripes;
return $this;
}
public function setColumnVisibility(array $visibility) {
$this->columnVisibility = $visibility;
return $this;
}
/**
* Parse a sorting parameter:
*
* list($sort, $reverse) = AphrontTableView::parseSortParam($sort_param);
*
* @param string Sort request parameter.
* @return pair Sort value, sort direction.
*/
public static function parseSort($sort) {
return array(ltrim($sort, '-'), preg_match('/^-/', $sort));
}
public function makeSortable(
PhutilURI $base_uri,
$param,
$selected,
$reverse,
array $sort_values) {
$this->sortURI = $base_uri;
$this->sortParam = $param;
$this->sortSelected = $selected;
$this->sortReverse = $reverse;
$this->sortValues = array_values($sort_values);
return $this;
}
public function render() {
require_celerity_resource('aphront-table-view-css');
- $class = $this->className;
- if ($class !== null) {
- $class = ' class="aphront-table-view '.$class.'"';
+ $table_class = $this->className;
+ if ($table_class !== null) {
+ $table_class = ' class="aphront-table-view '.$table_class.'"';
} else {
- $class = ' class="aphront-table-view"';
+ $table_class = ' class="aphront-table-view"';
}
- $table = array('<table'.$class.'>');
+ $table = array('<table'.$table_class.'>');
$col_classes = array();
foreach ($this->columnClasses as $key => $class) {
if (strlen($class)) {
$col_classes[] = $class;
} else {
$col_classes[] = null;
}
}
$visibility = array_values($this->columnVisibility);
$headers = $this->headers;
$sort_values = $this->sortValues;
if ($headers) {
while (count($headers) > count($visibility)) {
$visibility[] = true;
}
while (count($headers) > count($sort_values)) {
$sort_values[] = null;
}
$table[] = '<tr>';
foreach ($headers as $col_num => $header) {
if (!$visibility[$col_num]) {
continue;
}
$classes = array();
if (!empty($col_classes[$col_num])) {
$classes[] = $col_classes[$col_num];
}
if ($sort_values[$col_num] !== null) {
$classes[] = 'aphront-table-view-sortable';
$sort_value = $sort_values[$col_num];
$sort_glyph = "\xE2\x86\x93";
if ($sort_value == $this->sortSelected) {
if ($this->sortReverse) {
$sort_glyph = "\xE2\x86\x91";
} else if (!$this->sortReverse) {
$sort_value = '-'.$sort_value;
}
$classes[] = 'aphront-table-view-sortable-selected';
}
$sort_glyph = phutil_render_tag(
'span',
array(
'class' => 'aphront-table-view-sort-glyph',
),
$sort_glyph);
$header = phutil_render_tag(
'a',
array(
'href' => $this->sortURI->alter($this->sortParam, $sort_value),
'class' => 'aphront-table-view-sort-link',
),
$sort_glyph.' '.$header);
}
if ($classes) {
$class = ' class="'.implode(' ', $classes).'"';
} else {
$class = null;
}
$table[] = '<th'.$class.'>'.$header.'</th>';
}
$table[] = '</tr>';
}
foreach ($col_classes as $key => $value) {
if (($sort_values[$key] !== null) &&
($sort_values[$key] == $this->sortSelected)) {
$value = trim($value.' sorted-column');
}
if ($value !== null) {
$col_classes[$key] = ' class="'.$value.'"';
}
}
$data = $this->data;
if ($data) {
$row_num = 0;
foreach ($data as $row) {
while (count($row) > count($col_classes)) {
$col_classes[] = null;
}
while (count($row) > count($visibility)) {
$visibility[] = true;
}
$class = idx($this->rowClasses, $row_num);
if ($this->zebraStripes && ($row_num % 2)) {
if ($class !== null) {
$class = 'alt alt-'.$class;
} else {
$class = 'alt';
}
}
if ($class !== null) {
$class = ' class="'.$class.'"';
}
$table[] = '<tr'.$class.'>';
// NOTE: Use of a separate column counter is to allow this to work
// correctly if the row data has string or non-sequential keys.
$col_num = 0;
foreach ($row as $value) {
if (!$visibility[$col_num]) {
++$col_num;
continue;
}
$class = $col_classes[$col_num];
if ($class !== null) {
$table[] = '<td'.$class.'>';
} else {
$table[] = '<td>';
}
$table[] = $value.'</td>';
++$col_num;
}
++$row_num;
}
} else {
$colspan = max(count($headers), 1);
$table[] =
'<tr class="no-data"><td colspan="'.$colspan.'">'.
coalesce($this->noDataString, 'No data available.').
'</td></tr>';
}
$table[] = '</table>';
return implode('', $table);
}
public static function renderSingleDisplayLine($line) {
// TODO: Is there a cleaner way to do this? We use a relative div with
// overflow hidden to provide the bounds, and an absolute span with
// white-space: pre to prevent wrapping. We need to append a character
// (&nbsp; -- nonbreaking space) afterward to give the bounds div height
// (alternatively, we could hard-code the line height). This is gross but
// it's not clear that there's a better appraoch.
return phutil_render_tag(
'div',
array(
'class' => 'single-display-line-bounds',
),
phutil_render_tag(
'span',
array(
'class' => 'single-display-line-content',
),
$line).'&nbsp;');
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 14, 7:22 AM (1 d, 6 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
336861
Default Alt Text
(46 KB)

Event Timeline