Skip to content

Commit 1c5167d

Browse files
author
epriestley
committedJan 13, 2016
Allow profile menu items to be reordered
Summary: Ref T10054. Allows users to drag menu items to reorder them. Test Plan: Reordered a project menu. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10054 Differential Revision: https://secure.phabricator.com/D15011
1 parent f24318f commit 1c5167d

7 files changed

+173
-1
lines changed
 

‎resources/celerity/map.php

+9
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@
424424
'rsrc/js/application/releeph/releeph-request-state-change.js' => 'a0b57eb8',
425425
'rsrc/js/application/releeph/releeph-request-typeahead.js' => 'de2e896f',
426426
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
427+
'rsrc/js/application/search/behavior-reorder-profile-menu-items.js' => 'e2e0a072',
427428
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
428429
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
429430
'rsrc/js/application/transactions/behavior-comment-actions.js' => '1f2fcaf8',
@@ -663,6 +664,7 @@
663664
'javelin-behavior-remarkup-preview' => '4b700e9e',
664665
'javelin-behavior-reorder-applications' => '76b9fc3e',
665666
'javelin-behavior-reorder-columns' => 'e1d25dfb',
667+
'javelin-behavior-reorder-profile-menu-items' => 'e2e0a072',
666668
'javelin-behavior-repository-crossreference' => 'e5339c43',
667669
'javelin-behavior-scrollbar' => '834a1173',
668670
'javelin-behavior-search-reorder-queries' => 'e9581f08',
@@ -1933,6 +1935,13 @@
19331935
'e292eaf4' => array(
19341936
'javelin-install',
19351937
),
1938+
'e2e0a072' => array(
1939+
'javelin-behavior',
1940+
'javelin-stratcom',
1941+
'javelin-workflow',
1942+
'javelin-dom',
1943+
'phabricator-draggable-list',
1944+
),
19361945
'e379b58e' => array(
19371946
'javelin-behavior',
19381947
'javelin-stratcom',

‎src/applications/base/PhabricatorApplication.php

+1
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ protected function getPanelRouting($controller) {
642642
'(?P<panelAction>view)/(?P<panelID>[^/]+)/' => $controller,
643643
'(?P<panelAction>hide)/(?P<panelID>[^/]+)/' => $controller,
644644
'(?P<panelAction>configure)/' => $controller,
645+
'(?P<panelAction>reorder)/' => $controller,
645646
'(?P<panelAction>edit)/'.$edit_route => $controller,
646647
'(?P<panelAction>new)/(?<panelKey>[^/]+)/'.$edit_route => $controller,
647648
'(?P<panelAction>builtin)/(?<panelID>[^/]+)/'.$edit_route

‎src/applications/search/editor/PhabricatorProfilePanelEditor.php

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public function getTransactionTypes() {
1515
$types = parent::getTransactionTypes();
1616

1717
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY;
18+
$types[] = PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
1819

1920
return $types;
2021
}
@@ -27,6 +28,8 @@ protected function getCustomTransactionOldValue(
2728
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
2829
$key = $xaction->getMetadataValue('property.key');
2930
return $object->getPanelProperty($key, null);
31+
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
32+
return $object->getPanelOrder();
3033
}
3134
}
3235

@@ -37,6 +40,8 @@ protected function getCustomTransactionNewValue(
3740
switch ($xaction->getTransactionType()) {
3841
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
3942
return $xaction->getNewValue();
43+
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
44+
return (int)$xaction->getNewValue();
4045
}
4146
}
4247

@@ -50,6 +55,9 @@ protected function applyCustomInternalTransaction(
5055
$value = $xaction->getNewValue();
5156
$object->setPanelProperty($key, $value);
5257
return;
58+
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
59+
$object->setPanelOrder($xaction->getNewValue());
60+
return;
5361
}
5462

5563
return parent::applyCustomInternalTransaction($object, $xaction);
@@ -61,6 +69,7 @@ protected function applyCustomExternalTransaction(
6169

6270
switch ($xaction->getTransactionType()) {
6371
case PhabricatorProfilePanelConfigurationTransaction::TYPE_PROPERTY:
72+
case PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER:
6473
return;
6574
}
6675

‎src/applications/search/engine/PhabricatorProfilePanelEngine.php

+98-1
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ public function buildResponse() {
9191
$content = $this->buildPanelConfigureContent($panel_list);
9292
$crumbs->addTextCrumb(pht('Configure Menu'));
9393
break;
94+
case 'reorder':
95+
$content = $this->buildPanelReorderContent($panel_list);
96+
break;
9497
case 'new':
9598
$panel_key = $request->getURIData('panelKey');
9699
$content = $this->buildPanelNewContent($panel_key);
@@ -204,6 +207,8 @@ private function loadPanels() {
204207
$impl->setViewer($viewer);
205208
}
206209

210+
$panels = msort($panels, 'getSortKey');
211+
207212
// Normalize keys since callers shouldn't rely on this array being
208213
// partially keyed.
209214
$panels = array_values($panels);
@@ -305,6 +310,79 @@ private function getPanelURI($path) {
305310
return "/project/{$id}/panel/{$path}";
306311
}
307312

313+
private function buildPanelReorderContent(array $panels) {
314+
$viewer = $this->getViewer();
315+
$object = $this->getProfileObject();
316+
317+
PhabricatorPolicyFilter::requireCapability(
318+
$viewer,
319+
$object,
320+
PhabricatorPolicyCapability::CAN_EDIT);
321+
322+
$controller = $this->getController();
323+
$request = $controller->getRequest();
324+
325+
$request->validateCSRF();
326+
327+
$order = $request->getStrList('order');
328+
329+
$by_builtin = array();
330+
$by_id = array();
331+
332+
foreach ($panels as $key => $panel) {
333+
$id = $panel->getID();
334+
if ($id) {
335+
$by_id[$id] = $key;
336+
continue;
337+
}
338+
339+
$builtin_key = $panel->getBuiltinKey();
340+
if ($builtin_key) {
341+
$by_builtin[$builtin_key] = $key;
342+
continue;
343+
}
344+
}
345+
346+
$key_order = array();
347+
foreach ($order as $order_item) {
348+
if (isset($by_id[$order_item])) {
349+
$key_order[] = $by_id[$order_item];
350+
continue;
351+
}
352+
if (isset($by_builtin[$order_item])) {
353+
$key_order[] = $by_builtin[$order_item];
354+
continue;
355+
}
356+
}
357+
358+
$panels = array_select_keys($panels, $key_order) + $panels;
359+
360+
$type_order =
361+
PhabricatorProfilePanelConfigurationTransaction::TYPE_ORDER;
362+
363+
$order = 1;
364+
foreach ($panels as $panel) {
365+
$xactions = array();
366+
367+
$xactions[] = id(new PhabricatorProfilePanelConfigurationTransaction())
368+
->setTransactionType($type_order)
369+
->setNewValue($order);
370+
371+
$editor = id(new PhabricatorProfilePanelEditor())
372+
->setContentSourceFromRequest($request)
373+
->setActor($viewer)
374+
->setContinueOnMissingFields(true)
375+
->setContinueOnNoEffect(true)
376+
->applyTransactions($panel, $xactions);
377+
378+
$order++;
379+
}
380+
381+
return id(new AphrontRedirectResponse())
382+
->setURI($this->getConfigureURI());
383+
}
384+
385+
308386
private function buildPanelConfigureContent(array $panels) {
309387
$viewer = $this->getViewer();
310388
$object = $this->getProfileObject();
@@ -314,7 +392,18 @@ private function buildPanelConfigureContent(array $panels) {
314392
$object,
315393
PhabricatorPolicyCapability::CAN_EDIT);
316394

317-
$list = new PHUIObjectItemListView();
395+
$list_id = celerity_generate_unique_node_id();
396+
397+
Javelin::initBehavior(
398+
'reorder-profile-menu-items',
399+
array(
400+
'listID' => $list_id,
401+
'orderURI' => $this->getPanelURI('reorder/'),
402+
));
403+
404+
$list = id(new PHUIObjectItemListView())
405+
->setID($list_id);
406+
318407
foreach ($panels as $panel) {
319408
$id = $panel->getID();
320409
$builtin_key = $panel->getBuiltinKey();
@@ -336,6 +425,14 @@ private function buildPanelConfigureContent(array $panels) {
336425
$item->addAttribute($type);
337426

338427
if ($can_edit) {
428+
$item
429+
->setGrippable(true)
430+
->addSigil('profile-menu-item')
431+
->setMetadata(
432+
array(
433+
'key' => nonempty($id, $builtin_key),
434+
));
435+
339436
if ($id) {
340437
$item->setHref($this->getPanelURI("edit/{$id}/"));
341438
} else {

‎src/applications/search/storage/PhabricatorProfilePanelConfiguration.php

+14
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,20 @@ public function getDisplayName() {
101101
return $this->getPanel()->getDisplayName($this);
102102
}
103103

104+
public function getSortKey() {
105+
$order = $this->getPanelOrder();
106+
if ($order === null) {
107+
$order = 'Z';
108+
} else {
109+
$order = sprintf('%020d', $order);
110+
}
111+
112+
return sprintf(
113+
'~%s%020d',
114+
$order,
115+
$this->getID());
116+
}
117+
104118

105119
/* -( PhabricatorPolicyInterface )----------------------------------------- */
106120

‎src/applications/search/storage/PhabricatorProfilePanelConfigurationTransaction.php

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ final class PhabricatorProfilePanelConfigurationTransaction
44
extends PhabricatorApplicationTransaction {
55

66
const TYPE_PROPERTY = 'profilepanel.property';
7+
const TYPE_ORDER = 'profilepanel.order';
78

89
public function getApplicationName() {
910
return 'search';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @provides javelin-behavior-reorder-profile-menu-items
3+
* @requires javelin-behavior
4+
* javelin-stratcom
5+
* javelin-workflow
6+
* javelin-dom
7+
* phabricator-draggable-list
8+
*/
9+
10+
JX.behavior('reorder-profile-menu-items', function(config) {
11+
12+
var root = JX.$(config.listID);
13+
14+
var list = new JX.DraggableList('profile-menu-item', root)
15+
.setFindItemsHandler(function() {
16+
return JX.DOM.scry(root, 'li', 'profile-menu-item');
17+
});
18+
19+
list.listen('didDrop', function(node) {
20+
var nodes = list.findItems();
21+
var order = [];
22+
var key;
23+
for (var ii = 0; ii < nodes.length; ii++) {
24+
key = JX.Stratcom.getData(nodes[ii]).key;
25+
if (key) {
26+
order.push(key);
27+
}
28+
}
29+
30+
list.lock();
31+
JX.DOM.alterClass(node, 'drag-sending', true);
32+
33+
new JX.Workflow(config.orderURI, {order: order.join()})
34+
.setHandler(function() {
35+
JX.DOM.alterClass(node, 'drag-sending', false);
36+
list.unlock();
37+
})
38+
.start();
39+
});
40+
41+
});

0 commit comments

Comments
 (0)
Failed to load comments.