diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -9,7 +9,7 @@ 'names' => array( 'conpherence.pkg.css' => 'e68cf1fa', 'conpherence.pkg.js' => '15191c65', - 'core.pkg.css' => 'cff4ff6f', + 'core.pkg.css' => '9d1148a4', 'core.pkg.js' => '4bde473b', 'differential.pkg.css' => '06dc617c', 'differential.pkg.js' => 'ef0b989b', @@ -127,7 +127,7 @@ 'rsrc/css/phui/calendar/phui-calendar-list.css' => '576be600', 'rsrc/css/phui/calendar/phui-calendar-month.css' => '21154caf', 'rsrc/css/phui/calendar/phui-calendar.css' => 'f1ddf11c', - 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '628f59de', + 'rsrc/css/phui/object-item/phui-oi-big-ui.css' => '7a7c22af', 'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77', 'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => '08f4ccc3', 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6', @@ -469,6 +469,7 @@ 'rsrc/js/core/behavior-keyboard-shortcuts.js' => '01fca1f0', 'rsrc/js/core/behavior-lightbox-attachments.js' => '6b31879a', 'rsrc/js/core/behavior-line-linker.js' => '66a62306', + 'rsrc/js/core/behavior-linked-container.js' => '291da458', 'rsrc/js/core/behavior-more.js' => 'a80d0378', 'rsrc/js/core/behavior-object-selector.js' => '77c1f0b0', 'rsrc/js/core/behavior-oncopy.js' => '2926fff2', @@ -616,6 +617,7 @@ 'javelin-behavior-launch-icon-composer' => '48086888', 'javelin-behavior-lightbox-attachments' => '6b31879a', 'javelin-behavior-line-chart' => 'e4232876', + 'javelin-behavior-linked-container' => '291da458', 'javelin-behavior-maniphest-batch-selector' => 'ad54037e', 'javelin-behavior-maniphest-list-editor' => 'a9f88de2', 'javelin-behavior-maniphest-subpriority-editor' => '71237763', @@ -832,7 +834,7 @@ 'phui-lightbox-css' => '0a035e40', 'phui-list-view-css' => '38f8c9bd', 'phui-object-box-css' => '9cff003c', - 'phui-oi-big-ui-css' => '628f59de', + 'phui-oi-big-ui-css' => '7a7c22af', 'phui-oi-color-css' => 'cd2b9b77', 'phui-oi-drag-ui-css' => '08f4ccc3', 'phui-oi-flush-ui-css' => '9d9685d6', @@ -1027,6 +1029,10 @@ 'javelin-uri', 'phabricator-notification', ), + '291da458' => array( + 'javelin-behavior', + 'javelin-dom', + ), '2926fff2' => array( 'javelin-behavior', 'javelin-dom', @@ -1348,9 +1354,6 @@ 'javelin-magical-init', 'javelin-util', ), - '628f59de' => array( - 'phui-oi-list-view-css', - ), '62dfea03' => array( 'javelin-install', 'javelin-util', @@ -1508,6 +1511,9 @@ 'owners-path-editor', 'javelin-behavior', ), + '7a7c22af' => array( + 'phui-oi-list-view-css', + ), '7cbe244b' => array( 'javelin-install', 'javelin-util', diff --git a/src/applications/drydock/controller/DrydockConsoleController.php b/src/applications/drydock/controller/DrydockConsoleController.php --- a/src/applications/drydock/controller/DrydockConsoleController.php +++ b/src/applications/drydock/controller/DrydockConsoleController.php @@ -34,6 +34,7 @@ ->setHeader(pht('Blueprints')) ->setImageIcon('fa-map-o') ->setHref($this->getApplicationURI('blueprint/')) + ->setClickable(true) ->addAttribute( pht( 'Configure blueprints so Drydock can build resources, like '. @@ -44,6 +45,7 @@ ->setHeader(pht('Resources')) ->setImageIcon('fa-map') ->setHref($this->getApplicationURI('resource/')) + ->setClickable(true) ->addAttribute( pht('View and manage resources Drydock has built, like hosts.'))); @@ -52,6 +54,7 @@ ->setHeader(pht('Leases')) ->setImageIcon('fa-link') ->setHref($this->getApplicationURI('lease/')) + ->setClickable(true) ->addAttribute(pht('Manage leases on resources.'))); $menu->addItem( @@ -59,6 +62,7 @@ ->setHeader(pht('Repository Operations')) ->setImageIcon('fa-fighter-jet') ->setHref($this->getApplicationURI('operation/')) + ->setClickable(true) ->addAttribute(pht('Review the repository operation queue.'))); $crumbs = $this->buildApplicationCrumbs(); diff --git a/src/applications/maniphest/controller/ManiphestTaskSubtaskController.php b/src/applications/maniphest/controller/ManiphestTaskSubtaskController.php --- a/src/applications/maniphest/controller/ManiphestTaskSubtaskController.php +++ b/src/applications/maniphest/controller/ManiphestTaskSubtaskController.php @@ -37,39 +37,34 @@ ->addCancelButton($cancel_uri, pht('Close')); } - if ($request->isFormPost()) { - $form_key = $request->getStr('formKey'); - if (isset($subtype_options[$form_key])) { - $subtask_uri = id(new PhutilURI("/task/edit/form/{$form_key}/")) - ->setQueryParam('parent', $id) - ->setQueryParam('template', $id) - ->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus()); - $subtask_uri = $this->getApplicationURI($subtask_uri); + $menu = id(new PHUIObjectItemListView()) + ->setUser($viewer) + ->setBig(true) + ->setFlush(true); - return id(new AphrontRedirectResponse()) - ->setURI($subtask_uri); - } - } + foreach ($subtype_options as $form_key => $subtype_form) { + $subtype_key = $subtype_form->getSubtype(); + $subtype = $subtype_map->getSubtype($subtype_key); - $control = id(new AphrontFormRadioButtonControl()) - ->setName('formKey') - ->setLabel(pht('Subtype')); + $subtask_uri = id(new PhutilURI("/task/edit/form/{$form_key}/")) + ->setQueryParam('parent', $id) + ->setQueryParam('template', $id) + ->setQueryParam('status', ManiphestTaskStatus::getDefaultStatus()); + $subtask_uri = $this->getApplicationURI($subtask_uri); - foreach ($subtype_options as $key => $subtype_form) { - $control->addButton( - $key, - $subtype_form->getDisplayName(), - null); - } + $item = id(new PHUIObjectItemView()) + ->setHeader($subtype_form->getDisplayName()) + ->setHref($subtask_uri) + ->setClickable(true) + ->setImageIcon($subtype->newIconView()) + ->addAttribute($subtype->getName()); - $form = id(new AphrontFormView()) - ->setViewer($viewer) - ->appendControl($control); + $menu->addItem($item); + } return $this->newDialog() ->setTitle(pht('Choose Subtype')) - ->appendForm($form) - ->addSubmitButton(pht('Continue')) + ->appendChild($menu) ->addCancelButton($cancel_uri); } diff --git a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php --- a/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php +++ b/src/applications/transactions/editengine/PhabricatorEditEngineSubtype.php @@ -239,4 +239,9 @@ return new PhabricatorEditEngineSubtypeMap($map); } + public function newIconView() { + return id(new PHUIIconView()) + ->setIcon($this->getIcon(), $this->getColor()); + } + } diff --git a/src/view/AphrontDialogView.php b/src/view/AphrontDialogView.php --- a/src/view/AphrontDialogView.php +++ b/src/view/AphrontDialogView.php @@ -404,7 +404,7 @@ $header), phutil_tag('div', array( - 'class' => 'aphront-dialog-body phabricator-remarkup grouped', + 'class' => 'aphront-dialog-body grouped', ), $children), $tail, diff --git a/src/view/phui/PHUIObjectItemView.php b/src/view/phui/PHUIObjectItemView.php --- a/src/view/phui/PHUIObjectItemView.php +++ b/src/view/phui/PHUIObjectItemView.php @@ -28,6 +28,7 @@ private $sideColumn; private $coverImage; private $description; + private $clickable; private $selectableName; private $selectableValue; @@ -179,6 +180,15 @@ return $this; } + public function setClickable($clickable) { + $this->clickable = $clickable; + return $this; + } + + public function getClickable() { + return $this->clickable; + } + public function setEpoch($epoch) { $date = phabricator_datetime($epoch, $this->getUser()); $this->addIcon('none', $date); @@ -332,6 +342,13 @@ $item_classes[] = 'phui-oi-with-image-icon'; } + if ($this->getClickable()) { + Javelin::initBehavior('linked-container'); + + $item_classes[] = 'phui-oi-linked-container'; + $sigils[] = 'linked-container'; + } + return array( 'class' => $item_classes, 'sigil' => $sigils, @@ -443,15 +460,6 @@ ), $spec['label']); - if (isset($spec['attributes']['href'])) { - $icon_href = phutil_tag( - 'a', - array('href' => $spec['attributes']['href']), - array($icon, $label)); - } else { - $icon_href = array($icon, $label); - } - $classes = array(); $classes[] = 'phui-oi-icon'; if (isset($spec['attributes']['class'])) { @@ -463,7 +471,7 @@ array( 'class' => implode(' ', $classes), ), - $icon_href); + $icon); } $icons[] = phutil_tag( diff --git a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css --- a/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css +++ b/webroot/rsrc/css/phui/object-item/phui-oi-big-ui.css @@ -59,3 +59,16 @@ background-color: {$hoverblue}; border-radius: 3px; } + +.device-desktop .phui-oi-linked-container { + cursor: pointer; +} + +.device-desktop .phui-oi-linked-container:hover { + background-color: {$hoverblue}; + border-radius: 3px; +} + +.device-desktop .phui-oi-linked-container a:hover { + text-decoration: none; +} diff --git a/webroot/rsrc/js/core/behavior-linked-container.js b/webroot/rsrc/js/core/behavior-linked-container.js new file mode 100644 --- /dev/null +++ b/webroot/rsrc/js/core/behavior-linked-container.js @@ -0,0 +1,47 @@ +/** + * @provides javelin-behavior-linked-container + * @requires javelin-behavior javelin-dom + */ + +JX.behavior('linked-container', function() { + + JX.Stratcom.listen( + 'click', + 'linked-container', + function(e) { + + // If the user clicked some link inside the container, bail out and just + // click the link. + if (e.getNode('tag:a')) { + return; + } + + // If this is some sort of unusual click, bail out. Note that we'll + // handle "Left Click" and "Command + Left Click" differently, below. + if (!e.isLeftButton()) { + return; + } + + var container = e.getNode('linked-container'); + + // Find the first link in the container. We're going to pretend the user + // clicked it. + var link = JX.DOM.scry(container, 'a')[0]; + if (!link) { + return; + } + + // If the click is a "Command + Left Click", change the target of the + // link so we open it in a new tab. + var is_command = !!e.getRawEvent().metaKey; + if (is_command) { + var old_target = link.target; + link.target = '_blank'; + link.click(); + link.target = old_target; + } else { + link.click(); + } + }); + +});