Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/auth/view/PhabricatorAuthAccountView.php b/src/applications/auth/view/PhabricatorAuthAccountView.php
index 8eb73144aa..3f04281c8f 100644
--- a/src/applications/auth/view/PhabricatorAuthAccountView.php
+++ b/src/applications/auth/view/PhabricatorAuthAccountView.php
@@ -1,116 +1,117 @@
<?php
final class PhabricatorAuthAccountView extends AphrontView {
private $externalAccount;
private $provider;
public function setExternalAccount(
PhabricatorExternalAccount $external_account) {
$this->externalAccount = $external_account;
return $this;
}
public function setAuthProvider(PhabricatorAuthProvider $provider) {
$this->provider = $provider;
return $this;
}
public function render() {
$account = $this->externalAccount;
$provider = $this->provider;
require_celerity_resource('auth-css');
$content = array();
$dispname = $account->getDisplayName();
$username = $account->getUsername();
$realname = $account->getRealName();
$use_name = null;
if (strlen($dispname)) {
$use_name = $dispname;
} else if (strlen($username) && strlen($realname)) {
$use_name = $username.' ('.$realname.')';
} else if (strlen($username)) {
$use_name = $username;
} else if (strlen($realname)) {
$use_name = $realname;
} else {
$use_name = $account->getAccountID();
}
$content[] = phutil_tag(
'div',
array(
'class' => 'auth-account-view-name',
),
$use_name);
if ($provider) {
$prov_name = pht('%s Account', $provider->getProviderName());
} else {
$prov_name = pht('"%s" Account', $account->getProviderType());
}
$content[] = phutil_tag(
'div',
array(
'class' => 'auth-account-view-provider-name',
),
array(
$prov_name,
" \xC2\xB7 ",
$account->getAccountID(),
));
$account_uri = $account->getAccountURI();
if (strlen($account_uri)) {
// Make sure we don't link a "javascript:" URI if a user somehow
// managed to get one here.
if (PhabricatorEnv::isValidRemoteURIForLink($account_uri)) {
$account_uri = phutil_tag(
'a',
array(
'href' => $account_uri,
'target' => '_blank',
+ 'rel' => 'noreferrer',
),
$account_uri);
}
$content[] = phutil_tag(
'div',
array(
'class' => 'auth-account-view-account-uri',
),
$account_uri);
}
$image_file = $account->getProfileImageFile();
$xform = PhabricatorFileTransform::getTransformByKey(
PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
$image_uri = $image_file->getURIForTransform($xform);
list($x, $y) = $xform->getTransformedDimensions($image_file);
$profile_image = phutil_tag(
'div',
array(
'class' => 'auth-account-view-profile-image',
'style' => 'background-image: url('.$image_uri.');',
));
return phutil_tag(
'div',
array(
'class' => 'auth-account-view',
),
array(
$profile_image,
$content,
));
}
}
diff --git a/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
index 6174603c84..bd52ec5bc2 100644
--- a/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
+++ b/src/applications/calendar/import/PhabricatorCalendarICSURIImportEngine.php
@@ -1,120 +1,121 @@
<?php
final class PhabricatorCalendarICSURIImportEngine
extends PhabricatorCalendarICSImportEngine {
const ENGINETYPE = 'icsuri';
public function getImportEngineName() {
return pht('Import .ics URI');
}
public function getImportEngineTypeName() {
return pht('.ics URI');
}
public function getImportEngineHint() {
return pht('Import or subscribe to a calendar in .ics format by URI.');
}
public function supportsTriggers(PhabricatorCalendarImport $import) {
return true;
}
public function appendImportProperties(
PhabricatorUser $viewer,
PhabricatorCalendarImport $import,
PHUIPropertyListView $properties) {
$uri_key = PhabricatorCalendarImportICSURITransaction::PARAMKEY_URI;
$uri = $import->getParameter($uri_key);
// Since the URI may contain a secret hash, don't show it to users who
// can not edit the import.
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
$import,
PhabricatorPolicyCapability::CAN_EDIT);
if (!$can_edit) {
$uri_display = phutil_tag('em', array(), pht('Restricted'));
} else if (!PhabricatorEnv::isValidRemoteURIForLink($uri)) {
$uri_display = $uri;
} else {
$uri_display = phutil_tag(
'a',
array(
'href' => $uri,
'target' => '_blank',
+ 'rel' => 'noreferrer',
),
$uri);
}
$properties->addProperty(pht('Source URI'), $uri_display);
}
public function newEditEngineFields(
PhabricatorEditEngine $engine,
PhabricatorCalendarImport $import) {
$fields = array();
if ($engine->getIsCreate()) {
$fields[] = id(new PhabricatorTextEditField())
->setKey('uri')
->setLabel(pht('URI'))
->setDescription(pht('URI to import.'))
->setTransactionType(
PhabricatorCalendarImportICSURITransaction::TRANSACTIONTYPE)
->setConduitDescription(pht('URI to import.'))
->setConduitTypeDescription(pht('New URI.'));
}
return $fields;
}
public function getDisplayName(PhabricatorCalendarImport $import) {
return pht('ICS URI');
}
public function importEventsFromSource(
PhabricatorUser $viewer,
PhabricatorCalendarImport $import,
$should_queue) {
$uri_key = PhabricatorCalendarImportICSURITransaction::PARAMKEY_URI;
$uri = $import->getParameter($uri_key);
PhabricatorSystemActionEngine::willTakeAction(
array($viewer->getPHID()),
new PhabricatorFilesOutboundRequestAction(),
1);
$file = PhabricatorFile::newFromFileDownload(
$uri,
array(
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
'authorPHID' => $import->getAuthorPHID(),
'canCDN' => true,
));
$import->newLogMessage(
PhabricatorCalendarImportFetchLogType::LOGTYPE,
array(
'file.phid' => $file->getPHID(),
));
$data = $file->loadFileData();
if ($should_queue && $this->shouldQueueDataImport($data)) {
return $this->queueDataImport($import, $data);
}
return $this->importICSData($viewer, $import, $data);
}
public function canDisable(
PhabricatorUser $viewer,
PhabricatorCalendarImport $import) {
return true;
}
}
diff --git a/src/applications/files/markup/PhabricatorImageRemarkupRule.php b/src/applications/files/markup/PhabricatorImageRemarkupRule.php
index 9e91bdc096..36089dc57e 100644
--- a/src/applications/files/markup/PhabricatorImageRemarkupRule.php
+++ b/src/applications/files/markup/PhabricatorImageRemarkupRule.php
@@ -1,75 +1,69 @@
<?php
final class PhabricatorImageRemarkupRule extends PhutilRemarkupRule {
public function getPriority() {
return 200.0;
}
public function apply($text) {
return preg_replace_callback(
'@{(image|img) ((?:[^}\\\\]+|\\\\.)*)}@m',
array($this, 'markupImage'),
$text);
}
public function markupImage(array $matches) {
if (!$this->isFlatText($matches[0])) {
return $matches[0];
}
$args = array();
$defaults = array(
'uri' => null,
'alt' => null,
- 'href' => null,
'width' => null,
'height' => null,
);
$trimmed_match = trim($matches[2]);
if ($this->isURI($trimmed_match)) {
$args['uri'] = new PhutilURI($trimmed_match);
} else {
$parser = new PhutilSimpleOptions();
$keys = $parser->parse($trimmed_match);
$uri_key = '';
foreach (array('src', 'uri', 'url') as $key) {
if (array_key_exists($key, $keys)) {
$uri_key = $key;
}
}
if ($uri_key) {
$args['uri'] = new PhutilURI($keys[$uri_key]);
}
$args += $keys;
}
$args += $defaults;
- if ($args['href'] && !PhabricatorEnv::isValidURIForLink($args['href'])) {
- $args['href'] = null;
- }
-
if ($args['uri']) {
$src_uri = id(new PhutilURI('/file/imageproxy/'))
->setQueryParam('uri', (string)$args['uri']);
$img = $this->newTag(
'img',
array(
'src' => $src_uri,
'alt' => $args['alt'],
- 'href' => $args['href'],
'width' => $args['width'],
'height' => $args['height'],
- ));
+ ));
return $this->getEngine()->storeText($img);
} else {
return $matches[0];
}
}
private function isURI($uri_string) {
// Very simple check to make sure it starts with either http or https.
// If it does, we'll try to treat it like a valid URI
return preg_match('~^https?\:\/\/.*\z~i', $uri_string);
}
}
diff --git a/src/applications/harbormaster/artifact/HarbormasterURIArtifact.php b/src/applications/harbormaster/artifact/HarbormasterURIArtifact.php
index 345621f0f5..93f7564033 100644
--- a/src/applications/harbormaster/artifact/HarbormasterURIArtifact.php
+++ b/src/applications/harbormaster/artifact/HarbormasterURIArtifact.php
@@ -1,119 +1,120 @@
<?php
final class HarbormasterURIArtifact extends HarbormasterArtifact {
const ARTIFACTCONST = 'uri';
public function getArtifactTypeName() {
return pht('URI');
}
public function getArtifactTypeSummary() {
return pht('Stores a URI.');
}
public function getArtifactTypeDescription() {
return pht(
"Stores a URI.\n\n".
"With `ui.external`, you can use this artifact type to add links to ".
"build results in an external build system.");
}
public function getArtifactParameterSpecification() {
return array(
'uri' => 'string',
'name' => 'optional string',
'ui.external' => 'optional bool',
);
}
public function readArtifactHTTPParameter($key, $value) {
// TODO: This is hacky and artifact parameters should be replaced more
// broadly, likely with EditFields. See T11887.
switch ($key) {
case 'ui.external':
return (bool)$value;
}
return $value;
}
public function getArtifactParameterDescriptions() {
return array(
'uri' => pht('The URI to store.'),
'name' => pht('Optional label for this URI.'),
'ui.external' => pht(
'If true, display this URI in the UI as an link to '.
'additional build details in an external build system.'),
);
}
public function getArtifactDataExample() {
return array(
'uri' => 'https://buildserver.mycompany.com/build/123/',
'name' => pht('View External Build Results'),
'ui.external' => true,
);
}
public function renderArtifactSummary(PhabricatorUser $viewer) {
return $this->renderLink();
}
public function isExternalLink() {
$artifact = $this->getBuildArtifact();
return (bool)$artifact->getProperty('ui.external', false);
}
public function renderLink() {
$artifact = $this->getBuildArtifact();
$uri = $artifact->getProperty('uri');
try {
$this->validateURI($uri);
} catch (Exception $ex) {
return pht('<Invalid URI>');
}
$name = $artifact->getProperty('name', $uri);
return phutil_tag(
'a',
array(
'href' => $uri,
'target' => '_blank',
+ 'rel' => 'noreferrer',
),
$name);
}
public function willCreateArtifact(PhabricatorUser $actor) {
$artifact = $this->getBuildArtifact();
$uri = $artifact->getProperty('uri');
$this->validateURI($uri);
}
private function validateURI($raw_uri) {
$uri = new PhutilURI($raw_uri);
$protocol = $uri->getProtocol();
if (!strlen($protocol)) {
throw new Exception(
pht(
'Unable to identify the protocol for URI "%s". URIs must be '.
'fully qualified and have an identifiable protocol.',
$raw_uri));
}
$protocol_key = 'uri.allowed-protocols';
$protocols = PhabricatorEnv::getEnvConfig($protocol_key);
if (empty($protocols[$protocol])) {
throw new Exception(
pht(
'URI "%s" does not have an allowable protocol. Configure '.
'protocols in `%s`. Allowed protocols are: %s.',
$raw_uri,
$protocol_key,
implode(', ', array_keys($protocols))));
}
}
}
diff --git a/src/applications/nuance/item/NuanceGitHubEventItemType.php b/src/applications/nuance/item/NuanceGitHubEventItemType.php
index b8bfb3ccab..1f6249f222 100644
--- a/src/applications/nuance/item/NuanceGitHubEventItemType.php
+++ b/src/applications/nuance/item/NuanceGitHubEventItemType.php
@@ -1,450 +1,452 @@
<?php
final class NuanceGitHubEventItemType
extends NuanceItemType {
const ITEMTYPE = 'github.event';
private $externalObject;
private $externalActor;
public function getItemTypeDisplayName() {
return pht('GitHub Event');
}
public function getItemTypeDisplayIcon() {
return 'fa-github';
}
public function getItemDisplayName(NuanceItem $item) {
return $this->newRawEvent($item)->getEventFullTitle();
}
public function canUpdateItems() {
return true;
}
protected function updateItemFromSource(NuanceItem $item) {
$viewer = $this->getViewer();
$is_dirty = false;
$xobj = $this->reloadExternalObject($item);
if ($xobj) {
$item->setItemProperty('doorkeeper.xobj.phid', $xobj->getPHID());
$is_dirty = true;
}
$actor = $this->reloadExternalActor($item);
if ($actor) {
$item->setRequestorPHID($actor->getPHID());
$is_dirty = true;
}
if ($item->getStatus() == NuanceItem::STATUS_IMPORTING) {
$item->setStatus(NuanceItem::STATUS_ROUTING);
$is_dirty = true;
}
if ($is_dirty) {
$item->save();
}
}
private function getDoorkeeperActorRef(NuanceItem $item) {
$raw = $this->newRawEvent($item);
$user_id = $raw->getActorGitHubUserID();
if (!$user_id) {
return null;
}
$ref_type = DoorkeeperBridgeGitHubUser::OBJTYPE_GITHUB_USER;
return $this->newDoorkeeperRef()
->setObjectType($ref_type)
->setObjectID($user_id);
}
private function getDoorkeeperRef(NuanceItem $item) {
$raw = $this->newRawEvent($item);
$full_repository = $raw->getRepositoryFullName();
if (!strlen($full_repository)) {
return null;
}
if ($raw->isIssueEvent()) {
$ref_type = DoorkeeperBridgeGitHubIssue::OBJTYPE_GITHUB_ISSUE;
$issue_number = $raw->getIssueNumber();
$full_ref = "{$full_repository}#{$issue_number}";
} else {
return null;
}
return $this->newDoorkeeperRef()
->setObjectType($ref_type)
->setObjectID($full_ref);
}
private function newDoorkeeperRef() {
return id(new DoorkeeperObjectRef())
->setApplicationType(DoorkeeperBridgeGitHub::APPTYPE_GITHUB)
->setApplicationDomain(DoorkeeperBridgeGitHub::APPDOMAIN_GITHUB);
}
private function reloadExternalObject(NuanceItem $item, $local = false) {
$ref = $this->getDoorkeeperRef($item);
if (!$ref) {
return null;
}
$xobj = $this->reloadExternalRef($item, $ref, $local);
if ($xobj) {
$this->externalObject = $xobj;
}
return $xobj;
}
private function reloadExternalActor(NuanceItem $item, $local = false) {
$ref = $this->getDoorkeeperActorRef($item);
if (!$ref) {
return null;
}
$xobj = $this->reloadExternalRef($item, $ref, $local);
if ($xobj) {
$this->externalActor = $xobj;
}
return $xobj;
}
private function reloadExternalRef(
NuanceItem $item,
DoorkeeperObjectRef $ref,
$local) {
$source = $item->getSource();
$token = $source->getSourceProperty('github.token');
$token = new PhutilOpaqueEnvelope($token);
$viewer = $this->getViewer();
$ref = id(new DoorkeeperImportEngine())
->setViewer($viewer)
->setRefs(array($ref))
->setThrowOnMissingLink(true)
->setContextProperty('github.token', $token)
->needLocalOnly($local)
->executeOne();
if ($ref->getSyncFailed()) {
$xobj = null;
} else {
$xobj = $ref->getExternalObject();
}
return $xobj;
}
private function getExternalObject(NuanceItem $item) {
if ($this->externalObject === null) {
$xobj = $this->reloadExternalObject($item, $local = true);
if ($xobj) {
$this->externalObject = $xobj;
} else {
$this->externalObject = false;
}
}
if ($this->externalObject) {
return $this->externalObject;
}
return null;
}
private function getExternalActor(NuanceItem $item) {
if ($this->externalActor === null) {
$xobj = $this->reloadExternalActor($item, $local = true);
if ($xobj) {
$this->externalActor = $xobj;
} else {
$this->externalActor = false;
}
}
if ($this->externalActor) {
return $this->externalActor;
}
return null;
}
private function newRawEvent(NuanceItem $item) {
$type = $item->getItemProperty('api.type');
$raw = $item->getItemProperty('api.raw', array());
return NuanceGitHubRawEvent::newEvent($type, $raw);
}
public function getItemActions(NuanceItem $item) {
$actions = array();
$xobj = $this->getExternalObject($item);
if ($xobj) {
$actions[] = $this->newItemAction($item, 'reload')
->setName(pht('Reload from GitHub'))
->setIcon('fa-refresh')
->setWorkflow(true)
->setRenderAsForm(true);
}
$actions[] = $this->newItemAction($item, 'sync')
->setName(pht('Import to Maniphest'))
->setIcon('fa-anchor')
->setWorkflow(true)
->setRenderAsForm(true);
$actions[] = $this->newItemAction($item, 'raw')
->setName(pht('View Raw Event'))
->setWorkflow(true)
->setIcon('fa-code');
return $actions;
}
public function getItemCurtainPanels(NuanceItem $item) {
$viewer = $this->getViewer();
$panels = array();
$xobj = $this->getExternalObject($item);
if ($xobj) {
$xobj_phid = $xobj->getPHID();
$task = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withBridgedObjectPHIDs(array($xobj_phid))
->executeOne();
if ($task) {
$panels[] = $this->newCurtainPanel($item)
->setHeaderText(pht('Imported As'))
->appendChild($viewer->renderHandle($task->getPHID()));
}
}
$xactor = $this->getExternalActor($item);
if ($xactor) {
$panels[] = $this->newCurtainPanel($item)
->setHeaderText(pht('GitHub Actor'))
->appendChild($viewer->renderHandle($xactor->getPHID()));
}
return $panels;
}
protected function handleAction(NuanceItem $item, $action) {
$viewer = $this->getViewer();
$controller = $this->getController();
switch ($action) {
case 'raw':
$raw = array(
'api.type' => $item->getItemProperty('api.type'),
'api.raw' => $item->getItemProperty('api.raw'),
);
$raw_output = id(new PhutilJSON())->encodeFormatted($raw);
$raw_box = id(new AphrontFormTextAreaControl())
->setCustomClass('PhabricatorMonospaced')
->setLabel(pht('Raw Event'))
->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)
->setValue($raw_output);
$form = id(new AphrontFormView())
->appendChild($raw_box);
return $controller->newDialog()
->setWidth(AphrontDialogView::WIDTH_FULL)
->setTitle(pht('GitHub Raw Event'))
->appendForm($form)
->addCancelButton($item->getURI(), pht('Done'));
case 'sync':
case 'reload':
$item->issueCommand($viewer->getPHID(), $action);
return id(new AphrontRedirectResponse())->setURI($item->getURI());
}
return null;
}
protected function newItemView(NuanceItem $item) {
$content = array();
$content[] = $this->newGitHubEventItemPropertyBox($item);
return $content;
}
private function newGitHubEventItemPropertyBox($item) {
$viewer = $this->getViewer();
$property_list = id(new PHUIPropertyListView())
->setViewer($viewer);
$event = $this->newRawEvent($item);
$property_list->addProperty(
pht('GitHub Event ID'),
$event->getID());
$event_uri = $event->getURI();
if ($event_uri && PhabricatorEnv::isValidRemoteURIForLink($event_uri)) {
$event_uri = phutil_tag(
'a',
array(
'href' => $event_uri,
+ 'target' => '_blank',
+ 'rel' => 'noreferrer',
),
$event_uri);
}
if ($event_uri) {
$property_list->addProperty(
pht('GitHub Event URI'),
$event_uri);
}
return id(new PHUIObjectBoxView())
->setHeaderText(pht('Event Properties'))
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
->appendChild($property_list);
}
protected function handleCommand(
NuanceItem $item,
NuanceItemCommand $command) {
// TODO: This code is no longer reachable, and has moved to
// CommandImplementation subclasses.
$action = $command->getCommand();
switch ($action) {
case 'sync':
return $this->syncItem($item, $command);
case 'reload':
$this->reloadExternalObject($item);
return true;
}
return null;
}
private function syncItem(
NuanceItem $item,
NuanceItemCommand $command) {
$xobj_phid = $item->getItemProperty('doorkeeper.xobj.phid');
if (!$xobj_phid) {
throw new Exception(
pht(
'Unable to sync: no external object PHID.'));
}
// TODO: Write some kind of marker to prevent double-synchronization.
$viewer = $this->getViewer();
$xobj = id(new DoorkeeperExternalObjectQuery())
->setViewer($viewer)
->withPHIDs(array($xobj_phid))
->executeOne();
if (!$xobj) {
throw new Exception(
pht(
'Unable to sync: failed to load object "%s".',
$xobj_phid));
}
$acting_as_phid = $this->getActingAsPHID($item);
$xactions = array();
$task = id(new ManiphestTaskQuery())
->setViewer($viewer)
->withBridgedObjectPHIDs(array($xobj_phid))
->executeOne();
if (!$task) {
$task = ManiphestTask::initializeNewTask($viewer)
->setAuthorPHID($acting_as_phid)
->setBridgedObjectPHID($xobj_phid);
$title = $xobj->getProperty('task.title');
if (!strlen($title)) {
$title = pht('Nuance Item %d Task', $item->getID());
}
$description = $xobj->getProperty('task.description');
$created = $xobj->getProperty('task.created');
$state = $xobj->getProperty('task.state');
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(
ManiphestTaskTitleTransaction::TRANSACTIONTYPE)
->setNewValue($title)
->setDateCreated($created);
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(
ManiphestTaskDescriptionTransaction::TRANSACTIONTYPE)
->setNewValue($description)
->setDateCreated($created);
$task->setDateCreated($created);
// TODO: Synchronize state.
}
$event = $this->newRawEvent($item);
$comment = $event->getComment();
if (strlen($comment)) {
$xactions[] = id(new ManiphestTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new ManiphestTransactionComment())
->setContent($comment));
}
$agent_phid = $command->getAuthorPHID();
$source = $this->newContentSource($item, $agent_phid);
$editor = id(new ManiphestTransactionEditor())
->setActor($viewer)
->setActingAsPHID($acting_as_phid)
->setContentSource($source)
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true);
$xactions = $editor->applyTransactions($task, $xactions);
return array(
'objectPHID' => $task->getPHID(),
'xactionPHIDs' => mpull($xactions, 'getPHID'),
);
}
protected function getActingAsPHID(NuanceItem $item) {
$actor_phid = $item->getRequestorPHID();
if ($actor_phid) {
return $actor_phid;
}
return parent::getActingAsPHID($item);
}
}
diff --git a/src/applications/phurl/remarkup/PhabricatorPhurlLinkRemarkupRule.php b/src/applications/phurl/remarkup/PhabricatorPhurlLinkRemarkupRule.php
index 4ef59b300c..c4ffc366da 100644
--- a/src/applications/phurl/remarkup/PhabricatorPhurlLinkRemarkupRule.php
+++ b/src/applications/phurl/remarkup/PhabricatorPhurlLinkRemarkupRule.php
@@ -1,74 +1,75 @@
<?php
final class PhabricatorPhurlLinkRemarkupRule extends PhutilRemarkupRule {
public function getPriority() {
return 200.0;
}
public function apply($text) {
// `((123))` remarkup link to `/u/123`
// `((alias))` remarkup link to `/u/alias`
return preg_replace_callback(
'/\(\(([^ )]+)\)\)/',
array($this, 'markupLink'),
$text);
}
public function markupLink(array $matches) {
$engine = $this->getEngine();
$viewer = $engine->getConfig('viewer');
$text_mode = $engine->isTextMode();
$html_mode = $engine->isHTMLMailMode();
if (!$this->isFlatText($matches[0])) {
return $matches[0];
}
$ref = $matches[1];
$monogram = null;
$is_monogram = '/^U(?P<id>[1-9]\d*)/';
$query = id(new PhabricatorPhurlURLQuery())
->setViewer($viewer);
if (preg_match($is_monogram, $ref, $monogram)) {
$query->withIDs(array($monogram[1]));
} else if (ctype_digit($ref)) {
$query->withIDs(array($ref));
} else {
$query->withAliases(array($ref));
}
$phurl = $query->executeOne();
if (!$phurl) {
return $matches[0];
}
$uri = $phurl->getRedirectURI();
$name = $phurl->getDisplayName();
if ($text_mode || $html_mode) {
$uri = PhabricatorEnv::getProductionURI($uri);
}
if ($text_mode) {
return pht(
'%s <%s>',
$name,
$uri);
} else {
$link = phutil_tag(
'a',
array(
'href' => $uri,
'target' => '_blank',
+ 'rel' => 'noreferrer',
),
$name);
}
return $this->getEngine()->storeText($link);
}
}
diff --git a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
index f790816c8b..0b6a2f330e 100644
--- a/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
+++ b/src/applications/search/menuitem/PhabricatorLinkProfileMenuItem.php
@@ -1,158 +1,159 @@
<?php
final class PhabricatorLinkProfileMenuItem
extends PhabricatorProfileMenuItem {
const MENUITEMKEY = 'link';
const FIELD_URI = 'uri';
const FIELD_NAME = 'name';
const FIELD_TOOLTIP = 'tooltip';
public function getMenuItemTypeIcon() {
return 'fa-link';
}
public function getMenuItemTypeName() {
return pht('Link');
}
public function canAddToObject($object) {
return true;
}
public function getDisplayName(
PhabricatorProfileMenuItemConfiguration $config) {
return $this->getLinkName($config);
}
public function buildEditEngineFields(
PhabricatorProfileMenuItemConfiguration $config) {
return array(
id(new PhabricatorTextEditField())
->setKey(self::FIELD_NAME)
->setLabel(pht('Name'))
->setIsRequired(true)
->setValue($this->getLinkName($config)),
id(new PhabricatorTextEditField())
->setKey(self::FIELD_URI)
->setLabel(pht('URI'))
->setIsRequired(true)
->setValue($this->getLinkURI($config)),
id(new PhabricatorTextEditField())
->setKey(self::FIELD_TOOLTIP)
->setLabel(pht('Tooltip'))
->setValue($this->getLinkTooltip($config)),
id(new PhabricatorIconSetEditField())
->setKey('icon')
->setLabel(pht('Icon'))
->setIconSet(new PhabricatorProfileMenuItemIconSet())
->setValue($this->getLinkIcon($config)),
);
}
private function getLinkName(
PhabricatorProfileMenuItemConfiguration $config) {
return $config->getMenuItemProperty('name');
}
private function getLinkIcon(
PhabricatorProfileMenuItemConfiguration $config) {
return $config->getMenuItemProperty('icon', 'link');
}
private function getLinkURI(
PhabricatorProfileMenuItemConfiguration $config) {
return $config->getMenuItemProperty('uri');
}
private function getLinkTooltip(
PhabricatorProfileMenuItemConfiguration $config) {
return $config->getMenuItemProperty('tooltip');
}
private function isValidLinkURI($uri) {
return PhabricatorEnv::isValidURIForLink($uri);
}
protected function newNavigationMenuItems(
PhabricatorProfileMenuItemConfiguration $config) {
$icon = $this->getLinkIcon($config);
$name = $this->getLinkName($config);
$href = $this->getLinkURI($config);
$tooltip = $this->getLinkTooltip($config);
if (!$this->isValidLinkURI($href)) {
$href = '#';
}
$icon_object = id(new PhabricatorProfileMenuItemIconSet())
->getIcon($icon);
if ($icon_object) {
$icon_class = $icon_object->getIcon();
} else {
$icon_class = 'fa-link';
}
$item = $this->newItem()
->setHref($href)
->setName($name)
->setIcon($icon_class)
- ->setTooltip($tooltip);
+ ->setTooltip($tooltip)
+ ->setRel('noreferrer');
return array(
$item,
);
}
public function validateTransactions(
PhabricatorProfileMenuItemConfiguration $config,
$field_key,
$value,
array $xactions) {
$viewer = $this->getViewer();
$errors = array();
if ($field_key == self::FIELD_NAME) {
if ($this->isEmptyTransaction($value, $xactions)) {
$errors[] = $this->newRequiredError(
pht('You must choose a link name.'),
$field_key);
}
}
if ($field_key == self::FIELD_URI) {
if ($this->isEmptyTransaction($value, $xactions)) {
$errors[] = $this->newRequiredError(
pht('You must choose a URI to link to.'),
$field_key);
}
foreach ($xactions as $xaction) {
$new = $xaction['new'];
if (!$new) {
continue;
}
if ($new === $value) {
continue;
}
if (!$this->isValidLinkURI($new)) {
$errors[] = $this->newInvalidError(
pht(
'URI "%s" is not a valid link URI. It should be a full, valid '.
'URI beginning with a protocol like "%s".',
$new,
'https://'),
$xaction['xaction']);
}
}
}
return $errors;
}
}
diff --git a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php
index c2b9d6543c..146f34ab07 100644
--- a/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php
+++ b/src/infrastructure/customfield/standard/PhabricatorStandardCustomFieldLink.php
@@ -1,105 +1,109 @@
<?php
final class PhabricatorStandardCustomFieldLink
extends PhabricatorStandardCustomField {
public function getFieldType() {
return 'link';
}
public function buildFieldIndexes() {
$indexes = array();
$value = $this->getFieldValue();
if (strlen($value)) {
$indexes[] = $this->newStringIndex($value);
}
return $indexes;
}
public function renderPropertyViewValue(array $handles) {
$value = $this->getFieldValue();
if (!strlen($value)) {
return null;
}
if (!PhabricatorEnv::isValidRemoteURIForLink($value)) {
return $value;
}
return phutil_tag(
'a',
- array('href' => $value, 'target' => '_blank'),
+ array(
+ 'href' => $value,
+ 'target' => '_blank',
+ 'rel' => 'noreferrer',
+ ),
$value);
}
public function readApplicationSearchValueFromRequest(
PhabricatorApplicationSearchEngine $engine,
AphrontRequest $request) {
return $request->getStr($this->getFieldKey());
}
public function applyApplicationSearchConstraintToQuery(
PhabricatorApplicationSearchEngine $engine,
PhabricatorCursorPagedPolicyAwareQuery $query,
$value) {
if (is_string($value) && !strlen($value)) {
return;
}
$value = (array)$value;
if ($value) {
$query->withApplicationSearchContainsConstraint(
$this->newStringIndex(null),
$value);
}
}
public function appendToApplicationSearchForm(
PhabricatorApplicationSearchEngine $engine,
AphrontFormView $form,
$value) {
$form->appendChild(
id(new AphrontFormTextControl())
->setLabel($this->getFieldName())
->setName($this->getFieldKey())
->setValue($value));
}
public function shouldAppearInHerald() {
return true;
}
public function getHeraldFieldConditions() {
return array(
HeraldAdapter::CONDITION_CONTAINS,
HeraldAdapter::CONDITION_NOT_CONTAINS,
HeraldAdapter::CONDITION_IS,
HeraldAdapter::CONDITION_IS_NOT,
HeraldAdapter::CONDITION_REGEXP,
HeraldAdapter::CONDITION_NOT_REGEXP,
);
}
public function getHeraldFieldStandardType() {
return HeraldField::STANDARD_TEXT;
}
protected function getHTTPParameterType() {
return new AphrontStringHTTPParameterType();
}
protected function newConduitSearchParameterType() {
return new ConduitStringListParameterType();
}
protected function newConduitEditParameterType() {
return new ConduitStringParameterType();
}
}
diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php
index f6de8eca5b..a1d8fe2664 100644
--- a/src/view/layout/PhabricatorActionView.php
+++ b/src/view/layout/PhabricatorActionView.php
@@ -1,371 +1,374 @@
<?php
final class PhabricatorActionView extends AphrontView {
private $name;
private $icon;
private $href;
private $disabled;
private $label;
private $workflow;
private $renderAsForm;
private $download;
private $sigils = array();
private $metadata;
private $selected;
private $openInNewWindow;
private $submenu = array();
private $hidden;
private $depth;
private $id;
private $order;
private $color;
private $type;
const TYPE_DIVIDER = 'type-divider';
const TYPE_LABEL = 'label';
const RED = 'action-item-red';
public function setSelected($selected) {
$this->selected = $selected;
return $this;
}
public function getSelected() {
return $this->selected;
}
public function setMetadata($metadata) {
$this->metadata = $metadata;
return $this;
}
public function getMetadata() {
return $this->metadata;
}
public function setDownload($download) {
$this->download = $download;
return $this;
}
public function getDownload() {
return $this->download;
}
public function setHref($href) {
$this->href = $href;
return $this;
}
public function setColor($color) {
$this->color = $color;
return $this;
}
public function addSigil($sigil) {
$this->sigils[] = $sigil;
return $this;
}
public function getHref() {
return $this->href;
}
public function setIcon($icon) {
$this->icon = $icon;
return $this;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setLabel($label) {
$this->label = $label;
return $this;
}
public function setDisabled($disabled) {
$this->disabled = $disabled;
return $this;
}
public function getDisabled() {
return $this->disabled;
}
public function setWorkflow($workflow) {
$this->workflow = $workflow;
return $this;
}
public function setRenderAsForm($form) {
$this->renderAsForm = $form;
return $this;
}
public function setOpenInNewWindow($open_in_new_window) {
$this->openInNewWindow = $open_in_new_window;
return $this;
}
public function getOpenInNewWindow() {
return $this->openInNewWindow;
}
public function setID($id) {
$this->id = $id;
return $this;
}
public function getID() {
if (!$this->id) {
$this->id = celerity_generate_unique_node_id();
}
return $this->id;
}
public function setOrder($order) {
$this->order = $order;
return $this;
}
public function getOrder() {
return $this->order;
}
public function setType($type) {
$this->type = $type;
return $this;
}
public function getType() {
return $this->type;
}
public function setSubmenu(array $submenu) {
$this->submenu = $submenu;
if (!$this->getHref()) {
$this->setHref('#');
}
return $this;
}
public function getItems($depth = 0) {
$items = array();
$items[] = $this;
foreach ($this->submenu as $action) {
foreach ($action->getItems($depth + 1) as $item) {
$item
->setHidden(true)
->setDepth($depth + 1);
$items[] = $item;
}
}
return $items;
}
public function setHidden($hidden) {
$this->hidden = $hidden;
return $this;
}
public function getHidden() {
return $this->hidden;
}
public function setDepth($depth) {
$this->depth = $depth;
return $this;
}
public function getDepth() {
return $this->depth;
}
public function render() {
$caret_id = celerity_generate_unique_node_id();
$icon = null;
if ($this->icon) {
$color = '';
if ($this->disabled) {
$color = ' grey';
}
$icon = id(new PHUIIconView())
->addClass('phabricator-action-view-icon')
->setIcon($this->icon.$color);
}
$sigils = array();
if ($this->workflow) {
$sigils[] = 'workflow';
}
if ($this->download) {
$sigils[] = 'download';
}
if ($this->submenu) {
$sigils[] = 'keep-open';
}
if ($this->sigils) {
$sigils = array_merge($sigils, $this->sigils);
}
$sigils = $sigils ? implode(' ', $sigils) : null;
if ($this->href) {
if ($this->renderAsForm) {
if (!$this->hasViewer()) {
throw new Exception(
pht(
'Call %s when rendering an action as a form.',
'setViewer()'));
}
$item = javelin_tag(
'button',
array(
'class' => 'phabricator-action-view-item',
),
array($icon, $this->name));
$item = phabricator_form(
$this->getViewer(),
array(
'action' => $this->getHref(),
'method' => 'POST',
'sigil' => $sigils,
'meta' => $this->metadata,
),
$item);
} else {
if ($this->getOpenInNewWindow()) {
$target = '_blank';
+ $rel = 'noreferrer';
} else {
$target = null;
+ $rel = null;
}
if ($this->submenu) {
$caret = javelin_tag(
'span',
array(
'class' => 'caret-right',
'id' => $caret_id,
),
'');
} else {
$caret = null;
}
$item = javelin_tag(
'a',
array(
'href' => $this->getHref(),
'class' => 'phabricator-action-view-item',
'target' => $target,
+ 'rel' => $rel,
'sigil' => $sigils,
'meta' => $this->metadata,
),
array($icon, $this->name, $caret));
}
} else {
$item = javelin_tag(
'span',
array(
'class' => 'phabricator-action-view-item',
'sigil' => $sigils,
),
array($icon, $this->name, $this->renderChildren()));
}
$classes = array();
$classes[] = 'phabricator-action-view';
if ($this->disabled) {
$classes[] = 'phabricator-action-view-disabled';
}
if ($this->label) {
$classes[] = 'phabricator-action-view-label';
}
if ($this->selected) {
$classes[] = 'phabricator-action-view-selected';
}
if ($this->submenu) {
$classes[] = 'phabricator-action-view-submenu';
}
if ($this->getHref()) {
$classes[] = 'phabricator-action-view-href';
}
if ($this->icon) {
$classes[] = 'action-has-icon';
}
if ($this->color) {
$classes[] = $this->color;
}
if ($this->type) {
$classes[] = 'phabricator-action-view-'.$this->type;
}
$style = array();
if ($this->hidden) {
$style[] = 'display: none;';
}
if ($this->depth) {
$indent = ($this->depth * 16);
$style[] = "margin-left: {$indent}px;";
}
$sigil = null;
$meta = null;
if ($this->submenu) {
Javelin::initBehavior('phui-submenu');
$sigil = 'phui-submenu';
$item_ids = array();
foreach ($this->submenu as $subitem) {
$item_ids[] = $subitem->getID();
}
$meta = array(
'itemIDs' => $item_ids,
'caretID' => $caret_id,
);
}
return javelin_tag(
'li',
array(
'id' => $this->getID(),
'class' => implode(' ', $classes),
'style' => implode(' ', $style),
'sigil' => $sigil,
'meta' => $meta,
),
$item);
}
}
diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php
index e8a1940737..8e53024826 100644
--- a/src/view/phui/PHUIListItemView.php
+++ b/src/view/phui/PHUIListItemView.php
@@ -1,379 +1,390 @@
<?php
final class PHUIListItemView extends AphrontTagView {
const TYPE_LINK = 'type-link';
const TYPE_SPACER = 'type-spacer';
const TYPE_LABEL = 'type-label';
const TYPE_BUTTON = 'type-button';
const TYPE_CUSTOM = 'type-custom';
const TYPE_DIVIDER = 'type-divider';
const TYPE_ICON = 'type-icon';
const STATUS_WARN = 'phui-list-item-warn';
const STATUS_FAIL = 'phui-list-item-fail';
private $name;
private $href;
private $type = self::TYPE_LINK;
private $isExternal;
private $key;
private $icon;
private $selected;
private $disabled;
private $renderNameAsTooltip;
private $statusColor;
private $order;
private $aural;
private $profileImage;
private $indented;
private $hideInApplicationMenu;
private $icons = array();
private $openInNewWindow = false;
private $tooltip;
private $actionIcon;
private $actionIconHref;
private $count;
+ private $rel;
public function setOpenInNewWindow($open_in_new_window) {
$this->openInNewWindow = $open_in_new_window;
return $this;
}
public function getOpenInNewWindow() {
return $this->openInNewWindow;
}
- public function setHideInApplicationMenu($hide) {
+ public function setRel($rel) {
+ $this->rel = $rel;
+ return $this;
+ }
+
+ public function getRel() {
+ return $this->rel;
+ }
+
+ public function setHideInApplicationMenu($hide) {
$this->hideInApplicationMenu = $hide;
return $this;
}
public function getHideInApplicationMenu() {
return $this->hideInApplicationMenu;
}
public function setDropdownMenu(PhabricatorActionListView $actions) {
Javelin::initBehavior('phui-dropdown-menu');
$this->addSigil('phui-dropdown-menu');
$this->setMetadata($actions->getDropdownMenuMetadata());
return $this;
}
public function setAural($aural) {
$this->aural = $aural;
return $this;
}
public function getAural() {
return $this->aural;
}
public function setOrder($order) {
$this->order = $order;
return $this;
}
public function getOrder() {
return $this->order;
}
public function setRenderNameAsTooltip($render_name_as_tooltip) {
$this->renderNameAsTooltip = $render_name_as_tooltip;
return $this;
}
public function getRenderNameAsTooltip() {
return $this->renderNameAsTooltip;
}
public function setSelected($selected) {
$this->selected = $selected;
return $this;
}
public function getSelected() {
return $this->selected;
}
public function setIcon($icon) {
$this->icon = $icon;
return $this;
}
public function setProfileImage($image) {
$this->profileImage = $image;
return $this;
}
public function getIcon() {
return $this->icon;
}
public function setCount($count) {
$this->count = $count;
return $this;
}
public function setIndented($indented) {
$this->indented = $indented;
return $this;
}
public function getIndented() {
return $this->indented;
}
public function setKey($key) {
$this->key = (string)$key;
return $this;
}
public function getKey() {
return $this->key;
}
public function setType($type) {
$this->type = $type;
return $this;
}
public function getType() {
return $this->type;
}
public function setHref($href) {
$this->href = $href;
return $this;
}
public function getHref() {
return $this->href;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function getName() {
return $this->name;
}
public function setActionIcon($icon, $href) {
$this->actionIcon = $icon;
$this->actionIconHref = $href;
return $this;
}
public function setIsExternal($is_external) {
$this->isExternal = $is_external;
return $this;
}
public function getIsExternal() {
return $this->isExternal;
}
public function setStatusColor($color) {
$this->statusColor = $color;
return $this;
}
public function addIcon($icon) {
$this->icons[] = $icon;
return $this;
}
public function getIcons() {
return $this->icons;
}
public function setTooltip($tooltip) {
$this->tooltip = $tooltip;
return $this;
}
protected function getTagName() {
return 'li';
}
protected function getTagAttributes() {
$classes = array();
$classes[] = 'phui-list-item-view';
$classes[] = 'phui-list-item-'.$this->type;
if ($this->icon || $this->profileImage) {
$classes[] = 'phui-list-item-has-icon';
}
if ($this->selected) {
$classes[] = 'phui-list-item-selected';
}
if ($this->disabled) {
$classes[] = 'phui-list-item-disabled';
}
if ($this->statusColor) {
$classes[] = $this->statusColor;
}
if ($this->actionIcon) {
$classes[] = 'phui-list-item-has-action-icon';
}
return array(
'class' => implode(' ', $classes),
);
}
public function setDisabled($disabled) {
$this->disabled = $disabled;
return $this;
}
public function getDisabled() {
return $this->disabled;
}
protected function getTagContent() {
$name = null;
$icon = null;
$meta = null;
$sigil = null;
if ($this->name) {
if ($this->getRenderNameAsTooltip()) {
Javelin::initBehavior('phabricator-tooltips');
$sigil = 'has-tooltip';
$meta = array(
'tip' => $this->name,
'align' => 'E',
);
} else {
if ($this->tooltip) {
Javelin::initBehavior('phabricator-tooltips');
$sigil = 'has-tooltip';
$meta = array(
'tip' => $this->tooltip,
'align' => 'E',
'size' => 300,
);
}
$external = null;
if ($this->isExternal) {
$external = " \xE2\x86\x97";
}
// If this element has an aural representation, make any name visual
// only. This is primarily dealing with the links in the main menu like
// "Profile" and "Logout". If we don't hide the name, the mobile
// version of these elements will have two redundant names.
$classes = array();
$classes[] = 'phui-list-item-name';
if ($this->aural !== null) {
$classes[] = 'visual-only';
}
$name = phutil_tag(
'span',
array(
'class' => implode(' ', $classes),
),
array(
$this->name,
$external,
));
}
}
$aural = null;
if ($this->aural !== null) {
$aural = javelin_tag(
'span',
array(
'aural' => true,
),
$this->aural);
}
if ($this->icon) {
$icon_name = $this->icon;
if ($this->getDisabled()) {
$icon_name .= ' grey';
}
$icon = id(new PHUIIconView())
->addClass('phui-list-item-icon')
->setIcon($icon_name);
}
if ($this->profileImage) {
$icon = id(new PHUIIconView())
->setHeadSize(PHUIIconView::HEAD_SMALL)
->addClass('phui-list-item-icon')
->setImage($this->profileImage);
}
$classes = array();
if ($this->href) {
$classes[] = 'phui-list-item-href';
}
if ($this->indented) {
$classes[] = 'phui-list-item-indented';
}
$action_link = null;
if ($this->actionIcon) {
$action_icon = id(new PHUIIconView())
->setIcon($this->actionIcon)
->addClass('phui-list-item-action-icon');
$action_link = phutil_tag(
'a',
array(
'href' => $this->actionIconHref,
'class' => 'phui-list-item-action-href',
),
$action_icon);
}
$count = null;
if ($this->count) {
$count = phutil_tag(
'span',
array(
'class' => 'phui-list-item-count',
),
$this->count);
}
$icons = $this->getIcons();
$list_item = javelin_tag(
$this->href ? 'a' : 'div',
array(
'href' => $this->href,
'class' => implode(' ', $classes),
'meta' => $meta,
'sigil' => $sigil,
'target' => $this->getOpenInNewWindow() ? '_blank' : null,
+ 'rel' => $this->rel,
),
array(
$aural,
$icon,
$icons,
$this->renderChildren(),
$name,
$count,
));
return array($list_item, $action_link);
}
}
diff --git a/src/view/phui/PHUITagView.php b/src/view/phui/PHUITagView.php
index 292246c4a7..482b3f4400 100644
--- a/src/view/phui/PHUITagView.php
+++ b/src/view/phui/PHUITagView.php
@@ -1,312 +1,317 @@
<?php
final class PHUITagView extends AphrontTagView {
const TYPE_PERSON = 'person';
const TYPE_OBJECT = 'object';
const TYPE_STATE = 'state';
const TYPE_SHADE = 'shade';
const TYPE_OUTLINE = 'outline';
const COLOR_RED = 'red';
const COLOR_ORANGE = 'orange';
const COLOR_YELLOW = 'yellow';
const COLOR_BLUE = 'blue';
const COLOR_INDIGO = 'indigo';
const COLOR_VIOLET = 'violet';
const COLOR_GREEN = 'green';
const COLOR_BLACK = 'black';
const COLOR_SKY = 'sky';
const COLOR_FIRE = 'fire';
const COLOR_GREY = 'grey';
const COLOR_WHITE = 'white';
const COLOR_PINK = 'pink';
const COLOR_BLUEGREY = 'bluegrey';
const COLOR_CHECKERED = 'checkered';
const COLOR_DISABLED = 'disabled';
const COLOR_OBJECT = 'object';
const COLOR_PERSON = 'person';
const BORDER_NONE = 'border-none';
private $type;
private $href;
private $name;
private $phid;
private $color;
private $backgroundColor;
private $dotColor;
private $closed;
private $external;
private $icon;
private $shade;
private $slimShady;
private $border;
public function setType($type) {
$this->type = $type;
switch ($type) {
case self::TYPE_SHADE:
case self::TYPE_OUTLINE:
break;
case self::TYPE_OBJECT:
$this->setBackgroundColor(self::COLOR_OBJECT);
break;
case self::TYPE_PERSON:
$this->setBackgroundColor(self::COLOR_PERSON);
break;
}
return $this;
}
/**
* This method has been deprecated, use @{method:setColor} instead.
*
* @deprecated
*/
public function setShade($shade) {
phlog(
pht('Deprecated call to setShade(), use setColor() instead.'));
$this->color = $shade;
return $this;
}
public function setColor($color) {
$this->color = $color;
return $this;
}
public function setDotColor($dot_color) {
$this->dotColor = $dot_color;
return $this;
}
public function setBackgroundColor($background_color) {
$this->backgroundColor = $background_color;
return $this;
}
public function setPHID($phid) {
$this->phid = $phid;
return $this;
}
public function setName($name) {
$this->name = $name;
return $this;
}
public function setHref($href) {
$this->href = $href;
return $this;
}
public function setClosed($closed) {
$this->closed = $closed;
return $this;
}
public function setBorder($border) {
$this->border = $border;
return $this;
}
public function setIcon($icon) {
$this->icon = $icon;
return $this;
}
public function setSlimShady($mm) {
$this->slimShady = $mm;
return $this;
}
protected function getTagName() {
return strlen($this->href) ? 'a' : 'span';
}
protected function getTagAttributes() {
require_celerity_resource('phui-tag-view-css');
$classes = array(
'phui-tag-view',
'phui-tag-type-'.$this->type,
);
if ($this->color) {
$classes[] = 'phui-tag-'.$this->color;
}
if ($this->slimShady) {
$classes[] = 'phui-tag-slim';
}
if ($this->type == self::TYPE_SHADE) {
$classes[] = 'phui-tag-shade';
}
if ($this->icon) {
$classes[] = 'phui-tag-icon-view';
}
if ($this->border) {
$classes[] = 'phui-tag-'.$this->border;
}
+ $attributes = array(
+ 'href' => $this->href,
+ 'class' => $classes,
+ );
+
+ if ($this->external) {
+ $attributes += array(
+ 'target' => '_blank',
+ 'rel' => 'noreferrer',
+ );
+ }
+
if ($this->phid) {
Javelin::initBehavior('phui-hovercards');
- $attributes = array(
- 'href' => $this->href,
+ $attributes += array(
'sigil' => 'hovercard',
- 'meta' => array(
+ 'meta' => array(
'hoverPHID' => $this->phid,
),
- 'target' => $this->external ? '_blank' : null,
- );
- } else {
- $attributes = array(
- 'href' => $this->href,
- 'target' => $this->external ? '_blank' : null,
);
}
- return $attributes + array('class' => $classes);
+ return $attributes;
}
protected function getTagContent() {
if (!$this->type) {
throw new PhutilInvalidStateException('setType', 'render');
}
$color = null;
if (!$this->shade && $this->backgroundColor) {
$color = 'phui-tag-color-'.$this->backgroundColor;
}
if ($this->dotColor) {
$dotcolor = 'phui-tag-color-'.$this->dotColor;
$dot = phutil_tag(
'span',
array(
'class' => 'phui-tag-dot '.$dotcolor,
),
'');
} else {
$dot = null;
}
if ($this->icon) {
$icon = id(new PHUIIconView())
->setIcon($this->icon);
} else {
$icon = null;
}
$content = phutil_tag(
'span',
array(
'class' => 'phui-tag-core '.$color,
),
array($dot, $icon, $this->name));
if ($this->closed) {
$content = phutil_tag(
'span',
array(
'class' => 'phui-tag-core-closed',
),
array($icon, $content));
}
return $content;
}
public static function getTagTypes() {
return array(
self::TYPE_PERSON,
self::TYPE_OBJECT,
self::TYPE_STATE,
);
}
public static function getColors() {
return array(
self::COLOR_RED,
self::COLOR_ORANGE,
self::COLOR_YELLOW,
self::COLOR_BLUE,
self::COLOR_INDIGO,
self::COLOR_VIOLET,
self::COLOR_GREEN,
self::COLOR_BLACK,
self::COLOR_GREY,
self::COLOR_WHITE,
self::COLOR_OBJECT,
self::COLOR_PERSON,
);
}
public static function getShades() {
return array_keys(self::getShadeMap());
}
public static function getShadeMap() {
return array(
self::COLOR_RED => pht('Red'),
self::COLOR_ORANGE => pht('Orange'),
self::COLOR_YELLOW => pht('Yellow'),
self::COLOR_BLUE => pht('Blue'),
self::COLOR_INDIGO => pht('Indigo'),
self::COLOR_VIOLET => pht('Violet'),
self::COLOR_GREEN => pht('Green'),
self::COLOR_GREY => pht('Grey'),
self::COLOR_PINK => pht('Pink'),
self::COLOR_CHECKERED => pht('Checkered'),
self::COLOR_DISABLED => pht('Disabled'),
);
}
public static function getShadeName($shade) {
return idx(self::getShadeMap(), $shade, $shade);
}
public static function getOutlines() {
return array_keys(self::getOutlineMap());
}
public static function getOutlineMap() {
return array(
self::COLOR_RED => pht('Red'),
self::COLOR_ORANGE => pht('Orange'),
self::COLOR_YELLOW => pht('Yellow'),
self::COLOR_BLUE => pht('Blue'),
self::COLOR_INDIGO => pht('Indigo'),
self::COLOR_VIOLET => pht('Violet'),
self::COLOR_GREEN => pht('Green'),
self::COLOR_GREY => pht('Grey'),
self::COLOR_PINK => pht('Pink'),
self::COLOR_SKY => pht('Sky'),
self::COLOR_FIRE => pht('Fire'),
self::COLOR_BLACK => pht('Black'),
self::COLOR_DISABLED => pht('Disabled'),
);
}
public static function getOutlineName($outline) {
return idx(self::getOutlineMap(), $outline, $outline);
}
public function setExternal($external) {
$this->external = $external;
return $this;
}
public function getExternal() {
return $this->external;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 12:01 PM (1 d, 2 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71850
Default Alt Text
(59 KB)

Event Timeline