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

Return safe HTML from all render()

Summary:
This is pretty brutal and it adds some `phutil_safe_html()`.
But it is a big step in the right direction.

Test Plan: None.

Reviewers: epriestley

Reviewed By: epriestley

CC: aran, Korvin

Maniphest Tasks: T2432

Differential Revision: https://secure.phabricator.com/D4905
This commit is contained in:
vrana 2013-02-11 13:16:57 -08:00
parent 37b98450a5
commit c9ab1fe505
48 changed files with 389 additions and 382 deletions

View file

@ -26,7 +26,7 @@ final class Aphront403Response extends AphrontHTMLResponse {
} }
$failure = new AphrontRequestFailureView(); $failure = new AphrontRequestFailureView();
$failure->setHeader('403 Forbidden'); $failure->setHeader('403 Forbidden');
$failure->appendChild('<p>'.$forbidden_text.'</p>'); $failure->appendChild(phutil_tag('p', array(), $forbidden_text));
$view = new PhabricatorStandardPageView(); $view = new PhabricatorStandardPageView();
$view->setTitle('403 Forbidden'); $view->setTitle('403 Forbidden');

View file

@ -12,7 +12,8 @@ final class Aphront404Response extends AphrontHTMLResponse {
public function buildResponseString() { public function buildResponseString() {
$failure = new AphrontRequestFailureView(); $failure = new AphrontRequestFailureView();
$failure->setHeader('404 Not Found'); $failure->setHeader('404 Not Found');
$failure->appendChild('<p>The page you requested was not found.</p>'); $failure->appendChild(phutil_tag('p', array(), pht(
'The page you requested was not found.')));
$view = new PhabricatorStandardPageView(); $view = new PhabricatorStandardPageView();
$view->setTitle('404 Not Found'); $view->setTitle('404 Not Found');

View file

@ -16,8 +16,8 @@ final class PhabricatorDisabledUserController
$failure_view = new AphrontRequestFailureView(); $failure_view = new AphrontRequestFailureView();
$failure_view->setHeader(pht('Account Disabled')); $failure_view->setHeader(pht('Account Disabled'));
$failure_view->appendChild( $failure_view->appendChild(phutil_tag('p', array(), pht(
'<p>'.pht('Your account has been disabled.').'</p>'); 'Your account has been disabled.')));
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
$failure_view, $failure_view,

View file

@ -98,10 +98,8 @@ EOBODY;
$view = new AphrontRequestFailureView(); $view = new AphrontRequestFailureView();
$view->setHeader(pht('Check Your Email')); $view->setHeader(pht('Check Your Email'));
$view->appendChild( $view->appendChild(phutil_tag('p', array(), pht(
'<p>'.pht( 'An email has been sent with a link you can use to login.')));
'An email has been sent with a link you can use to login.'
).'</p>');
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
$view, $view,
array( array(

View file

@ -50,17 +50,16 @@ final class PhabricatorEmailTokenController
$view = new AphrontRequestFailureView(); $view = new AphrontRequestFailureView();
$view->setHeader(pht('Unable to Login')); $view->setHeader(pht('Unable to Login'));
$view->appendChild( $view->appendChild(phutil_tag('p', array(), pht(
'<p>'.pht('The authentication information in the link you clicked is '. 'The authentication information in the link you clicked is '.
'invalid or out of date. Make sure you are copy-and-pasting the '. 'invalid or out of date. Make sure you are copy-and-pasting the '.
'entire link into your browser. You can try again, or request '. 'entire link into your browser. You can try again, or request '.
'a new email.').'</p>'); 'a new email.')));
$view->appendChild( $view->appendChild(hsprintf(
'<div class="aphront-failure-continue">'. '<div class="aphront-failure-continue">'.
'<a class="button" href="/login/email/">'. '<a class="button" href="/login/email/">%s</a>'.
pht('Send Another Email'). '</div>',
'</a>'. pht('Send Another Email')));
'</div>');
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
$view, $view,

View file

@ -49,14 +49,16 @@ final class PhabricatorLoginValidateController
$view = new AphrontRequestFailureView(); $view = new AphrontRequestFailureView();
$view->setHeader(pht('Login Failed')); $view->setHeader(pht('Login Failed'));
$view->appendChild( $view->appendChild(hsprintf(
'<p>'.pht('Login failed:').'</p>'. '<p>%s</p>%s<p>%s</p>',
$list. pht('Login failed:'),
'<p>'.pht('<strong>Clear your cookies</strong> and try again.').'</p>'); $list,
$view->appendChild( pht('<strong>Clear your cookies</strong> and try again.')));
$view->appendChild(hsprintf(
'<div class="aphront-failure-continue">'. '<div class="aphront-failure-continue">'.
'<a class="button" href="/login/">'.pht('Try Again').'</a>'. '<a class="button" href="/login/">%s</a>'.
'</div>'); '</div>',
pht('Try Again')));
return $this->buildStandardPageResponse( return $this->buildStandardPageResponse(
$view, $view,
array( array(

View file

@ -41,19 +41,15 @@ final class PhabricatorMustVerifyEmailController
$error_view = new AphrontRequestFailureView(); $error_view = new AphrontRequestFailureView();
$error_view->setHeader(pht('Check Your Email')); $error_view->setHeader(pht('Check Your Email'));
$error_view->appendChild( $error_view->appendChild(phutil_tag('p', array(), pht(
'<p>'. 'You must verify your email address to login. You should have a new '.
pht('You must verify your email address to login. You should have a new '.
'email message from Phabricator with verification instructions in your '. 'email message from Phabricator with verification instructions in your '.
'inbox (%s).', phutil_tag('strong', array(), $email_address)). 'inbox (%s).', phutil_tag('strong', array(), $email_address))));
'</p>'); $error_view->appendChild(phutil_tag('p', array(), pht(
$error_view->appendChild( 'If you did not receive an email, you can click the button below '.
'<p>'. 'to try sending another one.')));
pht('If you did not receive an email, you can click the button below '. $error_view->appendChild(hsprintf(
'to try sending another one.'). '<div class="aphront-failure-continue">%s</div>',
'</p>');
$error_view->appendChild(
'<div class="aphront-failure-continue">'.
phabricator_form( phabricator_form(
$user, $user,
array( array(
@ -64,8 +60,7 @@ final class PhabricatorMustVerifyEmailController
'button', 'button',
array( array(
), ),
pht('Send Another Email'))). pht('Send Another Email')))));
'</div>');
return $this->buildApplicationPage( return $this->buildApplicationPage(

View file

@ -77,11 +77,12 @@ final class PhabricatorOAuthFailureView extends AphrontView {
$provider_name); $provider_name);
} }
$view->appendChild( $view->appendChild(hsprintf(
'<div class="aphront-failure-continue">'. '<div class="aphront-failure-continue">'.
$diagnose. '%s<a href="/login/" class="button">%s</a>'.
'<a href="/login/" class="button">'.pht('Continue').'</a>'. '</div>',
'</div>'); $diagnose,
pht('Continue')));
return $view->render(); return $view->render();
} }

View file

@ -48,9 +48,10 @@ final class AphrontCalendarMonthView extends AphrontView {
$markup = array(); $markup = array();
$empty_box = $empty_box = phutil_tag(
'<div class="aphront-calendar-day aphront-calendar-empty">'. 'div',
'</div>'; array('class' => 'aphront-calendar-day aphront-calendar-empty'),
'');
for ($ii = 0; $ii < $empty; $ii++) { for ($ii = 0; $ii < $empty; $ii++) {
$markup[] = $empty_box; $markup[] = $empty_box;
@ -79,9 +80,10 @@ final class AphrontCalendarMonthView extends AphrontView {
} else { } else {
$show_events = array_fill_keys( $show_events = array_fill_keys(
array_keys($show_events), array_keys($show_events),
hsprintf(
'<div class="aphront-calendar-event aphront-calendar-event-empty">'. '<div class="aphront-calendar-event aphront-calendar-event-empty">'.
'&nbsp;'. '&nbsp;'.
'</div>'); '</div>'));
} }
foreach ($events as $event) { foreach ($events as $event) {
@ -110,31 +112,32 @@ final class AphrontCalendarMonthView extends AphrontView {
$name); $name);
} }
$markup[] = $markup[] = hsprintf(
'<div class="'.$class.'">'. '<div class="%s">'.
'<div class="aphront-calendar-date-number">'. '<div class="aphront-calendar-date-number">%s</div>'.
$day_number. '%s%s'.
'</div>'. '</div>',
$holiday_markup. $class,
implode("\n", $show_events). $day_number,
'</div>'; $holiday_markup,
phutil_implode_html("\n", $show_events));
} }
$table = array(); $table = array();
$rows = array_chunk($markup, 7); $rows = array_chunk($markup, 7);
foreach ($rows as $row) { foreach ($rows as $row) {
$table[] = '<tr>'; $table[] = hsprintf('<tr>');
while (count($row) < 7) { while (count($row) < 7) {
$row[] = $empty_box; $row[] = $empty_box;
} }
foreach ($row as $cell) { foreach ($row as $cell) {
$table[] = '<td>'.$cell.'</td>'; $table[] = phutil_tag('p', array(), $cell);
} }
$table[] = '</tr>'; $table[] = hsprintf('</tr>');
} }
$table = $table = hsprintf(
'<table class="aphront-calendar-view">'. '<table class="aphront-calendar-view">'.
$this->renderCalendarHeader($first). '%s'.
'<tr class="aphront-calendar-day-of-week-header">'. '<tr class="aphront-calendar-day-of-week-header">'.
'<th>Sun</th>'. '<th>Sun</th>'.
'<th>Mon</th>'. '<th>Mon</th>'.
@ -144,8 +147,10 @@ final class AphrontCalendarMonthView extends AphrontView {
'<th>Fri</th>'. '<th>Fri</th>'.
'<th>Sat</th>'. '<th>Sat</th>'.
'</tr>'. '</tr>'.
implode("\n", $table). '%s'.
'</table>'; '</table>',
$this->renderCalendarHeader($first),
phutil_implode_html("\n", $table));
return $table; return $table;
} }
@ -176,16 +181,15 @@ final class AphrontCalendarMonthView extends AphrontView {
"\xE2\x86\x92" "\xE2\x86\x92"
); );
$left_th = '<th>'.$prev_link.'</th>'; $left_th = phutil_tag('th', array(), $prev_link);
$right_th = '<th>'.$next_link.'</th>'; $right_th = phutil_tag('th', array(), $next_link);
} }
return return hsprintf(
'<tr class="aphront-calendar-month-year-header">'. '<tr class="aphront-calendar-month-year-header">%s%s%s</tr>',
$left_th. $left_th,
'<th colspan="'.$colspan.'">'.$date->format('F Y').'</th>'. phutil_tag('th', array('colspan' => $colspan), $date->format('F Y')),
$right_th. $right_th);
'</tr>';
} }
private function getNextYearAndMonth() { private function getNextYearAndMonth() {

View file

@ -386,14 +386,15 @@ final class DifferentialRevisionViewController extends DifferentialController {
$page_pane = id(new DifferentialPrimaryPaneView()) $page_pane = id(new DifferentialPrimaryPaneView())
->setID($pane_id) ->setID($pane_id)
->appendChild( ->appendChild(array(
$comment_view->render(). $comment_view->render(),
$diff_history->render(). $diff_history->render(),
$warning. $warning,
$local_view->render(). $local_view->render(),
$toc_view->render(). $toc_view->render(),
$other_view. $other_view,
$changeset_view->render()); $changeset_view->render(),
));
if ($comment_form) { if ($comment_form) {
$page_pane->appendChild($comment_form->render()); $page_pane->appendChild($comment_form->render());
} }
@ -857,13 +858,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
$handles = $this->loadViewerHandles($phids); $handles = $this->loadViewerHandles($phids);
$view->setHandles($handles); $view->setHandles($handles);
return return hsprintf(
'%s<div class="differential-panel">%s</div>',
id(new PhabricatorHeaderView()) id(new PhabricatorHeaderView())
->setHeader(pht('Open Revisions Affecting These Files')) ->setHeader(pht('Open Revisions Affecting These Files'))
->render(). ->render(),
'<div class="differential-panel">'. $view->render());
$view->render().
'</div>';
} }
/** /**

View file

@ -128,12 +128,12 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
$pchar = $pchar =
($changeset->getOldProperties() === $changeset->getNewProperties()) ($changeset->getOldProperties() === $changeset->getNewProperties())
? null ? null
: '<span title="'.pht('Properties Changed').'">M</span>'; : hsprintf('<span title="%s">M</span>', pht('Properties Changed'));
$fname = $changeset->getFilename(); $fname = $changeset->getFilename();
$cov = $this->renderCoverage($coverage, $fname); $cov = $this->renderCoverage($coverage, $fname);
if ($cov === null) { if ($cov === null) {
$mcov = $cov = '<em>-</em>'; $mcov = $cov = phutil_tag('em', array(), '-');
} else { } else {
$mcov = phutil_tag( $mcov = phutil_tag(
'div', 'div',
@ -144,21 +144,21 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
(isset($this->visibleChangesets[$id]) ? 'Loading...' : '?')); (isset($this->visibleChangesets[$id]) ? 'Loading...' : '?'));
} }
$rows[] = $rows[] = hsprintf(
'<tr>'. '<tr>'.
phutil_tag( '<td class="differential-toc-char" title="%s">%s</td>'.
'td', '<td class="differential-toc-prop">%s</td>'.
array( '<td class="differential-toc-ftype">%s</td>'.
'class' => 'differential-toc-char', '<td class="differential-toc-file">%s%s</td>'.
'title' => $chartitle, '<td class="differential-toc-cov">%s</td>'.
), '<td class="differential-toc-mcov">%s</td>'.
$char). '</tr>',
'<td class="differential-toc-prop">'.$pchar.'</td>'. $chartitle, $char,
'<td class="differential-toc-ftype">'.$desc.'</td>'. $pchar,
'<td class="differential-toc-file">'.$link.$lines.'</td>'. $desc,
'<td class="differential-toc-cov">'.$cov.'</td>'. $link, $lines,
'<td class="differential-toc-mcov">'.$mcov.'</td>'. $cov,
'</tr>'; $mcov);
if ($meta) { if ($meta) {
$rows[] = hsprintf( $rows[] = hsprintf(
'<tr>'. '<tr>'.
@ -200,19 +200,13 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
), ),
pht('Show All Context')); pht('Show All Context'));
$buttons = $buttons = hsprintf(
'<tr><td colspan="7">'. '<tr><td colspan="7">%s%s</td></tr>',
$editor_link.$reveal_link. $editor_link,
'</td></tr>'; $reveal_link);
return return hsprintf(
id(new PhabricatorAnchorView()) '%s%s'.
->setAnchorName('toc')
->setNavigationMarker(true)
->render().
id(new PhabricatorHeaderView())
->setHeader(pht('Table of Contents'))
->render().
'<div class="differential-toc differential-panel">'. '<div class="differential-toc differential-panel">'.
'<table>'. '<table>'.
'<tr>'. '<tr>'.
@ -220,17 +214,23 @@ final class DifferentialDiffTableOfContentsView extends AphrontView {
'<th></th>'. '<th></th>'.
'<th></th>'. '<th></th>'.
'<th>Path</th>'. '<th>Path</th>'.
'<th class="differential-toc-cov">'. '<th class="differential-toc-cov">%s</th>'.
pht('Coverage (All)'). '<th class="differential-toc-mcov">%s</th>'.
'</th>'.
'<th class="differential-toc-mcov">'.
pht('Coverage (Touched)').
'</th>'.
'</tr>'. '</tr>'.
implode("\n", $rows). '%s%s'.
$buttons.
'</table>'. '</table>'.
'</div>'; '</div>',
id(new PhabricatorAnchorView())
->setAnchorName('toc')
->setNavigationMarker(true)
->render(),
id(new PhabricatorHeaderView())
->setHeader(pht('Table of Contents'))
->render(),
pht('Coverage (All)'),
pht('Coverage (Touched)'),
phutil_implode_html("\n", $rows),
$buttons);
} }
private function renderCoverage(array $coverage, $file) { private function renderCoverage(array $coverage, $file) {

View file

@ -114,29 +114,31 @@ final class DifferentialLocalCommitsView extends AphrontView {
$headers = array(); $headers = array();
$headers[] = '<th>'.pht('Commit').'</th>'; $headers[] = phutil_tag('th', array(), pht('Commit'));
if ($has_tree) { if ($has_tree) {
$headers[] = '<th>'.pht('Tree').'</th>'; $headers[] = phutil_tag('th', array(), pht('Tree'));
} }
if ($has_local) { if ($has_local) {
$headers[] = '<th>'.pht('Local').'</th>'; $headers[] = phutil_tag('th', array(), pht('Local'));
} }
$headers[] = '<th>'.pht('Parents').'</th>'; $headers[] = phutil_tag('th', array(), pht('Parents'));
$headers[] = '<th>'.pht('Author').'</th>'; $headers[] = phutil_tag('th', array(), pht('Author'));
$headers[] = '<th>'.pht('Summary').'</th>'; $headers[] = phutil_tag('th', array(), pht('Summary'));
$headers[] = '<th>'.pht('Date').'</th>'; $headers[] = phutil_tag('th', array(), pht('Date'));
$headers = '<tr>'.implode('', $headers).'</tr>'; $headers = phutil_tag('tr', array(), $headers);
return $header = id(new PhabricatorHeaderView())
id(new PhabricatorHeaderView())
->setHeader(pht('Local Commits')) ->setHeader(pht('Local Commits'))
->render(). ->render();
return hsprintf(
'%s'.
'<div class="differential-panel">'. '<div class="differential-panel">'.
'<table class="differential-local-commits-table">'. '<table class="differential-local-commits-table">%s%s</table>'.
$headers. '</div>',
implode("\n", $rows). $header,
'</table>'. $headers,
'</div>'; phutil_implode_html("\n", $rows));
} }
} }

View file

@ -11,13 +11,13 @@ final class DifferentialPrimaryPaneView extends AphrontView {
public function render() { public function render() {
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => 'differential-primary-pane', 'class' => 'differential-primary-pane',
'id' => $this->id, 'id' => $this->id,
), ),
$this->renderChildren()); $this->renderHTMLChildren());
} }
} }

View file

@ -187,14 +187,12 @@ final class DifferentialRevisionCommentListView extends AphrontView {
$hidden = null; $hidden = null;
} }
return javelin_render_tag( return javelin_tag(
'div', 'div',
array( array(
'class' => 'differential-comment-list', 'class' => 'differential-comment-list',
'id' => $this->getID(), 'id' => $this->getID(),
), ),
implode("\n", $header). array_merge($header, array($hidden), $visible));
$hidden.
implode("\n", $visible));
} }
} }

View file

@ -87,7 +87,11 @@ final class DifferentialRevisionDetailView extends AphrontView {
} }
$properties->setHasKeyboardShortcuts(true); $properties->setHasKeyboardShortcuts(true);
return $header->render() . $actions->render() . $properties->render(); return hsprintf(
'%s%s%s',
$header->render(),
$actions->render(),
$properties->render());
} }
private function renderHeader(DifferentialRevision $revision) { private function renderHeader(DifferentialRevision $revision) {

View file

@ -177,9 +177,8 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
DifferentialChangesetParser::WHITESPACE_SHOW_ALL => 'Show All', DifferentialChangesetParser::WHITESPACE_SHOW_ALL => 'Show All',
); );
$select = '<select name="whitespace">';
foreach ($options as $value => $label) { foreach ($options as $value => $label) {
$select .= phutil_tag( $options[$value] = phutil_tag(
'option', 'option',
array( array(
'value' => $value, 'value' => $value,
@ -189,34 +188,39 @@ final class DifferentialRevisionUpdateHistoryView extends AphrontView {
), ),
$label); $label);
} }
$select .= '</select>'; $select = phutil_tag('select', array('name' => 'whitespace'), $options);
return array_unshift($rows, phutil_tag('tr', array(), array(
id(new PhabricatorHeaderView()) phutil_tag('th', array(), pht('Diff')),
->setHeader(pht('Revision Update History')) phutil_tag('th', array(), pht('ID')),
->render() . phutil_tag('th', array(), pht('Base')),
phutil_tag('th', array(), pht('Description')),
phutil_tag('th', array(), pht('Created')),
phutil_tag('th', array(), pht('Lint')),
phutil_tag('th', array(), pht('Unit')),
)));
return hsprintf(
'%s'.
'<div class="differential-revision-history differential-panel">'. '<div class="differential-revision-history differential-panel">'.
'<form action="#toc">'. '<form action="#toc">'.
'<table class="differential-revision-history-table">'. '<table class="differential-revision-history-table">'.
'<tr>'. '%s'.
'<th>'.pht('Diff').'</th>'.
'<th>'.pht('ID').'</th>'.
'<th>'.pht('Base').'</th>'.
'<th>'.pht('Description').'</th>'.
'<th>'.pht('Created').'</th>'.
'<th>'.pht('Lint').'</th>'.
'<th>'.pht('Unit').'</th>'.
'</tr>'.
implode("\n", $rows).
'<tr>'. '<tr>'.
'<td colspan="9" class="diff-differ-submit">'. '<td colspan="9" class="diff-differ-submit">'.
'<label>'.pht('Whitespace Changes: %s', $select).'</label>'. '<label>%s</label>'.
'<button>'.pht('Show Diff').'</button>'. '<button>%s</button>'.
'</td>'. '</td>'.
'</tr>'. '</tr>'.
'</table>'. '</table>'.
'</form>'. '</form>'.
'</div>'; '</div>',
id(new PhabricatorHeaderView())
->setHeader(pht('Revision Update History'))
->render(),
phutil_implode_html("\n", $rows),
pht('Whitespace Changes: %s', $select),
pht('Show Diff'));
} }
const STAR_NONE = 'none'; const STAR_NONE = 'none';

View file

@ -87,10 +87,10 @@ final class DiffusionCommentListView extends AphrontView {
++$num; ++$num;
} }
return return phutil_tag(
'<div class="diffusion-comment-list">'. 'div',
$this->renderSingleView($comments). array('class' => 'diffusion-comment-list'),
'</div>'; $comments);
} }
} }

View file

@ -40,8 +40,8 @@ final class PhabricatorFeedBuilder {
if ($date !== $last_date) { if ($date !== $last_date) {
if ($last_date !== null) { if ($last_date !== null) {
$null_view->appendChild( $null_view->appendChild(hsprintf(
'<div class="phabricator-feed-story-date-separator"></div>'); '<div class="phabricator-feed-story-date-separator"></div>'));
} }
$last_date = $date; $last_date = $date;
$null_view->appendChild( $null_view->appendChild(
@ -59,10 +59,9 @@ final class PhabricatorFeedBuilder {
$null_view->appendChild($view); $null_view->appendChild($view);
} }
return id(new AphrontNullView())->appendChild( return id(new AphrontNullView())->appendChild(hsprintf(
'<div class="phabricator-feed-frame">'. '<div class="phabricator-feed-frame">%s</div>',
$null_view->render(). $null_view->render()));
'</div>');
} }
} }

View file

@ -58,7 +58,7 @@ final class PhabricatorFeedStoryView extends PhabricatorFeedView {
$classes[] = 'phabricator-notification-unread'; $classes[] = 'phabricator-notification-unread';
} }
return javelin_render_tag( return javelin_tag(
'div', 'div',
array( array(
'class' => implode(' ', $classes), 'class' => implode(' ', $classes),
@ -67,29 +67,29 @@ final class PhabricatorFeedStoryView extends PhabricatorFeedView {
'href' => $this->getHref(), 'href' => $this->getHref(),
), ),
), ),
$this->title); phutil_safe_html($this->title));
} }
public function render() { public function render() {
$head = phutil_render_tag( $head = phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-feed-story-head', 'class' => 'phabricator-feed-story-head',
), ),
nonempty($this->title, 'Untitled Story')); nonempty(phutil_safe_html($this->title), 'Untitled Story'));
$body = null; $body = null;
$foot = null; $foot = null;
$image_style = null; $image_style = null;
if (!$this->oneLine) { if (!$this->oneLine) {
$body = phutil_render_tag( $body = phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-feed-story-body', 'class' => 'phabricator-feed-story-body',
), ),
$this->renderChildren()); phutil_safe_html($this->renderChildren()));
if ($this->epoch) { if ($this->epoch) {
$foot = phabricator_datetime($this->epoch, $this->user); $foot = phabricator_datetime($this->epoch, $this->user);
@ -111,7 +111,7 @@ final class PhabricatorFeedStoryView extends PhabricatorFeedView {
require_celerity_resource('phabricator-feed-css'); require_celerity_resource('phabricator-feed-css');
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => $this->oneLine 'class' => $this->oneLine

View file

@ -88,31 +88,27 @@ final class ManiphestTaskDetailController extends ManiphestController {
if ($parent_task) { if ($parent_task) {
$context_bar = new AphrontContextBarView(); $context_bar = new AphrontContextBarView();
$context_bar->addButton( $context_bar->addButton(phutil_tag(
phutil_tag(
'a', 'a',
array( array(
'href' => '/maniphest/task/create/?parent='.$parent_task->getID(), 'href' => '/maniphest/task/create/?parent='.$parent_task->getID(),
'class' => 'green button', 'class' => 'green button',
), ),
'Create Another Subtask')); 'Create Another Subtask'));
$context_bar->appendChild( $context_bar->appendChild(hsprintf(
'Created a subtask of <strong>'. 'Created a subtask of <strong>%s</strong>',
$this->getHandle($parent_task->getPHID())->renderLink(). $this->getHandle($parent_task->getPHID())->renderLink()));
'</strong>');
} else if ($workflow == 'create') { } else if ($workflow == 'create') {
$context_bar = new AphrontContextBarView(); $context_bar = new AphrontContextBarView();
$context_bar->addButton('<label>Create Another:</label>'); $context_bar->addButton(phutil_tag('label', array(), 'Create Another'));
$context_bar->addButton( $context_bar->addButton(phutil_tag(
phutil_tag(
'a', 'a',
array( array(
'href' => '/maniphest/task/create/?template='.$task->getID(), 'href' => '/maniphest/task/create/?template='.$task->getID(),
'class' => 'green button', 'class' => 'green button',
), ),
'Similar Task')); 'Similar Task'));
$context_bar->addButton( $context_bar->addButton(phutil_tag(
phutil_tag(
'a', 'a',
array( array(
'href' => '/maniphest/task/create/', 'href' => '/maniphest/task/create/',

View file

@ -298,13 +298,14 @@ final class ManiphestTaskListController extends ManiphestController {
require_celerity_resource('maniphest-task-summary-css'); require_celerity_resource('maniphest-task-summary-css');
$list_container = new AphrontNullView(); $list_container = new AphrontNullView();
$list_container->appendChild('<div class="maniphest-list-container">'); $list_container->appendChild(hsprintf(
'<div class="maniphest-list-container">'));
if (!$have_tasks) { if (!$have_tasks) {
$list_container->appendChild( $list_container->appendChild(hsprintf(
'<h1 class="maniphest-task-group-header">'. '<h1 class="maniphest-task-group-header">'.
'No matching tasks.'. 'No matching tasks.'.
'</h1>'); '</h1>'));
} else { } else {
$pager = new AphrontPagerView(); $pager = new AphrontPagerView();
$pager->setURI($request->getRequestURI(), 'offset'); $pager->setURI($request->getRequestURI(), 'offset');
@ -316,14 +317,13 @@ final class ManiphestTaskListController extends ManiphestController {
$max = min($pager->getOffset() + $page_size, $total_count); $max = min($pager->getOffset() + $page_size, $total_count);
$tot = $total_count; $tot = $total_count;
$cur = number_format($cur); $list_container->appendChild(hsprintf(
$max = number_format($max);
$tot = number_format($tot);
$list_container->appendChild(
'<div class="maniphest-total-result-count">'. '<div class="maniphest-total-result-count">'.
"Displaying tasks {$cur} - {$max} of {$tot}.". "Displaying tasks %s - %s of %s.".
'</div>'); '</div>',
number_format($cur),
number_format($max),
number_format($tot)));
$selector = new AphrontNullView(); $selector = new AphrontNullView();
@ -334,7 +334,7 @@ final class ManiphestTaskListController extends ManiphestController {
($group == 'none' || $group == 'priority'); ($group == 'none' || $group == 'priority');
$lists = new AphrontNullView(); $lists = new AphrontNullView();
$lists->appendChild('<div class="maniphest-group-container">'); $lists->appendChild(hsprintf('<div class="maniphest-group-container">'));
foreach ($tasks as $group => $list) { foreach ($tasks as $group => $list) {
$task_list = new ManiphestTaskListView(); $task_list = new ManiphestTaskListView();
$task_list->setShowBatchControls(true); $task_list->setShowBatchControls(true);
@ -367,14 +367,14 @@ final class ManiphestTaskListController extends ManiphestController {
$lists->appendChild($panel); $lists->appendChild($panel);
} }
$lists->appendChild('</div>'); $lists->appendChild(hsprintf('</div>'));
$selector->appendChild($lists); $selector->appendChild($lists);
$selector->appendChild($this->renderBatchEditor($query)); $selector->appendChild($this->renderBatchEditor($query));
$form_id = celerity_generate_unique_node_id(); $form_id = celerity_generate_unique_node_id();
$selector = phabricator_render_form( $selector = phabricator_form(
$user, $user,
array( array(
'method' => 'POST', 'method' => 'POST',
@ -394,7 +394,7 @@ final class ManiphestTaskListController extends ManiphestController {
)); ));
} }
$list_container->appendChild('</div>'); $list_container->appendChild(hsprintf('</div>'));
$nav->appendChild($list_container); $nav->appendChild($list_container);
$title = pht('Task List'); $title = pht('Task List');
@ -678,25 +678,21 @@ final class ManiphestTaskListController extends ManiphestController {
), ),
'Export Tasks to Excel...'); 'Export Tasks to Excel...');
return return hsprintf(
'<div class="maniphest-batch-editor">'. '<div class="maniphest-batch-editor">'.
'<div class="batch-editor-header">Batch Task Editor</div>'. '<div class="batch-editor-header">Batch Task Editor</div>'.
'<table class="maniphest-batch-editor-layout">'. '<table class="maniphest-batch-editor-layout">'.
'<tr>'. '<tr>'.
'<td>'. '<td>%s%s</td>'.
$select_all. '<td>%s</td>'.
$select_none. '<td id="batch-select-status-cell">0 Selected Tasks</td>'.
'</td>'. '<td class="batch-select-submit-cell">%s</td>'.
'<td>'.
$export.
'</td>'.
'<td id="batch-select-status-cell">'.
'0 Selected Tasks'.
'</td>'.
'<td class="batch-select-submit-cell">'.$submit.'</td>'.
'</tr>'. '</tr>'.
'</table>'. '</table>'.
'</table>'; '</table>',
$select_all, $select_none,
$export,
$submit);
} }
private function buildQueryFromRequest() { private function buildQueryFromRequest() {

View file

@ -179,7 +179,7 @@ final class ManiphestTransactionDetailView extends ManiphestView {
} }
if ($this->getRenderSummaryOnly()) { if ($this->getRenderSummaryOnly()) {
return implode("\n", $descs); return phutil_implode_html("\n", $descs);
} }
if ($comment_transaction && $comment_transaction->hasComments()) { if ($comment_transaction && $comment_transaction->hasComments()) {

View file

@ -102,10 +102,10 @@ final class ManiphestTransactionListView extends ManiphestView {
$views[] = $view->render(); $views[] = $view->render();
} }
return return phutil_tag(
'<div class="maniphest-transaction-list-view">'. 'div',
implode("\n", $views). array('class' => 'maniphest-transaction-list-view'),
'</div>'; $views);
} }
} }

View file

@ -157,7 +157,7 @@ final class PhrictionDocumentController
$version_note = $version_note->render(); $version_note = $version_note->render();
} }
$children = $this->renderChildren($slug); $children = $this->renderDocumentChildren($slug);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumb_views = $this->renderBreadcrumbs($slug); $crumb_views = $this->renderBreadcrumbs($slug);
@ -225,7 +225,7 @@ final class PhrictionDocumentController
->setHref(PhrictionDocument::getSlugURI($slug, 'history'))); ->setHref(PhrictionDocument::getSlugURI($slug, 'history')));
} }
private function renderChildren($slug) { private function renderDocumentChildren($slug) {
$document_dao = new PhrictionDocument(); $document_dao = new PhrictionDocument();
$content_dao = new PhrictionContent(); $content_dao = new PhrictionContent();
$conn = $document_dao->establishConnection('r'); $conn = $document_dao->establishConnection('r');

View file

@ -44,14 +44,14 @@ final class PonderAddAnswerView extends AphrontView {
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
->setValue($is_serious ? 'Submit' : 'Make it so')); ->setValue($is_serious ? 'Submit' : 'Make it so'));
$preview = $preview = hsprintf(
'<div class="aphront-panel-flush">'. '<div class="aphront-panel-flush">'.
'<div id="answer-preview">'. '<div id="answer-preview">'.
'<span class="aphront-panel-preview-loading-text">'. '<span class="aphront-panel-preview-loading-text">'.
'Loading answer preview...'. 'Loading answer preview...'.
'</span>'. '</span>'.
'</div>'. '</div>'.
'</div>'; '</div>');
Javelin::initBehavior( Javelin::initBehavior(
'ponder-feedback-preview', 'ponder-feedback-preview',

View file

@ -43,8 +43,7 @@ final class PonderQuestionSummaryView extends AphrontView {
'</div>', '</div>',
$question->getAnswerCount()); $question->getAnswerCount());
$title = $title = hsprintf('<h2 class="ponder-question-title">%s</h2>',
'<h2 class="ponder-question-title">'.
phutil_tag( phutil_tag(
'a', 'a',
array( array(
@ -52,25 +51,21 @@ final class PonderQuestionSummaryView extends AphrontView {
), ),
'Q' . $question->getID() . 'Q' . $question->getID() .
' ' . $question->getTitle() ' ' . $question->getTitle()
) . ));
'</h2>';
$rhs = $rhs = hsprintf(
'<div class="ponder-metadata">'. '<div class="ponder-metadata">'.
$title. '%s <span class="ponder-small-metadata">asked on %s by %s</span>'.
'<span class="ponder-small-metadata">'. '</div>',
'asked on '. $title,
phabricator_datetime($question->getDateCreated(), $user). phabricator_datetime($question->getDateCreated(), $user),
' by ' . $authorlink. $authorlink);
'</span>'.
'</div>';
$summary = $summary = hsprintf(
'<div class="ponder-question-summary">'. '<div class="ponder-question-summary">%s%s%s</div>',
$votecount. $votecount,
$answercount. $answercount,
$rhs. $rhs);
'</div>';
return $summary; return $summary;

View file

@ -63,7 +63,7 @@ final class PonderVotableView extends AphrontView {
), ),
$this->count); $this->count);
return javelin_render_tag( return javelin_tag(
'div', 'div',
array( array(
'class' => 'ponder-votable', 'class' => 'ponder-votable',
@ -80,12 +80,12 @@ final class PonderVotableView extends AphrontView {
'class' => 'ponder-votebox', 'class' => 'ponder-votebox',
), ),
array($up, $count, $down)), array($up, $count, $down)),
phutil_render_tag( phutil_tag(
'div', 'div',
array( array(
'class' => 'ponder-votebox-content', 'class' => 'ponder-votebox-content',
), ),
$this->renderChildren()), $this->renderHTMLChildren()),
)); ));
} }

View file

@ -70,21 +70,25 @@ final class PhabricatorSearchResultView extends AphrontView {
break; break;
} }
return return hsprintf(
'<div class="phabricator-search-result">'. '<div class="phabricator-search-result">'.
$img. '%s'.
'<div class="result-desc">'. '<div class="result-desc">'.
'%s'.
'<div class="result-type">%s &middot; %s</div>'.
'</div>'.
'<div style="clear: both;"></div>'.
'</div>',
$img,
phutil_tag( phutil_tag(
'a', 'a',
array( array(
'class' => 'result-name', 'class' => 'result-name',
'href' => $handle->getURI(), 'href' => $handle->getURI(),
), ),
$this->emboldenQuery($object_name)). $this->emboldenQuery($object_name)),
'<div class="result-type">'.$type_name.' &middot; '.$link.'</div>'. $type_name,
'</div>'. $link);
'<div style="clear: both;"></div>'.
'</div>';
} }
private function emboldenQuery($str) { private function emboldenQuery($str) {

View file

@ -8,7 +8,7 @@ final class JavelinViewExampleServerView extends AphrontView {
array( array(
'class' => 'server-view', 'class' => 'server-view',
), ),
$this->renderChildren()); $this->renderHTMLChildren());
} }
} }

View file

@ -15,7 +15,7 @@ final class PhabricatorInlineSummaryView extends AphrontView {
public function render() { public function render() {
require_celerity_resource('inline-comment-summary-css'); require_celerity_resource('inline-comment-summary-css');
return $this->renderHeader().$this->renderTable(); return hsprintf('%s%s', $this->renderHeader(), $this->renderTable());
} }
private function renderHeader() { private function renderHeader() {

View file

@ -3,7 +3,7 @@
final class AphrontNullView extends AphrontView { final class AphrontNullView extends AphrontView {
public function render() { public function render() {
return $this->renderChildren(); return $this->renderHTMLChildren();
} }
} }

View file

@ -52,7 +52,7 @@ abstract class AphrontView extends Phobject {
foreach ($child as $element) { foreach ($child as $element) {
$out[] = $this->renderSingleView($element); $out[] = $this->renderSingleView($element);
} }
return implode('', $out); return phutil_implode_html('', $out);
} else { } else {
return $child; return $child;
} }
@ -60,7 +60,7 @@ abstract class AphrontView extends Phobject {
final protected function renderHTMLView($child) { final protected function renderHTMLView($child) {
if ($child instanceof AphrontView) { if ($child instanceof AphrontView) {
return phutil_safe_html($child->render()); return $child->render();
} else if ($child instanceof PhutilSafeHTML) { } else if ($child instanceof PhutilSafeHTML) {
return $child; return $child;
} else if (is_array($child)) { } else if (is_array($child)) {
@ -68,9 +68,9 @@ abstract class AphrontView extends Phobject {
foreach ($child as $element) { foreach ($child as $element) {
$out[] = $this->renderHTMLView($element); $out[] = $this->renderHTMLView($element);
} }
return phutil_safe_html(implode('', $out)); return phutil_implode_html('', $out);
} else { } else {
return phutil_safe_html(phutil_escape_html($child)); return hsprintf('%s', $child);
} }
} }

View file

@ -44,14 +44,18 @@ final class AphrontAttachedFileView extends AphrontView {
), ),
"\xE2\x9C\x96"); // "Heavy Multiplication X" "\xE2\x9C\x96"); // "Heavy Multiplication X"
return return hsprintf(
'<table class="aphront-attached-file-view"> '<table class="aphront-attached-file-view">
<tr> <tr>
<td>'.$thumb.'</td> <td>%s</td>
<th><strong>'.$name.'</strong><br />'.$size.'</th> <th><strong>%s</strong><br />%s</th>
<td class="aphront-attached-file-view-remove">'.$remove.'</td> <td class="aphront-attached-file-view-remove">%s</td>
</tr> </tr>
</table>'; </table>',
$thumb,
$name,
$size,
$remove);
} }
} }

View file

@ -120,10 +120,10 @@ final class AphrontCursorPagerView extends AphrontView {
"Next \xE2\x80\xBA"); "Next \xE2\x80\xBA");
} }
return return phutil_tag(
'<div class="aphront-pager-view">'. 'div',
implode('', $links). array('class' => 'aphront-pager-view'),
'</div>'; $links);
} }
} }

View file

@ -115,7 +115,7 @@ final class AphrontPagerView extends AphrontView {
if ($max - $min > $last) { if ($max - $min > $last) {
$max = $min + $last; $max = $min + $last;
if ($max == $min) { if ($max == $min) {
return '<div class="aphront-pager-view"></div>'; return phutil_tag('div', array('class' => 'aphront-pager-view'), '');
} }
} }
@ -196,10 +196,10 @@ final class AphrontPagerView extends AphrontView {
$label); $label);
} }
return return phutil_tag(
'<div class="aphront-pager-view">'. 'div',
implode('', $rendered_links). array('class' => 'aphront-pager-view'),
'</div>'; $rendered_links);
} }
private function getDisplayIndex($page_index) { private function getDisplayIndex($page_index) {

View file

@ -15,18 +15,16 @@ final class AphrontContextBarView extends AphrontView {
require_celerity_resource('aphront-contextbar-view-css'); require_celerity_resource('aphront-contextbar-view-css');
return return hsprintf(
'<div class="aphront-contextbar-view">'. '<div class="aphront-contextbar-view">'.
'<div class="aphront-contextbar-core">'. '<div class="aphront-contextbar-core">'.
'<div class="aphront-contextbar-buttons">'. '<div class="aphront-contextbar-buttons">%s</div>'.
$view->render(). '<div class="aphront-contextbar-content">%s</div>'.
'</div>'.
'<div class="aphront-contextbar-content">'.
$this->renderChildren().
'</div>'.
'</div>'. '</div>'.
'<div style="clear: both;"></div>'. '<div style="clear: both;"></div>'.
'</div>'; '</div>',
$view->render(),
$this->renderHTMLChildren());
} }
} }

View file

@ -17,18 +17,15 @@ final class AphrontCrumbsView extends AphrontView {
foreach ($this->crumbs as $crumb) { foreach ($this->crumbs as $crumb) {
$out[] = $this->renderSingleView($crumb); $out[] = $this->renderSingleView($crumb);
} }
$out = implode( $out = phutil_implode_html(
'<span class="aphront-crumbs-spacer">'. hsprintf('<span class="aphront-crumbs-spacer">'."\xC2\xBB".'</span>'),
"\xC2\xBB".
'</span>',
$out); $out);
return return hsprintf(
'<div class="aphront-crumbs-view">'. '<div class="aphront-crumbs-view">'.
'<div class="aphront-crumbs-content">'. '<div class="aphront-crumbs-content">%s</div>'.
$out. '</div>',
'</div>'. $out);
'</div>';
} }
} }

View file

@ -4,14 +4,13 @@ final class AphrontListFilterView extends AphrontView {
public function render() { public function render() {
require_celerity_resource('aphront-list-filter-view-css'); require_celerity_resource('aphront-list-filter-view-css');
return return hsprintf(
'<table class="aphront-list-filter-view">'. '<table class="aphront-list-filter-view">'.
'<tr>'. '<tr>'.
'<td class="aphront-list-filter-view-controls">'. '<td class="aphront-list-filter-view-controls">%s</td>'.
$this->renderChildren().
'</td>'.
'</tr>'. '</tr>'.
'</table>'; '</table>',
$this->renderHTMLChildren());
} }
} }

View file

@ -3,10 +3,9 @@
final class AphrontMiniPanelView extends AphrontView { final class AphrontMiniPanelView extends AphrontView {
public function render() { public function render() {
return return hsprintf(
'<div class="aphront-mini-panel-view">'. '<div class="aphront-mini-panel-view">%s</div>',
$this->renderChildren(). $this->renderHTMLChildren());
'</div>';
} }
} }

View file

@ -98,13 +98,14 @@ final class AphrontPanelView extends AphrontView {
$classes[] = 'aphront-panel-width-'.$this->width; $classes[] = 'aphront-panel-width-'.$this->width;
} }
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => implode(' ', $classes), 'class' => implode(' ', $classes),
'id' => $this->id, 'id' => $this->id,
), ),
$header_elements.$table); // TODO: [HTML] Make HTML safe.
phutil_safe_html($header_elements.$table));
} }
} }

View file

@ -277,21 +277,26 @@ final class AphrontSideNavFilterView extends AphrontView {
$nav_classes = array_merge($nav_classes, $this->classes); $nav_classes = array_merge($nav_classes, $this->classes);
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => implode(' ', $nav_classes), 'class' => implode(' ', $nav_classes),
'id' => $main_id, 'id' => $main_id,
), ),
$local_menu. array(
$flex_bar. $local_menu,
phutil_render_tag( $flex_bar,
phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-nav-content', 'class' => 'phabricator-nav-content',
'id' => $content_id, 'id' => $content_id,
), ),
$crumbs.$this->renderChildren())); array(
$crumbs,
phutil_safe_html($this->renderChildren()),
))
));
} }
} }

View file

@ -31,7 +31,7 @@ final class PhabricatorFileLinkListView extends AphrontView {
$file_links[] = $view->render(); $file_links[] = $view->render();
} }
return implode('<br />', $file_links); return phutil_implode_html(phutil_tag('br'), $file_links);
} }
} }

View file

@ -67,9 +67,9 @@ final class PhabricatorProfileHeaderView extends AphrontView {
</tr> </tr>
</table>', </table>',
$this->profileName, $this->profileName,
phutil_safe_html(self::renderSingleView($this->profileActions)), self::renderSingleView($this->profileActions),
$image, $image,
$description). $description).
$this->renderChildren(); $this->renderHTMLChildren();
} }
} }

View file

@ -62,20 +62,22 @@ final class PhabricatorTransactionView extends AphrontView {
$transaction_id = $this->anchorName ? 'anchor-'.$this->anchorName : null; $transaction_id = $this->anchorName ? 'anchor-'.$this->anchorName : null;
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-transaction-view', 'class' => 'phabricator-transaction-view',
'id' => $transaction_id, 'id' => $transaction_id,
'style' => $style, 'style' => $style,
), ),
// TODO: [HTML] Make HTML safe.
phutil_safe_html(
'<div class="phabricator-transaction-detail '.$classes.'">'. '<div class="phabricator-transaction-detail '.$classes.'">'.
'<div class="phabricator-transaction-header">'. '<div class="phabricator-transaction-header">'.
$info. $info.
$actions. $actions.
'</div>'. '</div>'.
$content. $content.
'</div>'); '</div>'));
} }

View file

@ -73,7 +73,9 @@ abstract class AphrontPageView extends AphrontView {
EOHTML; EOHTML;
$response = $this->willSendResponse($response); $response = $this->willSendResponse($response);
return $response;
// TODO: [HTML] Make HTML safe.
return phutil_safe_html($response);
} }

View file

@ -13,15 +13,15 @@ final class AphrontRequestFailureView extends AphrontView {
final public function render() { final public function render() {
require_celerity_resource('aphront-request-failure-view-css'); require_celerity_resource('aphront-request-failure-view-css');
return return hsprintf(
'<div class="aphront-request-failure-view">'. '<div class="aphront-request-failure-view">'.
'<div class="aphront-request-failure-head">'. '<div class="aphront-request-failure-head">'.
phutil_tag('h1', array(), $this->header). '<h1>%s</h1>'.
'</div>'. '</div>'.
'<div class="aphront-request-failure-body">'. '<div class="aphront-request-failure-body">%s</div>'.
$this->renderChildren(). '</div>',
'</div>'. $this->header,
'</div>'; $this->renderHTMLChildren());
} }
} }

View file

@ -60,18 +60,19 @@ final class PhabricatorMainMenuSearchView extends AphrontView {
'value' => $scope, 'value' => $scope,
)); ));
$form = phabricator_render_form( $form = phabricator_form(
$user, $user,
array( array(
'action' => '/search/', 'action' => '/search/',
'method' => 'POST', 'method' => 'POST',
), ),
hsprintf(
'<div class="phabricator-main-menu-search-container">'. '<div class="phabricator-main-menu-search-container">'.
$input. '%s<button>Search</button>%s%s'.
'<button>Search</button>'. '</div>',
$scope_input. $input,
$target. $scope_input,
'</div>'); $target));
return $form; return $form;
} }

View file

@ -51,7 +51,7 @@ final class PhabricatorMainMenuView extends AphrontView {
$phabricator_menu = $this->renderPhabricatorMenu(); $phabricator_menu = $this->renderPhabricatorMenu();
if ($alerts) { if ($alerts) {
$alerts = phutil_render_tag( $alerts = phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-main-menu-alerts', 'class' => 'phabricator-main-menu-alerts',
@ -65,14 +65,14 @@ final class PhabricatorMainMenuView extends AphrontView {
$application_menu->addClass('phabricator-application-menu'); $application_menu->addClass('phabricator-application-menu');
} }
return phutil_render_tag( return phutil_tag(
'div', 'div',
array( array(
'class' => 'phabricator-main-menu', 'class' => 'phabricator-main-menu',
'id' => $header_id, 'id' => $header_id,
), ),
self::renderSingleView(
array( array(
self::renderSingleView(array(
$this->renderPhabricatorMenuButton($header_id), $this->renderPhabricatorMenuButton($header_id),
$application_menu $application_menu
? $this->renderApplicationMenuButton($header_id) ? $this->renderApplicationMenuButton($header_id)
@ -81,8 +81,9 @@ final class PhabricatorMainMenuView extends AphrontView {
$alerts, $alerts,
$phabricator_menu, $phabricator_menu,
$application_menu, $application_menu,
))). )),
self::renderSingleView($menus); self::renderSingleView($menus),
));
} }
private function renderSearch() { private function renderSearch() {