Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14415009
D19252.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D19252.id.diff
View Options
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
Details
Attached
Mime Type
text/plain
Expires
Wed, Dec 25, 4:44 PM (7 h, 55 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6927129
Default Alt Text
D19252.id.diff (11 KB)
Attached To
Mode
D19252: Add a PDF document "rendering" engine
Attached
Detach File
Event Timeline
Log In to Comment