1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Move Diffusion browse rendering to DocumentEngine, breaking almost all features

Summary:
Ref T13105. This breaks about 9,000 features but moves Diffusion to DocumentEngine for rendering. See T13105 for a more complete list of all the broken stuff.

But you can't bake a software without breaking all the features every time you make a change, right?

Test Plan: Viewed various files in Diffusion, used DocumentEngine features like highlighting and rendering engine selection.

Reviewers: mydeveloperday

Reviewed By: mydeveloperday

Subscribers: mydeveloperday

Maniphest Tasks: T13105

Differential Revision: https://secure.phabricator.com/D19302
This commit is contained in:
epriestley 2018-04-05 10:21:48 -07:00
parent 245132a0b2
commit 1fde4a9450
9 changed files with 187 additions and 653 deletions

View file

@ -732,6 +732,8 @@ phutil_register_library_map(array(
'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php', 'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php',
'DiffusionDiffInlineCommentQuery' => 'applications/diffusion/query/DiffusionDiffInlineCommentQuery.php', 'DiffusionDiffInlineCommentQuery' => 'applications/diffusion/query/DiffusionDiffInlineCommentQuery.php',
'DiffusionDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php', 'DiffusionDiffQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionDiffQueryConduitAPIMethod.php',
'DiffusionDocumentController' => 'applications/diffusion/controller/DiffusionDocumentController.php',
'DiffusionDocumentRenderingEngine' => 'applications/diffusion/document/DiffusionDocumentRenderingEngine.php',
'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php',
'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php',
'DiffusionExistsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php', 'DiffusionExistsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php',
@ -5987,6 +5989,8 @@ phutil_register_library_map(array(
'DiffusionDiffController' => 'DiffusionController', 'DiffusionDiffController' => 'DiffusionController',
'DiffusionDiffInlineCommentQuery' => 'PhabricatorDiffInlineCommentQuery', 'DiffusionDiffInlineCommentQuery' => 'PhabricatorDiffInlineCommentQuery',
'DiffusionDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionDiffQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',
'DiffusionDocumentController' => 'DiffusionController',
'DiffusionDocumentRenderingEngine' => 'PhabricatorDocumentRenderingEngine',
'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
'DiffusionEmptyResultView' => 'DiffusionView', 'DiffusionEmptyResultView' => 'DiffusionView',
'DiffusionExistsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod', 'DiffusionExistsQueryConduitAPIMethod' => 'DiffusionQueryConduitAPIMethod',

View file

@ -53,6 +53,8 @@ final class PhabricatorDiffusionApplication extends PhabricatorApplication {
'history/(?P<dblob>.*)' => 'DiffusionHistoryController', 'history/(?P<dblob>.*)' => 'DiffusionHistoryController',
'graph/(?P<dblob>.*)' => 'DiffusionGraphController', 'graph/(?P<dblob>.*)' => 'DiffusionGraphController',
'browse/(?P<dblob>.*)' => 'DiffusionBrowseController', 'browse/(?P<dblob>.*)' => 'DiffusionBrowseController',
'document/(?P<dblob>.*)'
=> 'DiffusionDocumentController',
'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController', 'lastmodified/(?P<dblob>.*)' => 'DiffusionLastModifiedController',
'diff/' => 'DiffusionDiffController', 'diff/' => 'DiffusionDiffController',
'tags/(?P<dblob>.*)' => 'DiffusionTagListController', 'tags/(?P<dblob>.*)' => 'DiffusionTagListController',

View file

@ -45,13 +45,13 @@ final class DiffusionBrowseController extends DiffusionController {
if ($is_file) { if ($is_file) {
return $this->browseFile(); return $this->browseFile();
} else {
$paths = $results->getPaths();
$paths = $pager->sliceResults($paths);
$results->setPaths($paths);
return $this->browseDirectory($results, $pager);
} }
$paths = $results->getPaths();
$paths = $pager->sliceResults($paths);
$results->setPaths($paths);
return $this->browseDirectory($results, $pager);
} }
private function browseSearch() { private function browseSearch() {
@ -187,26 +187,21 @@ final class DiffusionBrowseController extends DiffusionController {
} else { } else {
$corpus = $this->buildGitLFSCorpus($lfs_ref); $corpus = $this->buildGitLFSCorpus($lfs_ref);
} }
} else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) {
$file_uri = $file->getBestURI();
if ($file->isViewableImage()) {
$corpus = $this->buildImageCorpus($file_uri);
} else {
$corpus = $this->buildBinaryCorpus($file_uri, $data);
}
} else { } else {
$this->loadLintMessages(); $this->loadLintMessages();
$this->coverage = $drequest->loadCoverage(); $this->coverage = $drequest->loadCoverage();
$show_editor = true; $show_editor = true;
// Build the content of the file. $ref = id(new PhabricatorDocumentRef())
$corpus = $this->buildCorpus( ->setFile($file);
$data,
$needs_blame, $engine = id(new DiffusionDocumentRenderingEngine())
$drequest, ->setRequest($request)
$path, ->setDiffusionRequest($drequest);
$data);
$corpus = $engine->newDocumentView($ref);
$this->corpusButtons[] = $this->renderFileButton();
} }
} }
@ -514,164 +509,6 @@ final class DiffusionBrowseController extends DiffusionController {
'/'.$drequest->getPath()); '/'.$drequest->getPath());
} }
private function buildCorpus(
$file_corpus,
$needs_blame,
DiffusionRequest $drequest,
$path,
$data) {
$viewer = $this->getViewer();
$blame_timeout = 15;
$blame_failed = false;
$highlight_limit = DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT;
$blame_limit = DifferentialChangesetParser::HIGHLIGHT_BYTE_LIMIT;
$can_highlight = (strlen($file_corpus) <= $highlight_limit);
$can_blame = (strlen($file_corpus) <= $blame_limit);
if ($needs_blame && $can_blame) {
$blame = $this->loadBlame($path, $drequest->getCommit(), $blame_timeout);
list($blame_list, $blame_commits) = $blame;
if ($blame_list === null) {
$blame_failed = true;
$blame_list = array();
}
} else {
$blame_list = array();
$blame_commits = array();
}
require_celerity_resource('syntax-highlighting-css');
if ($can_highlight) {
$highlighted = PhabricatorSyntaxHighlighter::highlightWithFilename(
$path,
$file_corpus);
} else {
// Highlight as plain text to escape the content properly.
$highlighted = PhabricatorSyntaxHighlighter::highlightWithLanguage(
'txt',
$file_corpus);
}
$lines = phutil_split_lines($highlighted);
$rows = $this->buildDisplayRows(
$lines,
$blame_list,
$blame_commits);
$corpus_table = javelin_tag(
'table',
array(
'class' => 'diffusion-source remarkup-code PhabricatorMonospaced',
'sigil' => 'phabricator-source',
'meta' => array(
'uri' => $this->getLineNumberBaseURI(),
),
),
$rows);
$corpus_table = phutil_tag_div('diffusion-source-wrap', $corpus_table);
if ($this->getRequest()->isAjax()) {
return $corpus_table;
}
$id = celerity_generate_unique_node_id();
$repo = $drequest->getRepository();
$symbol_repos = nonempty($repo->getSymbolSources(), array());
$symbol_repos[] = $repo->getPHID();
$lang = last(explode('.', $drequest->getPath()));
$repo_languages = $repo->getSymbolLanguages();
$repo_languages = nonempty($repo_languages, array());
$repo_languages = array_fill_keys($repo_languages, true);
$needs_symbols = true;
if ($repo_languages && $symbol_repos) {
$have_symbols = id(new DiffusionSymbolQuery())
->existsSymbolsInRepository($repo->getPHID());
if (!$have_symbols) {
$needs_symbols = false;
}
}
if ($needs_symbols && $repo_languages) {
$needs_symbols = isset($repo_languages[$lang]);
}
if ($needs_symbols) {
Javelin::initBehavior(
'repository-crossreference',
array(
'container' => $id,
'lang' => $lang,
'repositories' => $symbol_repos,
));
}
$corpus = phutil_tag(
'div',
array(
'id' => $id,
),
$corpus_table);
Javelin::initBehavior('load-blame', array('id' => $id));
$this->corpusButtons[] = $this->renderFileButton();
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file-code-o';
$drequest = $this->getDiffusionRequest();
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
$corpus = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($corpus)
->addClass('diffusion-mobile-view')
->addSigil('diffusion-file-content-view')
->setMetadata(
array(
'path' => $this->getDiffusionRequest()->getPath(),
))
->setCollapsed(true);
$messages = array();
if (!$can_highlight) {
$messages[] = pht(
'This file is larger than %s, so syntax highlighting is disabled '.
'by default.',
phutil_format_bytes($highlight_limit));
}
if (!$can_blame) {
$messages[] = pht(
'This file is larger than %s, so blame is disabled.',
phutil_format_bytes($blame_limit));
}
if ($blame_failed) {
$messages[] = pht(
'Failed to load blame information for this file in %s second(s).',
new PhutilNumber($blame_timeout));
}
if ($messages) {
$corpus->setInfoView(
id(new PHUIInfoView())
->setSeverity(PHUIInfoView::SEVERITY_WARNING)
->setErrors($messages));
}
return $corpus;
}
private function buildButtonBar( private function buildButtonBar(
DiffusionRequest $drequest, DiffusionRequest $drequest,
$show_editor) { $show_editor) {
@ -868,389 +705,6 @@ final class DiffusionBrowseController extends DiffusionController {
->setColor(PHUIButtonView::GREY); ->setColor(PHUIButtonView::GREY);
} }
private function buildDisplayRows(
array $lines,
array $blame_list,
array $blame_commits) {
$request = $this->getRequest();
$viewer = $this->getViewer();
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$revision_map = array();
$revisions = array();
if ($blame_commits) {
$commit_map = mpull($blame_commits, 'getCommitIdentifier', 'getPHID');
$revision_ids = id(new DifferentialRevision())
->loadIDsByCommitPHIDs(array_keys($commit_map));
if ($revision_ids) {
$revisions = id(new DifferentialRevisionQuery())
->setViewer($viewer)
->withIDs($revision_ids)
->execute();
$revisions = mpull($revisions, null, 'getID');
}
foreach ($revision_ids as $commit_phid => $revision_id) {
// If the viewer can't actually see this revision, skip it.
if (!isset($revisions[$revision_id])) {
continue;
}
$revision_map[$commit_map[$commit_phid]] = $revision_id;
}
}
$phids = array();
foreach ($blame_commits as $commit) {
$author_phid = $commit->getAuthorPHID();
if ($author_phid === null) {
continue;
}
$phids[$author_phid] = $author_phid;
}
foreach ($revisions as $revision) {
$author_phid = $revision->getAuthorPHID();
if ($author_phid === null) {
continue;
}
$phids[$author_phid] = $author_phid;
}
$handles = $viewer->loadHandles($phids);
$author_phids = array();
$author_map = array();
foreach ($blame_commits as $commit) {
$commit_identifier = $commit->getCommitIdentifier();
$author_phid = '';
if (isset($revision_map[$commit_identifier])) {
$revision_id = $revision_map[$commit_identifier];
$revision = $revisions[$revision_id];
$author_phid = $revision->getAuthorPHID();
} else {
$author_phid = $commit->getAuthorPHID();
}
$author_map[$commit_identifier] = $author_phid;
$author_phids[$author_phid] = $author_phid;
}
$colors = array();
if ($blame_commits) {
$epochs = array();
foreach ($blame_commits as $identifier => $commit) {
$epochs[$identifier] = $commit->getEpoch();
}
$epoch_list = array_filter($epochs);
$epoch_list = array_unique($epoch_list);
$epoch_list = array_values($epoch_list);
$epoch_min = min($epoch_list);
$epoch_max = max($epoch_list);
$epoch_range = ($epoch_max - $epoch_min) + 1;
foreach ($blame_commits as $identifier => $commit) {
$epoch = $epochs[$identifier];
if (!$epoch) {
$color = '#ffffdd'; // Warning color, missing data.
} else {
$color_ratio = ($epoch - $epoch_min) / $epoch_range;
$color_value = 0xE6 * (1.0 - $color_ratio);
$color = sprintf(
'#%02x%02x%02x',
$color_value,
0xF6,
$color_value);
}
$colors[$identifier] = $color;
}
}
$display = array();
$last_identifier = null;
$last_color = null;
foreach ($lines as $line_index => $line) {
$color = '#f6f6f6';
$duplicate = false;
if (isset($blame_list[$line_index])) {
$identifier = $blame_list[$line_index];
if (isset($colors[$identifier])) {
$color = $colors[$identifier];
}
if ($identifier === $last_identifier) {
$duplicate = true;
} else {
$last_identifier = $identifier;
}
}
$display[$line_index] = array(
'data' => $line,
'target' => false,
'highlighted' => false,
'color' => $color,
'duplicate' => $duplicate,
);
}
$line_arr = array();
$line_str = $drequest->getLine();
$ranges = explode(',', $line_str);
foreach ($ranges as $range) {
if (strpos($range, '-') !== false) {
list($min, $max) = explode('-', $range, 2);
$line_arr[] = array(
'min' => min($min, $max),
'max' => max($min, $max),
);
} else if (strlen($range)) {
$line_arr[] = array(
'min' => $range,
'max' => $range,
);
}
}
// Mark the first highlighted line as the target line.
if ($line_arr) {
$target_line = $line_arr[0]['min'];
if (isset($display[$target_line - 1])) {
$display[$target_line - 1]['target'] = true;
}
}
// Mark all other highlighted lines as highlighted.
foreach ($line_arr as $range) {
for ($ii = $range['min']; $ii <= $range['max']; $ii++) {
if (isset($display[$ii - 1])) {
$display[$ii - 1]['highlighted'] = true;
}
}
}
$engine = null;
$inlines = array();
if ($this->getRequest()->getStr('lint') !== null && $this->lintMessages) {
$engine = new PhabricatorMarkupEngine();
$engine->setViewer($viewer);
foreach ($this->lintMessages as $message) {
$inline = id(new PhabricatorAuditInlineComment())
->setSyntheticAuthor(
ArcanistLintSeverity::getStringForSeverity($message['severity']).
' '.$message['code'].' ('.$message['name'].')')
->setLineNumber($message['line'])
->setContent($message['description']);
$inlines[$message['line']][] = $inline;
$engine->addObject(
$inline,
PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY);
}
$engine->process();
require_celerity_resource('differential-changeset-view-css');
}
$rows = $this->renderInlines(
idx($inlines, 0, array()),
(bool)$this->coverage,
$engine);
// NOTE: We're doing this manually because rendering is otherwise
// dominated by URI generation for very large files.
$line_base = $this->getLineNumberBaseURI();
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('phabricator-oncopy');
Javelin::initBehavior('phabricator-tooltips');
Javelin::initBehavior('phabricator-line-linker');
// Render these once, since they tend to get repeated many times in large
// blame outputs.
$commit_links = $this->renderCommitLinks($blame_commits, $handles);
$revision_links = $this->renderRevisionLinks($revisions, $handles);
$author_links = $this->renderAuthorLinks($author_map, $handles);
if ($this->coverage) {
require_celerity_resource('differential-changeset-view-css');
Javelin::initBehavior(
'diffusion-browse-file',
array(
'labels' => array(
'cov-C' => pht('Covered'),
'cov-N' => pht('Not Covered'),
'cov-U' => pht('Not Executable'),
),
));
}
$skip_text = pht('Skip Past This Commit');
$skip_icon = id(new PHUIIconView())
->setIcon('fa-backward');
foreach ($display as $line_index => $line) {
$row = array();
$line_number = $line_index + 1;
$line_href = $line_base.'$'.$line_number;
if (isset($blame_list[$line_index])) {
$identifier = $blame_list[$line_index];
} else {
$identifier = null;
}
$revision_link = null;
$commit_link = null;
$author_link = null;
$before_link = null;
$style = 'background: '.$line['color'].';';
if ($identifier && !$line['duplicate']) {
if (isset($commit_links[$identifier])) {
$commit_link = $commit_links[$identifier];
$author_link = $author_links[$author_map[$identifier]];
}
if (isset($revision_map[$identifier])) {
$revision_id = $revision_map[$identifier];
if (isset($revision_links[$revision_id])) {
$revision_link = $revision_links[$revision_id];
}
}
$skip_href = $line_href.'?before='.$identifier;
$before_link = javelin_tag(
'a',
array(
'href' => $skip_href,
'sigil' => 'has-tooltip',
'meta' => array(
'tip' => $skip_text,
'align' => 'E',
'size' => 300,
),
),
$skip_icon);
}
$row[] = phutil_tag(
'th',
array(
'class' => 'diffusion-blame-link',
),
$before_link);
$object_links = array();
$object_links[] = $author_link;
$object_links[] = $commit_link;
if ($revision_link) {
$object_links[] = phutil_tag('span', array(), '/');
$object_links[] = $revision_link;
}
$row[] = phutil_tag(
'th',
array(
'class' => 'diffusion-rev-link',
),
$object_links);
$line_link = phutil_tag(
'a',
array(
'href' => $line_href,
'style' => $style,
),
$line_number);
$row[] = javelin_tag(
'th',
array(
'class' => 'diffusion-line-link',
'sigil' => 'phabricator-source-line',
'style' => $style,
),
$line_link);
if ($line['target']) {
Javelin::initBehavior(
'diffusion-jump-to',
array(
'target' => 'scroll_target',
));
$anchor_text = phutil_tag(
'a',
array(
'id' => 'scroll_target',
),
'');
} else {
$anchor_text = null;
}
$row[] = phutil_tag(
'td',
array(
),
array(
$anchor_text,
// NOTE: See phabricator-oncopy behavior.
"\xE2\x80\x8B",
// TODO: [HTML] Not ideal.
phutil_safe_html(str_replace("\t", ' ', $line['data'])),
));
if ($this->coverage) {
$cov_index = $line_index;
if (isset($this->coverage[$cov_index])) {
$cov_class = $this->coverage[$cov_index];
} else {
$cov_class = 'N';
}
$row[] = phutil_tag(
'td',
array(
'class' => 'cov cov-'.$cov_class,
),
'');
}
$rows[] = phutil_tag(
'tr',
array(
'class' => ($line['highlighted'] ?
'phabricator-source-highlight' :
null),
),
$row);
$cur_inlines = $this->renderInlines(
idx($inlines, $line_number, array()),
$this->coverage,
$engine);
foreach ($cur_inlines as $cur_inline) {
$rows[] = $cur_inline;
}
}
return $rows;
}
private function renderInlines( private function renderInlines(
array $inlines, array $inlines,
$has_coverage, $has_coverage,
@ -1285,53 +739,6 @@ final class DiffusionBrowseController extends DiffusionController {
return $rows; return $rows;
} }
private function buildImageCorpus($file_uri) {
$properties = new PHUIPropertyListView();
$properties->addImageContent(
phutil_tag(
'img',
array(
'src' => $file_uri,
)));
$this->corpusButtons[] = $this->renderFileButton($file_uri);
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file-image-o';
$drequest = $this->getDiffusionRequest();
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
return id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->addPropertyList($properties);
}
private function buildBinaryCorpus($file_uri, $data) {
$size = new PhutilNumber(strlen($data));
$text = pht('This is a binary file. It is %s byte(s) in length.', $size);
$text = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE)
->appendChild($text);
$this->corpusButtons[] = $this->renderFileButton($file_uri);
$title = basename($this->getDiffusionRequest()->getPath());
$icon = 'fa-file';
$drequest = $this->getDiffusionRequest();
$this->buildActionButtons($drequest);
$header = $this->buildPanelHeaderView($title, $icon);
$box = id(new PHUIObjectBoxView())
->setHeader($header)
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->addClass('diffusion-mobile-view')
->appendChild($text);
return $box;
}
private function buildErrorCorpus($message) { private function buildErrorCorpus($message) {
$text = id(new PHUIBoxView()) $text = id(new PHUIBoxView())
->addPadding(PHUI::PADDING_LARGE) ->addPadding(PHUI::PADDING_LARGE)

View file

@ -0,0 +1,45 @@
<?php
final class DiffusionDocumentController extends DiffusionController {
public function shouldAllowPublic() {
return true;
}
public function handleRequest(AphrontRequest $request) {
$response = $this->loadDiffusionContext();
if ($response) {
return $response;
}
$drequest = $this->getDiffusionRequest();
$engine = id(new DiffusionDocumentRenderingEngine())
->setRequest($request)
->setDiffusionRequest($drequest)
->setController($this);
$viewer = $this->getViewer();
$request = $this->getRequest();
$repository = $drequest->getRepository();
$file_phid = $request->getStr('filePHID');
$file = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs(array($file_phid))
->executeOne();
if (!$file) {
return $engine->newErrorResponse(
pht(
'This file ("%s") does not exist or could not be loaded.',
$file_phid));
}
$ref = id(new PhabricatorDocumentRef())
->setFile($file);
return $engine->newRenderResponse($ref);
}
}

View file

@ -0,0 +1,67 @@
<?php
final class DiffusionDocumentRenderingEngine
extends PhabricatorDocumentRenderingEngine {
private $diffusionRequest;
public function setDiffusionRequest(DiffusionRequest $drequest) {
$this->diffusionRequest = $drequest;
return $this;
}
public function getDiffusionRequest() {
return $this->diffusionRequest;
}
protected function getSelectedDocumentEngineKey() {
return $this->getRequest()->getStr('as');
}
protected function newRefViewURI(
PhabricatorDocumentRef $ref,
PhabricatorDocumentEngine $engine) {
$file = $ref->getFile();
$engine_key = $engine->getDocumentEngineKey();
$drequest = $this->getDiffusionRequest();
return (string)$drequest->generateURI(
array(
'action' => 'browse',
'stable' => true,
'params' => array(
'as' => $engine_key,
),
));
}
protected function newRefRenderURI(
PhabricatorDocumentRef $ref,
PhabricatorDocumentEngine $engine) {
$engine_key = $engine->getDocumentEngineKey();
$file = $ref->getFile();
$file_phid = $file->getPHID();
$drequest = $this->getDiffusionRequest();
return (string)$drequest->generateURI(
array(
'action' => 'document',
'stable' => true,
'params' => array(
'as' => $engine_key,
'filePHID' => $file_phid,
),
));
}
protected function addApplicationCrumbs(
PHUICrumbsView $crumbs,
PhabricatorDocumentRef $ref = null) {
return;
}
}

View file

@ -8,6 +8,10 @@ final class PhabricatorFileDocumentController
} }
public function handleRequest(AphrontRequest $request) { public function handleRequest(AphrontRequest $request) {
$engine = id(new PhabricatorFileDocumentRenderingEngine())
->setRequest($request)
->setController($this);
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$file_phid = $request->getURIData('phid'); $file_phid = $request->getURIData('phid');
@ -17,7 +21,7 @@ final class PhabricatorFileDocumentController
->withPHIDs(array($file_phid)) ->withPHIDs(array($file_phid))
->executeOne(); ->executeOne();
if (!$file) { if (!$file) {
return $this->newErrorResponse( return $engine->newErrorResponse(
pht( pht(
'This file ("%s") does not exist or could not be loaded.', 'This file ("%s") does not exist or could not be loaded.',
$file_phid)); $file_phid));
@ -26,10 +30,7 @@ final class PhabricatorFileDocumentController
$ref = id(new PhabricatorDocumentRef()) $ref = id(new PhabricatorDocumentRef())
->setFile($file); ->setFile($file);
return id(new PhabricatorFileDocumentRenderingEngine()) return $engine->newRenderResponse($ref);
->setRequest($request)
->setController($this)
->newRenderResponse($ref);
} }
} }

View file

@ -6,6 +6,7 @@ abstract class PhabricatorDocumentRenderingEngine
private $request; private $request;
private $controller; private $controller;
private $activeEngine; private $activeEngine;
private $ref;
final public function setRequest(AphrontRequest $request) { final public function setRequest(AphrontRequest $request) {
$this->request = $request; $this->request = $request;
@ -34,13 +35,13 @@ abstract class PhabricatorDocumentRenderingEngine
} }
final protected function getActiveEngine() { final protected function getActiveEngine() {
if (!$this->activeEngine) {
throw new PhutilInvalidStateException('setActiveEngine');
}
return $this->activeEngine; return $this->activeEngine;
} }
final protected function getRef() {
return $this->ref;
}
final public function newDocumentView(PhabricatorDocumentRef $ref) { final public function newDocumentView(PhabricatorDocumentRef $ref) {
$request = $this->getRequest(); $request = $this->getRequest();
$viewer = $request->getViewer(); $viewer = $request->getViewer();
@ -173,10 +174,9 @@ abstract class PhabricatorDocumentRenderingEngine
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$engines = PhabricatorDocumentEngine::getEnginesForRef($viewer, $ref); $engines = PhabricatorDocumentEngine::getEnginesForRef($viewer, $ref);
$engine_key = $request->getURIData('engineKey'); $engine_key = $this->getSelectedDocumentEngineKey();
if (!isset($engines[$engine_key])) { if (!isset($engines[$engine_key])) {
return $this->newErrorResponse( return $this->newErrorResponse(
$ref,
pht( pht(
'The engine ("%s") is unknown, or unable to render this document.', 'The engine ("%s") is unknown, or unable to render this document.',
$engine_key)); $engine_key));
@ -198,16 +198,13 @@ abstract class PhabricatorDocumentRenderingEngine
try { try {
$content = $engine->newDocument($ref); $content = $engine->newDocument($ref);
} catch (Exception $ex) { } catch (Exception $ex) {
return $this->newErrorResponse($ref, $ex->getMessage()); return $this->newErrorResponse($ex->getMessage());
} }
return $this->newContentResponse($ref, $content); return $this->newContentResponse($content);
} }
private function newErrorResponse( public function newErrorResponse($message) {
PhabricatorDocumentRef $ref,
$message) {
$container = phutil_tag( $container = phutil_tag(
'div', 'div',
array( array(
@ -220,13 +217,10 @@ abstract class PhabricatorDocumentRenderingEngine
$message, $message,
)); ));
return $this->newContentResponse($ref, $container); return $this->newContentResponse($container);
} }
private function newContentResponse( private function newContentResponse($content) {
PhabricatorDocumentRef $ref,
$content) {
$request = $this->getRequest(); $request = $this->getRequest();
$viewer = $request->getViewer(); $viewer = $request->getViewer();
$controller = $this->getController(); $controller = $this->getController();
@ -239,10 +233,8 @@ abstract class PhabricatorDocumentRenderingEngine
)); ));
} }
$crumbs = $this->newCrumbs($ref); $crumbs = $this->newCrumbs();
if ($crumbs) { $crumbs->setBorder(true);
$crumbs->setBorder(true);
}
$content_frame = id(new PHUIObjectBoxView()) $content_frame = id(new PHUIObjectBoxView())
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
@ -251,34 +243,46 @@ abstract class PhabricatorDocumentRenderingEngine
$page_frame = id(new PHUITwoColumnView()) $page_frame = id(new PHUITwoColumnView())
->setFooter($content_frame); ->setFooter($content_frame);
$title = array();
$ref = $this->getRef();
if ($ref) {
$title = array(
$ref->getName(),
pht('Standalone'),
);
} else {
$title = pht('Document');
}
return $controller->newPage() return $controller->newPage()
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setTitle( ->setTitle($title)
array(
$ref->getName(),
pht('Standalone'),
))
->appendChild($page_frame); ->appendChild($page_frame);
} }
protected function newCrumbs(PhabricatorDocumentRef $ref) { protected function newCrumbs() {
$engine = $this->getActiveEngine();
$controller = $this->getController(); $controller = $this->getController();
$crumbs = $controller->buildApplicationCrumbsForEditEngine(); $crumbs = $controller->buildApplicationCrumbsForEditEngine();
$this->addApplicationCrumbs($ref, $crumbs); $ref = $this->getRef();
$engine = $this->getActiveEngine(); $this->addApplicationCrumbs($crumbs, $ref);
$label = $engine->getViewAsLabel($ref);
if ($label) { if ($ref) {
$crumbs->addTextCrumb($label); $label = $engine->getViewAsLabel($ref);
if ($label) {
$crumbs->addTextCrumb($label);
}
} }
return $crumbs; return $crumbs;
} }
protected function addApplicationCrumbs( protected function addApplicationCrumbs(
PhabricatorDocumentRef $ref, PHUICrumbsView $crumbs,
PHUICrumbsView $crumbs) { PhabricatorDocumentRef $ref = null) {
return; return;
} }

View file

@ -34,12 +34,14 @@ final class PhabricatorFileDocumentRenderingEngine
} }
protected function addApplicationCrumbs( protected function addApplicationCrumbs(
PhabricatorDocumentRef $ref, PHUICrumbsView $crumbs,
PHUICrumbsView $crumbs) { PhabricatorDocumentRef $ref = null) {
$file = $ref->getFile(); if ($ref) {
if ($file) { $file = $ref->getFile();
$crumbs->addTextCrumb($file->getMonogram(), $file->getInfoURI()); if ($file) {
$crumbs->addTextCrumb($file->getMonogram(), $file->getInfoURI());
}
} }
} }

View file

@ -704,6 +704,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
case 'graph': case 'graph':
case 'clone': case 'clone':
case 'browse': case 'browse':
case 'document':
case 'change': case 'change':
case 'lastmodified': case 'lastmodified':
case 'tags': case 'tags':
@ -782,6 +783,7 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
case 'history': case 'history':
case 'graph': case 'graph':
case 'browse': case 'browse':
case 'document':
case 'lastmodified': case 'lastmodified':
case 'tags': case 'tags':
case 'branches': case 'branches':