[ Index ] |
PHP Cross Reference of Phabricator |
[Summary view] [Print] [Text view]
1 <?php 2 3 final class PhabricatorMentionRemarkupRule extends PhutilRemarkupRule { 4 5 const KEY_RULE_MENTION = 'rule.mention'; 6 const KEY_RULE_MENTION_ORIGINAL = 'rule.mention.original'; 7 8 const KEY_MENTIONED = 'phabricator.mentioned-user-phids'; 9 10 11 // NOTE: The negative lookbehind prevents matches like "mail@lists", while 12 // allowing constructs like "@tomo/@mroch". Since we now allow periods in 13 // usernames, we can't resonably distinguish that "@company.com" isn't a 14 // username, so we'll incorrectly pick it up, but there's little to be done 15 // about that. We forbid terminal periods so that we can correctly capture 16 // "@joe" instead of "@joe." in "Hey, @joe.". 17 // 18 // We disallow "@@joe" because it creates a false positive in the common 19 // construction "l@@k", made popular by eBay. 20 const REGEX = '/(?<!\w|@)@([a-zA-Z0-9._-]*[a-zA-Z0-9_-])/'; 21 22 public function apply($text) { 23 return preg_replace_callback( 24 self::REGEX, 25 array($this, 'markupMention'), 26 $text); 27 } 28 29 protected function markupMention($matches) { 30 $engine = $this->getEngine(); 31 32 if ($engine->isTextMode()) { 33 return $engine->storeText($matches[0]); 34 } 35 36 $token = $engine->storeText(''); 37 38 // Store the original text exactly so we can preserve casing if it doesn't 39 // resolve into a username. 40 $original_key = self::KEY_RULE_MENTION_ORIGINAL; 41 $original = $engine->getTextMetadata($original_key, array()); 42 $original[$token] = $matches[1]; 43 $engine->setTextMetadata($original_key, $original); 44 45 $metadata_key = self::KEY_RULE_MENTION; 46 $metadata = $engine->getTextMetadata($metadata_key, array()); 47 $username = strtolower($matches[1]); 48 if (empty($metadata[$username])) { 49 $metadata[$username] = array(); 50 } 51 $metadata[$username][] = $token; 52 $engine->setTextMetadata($metadata_key, $metadata); 53 54 return $token; 55 } 56 57 public function didMarkupText() { 58 $engine = $this->getEngine(); 59 60 $metadata_key = self::KEY_RULE_MENTION; 61 $metadata = $engine->getTextMetadata($metadata_key, array()); 62 if (empty($metadata)) { 63 // No mentions, or we already processed them. 64 return; 65 } 66 67 $original_key = self::KEY_RULE_MENTION_ORIGINAL; 68 $original = $engine->getTextMetadata($original_key, array()); 69 70 $usernames = array_keys($metadata); 71 72 $users = id(new PhabricatorPeopleQuery()) 73 ->setViewer($this->getEngine()->getConfig('viewer')) 74 ->withUsernames($usernames) 75 ->execute(); 76 77 if ($users) { 78 $user_statuses = id(new PhabricatorCalendarEvent()) 79 ->loadCurrentStatuses(mpull($users, 'getPHID')); 80 $user_statuses = mpull($user_statuses, null, 'getUserPHID'); 81 } else { 82 $user_statuses = array(); 83 } 84 85 $actual_users = array(); 86 87 $mentioned_key = self::KEY_MENTIONED; 88 $mentioned = $engine->getTextMetadata($mentioned_key, array()); 89 foreach ($users as $row) { 90 $actual_users[strtolower($row->getUserName())] = $row; 91 $mentioned[$row->getPHID()] = $row->getPHID(); 92 } 93 94 $engine->setTextMetadata($mentioned_key, $mentioned); 95 96 foreach ($metadata as $username => $tokens) { 97 $exists = isset($actual_users[$username]); 98 99 if ($exists) { 100 $user = $actual_users[$username]; 101 Javelin::initBehavior('phabricator-hovercards'); 102 103 $user_href = '/p/'.$user->getUserName().'/'; 104 105 if ($engine->isHTMLMailMode()) { 106 $user_href = PhabricatorEnv::getProductionURI($user_href); 107 $tag = phutil_tag( 108 'a', 109 array( 110 'href' => $user_href, 111 'style' => 'background-color: #f1f7ff; 112 border-color: #f1f7ff; 113 border: 1px solid transparent; 114 border-radius: 3px; 115 color: #19558d; 116 font-weight: bold; 117 padding: 0 4px;', 118 ), 119 '@'.$user->getUserName()); 120 } else { 121 $tag = id(new PHUITagView()) 122 ->setType(PHUITagView::TYPE_PERSON) 123 ->setPHID($user->getPHID()) 124 ->setName('@'.$user->getUserName()) 125 ->setHref($user_href); 126 127 if (!$user->isUserActivated()) { 128 $tag->setDotColor(PHUITagView::COLOR_GREY); 129 } else { 130 $status = idx($user_statuses, $user->getPHID()); 131 if ($status) { 132 $status = $status->getStatus(); 133 if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 134 $tag->setDotColor(PHUITagView::COLOR_RED); 135 } else if ($status == PhabricatorCalendarEvent::STATUS_AWAY) { 136 $tag->setDotColor(PHUITagView::COLOR_ORANGE); 137 } 138 } 139 } 140 } 141 142 foreach ($tokens as $token) { 143 $engine->overwriteStoredText($token, $tag); 144 } 145 } else { 146 // NOTE: The structure here is different from the 'exists' branch, 147 // because we want to preserve the original text capitalization and it 148 // may differ for each token. 149 foreach ($tokens as $token) { 150 $tag = phutil_tag( 151 'span', 152 array( 153 'class' => 'phabricator-remarkup-mention-unknown', 154 ), 155 '@'.idx($original, $token, $username)); 156 $engine->overwriteStoredText($token, $tag); 157 } 158 } 159 } 160 161 // Don't re-process these mentions. 162 $engine->setTextMetadata($metadata_key, array()); 163 } 164 165 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Nov 30 09:20:46 2014 | Cross-referenced by PHPXref 0.7.1 |