@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Improve minor workboard drag behaviors

Summary:
Ref T5240.

- Add proper class when dropping cards.
- Add proper class when creating new cards.
- Make X-drag explicit so that it works if there's only one column.
- Stop tootips when dragging, resume them after dropping.
- Move CSS rule for consistency.
- Allow user to hit "Escape" to cancel an in-progress drag.

Test Plan:
- Dropped cards.
- Created new cards.
- X-dragged on a workboard with one column and a dashboard.
- Dragged over a tooltip (no tip), dropped, moused over tooltip (tip).
- Hit escape during a drag.

Reviewers: chad

Reviewed By: chad

Subscribers: cspeckmim

Maniphest Tasks: T5240

Differential Revision: https://secure.phabricator.com/D15163

+115 -79
+45 -45
resources/celerity/map.php
··· 7 7 */ 8 8 return array( 9 9 'names' => array( 10 - 'core.pkg.css' => 'a01828d4', 11 - 'core.pkg.js' => 'c5178ede', 10 + 'core.pkg.css' => '764d4c80', 11 + 'core.pkg.js' => '5b832397', 12 12 'darkconsole.pkg.js' => 'e7393ebb', 13 13 'differential.pkg.css' => '2de124c9', 14 14 'differential.pkg.js' => '5c2ba922', ··· 142 142 'rsrc/css/phui/phui-info-view.css' => '6d7c3509', 143 143 'rsrc/css/phui/phui-list.css' => '9da2aa00', 144 144 'rsrc/css/phui/phui-object-box.css' => '407eaf5a', 145 - 'rsrc/css/phui/phui-object-item-list-view.css' => '56aab18d', 145 + 'rsrc/css/phui/phui-object-item-list-view.css' => 'fe594a65', 146 146 'rsrc/css/phui/phui-pager.css' => 'bea33d23', 147 147 'rsrc/css/phui/phui-pinboard-view.css' => '2495140e', 148 148 'rsrc/css/phui/phui-profile-menu.css' => 'ab4fcf5f', ··· 154 154 'rsrc/css/phui/phui-timeline-view.css' => '2efceff8', 155 155 'rsrc/css/phui/phui-two-column-view.css' => 'c75bfc5b', 156 156 'rsrc/css/phui/workboards/phui-workboard.css' => 'b07a5524', 157 - 'rsrc/css/phui/workboards/phui-workcard.css' => '92178913', 157 + 'rsrc/css/phui/workboards/phui-workcard.css' => '42c703d7', 158 158 'rsrc/css/phui/workboards/phui-workpanel.css' => 'b90970eb', 159 159 'rsrc/css/sprite-login.css' => '60e8560e', 160 160 'rsrc/css/sprite-menu.css' => '9dd65b92', ··· 368 368 'rsrc/js/application/countdown/timer.js' => 'e4cc26b3', 369 369 'rsrc/js/application/daemon/behavior-bulk-job-reload.js' => 'edf8a145', 370 370 'rsrc/js/application/dashboard/behavior-dashboard-async-panel.js' => '469c0d9e', 371 - 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '82439934', 371 + 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => '019f36c4', 372 372 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '453c5375', 373 373 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => 'd4eecc63', 374 374 'rsrc/js/application/differential/ChangesetViewManager.js' => 'a2828756', ··· 413 413 'rsrc/js/application/phortune/phortune-credit-card-form.js' => '2290aeef', 414 414 'rsrc/js/application/policy/behavior-policy-control.js' => 'ae45872f', 415 415 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '5e9f347c', 416 - 'rsrc/js/application/projects/behavior-project-boards.js' => 'ba4fa35c', 416 + 'rsrc/js/application/projects/behavior-project-boards.js' => '16c76360', 417 417 'rsrc/js/application/projects/behavior-project-create.js' => '065227cc', 418 418 'rsrc/js/application/projects/behavior-reorder-columns.js' => 'e1d25dfb', 419 419 'rsrc/js/application/releeph/releeph-preview-branch.js' => 'b2b4fbaf', ··· 446 446 'rsrc/js/application/uiexample/notification-example.js' => '8ce821c5', 447 447 'rsrc/js/core/Busy.js' => '59a7976a', 448 448 'rsrc/js/core/DragAndDropFileUpload.js' => 'ad10aeac', 449 - 'rsrc/js/core/DraggableList.js' => 'f1844746', 449 + 'rsrc/js/core/DraggableList.js' => '1fe26f18', 450 450 'rsrc/js/core/FileUpload.js' => '477359c8', 451 451 'rsrc/js/core/Hovercard.js' => 'c6f720ff', 452 452 'rsrc/js/core/KeyboardShortcut.js' => '1ae869f2', ··· 457 457 'rsrc/js/core/ShapedRequest.js' => '7cbe244b', 458 458 'rsrc/js/core/TextAreaUtils.js' => '9e54692d', 459 459 'rsrc/js/core/Title.js' => 'df5e11d2', 460 - 'rsrc/js/core/ToolTip.js' => '1d298e3a', 460 + 'rsrc/js/core/ToolTip.js' => '6323f942', 461 461 'rsrc/js/core/behavior-active-nav.js' => 'e379b58e', 462 462 'rsrc/js/core/behavior-audio-source.js' => '59b251eb', 463 463 'rsrc/js/core/behavior-autofocus.js' => '7319e029', ··· 579 579 'javelin-behavior-countdown-timer' => 'e4cc26b3', 580 580 'javelin-behavior-dark-console' => 'f411b6ae', 581 581 'javelin-behavior-dashboard-async-panel' => '469c0d9e', 582 - 'javelin-behavior-dashboard-move-panels' => '82439934', 582 + 'javelin-behavior-dashboard-move-panels' => '019f36c4', 583 583 'javelin-behavior-dashboard-query-panel-select' => '453c5375', 584 584 'javelin-behavior-dashboard-tab-panel' => 'd4eecc63', 585 585 'javelin-behavior-day-view' => '5c46cff2', ··· 653 653 'javelin-behavior-phui-profile-menu' => '12884df9', 654 654 'javelin-behavior-policy-control' => 'ae45872f', 655 655 'javelin-behavior-policy-rule-editor' => '5e9f347c', 656 - 'javelin-behavior-project-boards' => 'ba4fa35c', 656 + 'javelin-behavior-project-boards' => '16c76360', 657 657 'javelin-behavior-project-create' => '065227cc', 658 658 'javelin-behavior-quicksand-blacklist' => '7927a7d3', 659 659 'javelin-behavior-recurring-edit' => '5f1c4d5f', ··· 741 741 'phabricator-countdown-css' => 'e7544472', 742 742 'phabricator-dashboard-css' => 'eb458607', 743 743 'phabricator-drag-and-drop-file-upload' => 'ad10aeac', 744 - 'phabricator-draggable-list' => 'f1844746', 744 + 'phabricator-draggable-list' => '1fe26f18', 745 745 'phabricator-fatal-config-template-css' => '8e6c6fcd', 746 746 'phabricator-feed-css' => 'ecd4ec57', 747 747 'phabricator-file-upload' => '477359c8', ··· 768 768 'phabricator-standard-page-view' => '7b0d68d8', 769 769 'phabricator-textareautils' => '9e54692d', 770 770 'phabricator-title' => 'df5e11d2', 771 - 'phabricator-tooltip' => '1d298e3a', 771 + 'phabricator-tooltip' => '6323f942', 772 772 'phabricator-ui-example-css' => '528b19de', 773 773 'phabricator-uiexample-javelin-view' => 'd4a14807', 774 774 'phabricator-uiexample-reactor-button' => 'd19198c8', ··· 818 818 'phui-inline-comment-view-css' => '0fdb3667', 819 819 'phui-list-view-css' => '9da2aa00', 820 820 'phui-object-box-css' => '407eaf5a', 821 - 'phui-object-item-list-view-css' => '56aab18d', 821 + 'phui-object-item-list-view-css' => 'fe594a65', 822 822 'phui-pager-css' => 'bea33d23', 823 823 'phui-pinboard-view-css' => '2495140e', 824 824 'phui-profile-menu-css' => 'ab4fcf5f', ··· 831 831 'phui-timeline-view-css' => '2efceff8', 832 832 'phui-two-column-view-css' => 'c75bfc5b', 833 833 'phui-workboard-view-css' => 'b07a5524', 834 - 'phui-workcard-view-css' => '92178913', 834 + 'phui-workcard-view-css' => '42c703d7', 835 835 'phui-workpanel-view-css' => 'b90970eb', 836 836 'phuix-action-list-view' => 'b5c256b8', 837 837 'phuix-action-view' => '8cf6d262', ··· 875 875 'javelin-behavior-device', 876 876 'javelin-vector', 877 877 ), 878 + '019f36c4' => array( 879 + 'javelin-behavior', 880 + 'javelin-dom', 881 + 'javelin-util', 882 + 'javelin-stratcom', 883 + 'javelin-workflow', 884 + 'phabricator-draggable-list', 885 + ), 878 886 '031cee25' => array( 879 887 'javelin-behavior', 880 888 'javelin-request', ··· 944 952 'javelin-stratcom', 945 953 'javelin-dom', 946 954 'javelin-history', 955 + ), 956 + '16c76360' => array( 957 + 'javelin-behavior', 958 + 'javelin-dom', 959 + 'javelin-util', 960 + 'javelin-vector', 961 + 'javelin-stratcom', 962 + 'javelin-workflow', 963 + 'phabricator-draggable-list', 947 964 ), 948 965 '1ad0a787' => array( 949 966 'javelin-install', ··· 962 979 'javelin-dom', 963 980 'javelin-typeahead-normalizer', 964 981 ), 965 - '1d298e3a' => array( 966 - 'javelin-install', 967 - 'javelin-util', 968 - 'javelin-dom', 969 - 'javelin-vector', 970 - ), 971 982 '1d45c74d' => array( 972 983 'javelin-behavior', 973 984 'javelin-dom', ··· 995 1006 'phuix-form-control-view', 996 1007 'phuix-icon-view', 997 1008 'javelin-behavior-phabricator-gesture', 1009 + ), 1010 + '1fe26f18' => array( 1011 + 'javelin-install', 1012 + 'javelin-dom', 1013 + 'javelin-stratcom', 1014 + 'javelin-util', 1015 + 'javelin-vector', 1016 + 'javelin-magical-init', 998 1017 ), 999 1018 '21ba5861' => array( 1000 1019 'javelin-behavior', ··· 1290 1309 'javelin-install', 1291 1310 'javelin-util', 1292 1311 ), 1312 + '6323f942' => array( 1313 + 'javelin-install', 1314 + 'javelin-util', 1315 + 'javelin-dom', 1316 + 'javelin-vector', 1317 + ), 1293 1318 '635de1ec' => array( 1294 1319 'javelin-behavior', 1295 1320 'javelin-stratcom', ··· 1430 1455 'javelin-vector', 1431 1456 'javelin-stratcom', 1432 1457 ), 1433 - 82439934 => array( 1434 - 'javelin-behavior', 1435 - 'javelin-dom', 1436 - 'javelin-util', 1437 - 'javelin-stratcom', 1438 - 'javelin-workflow', 1439 - 'phabricator-draggable-list', 1440 - ), 1441 1458 '834a1173' => array( 1442 1459 'javelin-behavior', 1443 1460 'javelin-scrollbar', ··· 1747 1764 'b90970eb' => array( 1748 1765 'phui-workcard-view-css', 1749 1766 ), 1750 - 'ba4fa35c' => array( 1751 - 'javelin-behavior', 1752 - 'javelin-dom', 1753 - 'javelin-util', 1754 - 'javelin-vector', 1755 - 'javelin-stratcom', 1756 - 'javelin-workflow', 1757 - 'phabricator-draggable-list', 1758 - ), 1759 1767 'bd4c8dca' => array( 1760 1768 'javelin-install', 1761 1769 'javelin-util', ··· 2010 2018 'javelin-util', 2011 2019 'javelin-workflow', 2012 2020 'javelin-json', 2013 - ), 2014 - 'f1844746' => array( 2015 - 'javelin-install', 2016 - 'javelin-dom', 2017 - 'javelin-stratcom', 2018 - 'javelin-util', 2019 - 'javelin-vector', 2020 - 'javelin-magical-init', 2021 2021 ), 2022 2022 'f411b6ae' => array( 2023 2023 'javelin-behavior',
+2
src/applications/maniphest/editor/ManiphestEditEngine.php
··· 338 338 ->setCanEdit(true) 339 339 ->getItem(); 340 340 341 + $tasks->addClass('phui-workcard'); 342 + 341 343 $payload = array( 342 344 'tasks' => $tasks, 343 345 'data' => $data,
+2
src/applications/project/controller/PhabricatorProjectMoveController.php
··· 160 160 ->setProject($project) 161 161 ->getItem(); 162 162 163 + $card->addClass('phui-workcard'); 164 + 163 165 return id(new AphrontAjaxResponse())->setContent( 164 166 array('task' => $card)); 165 167 }
-5
webroot/rsrc/css/phui/phui-object-item-list-view.css
··· 374 374 attributes. 375 375 */ 376 376 377 - .phui-workcard.phui-object-item { 378 - border-left-width: 4px; 379 - box-sizing: border-box; 380 - } 381 - 382 377 .phui-object-item { 383 378 border-left-width: 0; 384 379 }
+2 -1
webroot/rsrc/css/phui/workboards/phui-workcard.css
··· 6 6 background-color: #fff; 7 7 border-radius: 3px; 8 8 margin-bottom: 8px; 9 + border-left-width: 4px; 10 + box-sizing: border-box; 9 11 } 10 12 11 13 .phui-workcard .phui-object-item-name { ··· 85 87 .phui-workcard .phui-object-item-attributes { 86 88 margin-right: 12px; 87 89 } 88 - 89 90 90 91 91 92 /* - Draggable Colors --------------------------------------------------------*/
+2 -1
webroot/rsrc/js/application/dashboard/behavior-dashboard-move-panels.js
··· 85 85 for (ii = 0; ii < cols.length; ii++) { 86 86 col = cols[ii]; 87 87 var list = new JX.DraggableList(itemSigil, col) 88 - .setFindItemsHandler(JX.bind(null, finditems, col)); 88 + .setFindItemsHandler(JX.bind(null, finditems, col)) 89 + .setCanDragX(true); 89 90 90 91 list.listen('didSend', JX.bind(list, onupdate, col)); 91 92 list.listen('didReceive', JX.bind(list, onupdate, col));
+2 -1
webroot/rsrc/js/application/projects/behavior-project-boards.js
··· 231 231 232 232 for (ii = 0; ii < cols.length; ii++) { 233 233 var list = new JX.DraggableList('project-card', cols[ii]) 234 - .setFindItemsHandler(JX.bind(null, finditems, cols[ii])); 234 + .setFindItemsHandler(JX.bind(null, finditems, cols[ii])) 235 + .setCanDragX(true); 235 236 236 237 list.listen('didSend', JX.bind(list, onupdate, cols[ii])); 237 238 list.listen('didReceive', JX.bind(list, onupdate, cols[ii]));
+33 -18
webroot/rsrc/js/core/DraggableList.js
··· 23 23 JX.Stratcom.listen('mousemove', null, JX.bind(this, this._onmove)); 24 24 JX.Stratcom.listen('scroll', null, JX.bind(this, this._onmove)); 25 25 JX.Stratcom.listen('mouseup', null, JX.bind(this, this._ondrop)); 26 + JX.Stratcom.listen('keypress', null, JX.bind(this, this._onkey)); 26 27 }, 27 28 28 29 events : [ ··· 37 38 'didReceive'], 38 39 39 40 properties : { 40 - findItemsHandler : null 41 + findItemsHandler: null, 42 + canDragX: false 41 43 }, 42 44 43 45 members : { ··· 97 99 return this; 98 100 }, 99 101 100 - _canDragX : function() { 101 - return this._hasGroup(); 102 - }, 103 - 104 102 _hasGroup : function() { 105 103 return (this._group.length > 1); 106 104 }, ··· 236 234 237 235 var cursor = JX.$V(e); 238 236 this._offset = new JX.Vector(pos.x - cursor.x, pos.y - cursor.y); 237 + 238 + JX.Tooltip.lock(); 239 239 240 240 this.invoke('didBeginDrag', this._dragging); 241 241 }, ··· 446 446 p.y += this._offset.y; 447 447 this._clone.style.top = p.y + 'px'; 448 448 449 - if (this._canDragX()) { 449 + if (this.getCanDragX()) { 450 450 p.x += this._offset.x; 451 451 this._clone.style.left = p.x + 'px'; 452 452 } ··· 454 454 e.kill(); 455 455 }, 456 456 457 + _onkey: function(e) { 458 + // Cancel any current drag if the user presses escape. 459 + if (this._dragging && (e.getSpecialKey() == 'esc')) { 460 + e.kill(); 461 + this._drop(null); 462 + return; 463 + } 464 + }, 465 + 457 466 _ondrop : function(e) { 467 + var p = JX.$V(e); 468 + this._drop(p); 469 + }, 470 + 471 + _drop: function(cursor) { 458 472 if (!this._dragging) { 459 473 return; 460 474 } 461 475 462 - var p = JX.$V(e); 463 - 464 476 var dragging = this._dragging; 465 477 this._dragging = null; 466 478 ··· 471 483 var target = false; 472 484 var ghost = false; 473 485 474 - var target_list = this._getTargetList(p); 475 - if (target_list) { 476 - target = target_list._target; 477 - ghost = target_list.getGhostNode(); 486 + if (cursor) { 487 + var target_list = this._getTargetList(cursor); 488 + if (target_list) { 489 + target = target_list._target; 490 + ghost = target_list.getGhostNode(); 491 + } 478 492 } 479 493 480 494 JX.$V(0, 0).setPos(dragging); 481 495 482 - if (target !== false) { 496 + if (target === false) { 497 + this.invoke('didCancelDrag', dragging); 498 + } else { 483 499 JX.DOM.remove(dragging); 484 500 JX.DOM.replace(ghost, dragging); 485 501 this.invoke('didSend', dragging, target_list); 486 502 target_list.invoke('didReceive', dragging, this); 487 503 target_list.invoke('didDrop', dragging, target, this); 488 - } else { 489 - this.invoke('didCancelDrag', dragging); 490 504 } 491 505 492 506 var group = this._group; ··· 495 509 group[ii]._clearTarget(); 496 510 } 497 511 498 - if (!this.invoke('didEndDrag', dragging).getPrevented()) { 499 - JX.DOM.alterClass(dragging, 'drag-dragging', false); 500 - } 512 + JX.DOM.alterClass(dragging, 'drag-dragging', false); 513 + JX.Tooltip.unlock(); 501 514 502 515 e.kill(); 516 + 517 + this.invoke('didEndDrag', dragging); 503 518 }, 504 519 505 520 lock : function() {
+27 -8
webroot/rsrc/js/core/ToolTip.js
··· 9 9 10 10 JX.install('Tooltip', { 11 11 12 - statics : { 13 - _node : null, 12 + statics: { 13 + _node: null, 14 + _lock: 0, 14 15 15 16 show : function(root, scale, align, content) { 17 + var self = JX.Tooltip; 18 + 19 + if (self._lock) { 20 + return; 21 + } 22 + 16 23 if (__DEV__) { 17 24 switch (align) { 18 25 case 'N': ··· 45 52 node.style.maxWidth = scale + 'px'; 46 53 47 54 JX.Tooltip.hide(); 48 - this._node = node; 55 + self._node = node; 49 56 50 57 // Append the tip to the document, but offscreen, so we can measure it. 51 58 node.style.left = '-10000px'; 52 59 document.body.appendChild(node); 53 60 54 61 // Jump through some hoops trying to auto-position the tooltip 55 - var pos = this._getSmartPosition(align, root, node); 62 + var pos = self._getSmartPosition(align, root, node); 56 63 pos.setPos(node); 57 64 }, 58 65 59 66 _getSmartPosition: function (align, root, node) { 60 - var pos = JX.Tooltip._proposePosition(align, root, node); 67 + var self = JX.Tooltip; 68 + var pos = self._proposePosition(align, root, node); 61 69 62 70 // If toolip is offscreen, try to be clever 63 71 if (!JX.Tooltip.isOnScreen(pos, node)) { 64 - align = JX.Tooltip._getImprovedOrientation(pos, node); 65 - pos = JX.Tooltip._proposePosition(align, root, node); 72 + align = self._getImprovedOrientation(pos, node); 73 + pos = self._proposePosition(align, root, node); 66 74 } 67 75 68 - JX.Tooltip._setAnchor(align); 76 + self._setAnchor(align); 69 77 return pos; 70 78 }, 71 79 ··· 167 175 JX.DOM.remove(this._node); 168 176 this._node = null; 169 177 } 178 + }, 179 + 180 + lock: function() { 181 + var self = JX.Tooltip; 182 + self.hide(); 183 + self._lock++; 184 + }, 185 + 186 + unlock: function() { 187 + var self = JX.Tooltip; 188 + self._lock--; 170 189 } 171 190 } 172 191 });