@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Reduce Pholio brokenness for non-image files

Summary:
Ref T5359. When users upload non-image file types (PDFs, text files, whatever), Pholio currently chokes in a few places. Make most of these behaviors more reasonable:

- Provide thumbs in the required sizes.
- Predict the thumb size of these files correctly.
- Disable inline comments.
- Make "View Fullsize" and "Download" into buttons. These mostly-work. Download should probaly really download, but CSRF on forms is a bit of a pain right now.

Test Plan: See screenshots.

Reviewers: chad

Reviewed By: chad

Subscribers: epriestley

Maniphest Tasks: T5359

Differential Revision: https://secure.phabricator.com/D9548

+147 -56
+34 -26
resources/celerity/map.php
··· 80 80 'rsrc/css/application/people/people-profile.css' => 'ba7b2762', 81 81 'rsrc/css/application/phame/phame.css' => '19ecc703', 82 82 'rsrc/css/application/pholio/pholio-edit.css' => 'b9e59b6d', 83 - 'rsrc/css/application/pholio/pholio-inline-comments.css' => '609c3320', 84 - 'rsrc/css/application/pholio/pholio.css' => '72af321e', 83 + 'rsrc/css/application/pholio/pholio-inline-comments.css' => '3d5a5590', 84 + 'rsrc/css/application/pholio/pholio.css' => '344c1440', 85 85 'rsrc/css/application/phortune/phortune-credit-card-form.css' => 'b25b4beb', 86 86 'rsrc/css/application/phrequent/phrequent.css' => 'ffc185ad', 87 87 'rsrc/css/application/phriction/phriction-document-css.css' => '7d7f0071', ··· 261 261 'rsrc/image/icon/fatcow/source/mobile.png' => 'f1321264', 262 262 'rsrc/image/icon/fatcow/source/tablet.png' => '49396799', 263 263 'rsrc/image/icon/fatcow/source/web.png' => '136ccb5d', 264 + 'rsrc/image/icon/fatcow/thumbnails/default.p100.png' => '7d490b01', 264 265 'rsrc/image/icon/fatcow/thumbnails/default160x120.png' => 'f2e8a2eb', 266 + 'rsrc/image/icon/fatcow/thumbnails/default280x210.png' => '43e8926a', 265 267 'rsrc/image/icon/fatcow/thumbnails/default60x45.png' => '0118abed', 268 + 'rsrc/image/icon/fatcow/thumbnails/image.p100.png' => 'da23cf97', 266 269 'rsrc/image/icon/fatcow/thumbnails/image160x120.png' => '79bb556a', 270 + 'rsrc/image/icon/fatcow/thumbnails/image280x210.png' => '91ae054a', 267 271 'rsrc/image/icon/fatcow/thumbnails/image60x45.png' => 'c5e1685e', 272 + 'rsrc/image/icon/fatcow/thumbnails/pdf.p100.png' => '87d5e065', 268 273 'rsrc/image/icon/fatcow/thumbnails/pdf160x120.png' => 'ac9edbf5', 274 + 'rsrc/image/icon/fatcow/thumbnails/pdf280x210.png' => '1c585653', 269 275 'rsrc/image/icon/fatcow/thumbnails/pdf60x45.png' => 'c0db4143', 276 + 'rsrc/image/icon/fatcow/thumbnails/zip.p100.png' => '6ea5aae4', 270 277 'rsrc/image/icon/fatcow/thumbnails/zip160x120.png' => '75f9cd0f', 278 + 'rsrc/image/icon/fatcow/thumbnails/zip280x210.png' => 'dfda5b8e', 271 279 'rsrc/image/icon/fatcow/thumbnails/zip60x45.png' => 'af11bf3e', 272 280 'rsrc/image/icon/lightbox/close-2.png' => 'cc40e7c8', 273 281 'rsrc/image/icon/lightbox/close-hover-2.png' => 'fb5d6d9e', ··· 390 398 'rsrc/js/application/passphrase/phame-credential-control.js' => '1e1c8a59', 391 399 'rsrc/js/application/phame/phame-post-preview.js' => '61d927ec', 392 400 'rsrc/js/application/pholio/behavior-pholio-mock-edit.js' => '1e1e8bb0', 393 - 'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => '09c4fe2d', 401 + 'rsrc/js/application/pholio/behavior-pholio-mock-view.js' => 'd7f9b108', 394 402 'rsrc/js/application/phortune/behavior-balanced-payment-form.js' => '3b3e1664', 395 403 'rsrc/js/application/phortune/behavior-stripe-payment-form.js' => '1693a296', 396 404 'rsrc/js/application/phortune/behavior-test-payment-form.js' => 'b3e5ee60', ··· 614 622 'javelin-behavior-phabricator-watch-anchor' => '06e05112', 615 623 'javelin-behavior-phame-post-preview' => '61d927ec', 616 624 'javelin-behavior-pholio-mock-edit' => '1e1e8bb0', 617 - 'javelin-behavior-pholio-mock-view' => '09c4fe2d', 625 + 'javelin-behavior-pholio-mock-view' => 'd7f9b108', 618 626 'javelin-behavior-phui-object-box-tabs' => 'a3e2244e', 619 627 'javelin-behavior-phui-timeline-dropdown-menu' => '4d94d9c3', 620 628 'javelin-behavior-policy-control' => 'f3fef818', ··· 740 748 'phabricator-uiexample-reactor-sendproperties' => '551add57', 741 749 'phabricator-zindex-css' => 'efb673ac', 742 750 'phame-css' => '19ecc703', 743 - 'pholio-css' => '72af321e', 751 + 'pholio-css' => '344c1440', 744 752 'pholio-edit-css' => 'b9e59b6d', 745 - 'pholio-inline-comments-css' => '609c3320', 753 + 'pholio-inline-comments-css' => '3d5a5590', 746 754 'phortune-credit-card-form' => '2290aeef', 747 755 'phortune-credit-card-form-css' => 'b25b4beb', 748 756 'phrequent-css' => 'ffc185ad', ··· 875 883 7 => 'javelin-uri', 876 884 8 => 'javelin-routable', 877 885 ), 878 - '09c4fe2d' => 879 - array( 880 - 0 => 'javelin-behavior', 881 - 1 => 'javelin-util', 882 - 2 => 'javelin-stratcom', 883 - 3 => 'javelin-dom', 884 - 4 => 'javelin-vector', 885 - 5 => 'javelin-magical-init', 886 - 6 => 'javelin-request', 887 - 7 => 'javelin-history', 888 - 8 => 'javelin-workflow', 889 - 9 => 'javelin-mask', 890 - 10 => 'javelin-behavior-device', 891 - 11 => 'phabricator-keyboard-shortcut', 892 - ), 893 886 '0a3f3021' => 894 887 array( 895 888 0 => 'javelin-behavior', ··· 1270 1263 2 => 'javelin-util', 1271 1264 3 => 'phabricator-shaped-request', 1272 1265 ), 1266 + '7319e029' => 1267 + array( 1268 + 0 => 'javelin-behavior', 1269 + 1 => 'javelin-dom', 1270 + ), 1273 1271 '62e18640' => 1274 1272 array( 1275 1273 0 => 'javelin-install', ··· 1341 1339 0 => 'javelin-behavior', 1342 1340 1 => 'javelin-stratcom', 1343 1341 2 => 'javelin-dom', 1344 - ), 1345 - '7319e029' => 1346 - array( 1347 - 0 => 'javelin-behavior', 1348 - 1 => 'javelin-dom', 1349 1342 ), 1350 1343 '76f4ebed' => 1351 1344 array( ··· 1874 1867 2 => 'javelin-json', 1875 1868 3 => 'javelin-dom', 1876 1869 4 => 'phabricator-keyboard-shortcut', 1870 + ), 1871 + 'd7f9b108' => 1872 + array( 1873 + 0 => 'javelin-behavior', 1874 + 1 => 'javelin-util', 1875 + 2 => 'javelin-stratcom', 1876 + 3 => 'javelin-dom', 1877 + 4 => 'javelin-vector', 1878 + 5 => 'javelin-magical-init', 1879 + 6 => 'javelin-request', 1880 + 7 => 'javelin-history', 1881 + 8 => 'javelin-workflow', 1882 + 9 => 'javelin-mask', 1883 + 10 => 'javelin-behavior-device', 1884 + 11 => 'phabricator-keyboard-shortcut', 1877 1885 ), 1878 1886 'd83a949c' => 1879 1887 array(
+7 -4
src/applications/files/controller/PhabricatorFileTransformController.php
··· 68 68 case 'preview-100': 69 69 $xformed_file = $this->executePreviewTransform($file, 100); 70 70 break; 71 - case 'preview-140': 72 - $xformed_file = $this->executePreviewTransform($file, 140); 73 - break; 74 71 case 'preview-220': 75 72 $xformed_file = $this->executePreviewTransform($file, 220); 76 73 break; ··· 115 112 } 116 113 117 114 switch ($this->transform) { 115 + case 'thumb-280x210': 116 + $suffix = '280x210'; 117 + break; 118 118 case 'thumb-160x120': 119 119 $suffix = '160x120'; 120 120 break; 121 121 case 'thumb-60x45': 122 122 $suffix = '60x45'; 123 123 break; 124 + case 'preview-100': 125 + $suffix = '.p100'; 126 + break; 124 127 default: 125 128 throw new Exception('Unsupported transformation type!'); 126 129 } 127 130 128 131 $path = celerity_get_resource_uri( 129 - "/rsrc/image/icon/fatcow/thumbnails/{$prefix}{$suffix}.png"); 132 + "rsrc/image/icon/fatcow/thumbnails/{$prefix}{$suffix}.png"); 130 133 131 134 return id(new AphrontRedirectResponse()) 132 135 ->setURI($path);
-6
src/applications/files/storage/PhabricatorFile.php
··· 544 544 return PhabricatorEnv::getCDNURI($path); 545 545 } 546 546 547 - public function getPreview140URI() { 548 - $path = '/file/xform/preview-140/'.$this->getPHID().'/' 549 - .$this->getSecretKey().'/'; 550 - return PhabricatorEnv::getCDNURI($path); 551 - } 552 - 553 547 public function getPreview220URI() { 554 548 $path = '/file/xform/preview-220/'.$this->getPHID().'/' 555 549 .$this->getSecretKey().'/';
+13
src/applications/pholio/view/PholioMockImagesView.php
··· 62 62 $selected_id = head_key($ids); 63 63 } 64 64 65 + // TODO: We could maybe do a better job with tailoring this, which is the 66 + // image shown on the review stage. 67 + $nonimage_uri = celerity_get_resource_uri( 68 + 'rsrc/image/icon/fatcow/thumbnails/default.p100.png'); 69 + 65 70 foreach ($mock->getAllImages() as $image) { 66 71 $file = $image->getFile(); 67 72 $metadata = $file->getMetadata(); ··· 72 77 $images[] = array( 73 78 'id' => $image->getID(), 74 79 'fullURI' => $file->getBestURI(), 80 + 'stageURI' => ($file->isViewableImage() 81 + ? $file->getBestURI() 82 + : $nonimage_uri), 75 83 'pageURI' => $this->getImagePageURI($image, $mock), 84 + 'downloadURI' => $file->getInfoURI(), 76 85 'historyURI' => $history_uri, 77 86 'width' => $x, 78 87 'height' => $y, 79 88 'title' => $image->getName(), 80 89 'desc' => $image->getDescription(), 81 90 'isObsolete' => (bool)$image->getIsObsolete(), 91 + 'isImage' => $file->isViewableImage(), 92 + 'isViewable' => $file->isViewableInBrowser(), 82 93 ); 83 94 } 84 95 ··· 99 110 'loggedIn' => $this->getUser()->isLoggedIn(), 100 111 'logInLink' => (string) $login_uri, 101 112 'navsequence' => $navsequence, 113 + 'fullIcon' => id(new PHUIIconView())->setIconFont('fa-arrows-alt'), 114 + 'downloadIcon' => id(new PHUIIconView())->setIconFont('fa-download'), 102 115 ); 103 116 Javelin::initBehavior('pholio-mock-view', $config); 104 117
+12 -3
src/applications/pholio/view/PholioMockThumbGridView.php
··· 101 101 private function renderThumbnail(PholioImage $image) { 102 102 $thumbfile = $image->getFile(); 103 103 104 - $dimensions = PhabricatorImageTransformer::getPreviewDimensions( 105 - $thumbfile, 106 - 100); 104 + if ($image->getFile()->isViewableImage()) { 105 + $dimensions = PhabricatorImageTransformer::getPreviewDimensions( 106 + $thumbfile, 107 + 100); 108 + } else { 109 + // If this is a PDF or a text file or something, we'll end up using a 110 + // generic thumbnail which is always sized correctly. 111 + $dimensions = array( 112 + 'sdx' => 100, 113 + 'sdy' => 100, 114 + ); 115 + } 107 116 108 117 $tag = phutil_tag( 109 118 'img',
+4 -7
src/infrastructure/celerity/api.php
··· 50 50 * @group celerity 51 51 */ 52 52 function celerity_get_resource_uri($resource, $source = 'phabricator') { 53 - $map = CelerityResourceMap::getNamedInstance($source); 53 + $resource = ltrim($resource, '/'); 54 54 55 - $uri = $map->getURIForName($resource); 56 - if ($uri) { 57 - return $uri; 58 - } 59 - 60 - return $resource; 55 + $map = CelerityResourceMap::getNamedInstance($source); 56 + $response = CelerityAPI::getStaticResourceResponse(); 57 + return $response->getURI($map, $resource); 61 58 }
+1
webroot/rsrc/css/application/pholio/pholio-inline-comments.css
··· 11 11 background: #fff; 12 12 border-top: 1px solid {$thinblueborder}; 13 13 text-align: left; 14 + overflow: hidden; 14 15 } 15 16 16 17 .pholio-mock-inline-comments a {
+33
webroot/rsrc/css/application/pholio/pholio.css
··· 167 167 text-decoration: none; 168 168 background: {$indigo}; 169 169 } 170 + 171 + .pholio-image-button { 172 + float: right; 173 + margin-left: 2px; 174 + } 175 + 176 + .pholio-image-button-link { 177 + width: 56px; 178 + height: 56px; 179 + overflow: hidden; 180 + display: block; 181 + position: relative; 182 + background: {$lightgreybackground}; 183 + text-align: center; 184 + line-height: 56px; 185 + font-size: 24px; 186 + } 187 + 188 + a.pholio-image-button-link:hover { 189 + background: {$darkgreybackground}; 190 + } 191 + 192 + span.pholio-image-button-link .phui-icon-view { 193 + color: {$darkgreybackground}; 194 + } 195 + 196 + a.pholio-image-button-link .phui-icon-view { 197 + color: {$lightgreytext}; 198 + } 199 + 200 + .device-desktop a.pholio-image-button-link:hover .phui-icon-view { 201 + color: {$sky}; 202 + }
webroot/rsrc/image/icon/fatcow/thumbnails/default.p100.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/default280x210.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/image.p100.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/image280x210.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/pdf.p100.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/pdf280x210.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/zip.p100.png

This is a binary file and will not be displayed.

webroot/rsrc/image/icon/fatcow/thumbnails/zip280x210.png

This is a binary file and will not be displayed.

+43 -10
webroot/rsrc/js/application/pholio/behavior-pholio-mock-view.js
··· 206 206 207 207 var img = JX.$N('img', {className: 'pholio-mock-image'}); 208 208 img.onload = JX.bind(img, onload_image, active_image.id); 209 - img.src = active_image.fullURI; 209 + img.src = active_image.stageURI; 210 210 211 211 var thumbs = JX.DOM.scry( 212 212 JX.$('pholio-mock-thumb-grid'), ··· 259 259 } 260 260 261 261 e.kill(); 262 + 263 + if (!active_image.isImage) { 264 + // If this is a PDF or something like that, we eat the event but we 265 + // don't let users add inlines to the thumbnail. 266 + return; 267 + } 262 268 263 269 is_dragging = true; 264 270 drag_begin = get_image_xy(JX.$V(e)); ··· 583 589 function render_image_info(image) { 584 590 var info = []; 585 591 592 + var buttons = []; 593 + 594 + buttons.push( 595 + JX.$N( 596 + 'div', 597 + { 598 + className: 'pholio-image-button' 599 + }, 600 + JX.$N( 601 + image.isViewable ? 'a' : 'span', 602 + { 603 + href: image.fullURI, 604 + target: '_blank', 605 + className: 'pholio-image-button-link' 606 + }, 607 + JX.$H(config.fullIcon)))); 608 + 609 + // TODO: This should be a form which performs the download; for now, it 610 + // just takes the user to the info page. 611 + buttons.push( 612 + JX.$N( 613 + 'div', 614 + { 615 + className: 'pholio-image-button' 616 + }, 617 + JX.$N( 618 + 'a', 619 + { 620 + href: image.downloadURI, 621 + className: 'pholio-image-button-link' 622 + }, 623 + JX.$H(config.downloadIcon)))); 624 + 586 625 var title = JX.$N( 587 626 'div', 588 627 {className: 'pholio-image-title'}, ··· 604 643 info.push(embed); 605 644 } 606 645 607 - var full_link = JX.$N( 608 - 'a', 609 - {href: image.fullURI, target: '_blank'}, 610 - 'View Full Image'); 611 - info.push(full_link); 612 - 613 646 for (var ii = 0; ii < info.length; ii++) { 614 647 info[ii] = JX.$N('div', {className: 'pholio-image-info-item'}, info[ii]); 615 648 } 616 649 info = JX.$N('div', {className: 'pholio-image-info'}, info); 617 650 618 - return info; 651 + return [buttons, info]; 619 652 } 620 653 621 654 function render_reticle(classes) { ··· 654 687 var image = JX.$N('img'); 655 688 image.onload = lightbox_loaded; 656 689 setTimeout(function() { 657 - image.src = active_image.fullURI; 690 + image.src = active_image.stageURI; 658 691 }, 1000); 659 692 JX.DOM.setContent(lightbox, image); 660 693 JX.DOM.alterClass(lightbox, 'pholio-device-lightbox-loading', true); ··· 694 727 695 728 var preload = []; 696 729 for (var ii = 0; ii < config.images.length; ii++) { 697 - preload.push(config.images[ii].fullURI); 730 + preload.push(config.images[ii].stageURI); 698 731 } 699 732 700 733 function preload_next() {