@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

Improve wrapping and overflow behavior for curtain panels containing long usernames

Summary:
Ref T13486. When a curtain element like "Author" in Maniphest has a very long username, the wrapping and overflow behavior is poor: the date is obscured.

Adjust curtain elements which contain lists of references to other objects to improve wrapping behavior (put the date on a separate line) and overflow behavior (so we get a "..." when a name overflows).

Test Plan: {F7179376}

Maniphest Tasks: T13486

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

+269 -22
+2
resources/celerity/map.php
··· 146 146 'rsrc/css/phui/phui-comment-form.css' => '68a2d99a', 147 147 'rsrc/css/phui/phui-comment-panel.css' => 'ec4e31c0', 148 148 'rsrc/css/phui/phui-crumbs-view.css' => '614f43cf', 149 + 'rsrc/css/phui/phui-curtain-object-ref-view.css' => 'e3331b60', 149 150 'rsrc/css/phui/phui-curtain-view.css' => '68c5efb6', 150 151 'rsrc/css/phui/phui-document-pro.css' => 'b9613a10', 151 152 'rsrc/css/phui/phui-document-summary.css' => 'b068eed1', ··· 833 834 'phui-comment-form-css' => '68a2d99a', 834 835 'phui-comment-panel-css' => 'ec4e31c0', 835 836 'phui-crumbs-view-css' => '614f43cf', 837 + 'phui-curtain-object-ref-view-css' => 'e3331b60', 836 838 'phui-curtain-view-css' => '68c5efb6', 837 839 'phui-document-summary-view-css' => 'b068eed1', 838 840 'phui-document-view-css' => '52b748a5',
+4
src/__phutil_library_map__.php
··· 1991 1991 'PHUICrumbView' => 'view/phui/PHUICrumbView.php', 1992 1992 'PHUICrumbsView' => 'view/phui/PHUICrumbsView.php', 1993 1993 'PHUICurtainExtension' => 'view/extension/PHUICurtainExtension.php', 1994 + 'PHUICurtainObjectRefListView' => 'view/phui/PHUICurtainObjectRefListView.php', 1995 + 'PHUICurtainObjectRefView' => 'view/phui/PHUICurtainObjectRefView.php', 1994 1996 'PHUICurtainPanelView' => 'view/layout/PHUICurtainPanelView.php', 1995 1997 'PHUICurtainView' => 'view/layout/PHUICurtainView.php', 1996 1998 'PHUIDiffGraphView' => 'infrastructure/diff/view/PHUIDiffGraphView.php', ··· 8189 8191 'PHUICrumbView' => 'AphrontView', 8190 8192 'PHUICrumbsView' => 'AphrontView', 8191 8193 'PHUICurtainExtension' => 'Phobject', 8194 + 'PHUICurtainObjectRefListView' => 'AphrontTagView', 8195 + 'PHUICurtainObjectRefView' => 'AphrontTagView', 8192 8196 'PHUICurtainPanelView' => 'AphrontTagView', 8193 8197 'PHUICurtainView' => 'AphrontTagView', 8194 8198 'PHUIDiffGraphView' => 'Phobject',
+14 -22
src/applications/maniphest/controller/ManiphestTaskDetailController.php
··· 340 340 $author_phid = $task->getAuthorPHID(); 341 341 $handles = $viewer->loadHandles(array($owner_phid, $author_phid)); 342 342 343 + $assigned_refs = id(new PHUICurtainObjectRefListView()) 344 + ->setViewer($viewer) 345 + ->setEmptyMessage(pht('None')); 346 + 343 347 if ($owner_phid) { 344 - $image_uri = $handles[$owner_phid]->getImageURI(); 345 - $image_href = $handles[$owner_phid]->getURI(); 346 - $owner = $viewer->renderHandle($owner_phid)->render(); 347 - $content = phutil_tag('strong', array(), $owner); 348 - $assigned_to = id(new PHUIHeadThingView()) 349 - ->setImage($image_uri) 350 - ->setImageHref($image_href) 351 - ->setContent($content); 352 - } else { 353 - $assigned_to = phutil_tag('em', array(), pht('None')); 348 + $assigned_ref = $assigned_refs->newObjectRefView() 349 + ->setHandle($handles[$owner_phid]); 354 350 } 355 351 356 352 $curtain->newPanel() 357 353 ->setHeaderText(pht('Assigned To')) 358 - ->appendChild($assigned_to); 354 + ->appendChild($assigned_refs); 359 355 360 - $author_uri = $handles[$author_phid]->getImageURI(); 361 - $author_href = $handles[$author_phid]->getURI(); 362 - $author = $viewer->renderHandle($author_phid)->render(); 363 - $content = phutil_tag('strong', array(), $author); 364 - $date = phabricator_date($task->getDateCreated(), $viewer); 365 - $content = pht('%s, %s', $content, $date); 366 - $authored_by = id(new PHUIHeadThingView()) 367 - ->setImage($author_uri) 368 - ->setImageHref($author_href) 369 - ->setContent($content); 356 + $author_refs = id(new PHUICurtainObjectRefListView()) 357 + ->setViewer($viewer); 358 + 359 + $author_ref = $author_refs->newObjectRefView() 360 + ->setHandle($handles[$author_phid]) 361 + ->setEpoch($task->getDateCreated()); 370 362 371 363 $curtain->newPanel() 372 364 ->setHeaderText(pht('Authored By')) 373 - ->appendChild($authored_by); 365 + ->appendChild($author_refs); 374 366 375 367 return $curtain; 376 368 }
+46
src/view/phui/PHUICurtainObjectRefListView.php
··· 1 + <?php 2 + 3 + final class PHUICurtainObjectRefListView 4 + extends AphrontTagView { 5 + 6 + private $refs = array(); 7 + private $emptyMessage; 8 + 9 + protected function getTagAttributes() { 10 + return array( 11 + 'class' => 'phui-curtain-object-ref-list-view', 12 + ); 13 + } 14 + 15 + public function setEmptyMessage($empty_message) { 16 + $this->emptyMessage = $empty_message; 17 + return $this; 18 + } 19 + 20 + protected function getTagContent() { 21 + $refs = $this->refs; 22 + 23 + if (!$refs) { 24 + if ($this->emptyMessage) { 25 + return phutil_tag( 26 + 'div', 27 + array( 28 + 'class' => 'phui-curtain-object-ref-list-view-empty', 29 + ), 30 + $this->emptyMessage); 31 + } 32 + } 33 + 34 + return $refs; 35 + } 36 + 37 + public function newObjectRefView() { 38 + $ref_view = id(new PHUICurtainObjectRefView()) 39 + ->setViewer($this->getViewer()); 40 + 41 + $this->refs[] = $ref_view; 42 + 43 + return $ref_view; 44 + } 45 + 46 + }
+155
src/view/phui/PHUICurtainObjectRefView.php
··· 1 + <?php 2 + 3 + final class PHUICurtainObjectRefView 4 + extends AphrontTagView { 5 + 6 + private $handle; 7 + private $epoch; 8 + 9 + public function setHandle(PhabricatorObjectHandle $handle) { 10 + $this->handle = $handle; 11 + return $this; 12 + } 13 + 14 + public function setEpoch($epoch) { 15 + $this->epoch = $epoch; 16 + return $this; 17 + } 18 + 19 + protected function getTagAttributes() { 20 + return array( 21 + 'class' => 'phui-curtain-object-ref-view', 22 + ); 23 + } 24 + 25 + protected function getTagContent() { 26 + require_celerity_resource('phui-curtain-object-ref-view-css'); 27 + 28 + $viewer = $this->getViewer(); 29 + $handle = $this->handle; 30 + 31 + $more_rows = array(); 32 + 33 + $epoch = $this->epoch; 34 + if ($epoch !== null) { 35 + $epoch_view = phabricator_datetime($epoch, $viewer); 36 + 37 + $epoch_cells = array(); 38 + 39 + $epoch_cells[] = phutil_tag( 40 + 'td', 41 + array( 42 + 'class' => 'phui-curtain-object-ref-view-epoch-cell', 43 + ), 44 + $epoch_view); 45 + 46 + $more_rows[] = phutil_tag('tr', array(), $epoch_cells); 47 + } 48 + 49 + $header_cells = array(); 50 + 51 + $image_view = $this->newImage(); 52 + 53 + if ($more_rows) { 54 + $row_count = 1 + count($more_rows); 55 + } else { 56 + $row_count = null; 57 + } 58 + 59 + $header_cells[] = phutil_tag( 60 + 'td', 61 + array( 62 + 'rowspan' => $row_count, 63 + 'class' => 'phui-curtain-object-ref-view-image-cell', 64 + ), 65 + $image_view); 66 + 67 + $title_view = $this->newTitle(); 68 + 69 + $header_cells[] = phutil_tag( 70 + 'td', 71 + array( 72 + 'class' => 'phui-curtain-object-ref-view-title-cell', 73 + ), 74 + $title_view); 75 + 76 + $rows = array(); 77 + 78 + if (!$more_rows) { 79 + $title_row_class = 'phui-curtain-object-ref-view-without-content'; 80 + } else { 81 + $title_row_class = 'phui-curtain-object-ref-view-with-content'; 82 + } 83 + 84 + $rows[] = phutil_tag( 85 + 'tr', 86 + array( 87 + 'class' => $title_row_class, 88 + ), 89 + $header_cells); 90 + 91 + $body = phutil_tag( 92 + 'tbody', 93 + array(), 94 + array( 95 + $rows, 96 + $more_rows, 97 + )); 98 + 99 + return phutil_tag('table', array(), $body); 100 + } 101 + 102 + private function newTitle() { 103 + $title_view = null; 104 + $handle = $this->handle; 105 + 106 + if ($handle) { 107 + $title_view = $handle->renderLink(); 108 + } 109 + 110 + return $title_view; 111 + } 112 + 113 + private function newImage() { 114 + $image_uri = $this->getImageURI(); 115 + $target_uri = $this->getTargetURI(); 116 + 117 + if ($image_uri !== null) { 118 + $image_view = javelin_tag( 119 + 'a', 120 + array( 121 + 'style' => sprintf('background-image: url(%s)', $image_uri), 122 + 'href' => $target_uri, 123 + 'aural' => false, 124 + )); 125 + } else { 126 + $image_view = null; 127 + } 128 + 129 + return $image_view; 130 + } 131 + 132 + private function getTargetURI() { 133 + $target_uri = null; 134 + $handle = $this->handle; 135 + 136 + if ($handle) { 137 + $target_uri = $handle->getURI(); 138 + } 139 + 140 + return $target_uri; 141 + } 142 + 143 + private function getImageURI() { 144 + $image_uri = null; 145 + $handle = $this->handle; 146 + 147 + if ($handle) { 148 + $image_uri = $handle->getImageURI(); 149 + } 150 + 151 + return $image_uri; 152 + } 153 + 154 + 155 + }
+48
webroot/rsrc/css/phui/phui-curtain-object-ref-view.css
··· 1 + /** 2 + * @provides phui-curtain-object-ref-view-css 3 + */ 4 + 5 + .phui-curtain-object-ref-list-view-empty { 6 + font-style: italic; 7 + color: {$greytext}; 8 + } 9 + 10 + .phui-curtain-object-ref-view-image-cell { 11 + min-width: 32px; 12 + min-height: 32px; 13 + } 14 + 15 + .phui-curtain-object-ref-view-image-cell > a { 16 + height: 24px; 17 + width: 24px; 18 + background-size: 100%; 19 + border-radius: 3px; 20 + display: block; 21 + } 22 + 23 + .phui-curtain-object-ref-view-title-cell { 24 + font-weight: bold; 25 + text-overflow: ellipsis; 26 + overflow: hidden; 27 + 28 + /* This is forcing "text-overflow: ellipsis" to actually work. */ 29 + max-width: 225px; 30 + } 31 + 32 + .phui-curtain-object-ref-view-without-content > 33 + .phui-curtain-object-ref-view-title-cell { 34 + vertical-align: middle; 35 + } 36 + 37 + .phui-curtain-object-ref-view-with-content > 38 + .phui-curtain-object-ref-view-image-cell > a { 39 + margin-top: 4px; 40 + } 41 + 42 + .phui-curtain-object-ref-view-title-cell > a { 43 + color: {$darkgreytext}; 44 + } 45 + 46 + .phui-curtain-object-ref-view-epoch-cell { 47 + color: {$greytext}; 48 + }