@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.

Add previews to ApplicationTransaction

Summary:
Implements previews for Macros and Pholio.

(Design is nonfinal -- kind of split the difference between `diff_full_view.png`, laziness, and space concerns. Next couple diffs will add more stuff here.)

Test Plan: {F28055}

Reviewers: btrahan, chad

Reviewed By: btrahan

CC: aran, vrana

Maniphest Tasks: T2104

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

+391 -137
+14 -1
src/__celerity_resource_map__.php
··· 1676 1676 ), 1677 1677 'disk' => '/rsrc/js/application/core/behavior-tooltip.js', 1678 1678 ), 1679 + 'javelin-behavior-phabricator-transaction-comment-form' => 1680 + array( 1681 + 'uri' => '/res/bdc362ee/rsrc/js/application/transactions/behavior-transaction-comment-form.js', 1682 + 'type' => 'js', 1683 + 'requires' => 1684 + array( 1685 + 0 => 'javelin-behavior', 1686 + 1 => 'javelin-dom', 1687 + 2 => 'javelin-util', 1688 + 3 => 'phabricator-shaped-request', 1689 + ), 1690 + 'disk' => '/rsrc/js/application/transactions/behavior-transaction-comment-form.js', 1691 + ), 1679 1692 'javelin-behavior-phabricator-transaction-list' => 1680 1693 array( 1681 1694 'uri' => '/res/212f97ba/rsrc/js/application/transactions/behavior-transaction-list.js', ··· 2847 2860 ), 2848 2861 'phabricator-timeline-view-css' => 2849 2862 array( 2850 - 'uri' => '/res/1846f7d5/rsrc/css/layout/phabricator-timeline-view.css', 2863 + 'uri' => '/res/9cbeb7f0/rsrc/css/layout/phabricator-timeline-view.css', 2851 2864 'type' => 'css', 2852 2865 'requires' => 2853 2866 array(
+2
src/__phutil_library_map__.php
··· 613 613 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 614 614 'PhabricatorApplicationTransactionCommentHistoryController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentHistoryController.php', 615 615 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', 616 + 'PhabricatorApplicationTransactionCommentView' => 'applications/transactions/view/PhabricatorApplicationTransactionCommentView.php', 616 617 'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php', 617 618 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', 618 619 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', ··· 1904 1905 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 1905 1906 'PhabricatorApplicationTransactionCommentHistoryController' => 'PhabricatorApplicationTransactionController', 1906 1907 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 1908 + 'PhabricatorApplicationTransactionCommentView' => 'AphrontView', 1907 1909 'PhabricatorApplicationTransactionController' => 'PhabricatorController', 1908 1910 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', 1909 1911 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory',
+5
src/aphront/AphrontRequest.php
··· 18 18 const TYPE_CONDUIT = '__conduit__'; 19 19 const TYPE_WORKFLOW = '__wflow__'; 20 20 const TYPE_CONTINUE = '__continue__'; 21 + const TYPE_PREVIEW = '__preview__'; 21 22 22 23 private $host; 23 24 private $path; ··· 337 338 338 339 public function isContinueRequest() { 339 340 return $this->isFormPost() && $this->getStr('__continue__'); 341 + } 342 + 343 + public function isPreviewRequest() { 344 + return $this->isFormPost() && $this->getStr('__preview__'); 340 345 } 341 346 342 347 /**
+5 -2
src/applications/macro/controller/PhabricatorMacroCommentController.php
··· 22 22 return new Aphront404Response(); 23 23 } 24 24 25 + $is_preview = $request->isPreviewRequest(); 26 + 25 27 $view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/'); 26 28 27 29 $xactions = array(); 28 - 29 30 $xactions[] = id(new PhabricatorMacroTransaction()) 30 31 ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 31 32 ->attachComment( ··· 40 41 PhabricatorContentSource::SOURCE_WEB, 41 42 array( 42 43 'ip' => $request->getRemoteAddr(), 43 - ))); 44 + ))) 45 + ->setIsPreview($is_preview); 44 46 45 47 try { 46 48 $xactions = $editor->applyTransactions($macro, $xactions); ··· 54 56 return id(new PhabricatorApplicationTransactionResponse()) 55 57 ->setViewer($user) 56 58 ->setTransactions($xactions) 59 + ->setIsPreview($is_preview) 57 60 ->setAnchorOffset($request->getStr('anchor')); 58 61 } else { 59 62 return id(new AphrontRedirectResponse())
+7 -16
src/applications/macro/controller/PhabricatorMacroViewController.php
··· 79 79 ? pht('Add Comment') 80 80 : pht('Grovel in Awe')); 81 81 82 - $add_comment_form = id(new AphrontFormView()) 83 - ->setWorkflow(true) 84 - ->setFlexible(true) 85 - ->addSigil('transaction-append') 86 - ->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/')) 82 + $submit_button_name = $is_serious 83 + ? pht('Add Comment') 84 + : pht('Lavish Praise'); 85 + 86 + $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) 87 87 ->setUser($user) 88 - ->appendChild( 89 - id(new PhabricatorRemarkupControl()) 90 - ->setUser($user) 91 - ->setLabel('Comment') 92 - ->setName('comment')) 93 - ->appendChild( 94 - id(new AphrontFormSubmitControl()) 95 - ->setValue( 96 - $is_serious 97 - ? pht('Add Comment') 98 - : pht('Lavish Praise'))); 88 + ->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/')) 89 + ->setSubmitButtonName($submit_button_name); 99 90 100 91 return $this->buildApplicationPage( 101 92 array(
+9 -1
src/applications/pholio/controller/PholioMockCommentController.php
··· 15 15 $request = $this->getRequest(); 16 16 $user = $request->getUser(); 17 17 18 + if (!$request->isFormPost()) { 19 + return new Aphront400Response(); 20 + } 21 + 18 22 $mock = id(new PholioMockQuery()) 19 23 ->setViewer($user) 20 24 ->withIDs(array($this->id)) ··· 24 28 return new Aphront404Response(); 25 29 } 26 30 31 + $is_preview = $request->isPreviewRequest(); 32 + 27 33 $mock_uri = '/M'.$mock->getID(); 28 34 29 35 $comment = $request->getStr('comment'); ··· 44 50 $editor = id(new PholioMockEditor()) 45 51 ->setActor($user) 46 52 ->setContentSource($content_source) 47 - ->setContinueOnException($request->isContinueRequest()); 53 + ->setContinueOnNoEffect($request->isContinueRequest()) 54 + ->setIsPreview($is_preview); 48 55 49 56 try { 50 57 $xactions = $editor->applyTransactions($mock, $xactions); ··· 58 65 return id(new PhabricatorApplicationTransactionResponse()) 59 66 ->setViewer($user) 60 67 ->setTransactions($xactions) 68 + ->setIsPreview($is_preview) 61 69 ->setAnchorOffset($request->getStr('anchor')); 62 70 } else { 63 71 return id(new AphrontRedirectResponse())->setURI($mock_uri);
+1 -1
src/applications/pholio/controller/PholioMockEditController.php
··· 120 120 $mock->openTransaction(); 121 121 $editor = id(new PholioMockEditor()) 122 122 ->setContentSource($content_source) 123 - ->setContinueOnException(true) 123 + ->setContinueOnNoEffect(true) 124 124 ->setActor($user); 125 125 126 126 $xactions = $editor->applyTransactions($mock, $xactions);
+5 -15
src/applications/pholio/controller/PholioMockViewController.php
··· 65 65 'Carousel Goes Here</h1>'; 66 66 67 67 $xaction_view = id(new PhabricatorApplicationTransactionView()) 68 - ->setViewer($this->getRequest()->getUser()) 68 + ->setUser($this->getRequest()->getUser()) 69 69 ->setTransactions($xactions) 70 70 ->setMarkupEngine($engine); 71 71 ··· 168 168 $header = id(new PhabricatorHeaderView()) 169 169 ->setHeader($title); 170 170 171 - $action = $is_serious 171 + $button_name = $is_serious 172 172 ? pht('Add Comment') 173 173 : pht('Answer The Call'); 174 174 175 - $form = id(new AphrontFormView()) 175 + $form = id(new PhabricatorApplicationTransactionCommentView()) 176 176 ->setUser($user) 177 - ->addSigil('transaction-append') 178 - ->setAction($this->getApplicationURI('/comment/'.$mock->getID().'/')) 179 - ->setWorkflow(true) 180 - ->setFlexible(true) 181 - ->appendChild( 182 - id(new PhabricatorRemarkupControl()) 183 - ->setName('comment') 184 - ->setLabel(pht('Comment')) 185 - ->setUser($user)) 186 - ->appendChild( 187 - id(new AphrontFormSubmitControl()) 188 - ->setValue($action)); 177 + ->setSubmitButtonName($button_name) 178 + ->setAction($this->getApplicationURI('/comment/'.$mock->getID().'/')); 189 179 190 180 return array( 191 181 $header,
+26 -11
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 15 15 private $mentionedPHIDs; 16 16 private $continueOnNoEffect; 17 17 18 + private $isPreview; 18 19 19 20 /** 20 21 * When the editor tries to apply transactions that have no effect, should ··· 44 45 45 46 protected function getMentionedPHIDs() { 46 47 return $this->mentionedPHIDs; 48 + } 49 + 50 + public function setIsPreview($is_preview) { 51 + $this->isPreview = $is_preview; 52 + return $this; 53 + } 54 + 55 + public function getIsPreview() { 56 + return $this->isPreview; 47 57 } 48 58 49 59 public function getTransactionTypes() { ··· 225 235 $xactions = $this->filterTransactions($object, $xactions); 226 236 227 237 if (!$xactions) { 228 - return $this; 238 + return array(); 229 239 } 230 240 231 241 $xactions = $this->sortTransactions($xactions); 242 + 243 + if ($this->getIsPreview()) { 244 + $this->loadHandles($xactions); 245 + return $xactions; 246 + } 232 247 233 248 $comment_editor = id(new PhabricatorApplicationTransactionCommentEditor()) 234 249 ->setActor($actor) ··· 256 271 } 257 272 $object->saveTransaction(); 258 273 259 - 260 274 $this->loadHandles($xactions); 261 - 262 275 263 276 $mail = null; 264 277 if ($this->supportsMail()) { ··· 285 298 286 299 private function loadHandles(array $xactions) { 287 300 $phids = array(); 288 - foreach ($xactions as $xaction) { 289 - $phids[$xaction->getPHID()] = $xaction->getRequiredHandlePHIDs(); 301 + foreach ($xactions as $key => $xaction) { 302 + $phids[$key] = $xaction->getRequiredHandlePHIDs(); 290 303 } 291 304 $handles = array(); 292 305 $merged = array_mergev($phids); ··· 295 308 ->setViewer($this->requireActor()) 296 309 ->loadHandles(); 297 310 } 298 - foreach ($xactions as $xaction) { 299 - $xaction->setHandles( 300 - array_select_keys( 301 - $handles, 302 - $phids[$xaction->getPHID()])); 311 + foreach ($xactions as $key => $xaction) { 312 + $xaction->setHandles(array_select_keys($handles, $phids[$key])); 303 313 } 304 314 } 305 315 ··· 587 597 return $xactions; 588 598 } 589 599 590 - if (!$this->getContinueOnNoEffect()) { 600 + if (!$this->getContinueOnNoEffect() && !$this->getIsPreview()) { 591 601 throw new PhabricatorApplicationTransactionNoEffectException( 592 602 $no_effect, 593 603 $any_effect, 594 604 $has_comment); 605 + } 606 + 607 + if (!$any_effect && !$has_comment) { 608 + // If we only have empty comment transactions, just drop them all. 609 + return array(); 595 610 } 596 611 597 612 foreach ($no_effect as $key => $xaction) {
+14 -3
src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php
··· 6 6 private $viewer; 7 7 private $transactions; 8 8 private $anchorOffset; 9 + private $isPreview; 9 10 10 11 protected function buildProxy() { 11 12 return new AphrontAjaxResponse(); ··· 40 41 return $this->viewer; 41 42 } 42 43 44 + public function setIsPreview($is_preview) { 45 + $this->isPreview = $is_preview; 46 + return $this; 47 + } 48 + 43 49 public function reduceProxyResponse() { 44 50 $view = id(new PhabricatorApplicationTransactionView()) 45 - ->setViewer($this->getViewer()) 46 - ->setTransactions($this->getTransactions()); 51 + ->setUser($this->getViewer()) 52 + ->setTransactions($this->getTransactions()) 53 + ->setIsPreview($this->isPreview); 47 54 48 55 if ($this->getAnchorOffset()) { 49 56 $view->setAnchorOffset($this->getAnchorOffset()); 50 57 } 51 58 52 - $xactions = mpull($view->buildEvents(), 'render', 'getTransactionPHID'); 59 + if ($this->isPreview) { 60 + $xactions = mpull($view->buildEvents(), 'render'); 61 + } else { 62 + $xactions = mpull($view->buildEvents(), 'render', 'getTransactionPHID'); 63 + } 53 64 54 65 $content = array( 55 66 'xactions' => $xactions,
+147
src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php
··· 1 + <?php 2 + 3 + /** 4 + * @concrete-extensible 5 + */ 6 + class PhabricatorApplicationTransactionCommentView extends AphrontView { 7 + 8 + private $submitButtonName; 9 + private $action; 10 + 11 + private $previewPanelID; 12 + private $previewTimelineID; 13 + private $previewToggleID; 14 + private $formID; 15 + private $statusID; 16 + 17 + public function setSubmitButtonName($submit_button_name) { 18 + $this->submitButtonName = $submit_button_name; 19 + return $this; 20 + } 21 + 22 + public function getSubmitButtonName() { 23 + return $this->submitButtonName; 24 + } 25 + 26 + public function setAction($action) { 27 + $this->action = $action; 28 + return $this; 29 + } 30 + 31 + public function getAction() { 32 + return $this->action; 33 + } 34 + 35 + public function render() { 36 + 37 + $data = array(); 38 + 39 + $comment = $this->renderCommentPanel(); 40 + 41 + $preview = $this->renderPreviewPanel(); 42 + 43 + Javelin::initBehavior( 44 + 'phabricator-transaction-comment-form', 45 + array( 46 + 'formID' => $this->getFormID(), 47 + 'timelineID' => $this->getPreviewTimelineID(), 48 + 'panelID' => $this->getPreviewPanelID(), 49 + 'statusID' => $this->getStatusID(), 50 + 51 + 'loadingString' => pht('Loading Preview...'), 52 + 'savingString' => pht('Saving Draft...'), 53 + 'draftString' => pht('Saved Draft'), 54 + 55 + 'actionURI' => $this->getAction(), 56 + )); 57 + 58 + return self::renderSingleView( 59 + array( 60 + $comment, 61 + $preview, 62 + )); 63 + } 64 + 65 + private function renderCommentPanel() { 66 + $status = phutil_render_tag( 67 + 'div', 68 + array( 69 + 'id' => $this->getStatusID(), 70 + ), 71 + ''); 72 + 73 + return id(new AphrontFormView()) 74 + ->setUser($this->getUser()) 75 + ->setFlexible(true) 76 + ->addSigil('transaction-append') 77 + ->setWorkflow(true) 78 + ->setAction($this->getAction()) 79 + ->setID($this->getFormID()) 80 + ->appendChild( 81 + id(new PhabricatorRemarkupControl()) 82 + ->setName('comment') 83 + ->setLabel(pht('Comment')) 84 + ->setUser($this->getUser())) 85 + ->appendChild( 86 + id(new AphrontFormSubmitControl()) 87 + ->setValue($this->getSubmitButtonName())) 88 + ->appendChild( 89 + id(new AphrontFormMarkupControl()) 90 + ->setValue($status)); 91 + } 92 + 93 + private function renderPreviewPanel() { 94 + 95 + $preview = id(new PhabricatorTimelineView()) 96 + ->setID($this->getPreviewTimelineID()); 97 + 98 + $header = phutil_render_tag( 99 + 'div', 100 + array( 101 + 'class' => 'phabricator-timeline-preview-header', 102 + ), 103 + phutil_escape_html(pht('Preview'))); 104 + 105 + return phutil_render_tag( 106 + 'div', 107 + array( 108 + 'id' => $this->getPreviewPanelID(), 109 + 'style' => 'display: none', 110 + ), 111 + self::renderSingleView( 112 + array( 113 + $header, 114 + $preview, 115 + ))); 116 + } 117 + 118 + private function getPreviewPanelID() { 119 + if (!$this->previewPanelID) { 120 + $this->previewPanelID = celerity_generate_unique_node_id(); 121 + } 122 + return $this->previewPanelID; 123 + } 124 + 125 + private function getPreviewTimelineID() { 126 + if (!$this->previewTimelineID) { 127 + $this->previewTimelineID = celerity_generate_unique_node_id(); 128 + } 129 + return $this->previewTimelineID; 130 + } 131 + 132 + private function getFormID() { 133 + if (!$this->formID) { 134 + $this->formID = celerity_generate_unique_node_id(); 135 + } 136 + return $this->formID; 137 + } 138 + 139 + private function getStatusID() { 140 + if (!$this->statusID) { 141 + $this->statusID = celerity_generate_unique_node_id(); 142 + } 143 + return $this->statusID; 144 + } 145 + 146 + } 147 +
+23 -16
src/applications/transactions/view/PhabricatorApplicationTransactionView.php
··· 5 5 */ 6 6 class PhabricatorApplicationTransactionView extends AphrontView { 7 7 8 - private $viewer; 9 8 private $transactions; 10 9 private $engine; 11 10 private $anchorOffset = 1; 12 11 private $showEditActions = true; 12 + private $isPreview; 13 + 14 + public function setIsPreview($is_preview) { 15 + $this->isPreview = $is_preview; 16 + return $this; 17 + } 13 18 14 19 public function setShowEditActions($show_edit_actions) { 15 20 $this->showEditActions = $show_edit_actions; ··· 36 41 return $this; 37 42 } 38 43 39 - public function setViewer(PhabricatorUser $viewer) { 40 - $this->viewer = $viewer; 41 - return $this; 42 - } 43 - 44 44 public function buildEvents() { 45 45 $field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT; 46 46 $engine = $this->getOrBuildEngine(); 47 47 48 - $viewer = $this->viewer; 48 + $user = $this->getUser(); 49 49 50 50 $anchor = $this->anchorOffset; 51 51 $events = array(); ··· 55 55 } 56 56 57 57 $event = id(new PhabricatorTimelineEventView()) 58 - ->setViewer($viewer) 58 + ->setUser($user) 59 59 ->setTransactionPHID($xaction->getPHID()) 60 60 ->setUserHandle($xaction->getHandle($xaction->getAuthorPHID())) 61 61 ->setIcon($xaction->getIcon()) 62 62 ->setColor($xaction->getColor()) 63 - ->setTitle($xaction->getTitle()) 64 - ->setDateCreated($xaction->getDateCreated()) 65 - ->setContentSource($xaction->getContentSource()) 66 - ->setAnchor($anchor); 63 + ->setTitle($xaction->getTitle()); 64 + 65 + if ($this->isPreview) { 66 + $event->setIsPreview(true); 67 + } else { 68 + $event 69 + ->setDateCreated($xaction->getDateCreated()) 70 + ->setContentSource($xaction->getContentSource()) 71 + ->setAnchor($anchor); 72 + 73 + $anchor++; 74 + } 67 75 68 - $anchor++; 69 76 70 77 $has_deleted_comment = $xaction->getComment() && 71 78 $xaction->getComment()->getIsDeleted(); 72 79 73 - if ($this->getShowEditActions()) { 80 + if ($this->getShowEditActions() && !$this->isPreview) { 74 81 if ($xaction->getCommentVersion() > 1) { 75 82 $event->setIsEdited(true); 76 83 } ··· 79 86 80 87 if ($xaction->hasComment() || $has_deleted_comment) { 81 88 $has_edit_capability = PhabricatorPolicyFilter::hasCapability( 82 - $viewer, 89 + $user, 83 90 $xaction, 84 91 $can_edit); 85 92 if ($has_edit_capability) { ··· 134 141 $field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT; 135 142 136 143 $engine = id(new PhabricatorMarkupEngine()) 137 - ->setViewer($this->viewer); 144 + ->setViewer($this->getUser()); 138 145 foreach ($this->transactions as $xaction) { 139 146 if (!$xaction->hasComment()) { 140 147 continue;
+82 -71
src/view/layout/PhabricatorTimelineEventView.php
··· 9 9 private $classes = array(); 10 10 private $contentSource; 11 11 private $dateCreated; 12 - private $viewer; 13 12 private $anchor; 14 13 private $isEditable; 15 14 private $isEdited; 16 15 private $transactionPHID; 16 + private $isPreview; 17 17 18 18 public function setTransactionPHID($transaction_phid) { 19 19 $this->transactionPHID = $transaction_phid; ··· 33 33 return $this->isEdited; 34 34 } 35 35 36 + public function setIsPreview($is_preview) { 37 + $this->isPreview = $is_preview; 38 + return $this; 39 + } 40 + 41 + public function getIsPreview() { 42 + return $this->isPreview; 43 + } 36 44 37 45 public function setIsEditable($is_editable) { 38 46 $this->isEditable = $is_editable; ··· 41 49 42 50 public function getIsEditable() { 43 51 return $this->isEditable; 44 - } 45 - 46 - public function setViewer(PhabricatorUser $viewer) { 47 - $this->viewer = $viewer; 48 - return $this; 49 - } 50 - 51 - public function getViewer() { 52 - return $this->viewer; 53 52 } 54 53 55 54 public function setDateCreated($date_created) { ··· 108 107 $title = ''; 109 108 } 110 109 111 - $extra = array(); 112 - $xaction_phid = $this->getTransactionPHID(); 113 - 114 - if ($this->getIsEdited()) { 115 - $extra[] = javelin_render_tag( 116 - 'a', 117 - array( 118 - 'href' => '/transactions/history/'.$xaction_phid.'/', 119 - 'sigil' => 'workflow', 120 - ), 121 - pht('Edited')); 122 - } 123 - 124 - if ($this->getIsEditable()) { 125 - $extra[] = javelin_render_tag( 126 - 'a', 127 - array( 128 - 'href' => '/transactions/edit/'.$xaction_phid.'/', 129 - 'sigil' => 'workflow transaction-edit', 130 - ), 131 - pht('Edit')); 132 - } 133 - 134 - $source = $this->getContentSource(); 135 - if ($source) { 136 - $extra[] = id(new PhabricatorContentSourceView()) 137 - ->setContentSource($source) 138 - ->setUser($this->getViewer()) 139 - ->render(); 140 - } 141 - 142 - if ($this->getDateCreated()) { 143 - $date = phabricator_datetime( 144 - $this->getDateCreated(), 145 - $this->getViewer()); 146 - if ($this->anchor) { 147 - Javelin::initBehavior('phabricator-watch-anchor'); 148 - 149 - $anchor = id(new PhabricatorAnchorView()) 150 - ->setAnchorName($this->anchor) 151 - ->render(); 152 - 153 - $date = $anchor.phutil_render_tag( 154 - 'a', 155 - array( 156 - 'href' => '#'.$this->anchor, 157 - ), 158 - $date); 159 - } 160 - $extra[] = $date; 161 - } 162 - 163 - $extra = implode(' &middot; ', $extra); 164 - if ($extra) { 165 - $extra = phutil_render_tag( 166 - 'span', 167 - array( 168 - 'class' => 'phabricator-timeline-extra', 169 - ), 170 - $extra); 171 - } 110 + $extra = $this->renderExtra(); 172 111 173 112 if ($title !== null || $extra !== null) { 174 113 $title_classes = array(); ··· 284 223 'class' => implode(' ', $classes), 285 224 ), 286 225 $content)); 226 + } 227 + 228 + private function renderExtra() { 229 + $extra = array(); 230 + 231 + if ($this->getIsPreview()) { 232 + $extra[] = pht('PREVIEW'); 233 + } else { 234 + $xaction_phid = $this->getTransactionPHID(); 235 + 236 + 237 + if ($this->getIsEdited()) { 238 + $extra[] = javelin_render_tag( 239 + 'a', 240 + array( 241 + 'href' => '/transactions/history/'.$xaction_phid.'/', 242 + 'sigil' => 'workflow', 243 + ), 244 + pht('Edited')); 245 + } 246 + 247 + if ($this->getIsEditable()) { 248 + $extra[] = javelin_render_tag( 249 + 'a', 250 + array( 251 + 'href' => '/transactions/edit/'.$xaction_phid.'/', 252 + 'sigil' => 'workflow transaction-edit', 253 + ), 254 + pht('Edit')); 255 + } 256 + 257 + $source = $this->getContentSource(); 258 + if ($source) { 259 + $extra[] = id(new PhabricatorContentSourceView()) 260 + ->setContentSource($source) 261 + ->setUser($this->getUser()) 262 + ->render(); 263 + } 264 + 265 + if ($this->getDateCreated()) { 266 + $date = phabricator_datetime( 267 + $this->getDateCreated(), 268 + $this->getUser()); 269 + if ($this->anchor) { 270 + Javelin::initBehavior('phabricator-watch-anchor'); 271 + 272 + $anchor = id(new PhabricatorAnchorView()) 273 + ->setAnchorName($this->anchor) 274 + ->render(); 275 + 276 + $date = $anchor.phutil_render_tag( 277 + 'a', 278 + array( 279 + 'href' => '#'.$this->anchor, 280 + ), 281 + $date); 282 + } 283 + $extra[] = $date; 284 + } 285 + } 286 + 287 + $extra = implode(' &middot; ', $extra); 288 + if ($extra) { 289 + $extra = phutil_render_tag( 290 + 'span', 291 + array( 292 + 'class' => 'phabricator-timeline-extra', 293 + ), 294 + $extra); 295 + } 296 + 297 + return $extra; 287 298 } 288 299 289 300 }
+7
webroot/rsrc/css/layout/phabricator-timeline-view.css
··· 245 245 background: rgba(255, 255, 0, 0.50); 246 246 box-shadow: 0 0 3px 6px rgba(255, 255, 0, 0.50); 247 247 } 248 + 249 + .phabricator-timeline-preview-header { 250 + background: #e0e3ec; 251 + color: #444444; 252 + padding: 4px 1.25%; 253 + border: solid #c0c5d1 1px 0; 254 + }
+44
webroot/rsrc/js/application/transactions/behavior-transaction-comment-form.js
··· 1 + /** 2 + * @provides javelin-behavior-phabricator-transaction-comment-form 3 + * @requires javelin-behavior 4 + * javelin-dom 5 + * javelin-util 6 + * phabricator-shaped-request 7 + */ 8 + 9 + JX.behavior('phabricator-transaction-comment-form', function(config) { 10 + 11 + var form = JX.$(config.formID); 12 + 13 + var getdata = function() { 14 + var obj = JX.DOM.convertFormToDictionary(form); 15 + obj.__preview__ = 1; 16 + return obj; 17 + }; 18 + 19 + var onresponse = function(response) { 20 + var panel = JX.$(config.panelID); 21 + if (!response.xactions.length) { 22 + JX.DOM.hide(panel); 23 + } else { 24 + JX.DOM.setContent( 25 + JX.$(config.timelineID), 26 + [ 27 + JX.$H(response.spacer), 28 + JX.$H(response.xactions.join(response.spacer)), 29 + JX.$H(response.spacer), 30 + ]); 31 + JX.DOM.show(panel); 32 + } 33 + }; 34 + 35 + var request = new JX.PhabricatorShapedRequest( 36 + config.actionURI, 37 + onresponse, 38 + getdata); 39 + var trigger = JX.bind(request, request.trigger); 40 + 41 + JX.DOM.listen(form, 'keydown', null, trigger); 42 + 43 + request.start(); 44 + });