From 0fd77783a49e8ff8ed1c5d4ef5697d3c3af1af19 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 21 Dec 2012 05:51:33 -0800 Subject: [PATCH] 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 --- src/__celerity_resource_map__.php | 15 +- src/__phutil_library_map__.php | 2 + src/aphront/AphrontRequest.php | 5 + .../PhabricatorMacroCommentController.php | 7 +- .../PhabricatorMacroViewController.php | 23 +-- .../PholioMockCommentController.php | 10 +- .../controller/PholioMockEditController.php | 2 +- .../controller/PholioMockViewController.php | 20 +-- ...habricatorApplicationTransactionEditor.php | 37 +++-- ...bricatorApplicationTransactionResponse.php | 17 +- ...catorApplicationTransactionCommentView.php | 147 +++++++++++++++++ .../PhabricatorApplicationTransactionView.php | 39 +++-- .../layout/PhabricatorTimelineEventView.php | 153 ++++++++++-------- .../css/layout/phabricator-timeline-view.css | 7 + .../behavior-transaction-comment-form.js | 44 +++++ 15 files changed, 391 insertions(+), 137 deletions(-) create mode 100644 src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php create mode 100644 webroot/rsrc/js/application/transactions/behavior-transaction-comment-form.js diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 467e03734d..ce9285077a 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -1676,6 +1676,19 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/behavior-tooltip.js', ), + 'javelin-behavior-phabricator-transaction-comment-form' => + array( + 'uri' => '/res/bdc362ee/rsrc/js/application/transactions/behavior-transaction-comment-form.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-dom', + 2 => 'javelin-util', + 3 => 'phabricator-shaped-request', + ), + 'disk' => '/rsrc/js/application/transactions/behavior-transaction-comment-form.js', + ), 'javelin-behavior-phabricator-transaction-list' => array( 'uri' => '/res/212f97ba/rsrc/js/application/transactions/behavior-transaction-list.js', @@ -2847,7 +2860,7 @@ celerity_register_resource_map(array( ), 'phabricator-timeline-view-css' => array( - 'uri' => '/res/1846f7d5/rsrc/css/layout/phabricator-timeline-view.css', + 'uri' => '/res/9cbeb7f0/rsrc/css/layout/phabricator-timeline-view.css', 'type' => 'css', 'requires' => array( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 9f0466cc20..fe90436abf 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -613,6 +613,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 'PhabricatorApplicationTransactionCommentHistoryController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentHistoryController.php', 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', + 'PhabricatorApplicationTransactionCommentView' => 'applications/transactions/view/PhabricatorApplicationTransactionCommentView.php', 'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php', 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', @@ -1904,6 +1905,7 @@ phutil_register_library_map(array( 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionCommentHistoryController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorApplicationTransactionCommentView' => 'AphrontView', 'PhabricatorApplicationTransactionController' => 'PhabricatorController', 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory', diff --git a/src/aphront/AphrontRequest.php b/src/aphront/AphrontRequest.php index aba20d6747..762d2394cd 100644 --- a/src/aphront/AphrontRequest.php +++ b/src/aphront/AphrontRequest.php @@ -18,6 +18,7 @@ final class AphrontRequest { const TYPE_CONDUIT = '__conduit__'; const TYPE_WORKFLOW = '__wflow__'; const TYPE_CONTINUE = '__continue__'; + const TYPE_PREVIEW = '__preview__'; private $host; private $path; @@ -339,6 +340,10 @@ final class AphrontRequest { return $this->isFormPost() && $this->getStr('__continue__'); } + public function isPreviewRequest() { + return $this->isFormPost() && $this->getStr('__preview__'); + } + /** * Get application request parameters in a flattened form suitable for * inclusion in an HTTP request, excluding parameters with special meanings. diff --git a/src/applications/macro/controller/PhabricatorMacroCommentController.php b/src/applications/macro/controller/PhabricatorMacroCommentController.php index 9b4fe7763d..a1ba47212a 100644 --- a/src/applications/macro/controller/PhabricatorMacroCommentController.php +++ b/src/applications/macro/controller/PhabricatorMacroCommentController.php @@ -22,10 +22,11 @@ final class PhabricatorMacroCommentController return new Aphront404Response(); } + $is_preview = $request->isPreviewRequest(); + $view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/'); $xactions = array(); - $xactions[] = id(new PhabricatorMacroTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) ->attachComment( @@ -40,7 +41,8 @@ final class PhabricatorMacroCommentController PhabricatorContentSource::SOURCE_WEB, array( 'ip' => $request->getRemoteAddr(), - ))); + ))) + ->setIsPreview($is_preview); try { $xactions = $editor->applyTransactions($macro, $xactions); @@ -54,6 +56,7 @@ final class PhabricatorMacroCommentController return id(new PhabricatorApplicationTransactionResponse()) ->setViewer($user) ->setTransactions($xactions) + ->setIsPreview($is_preview) ->setAnchorOffset($request->getStr('anchor')); } else { return id(new AphrontRedirectResponse()) diff --git a/src/applications/macro/controller/PhabricatorMacroViewController.php b/src/applications/macro/controller/PhabricatorMacroViewController.php index 30b417101a..547ba80c30 100644 --- a/src/applications/macro/controller/PhabricatorMacroViewController.php +++ b/src/applications/macro/controller/PhabricatorMacroViewController.php @@ -79,23 +79,14 @@ final class PhabricatorMacroViewController ? pht('Add Comment') : pht('Grovel in Awe')); - $add_comment_form = id(new AphrontFormView()) - ->setWorkflow(true) - ->setFlexible(true) - ->addSigil('transaction-append') - ->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/')) + $submit_button_name = $is_serious + ? pht('Add Comment') + : pht('Lavish Praise'); + + $add_comment_form = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($user) - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setUser($user) - ->setLabel('Comment') - ->setName('comment')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue( - $is_serious - ? pht('Add Comment') - : pht('Lavish Praise'))); + ->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/')) + ->setSubmitButtonName($submit_button_name); return $this->buildApplicationPage( array( diff --git a/src/applications/pholio/controller/PholioMockCommentController.php b/src/applications/pholio/controller/PholioMockCommentController.php index cf1537f4e4..8ee3c8d218 100644 --- a/src/applications/pholio/controller/PholioMockCommentController.php +++ b/src/applications/pholio/controller/PholioMockCommentController.php @@ -15,6 +15,10 @@ final class PholioMockCommentController extends PholioController { $request = $this->getRequest(); $user = $request->getUser(); + if (!$request->isFormPost()) { + return new Aphront400Response(); + } + $mock = id(new PholioMockQuery()) ->setViewer($user) ->withIDs(array($this->id)) @@ -24,6 +28,8 @@ final class PholioMockCommentController extends PholioController { return new Aphront404Response(); } + $is_preview = $request->isPreviewRequest(); + $mock_uri = '/M'.$mock->getID(); $comment = $request->getStr('comment'); @@ -44,7 +50,8 @@ final class PholioMockCommentController extends PholioController { $editor = id(new PholioMockEditor()) ->setActor($user) ->setContentSource($content_source) - ->setContinueOnException($request->isContinueRequest()); + ->setContinueOnNoEffect($request->isContinueRequest()) + ->setIsPreview($is_preview); try { $xactions = $editor->applyTransactions($mock, $xactions); @@ -58,6 +65,7 @@ final class PholioMockCommentController extends PholioController { return id(new PhabricatorApplicationTransactionResponse()) ->setViewer($user) ->setTransactions($xactions) + ->setIsPreview($is_preview) ->setAnchorOffset($request->getStr('anchor')); } else { return id(new AphrontRedirectResponse())->setURI($mock_uri); diff --git a/src/applications/pholio/controller/PholioMockEditController.php b/src/applications/pholio/controller/PholioMockEditController.php index 10d66fc652..cfc1da1022 100644 --- a/src/applications/pholio/controller/PholioMockEditController.php +++ b/src/applications/pholio/controller/PholioMockEditController.php @@ -120,7 +120,7 @@ final class PholioMockEditController extends PholioController { $mock->openTransaction(); $editor = id(new PholioMockEditor()) ->setContentSource($content_source) - ->setContinueOnException(true) + ->setContinueOnNoEffect(true) ->setActor($user); $xactions = $editor->applyTransactions($mock, $xactions); diff --git a/src/applications/pholio/controller/PholioMockViewController.php b/src/applications/pholio/controller/PholioMockViewController.php index 07b870b55c..9f23d46e1f 100644 --- a/src/applications/pholio/controller/PholioMockViewController.php +++ b/src/applications/pholio/controller/PholioMockViewController.php @@ -65,7 +65,7 @@ final class PholioMockViewController extends PholioController { 'Carousel Goes Here'; $xaction_view = id(new PhabricatorApplicationTransactionView()) - ->setViewer($this->getRequest()->getUser()) + ->setUser($this->getRequest()->getUser()) ->setTransactions($xactions) ->setMarkupEngine($engine); @@ -168,24 +168,14 @@ final class PholioMockViewController extends PholioController { $header = id(new PhabricatorHeaderView()) ->setHeader($title); - $action = $is_serious + $button_name = $is_serious ? pht('Add Comment') : pht('Answer The Call'); - $form = id(new AphrontFormView()) + $form = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($user) - ->addSigil('transaction-append') - ->setAction($this->getApplicationURI('/comment/'.$mock->getID().'/')) - ->setWorkflow(true) - ->setFlexible(true) - ->appendChild( - id(new PhabricatorRemarkupControl()) - ->setName('comment') - ->setLabel(pht('Comment')) - ->setUser($user)) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue($action)); + ->setSubmitButtonName($button_name) + ->setAction($this->getApplicationURI('/comment/'.$mock->getID().'/')); return array( $header, diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 5edd417cfe..3d99a4aef0 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -15,6 +15,7 @@ abstract class PhabricatorApplicationTransactionEditor private $mentionedPHIDs; private $continueOnNoEffect; + private $isPreview; /** * When the editor tries to apply transactions that have no effect, should @@ -46,6 +47,15 @@ abstract class PhabricatorApplicationTransactionEditor return $this->mentionedPHIDs; } + public function setIsPreview($is_preview) { + $this->isPreview = $is_preview; + return $this; + } + + public function getIsPreview() { + return $this->isPreview; + } + public function getTransactionTypes() { $types = array( PhabricatorTransactions::TYPE_COMMENT, @@ -225,11 +235,16 @@ abstract class PhabricatorApplicationTransactionEditor $xactions = $this->filterTransactions($object, $xactions); if (!$xactions) { - return $this; + return array(); } $xactions = $this->sortTransactions($xactions); + if ($this->getIsPreview()) { + $this->loadHandles($xactions); + return $xactions; + } + $comment_editor = id(new PhabricatorApplicationTransactionCommentEditor()) ->setActor($actor) ->setContentSource($this->getContentSource()); @@ -256,10 +271,8 @@ abstract class PhabricatorApplicationTransactionEditor } $object->saveTransaction(); - $this->loadHandles($xactions); - $mail = null; if ($this->supportsMail()) { $mail = $this->sendMail($object, $xactions); @@ -285,8 +298,8 @@ abstract class PhabricatorApplicationTransactionEditor private function loadHandles(array $xactions) { $phids = array(); - foreach ($xactions as $xaction) { - $phids[$xaction->getPHID()] = $xaction->getRequiredHandlePHIDs(); + foreach ($xactions as $key => $xaction) { + $phids[$key] = $xaction->getRequiredHandlePHIDs(); } $handles = array(); $merged = array_mergev($phids); @@ -295,11 +308,8 @@ abstract class PhabricatorApplicationTransactionEditor ->setViewer($this->requireActor()) ->loadHandles(); } - foreach ($xactions as $xaction) { - $xaction->setHandles( - array_select_keys( - $handles, - $phids[$xaction->getPHID()])); + foreach ($xactions as $key => $xaction) { + $xaction->setHandles(array_select_keys($handles, $phids[$key])); } } @@ -587,13 +597,18 @@ abstract class PhabricatorApplicationTransactionEditor return $xactions; } - if (!$this->getContinueOnNoEffect()) { + if (!$this->getContinueOnNoEffect() && !$this->getIsPreview()) { throw new PhabricatorApplicationTransactionNoEffectException( $no_effect, $any_effect, $has_comment); } + if (!$any_effect && !$has_comment) { + // If we only have empty comment transactions, just drop them all. + return array(); + } + foreach ($no_effect as $key => $xaction) { if ($xaction->getComment()) { $xaction->setTransactionType($type_comment); diff --git a/src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php b/src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php index cc5eede13d..1ddb9733eb 100644 --- a/src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php +++ b/src/applications/transactions/response/PhabricatorApplicationTransactionResponse.php @@ -6,6 +6,7 @@ final class PhabricatorApplicationTransactionResponse private $viewer; private $transactions; private $anchorOffset; + private $isPreview; protected function buildProxy() { return new AphrontAjaxResponse(); @@ -40,16 +41,26 @@ final class PhabricatorApplicationTransactionResponse return $this->viewer; } + public function setIsPreview($is_preview) { + $this->isPreview = $is_preview; + return $this; + } + public function reduceProxyResponse() { $view = id(new PhabricatorApplicationTransactionView()) - ->setViewer($this->getViewer()) - ->setTransactions($this->getTransactions()); + ->setUser($this->getViewer()) + ->setTransactions($this->getTransactions()) + ->setIsPreview($this->isPreview); if ($this->getAnchorOffset()) { $view->setAnchorOffset($this->getAnchorOffset()); } - $xactions = mpull($view->buildEvents(), 'render', 'getTransactionPHID'); + if ($this->isPreview) { + $xactions = mpull($view->buildEvents(), 'render'); + } else { + $xactions = mpull($view->buildEvents(), 'render', 'getTransactionPHID'); + } $content = array( 'xactions' => $xactions, diff --git a/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php b/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php new file mode 100644 index 0000000000..26e20c853c --- /dev/null +++ b/src/applications/transactions/view/PhabricatorApplicationTransactionCommentView.php @@ -0,0 +1,147 @@ +submitButtonName = $submit_button_name; + return $this; + } + + public function getSubmitButtonName() { + return $this->submitButtonName; + } + + public function setAction($action) { + $this->action = $action; + return $this; + } + + public function getAction() { + return $this->action; + } + + public function render() { + + $data = array(); + + $comment = $this->renderCommentPanel(); + + $preview = $this->renderPreviewPanel(); + + Javelin::initBehavior( + 'phabricator-transaction-comment-form', + array( + 'formID' => $this->getFormID(), + 'timelineID' => $this->getPreviewTimelineID(), + 'panelID' => $this->getPreviewPanelID(), + 'statusID' => $this->getStatusID(), + + 'loadingString' => pht('Loading Preview...'), + 'savingString' => pht('Saving Draft...'), + 'draftString' => pht('Saved Draft'), + + 'actionURI' => $this->getAction(), + )); + + return self::renderSingleView( + array( + $comment, + $preview, + )); + } + + private function renderCommentPanel() { + $status = phutil_render_tag( + 'div', + array( + 'id' => $this->getStatusID(), + ), + ''); + + return id(new AphrontFormView()) + ->setUser($this->getUser()) + ->setFlexible(true) + ->addSigil('transaction-append') + ->setWorkflow(true) + ->setAction($this->getAction()) + ->setID($this->getFormID()) + ->appendChild( + id(new PhabricatorRemarkupControl()) + ->setName('comment') + ->setLabel(pht('Comment')) + ->setUser($this->getUser())) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue($this->getSubmitButtonName())) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue($status)); + } + + private function renderPreviewPanel() { + + $preview = id(new PhabricatorTimelineView()) + ->setID($this->getPreviewTimelineID()); + + $header = phutil_render_tag( + 'div', + array( + 'class' => 'phabricator-timeline-preview-header', + ), + phutil_escape_html(pht('Preview'))); + + return phutil_render_tag( + 'div', + array( + 'id' => $this->getPreviewPanelID(), + 'style' => 'display: none', + ), + self::renderSingleView( + array( + $header, + $preview, + ))); + } + + private function getPreviewPanelID() { + if (!$this->previewPanelID) { + $this->previewPanelID = celerity_generate_unique_node_id(); + } + return $this->previewPanelID; + } + + private function getPreviewTimelineID() { + if (!$this->previewTimelineID) { + $this->previewTimelineID = celerity_generate_unique_node_id(); + } + return $this->previewTimelineID; + } + + private function getFormID() { + if (!$this->formID) { + $this->formID = celerity_generate_unique_node_id(); + } + return $this->formID; + } + + private function getStatusID() { + if (!$this->statusID) { + $this->statusID = celerity_generate_unique_node_id(); + } + return $this->statusID; + } + +} + diff --git a/src/applications/transactions/view/PhabricatorApplicationTransactionView.php b/src/applications/transactions/view/PhabricatorApplicationTransactionView.php index df4bfda588..07bcbafd47 100644 --- a/src/applications/transactions/view/PhabricatorApplicationTransactionView.php +++ b/src/applications/transactions/view/PhabricatorApplicationTransactionView.php @@ -5,11 +5,16 @@ */ class PhabricatorApplicationTransactionView extends AphrontView { - private $viewer; private $transactions; private $engine; private $anchorOffset = 1; private $showEditActions = true; + private $isPreview; + + public function setIsPreview($is_preview) { + $this->isPreview = $is_preview; + return $this; + } public function setShowEditActions($show_edit_actions) { $this->showEditActions = $show_edit_actions; @@ -36,16 +41,11 @@ class PhabricatorApplicationTransactionView extends AphrontView { return $this; } - public function setViewer(PhabricatorUser $viewer) { - $this->viewer = $viewer; - return $this; - } - public function buildEvents() { $field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT; $engine = $this->getOrBuildEngine(); - $viewer = $this->viewer; + $user = $this->getUser(); $anchor = $this->anchorOffset; $events = array(); @@ -55,22 +55,29 @@ class PhabricatorApplicationTransactionView extends AphrontView { } $event = id(new PhabricatorTimelineEventView()) - ->setViewer($viewer) + ->setUser($user) ->setTransactionPHID($xaction->getPHID()) ->setUserHandle($xaction->getHandle($xaction->getAuthorPHID())) ->setIcon($xaction->getIcon()) ->setColor($xaction->getColor()) - ->setTitle($xaction->getTitle()) - ->setDateCreated($xaction->getDateCreated()) - ->setContentSource($xaction->getContentSource()) - ->setAnchor($anchor); + ->setTitle($xaction->getTitle()); + + if ($this->isPreview) { + $event->setIsPreview(true); + } else { + $event + ->setDateCreated($xaction->getDateCreated()) + ->setContentSource($xaction->getContentSource()) + ->setAnchor($anchor); + + $anchor++; + } - $anchor++; $has_deleted_comment = $xaction->getComment() && $xaction->getComment()->getIsDeleted(); - if ($this->getShowEditActions()) { + if ($this->getShowEditActions() && !$this->isPreview) { if ($xaction->getCommentVersion() > 1) { $event->setIsEdited(true); } @@ -79,7 +86,7 @@ class PhabricatorApplicationTransactionView extends AphrontView { if ($xaction->hasComment() || $has_deleted_comment) { $has_edit_capability = PhabricatorPolicyFilter::hasCapability( - $viewer, + $user, $xaction, $can_edit); if ($has_edit_capability) { @@ -134,7 +141,7 @@ class PhabricatorApplicationTransactionView extends AphrontView { $field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT; $engine = id(new PhabricatorMarkupEngine()) - ->setViewer($this->viewer); + ->setViewer($this->getUser()); foreach ($this->transactions as $xaction) { if (!$xaction->hasComment()) { continue; diff --git a/src/view/layout/PhabricatorTimelineEventView.php b/src/view/layout/PhabricatorTimelineEventView.php index 7ee899cd53..f3534d7797 100644 --- a/src/view/layout/PhabricatorTimelineEventView.php +++ b/src/view/layout/PhabricatorTimelineEventView.php @@ -9,11 +9,11 @@ final class PhabricatorTimelineEventView extends AphrontView { private $classes = array(); private $contentSource; private $dateCreated; - private $viewer; private $anchor; private $isEditable; private $isEdited; private $transactionPHID; + private $isPreview; public function setTransactionPHID($transaction_phid) { $this->transactionPHID = $transaction_phid; @@ -33,6 +33,14 @@ final class PhabricatorTimelineEventView extends AphrontView { return $this->isEdited; } + public function setIsPreview($is_preview) { + $this->isPreview = $is_preview; + return $this; + } + + public function getIsPreview() { + return $this->isPreview; + } public function setIsEditable($is_editable) { $this->isEditable = $is_editable; @@ -43,15 +51,6 @@ final class PhabricatorTimelineEventView extends AphrontView { return $this->isEditable; } - public function setViewer(PhabricatorUser $viewer) { - $this->viewer = $viewer; - return $this; - } - - public function getViewer() { - return $this->viewer; - } - public function setDateCreated($date_created) { $this->dateCreated = $date_created; return $this; @@ -108,67 +107,7 @@ final class PhabricatorTimelineEventView extends AphrontView { $title = ''; } - $extra = array(); - $xaction_phid = $this->getTransactionPHID(); - - if ($this->getIsEdited()) { - $extra[] = javelin_render_tag( - 'a', - array( - 'href' => '/transactions/history/'.$xaction_phid.'/', - 'sigil' => 'workflow', - ), - pht('Edited')); - } - - if ($this->getIsEditable()) { - $extra[] = javelin_render_tag( - 'a', - array( - 'href' => '/transactions/edit/'.$xaction_phid.'/', - 'sigil' => 'workflow transaction-edit', - ), - pht('Edit')); - } - - $source = $this->getContentSource(); - if ($source) { - $extra[] = id(new PhabricatorContentSourceView()) - ->setContentSource($source) - ->setUser($this->getViewer()) - ->render(); - } - - if ($this->getDateCreated()) { - $date = phabricator_datetime( - $this->getDateCreated(), - $this->getViewer()); - if ($this->anchor) { - Javelin::initBehavior('phabricator-watch-anchor'); - - $anchor = id(new PhabricatorAnchorView()) - ->setAnchorName($this->anchor) - ->render(); - - $date = $anchor.phutil_render_tag( - 'a', - array( - 'href' => '#'.$this->anchor, - ), - $date); - } - $extra[] = $date; - } - - $extra = implode(' · ', $extra); - if ($extra) { - $extra = phutil_render_tag( - 'span', - array( - 'class' => 'phabricator-timeline-extra', - ), - $extra); - } + $extra = $this->renderExtra(); if ($title !== null || $extra !== null) { $title_classes = array(); @@ -286,4 +225,76 @@ final class PhabricatorTimelineEventView extends AphrontView { $content)); } + private function renderExtra() { + $extra = array(); + + if ($this->getIsPreview()) { + $extra[] = pht('PREVIEW'); + } else { + $xaction_phid = $this->getTransactionPHID(); + + + if ($this->getIsEdited()) { + $extra[] = javelin_render_tag( + 'a', + array( + 'href' => '/transactions/history/'.$xaction_phid.'/', + 'sigil' => 'workflow', + ), + pht('Edited')); + } + + if ($this->getIsEditable()) { + $extra[] = javelin_render_tag( + 'a', + array( + 'href' => '/transactions/edit/'.$xaction_phid.'/', + 'sigil' => 'workflow transaction-edit', + ), + pht('Edit')); + } + + $source = $this->getContentSource(); + if ($source) { + $extra[] = id(new PhabricatorContentSourceView()) + ->setContentSource($source) + ->setUser($this->getUser()) + ->render(); + } + + if ($this->getDateCreated()) { + $date = phabricator_datetime( + $this->getDateCreated(), + $this->getUser()); + if ($this->anchor) { + Javelin::initBehavior('phabricator-watch-anchor'); + + $anchor = id(new PhabricatorAnchorView()) + ->setAnchorName($this->anchor) + ->render(); + + $date = $anchor.phutil_render_tag( + 'a', + array( + 'href' => '#'.$this->anchor, + ), + $date); + } + $extra[] = $date; + } + } + + $extra = implode(' · ', $extra); + if ($extra) { + $extra = phutil_render_tag( + 'span', + array( + 'class' => 'phabricator-timeline-extra', + ), + $extra); + } + + return $extra; + } + } diff --git a/webroot/rsrc/css/layout/phabricator-timeline-view.css b/webroot/rsrc/css/layout/phabricator-timeline-view.css index 1521c85310..dbc3147767 100644 --- a/webroot/rsrc/css/layout/phabricator-timeline-view.css +++ b/webroot/rsrc/css/layout/phabricator-timeline-view.css @@ -245,3 +245,10 @@ background: rgba(255, 255, 0, 0.50); box-shadow: 0 0 3px 6px rgba(255, 255, 0, 0.50); } + +.phabricator-timeline-preview-header { + background: #e0e3ec; + color: #444444; + padding: 4px 1.25%; + border: solid #c0c5d1 1px 0; +} diff --git a/webroot/rsrc/js/application/transactions/behavior-transaction-comment-form.js b/webroot/rsrc/js/application/transactions/behavior-transaction-comment-form.js new file mode 100644 index 0000000000..5459584557 --- /dev/null +++ b/webroot/rsrc/js/application/transactions/behavior-transaction-comment-form.js @@ -0,0 +1,44 @@ +/** + * @provides javelin-behavior-phabricator-transaction-comment-form + * @requires javelin-behavior + * javelin-dom + * javelin-util + * phabricator-shaped-request + */ + +JX.behavior('phabricator-transaction-comment-form', function(config) { + + var form = JX.$(config.formID); + + var getdata = function() { + var obj = JX.DOM.convertFormToDictionary(form); + obj.__preview__ = 1; + return obj; + }; + + var onresponse = function(response) { + var panel = JX.$(config.panelID); + if (!response.xactions.length) { + JX.DOM.hide(panel); + } else { + JX.DOM.setContent( + JX.$(config.timelineID), + [ + JX.$H(response.spacer), + JX.$H(response.xactions.join(response.spacer)), + JX.$H(response.spacer), + ]); + JX.DOM.show(panel); + } + }; + + var request = new JX.PhabricatorShapedRequest( + config.actionURI, + onresponse, + getdata); + var trigger = JX.bind(request, request.trigger); + + JX.DOM.listen(form, 'keydown', null, trigger); + + request.start(); +});