Page MenuHomePhabricator

D19252.id46094.diff
No OneTemporary

D19252.id46094.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -9,7 +9,7 @@
'names' => array(
'conpherence.pkg.css' => 'e68cf1fa',
'conpherence.pkg.js' => '15191c65',
- 'core.pkg.css' => 'afe29a6c',
+ 'core.pkg.css' => '2d73b2f3',
'core.pkg.js' => 'b9b4a943',
'differential.pkg.css' => '113e692c',
'differential.pkg.js' => 'f6d809c0',
@@ -112,7 +112,7 @@
'rsrc/css/application/tokens/tokens.css' => '3d0f239e',
'rsrc/css/application/uiexample/example.css' => '528b19de',
'rsrc/css/core/core.css' => '62fa3ace',
- 'rsrc/css/core/remarkup.css' => '97dc3523',
+ 'rsrc/css/core/remarkup.css' => 'b375546d',
'rsrc/css/core/syntax.css' => 'cae95e89',
'rsrc/css/core/z-index.css' => '9d8f7c4b',
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
@@ -168,7 +168,7 @@
'rsrc/css/phui/phui-object-box.css' => '9cff003c',
'rsrc/css/phui/phui-pager.css' => 'edcbc226',
'rsrc/css/phui/phui-pinboard-view.css' => '2495140e',
- 'rsrc/css/phui/phui-property-list-view.css' => '94a14381',
+ 'rsrc/css/phui/phui-property-list-view.css' => '47018d3c',
'rsrc/css/phui/phui-remarkup-preview.css' => '54a34863',
'rsrc/css/phui/phui-segment-bar-view.css' => 'b1d1b892',
'rsrc/css/phui/phui-spacing.css' => '042804d6',
@@ -780,7 +780,7 @@
'phabricator-object-selector-css' => '85ee8ce6',
'phabricator-phtize' => 'd254d646',
'phabricator-prefab' => '77b0ae28',
- 'phabricator-remarkup-css' => '97dc3523',
+ 'phabricator-remarkup-css' => 'b375546d',
'phabricator-search-results-css' => '505dd8cf',
'phabricator-shaped-request' => '7cbe244b',
'phabricator-slowvote-css' => 'a94b7230',
@@ -850,7 +850,7 @@
'phui-oi-simple-ui-css' => 'a8beebea',
'phui-pager-css' => 'edcbc226',
'phui-pinboard-view-css' => '2495140e',
- 'phui-property-list-view-css' => '94a14381',
+ 'phui-property-list-view-css' => '47018d3c',
'phui-remarkup-preview-css' => '54a34863',
'phui-segment-bar-view-css' => 'b1d1b892',
'phui-spacing-css' => '042804d6',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3519,6 +3519,7 @@
'PhabricatorOwnersPathsSearchEngineAttachment' => 'applications/owners/engineextension/PhabricatorOwnersPathsSearchEngineAttachment.php',
'PhabricatorOwnersSchemaSpec' => 'applications/owners/storage/PhabricatorOwnersSchemaSpec.php',
'PhabricatorOwnersSearchField' => 'applications/owners/searchfield/PhabricatorOwnersSearchField.php',
+ 'PhabricatorPDFDocumentEngine' => 'applications/files/document/PhabricatorPDFDocumentEngine.php',
'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php',
'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php',
'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php',
@@ -9169,6 +9170,7 @@
'PhabricatorOwnersPathsSearchEngineAttachment' => 'PhabricatorSearchEngineAttachment',
'PhabricatorOwnersSchemaSpec' => 'PhabricatorConfigSchemaSpec',
'PhabricatorOwnersSearchField' => 'PhabricatorSearchTokenizerField',
+ 'PhabricatorPDFDocumentEngine' => 'PhabricatorDocumentEngine',
'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorPHID' => 'Phobject',
'PhabricatorPHIDConstants' => 'Phobject',
diff --git a/src/aphront/response/AphrontResponse.php b/src/aphront/response/AphrontResponse.php
--- a/src/aphront/response/AphrontResponse.php
+++ b/src/aphront/response/AphrontResponse.php
@@ -28,6 +28,7 @@
'connect-src' => array(),
'frame-src' => array(),
'form-action' => array(),
+ 'object-src' => array(),
);
}
@@ -163,8 +164,10 @@
$csp[] = "frame-ancestors 'none'";
}
- // Block relics of the old world: Flash, Java applets, and so on.
- $csp[] = "object-src 'none'";
+ // Block relics of the old world: Flash, Java applets, and so on. Note
+ // that Chrome prevents the user from viewing PDF documents if they are
+ // served with a policy which excludes the domain they are served from.
+ $csp[] = $this->newContentSecurityPolicy('object-src', "'none'");
// Don't allow forms to submit offsite.
diff --git a/src/applications/files/config/PhabricatorFilesConfigOptions.php b/src/applications/files/config/PhabricatorFilesConfigOptions.php
--- a/src/applications/files/config/PhabricatorFilesConfigOptions.php
+++ b/src/applications/files/config/PhabricatorFilesConfigOptions.php
@@ -45,6 +45,8 @@
'video/ogg' => 'video/ogg',
'video/webm' => 'video/webm',
'video/quicktime' => 'video/quicktime',
+
+ 'application/pdf' => 'application/pdf',
);
$image_default = array(
diff --git a/src/applications/files/controller/PhabricatorFileDataController.php b/src/applications/files/controller/PhabricatorFileDataController.php
--- a/src/applications/files/controller/PhabricatorFileDataController.php
+++ b/src/applications/files/controller/PhabricatorFileDataController.php
@@ -73,11 +73,14 @@
list($begin, $end) = $response->parseHTTPRange($range);
}
- $is_viewable = $file->isViewableInBrowser();
+ if (!$file->isViewableInBrowser()) {
+ $is_download = true;
+ }
+
$request_type = $request->getHTTPHeader('X-Phabricator-Request-Type');
$is_lfs = ($request_type == 'git-lfs');
- if ($is_viewable && !$is_download) {
+ if (!$is_download) {
$response->setMimeType($file->getViewableMimeType());
} else {
$is_post = $request->isHTTPPost();
@@ -109,6 +112,19 @@
$response->setContentLength($file->getByteSize());
$response->setContentIterator($iterator);
+ // In Chrome, we must permit this domain in "object-src" CSP when serving a
+ // PDF or the browser will refuse to render it.
+ if (!$is_download && $file->isPDF()) {
+ $request_uri = id(clone $request->getAbsoluteRequestURI())
+ ->setPath(null)
+ ->setFragment(null)
+ ->setQueryParams(array());
+
+ $response->addContentSecurityPolicyURI(
+ 'object-src',
+ (string)$request_uri);
+ }
+
return $response;
}
diff --git a/src/applications/files/document/PhabricatorPDFDocumentEngine.php b/src/applications/files/document/PhabricatorPDFDocumentEngine.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/document/PhabricatorPDFDocumentEngine.php
@@ -0,0 +1,57 @@
+<?php
+
+final class PhabricatorPDFDocumentEngine
+ extends PhabricatorDocumentEngine {
+
+ const ENGINEKEY = 'pdf';
+
+ public function getViewAsLabel(PhabricatorDocumentRef $ref) {
+ return pht('View as PDF');
+ }
+
+ protected function getDocumentIconIcon(PhabricatorDocumentRef $ref) {
+ return 'fa-file-pdf-o';
+ }
+
+ protected function canRenderDocumentType(PhabricatorDocumentRef $ref) {
+ // Since we just render a link to the document anyway, we don't need to
+ // check anything fancy in config to see if the MIME type is actually
+ // viewable.
+
+ return $ref->hasAnyMimeType(
+ array(
+ 'application/pdf',
+ ));
+ }
+
+ protected function newDocumentContent(PhabricatorDocumentRef $ref) {
+ $viewer = $this->getViewer();
+
+ $file = $ref->getFile();
+ if ($file) {
+ $source_uri = $file->getViewURI();
+ } else {
+ throw new PhutilMethodNotImplementedException();
+ }
+
+ $name = $ref->getName();
+ $length = $ref->getByteLength();
+
+ $link = id(new PhabricatorFileLinkView())
+ ->setViewer($viewer)
+ ->setFileName($name)
+ ->setFileViewURI($source_uri)
+ ->setFileViewable(true)
+ ->setFileSize(phutil_format_bytes($length));
+
+ $container = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'document-engine-pdf',
+ ),
+ $link);
+
+ return $container;
+ }
+
+}
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -930,6 +930,19 @@
return idx($mime_map, $mime_type);
}
+ public function isPDF() {
+ if (!$this->isViewableInBrowser()) {
+ return false;
+ }
+
+ $mime_map = array(
+ 'application/pdf' => 'application/pdf',
+ );
+
+ $mime_type = $this->getMimeType();
+ return idx($mime_map, $mime_type);
+ }
+
public function isTransformableImage() {
// NOTE: The way the 'gd' extension works in PHP is that you can install it
// with support for only some file types, so it might be able to handle
diff --git a/src/view/layout/PhabricatorFileLinkView.php b/src/view/layout/PhabricatorFileLinkView.php
--- a/src/view/layout/PhabricatorFileLinkView.php
+++ b/src/view/layout/PhabricatorFileLinkView.php
@@ -101,26 +101,39 @@
}
protected function getTagName() {
- return 'div';
+ if ($this->getFileDownloadURI()) {
+ return 'div';
+ } else {
+ return 'a';
+ }
}
protected function getTagAttributes() {
- $mustcapture = true;
- $sigil = 'lightboxable';
- $meta = $this->getMeta();
-
$class = 'phabricator-remarkup-embed-layout-link';
if ($this->getCustomClass()) {
$class = $this->getCustomClass();
}
- return array(
- 'href' => $this->getFileViewURI(),
- 'class' => $class,
- 'sigil' => $sigil,
- 'meta' => $meta,
- 'mustcapture' => $mustcapture,
+ $attributes = array(
+ 'href' => $this->getFileViewURI(),
+ 'target' => '_blank',
+ 'rel' => 'noreferrer',
+ 'class' => $class,
);
+
+ if ($this->getFilePHID()) {
+ $mustcapture = true;
+ $sigil = 'lightboxable';
+ $meta = $this->getMeta();
+
+ $attributes += array(
+ 'sigil' => $sigil,
+ 'meta' => $meta,
+ 'mustcapture' => $mustcapture,
+ );
+ }
+
+ return $attributes;
}
protected function getTagContent() {
@@ -131,16 +144,21 @@
->setIcon($this->getFileIcon())
->addClass('phabricator-remarkup-embed-layout-icon');
- $dl_icon = id(new PHUIIconView())
- ->setIcon('fa-download');
+ $download_link = null;
- $download_link = phutil_tag(
- 'a',
- array(
- 'class' => 'phabricator-remarkup-embed-layout-download',
- 'href' => $this->getFileDownloadURI(),
- ),
- pht('Download'));
+ $download_uri = $this->getFileDownloadURI();
+ if ($download_uri) {
+ $dl_icon = id(new PHUIIconView())
+ ->setIcon('fa-download');
+
+ $download_link = phutil_tag(
+ 'a',
+ array(
+ 'class' => 'phabricator-remarkup-embed-layout-download',
+ 'href' => $download_uri,
+ ),
+ pht('Download'));
+ }
$info = phutil_tag(
'span',
diff --git a/webroot/rsrc/css/core/remarkup.css b/webroot/rsrc/css/core/remarkup.css
--- a/webroot/rsrc/css/core/remarkup.css
+++ b/webroot/rsrc/css/core/remarkup.css
@@ -405,8 +405,9 @@
color: {$blacktext};
min-width: 256px;
position: relative;
- /*height: 22px;*/
line-height: 20px;
+ overflow: hidden;
+ min-height: 38px;
}
.phabricator-remarkup-embed-layout-icon {
@@ -426,6 +427,9 @@
.phabricator-remarkup-embed-layout-link:hover {
border-color: {$violet};
cursor: pointer;
+}
+
+.device-desktop .phabricator-remarkup-embed-layout-link:hover {
text-decoration: none;
}
diff --git a/webroot/rsrc/css/phui/phui-property-list-view.css b/webroot/rsrc/css/phui/phui-property-list-view.css
--- a/webroot/rsrc/css/phui/phui-property-list-view.css
+++ b/webroot/rsrc/css/phui/phui-property-list-view.css
@@ -248,3 +248,12 @@
.document-engine-remarkup {
margin: 20px;
}
+
+.document-engine-pdf {
+ margin: 20px;
+ text-align: center;
+}
+
+.document-engine-pdf .phabricator-remarkup-embed-layout-link {
+ text-align: left;
+}

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 26, 8:42 AM (11 h, 35 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6927129
Default Alt Text
D19252.id46094.diff (11 KB)

Event Timeline