From d96d515cc21ea02477b5c81faa2a6989b5f71459 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 31 May 2011 10:23:31 -0700 Subject: [PATCH] Add comment linking to Maniphest and Differential Summary: Allows you to link to comments with "D123#3" or "T123#3", then adds a pile of JS to try to make it not terrible. :/ The thing I'm trying to avoid here is when someone says "look at this! http://blog.com/#comment-239291" and you click and your browser jumps somewhere random and you have no idea which comment they meant. Since I really hate this, I've tried to avoid it by making sure the comment is always highlighted. Test Plan: Put T1#1 and D1#1 in remarkup and verified they linked properly. Clicked anchors on individual comments. Faked all comments hidden in Differential and verified they expanded on anchor or anchor change. Reviewed By: aran Reviewers: aran, tomo, mroch, jungejason, tuomaspelkonen CC: aran, epriestley Differential Revision: 383 --- externals/javelin | 2 +- src/__celerity_resource_map__.php | 119 ++++++++++-------- src/__phutil_library_map__.php | 6 +- .../login/PhabricatorLoginController.php | 2 +- .../DifferentialRevisionCommentView.php | 54 ++++++-- .../view/revisioncomment/__init__.php | 1 + .../DifferentialRevisionCommentListView.php | 5 +- .../ManiphestTransactionDetailView.php | 31 ++++- .../ManiphestTransactionListView.php | 4 +- src/docs/userguide/remarkup.diviner | 4 + .../CelerityStaticResourceResponse.php | 15 ++- .../PhabricatorRemarkupRuleDifferential.php | 14 +-- .../markuprule/differential/__init__.php | 2 +- .../PhabricatorRemarkupRuleManiphest.php | 14 +-- .../markuprule/maniphest/__init__.php | 2 +- .../PhabricatorRemarkupRuleObjectName.php | 57 +++++++++ .../markuprule/objectname/__init__.php | 13 ++ src/view/form/base/AphrontFormView.php | 9 +- .../differential/revision-comment.css | 20 ++- .../maniphest/transaction-detail.css | 15 ++- .../application/core/behavior-watch-anchor.js | 34 +++++ .../behavior-show-all-comments.js | 36 +++++- 22 files changed, 343 insertions(+), 116 deletions(-) create mode 100644 src/infrastructure/markup/remarkup/markuprule/objectname/PhabricatorRemarkupRuleObjectName.php create mode 100644 src/infrastructure/markup/remarkup/markuprule/objectname/__init__.php create mode 100644 webroot/rsrc/js/application/core/behavior-watch-anchor.js diff --git a/externals/javelin b/externals/javelin index 7ac64cd03d..c714cff45d 160000 --- a/externals/javelin +++ b/externals/javelin @@ -1 +1 @@ -Subproject commit 7ac64cd03d89d6d5f8c7f85b32c9611d3866ea2b +Subproject commit c714cff45db83fc8c34e82b7ec1155b7c442dc7b diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 93e039a88e..59b7cfc291 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -172,7 +172,7 @@ celerity_register_resource_map(array( ), 'differential-revision-comment-css' => array( - 'uri' => '/res/e3ea8c34/rsrc/css/application/differential/revision-comment.css', + 'uri' => '/res/e3539439/rsrc/css/application/differential/revision-comment.css', 'type' => 'css', 'requires' => array( @@ -188,6 +188,16 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/css/application/differential/revision-comment-list.css', ), + 0 => + array( + 'uri' => '/res/39de799e/rsrc/js/javelin/docs/Base.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-install', + ), + 'disk' => '/rsrc/js/javelin/docs/Base.js', + ), 'differential-revision-detail-css' => array( 'uri' => '/res/ea9de420/rsrc/css/application/differential/revision-detail.css', @@ -279,16 +289,6 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/javelin/lib/behavior.js', ), - 0 => - array( - 'uri' => '/res/39de799e/rsrc/js/javelin/docs/Base.js', - 'type' => 'js', - 'requires' => - array( - 0 => 'javelin-install', - ), - 'disk' => '/rsrc/js/javelin/docs/Base.js', - ), 'javelin-behavior-aphront-basic-tokenizer' => array( 'uri' => '/res/bce3961b/rsrc/js/application/core/behavior-tokenizer.js', @@ -424,7 +424,7 @@ celerity_register_resource_map(array( ), 'javelin-behavior-differential-show-all-comments' => array( - 'uri' => '/res/b7c7e1ee/rsrc/js/application/differential/behavior-show-all-comments.js', + 'uri' => '/res/bcc990f0/rsrc/js/application/differential/behavior-show-all-comments.js', 'type' => 'js', 'requires' => array( @@ -560,6 +560,19 @@ celerity_register_resource_map(array( ), 'disk' => '/rsrc/js/application/core/behavior-object-selector.js', ), + 'javelin-behavior-phabricator-watch-anchor' => + array( + 'uri' => '/res/bb6fa5b2/rsrc/js/application/core/behavior-watch-anchor.js', + 'type' => 'js', + 'requires' => + array( + 0 => 'javelin-behavior', + 1 => 'javelin-stratcom', + 2 => 'javelin-util', + 3 => 'javelin-dom', + ), + 'disk' => '/rsrc/js/application/core/behavior-watch-anchor.js', + ), 'javelin-behavior-workflow' => array( 'uri' => '/res/079f49c3/rsrc/js/application/core/behavior-workflow.js', @@ -574,7 +587,7 @@ celerity_register_resource_map(array( ), 'javelin-dom' => array( - 'uri' => '/res/770d72cd/rsrc/js/javelin/lib/DOM.js', + 'uri' => '/res/43e9e2de/rsrc/js/javelin/lib/DOM.js', 'type' => 'js', 'requires' => array( @@ -620,7 +633,7 @@ celerity_register_resource_map(array( ), 'javelin-magical-init' => array( - 'uri' => '/res/ce002e50/rsrc/js/javelin/core/init.js', + 'uri' => '/res/92e7f37e/rsrc/js/javelin/core/init.js', 'type' => 'js', 'requires' => array( @@ -641,7 +654,7 @@ celerity_register_resource_map(array( ), 'javelin-request' => array( - 'uri' => '/res/72a23e59/rsrc/js/javelin/lib/Request.js', + 'uri' => '/res/1ed0d596/rsrc/js/javelin/lib/Request.js', 'type' => 'js', 'requires' => array( @@ -811,7 +824,7 @@ celerity_register_resource_map(array( ), 'maniphest-transaction-detail-css' => array( - 'uri' => '/res/14758b00/rsrc/css/application/maniphest/transaction-detail.css', + 'uri' => '/res/7ee02b5e/rsrc/css/application/maniphest/transaction-detail.css', 'type' => 'css', 'requires' => array( @@ -1002,23 +1015,6 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/122a6b6d/workflow.pkg.js', 'type' => 'js', ), - '1ac25e8a' => - array ( - 'name' => 'differential.pkg.css', - 'symbols' => - array ( - 0 => 'differential-core-view-css', - 1 => 'differential-changeset-view-css', - 2 => 'differential-revision-detail-css', - 3 => 'differential-revision-history-css', - 4 => 'differential-table-of-contents-css', - 5 => 'differential-revision-comment-css', - 6 => 'differential-revision-add-comment-css', - 7 => 'differential-revision-comment-list-css', - ), - 'uri' => '/res/pkg/1ac25e8a/differential.pkg.css', - 'type' => 'css', - ), '33f413ef' => array ( 'name' => 'typeahead.pkg.js', @@ -1035,6 +1031,23 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/33f413ef/typeahead.pkg.js', 'type' => 'js', ), + '613cf273' => + array ( + 'name' => 'differential.pkg.css', + 'symbols' => + array ( + 0 => 'differential-core-view-css', + 1 => 'differential-changeset-view-css', + 2 => 'differential-revision-detail-css', + 3 => 'differential-revision-history-css', + 4 => 'differential-table-of-contents-css', + 5 => 'differential-revision-comment-css', + 6 => 'differential-revision-add-comment-css', + 7 => 'differential-revision-comment-list-css', + ), + 'uri' => '/res/pkg/613cf273/differential.pkg.css', + 'type' => 'css', + ), 'a6102fe7' => array ( 'name' => 'core.pkg.css', @@ -1059,7 +1072,7 @@ celerity_register_resource_map(array( 'uri' => '/res/pkg/a6102fe7/core.pkg.css', 'type' => 'css', ), - 'd985d27a' => + 'db95a6d0' => array ( 'name' => 'javelin.pkg.js', 'symbols' => @@ -1075,7 +1088,7 @@ celerity_register_resource_map(array( 8 => 'javelin-json', 9 => 'javelin-uri', ), - 'uri' => '/res/pkg/d985d27a/javelin.pkg.js', + 'uri' => '/res/pkg/db95a6d0/javelin.pkg.js', 'type' => 'js', ), 'ed383f69' => @@ -1104,16 +1117,16 @@ celerity_register_resource_map(array( 'aphront-table-view-css' => 'a6102fe7', 'aphront-tokenizer-control-css' => 'a6102fe7', 'aphront-typeahead-control-css' => 'a6102fe7', - 'differential-changeset-view-css' => '1ac25e8a', - 'differential-core-view-css' => '1ac25e8a', - 'differential-revision-add-comment-css' => '1ac25e8a', - 'differential-revision-comment-css' => '1ac25e8a', - 'differential-revision-comment-list-css' => '1ac25e8a', - 'differential-revision-detail-css' => '1ac25e8a', - 'differential-revision-history-css' => '1ac25e8a', - 'differential-table-of-contents-css' => '1ac25e8a', + 'differential-changeset-view-css' => '613cf273', + 'differential-core-view-css' => '613cf273', + 'differential-revision-add-comment-css' => '613cf273', + 'differential-revision-comment-css' => '613cf273', + 'differential-revision-comment-list-css' => '613cf273', + 'differential-revision-detail-css' => '613cf273', + 'differential-revision-history-css' => '613cf273', + 'differential-table-of-contents-css' => '613cf273', 'diffusion-commit-view-css' => '03ef179e', - 'javelin-behavior' => 'd985d27a', + 'javelin-behavior' => 'db95a6d0', 'javelin-behavior-aphront-basic-tokenizer' => '33f413ef', 'javelin-behavior-differential-diff-radios' => 'ed383f69', 'javelin-behavior-differential-edit-inline-comments' => 'ed383f69', @@ -1121,22 +1134,22 @@ celerity_register_resource_map(array( 'javelin-behavior-differential-populate' => 'ed383f69', 'javelin-behavior-differential-show-more' => 'ed383f69', 'javelin-behavior-workflow' => '122a6b6d', - 'javelin-dom' => 'd985d27a', - 'javelin-event' => 'd985d27a', - 'javelin-install' => 'd985d27a', - 'javelin-json' => 'd985d27a', + 'javelin-dom' => 'db95a6d0', + 'javelin-event' => 'db95a6d0', + 'javelin-install' => 'db95a6d0', + 'javelin-json' => 'db95a6d0', 'javelin-mask' => '122a6b6d', - 'javelin-request' => 'd985d27a', - 'javelin-stratcom' => 'd985d27a', + 'javelin-request' => 'db95a6d0', + 'javelin-stratcom' => 'db95a6d0', 'javelin-tokenizer' => '33f413ef', 'javelin-typeahead' => '33f413ef', 'javelin-typeahead-normalizer' => '33f413ef', 'javelin-typeahead-ondemand-source' => '33f413ef', 'javelin-typeahead-preloaded-source' => '33f413ef', 'javelin-typeahead-source' => '33f413ef', - 'javelin-uri' => 'd985d27a', - 'javelin-util' => 'd985d27a', - 'javelin-vector' => 'd985d27a', + 'javelin-uri' => 'db95a6d0', + 'javelin-util' => 'db95a6d0', + 'javelin-vector' => 'db95a6d0', 'javelin-workflow' => '122a6b6d', 'phabricator-core-buttons-css' => 'a6102fe7', 'phabricator-core-css' => 'a6102fe7', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 013a4e8002..81a9d42b03 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -410,6 +410,7 @@ phutil_register_library_map(array( 'PhabricatorRemarkupRuleDiffusion' => 'infrastructure/markup/remarkup/markuprule/diffusion', 'PhabricatorRemarkupRuleImageMacro' => 'infrastructure/markup/remarkup/markuprule/imagemacro', 'PhabricatorRemarkupRuleManiphest' => 'infrastructure/markup/remarkup/markuprule/maniphest', + 'PhabricatorRemarkupRuleObjectName' => 'infrastructure/markup/remarkup/markuprule/objectname', 'PhabricatorRemarkupRuleProxyImage' => 'infrastructure/markup/remarkup/markuprule/proxyimage', 'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/remarkup/markuprule/youtube', 'PhabricatorRepository' => 'applications/repository/storage/repository', @@ -841,10 +842,11 @@ phutil_register_library_map(array( 'PhabricatorProjectProfile' => 'PhabricatorProjectDAO', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorRedirectController' => 'PhabricatorController', - 'PhabricatorRemarkupRuleDifferential' => 'PhutilRemarkupRule', + 'PhabricatorRemarkupRuleDifferential' => 'PhabricatorRemarkupRuleObjectName', 'PhabricatorRemarkupRuleDiffusion' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule', - 'PhabricatorRemarkupRuleManiphest' => 'PhutilRemarkupRule', + 'PhabricatorRemarkupRuleManiphest' => 'PhabricatorRemarkupRuleObjectName', + 'PhabricatorRemarkupRuleObjectName' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleProxyImage' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', 'PhabricatorRepository' => 'PhabricatorRepositoryDAO', diff --git a/src/applications/auth/controller/login/PhabricatorLoginController.php b/src/applications/auth/controller/login/PhabricatorLoginController.php index 125bfcb408..6736eb01f2 100644 --- a/src/applications/auth/controller/login/PhabricatorLoginController.php +++ b/src/applications/auth/controller/login/PhabricatorLoginController.php @@ -42,7 +42,7 @@ class PhabricatorLoginController extends PhabricatorAuthController { $error_view = null; if ($password_auth) { $error = false; - $username = $request->getCookie('phusr'); + $username_or_email = $request->getCookie('phusr'); if ($request->isFormPost()) { $username_or_email = $request->getStr('username_or_email'); diff --git a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php index f037912c05..46170d46d6 100644 --- a/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php +++ b/src/applications/differential/view/revisioncomment/DifferentialRevisionCommentView.php @@ -25,6 +25,7 @@ final class DifferentialRevisionCommentView extends AphrontView { private $inlines; private $changesets; private $target; + private $commentNumber; public function setComment($comment) { $this->comment = $comment; @@ -61,6 +62,11 @@ final class DifferentialRevisionCommentView extends AphrontView { $this->target = $target; } + public function setCommentNumber($comment_number) { + $this->commentNumber = $comment_number; + return $this; + } + public function render() { require_celerity_resource('phabricator-remarkup-css'); @@ -78,6 +84,24 @@ final class DifferentialRevisionCommentView extends AphrontView { $date = date('F jS, Y g:i:s A', $comment->getDateCreated()); } + $info = array($date); + + $comment_anchor = null; + $num = $this->commentNumber; + if ($num) { + Javelin::initBehavior('phabricator-watch-anchor'); + $info[] = phutil_render_tag( + 'a', + array( + 'name' => 'comment-'.$num, + 'href' => '#comment-'.$num, + ), + 'Comment D'.$comment->getRevisionID().'#'.$num); + $comment_anchor = 'anchor-comment-'.$num; + } + + $info = implode(' · ', $info); + $author = $this->handles[$comment->getAuthorPHID()]; $author_link = $author->renderLink(); @@ -189,21 +213,25 @@ final class DifferentialRevisionCommentView extends AphrontView { $background = "background-image: url('{$uri}');"; } - return - '
'. - '
'. - '
'.$date.'
'. - '
'.$title.'
'. - '
'. - '
'. - '
'. - '
'. - $content. - '
'. - $inline_render. + return phutil_render_tag( + 'div', + array( + 'class' => "differential-comment {$action_class}", + 'id' => $comment_anchor, + ), + '
'. + ''.$info.''. + ''.$title.''. + '
'. + '
'. + '
'. + '
'. + '
'. + $content. '
'. + $inline_render. '
'. - '
'; + '
'); } } diff --git a/src/applications/differential/view/revisioncomment/__init__.php b/src/applications/differential/view/revisioncomment/__init__.php index e6fd906027..e4667c0379 100644 --- a/src/applications/differential/view/revisioncomment/__init__.php +++ b/src/applications/differential/view/revisioncomment/__init__.php @@ -8,6 +8,7 @@ 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('phutil', 'markup'); diff --git a/src/applications/differential/view/revisioncommentlist/DifferentialRevisionCommentListView.php b/src/applications/differential/view/revisioncommentlist/DifferentialRevisionCommentListView.php index de1ded72a2..23a24b0141 100644 --- a/src/applications/differential/view/revisioncommentlist/DifferentialRevisionCommentListView.php +++ b/src/applications/differential/view/revisioncommentlist/DifferentialRevisionCommentListView.php @@ -63,7 +63,7 @@ final class DifferentialRevisionCommentListView extends AphrontView { $inlines = mgroup($this->inlines, 'getCommentID'); - + $num = 1; $html = array(); foreach ($this->comments as $comment) { $view = new DifferentialRevisionCommentView(); @@ -73,6 +73,7 @@ final class DifferentialRevisionCommentListView extends AphrontView { $view->setInlineComments(idx($inlines, $comment->getID(), array())); $view->setChangesets($this->changesets); $view->setTargetDiff($this->target); + $view->setCommentNumber($num++); $html[] = $view->render(); } @@ -158,7 +159,7 @@ final class DifferentialRevisionCommentListView extends AphrontView { } return - '
'. + '
'. implode("\n", $header). $hidden. implode("\n", $visible). diff --git a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php index 7c76590db5..1258c9b4e2 100644 --- a/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php +++ b/src/applications/maniphest/view/transactiondetail/ManiphestTransactionDetailView.php @@ -23,6 +23,7 @@ class ManiphestTransactionDetailView extends AphrontView { private $markupEngine; private $forEmail; private $preview; + private $commentNumber; private $renderSummaryOnly; private $renderFullSummary; @@ -65,6 +66,11 @@ class ManiphestTransactionDetailView extends AphrontView { return $this->renderFullSummary; } + public function setCommentNumber($comment_number) { + $this->commentNumber = $comment_number; + return $this; + } + public function renderForEmail($with_date) { $this->forEmail = true; @@ -174,16 +180,37 @@ class ManiphestTransactionDetailView extends AphrontView { $timestamp = phabricator_format_timestamp($transaction->getDateCreated()); } + $info = array(); + $info[] = $timestamp; + + + $comment_anchor = null; + $num = $this->commentNumber; + if ($num) { + Javelin::initBehavior('phabricator-watch-anchor'); + $info[] = javelin_render_tag( + 'a', + array( + 'name' => 'comment-'.$num, + 'href' => '#comment-'.$num, + ), + 'Comment T'.$any_transaction->getTaskID().'#'.$num); + $comment_anchor = 'anchor-comment-'.$num; + } + + $info = implode(' · ', $info); + return phutil_render_tag( 'div', array( - 'class' => "maniphest-transaction-detail-container", + 'class' => "maniphest-transaction-detail-container", 'style' => "background-image: url('".$author->getImageURI()."')", + 'id' => $comment_anchor, ), '
'. '
'. '
'. - $timestamp. + $info. '
'. $descs. '
'. diff --git a/src/applications/maniphest/view/transactionlist/ManiphestTransactionListView.php b/src/applications/maniphest/view/transactionlist/ManiphestTransactionListView.php index 7ee4b38af5..ef95eecb0b 100644 --- a/src/applications/maniphest/view/transactionlist/ManiphestTransactionListView.php +++ b/src/applications/maniphest/view/transactionlist/ManiphestTransactionListView.php @@ -77,17 +77,19 @@ class ManiphestTransactionListView extends AphrontView { $groups[] = $group; } + $sequence = 1; foreach ($groups as $group) { $view = new ManiphestTransactionDetailView(); $view->setTransactionGroup($group); $view->setHandles($this->handles); $view->setMarkupEngine($this->markupEngine); $view->setPreview($this->preview); + $view->setCommentNumber($sequence++); $views[] = $view->render(); } return - '
'. + '
'. implode("\n", $views). '
'; } diff --git a/src/docs/userguide/remarkup.diviner b/src/docs/userguide/remarkup.diviner index 42263f91f6..03f511bdfb 100644 --- a/src/docs/userguide/remarkup.diviner +++ b/src/docs/userguide/remarkup.diviner @@ -98,6 +98,10 @@ by mentioning the name of an object: # You must specify at least 7 characters of the hash. T123 # Link to Maniphest task T123 +You can also link directly to a comment in Maniphest and Differential: + + T123#4 # Link to comment #4 of T123 + = Quoting Text = To quote text, preface it with an ">": diff --git a/src/infrastructure/celerity/response/CelerityStaticResourceResponse.php b/src/infrastructure/celerity/response/CelerityStaticResourceResponse.php index ee8af7dd16..8ef6be945c 100644 --- a/src/infrastructure/celerity/response/CelerityStaticResourceResponse.php +++ b/src/infrastructure/celerity/response/CelerityStaticResourceResponse.php @@ -43,9 +43,22 @@ final class CelerityStaticResourceResponse { return $this->metadataBlock; } + /** + * Register a behavior for initialization. NOTE: if $config is empty, + * a behavior will execute only once even if it is initialized multiple times. + * If $config is nonempty, the behavior will be invoked once for each config. + */ public function initBehavior($behavior, array $config = array()) { $this->requireResource('javelin-behavior-'.$behavior); - $this->behaviors[$behavior][] = $config; + + if (empty($this->behaviors[$behavior])) { + $this->behaviors[$behavior] = array(); + } + + if ($config) { + $this->behaviors[$behavior][] = $config; + } + return $this; } diff --git a/src/infrastructure/markup/remarkup/markuprule/differential/PhabricatorRemarkupRuleDifferential.php b/src/infrastructure/markup/remarkup/markuprule/differential/PhabricatorRemarkupRuleDifferential.php index fe3399bf30..0e2bdb2558 100644 --- a/src/infrastructure/markup/remarkup/markuprule/differential/PhabricatorRemarkupRuleDifferential.php +++ b/src/infrastructure/markup/remarkup/markuprule/differential/PhabricatorRemarkupRuleDifferential.php @@ -20,18 +20,10 @@ * @group markup */ class PhabricatorRemarkupRuleDifferential - extends PhutilRemarkupRule { + extends PhabricatorRemarkupRuleObjectName { - public function apply($text) { - return preg_replace_callback( - '@\bD(\d+)\b@', - array($this, 'markupDifferentialLink'), - $text); - } - - public function markupDifferentialLink($matches) { - return $this->getEngine()->storeText( - 'D'.$matches[1].''); + protected function getObjectNamePrefix() { + return 'D'; } } diff --git a/src/infrastructure/markup/remarkup/markuprule/differential/__init__.php b/src/infrastructure/markup/remarkup/markuprule/differential/__init__.php index 236c22dc6c..a16e23b5d3 100644 --- a/src/infrastructure/markup/remarkup/markuprule/differential/__init__.php +++ b/src/infrastructure/markup/remarkup/markuprule/differential/__init__.php @@ -6,7 +6,7 @@ -phutil_require_module('phutil', 'markup/engine/remarkup/markuprule/base'); +phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/objectname'); phutil_require_source('PhabricatorRemarkupRuleDifferential.php'); diff --git a/src/infrastructure/markup/remarkup/markuprule/maniphest/PhabricatorRemarkupRuleManiphest.php b/src/infrastructure/markup/remarkup/markuprule/maniphest/PhabricatorRemarkupRuleManiphest.php index bde8068f9a..accf97bfdd 100644 --- a/src/infrastructure/markup/remarkup/markuprule/maniphest/PhabricatorRemarkupRuleManiphest.php +++ b/src/infrastructure/markup/remarkup/markuprule/maniphest/PhabricatorRemarkupRuleManiphest.php @@ -20,18 +20,10 @@ * @group markup */ class PhabricatorRemarkupRuleManiphest - extends PhutilRemarkupRule { + extends PhabricatorRemarkupRuleObjectName { - public function apply($text) { - return preg_replace_callback( - '@\bT(\d+)\b@', - array($this, 'markupManiphestLink'), - $text); - } - - public function markupManiphestLink($matches) { - return $this->getEngine()->storeText( - 'T'.$matches[1].''); + protected function getObjectNamePrefix() { + return 'T'; } } diff --git a/src/infrastructure/markup/remarkup/markuprule/maniphest/__init__.php b/src/infrastructure/markup/remarkup/markuprule/maniphest/__init__.php index 711a1e8a7f..be4009a688 100644 --- a/src/infrastructure/markup/remarkup/markuprule/maniphest/__init__.php +++ b/src/infrastructure/markup/remarkup/markuprule/maniphest/__init__.php @@ -6,7 +6,7 @@ -phutil_require_module('phutil', 'markup/engine/remarkup/markuprule/base'); +phutil_require_module('phabricator', 'infrastructure/markup/remarkup/markuprule/objectname'); phutil_require_source('PhabricatorRemarkupRuleManiphest.php'); diff --git a/src/infrastructure/markup/remarkup/markuprule/objectname/PhabricatorRemarkupRuleObjectName.php b/src/infrastructure/markup/remarkup/markuprule/objectname/PhabricatorRemarkupRuleObjectName.php new file mode 100644 index 0000000000..62b7ea8cc4 --- /dev/null +++ b/src/infrastructure/markup/remarkup/markuprule/objectname/PhabricatorRemarkupRuleObjectName.php @@ -0,0 +1,57 @@ +getObjectNamePrefix(); + return preg_replace_callback( + "@\b{$prefix}(\d+)(?:#(\d+))?\b@", + array($this, 'markupObjectNameLink'), + $text); + } + + public function markupObjectNameLink($matches) { + $prefix = $this->getObjectNamePrefix(); + $id = $matches[1]; + + if (isset($matches[2])) { + $comment_id = $matches[2]; + $href = "/{$prefix}{$id}#comment-{$comment_id}"; + $text = "{$prefix}{$id}#{$comment_id}"; + } else { + $href = "/{$prefix}{$id}"; + $text = "{$prefix}{$id}"; + } + + return $this->getEngine()->storeText( + phutil_render_tag( + 'a', + array( + 'href' => $href, + ), + $text)); + } + +} diff --git a/src/infrastructure/markup/remarkup/markuprule/objectname/__init__.php b/src/infrastructure/markup/remarkup/markuprule/objectname/__init__.php new file mode 100644 index 0000000000..fc12aa560c --- /dev/null +++ b/src/infrastructure/markup/remarkup/markuprule/objectname/__init__.php @@ -0,0 +1,13 @@ +