Page MenuHomePhabricator

D16152.id38858.diff
No OneTemporary

D16152.id38858.diff

diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -7,11 +7,11 @@
*/
return array(
'names' => array(
- 'core.pkg.css' => 'c7fc5aec',
- 'core.pkg.js' => '10275c16',
+ 'core.pkg.css' => '15cd7345',
+ 'core.pkg.js' => '00dbc918',
'darkconsole.pkg.js' => 'e7393ebb',
'differential.pkg.css' => 'b3eea3f5',
- 'differential.pkg.js' => '4b7d8f19',
+ 'differential.pkg.js' => 'd574cebf',
'diffusion.pkg.css' => '91c5d3a6',
'diffusion.pkg.js' => '3a9a8bfa',
'maniphest.pkg.css' => '4845691a',
@@ -124,7 +124,7 @@
'rsrc/css/phui/phui-badge.css' => '3baef8db',
'rsrc/css/phui/phui-big-info-view.css' => 'bd903741',
'rsrc/css/phui/phui-box.css' => '5c8387cf',
- 'rsrc/css/phui/phui-button.css' => 'a64a8de6',
+ 'rsrc/css/phui/phui-button.css' => '287efbfa',
'rsrc/css/phui/phui-chart.css' => '6bf6f78e',
'rsrc/css/phui/phui-crumbs-view.css' => '6b813619',
'rsrc/css/phui/phui-curtain-view.css' => '7148ae25',
@@ -230,7 +230,7 @@
'rsrc/externals/javelin/ext/view/__tests__/ViewInterpreter.js' => '7a94d6a5',
'rsrc/externals/javelin/ext/view/__tests__/ViewRenderer.js' => '6ea96ac9',
'rsrc/externals/javelin/lib/Cookie.js' => '62dfea03',
- 'rsrc/externals/javelin/lib/DOM.js' => '805b806a',
+ 'rsrc/externals/javelin/lib/DOM.js' => '5e5acdda',
'rsrc/externals/javelin/lib/History.js' => 'd4505101',
'rsrc/externals/javelin/lib/JSON.js' => '69adf288',
'rsrc/externals/javelin/lib/Leader.js' => 'fea0eb47',
@@ -457,7 +457,7 @@
'rsrc/js/application/uiexample/gesture-example.js' => '558829c2',
'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5',
'rsrc/js/core/Busy.js' => '59a7976a',
- 'rsrc/js/core/DragAndDropFileUpload.js' => '58dea2fa',
+ 'rsrc/js/core/DragAndDropFileUpload.js' => 'd1d13c52',
'rsrc/js/core/DraggableList.js' => '5a13c79f',
'rsrc/js/core/FileUpload.js' => '680ea2c8',
'rsrc/js/core/Hovercard.js' => '1bd28176',
@@ -515,14 +515,14 @@
'rsrc/js/core/behavior-watch-anchor.js' => '9f36c42d',
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
'rsrc/js/core/phtize.js' => 'd254d646',
- 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '54733475',
+ 'rsrc/js/phui/behavior-phui-dropdown-menu.js' => '3d948804',
'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
'rsrc/js/phui/behavior-phui-object-box-tabs.js' => '2bfa2836',
'rsrc/js/phui/behavior-phui-profile-menu.js' => '12884df9',
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
'rsrc/js/phuix/PHUIXAutocomplete.js' => '9196fb06',
- 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
+ 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '1622a72d',
'rsrc/js/phuix/PHUIXFormControl.js' => 'e15869a8',
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
),
@@ -668,7 +668,7 @@
'javelin-behavior-phabricator-watch-anchor' => '9f36c42d',
'javelin-behavior-pholio-mock-edit' => 'bee502c8',
'javelin-behavior-pholio-mock-view' => 'fbe497e7',
- 'javelin-behavior-phui-dropdown-menu' => '54733475',
+ 'javelin-behavior-phui-dropdown-menu' => '3d948804',
'javelin-behavior-phui-file-upload' => 'b003d4fb',
'javelin-behavior-phui-hovercards' => 'bcaccd64',
'javelin-behavior-phui-object-box-tabs' => '2bfa2836',
@@ -706,7 +706,7 @@
'javelin-color' => '7e41274a',
'javelin-cookie' => '62dfea03',
'javelin-diffusion-locate-file-source' => 'b42eddc7',
- 'javelin-dom' => '805b806a',
+ 'javelin-dom' => '5e5acdda',
'javelin-dynval' => 'f6555212',
'javelin-event' => '2ee659ce',
'javelin-fx' => '54b612ba',
@@ -769,7 +769,7 @@
'phabricator-core-css' => 'd0801452',
'phabricator-countdown-css' => '16c52f5c',
'phabricator-dashboard-css' => 'bc6f2127',
- 'phabricator-drag-and-drop-file-upload' => '58dea2fa',
+ 'phabricator-drag-and-drop-file-upload' => 'd1d13c52',
'phabricator-draggable-list' => '5a13c79f',
'phabricator-fatal-config-template-css' => '8e6c6fcd',
'phabricator-feed-css' => 'ecd4ec57',
@@ -821,7 +821,7 @@
'phui-badge-view-css' => '3baef8db',
'phui-big-info-view-css' => 'bd903741',
'phui-box-css' => '5c8387cf',
- 'phui-button-css' => 'a64a8de6',
+ 'phui-button-css' => '287efbfa',
'phui-calendar-css' => 'ccabe893',
'phui-calendar-day-css' => 'd1cf6f93',
'phui-calendar-list-css' => '56e6381a',
@@ -869,7 +869,7 @@
'phuix-action-list-view' => 'b5c256b8',
'phuix-action-view' => '8cf6d262',
'phuix-autocomplete' => '9196fb06',
- 'phuix-dropdown-menu' => 'bd4c8dca',
+ 'phuix-dropdown-menu' => '1622a72d',
'phuix-form-control-view' => 'e15869a8',
'phuix-icon-view' => 'bff6884b',
'policy-css' => '957ea14c',
@@ -1034,6 +1034,13 @@
'javelin-workflow',
'javelin-workboard-controller',
),
+ '1622a72d' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-dom',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ ),
'1ad0a787' => array(
'javelin-install',
'javelin-reactor',
@@ -1143,6 +1150,12 @@
'javelin-util',
'javelin-uri',
),
+ '3d948804' => array(
+ 'javelin-behavior',
+ 'javelin-stratcom',
+ 'javelin-dom',
+ 'phuix-dropdown-menu',
+ ),
'3f5d6dbf' => array(
'javelin-behavior',
'javelin-dom',
@@ -1274,12 +1287,6 @@
'javelin-leader',
'javelin-json',
),
- 54733475 => array(
- 'javelin-behavior',
- 'javelin-stratcom',
- 'javelin-dom',
- 'phuix-dropdown-menu',
- ),
'54b612ba' => array(
'javelin-color',
'javelin-install',
@@ -1324,14 +1331,6 @@
'javelin-request',
'javelin-util',
),
- '58dea2fa' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-request',
- 'javelin-dom',
- 'javelin-uri',
- 'phabricator-file-upload',
- ),
'59a7976a' => array(
'javelin-install',
'javelin-dom',
@@ -1361,6 +1360,13 @@
'javelin-stratcom',
'javelin-dom',
),
+ '5e5acdda' => array(
+ 'javelin-magical-init',
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ ),
'5e9f347c' => array(
'javelin-behavior',
'multirow-row-manager',
@@ -1521,13 +1527,6 @@
'javelin-behavior',
'javelin-history',
),
- '805b806a' => array(
- 'javelin-magical-init',
- 'javelin-install',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-stratcom',
- ),
'834a1173' => array(
'javelin-behavior',
'javelin-scrollbar',
@@ -1845,13 +1844,6 @@
'javelin-vector',
'phui-hovercard',
),
- 'bd4c8dca' => array(
- 'javelin-install',
- 'javelin-util',
- 'javelin-dom',
- 'javelin-vector',
- 'javelin-stratcom',
- ),
'bdaf4d04' => array(
'javelin-behavior',
'javelin-dom',
@@ -1961,6 +1953,14 @@
'javelin-dynval',
'javelin-reactor-dom',
),
+ 'd1d13c52' => array(
+ 'javelin-install',
+ 'javelin-util',
+ 'javelin-request',
+ 'javelin-dom',
+ 'javelin-uri',
+ 'phabricator-file-upload',
+ ),
'd254d646' => array(
'javelin-util',
),
diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
--- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php
+++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php
@@ -166,15 +166,6 @@
->setDisabled(!$can_edit)
->setWorkflow(!$can_edit));
- $curtain->addAction(
- id(new PhabricatorActionView())
- ->setName(pht('Merge Duplicates In'))
- ->setHref("/search/attach/{$phid}/TASK/merge/")
- ->setWorkflow(true)
- ->setIcon('fa-compress')
- ->setDisabled(!$can_edit)
- ->setWorkflow(true));
-
$edit_config = $edit_engine->loadDefaultEditConfiguration();
$can_create = (bool)$edit_config;
@@ -195,7 +186,10 @@
$edit_uri = $this->getApplicationURI($edit_uri);
}
- $curtain->addAction(
+ $task_menu = id(new PhabricatorActionListView())
+ ->setUser($viewer);
+
+ $task_menu->addAction(
id(new PhabricatorActionView())
->setName(pht('Create Subtask'))
->setHref($edit_uri)
@@ -203,7 +197,7 @@
->setDisabled(!$can_create)
->setWorkflow(!$can_create));
- $curtain->addAction(
+ $task_menu->addAction(
id(new PhabricatorActionView())
->setName(pht('Edit Blocking Tasks'))
->setHref("/search/attach/{$phid}/TASK/blocks/")
@@ -212,6 +206,20 @@
->setDisabled(!$can_edit)
->setWorkflow(true));
+ $task_menu->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Merge Duplicates In'))
+ ->setHref("/search/attach/{$phid}/TASK/merge/")
+ ->setWorkflow(true)
+ ->setIcon('fa-compress')
+ ->setDisabled(!$can_edit)
+ ->setWorkflow(true));
+
+ $curtain->addAction(
+ id(new PhabricatorActionView())
+ ->setName(pht('Edit Related Tasks...'))
+ ->setIcon('fa-anchor')
+ ->setDropdownMenu($task_menu));
$owner_phid = $task->getOwnerPHID();
$author_phid = $task->getAuthorPHID();
diff --git a/src/view/layout/PhabricatorActionView.php b/src/view/layout/PhabricatorActionView.php
--- a/src/view/layout/PhabricatorActionView.php
+++ b/src/view/layout/PhabricatorActionView.php
@@ -14,6 +14,7 @@
private $metadata;
private $selected;
private $openInNewWindow;
+ private $isDropdown;
public function setSelected($selected) {
$this->selected = $selected;
@@ -95,6 +96,24 @@
return $this->openInNewWindow;
}
+ public function setDropdownMenu(PhabricatorActionListView $actions) {
+ Javelin::initBehavior('phui-dropdown-menu');
+
+ $this->addSigil('phui-dropdown-menu');
+ $this->setMetadata(
+ array(
+ 'width' => 'auto',
+ ) + $actions->getDropdownMenuMetadata());
+
+ if (!$this->getHref()) {
+ $this->setHref('#');
+ }
+
+ $this->isDropdown = true;
+
+ return $this;
+ }
+
public function render() {
$icon = null;
@@ -155,6 +174,12 @@
$target = null;
}
+ if ($this->isDropdown) {
+ $caret = phutil_tag('span', array('class' => 'caret'), '');
+ } else {
+ $caret = null;
+ }
+
$item = javelin_tag(
'a',
array(
@@ -164,7 +189,7 @@
'sigil' => $sigils,
'meta' => $this->metadata,
),
- array($icon, $this->name));
+ array($icon, $this->name, $caret));
}
} else {
$item = phutil_tag(
diff --git a/src/view/phui/PHUITimelineEventView.php b/src/view/phui/PHUITimelineEventView.php
--- a/src/view/phui/PHUITimelineEventView.php
+++ b/src/view/phui/PHUITimelineEventView.php
@@ -327,9 +327,7 @@
'sigil' => $sigil,
'aria-haspopup' => 'true',
'aria-expanded' => 'false',
- 'meta' => array(
- 'items' => hsprintf('%s', $action_list),
- ),
+ 'meta' => $action_list->getDropdownMenuMetadata(),
),
array(
$aural,
diff --git a/webroot/rsrc/css/phui/phui-button.css b/webroot/rsrc/css/phui/phui-button.css
--- a/webroot/rsrc/css/phui/phui-button.css
+++ b/webroot/rsrc/css/phui/phui-button.css
@@ -199,6 +199,7 @@
border: 1px solid {$blueborder};
border-radius: 3px;
margin-bottom: 16px;
+ box-sizing: border-box;
}
.phuix-dropdown-menu a:focus {
@@ -256,6 +257,20 @@
margin-left: 6px;
}
+.phabricator-action-view-item .caret {
+ float: right;
+ margin-top: 7px;
+ margin-right: 6px;
+ border-top-color: {$greytext};
+}
+
+a.phabricator-action-view-item.phuix-dropdown-open,
+.device-desktop
+ .phabricator-action-view:hover
+ a.phabricator-action-view-item.phuix-dropdown-open {
+ background: {$darkgreybackground};
+}
+
.small.dropdown .caret {
margin-top: 6px;
}
diff --git a/webroot/rsrc/externals/javelin/lib/DOM.js b/webroot/rsrc/externals/javelin/lib/DOM.js
--- a/webroot/rsrc/externals/javelin/lib/DOM.js
+++ b/webroot/rsrc/externals/javelin/lib/DOM.js
@@ -1011,6 +1011,25 @@
}
},
+
+ /**
+ * Test if a node is a container for a child.
+ *
+ * @param Node Container node.
+ * @param Node Child node.
+ * @return bool True if the child exists inside the container.
+ */
+ contains: function(container, child) {
+ do {
+ if (child === container) {
+ return true;
+ }
+ child = child.parentNode;
+ } while (child);
+
+ return false;
+ },
+
_getAutoID : function(node) {
if (!node.getAttribute('data-autoid')) {
node.setAttribute('data-autoid', 'autoid_'+(++JX.DOM._autoid));
diff --git a/webroot/rsrc/js/core/DragAndDropFileUpload.js b/webroot/rsrc/js/core/DragAndDropFileUpload.js
--- a/webroot/rsrc/js/core/DragAndDropFileUpload.js
+++ b/webroot/rsrc/js/core/DragAndDropFileUpload.js
@@ -73,19 +73,6 @@
},
start : function() {
-
- // TODO: move this to JX.DOM.contains()?
- function contains(container, child) {
- do {
- if (child === container) {
- return true;
- }
- child = child.parentNode;
- } while (child);
-
- return false;
- }
-
// Firefox has some issues sometimes; implement this click handler so
// the user can recover. See T5188.
var on_click = JX.bind(this, function (e) {
@@ -115,7 +102,7 @@
}
}
- if (contains(this._getTarget(), e.getTarget())) {
+ if (JX.DOM.contains(this._getTarget(), e.getTarget())) {
this._updateDepth(1);
}
@@ -130,7 +117,7 @@
return;
}
- if (contains(this._getTarget(), e.getTarget())) {
+ if (JX.DOM.contains(this._getTarget(), e.getTarget())) {
this._updateDepth(-1);
}
});
diff --git a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
--- a/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
+++ b/webroot/rsrc/js/phui/behavior-phui-dropdown-menu.js
@@ -21,6 +21,7 @@
var icon = e.getNode('phui-dropdown-menu');
data.menu = new JX.PHUIXDropdownMenu(icon);
data.menu.setContent(list);
+ data.menu.setWidth(data.width || null);
data.menu.open();
JX.DOM.listen(list, 'click', 'tag:a', function(e) {
diff --git a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
--- a/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
+++ b/webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
@@ -51,6 +51,11 @@
offsetY: 0
},
+ statics: {
+ _lastDim: null,
+ _lastPos: null
+ },
+
members: {
_node: null,
_menu: null,
@@ -80,6 +85,13 @@
if (!this._open) {
return;
}
+
+ // Save this menu's position and dimensions as the last closed menu.
+ // We'll reuse them if we're opening a submenu.
+ var self = JX.PHUIXDropdownMenu;
+ self._lastPos = JX.$V(this._menu);
+ self._lastDim = JX.Vector.getDim(this._menu);
+
this._open = false;
this._hide();
@@ -120,11 +132,8 @@
}
var t = e.getTarget();
- while (t) {
- if (t == this._menu || t == this._node) {
- return;
- }
- t = t.parentNode;
+ if (JX.DOM.contains(this._menu, t) || JX.DOM.contains(this._node, t)) {
+ return;
}
this.close();
@@ -133,7 +142,14 @@
_show : function() {
document.body.appendChild(this._menu);
- if (this.getWidth()) {
+ var width = this.getWidth();
+ if (width == 'auto') {
+ if (JX.DOM.contains(document, this._node)) {
+ var d = new JX.Vector.getDim(this._node);
+ d.y = null;
+ d.setDim(this._menu);
+ }
+ } else if (width) {
new JX.Vector(this.getWidth(), null).setDim(this._menu);
}
@@ -168,6 +184,18 @@
var v = JX.$V(this._node);
var d = JX.Vector.getDim(this._node);
+ // If the node has been removed from the DOM, assume we are opening
+ // a new dropdown from an existing dropdown. We're just going to replace
+ // the old dropdown.
+ if (!JX.DOM.contains(document, this._node)) {
+ var self = JX.PHUIXDropdownMenu;
+ if (self._lastPos) {
+ v = self._lastPos;
+ d = self._lastDim;
+ d.y = 0;
+ }
+ }
+
switch (this.getAlign()) {
case 'right':
v = v.add(d)

File Metadata

Mime Type
text/plain
Expires
Fri, Mar 21, 9:41 AM (6 d, 12 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7715296
Default Alt Text
D16152.id38858.diff (16 KB)

Event Timeline