Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15393969
D15414.id37159.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
28 KB
Referenced Files
None
Subscribers
None
D15414.id37159.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -127,6 +127,7 @@
'rsrc/css/phui/phui-button.css' => 'a64a8de6',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-crumbs-view.css' => '79d536e5',
+ 'rsrc/css/phui/phui-curtain-view.css' => '8bb7ee8f',
'rsrc/css/phui/phui-document-pro.css' => '92d5b648',
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
'rsrc/css/phui/phui-document.css' => '9c71d2bf',
@@ -811,6 +812,7 @@
'phui-calendar-month-css' => '476be7e0',
'phui-chart-css' => '6bf6f78e',
'phui-crumbs-view-css' => '79d536e5',
+ 'phui-curtain-view-css' => '8bb7ee8f',
'phui-document-summary-view-css' => '9ca48bdf',
'phui-document-view-css' => '9c71d2bf',
'phui-document-view-pro-css' => '92d5b648',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -1505,6 +1505,9 @@
'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php',
'PHUICrumbView' => 'view/phui/PHUICrumbView.php',
'PHUICrumbsView' => 'view/phui/PHUICrumbsView.php',
+ 'PHUICurtainExtension' => 'view/extension/PHUICurtainExtension.php',
+ 'PHUICurtainPanelView' => 'view/layout/PHUICurtainPanelView.php',
+ 'PHUICurtainView' => 'view/layout/PHUICurtainView.php',
'PHUIDiffInlineCommentDetailView' => 'infrastructure/diff/view/PHUIDiffInlineCommentDetailView.php',
'PHUIDiffInlineCommentEditView' => 'infrastructure/diff/view/PHUIDiffInlineCommentEditView.php',
'PHUIDiffInlineCommentRowScaffold' => 'infrastructure/diff/view/PHUIDiffInlineCommentRowScaffold.php',
@@ -3011,6 +3014,7 @@
'PhabricatorProjectWatcherListView' => 'applications/project/view/PhabricatorProjectWatcherListView.php',
'PhabricatorProjectWorkboardBackgroundColor' => 'applications/project/constants/PhabricatorProjectWorkboardBackgroundColor.php',
'PhabricatorProjectWorkboardProfilePanel' => 'applications/project/profilepanel/PhabricatorProjectWorkboardProfilePanel.php',
+ 'PhabricatorProjectsCurtainExtension' => 'applications/project/engineextension/PhabricatorProjectsCurtainExtension.php',
'PhabricatorProjectsEditEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsEditEngineExtension.php',
'PhabricatorProjectsEditField' => 'applications/transactions/editfield/PhabricatorProjectsEditField.php',
'PhabricatorProjectsFulltextEngineExtension' => 'applications/project/engineextension/PhabricatorProjectsFulltextEngineExtension.php',
@@ -3320,6 +3324,7 @@
'PhabricatorSubscriptionsAddSelfHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSelfHeraldAction.php',
'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'applications/subscriptions/herald/PhabricatorSubscriptionsAddSubscribersHeraldAction.php',
'PhabricatorSubscriptionsApplication' => 'applications/subscriptions/application/PhabricatorSubscriptionsApplication.php',
+ 'PhabricatorSubscriptionsCurtainExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php',
'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php',
'PhabricatorSubscriptionsEditEngineExtension' => 'applications/subscriptions/engineextension/PhabricatorSubscriptionsEditEngineExtension.php',
'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php',
@@ -3388,6 +3393,7 @@
'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php',
'PhabricatorTokenizerEditField' => 'applications/transactions/editfield/PhabricatorTokenizerEditField.php',
'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php',
+ 'PhabricatorTokensCurtainExtension' => 'applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php',
'PhabricatorTokensSettingsPanel' => 'applications/settings/panel/PhabricatorTokensSettingsPanel.php',
'PhabricatorTooltipUIExample' => 'applications/uiexample/examples/PhabricatorTooltipUIExample.php',
'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php',
@@ -5751,6 +5757,9 @@
'PHUIColorPalletteExample' => 'PhabricatorUIExample',
'PHUICrumbView' => 'AphrontView',
'PHUICrumbsView' => 'AphrontView',
+ 'PHUICurtainExtension' => 'Phobject',
+ 'PHUICurtainPanelView' => 'AphrontTagView',
+ 'PHUICurtainView' => 'AphrontTagView',
'PHUIDiffInlineCommentDetailView' => 'PHUIDiffInlineCommentView',
'PHUIDiffInlineCommentEditView' => 'PHUIDiffInlineCommentView',
'PHUIDiffInlineCommentRowScaffold' => 'AphrontView',
@@ -7503,6 +7512,7 @@
'PhabricatorProjectWatcherListView' => 'PhabricatorProjectUserListView',
'PhabricatorProjectWorkboardBackgroundColor' => 'Phobject',
'PhabricatorProjectWorkboardProfilePanel' => 'PhabricatorProfilePanel',
+ 'PhabricatorProjectsCurtainExtension' => 'PHUICurtainExtension',
'PhabricatorProjectsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorProjectsEditField' => 'PhabricatorTokenizerEditField',
'PhabricatorProjectsFulltextEngineExtension' => 'PhabricatorFulltextEngineExtension',
@@ -7872,6 +7882,7 @@
'PhabricatorSubscriptionsAddSelfHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsAddSubscribersHeraldAction' => 'PhabricatorSubscriptionsHeraldAction',
'PhabricatorSubscriptionsApplication' => 'PhabricatorApplication',
+ 'PhabricatorSubscriptionsCurtainExtension' => 'PHUICurtainExtension',
'PhabricatorSubscriptionsEditController' => 'PhabricatorController',
'PhabricatorSubscriptionsEditEngineExtension' => 'PhabricatorEditEngineExtension',
'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor',
@@ -7945,6 +7956,7 @@
'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener',
'PhabricatorTokenizerEditField' => 'PhabricatorPHIDListEditField',
'PhabricatorTokensApplication' => 'PhabricatorApplication',
+ 'PhabricatorTokensCurtainExtension' => 'PHUICurtainExtension',
'PhabricatorTokensSettingsPanel' => 'PhabricatorSettingsPanel',
'PhabricatorTooltipUIExample' => 'PhabricatorUIExample',
'PhabricatorTransactions' => 'Phobject',
diff --git a/src/applications/base/controller/PhabricatorController.php b/src/applications/base/controller/PhabricatorController.php
--- a/src/applications/base/controller/PhabricatorController.php
+++ b/src/applications/base/controller/PhabricatorController.php
@@ -468,7 +468,26 @@
public function newApplicationMenu() {
return id(new PHUIApplicationMenuView())
- ->setViewer($this->getRequest()->getUser());
+ ->setViewer($this->getViewer());
+ }
+
+ public function newCurtainView($object) {
+ $viewer = $this->getViewer();
+
+ $action_list = id(new PhabricatorActionListView())
+ ->setViewer($viewer)
+ ->setObject($object);
+
+ $curtain = id(new PHUICurtainView())
+ ->setViewer($viewer)
+ ->setActionList($action_list);
+
+ $panels = PHUICurtainExtension::buildExtensionPanels($viewer, $object);
+ foreach ($panels as $panel) {
+ $curtain->addPanel($panel);
+ }
+
+ return $curtain;
}
protected function buildTransactionTimeline(
diff --git a/src/applications/paste/controller/PhabricatorPasteViewController.php b/src/applications/paste/controller/PhabricatorPasteViewController.php
--- a/src/applications/paste/controller/PhabricatorPasteViewController.php
+++ b/src/applications/paste/controller/PhabricatorPasteViewController.php
@@ -40,15 +40,9 @@
return new Aphront404Response();
}
- $forks = id(new PhabricatorPasteQuery())
- ->setViewer($viewer)
- ->withParentPHIDs(array($paste->getPHID()))
- ->execute();
- $fork_phids = mpull($forks, 'getPHID');
-
$header = $this->buildHeaderView($paste);
- $actions = $this->buildActionView($viewer, $paste);
- $properties = $this->buildPropertyView($paste, $fork_phids);
+ $curtain = $this->buildCurtain($paste);
+
$subheader = $this->buildSubheaderView($paste);
$source_code = $this->buildSourceCodeView($paste, $this->highlightMap);
@@ -78,8 +72,7 @@
$timeline,
$comment_view,
))
- ->setPropertyList($properties)
- ->setActionList($actions)
+ ->setCurtain($curtain)
->addClass('ponder-question-view');
return $this->newPage()
@@ -116,9 +109,9 @@
return $header;
}
- private function buildActionView(
- PhabricatorUser $viewer,
- PhabricatorPaste $paste) {
+ private function buildCurtain(PhabricatorPaste $paste) {
+ $viewer = $this->getViewer();
+ $curtain = $this->newCurtainView($paste);
$can_edit = PhabricatorPolicyFilter::hasCapability(
$viewer,
@@ -126,43 +119,42 @@
PhabricatorPolicyCapability::CAN_EDIT);
$id = $paste->getID();
+ $edit_uri = $this->getApplicationURI("edit/{$id}/");
+ $archive_uri = $this->getApplicationURI("archive/{$id}/");
+ $raw_uri = $this->getApplicationURI("raw/{$id}/");
- $action_list = id(new PhabricatorActionListView())
- ->setUser($viewer)
- ->setObject($paste);
-
- $action_list->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Edit Paste'))
- ->setIcon('fa-pencil')
- ->setDisabled(!$can_edit)
- ->setHref($this->getApplicationURI("edit/{$id}/")));
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Paste'))
+ ->setIcon('fa-pencil')
+ ->setDisabled(!$can_edit)
+ ->setHref($edit_uri));
if ($paste->isArchived()) {
- $action_list->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Activate Paste'))
- ->setIcon('fa-check')
- ->setDisabled(!$can_edit)
- ->setWorkflow($can_edit)
- ->setHref($this->getApplicationURI("archive/{$id}/")));
+ ->setName(pht('Activate Paste'))
+ ->setIcon('fa-check')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow($can_edit)
+ ->setHref($archive_uri));
} else {
- $action_list->addAction(
+ $curtain->addAction(
id(new PhabricatorActionView())
- ->setName(pht('Archive Paste'))
- ->setIcon('fa-ban')
- ->setDisabled(!$can_edit)
- ->setWorkflow($can_edit)
- ->setHref($this->getApplicationURI("archive/{$id}/")));
+ ->setName(pht('Archive Paste'))
+ ->setIcon('fa-ban')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow($can_edit)
+ ->setHref($archive_uri));
}
- $action_list->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('View Raw File'))
- ->setIcon('fa-file-text-o')
- ->setHref($this->getApplicationURI("raw/{$id}/")));
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('View Raw File'))
+ ->setIcon('fa-file-text-o')
+ ->setHref($raw_uri));
- return $action_list;
+ return $curtain;
}
@@ -191,32 +183,4 @@
->setContent($content);
}
- private function buildPropertyView(
- PhabricatorPaste $paste,
- array $child_phids) {
- $viewer = $this->getViewer();
-
- $properties = id(new PHUIPropertyListView())
- ->setUser($viewer)
- ->setObject($paste);
-
- if ($paste->getParentPHID()) {
- $properties->addProperty(
- pht('Forked From'),
- $viewer->renderHandle($paste->getParentPHID()));
- }
-
- if ($child_phids) {
- $properties->addProperty(
- pht('Forks'),
- $viewer->renderHandleList($child_phids));
- }
-
- $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
- $viewer,
- $paste);
-
- return $properties;
- }
-
}
diff --git a/src/applications/project/engineextension/PhabricatorProjectsCurtainExtension.php b/src/applications/project/engineextension/PhabricatorProjectsCurtainExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/engineextension/PhabricatorProjectsCurtainExtension.php
@@ -0,0 +1,91 @@
+<?php
+
+final class PhabricatorProjectsCurtainExtension
+ extends PHUICurtainExtension {
+
+ const EXTENSIONKEY = 'projects.projects';
+
+ public function shouldEnableForObject($object) {
+ return ($object instanceof PhabricatorProjectInterface);
+ }
+
+ public function getExtensionApplication() {
+ return new PhabricatorProjectApplication();
+ }
+
+ public function buildCurtainPanel($object) {
+ $viewer = $this->getViewer();
+
+ $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
+ $object->getPHID(),
+ PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
+
+ $has_projects = (bool)$project_phids;
+ $project_phids = array_reverse($project_phids);
+ $handles = $viewer->loadHandles($project_phids);
+
+ // If this object can appear on boards, build the workboard annotations.
+ // Some day, this might be a generic interface. For now, only tasks can
+ // appear on boards.
+ $can_appear_on_boards = ($object instanceof ManiphestTask);
+
+ $annotations = array();
+ if ($has_projects && $can_appear_on_boards) {
+ $engine = id(new PhabricatorBoardLayoutEngine())
+ ->setViewer($viewer)
+ ->setBoardPHIDs($project_phids)
+ ->setObjectPHIDs(array($object->getPHID()))
+ ->executeLayout();
+
+ // TDOO: Generalize this UI and move it out of Maniphest.
+ require_celerity_resource('maniphest-task-summary-css');
+
+ foreach ($project_phids as $project_phid) {
+ $handle = $handles[$project_phid];
+
+ $columns = $engine->getObjectColumns(
+ $project_phid,
+ $object->getPHID());
+
+ $annotation = array();
+ foreach ($columns as $column) {
+ $project_id = $column->getProject()->getID();
+
+ $column_name = pht('(%s)', $column->getDisplayName());
+ $column_link = phutil_tag(
+ 'a',
+ array(
+ 'href' => "/project/board/{$project_id}/",
+ 'class' => 'maniphest-board-link',
+ ),
+ $column_name);
+
+ $annotation[] = $column_link;
+ }
+
+ if ($annotation) {
+ $annotations[$project_phid] = array(
+ ' ',
+ phutil_implode_html(', ', $annotation),
+ );
+ }
+ }
+
+ }
+
+ if ($has_projects) {
+ $list = id(new PHUIHandleTagListView())
+ ->setHandles($handles)
+ ->setAnnotations($annotations)
+ ->setShowHovercards(true);
+ } else {
+ $list = phutil_tag('em', array(), pht('None'));
+ }
+
+ return $this->newPanel()
+ ->setHeaderText(pht('Projects'))
+ ->setOrder(10000)
+ ->appendChild($list);
+ }
+
+}
diff --git a/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/subscriptions/engineextension/PhabricatorSubscriptionsCurtainExtension.php
@@ -0,0 +1,39 @@
+<?php
+
+final class PhabricatorSubscriptionsCurtainExtension
+ extends PHUICurtainExtension {
+
+ const EXTENSIONKEY = 'subscriptions.subscribers';
+
+ public function shouldEnableForObject($object) {
+ return ($object instanceof PhabricatorSubscribableInterface);
+ }
+
+ public function getExtensionApplication() {
+ return new PhabricatorSubscriptionsApplication();
+ }
+
+ public function buildCurtainPanel($object) {
+ $viewer = $this->getViewer();
+ $object_phid = $object->getPHID();
+
+ $subscriber_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID(
+ $object_phid);
+
+ $handles = $viewer->loadHandles($subscriber_phids);
+
+ // TODO: This class can't accept a HandleList yet.
+ $handles = iterator_to_array($handles);
+
+ $susbscribers_view = id(new SubscriptionListStringBuilder())
+ ->setObjectPHID($object_phid)
+ ->setHandles($handles)
+ ->buildPropertyString();
+
+ return $this->newPanel()
+ ->setHeaderText(pht('Subscribers'))
+ ->setOrder(20000)
+ ->appendChild($susbscribers_view);
+ }
+
+}
diff --git a/src/applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php b/src/applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php
new file mode 100644
--- /dev/null
+++ b/src/applications/tokens/engineextension/PhabricatorTokensCurtainExtension.php
@@ -0,0 +1,67 @@
+<?php
+
+final class PhabricatorTokensCurtainExtension
+ extends PHUICurtainExtension {
+
+ const EXTENSIONKEY = 'tokens.tokens';
+
+ public function shouldEnableForObject($object) {
+ return ($object instanceof PhabricatorTokenReceiverInterface);
+ }
+
+ public function getExtensionApplication() {
+ return new PhabricatorTokensApplication();
+ }
+
+ public function buildCurtainPanel($object) {
+ $viewer = $this->getViewer();
+
+ $tokens_given = id(new PhabricatorTokenGivenQuery())
+ ->setViewer($viewer)
+ ->withObjectPHIDs(array($object->getPHID()))
+ ->execute();
+ if (!$tokens_given) {
+ return null;
+ }
+
+ $author_phids = mpull($tokens_given, 'getAuthorPHID');
+ $handles = $viewer->loadHandles($author_phids);
+
+ Javelin::initBehavior('phabricator-tooltips');
+
+ $list = array();
+ foreach ($tokens_given as $token_given) {
+ $token = $token_given->getToken();
+
+ $aural = javelin_tag(
+ 'span',
+ array(
+ 'aural' => true,
+ ),
+ pht(
+ '"%s" token, awarded by %s.',
+ $token->getName(),
+ $handles[$token_given->getAuthorPHID()]->getName()));
+
+ $list[] = javelin_tag(
+ 'span',
+ array(
+ 'sigil' => 'has-tooltip',
+ 'class' => 'token-icon',
+ 'meta' => array(
+ 'tip' => $handles[$token_given->getAuthorPHID()]->getName(),
+ ),
+ ),
+ array(
+ $aural,
+ $token->renderIcon(),
+ ));
+ }
+
+ return $this->newPanel()
+ ->setHeaderText(pht('Tokens'))
+ ->setOrder(30000)
+ ->appendChild($list);
+ }
+
+}
diff --git a/src/applications/tokens/query/PhabricatorTokenGivenQuery.php b/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
--- a/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
+++ b/src/applications/tokens/query/PhabricatorTokenGivenQuery.php
@@ -58,10 +58,12 @@
}
protected function willFilterPage(array $results) {
+ $viewer = $this->getViewer();
+
$object_phids = mpull($results, 'getObjectPHID');
$objects = id(new PhabricatorObjectQuery())
- ->setViewer($this->getViewer())
+ ->setViewer($viewer)
->withPHIDs($object_phids)
->execute();
$objects = mpull($objects, null, 'getPHID');
@@ -80,6 +82,31 @@
unset($results[$key]);
}
+ if (!$results) {
+ return $results;
+ }
+
+ $token_phids = mpull($results, 'getTokenPHID');
+
+ $tokens = id(new PhabricatorTokenQuery())
+ ->setViewer($viewer)
+ ->withPHIDs($token_phids)
+ ->execute();
+ $tokens = mpull($tokens, null, 'getPHID');
+
+ foreach ($results as $key => $result) {
+ $token_phid = $result->getTokenPHID();
+
+ $token = idx($tokens, $token_phid);
+ if (!$token) {
+ $this->didRejectResult($result);
+ unset($results[$key]);
+ continue;
+ }
+
+ $result->attachToken($token);
+ }
+
return $results;
}
diff --git a/src/applications/tokens/storage/PhabricatorTokenGiven.php b/src/applications/tokens/storage/PhabricatorTokenGiven.php
--- a/src/applications/tokens/storage/PhabricatorTokenGiven.php
+++ b/src/applications/tokens/storage/PhabricatorTokenGiven.php
@@ -8,6 +8,7 @@
protected $tokenPHID;
private $object = self::ATTACHABLE;
+ private $token = self::ATTACHABLE;
protected function getConfiguration() {
return array(
@@ -35,6 +36,15 @@
return $this->assertAttached($this->object);
}
+ public function attachToken(PhabricatorToken $token) {
+ $this->token = $token;
+ return $this;
+ }
+
+ public function getToken() {
+ return $this->assertAttached($this->token);
+ }
+
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
diff --git a/src/view/extension/PHUICurtainExtension.php b/src/view/extension/PHUICurtainExtension.php
new file mode 100644
--- /dev/null
+++ b/src/view/extension/PHUICurtainExtension.php
@@ -0,0 +1,124 @@
+<?php
+
+abstract class PHUICurtainExtension extends Phobject {
+
+ private $viewer;
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ abstract public function shouldEnableForObject($object);
+ abstract public function getExtensionApplication();
+
+ public function buildCurtainPanels($object) {
+ $panel = $this->buildCurtainPanel($object);
+
+ if ($panel !== null) {
+ return array($panel);
+ }
+
+ return array();
+ }
+
+ public function buildCurtainPanel($object) {
+ throw new PhutilMethodNotImplementedException();
+ }
+
+ final public function getExtensionKey() {
+ return $this->getPhobjectClassConstant('EXTENSIONKEY');
+ }
+
+ final public static function getAllExtensions() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getExtensionKey')
+ ->execute();
+ }
+
+ protected function newPanel() {
+ return new PHUICurtainPanelView();
+ }
+
+ final public static function buildExtensionPanels(
+ PhabricatorUser $viewer,
+ $object) {
+
+ $extensions = self::getAllExtensions();
+ foreach ($extensions as $extension) {
+ $extension->setViewer($viewer);
+ }
+
+ foreach ($extensions as $key => $extension) {
+ $application = $extension->getExtensionApplication();
+ if (!($application instanceof PhabricatorApplication)) {
+ throw new Exception(
+ pht(
+ 'Curtain extension ("%s", of class "%s") did not return an '.
+ 'application from method "%s". This method must return an '.
+ 'object of class "%s".',
+ $key,
+ get_class($extension),
+ 'getExtensionApplication()',
+ 'PhabricatorApplication'));
+ }
+
+ $has_application = PhabricatorApplication::isClassInstalledForViewer(
+ get_class($application),
+ $viewer);
+
+ if (!$has_application) {
+ unset($extensions[$key]);
+ }
+ }
+
+ foreach ($extensions as $key => $extension) {
+ if (!$extension->shouldEnableForObject($object)) {
+ unset($extensions[$key]);
+ }
+ }
+
+ $result = array();
+
+ foreach ($extensions as $key => $extension) {
+ $panels = $extension->buildCurtainPanels($object);
+ if (!is_array($panels)) {
+ throw new Exception(
+ pht(
+ 'Curtain extension ("%s", of class "%s") did not return a list of '.
+ 'curtain panels from method "%s". This method must return an '.
+ 'array, and each value in the array must be a "%s" object.',
+ $key,
+ get_class($extension),
+ 'buildCurtainPanels()',
+ 'PHUICurtainPanelView'));
+ }
+
+ foreach ($panels as $panel_key => $panel) {
+ if (!($panel instanceof PHUICurtainPanelView)) {
+ throw new Exception(
+ pht(
+ 'Curtain extension ("%s", of class "%s") returned a list of '.
+ 'curtain panels from "%s" that contains an invalid value: '.
+ 'a value (with key "%s") is not an object of class "%s". '.
+ 'Each item in the returned array must be a panel.',
+ $key,
+ get_class($extension),
+ 'buildCurtainPanels()',
+ $panel_key,
+ 'PHUICurtainPanelView'));
+ }
+
+ $result[] = $panel;
+ }
+ }
+
+ return $result;
+ }
+
+}
diff --git a/src/view/layout/PHUICurtainPanelView.php b/src/view/layout/PHUICurtainPanelView.php
new file mode 100644
--- /dev/null
+++ b/src/view/layout/PHUICurtainPanelView.php
@@ -0,0 +1,63 @@
+<?php
+
+final class PHUICurtainPanelView extends AphrontTagView {
+
+ private $order = 0;
+ private $headerText;
+
+ public function setHeaderText($header_text) {
+ $this->headerText = $header_text;
+ return $this;
+ }
+
+ public function getHeaderText() {
+ return $this->headerText;
+ }
+
+ public function setOrder($order) {
+ $this->order = $order;
+ return $this;
+ }
+
+ public function getOrder() {
+ return $this->order;
+ }
+
+ public function getOrderVector() {
+ return id(new PhutilSortVector())
+ ->addInt($this->getOrder());
+ }
+
+ protected function getTagAttributes() {
+ return array(
+ 'class' => 'phui-curtain-panel',
+ );
+ }
+
+ protected function getTagContent() {
+ $header = null;
+
+ $header_text = $this->getHeaderText();
+ if (strlen($header_text)) {
+ $header = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phui-curtain-panel-header',
+ ),
+ $header_text);
+ }
+
+ $body = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'phui-curtain-panel-body',
+ ),
+ $this->renderChildren());
+
+ return array(
+ $header,
+ $body,
+ );
+ }
+
+}
diff --git a/src/view/layout/PHUICurtainView.php b/src/view/layout/PHUICurtainView.php
new file mode 100644
--- /dev/null
+++ b/src/view/layout/PHUICurtainView.php
@@ -0,0 +1,52 @@
+<?php
+
+final class PHUICurtainView extends AphrontTagView {
+
+ private $actionList;
+ private $panels = array();
+
+ public function addAction(PhabricatorActionView $action) {
+ $this->getActionList()->addAction($action);
+ return $this;
+ }
+
+ public function addPanel(PHUICurtainPanelView $curtain_panel) {
+ $this->panels[] = $curtain_panel;
+ return $this;
+ }
+
+ public function setActionList(PhabricatorActionListView $action_list) {
+ $this->actionList = $action_list;
+ return $this;
+ }
+
+ public function getActionList() {
+ return $this->actionList;
+ }
+
+ protected function canAppendChild() {
+ return false;
+ }
+
+ protected function getTagContent() {
+ $action_list = $this->actionList;
+
+ require_celerity_resource('phui-curtain-view-css');
+
+ $panels = $this->renderPanels();
+
+ return id(new PHUIObjectBoxView())
+ ->appendChild($action_list)
+ ->appendChild($panels)
+ ->addClass('phui-two-column-properties');
+ }
+
+ private function renderPanels() {
+ $panels = $this->panels;
+ $panels = msortv($panels, 'getOrderVector');
+
+ return $panels;
+ }
+
+
+}
diff --git a/src/view/phui/PHUITwoColumnView.php b/src/view/phui/PHUITwoColumnView.php
--- a/src/view/phui/PHUITwoColumnView.php
+++ b/src/view/phui/PHUITwoColumnView.php
@@ -11,6 +11,7 @@
private $propertySection = array();
private $actionList;
private $propertyList;
+ private $curtain;
const DISPLAY_LEFT = 'phui-side-column-left';
const DISPLAY_RIGHT = 'phui-side-column-right';
@@ -50,6 +51,15 @@
return $this;
}
+ public function setCurtain(PHUICurtainView $curtain) {
+ $this->curtain = $curtain;
+ return $this;
+ }
+
+ public function getCurtain() {
+ return $this->curtain;
+ }
+
public function setFluid($fluid) {
$this->fluid = $fluid;
return $this;
@@ -98,9 +108,17 @@
$header = null;
if ($this->header) {
- if ($this->actionList) {
- $this->header->setActionList($this->actionList);
+ $curtain = $this->getCurtain();
+ if ($curtain) {
+ $action_list = $curtain->getActionList();
+ } else {
+ $action_list = $this->actionList;
}
+
+ if ($action_list) {
+ $this->header->setActionList($action_list);
+ }
+
$header = phutil_tag_div(
'phui-two-column-header', $this->header);
}
@@ -166,6 +184,8 @@
->addClass('phui-two-column-properties');
}
+ $curtain = $this->getCurtain();
+
return phutil_tag(
'div',
array(
@@ -173,6 +193,7 @@
),
array(
$properties,
+ $curtain,
$this->sideColumn,
));
}
diff --git a/webroot/rsrc/css/phui/phui-curtain-view.css b/webroot/rsrc/css/phui/phui-curtain-view.css
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/css/phui/phui-curtain-view.css
@@ -0,0 +1,22 @@
+/**
+ * @provides phui-curtain-view-css
+ */
+
+.phui-curtain-panel {
+ margin: 4px;
+ padding: 4px 0;
+}
+
+.device-desktop .phui-curtain-panel {
+ border-top: 1px solid {$lightblueborder};
+}
+
+.phui-curtain-panel-header {
+ padding: 4px 0 0;
+ color: {$bluetext};
+ font-weight: bold;
+}
+
+.phui-curtain-panel-body {
+ padding: 4px 0 0;
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 11:18 PM (6 d, 4 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7390652
Default Alt Text
D15414.id37159.diff (28 KB)
Attached To
Mode
D15414: Introduce "Curtain" views, panels, and extensions
Attached
Detach File
Event Timeline
Log In to Comment