diff --git a/src/aphront/response/AphrontRedirectResponse.php b/src/aphront/response/AphrontRedirectResponse.php index b01cc3644d..4ee21fb4ee 100644 --- a/src/aphront/response/AphrontRedirectResponse.php +++ b/src/aphront/response/AphrontRedirectResponse.php @@ -1,66 +1,68 @@ uri = $uri; return $this; } public function getURI() { return (string)$this->uri; } public function shouldStopForDebugging() { return PhabricatorEnv::getEnvConfig('debug.stop-on-redirect'); } public function getHeaders() { $headers = array(); if (!$this->shouldStopForDebugging()) { $headers[] = array('Location', $this->uri); } $headers = array_merge(parent::getHeaders(), $headers); return $headers; } public function buildResponseString() { if ($this->shouldStopForDebugging()) { $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->setApplicationName('Debug'); $view->setTitle('Stopped on Redirect'); $error = new AphrontErrorView(); $error->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $error->setTitle('Stopped on Redirect'); + $error->appendChild(phutil_tag('p', array(), pht( + 'You were stopped here because %s is set in your configuration.', + phutil_tag('tt', array(), 'debug.stop-on-redirect')))); + $link = phutil_tag( 'a', array( 'href' => $this->getURI(), ), - 'Continue to: '.$this->getURI()); + $this->getURI()); - $error->appendChild(hsprintf( - '

You were stopped here because debug.stop-on-redirect '. - 'is set in your configuration.

'. - '

%s

', - $link)); + $error->appendChild(phutil_tag('p', array(), pht( + 'Continue to: %s', + $link))); $view->appendChild($error); return $view->render(); } return ''; } } diff --git a/src/infrastructure/celerity/CelerityStaticResourceResponse.php b/src/infrastructure/celerity/CelerityStaticResourceResponse.php index ccde0280e2..069be5cd85 100644 --- a/src/infrastructure/celerity/CelerityStaticResourceResponse.php +++ b/src/infrastructure/celerity/CelerityStaticResourceResponse.php @@ -1,262 +1,263 @@ metadataBlock = (int)$_REQUEST['__metablock__']; } } public function addMetadata($metadata) { $id = count($this->metadata); $this->metadata[$id] = $metadata; return $this->metadataBlock.'_'.$id; } public function getMetadataBlock() { return $this->metadataBlock; } /** * Register a behavior for initialization. NOTE: if $config is empty, * a behavior will execute only once even if it is initialized multiple times. * If $config is nonempty, the behavior will be invoked once for each config. */ public function initBehavior($behavior, array $config = array()) { $this->requireResource('javelin-behavior-'.$behavior); if (empty($this->behaviors[$behavior])) { $this->behaviors[$behavior] = array(); } if ($config) { $this->behaviors[$behavior][] = $config; } return $this; } public function requireResource($symbol) { $this->symbols[$symbol] = true; $this->needsResolve = true; return $this; } private function resolveResources() { if ($this->needsResolve) { $map = CelerityResourceMap::getInstance(); $this->resolved = $map->resolveResources(array_keys($this->symbols)); $this->packaged = $map->packageResources($this->resolved); $this->needsResolve = false; } return $this; } public function renderSingleResource($symbol) { $map = CelerityResourceMap::getInstance(); $resolved = $map->resolveResources(array($symbol)); $packaged = $map->packageResources($resolved); return $this->renderPackagedResources($packaged); } public function renderResourcesOfType($type) { $this->resolveResources(); $resources = array(); foreach ($this->packaged as $resource) { if ($resource['type'] == $type) { $resources[] = $resource; } } return $this->renderPackagedResources($resources); } private function renderPackagedResources(array $resources) { $output = array(); foreach ($resources as $resource) { if (isset($this->hasRendered[$resource['uri']])) { continue; } $this->hasRendered[$resource['uri']] = true; $output[] = $this->renderResource($resource); $output[] = "\n"; } return phutil_implode_html('', $output); } private function renderResource(array $resource) { $uri = $this->getURI($resource); switch ($resource['type']) { case 'css': return phutil_tag( 'link', array( 'rel' => 'stylesheet', 'type' => 'text/css', 'href' => $uri, )); case 'js': return phutil_tag( 'script', array( 'type' => 'text/javascript', 'src' => $uri, ), ''); } throw new Exception("Unable to render resource."); } public function renderHTMLFooter() { $data = array(); if ($this->metadata) { $json_metadata = AphrontResponse::encodeJSONForHTTPResponse( $this->metadata); $this->metadata = array(); } else { $json_metadata = '{}'; } // Even if there is no metadata on the page, Javelin uses the mergeData() // call to start dispatching the event queue. $data[] = 'JX.Stratcom.mergeData('.$this->metadataBlock.', '. $json_metadata.');'; $onload = array(); if ($this->behaviors) { $behaviors = $this->behaviors; $this->behaviors = array(); $higher_priority_names = array( 'refresh-csrf', 'aphront-basic-tokenizer', 'dark-console', 'history-install', ); $higher_priority_behaviors = array_select_keys( $behaviors, $higher_priority_names); foreach ($higher_priority_names as $name) { unset($behaviors[$name]); } $behavior_groups = array( $higher_priority_behaviors, $behaviors); foreach ($behavior_groups as $group) { if (!$group) { continue; } $group_json = AphrontResponse::encodeJSONForHTTPResponse( $group); $onload[] = 'JX.initBehaviors('.$group_json.')'; } } if ($onload) { foreach ($onload as $func) { $data[] = 'JX.onload(function(){'.$func.'});'; } } if ($data) { $data = implode("\n", $data); return self::renderInlineScript($data); } else { return ''; } } public static function renderInlineScript($data) { if (stripos($data, '') !== false) { throw new Exception( 'Literal is not allowed inside inline script.'); } if (strpos($data, ' because it is ignored by HTML parsers. We - // would need to send the document with XHTML content type. - '', + // We don't use because it is ignored by HTML parsers. We + // would need to send the document with XHTML content type. + return phutil_tag( + 'script', + array('type' => 'text/javascript'), phutil_safe_html($data)); } public function buildAjaxResponse($payload, $error = null) { $response = array( 'error' => $error, 'payload' => $payload, ); if ($this->metadata) { $response['javelin_metadata'] = $this->metadata; $this->metadata = array(); } if ($this->behaviors) { $response['javelin_behaviors'] = $this->behaviors; $this->behaviors = array(); } $this->resolveResources(); $resources = array(); foreach ($this->packaged as $resource) { $resources[] = $this->getURI($resource); } if ($resources) { $response['javelin_resources'] = $resources; } return $response; } private function getURI($resource) { $uri = $resource['uri']; // In developer mode, we dump file modification times into the URI. When a // page is reloaded in the browser, any resources brought in by Ajax calls // do not trigger revalidation, so without this it's very difficult to get // changes to Ajaxed-in CSS to work (you must clear your cache or rerun // the map script). In production, we can assume the map script gets run // after changes, and safely skip this. if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) { $root = dirname(phutil_get_library_root('phabricator')).'/webroot'; if (isset($resource['disk'])) { $mtime = (int)filemtime($root.$resource['disk']); } else { $mtime = 0; foreach ($resource['symbols'] as $symbol) { $map = CelerityResourceMap::getInstance(); $symbol_info = $map->lookupSymbolInformation($symbol); $mtime = max($mtime, (int)filemtime($root.$symbol_info['disk'])); } } $uri = preg_replace('@^/res/@', '/res/'.$mtime.'T/', $uri); } return PhabricatorEnv::getCDNURI($uri); } } diff --git a/src/infrastructure/diff/PhabricatorInlineCommentController.php b/src/infrastructure/diff/PhabricatorInlineCommentController.php index 3a8ad2f1ad..77b3bfe19e 100644 --- a/src/infrastructure/diff/PhabricatorInlineCommentController.php +++ b/src/infrastructure/diff/PhabricatorInlineCommentController.php @@ -1,247 +1,248 @@ commentID; } public function getOperation() { return $this->operation; } public function getCommentText() { return $this->commentText; } public function getLineLength() { return $this->lineLength; } public function getLineNumber() { return $this->lineNumber; } public function getIsOnRight() { return $this->isOnRight; } public function getChangesetID() { return $this->changesetID; } public function getIsNewFile() { return $this->isNewFile; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $this->readRequestParameters(); switch ($this->getOperation()) { case 'delete': $inline = $this->loadCommentForEdit($this->getCommentID()); if ($request->isFormPost()) { $inline->delete(); return $this->buildEmptyResponse(); } $dialog = new AphrontDialogView(); $dialog->setUser($user); $dialog->setSubmitURI($request->getRequestURI()); $dialog->setTitle('Really delete this comment?'); $dialog->addHiddenInput('id', $this->getCommentID()); $dialog->addHiddenInput('op', 'delete'); - $dialog->appendChild(hsprintf('

Delete this inline comment?

')); + $dialog->appendChild( + phutil_tag('p', array(), pht('Delete this inline comment?'))); $dialog->addCancelButton('#'); $dialog->addSubmitButton('Delete'); return id(new AphrontDialogResponse())->setDialog($dialog); case 'edit': $inline = $this->loadCommentForEdit($this->getCommentID()); $text = $this->getCommentText(); if ($request->isFormPost()) { if (strlen($text)) { $inline->setContent($text); $inline->save(); return $this->buildRenderedCommentResponse( $inline, $this->getIsOnRight()); } else { $inline->delete(); return $this->buildEmptyResponse(); } } $edit_dialog = $this->buildEditDialog(); $edit_dialog->setTitle('Edit Inline Comment'); $edit_dialog->addHiddenInput('id', $this->getCommentID()); $edit_dialog->addHiddenInput('op', 'edit'); $edit_dialog->appendChild( $this->renderTextArea( nonempty($text, $inline->getContent()))); return id(new AphrontAjaxResponse()) ->setContent($edit_dialog->render()); case 'create': $text = $this->getCommentText(); if (!$request->isFormPost() || !strlen($text)) { return $this->buildEmptyResponse(); } $inline = $this->createComment() ->setChangesetID($this->getChangesetID()) ->setAuthorPHID($user->getPHID()) ->setLineNumber($this->getLineNumber()) ->setLineLength($this->getLineLength()) ->setIsNewFile($this->getIsNewFile()) ->setContent($text) ->save(); return $this->buildRenderedCommentResponse( $inline, $this->getIsOnRight()); case 'reply': default: $edit_dialog = $this->buildEditDialog(); if ($this->getOperation() == 'reply') { $inline = $this->loadComment($this->getCommentID()); $edit_dialog->setTitle('Reply to Inline Comment'); $changeset = $inline->getChangesetID(); $is_new = $inline->getIsNewFile(); $number = $inline->getLineNumber(); $length = $inline->getLineLength(); } else { $edit_dialog->setTitle('New Inline Comment'); $changeset = $this->getChangesetID(); $is_new = $this->getIsNewFile(); $number = $this->getLineNumber(); $length = $this->getLineLength(); } $edit_dialog->addHiddenInput('op', 'create'); $edit_dialog->addHiddenInput('changeset', $changeset); $edit_dialog->addHiddenInput('is_new', $is_new); $edit_dialog->addHiddenInput('number', $number); $edit_dialog->addHiddenInput('length', $length); $text_area = $this->renderTextArea($this->getCommentText()); $edit_dialog->appendChild($text_area); return id(new AphrontAjaxResponse()) ->setContent($edit_dialog->render()); } } private function readRequestParameters() { $request = $this->getRequest(); // NOTE: This isn't necessarily a DifferentialChangeset ID, just an // application identifier for the changeset. In Diffusion, it's a Path ID. $this->changesetID = $request->getInt('changeset'); $this->isNewFile = $request->getBool('is_new'); $this->isOnRight = $request->getBool('on_right'); $this->lineNumber = $request->getInt('number'); $this->lineLength = $request->getInt('length'); $this->commentText = $request->getStr('text'); $this->commentID = $request->getInt('id'); $this->operation = $request->getStr('op'); } private function buildEditDialog() { $request = $this->getRequest(); $user = $request->getUser(); $edit_dialog = new DifferentialInlineCommentEditView(); $edit_dialog->setUser($user); $edit_dialog->setSubmitURI($request->getRequestURI()); $edit_dialog->setOnRight($this->getIsOnRight()); $edit_dialog->setNumber($this->getLineNumber()); $edit_dialog->setLength($this->getLineLength()); return $edit_dialog; } private function buildEmptyResponse() { return id(new AphrontAjaxResponse()) ->setContent( array( 'markup' => '', )); } private function buildRenderedCommentResponse( PhabricatorInlineCommentInterface $inline, $on_right) { $request = $this->getRequest(); $user = $request->getUser(); $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject( $inline, PhabricatorInlineCommentInterface::MARKUP_FIELD_BODY); $engine->process(); $phids = array($user->getPHID()); $handles = $this->loadViewerHandles($phids); $view = new DifferentialInlineCommentView(); $view->setInlineComment($inline); $view->setOnRight($on_right); $view->setBuildScaffolding(true); $view->setMarkupEngine($engine); $view->setHandles($handles); $view->setEditable(true); return id(new AphrontAjaxResponse()) ->setContent( array( 'inlineCommentID' => $inline->getID(), 'markup' => $view->render(), )); } private function renderTextArea($text) { return javelin_tag( 'textarea', array( 'class' => 'differential-inline-comment-edit-textarea', 'sigil' => 'differential-inline-comment-edit-textarea', 'name' => 'text', ), $text); } } diff --git a/src/infrastructure/diff/view/PhabricatorInlineSummaryView.php b/src/infrastructure/diff/view/PhabricatorInlineSummaryView.php index f8686ebba0..9e05640b61 100644 --- a/src/infrastructure/diff/view/PhabricatorInlineSummaryView.php +++ b/src/infrastructure/diff/view/PhabricatorInlineSummaryView.php @@ -1,113 +1,107 @@ groups[$name])) { $this->groups[$name] = $items; } else { $this->groups[$name] = array_merge($this->groups[$name], $items); } return $this; } public function render() { require_celerity_resource('inline-comment-summary-css'); return hsprintf('%s%s', $this->renderHeader(), $this->renderTable()); } private function renderHeader() { - return phutil_tag( - 'div', - array( - 'class' => 'phabricator-inline-summary', - ), - 'Inline Comments'); + return phutil_tag_div('phabricator-inline-summary', pht('Inline Comments')); } private function renderTable() { $rows = array(); foreach ($this->groups as $group => $items) { $has_where = false; foreach ($items as $item) { if (!empty($item['where'])) { $has_where = true; break; } } - $rows[] = hsprintf('%s', $group); + $rows[] = phutil_tag( + 'tr', + array(), + phutil_tag('th', array('colspan' => 3), $group)); foreach ($items as $item) { $items = isort($items, 'line'); $line = $item['line']; $length = $item['length']; if ($length) { $lines = $line."\xE2\x80\x93".($line + $length); } else { $lines = $line; } if (isset($item['href'])) { $href = $item['href']; $target = '_blank'; $tail = " \xE2\x86\x97"; } else { $href = '#inline-'.$item['id']; $target = null; $tail = null; } if ($href) { $lines = phutil_tag( 'a', array( 'href' => $href, 'target' => $target, 'class' => 'num', ), array( $lines, $tail, )); } $where = idx($item, 'where'); $colspan = ($has_where ? null : 2); - $rows[] = hsprintf( - ''. - '%s'. - '%s'. - '%s'. - '', - $lines, - ($has_where - ? hsprintf('%s', $where) - : null), - phutil_tag( - 'td', - array( - 'class' => 'inline-summary-content', - 'colspan' => $colspan, - ), - hsprintf( - '
%s
', - $item['content']))); + $rows[] = phutil_tag( + 'tr', + array(), + array( + phutil_tag('td', array('class' => 'inline-line-number'), $lines), + ($has_where + ? phutil_tag('td', array('class' => 'inline-which-diff'), $where) + : null), + phutil_tag( + 'td', + array( + 'class' => 'inline-summary-content', + 'colspan' => $colspan, + ), + phutil_tag_div('phabricator-remarkup', $item['content'])))); } } return phutil_tag( 'table', array( 'class' => 'phabricator-inline-summary-table', ), phutil_implode_html("\n", $rows)); } } diff --git a/src/infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php b/src/infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php index 6ea88db6ca..ba3b0c92dc 100644 --- a/src/infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php +++ b/src/infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php @@ -1,48 +1,48 @@ uri = new PhutilURI($text); if ($this->uri->getDomain() && preg_match('/(^|\.)youtube\.com$/', $this->uri->getDomain()) && idx($this->uri->getQueryParams(), 'v')) { return $this->markupYoutubeLink(); } return $text; } public function markupYoutubeLink() { $v = idx($this->uri->getQueryParams(), 'v'); if ($this->getEngine()->isTextMode()) { return $this->getEngine()->storeText('http://youtu.be/'.$v); } $youtube_src = 'https://www.youtube.com/embed/'.$v; - $iframe = hsprintf( - '
%s
', + $iframe = phutil_tag_div( + 'embedded-youtube-video', phutil_tag( 'iframe', array( 'width' => '650', 'height' => '400', 'style' => 'margin: 1em auto; border: 0px;', 'src' => $youtube_src, 'frameborder' => 0, ), '')); return $this->getEngine()->storeText($iframe); } } diff --git a/src/view/control/AphrontTableView.php b/src/view/control/AphrontTableView.php index ede387b65a..17fca10d5a 100644 --- a/src/view/control/AphrontTableView.php +++ b/src/view/control/AphrontTableView.php @@ -1,320 +1,323 @@ 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 setCellClasses(array $cell_classes) { $this->cellClasses = $cell_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; } public function setDeviceVisibility(array $device_visibility) { $this->deviceVisibility = $device_visibility; return $this; } public function setDeviceReadyTable($ready) { $this->deviceReadyTable = $ready; return $this; } public function setShortHeaders(array $short_headers) { $this->shortHeaders = $short_headers; 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'); $table = array(); $col_classes = array(); foreach ($this->columnClasses as $key => $class) { if (strlen($class)) { $col_classes[] = $class; } else { $col_classes[] = null; } } $visibility = array_values($this->columnVisibility); $device_visibility = array_values($this->deviceVisibility); $headers = $this->headers; $short_headers = $this->shortHeaders; $sort_values = $this->sortValues; if ($headers) { while (count($headers) > count($visibility)) { $visibility[] = true; } while (count($headers) > count($device_visibility)) { $device_visibility[] = true; } while (count($headers) > count($short_headers)) { $short_headers[] = null; } while (count($headers) > count($sort_values)) { $sort_values[] = null; } $tr = array(); 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 (empty($device_visiblity[$col_num])) { $classes[] = 'aphront-table-nodevice'; } if ($sort_values[$col_num] !== null) { $classes[] = 'aphront-table-view-sortable'; $sort_value = $sort_values[$col_num]; $sort_glyph_class = 'aphront-table-down-sort'; if ($sort_value == $this->sortSelected) { if ($this->sortReverse) { $sort_glyph_class = 'aphront-table-up-sort'; } else if (!$this->sortReverse) { $sort_value = '-'.$sort_value; } $classes[] = 'aphront-table-view-sortable-selected'; } $sort_glyph = phutil_tag( 'span', array( 'class' => $sort_glyph_class, ), ''); $header = phutil_tag( 'a', array( 'href' => $this->sortURI->alter($this->sortParam, $sort_value), 'class' => 'aphront-table-view-sort-link', ), array( $header, ' ', $sort_glyph, )); } if ($classes) { $class = implode(' ', $classes); } else { $class = null; } if ($short_headers[$col_num] !== null) { $header_nodevice = phutil_tag( 'span', array( 'class' => 'aphront-table-view-nodevice', ), $header); $header_device = phutil_tag( 'span', array( 'class' => 'aphront-table-view-device', ), $short_headers[$col_num]); $header = hsprintf('%s %s', $header_nodevice, $header_device); } $tr[] = phutil_tag('th', array('class' => $class), $header); } $table[] = phutil_tag('tr', array(), $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] = $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; } $tr = array(); // 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 (!empty($this->cellClasses[$row_num][$col_num])) { $class = trim($class.' '.$this->cellClasses[$row_num][$col_num]); } $tr[] = phutil_tag('td', array('class' => $class), $value); ++$col_num; } $class = idx($this->rowClasses, $row_num); if ($this->zebraStripes && ($row_num % 2)) { if ($class !== null) { $class = 'alt alt-'.$class; } else { $class = 'alt'; } } $table[] = phutil_tag('tr', array('class' => $class), $tr); ++$row_num; } } else { $colspan = max(count(array_filter($visibility)), 1); - $table[] = hsprintf( - '%s', - $colspan, - coalesce($this->noDataString, pht('No data available.'))); + $table[] = phutil_tag( + 'tr', + array('class' => 'no-data'), + phutil_tag( + 'td', + array('colspan' => $colspan), + coalesce($this->noDataString, pht('No data available.')))); } $table_class = 'aphront-table-view'; if ($this->className !== null) { $table_class .= ' '.$this->className; } if ($this->deviceReadyTable) { $table_class .= ' aphront-table-view-device-ready'; } $html = phutil_tag('table', array('class' => $table_class), $table); - return hsprintf('
%s
', $html); + return phutil_tag_div('aphront-table-wrap', $html); } 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 // (  -- 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_tag( 'div', array( 'class' => 'single-display-line-bounds', ), array( phutil_tag( 'span', array( 'class' => 'single-display-line-content', ), $line), "\xC2\xA0", )); } } diff --git a/src/view/control/PhabricatorObjectSelectorDialog.php b/src/view/control/PhabricatorObjectSelectorDialog.php index 0d98861dff..f6e107a99c 100644 --- a/src/view/control/PhabricatorObjectSelectorDialog.php +++ b/src/view/control/PhabricatorObjectSelectorDialog.php @@ -1,199 +1,194 @@ user = $user; return $this; } public function setFilters(array $filters) { $this->filters = $filters; return $this; } public function setSelectedFilter($selected_filter) { $this->selectedFilter = $selected_filter; return $this; } public function setExcluded($excluded_phid) { $this->excluded = $excluded_phid; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function setCancelURI($cancel_uri) { $this->cancelURI = $cancel_uri; return $this; } public function setSubmitURI($submit_uri) { $this->submitURI = $submit_uri; return $this; } public function setSearchURI($search_uri) { $this->searchURI = $search_uri; return $this; } public function setTitle($title) { $this->title = $title; return $this; } public function setHeader($header) { $this->header = $header; return $this; } public function setButtonText($button_text) { $this->buttonText = $button_text; return $this; } public function setInstructions($instructions) { $this->instructions = $instructions; return $this; } public function buildDialog() { $user = $this->user; $filter_id = celerity_generate_unique_node_id(); $query_id = celerity_generate_unique_node_id(); $results_id = celerity_generate_unique_node_id(); $current_id = celerity_generate_unique_node_id(); $search_id = celerity_generate_unique_node_id(); $form_id = celerity_generate_unique_node_id(); require_celerity_resource('phabricator-object-selector-css'); $options = array(); foreach ($this->filters as $key => $label) { $options[] = phutil_tag( 'option', array( 'value' => $key, 'selected' => ($key == $this->selectedFilter) ? 'selected' : null, ), $label); } $instructions = null; if ($this->instructions) { $instructions = phutil_tag( 'p', array('class' => 'phabricator-object-selector-instructions'), $this->instructions); } $search_box = phabricator_form( $user, array( 'method' => 'POST', 'action' => $this->submitURI, 'id' => $search_id, ), - hsprintf( - ' - - - - - ', - phutil_tag( - 'select', - array('id' => $filter_id), - $options), - phutil_tag( - 'input', - array( - 'id' => $query_id, - 'type' => 'text')))); + phutil_tag( + 'table', + array('class' => 'phabricator-object-selector-search'), + phutil_tag('tr', array(), array( + phutil_tag( + 'td', + array('class' => 'phabricator-object-selector-search-filter'), + phutil_tag('select', array('id' => $filter_id), $options)), + phutil_tag( + 'td', + array('class' => 'phabricator-object-selector-search-text'), + phutil_tag('input', array('id' => $query_id, 'type' => 'text'))), + )))); $result_box = phutil_tag( 'div', array( 'class' => 'phabricator-object-selector-results', 'id' => $results_id, ), ''); - $attached_box = hsprintf( - '
'. - '
'. - '
%s
'. - '
'. - '%s'. - '
'. - '
', - $this->header, - $current_id, - $instructions); + $attached_box = phutil_tag_div( + 'phabricator-object-selector-current', + phutil_tag_div( + 'phabricator-object-selector-currently-attached', + array( + phutil_tag_div('phabricator-object-selector-header', $this->header), + phutil_tag('div', array('id' => $current_id)), + $instructions, + ))); $dialog = new AphrontDialogView(); $dialog ->setUser($this->user) ->setTitle($this->title) ->setClass('phabricator-object-selector-dialog') ->appendChild($search_box) ->appendChild($result_box) ->appendChild($attached_box) ->setRenderDialogAsDiv() ->setFormID($form_id) ->addSubmitButton($this->buttonText); if ($this->cancelURI) { $dialog->addCancelButton($this->cancelURI); } $handle_views = array(); foreach ($this->handles as $handle) { $phid = $handle->getPHID(); $view = new PhabricatorHandleObjectSelectorDataView($handle); $handle_views[$phid] = $view->renderData(); } $dialog->addHiddenInput('phids', implode(';', array_keys($this->handles))); Javelin::initBehavior( 'phabricator-object-selector', array( 'filter' => $filter_id, 'query' => $query_id, 'search' => $search_id, 'results' => $results_id, 'current' => $current_id, 'form' => $form_id, 'exclude' => $this->excluded, 'uri' => $this->searchURI, 'handles' => $handle_views, )); return $dialog; } } diff --git a/src/view/form/control/AphrontFormCheckboxControl.php b/src/view/form/control/AphrontFormCheckboxControl.php index 4d452c448e..6e575fd533 100644 --- a/src/view/form/control/AphrontFormCheckboxControl.php +++ b/src/view/form/control/AphrontFormCheckboxControl.php @@ -1,52 +1,52 @@ boxes[] = array( 'name' => $name, 'value' => $value, 'label' => $label, 'checked' => $checked, ); return $this; } protected function getCustomControlClass() { return 'aphront-form-control-checkbox'; } protected function renderInput() { $rows = array(); foreach ($this->boxes as $box) { $id = celerity_generate_unique_node_id(); $checkbox = phutil_tag( 'input', array( 'id' => $id, 'type' => 'checkbox', 'name' => $box['name'], 'value' => $box['value'], 'checked' => $box['checked'] ? 'checked' : null, 'disabled' => $this->getDisabled() ? 'disabled' : null, )); $label = phutil_tag( 'label', array( 'for' => $id, ), $box['label']); - $rows[] = hsprintf( - '%s%s', - $checkbox, - $label); + $rows[] = phutil_tag('tr', array(), array( + phutil_tag('td', array(), $checkbox), + phutil_tag('th', array(), $label) + )); } return phutil_tag( 'table', array('class' => 'aphront-form-control-checkbox-layout'), $rows); } } diff --git a/src/view/form/control/AphrontFormRadioButtonControl.php b/src/view/form/control/AphrontFormRadioButtonControl.php index 589968af13..5764275151 100644 --- a/src/view/form/control/AphrontFormRadioButtonControl.php +++ b/src/view/form/control/AphrontFormRadioButtonControl.php @@ -1,71 +1,71 @@ buttons[] = array( 'value' => $value, 'label' => $label, 'caption' => $caption, 'class' => $class, 'disabled' => $disabled, ); return $this; } protected function getCustomControlClass() { return 'aphront-form-control-radio'; } protected function renderInput() { $rows = array(); foreach ($this->buttons as $button) { $id = celerity_generate_unique_node_id(); $radio = phutil_tag( 'input', array( 'id' => $id, 'type' => 'radio', 'name' => $this->getName(), 'value' => $button['value'], 'checked' => ($button['value'] == $this->getValue()) ? 'checked' : null, 'disabled' => ($this->getDisabled() || $button['disabled']) ? 'disabled' : null, )); $label = phutil_tag( 'label', array( 'for' => $id, 'class' => $button['class'], ), $button['label']); if ($button['caption']) { - $label = hsprintf( - '%s
%s
', + $label = array( $label, - $button['caption']); + phutil_tag_div('aphront-form-radio-caption', $button['caption']), + ); } - $rows[] = hsprintf( - '%s%s', - $radio, - $label); + $rows[] = phutil_tag('tr', array(), array( + phutil_tag('td', array(), $radio), + phutil_tag('th', array(), $label), + )); } return phutil_tag( 'table', array('class' => 'aphront-form-control-radio-layout'), $rows); } } diff --git a/src/view/layout/AphrontContextBarView.php b/src/view/layout/AphrontContextBarView.php index 07c640fbb5..2d5a6d3637 100644 --- a/src/view/layout/AphrontContextBarView.php +++ b/src/view/layout/AphrontContextBarView.php @@ -1,30 +1,29 @@ buttons[] = $button; return $this; } public function render() { $view = new AphrontNullView(); $view->appendChild($this->buttons); require_celerity_resource('aphront-contextbar-view-css'); - return hsprintf( - '
'. - '
'. - '
%s
'. - '
%s
'. - '
'. - '
'. - '
', - $view->render(), - $this->renderChildren()); + return phutil_tag_div( + 'aphront-contextbar-view', + array( + phutil_tag_div('aphront-contextbar-core', array( + phutil_tag_div('aphront-contextbar-buttons', $view->render()), + phutil_tag_div('aphront-contextbar-content', $this->renderChildren()), + )), + phutil_tag('div', array('style' => 'clear: both;')), + )); } } diff --git a/src/view/layout/AphrontPanelView.php b/src/view/layout/AphrontPanelView.php index 0ae35ef0df..066d538de6 100644 --- a/src/view/layout/AphrontPanelView.php +++ b/src/view/layout/AphrontPanelView.php @@ -1,111 +1,106 @@ addButton( phutil_tag( 'a', array( 'href' => $href, 'class' => 'button green', ), $create_button)); return $this; } public function addClass($class) { $this->classes[] = $class; return $this; } public function addButton($button) { $this->buttons[] = $button; return $this; } public function setHeader($header) { $this->header = $header; return $this; } public function setWidth($width) { $this->width = $width; return $this; } public function setID($id) { $this->id = $id; return $this; } public function setCaption($caption) { $this->caption = $caption; return $this; } public function setNoBackground() { $this->classes[] = 'aphront-panel-plain'; return $this; } public function render() { if ($this->header !== null) { $header = phutil_tag('h1', array(), $this->header); } else { $header = null; } if ($this->caption !== null) { - $caption = phutil_tag( - 'div', - array('class' => 'aphront-panel-view-caption'), - $this->caption); + $caption = phutil_tag_div('aphront-panel-view-caption', $this->caption); } else { $caption = null; } $buttons = null; if ($this->buttons) { - $buttons = hsprintf( - '
%s
', + $buttons = phutil_tag_div( + 'aphront-panel-view-buttons', phutil_implode_html(" ", $this->buttons)); } - $header_elements = hsprintf( - '
%s%s%s
', - $buttons, - $header, - $caption); + $header_elements = phutil_tag_div( + 'aphront-panel-header', + array($buttons, $header, $caption)); $table = phutil_implode_html('', $this->renderChildren()); require_celerity_resource('aphront-panel-view-css'); $classes = $this->classes; $classes[] = 'aphront-panel-view'; if ($this->width) { $classes[] = 'aphront-panel-width-'.$this->width; } return phutil_tag( 'div', array( 'class' => implode(' ', $classes), 'id' => $this->id, ), array($header_elements, $table)); } } diff --git a/src/view/layout/PhabricatorSourceCodeView.php b/src/view/layout/PhabricatorSourceCodeView.php index b8396b78b2..7c2b64d660 100644 --- a/src/view/layout/PhabricatorSourceCodeView.php +++ b/src/view/layout/PhabricatorSourceCodeView.php @@ -1,133 +1,130 @@ limit = $limit; return $this; } public function setLines(array $lines) { $this->lines = $lines; return $this; } public function setURI(PhutilURI $uri) { $this->uri = $uri; return $this; } public function setHighlights(array $array) { $this->highlights = array_fuse($array); return $this; } public function disableHighlightOnClick() { $this->canClickHighlight = false; return $this; } public function render() { require_celerity_resource('phabricator-source-code-view-css'); require_celerity_resource('syntax-highlighting-css'); Javelin::initBehavior('phabricator-oncopy', array()); if ($this->canClickHighlight) { Javelin::initBehavior('phabricator-line-linker'); } $line_number = 1; $rows = array(); foreach ($this->lines as $line) { $hit_limit = $this->limit && ($line_number == $this->limit) && (count($this->lines) != $this->limit); if ($hit_limit) { $content_number = ''; $content_line = phutil_tag( 'span', array( 'class' => 'c', ), pht('...')); } else { $content_number = $line_number; $content_line = hsprintf("\xE2\x80\x8B%s", $line); } $row_attributes = array(); if (isset($this->highlights[$line_number])) { $row_attributes['class'] = 'phabricator-source-highlight'; } if ($this->canClickHighlight) { $line_uri = $this->uri . "$" . $line_number; $line_href = (string) new PhutilURI($line_uri); $tag_number = javelin_tag( 'a', array( 'href' => $line_href ), $line_number); } else { $tag_number = javelin_tag( 'span', array(), $line_number); } $rows[] = phutil_tag( 'tr', $row_attributes, array( javelin_tag( 'th', array( 'class' => 'phabricator-source-line', 'sigil' => 'phabricator-source-line' ), $tag_number), phutil_tag( 'td', array( 'class' => 'phabricator-source-code' ), $content_line))); if ($hit_limit) { break; } $line_number++; } $classes = array(); $classes[] = 'phabricator-source-code-view'; $classes[] = 'remarkup-code'; $classes[] = 'PhabricatorMonospaced'; - return phutil_tag( - 'div', - array( - 'class' => 'phabricator-source-code-container', - ), + return phutil_tag_div( + 'phabricator-source-code-container', javelin_tag( 'table', array( 'class' => implode(' ', $classes), 'sigil' => 'phabricator-source' ), phutil_implode_html('', $rows))); } } diff --git a/src/view/layout/PhabricatorTransactionView.php b/src/view/layout/PhabricatorTransactionView.php index 7ceb3023bc..f87a1f3df9 100644 --- a/src/view/layout/PhabricatorTransactionView.php +++ b/src/view/layout/PhabricatorTransactionView.php @@ -1,148 +1,146 @@ imageURI = $uri; return $this; } public function setActions(array $actions) { $this->actions = $actions; return $this; } public function setEpoch($epoch) { $this->epoch = $epoch; return $this; } public function setContentSource(PhabricatorContentSource $source) { $this->contentSource = $source; return $this; } public function setAnchor($anchor_name, $anchor_text) { $this->anchorName = $anchor_name; $this->anchorText = $anchor_text; return $this; } public function addClass($class) { $this->classes[] = $class; return $this; } public function setIsPreview($preview) { $this->isPreview = $preview; return $this; } public function render() { if (!$this->user) { throw new Exception(pht("Call setUser() before render()!")); } require_celerity_resource('phabricator-transaction-view-css'); $info = $this->renderTransactionInfo(); $actions = $this->renderTransactionActions(); $style = $this->renderTransactionStyle(); $content = $this->renderTransactionContent(); $classes = implode(' ', $this->classes); $transaction_id = $this->anchorName ? 'anchor-'.$this->anchorName : null; + $header = phutil_tag_div( + 'phabricator-transaction-header', + array($info, $actions)); + return phutil_tag( 'div', array( 'class' => 'phabricator-transaction-view', 'id' => $transaction_id, 'style' => $style, ), - hsprintf( - '
'. - '
%s%s
'. - '%s'. - '
', - $classes, - $info, - $actions, - $content)); + phutil_tag_div( + 'phabricator-transaction-detail '.$classes, + array($header, $content))); } private function renderTransactionInfo() { $info = array(); if ($this->contentSource) { $content_source = new PhabricatorContentSourceView(); $content_source->setContentSource($this->contentSource); $content_source->setUser($this->user); $source = $content_source->render(); if ($source) { $info[] = $source; } } if ($this->isPreview) { $info[] = 'PREVIEW'; } else if ($this->epoch) { $info[] = phabricator_datetime($this->epoch, $this->user); } if ($this->anchorName) { Javelin::initBehavior('phabricator-watch-anchor'); $anchor = id(new PhabricatorAnchorView()) ->setAnchorName($this->anchorName) ->render(); $info[] = hsprintf( '%s%s', $anchor, phutil_tag( 'a', array('href' => '#'.$this->anchorName), $this->anchorText)); } $info = phutil_implode_html(" \xC2\xB7 ", $info); - return hsprintf( - '%s', + return phutil_tag( + 'span', + array('class' => 'phabricator-transaction-info'), $info); } private function renderTransactionActions() { return $this->actions; } private function renderTransactionStyle() { if ($this->imageURI) { return 'background-image: url('.$this->imageURI.');'; } else { return null; } } private function renderTransactionContent() { if (!$this->hasChildren()) { return null; } - return phutil_tag( - 'div', - array('class' => 'phabricator-transaction-content'), + return phutil_tag_div( + 'phabricator-transaction-content', $this->renderChildren()); } } diff --git a/src/view/page/AphrontRequestFailureView.php b/src/view/page/AphrontRequestFailureView.php index 1965340dd5..5910b4468f 100644 --- a/src/view/page/AphrontRequestFailureView.php +++ b/src/view/page/AphrontRequestFailureView.php @@ -1,27 +1,27 @@ header = $header; return $this; } final public function render() { require_celerity_resource('aphront-request-failure-view-css'); - return hsprintf( - '
'. - '
'. - '

%s

'. - '
'. - '
%s
'. - '
', - $this->header, + $head = phutil_tag_div( + 'aphront-request-failure-head', + phutil_tag('h1', array(), $this->header)); + + $body = phutil_tag_div( + 'aphront-request-failure-body', $this->renderChildren()); + + return phutil_tag_div('aphront-request-failure-view', array($head, $body)); } } diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php index affcc3bd88..f01d2ccd92 100644 --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -1,441 +1,435 @@ applicationMenu = $application_menu; return $this; } public function getApplicationMenu() { return $this->applicationMenu; } public function setApplicationName($application_name) { $this->applicationName = $application_name; return $this; } public function setDisableConsole($disable) { $this->disableConsole = $disable; return $this; } public function getApplicationName() { return $this->applicationName; } public function setBaseURI($base_uri) { $this->baseURI = $base_uri; return $this; } public function getBaseURI() { return $this->baseURI; } public function setShowChrome($show_chrome) { $this->showChrome = $show_chrome; return $this; } public function getShowChrome() { return $this->showChrome; } public function setSearchDefaultScope($search_default_scope) { $this->searchDefaultScope = $search_default_scope; return $this; } public function getSearchDefaultScope() { return $this->searchDefaultScope; } public function appendPageObjects(array $objs) { foreach ($objs as $obj) { $this->pageObjects[] = $obj; } } public function getTitle() { $use_glyph = true; $request = $this->getRequest(); if ($request) { $user = $request->getUser(); if ($user && $user->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_TITLES) !== 'glyph') { $use_glyph = false; } } $title = parent::getTitle(); $prefix = null; if ($use_glyph) { $prefix = $this->getGlyph(); } else { $application_name = $this->getApplicationName(); if (strlen($application_name)) { $prefix = '['.$application_name.']'; } } if (strlen($prefix)) { $title = $prefix.' '.$title; } return $title; } protected function willRenderPage() { parent::willRenderPage(); if (!$this->getRequest()) { throw new Exception( pht( "You must set the Request to render a PhabricatorStandardPageView.")); } $console = $this->getConsole(); require_celerity_resource('phabricator-core-css'); require_celerity_resource('phabricator-zindex-css'); require_celerity_resource('phui-button-css'); require_celerity_resource('phui-spacing-css'); require_celerity_resource('phui-form-css'); require_celerity_resource('sprite-gradient-css'); require_celerity_resource('phabricator-standard-page-view'); Javelin::initBehavior('workflow', array()); $request = $this->getRequest(); $user = null; if ($request) { $user = $request->getUser(); } if ($user) { $default_img_uri = PhabricatorEnv::getCDNURI( '/rsrc/image/icon/fatcow/document_black.png'); $download_form = phabricator_form( $user, array( 'action' => '#', 'method' => 'POST', 'class' => 'lightbox-download-form', 'sigil' => 'download', ), phutil_tag( 'button', array(), pht('Download'))); Javelin::initBehavior( 'lightbox-attachments', array( 'defaultImageUri' => $default_img_uri, 'downloadForm' => $download_form, )); } Javelin::initBehavior('aphront-form-disable-on-submit'); Javelin::initBehavior('toggle-class', array()); Javelin::initBehavior('konami', array()); Javelin::initBehavior('history-install'); Javelin::initBehavior('phabricator-gesture'); $current_token = null; if ($user) { $current_token = $user->getCSRFToken(); } Javelin::initBehavior( 'refresh-csrf', array( 'tokenName' => AphrontRequest::getCSRFTokenName(), 'header' => AphrontRequest::getCSRFHeaderName(), 'current' => $current_token, )); Javelin::initBehavior('device'); if ($console) { require_celerity_resource('aphront-dark-console-css'); $headers = array(); if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) { $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page'; } Javelin::initBehavior( 'dark-console', array( // NOTE: We use a generic label here to prevent input reflection // and mitigate compression attacks like BREACH. See discussion in // T3684. 'uri' => pht('Main Request'), 'selected' => $user ? $user->getConsoleTab() : null, 'visible' => $user ? (int)$user->getConsoleVisible() : true, 'headers' => $headers, )); // Change this to initBehavior when there is some behavior to initialize require_celerity_resource('javelin-behavior-error-log'); } if ($user) { $viewer = $user; } else { $viewer = new PhabricatorUser(); } $menu = id(new PhabricatorMainMenuView()) ->setUser($viewer) ->setDefaultSearchScope($this->getSearchDefaultScope()); if ($this->getController()) { $menu->setController($this->getController()); } if ($this->getApplicationMenu()) { $menu->setApplicationMenu($this->getApplicationMenu()); } $this->menuContent = $menu->render(); } protected function getHead() { $monospaced = PhabricatorEnv::getEnvConfig('style.monospace'); $monospaced_win = PhabricatorEnv::getEnvConfig('style.monospace.windows'); $request = $this->getRequest(); if ($request) { $user = $request->getUser(); if ($user) { $pref = $user->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_MONOSPACED); $monospaced = nonempty($pref, $monospaced); $monospaced_win = nonempty($pref, $monospaced_win); } } $response = CelerityAPI::getStaticResourceResponse(); return hsprintf( '%s%s', parent::getHead(), phutil_safe_html($monospaced), phutil_safe_html($monospaced_win), $response->renderSingleResource('javelin-magical-init')); } public function setGlyph($glyph) { $this->glyph = $glyph; return $this; } public function getGlyph() { return $this->glyph; } protected function willSendResponse($response) { $request = $this->getRequest(); $response = parent::willSendResponse($response); $console = $request->getApplicationConfiguration()->getConsole(); if ($console) { $response = PhutilSafeHTML::applyFunction( 'str_replace', hsprintf(''), $console->render($request), $response); } return $response; } protected function getBody() { $console = $this->getConsole(); $user = null; $request = $this->getRequest(); if ($request) { $user = $request->getUser(); } $header_chrome = null; if ($this->getShowChrome()) { $header_chrome = $this->menuContent; } $developer_warning = null; if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode') && DarkConsoleErrorLogPluginAPI::getErrors()) { - $developer_warning = phutil_tag( - 'div', - array( - 'class' => 'aphront-developer-error-callout', - ), + $developer_warning = phutil_tag_div( + 'aphront-developer-error-callout', pht( 'This page raised PHP errors. Find them in DarkConsole '. 'or the error log.')); } // Render the "you have unresolved setup issues..." warning. $setup_warning = null; if ($user && $user->getIsAdmin()) { $open = PhabricatorSetupCheck::getOpenSetupIssueCount(); if ($open) { - $setup_warning = phutil_tag( - 'div', - array( - 'class' => 'setup-warning-callout', - ), + $setup_warning = phutil_tag_div( + 'setup-warning-callout', phutil_tag( 'a', array( 'href' => '/config/issue/', ), pht('You have %d unresolved setup issue(s)...', $open))); } } return phutil_tag( 'div', array( 'id' => 'base-page', 'class' => 'phabricator-standard-page', ), - hsprintf( - '%s%s%s'. - '
'. - '%s%s
'. - '
', - $developer_warning, - $setup_warning, - $header_chrome, - ($console ? hsprintf('') : null), - parent::getBody())); + array( + $developer_warning, + $setup_warning, + $header_chrome, + phutil_tag_div('phabricator-standard-page-body', array( + ($console ? hsprintf('') : null), + parent::getBody(), + phutil_tag('div', array('style' => 'clear: both;')), + )), + )); } protected function getTail() { $request = $this->getRequest(); $user = $request->getUser(); $container = null; if ($user && $user->isLoggedIn()) { $aphlict_object_id = celerity_generate_unique_node_id(); $aphlict_container_id = celerity_generate_unique_node_id(); $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri'); $client_uri = new PhutilURI($client_uri); if ($client_uri->getDomain() == 'localhost') { $this_host = $this->getRequest()->getHost(); $this_host = new PhutilURI('http://'.$this_host.'/'); $client_uri->setDomain($this_host->getDomain()); } $enable_debug = PhabricatorEnv::getEnvConfig('notification.debug'); Javelin::initBehavior( 'aphlict-listen', array( 'id' => $aphlict_object_id, 'containerID' => $aphlict_container_id, 'server' => $client_uri->getDomain(), 'port' => $client_uri->getPort(), 'debug' => $enable_debug, 'pageObjects' => array_fill_keys($this->pageObjects, true), )); $container = phutil_tag( 'div', array( 'id' => $aphlict_container_id, 'style' => 'position: absolute; width: 0; height: 0; overflow: hidden;', ), ''); } $response = CelerityAPI::getStaticResourceResponse(); $tail = array( parent::getTail(), $container, $response->renderHTMLFooter(), ); return phutil_implode_html("\n", $tail); } protected function getBodyClasses() { $classes = array(); if (!$this->getShowChrome()) { $classes[] = 'phabricator-chromeless-page'; } $agent = AphrontRequest::getHTTPHeader('User-Agent'); // Try to guess the device resolution based on UA strings to avoid a flash // of incorrectly-styled content. $device_guess = 'device-desktop'; if (preg_match('@iPhone|iPod|(Android.*Chrome/[.0-9]* Mobile)@', $agent)) { $device_guess = 'device-phone device'; } else if (preg_match('@iPad|(Android.*Chrome/)@', $agent)) { $device_guess = 'device-tablet device'; } $classes[] = $device_guess; if (preg_match('@Windows@', $agent)) { $classes[] = 'platform-windows'; } else if (preg_match('@Macintosh@', $agent)) { $classes[] = 'platform-mac'; } else if (preg_match('@X11@', $agent)) { $classes[] = 'platform-linux'; } if ($this->getRequest()->getStr('__print__')) { $classes[] = 'printable'; } return implode(' ', $classes); } private function getConsole() { if ($this->disableConsole) { return null; } return $this->getRequest()->getApplicationConfiguration()->getConsole(); } } diff --git a/src/view/page/menu/PhabricatorMainMenuSearchView.php b/src/view/page/menu/PhabricatorMainMenuSearchView.php index 1f416a1f94..4d2cd11045 100644 --- a/src/view/page/menu/PhabricatorMainMenuSearchView.php +++ b/src/view/page/menu/PhabricatorMainMenuSearchView.php @@ -1,80 +1,79 @@ scope = $scope; return $this; } public function getID() { if (!$this->id) { $this->id = celerity_generate_unique_node_id(); } return $this->id; } public function render() { $user = $this->user; $target_id = celerity_generate_unique_node_id(); $search_id = $this->getID(); $input = phutil_tag( 'input', array( 'type' => 'text', 'name' => 'query', 'id' => $search_id, 'autocomplete' => 'off', )); $scope = $this->scope; $target = javelin_tag( 'div', array( 'id' => $target_id, 'class' => 'phabricator-main-menu-search-target', ), ''); Javelin::initBehavior( 'phabricator-search-typeahead', array( 'id' => $target_id, 'input' => $search_id, 'src' => '/typeahead/common/mainsearch/', 'limit' => 10, 'placeholder' => PhabricatorSearchScope::getScopePlaceholder($scope), )); $scope_input = phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'scope', 'value' => $scope, )); $form = phabricator_form( $user, array( 'action' => '/search/', 'method' => 'POST', ), - hsprintf( - '
'. - '%s%s%s'. - '
', + phutil_tag_div('phabricator-main-menu-search-container', array( $input, + phutil_tag('button', array(), pht('Search')), $scope_input, - $target)); + $target, + ))); return $form; } } diff --git a/src/view/widget/bars/AphrontProgressBarView.php b/src/view/widget/bars/AphrontProgressBarView.php index 4584c08c8f..ef63cd0ccd 100644 --- a/src/view/widget/bars/AphrontProgressBarView.php +++ b/src/view/widget/bars/AphrontProgressBarView.php @@ -1,60 +1,57 @@ value = $value; return $this; } public function setMax($max) { $this->max = $max; return $this; } public function setAlt($text) { $this->alt = $text; return $this; } protected function getRatio() { return min($this->value, $this->max) / $this->max; } public function render() { require_celerity_resource('aphront-bars'); $ratio = $this->getRatio(); $width = self::WIDTH * $ratio; $color = $this->getColor(); - return phutil_tag( - 'div', - array( - 'class' => "aphront-bar progress color-{$color}", - ), + return phutil_tag_div( + "aphront-bar progress color-{$color}", array( phutil_tag( 'div', array('title' => $this->alt), phutil_tag( 'div', - array('style' => hsprintf("width: %dpx;", $width)), + array('style' => "width: {$width}px;"), '')), phutil_tag( 'span', array(), $this->getCaption()))); } } diff --git a/src/view/widget/hovercard/PhabricatorHovercardView.php b/src/view/widget/hovercard/PhabricatorHovercardView.php index 7b68046bb1..1db3af0a4b 100644 --- a/src/view/widget/hovercard/PhabricatorHovercardView.php +++ b/src/view/widget/hovercard/PhabricatorHovercardView.php @@ -1,186 +1,161 @@ handle = $handle; return $this; } public function setTitle($title) { $this->title = $title; return $this; } public function setDetail($detail) { $this->detail = $detail; return $this; } public function addField($label, $value) { $this->fields[] = array( 'label' => $label, 'value' => $value, ); return $this; } public function addAction($label, $uri, $workflow = false) { $this->actions[] = array( 'label' => $label, 'uri' => $uri, 'workflow' => $workflow, ); return $this; } public function addTag(PhabricatorTagView $tag) { $this->tags[] = $tag; return $this; } public function setColor($color) { $this->color = $color; return $this; } public function render() { if (!$this->handle) { throw new Exception("Call setObjectHandle() before calling render()!"); } $handle = $this->handle; require_celerity_resource("phabricator-hovercard-view-css"); $title = pht("%s: %s", $handle->getTypeName(), $this->title ? $this->title : $handle->getName()); $header = new PhabricatorActionHeaderView(); $header->setHeaderColor($this->color); $header->setHeaderTitle($title); if ($this->tags) { foreach ($this->tags as $tag) { $header->setTag($tag); } } $body = array(); if ($this->detail) { $body_title = $this->detail; } else { // Fallback for object handles $body_title = $handle->getFullName(); } - $body[] = phutil_tag( - 'div', - array( - 'class' => 'phabricator-hovercard-body-header' - ), - $body_title); + $body[] = phutil_tag_div('phabricator-hovercard-body-header', $body_title); foreach ($this->fields as $field) { - $item = hsprintf('%s: %s', - $field['label'], $field['value']); - $body[] = phutil_tag( - 'div', - array( - 'class' => 'phabricator-hovercard-body-item' - ), - $item); + $item = array( + phutil_tag('strong', array(), $field['label']), + ' ', + phutil_tag('span', array(), $field['value']), + ); + $body[] = phutil_tag_div('phabricator-hovercard-body-item', $item); } if ($handle->getImageURI()) { // Probably a user, we don't need to assume something else // "Prepend" the image by appending $body $body = phutil_tag( 'div', array( 'class' => 'profile-header-picture-frame', 'style' => 'background-image: url('.$handle->getImageURI().');', ), '') ->appendHTML($body); } $buttons = array(); foreach ($this->actions as $action) { $options = array( 'class' => 'button grey', 'href' => $action['uri'], ); if ($action['workflow']) { $options['sigil'] = 'workflow'; $buttons[] = javelin_tag( 'a', $options, $action['label']); } else { $buttons[] = phutil_tag( 'a', $options, $action['label']); } } $tail = null; if ($buttons) { - $tail = phutil_tag('div', - array('class' => 'phabricator-hovercard-tail'), - $buttons); + $tail = phutil_tag_div('phabricator-hovercard-tail', $buttons); } // Assemble container // TODO: Add color support - $content = hsprintf( - '%s%s%s', - phutil_tag('div', - array( - 'class' => 'phabricator-hovercard-head' - ), - $header), - phutil_tag('div', - array( - 'class' => 'phabricator-hovercard-body' - ), - $body), - $tail); - - $hovercard = phutil_tag("div", + $hovercard = phutil_tag_div( + 'phabricator-hovercard-container', array( - "class" => "phabricator-hovercard-container", - ), - $content); + phutil_tag_div('phabricator-hovercard-head', $header), + phutil_tag_div('phabricator-hovercard-body', $body), + $tail, + )); // Wrap for thick border // and later the tip at the bottom - return phutil_tag('div', - array( - 'class' => 'phabricator-hovercard-wrapper', - ), - $hovercard); + return phutil_tag_div('phabricator-hovercard-wrapper', $hovercard); } }