diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 5ff960b7ed..44c6321e90 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -27,7 +27,7 @@ celerity_register_resource_map(array( ), 'aphront-panel-view-css' => array( - 'uri' => '/res/fe62e634/rsrc/css/aphront/panel-view.css', + 'uri' => '/res/63672373/rsrc/css/aphront/panel-view.css', 'type' => 'css', 'requires' => array( @@ -36,7 +36,7 @@ celerity_register_resource_map(array( ), 'aphront-request-failure-view-css' => array( - 'uri' => '/res/d7df3b42/rsrc/css/aphront/request-failure-view.css', + 'uri' => '/res/97b8337a/rsrc/css/aphront/request-failure-view.css', 'type' => 'css', 'requires' => array( @@ -89,6 +89,15 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/application/base/standard-page-view.css', ), + 'differential-revision-add-comment-css' => + array( + 'uri' => '/res/623fef21/rsrc/css/application/differential/add-comment.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/application/differential/add-comment.css', + ), 'differential-changeset-view-css' => array( 'uri' => '/res/658d181a/rsrc/css/application/differential/changeset-view.css', @@ -207,6 +216,16 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/behavior-tokenizer.js', ), + 'javelin-behavior-differential-feedback-preview' => + array( + 'uri' => '/res/34fbb670/rsrc/js/application/differential/behavior-comment-preview.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-lib-dev', + ), + 'disk' => '/rsrc/js/application/differential/behavior-comment-preview.js', + ), 'javelin-behavior-differential-populate' => array( 'uri' => '/res/9982573c/rsrc/js/application/differential/behavior-populate.js', @@ -274,7 +293,7 @@ celerity_register_resource_map(array( ), array ( 'packages' => array ( - '364a306c' => + 'd348c79d' => array ( 'name' => 'core.pkg.css', 'symbols' => @@ -291,7 +310,7 @@ celerity_register_resource_map(array( 9 => 'aphront-typeahead-control-css', 10 => 'phabricator-directory-css', ), - 'uri' => '/res/pkg/364a306c/core.pkg.css', + 'uri' => '/res/pkg/d348c79d/core.pkg.css', 'type' => 'css', ), '69b11588' => @@ -311,17 +330,17 @@ celerity_register_resource_map(array( ), 'reverse' => array ( - 'phabricator-core-css' => '364a306c', - 'phabricator-core-buttons-css' => '364a306c', - 'phabricator-standard-page-view' => '364a306c', - 'aphront-dialog-view-css' => '364a306c', - 'aphront-form-view-css' => '364a306c', - 'aphront-panel-view-css' => '364a306c', - 'aphront-side-nav-view-css' => '364a306c', - 'aphront-table-view-css' => '364a306c', - 'aphront-tokenizer-control-css' => '364a306c', - 'aphront-typeahead-control-css' => '364a306c', - 'phabricator-directory-css' => '364a306c', + 'phabricator-core-css' => 'd348c79d', + 'phabricator-core-buttons-css' => 'd348c79d', + 'phabricator-standard-page-view' => 'd348c79d', + 'aphront-dialog-view-css' => 'd348c79d', + 'aphront-form-view-css' => 'd348c79d', + 'aphront-panel-view-css' => 'd348c79d', + 'aphront-side-nav-view-css' => 'd348c79d', + 'aphront-table-view-css' => 'd348c79d', + 'aphront-tokenizer-control-css' => 'd348c79d', + 'aphront-typeahead-control-css' => 'd348c79d', + 'phabricator-directory-css' => 'd348c79d', 'differential-core-view-css' => '69b11588', 'differential-changeset-view-css' => '69b11588', 'differential-revision-detail-css' => '69b11588', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 261d63ec43..9a5aacd4d4 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -80,6 +80,7 @@ phutil_register_library_map(array( 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', + 'DifferentialCommentPreviewController' => 'applications/differential/controller/commentpreview', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', @@ -253,6 +254,7 @@ phutil_register_library_map(array( 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', + 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index a7dbbe58cf..046b99f300 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -87,7 +87,7 @@ class AphrontDefaultApplicationConfiguration 'revision/edit/(?:(?\d+)/)?$' => 'DifferentialRevisionEditController', 'comment/' => array( - 'preview/$' => 'DifferentialCommentPreviewController', + 'preview/(?\d+)/$' => 'DifferentialCommentPreviewController', 'save/$' => 'DifferentialCommentSaveController', 'inline/' => array( 'preview/$' => 'DifferentialInlineCommentPreviewController', diff --git a/src/applications/conduit/method/differential/creatediff/__init__.php b/src/applications/conduit/method/differential/creatediff/__init__.php index f43bd3996d..160deafd17 100644 --- a/src/applications/conduit/method/differential/creatediff/__init__.php +++ b/src/applications/conduit/method/differential/creatediff/__init__.php @@ -14,6 +14,7 @@ phutil_require_module('phabricator', 'applications/differential/constants/revisi phutil_require_module('phabricator', 'applications/differential/constants/unitstatus'); phutil_require_module('phabricator', 'applications/differential/storage/diff'); phutil_require_module('phabricator', 'applications/differential/storage/revision'); +phutil_require_module('phabricator', 'infrastructure/env'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/differential/controller/commentpreview/DifferentialCommentPreviewController.php b/src/applications/differential/controller/commentpreview/DifferentialCommentPreviewController.php new file mode 100644 index 0000000000..96ef550e44 --- /dev/null +++ b/src/applications/differential/controller/commentpreview/DifferentialCommentPreviewController.php @@ -0,0 +1,54 @@ +id = $data['id']; + } + + public function processRequest() { + + $request = $this->getRequest(); + + $author_phid = $request->getUser()->getPHID(); + + $handles = id(new PhabricatorObjectHandleData(array($author_phid))) + ->loadHandles(); + + $factory = new DifferentialMarkupEngineFactory(); + $engine = $factory->newDifferentialCommentMarkupEngine(); + + $comment = new DifferentialComment(); + $comment->setContent($request->getStr('content')); + $comment->setAction($request->getStr('action')); + $comment->setAuthorPHID($author_phid); + + $view = new DifferentialRevisionCommentView(); + $view->setComment($comment); + $view->setHandles($handles); + $view->setMarkupEngine($engine); + $view->setPreview(true); + + return id(new AphrontAjaxResponse()) + ->setContent($view->render()); + } + +} diff --git a/src/applications/differential/controller/commentpreview/__init__.php b/src/applications/differential/controller/commentpreview/__init__.php new file mode 100644 index 0000000000..0d1ba25e1e --- /dev/null +++ b/src/applications/differential/controller/commentpreview/__init__.php @@ -0,0 +1,19 @@ +revision; $actions = array(); @@ -58,19 +61,39 @@ final class DifferentialAddCommentView extends AphrontView { id(new AphrontFormSelectControl()) ->setLabel('Action') ->setName('action') + ->setID('comment-action') ->setOptions($actions)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setName('comment') + ->setID('comment-content') ->setLabel('Comment')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Comment')); + Javelin::initBehavior( + 'differential-feedback-preview', + array( + 'uri' => '/differential/comment/preview/'.$revision->getID().'/', + 'preview' => 'comment-preview', + 'action' => 'comment-action', + 'content' => 'comment-content', + )); + return - '
'. - '

Add Comment

'. - $form->render(). + '
'. + '
'. + '

Add Comment

'. + $form->render(). + '
'. + '
'. + '
'. + ''. + 'Loading comment preview...'. + ''. + '
'. + '
'. '
'; } } diff --git a/src/applications/differential/view/addcomment/__init__.php b/src/applications/differential/view/addcomment/__init__.php index 67d21d5c5e..1597617bf0 100644 --- a/src/applications/differential/view/addcomment/__init__.php +++ b/src/applications/differential/view/addcomment/__init__.php @@ -7,6 +7,8 @@ phutil_require_module('phabricator', 'applications/differential/constants/action'); +phutil_require_module('phabricator', 'infrastructure/celerity/api'); +phutil_require_module('phabricator', 'infrastructure/javelin/api'); phutil_require_module('phabricator', 'view/base'); phutil_require_module('phabricator', 'view/form/base'); phutil_require_module('phabricator', 'view/form/control/submit'); diff --git a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php index cb9bab5604..2ef005669a 100644 --- a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php +++ b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php @@ -21,6 +21,7 @@ final class DifferentialRevisionCommentView extends AphrontView { private $comment; private $handles; private $markupEngine; + private $preview; public function setComment($comment) { $this->comment = $comment; @@ -37,6 +38,11 @@ final class DifferentialRevisionCommentView extends AphrontView { return $this; } + public function setPreview($preview) { + $this->preview = $preview; + return $this; + } + public function render() { require_celerity_resource('phabricator-remarkup-css'); @@ -48,7 +54,11 @@ final class DifferentialRevisionCommentView extends AphrontView { $action_class = 'differential-comment-action-'.phutil_escape_html($action); - $date = date('F jS, Y g:i:s A', $comment->getDateCreated()); + if ($this->preview) { + $date = 'COMMENT PREVIEW'; + } else { + $date = date('F jS, Y g:i:s A', $comment->getDateCreated()); + } $author = $this->handles[$comment->getAuthorPHID()]; $author_link = $author->renderLink(); @@ -70,12 +80,12 @@ final class DifferentialRevisionCommentView extends AphrontView { "

{$author_link} {$verb} this revision.

". '
'; } - + $background = null; $uri = $author->getImageURI(); if ($uri) { $background = "background-image: url('{$uri}');"; - } + } return '
'. diff --git a/src/view/form/control/base/AphrontFormControl.php b/src/view/form/control/base/AphrontFormControl.php index b35988d64b..48c494b2d8 100755 --- a/src/view/form/control/base/AphrontFormControl.php +++ b/src/view/form/control/base/AphrontFormControl.php @@ -24,6 +24,16 @@ abstract class AphrontFormControl extends AphrontView { private $name; private $value; private $disabled; + private $id; + + public function setID($id) { + $this->id = $id; + return $this; + } + + public function getID() { + return $this->id; + } public function setLabel($label) { $this->label = $label; diff --git a/src/view/form/control/password/AphrontFormPasswordControl.php b/src/view/form/control/password/AphrontFormPasswordControl.php index cb0f259fbb..ae02ea73f4 100755 --- a/src/view/form/control/password/AphrontFormPasswordControl.php +++ b/src/view/form/control/password/AphrontFormPasswordControl.php @@ -30,6 +30,7 @@ class AphrontFormPasswordControl extends AphrontFormControl { 'name' => $this->getName(), 'value' => $this->getValue(), 'disabled' => $this->getDisabled() ? 'disabled' : null, + 'id' => $this->getID(), )); } diff --git a/src/view/form/control/select/AphrontFormSelectControl.php b/src/view/form/control/select/AphrontFormSelectControl.php index d2ffaad74d..fdb6a58080 100755 --- a/src/view/form/control/select/AphrontFormSelectControl.php +++ b/src/view/form/control/select/AphrontFormSelectControl.php @@ -50,6 +50,7 @@ class AphrontFormSelectControl extends AphrontFormControl { array( 'name' => $this->getName(), 'disabled' => $this->getDisabled() ? 'disabled' : null, + 'id' => $this->getID(), ), implode("\n", $options)); } diff --git a/src/view/form/control/text/AphrontFormTextControl.php b/src/view/form/control/text/AphrontFormTextControl.php index f8265188af..185ffd6a7e 100755 --- a/src/view/form/control/text/AphrontFormTextControl.php +++ b/src/view/form/control/text/AphrontFormTextControl.php @@ -30,6 +30,7 @@ class AphrontFormTextControl extends AphrontFormControl { 'name' => $this->getName(), 'value' => $this->getValue(), 'disabled' => $this->getDisabled() ? 'disabled' : null, + 'id' => $this->getID(), )); } diff --git a/src/view/form/control/textarea/AphrontFormTextAreaControl.php b/src/view/form/control/textarea/AphrontFormTextAreaControl.php index 55ec143551..36b64a8b53 100755 --- a/src/view/form/control/textarea/AphrontFormTextAreaControl.php +++ b/src/view/form/control/textarea/AphrontFormTextAreaControl.php @@ -20,7 +20,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl { const HEIGHT_VERY_SHORT = 'very-short'; const HEIGHT_SHORT = 'short'; - + private $height; public function setHeight($height) { @@ -48,6 +48,7 @@ class AphrontFormTextAreaControl extends AphrontFormControl { 'name' => $this->getName(), 'disabled' => $this->getDisabled() ? 'disabled' : null, 'class' => $height_class, + 'id' => $this->getID(), ), phutil_escape_html($this->getValue())); } diff --git a/webroot/rsrc/css/application/differential/add-comment.css b/webroot/rsrc/css/application/differential/add-comment.css new file mode 100644 index 0000000000..99be1e9f7f --- /dev/null +++ b/webroot/rsrc/css/application/differential/add-comment.css @@ -0,0 +1,23 @@ +/** + * @provides differential-revision-add-comment-css + */ + +.differential-add-comment-panel .aphront-form-view { + background: #fffff5; +} + +.differential-add-comment-panel .differential-panel { + margin-bottom: 0; +} + +.differential-comment-preview { + background: #f0f0f0; + border-bottom: 1px solid #aaaaaa; + margin-bottom: 2em; + max-width: 1120px; + padding: 15px 20px; +} + +.differential-comment-preview .differential-loading-text { + color: #aaaaaa; +} diff --git a/webroot/rsrc/js/application/differential/behavior-comment-preview.js b/webroot/rsrc/js/application/differential/behavior-comment-preview.js new file mode 100644 index 0000000000..41bdec070b --- /dev/null +++ b/webroot/rsrc/js/application/differential/behavior-comment-preview.js @@ -0,0 +1,50 @@ +/** + * @provides javelin-behavior-differential-feedback-preview + * @requires javelin-lib-dev + */ + +JX.behavior('differential-feedback-preview', function(config) { + + var action = JX.$(config.action); + var content = JX.$(config.content); + var preview = JX.$(config.preview); + + var aval = null;//action.value; + var cval = null;//content.value; + var defer = null; + var min = null; + var request = null; + + function check() { + if (request || (min && (new Date().getTime() < min))) { + // Waiting on an async or just got one back, rate-limit. + return; + } + + defer && defer.stop(); + + if (action.value !== aval || content.value !== cval) { + aval = action.value; + cval = content.value; + + request = new JX.Request(config.uri, function(r) { + preview && JX.DOM.setContent(preview, JX.HTML(r)); + min = new Date().getTime() + 500; + defer && defer.stop(); + defer = JX.defer(check, 500); + }); + request.listen('finally', function() { request = null; }); + request.setData({action : aval, content : cval}); + // If we don't get a response back soon, retry on the next action. + request.setTimeout(2000); + request.send(); + } else { + defer = JX.defer(check, 2000); + } + } + + JX.DOM.listen(content, 'keydown', null, check); + JX.DOM.listen(action, 'change', null, check); + + check(); +});