@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.

Update the "View Options" menu for recent filetree changes

Summary:
Ref T13516. Minor improvements here:

- Show key commands in the "View Options" dropdown.
- Organize it slightly better.
- Improve disabled item behaviors a little bit.
- Add a "Browse Directory" action.
- Rename "...in Diffusion" to "...in Repository".
- Make "d", "D", and "h" use the same targeting rules as "\".
- When you hide a file with the "h" menu item, select it.

Test Plan: Poked at the menu a lot, ran into less questionable behavior.

Maniphest Tasks: T13516

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

+289 -89
+33 -33
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => '3c8a0668', 11 11 'conpherence.pkg.js' => '020aebcf', 12 - 'core.pkg.css' => 'dd5f04a3', 13 - 'core.pkg.js' => '544bc792', 12 + 'core.pkg.css' => '61b7e380', 13 + 'core.pkg.js' => 'fc49f65b', 14 14 'differential.pkg.css' => 'cb99cd21', 15 - 'differential.pkg.js' => '54613dd5', 15 + 'differential.pkg.js' => 'ae77bf85', 16 16 'diffusion.pkg.css' => '42c75c37', 17 17 'diffusion.pkg.js' => 'a98c0bf7', 18 18 'maniphest.pkg.css' => '35995d6d', ··· 134 134 'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '490e2e2e', 135 135 'rsrc/css/phui/object-item/phui-oi-list-view.css' => 'd7723ecc', 136 136 'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => '6a30fa46', 137 - 'rsrc/css/phui/phui-action-list.css' => 'e820263c', 137 + 'rsrc/css/phui/phui-action-list.css' => '1b0085b2', 138 138 'rsrc/css/phui/phui-action-panel.css' => '6c386cbf', 139 139 'rsrc/css/phui/phui-badge.css' => '666e25ad', 140 140 'rsrc/css/phui/phui-basic-nav-view.css' => '56ebd66d', ··· 378 378 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 379 379 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 380 380 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 381 - 'rsrc/js/application/diff/DiffChangeset.js' => 'dd1a6f34', 382 - 'rsrc/js/application/diff/DiffChangesetList.js' => '57035863', 381 + 'rsrc/js/application/diff/DiffChangeset.js' => '27305b60', 382 + 'rsrc/js/application/diff/DiffChangesetList.js' => '62a3a351', 383 383 'rsrc/js/application/diff/DiffInline.js' => '16e97ebc', 384 384 'rsrc/js/application/diff/DiffPathView.js' => '8207abf9', 385 385 'rsrc/js/application/diff/DiffTreeView.js' => '5d83623b', ··· 520 520 'rsrc/js/phui/behavior-phui-tab-group.js' => '242aa08b', 521 521 'rsrc/js/phui/behavior-phui-timer-control.js' => 'f84bcbf4', 522 522 'rsrc/js/phuix/PHUIXActionListView.js' => 'c68f183f', 523 - 'rsrc/js/phuix/PHUIXActionView.js' => 'aaa08f3b', 523 + 'rsrc/js/phuix/PHUIXActionView.js' => 'a8f573a9', 524 524 'rsrc/js/phuix/PHUIXAutocomplete.js' => '2fbe234d', 525 525 'rsrc/js/phuix/PHUIXButtonView.js' => '55a24e84', 526 526 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '7acfd98b', ··· 766 766 'path-typeahead' => 'ad486db3', 767 767 'people-picture-menu-item-css' => 'fe8e07cf', 768 768 'people-profile-css' => '2ea2daa1', 769 - 'phabricator-action-list-view-css' => 'e820263c', 769 + 'phabricator-action-list-view-css' => '1b0085b2', 770 770 'phabricator-busy' => '5202e831', 771 771 'phabricator-chatlog-css' => 'abdc76ee', 772 772 'phabricator-content-source-view-css' => 'cdf0d579', ··· 775 775 'phabricator-darklog' => '3b869402', 776 776 'phabricator-darkmessage' => '26cd4b73', 777 777 'phabricator-dashboard-css' => '5a205b9d', 778 - 'phabricator-diff-changeset' => 'dd1a6f34', 779 - 'phabricator-diff-changeset-list' => '57035863', 778 + 'phabricator-diff-changeset' => '27305b60', 779 + 'phabricator-diff-changeset-list' => '62a3a351', 780 780 'phabricator-diff-inline' => '16e97ebc', 781 781 'phabricator-diff-path-view' => '8207abf9', 782 782 'phabricator-diff-tree-view' => '5d83623b', ··· 884 884 'phui-workcard-view-css' => '913441b6', 885 885 'phui-workpanel-view-css' => '3ae89b20', 886 886 'phuix-action-list-view' => 'c68f183f', 887 - 'phuix-action-view' => 'aaa08f3b', 887 + 'phuix-action-view' => 'a8f573a9', 888 888 'phuix-autocomplete' => '2fbe234d', 889 889 'phuix-button-view' => '55a24e84', 890 890 'phuix-dropdown-menu' => '7acfd98b', ··· 1146 1146 'javelin-json', 1147 1147 'phabricator-prefab', 1148 1148 ), 1149 + '27305b60' => array( 1150 + 'javelin-dom', 1151 + 'javelin-util', 1152 + 'javelin-stratcom', 1153 + 'javelin-install', 1154 + 'javelin-workflow', 1155 + 'javelin-router', 1156 + 'javelin-behavior-device', 1157 + 'javelin-vector', 1158 + 'phabricator-diff-inline', 1159 + 'phabricator-diff-path-view', 1160 + ), 1149 1161 '289bf236' => array( 1150 1162 'javelin-install', 1151 1163 'javelin-util', ··· 1424 1436 'javelin-stratcom', 1425 1437 'javelin-dom', 1426 1438 ), 1427 - 57035863 => array( 1428 - 'javelin-install', 1429 - 'phuix-button-view', 1430 - 'phabricator-diff-tree-view', 1431 - ), 1432 1439 '5793d835' => array( 1433 1440 'javelin-install', 1434 1441 'javelin-util', ··· 1514 1521 '60cd9241' => array( 1515 1522 'javelin-behavior', 1516 1523 ), 1524 + '62a3a351' => array( 1525 + 'javelin-install', 1526 + 'phuix-button-view', 1527 + 'phabricator-diff-tree-view', 1528 + ), 1517 1529 '65bb0011' => array( 1518 1530 'javelin-behavior', 1519 1531 'javelin-dom', ··· 1863 1875 'javelin-install', 1864 1876 'javelin-dom', 1865 1877 ), 1878 + 'a8f573a9' => array( 1879 + 'javelin-install', 1880 + 'javelin-dom', 1881 + 'javelin-util', 1882 + ), 1866 1883 'a9942052' => array( 1867 1884 'javelin-behavior', 1868 1885 'javelin-dom', ··· 1898 1915 'javelin-json', 1899 1916 'phuix-form-control-view', 1900 1917 ), 1901 - 'aaa08f3b' => array( 1902 - 'javelin-install', 1903 - 'javelin-dom', 1904 - 'javelin-util', 1905 - ), 1906 1918 'ab85e184' => array( 1907 1919 'javelin-install', 1908 1920 'javelin-dom', ··· 2107 2119 'javelin-behavior', 2108 2120 'javelin-uri', 2109 2121 'phabricator-notification', 2110 - ), 2111 - 'dd1a6f34' => array( 2112 - 'javelin-dom', 2113 - 'javelin-util', 2114 - 'javelin-stratcom', 2115 - 'javelin-install', 2116 - 'javelin-workflow', 2117 - 'javelin-router', 2118 - 'javelin-behavior-device', 2119 - 'javelin-vector', 2120 - 'phabricator-diff-inline', 2121 - 'phabricator-diff-path-view', 2122 2122 ), 2123 2123 'e150bd50' => array( 2124 2124 'javelin-behavior',
+55
src/applications/differential/view/DifferentialChangesetDetailView.php
··· 14 14 private $repository; 15 15 private $diff; 16 16 private $changesetResponse; 17 + private $branch; 17 18 18 19 public function setAutoload($autoload) { 19 20 $this->autoload = $autoload; ··· 71 72 return $this; 72 73 } 73 74 75 + public function setBranch($branch) { 76 + $this->branch = $branch; 77 + return $this; 78 + } 79 + 80 + public function getBranch() { 81 + return $this->branch; 82 + } 83 + 74 84 public function getID() { 75 85 if (!$this->id) { 76 86 $this->id = celerity_generate_unique_node_id(); ··· 93 103 } 94 104 95 105 public function render() { 106 + $viewer = $this->getViewer(); 107 + 96 108 $this->requireResource('differential-changeset-view-css'); 97 109 $this->requireResource('syntax-highlighting-css'); 98 110 ··· 181 193 $path_parts = trim($display_filename, '/'); 182 194 $path_parts = explode('/', $path_parts); 183 195 196 + $show_path_uri = null; 197 + $show_directory_uri = null; 198 + 199 + $repository = $this->getRepository(); 200 + if ($repository) { 201 + $diff = $this->getDiff(); 202 + if ($diff) { 203 + $repo_path = $changeset->getAbsoluteRepositoryPath($repository, $diff); 204 + 205 + $repo_dir = dirname($repo_path); 206 + if ($repo_dir === $repo_path) { 207 + $repo_dir = null; 208 + } 209 + 210 + $show_path_uri = $repository->getDiffusionBrowseURIForPath( 211 + $viewer, 212 + $repo_path, 213 + idx($changeset->getMetadata(), 'line:first'), 214 + $this->getBranch()); 215 + 216 + if ($repo_dir !== null) { 217 + $repo_dir = rtrim($repo_dir, '/').'/'; 218 + 219 + $show_directory_uri = $repository->getDiffusionBrowseURIForPath( 220 + $viewer, 221 + $repo_dir, 222 + null, 223 + $this->getBranch()); 224 + } 225 + } 226 + } 227 + 228 + if ($show_path_uri) { 229 + $show_path_uri = phutil_string_cast($show_path_uri); 230 + } 231 + 232 + if ($show_directory_uri) { 233 + $show_directory_uri = phutil_string_cast($show_directory_uri); 234 + } 235 + 184 236 return javelin_tag( 185 237 'div', 186 238 array( ··· 205 257 206 258 'loaded' => $is_loaded, 207 259 'changesetState' => $changeset_state, 260 + 261 + 'showPathURI' => $show_path_uri, 262 + 'showDirectoryURI' => $show_directory_uri, 208 263 ), 209 264 'class' => $class, 210 265 'id' => $id,
+17 -18
src/applications/differential/view/DifferentialChangesetListView.php
··· 198 198 $detail->setVsChangesetID(idx($this->vsMap, $changeset->getID())); 199 199 $detail->setEditable(true); 200 200 $detail->setRenderingRef($ref); 201 + $detail->setBranch($this->getBranch()); 201 202 202 203 $detail->setRenderURI($this->renderURI); 203 204 ··· 263 264 "Can't Toggle Unloaded File" => pht("Can't Toggle Unloaded File"), 264 265 'Expand File' => pht('Expand File'), 265 266 'Collapse File' => pht('Collapse File'), 266 - 'Browse in Diffusion' => pht('Browse in Diffusion'), 267 + 'Show Path in Repository' => pht('Show Path in Repository'), 268 + 'Show Directory in Repository' => pht('Show Directory in Repository'), 267 269 'View Standalone' => pht('View Standalone'), 268 270 'Show Raw File (Left)' => pht('Show Raw File (Left)'), 269 271 'Show Raw File (Right)' => pht('Show Raw File (Right)'), 270 272 'Configure Editor' => pht('Configure Editor'), 271 273 'Load Changes' => pht('Load Changes'), 272 - 'View Side-by-Side' => pht('View Side-by-Side'), 273 - 'View Unified' => pht('View Unified'), 274 + 'View Side-by-Side Diff' => pht('View Side-by-Side Diff'), 275 + 'View Unified Diff' => pht('View Unified Diff'), 274 276 'Change Text Encoding...' => pht('Change Text Encoding...'), 275 277 'Highlight As...' => pht('Highlight As...'), 276 - 'View As...' => pht('View As...'), 278 + 'View As Document Type...' => pht('View As Document Type...'), 277 279 278 280 'Loading...' => pht('Loading...'), 279 281 ··· 350 352 'You must select a file to edit.' => 351 353 pht('You must select a file to edit.'), 352 354 355 + 'You must select a file to open.' => 356 + pht('You must select a file to open.'), 357 + 353 358 'No external editor is configured.' => 354 359 pht('No external editor is configured.'), 360 + 361 + 'Hide or show the paths panel.' => 362 + pht('Hide or show the paths panel.'), 363 + 364 + 'Show path in repository.' => 365 + pht('Show path in repository.'), 366 + 'Show directory in repository.' => 367 + pht('Show directory in repository.'), 355 368 ), 356 369 )); 357 370 ··· 395 408 $uri = new PhutilURI($this->standaloneURI); 396 409 $uri = $this->appendDefaultQueryParams($uri, $qparams); 397 410 $meta['standaloneURI'] = (string)$uri; 398 - } 399 - 400 - $repository = $this->repository; 401 - if ($repository) { 402 - try { 403 - $meta['diffusionURI'] = 404 - (string)$repository->getDiffusionBrowseURIForPath( 405 - $viewer, 406 - $changeset->getAbsoluteRepositoryPath($repository, $this->diff), 407 - idx($changeset->getMetadata(), 'line:first'), 408 - $this->getBranch()); 409 - } catch (DiffusionSetupException $e) { 410 - // Ignore 411 - } 412 411 } 413 412 414 413 $change = $changeset->getChangeType();
+22
webroot/rsrc/css/phui/phui-action-list.css
··· 242 242 .phui-icon-view { 243 243 margin-left: 12px; 244 244 } 245 + 246 + .phabricator-action-view .keyboard-shortcut-key { 247 + display: none; 248 + } 249 + 250 + .phabricator-action-view.has-key-command .keyboard-shortcut-key { 251 + display: block; 252 + position: absolute; 253 + width: 12px; 254 + height: 12px; 255 + right: 0; 256 + top: 2px; 257 + line-height: 12px; 258 + padding: 4px; 259 + color: {$greytext}; 260 + background: {$bluebackground}; 261 + border: none; 262 + } 263 + 264 + .phabricator-action-view.has-key-command .phabricator-action-view-item { 265 + padding-right: 24px; 266 + }
+13
webroot/rsrc/js/application/diff/DiffChangeset.js
··· 34 34 35 35 this._editorURI = data.editorURI; 36 36 this._editorConfigureURI = data.editorConfigureURI; 37 + this._showPathURI = data.showPathURI; 38 + this._showDirectoryURI = data.showDirectoryURI; 37 39 38 40 this._pathIconIcon = data.pathIconIcon; 39 41 this._pathIconColor = data.pathIconColor; ··· 76 78 77 79 _editorURI: null, 78 80 _editorConfigureURI: null, 81 + _showPathURI: null, 82 + _showDirectoryURI: null, 83 + 79 84 _pathView: null, 80 85 81 86 _pathIconIcon: null, ··· 90 95 91 96 getEditorConfigureURI: function() { 92 97 return this._editorConfigureURI; 98 + }, 99 + 100 + getShowPathURI: function() { 101 + return this._showPathURI; 102 + }, 103 + 104 + getShowDirectoryURI: function() { 105 + return this._showDirectoryURI; 93 106 }, 94 107 95 108 getLeftChangesetID: function() {
+99 -31
webroot/rsrc/js/application/diff/DiffChangesetList.js
··· 198 198 if (formation) { 199 199 var filetree = formation.getColumn(0); 200 200 var toggletree = JX.bind(filetree, filetree.toggleVisibility); 201 + label = pht('Hide or show the paths panel.'); 201 202 this._installKey('f', 'diff-vis', label, toggletree); 202 203 } 203 204 ··· 226 227 label = pht('Hide or show all inline comments.'); 227 228 this._installKey('A', 'diff-vis', label, this._onkeyhideall); 228 229 230 + label = pht('Show path in repository.'); 231 + this._installKey('d', 'diff-nav', label, this._onkeyshowpath); 232 + 233 + label = pht('Show directory in repository.'); 234 + this._installKey('D', 'diff-nav', label, this._onkeyshowdirectory); 235 + 229 236 label = pht('Open file in external editor.'); 230 237 this._installKey('\\', 'diff-nav', label, this._onkeyopeneditor); 231 - 232 238 }, 233 239 234 240 isAsleep: function() { ··· 456 462 }, 457 463 458 464 _onkeytogglefile: function() { 459 - var cursor = this._cursorItem; 465 + var pht = this.getTranslations(); 466 + var changeset = this._getChangesetForKeyCommand(); 460 467 461 - if (cursor) { 462 - if (cursor.type == 'file') { 463 - cursor.changeset.toggleVisibility(); 464 - return; 465 - } 468 + if (!changeset) { 469 + this._warnUser(pht('You must select a file to hide or show.')); 470 + return; 466 471 } 467 472 468 - var pht = this.getTranslations(); 469 - this._warnUser(pht('You must select a file to hide or show.')); 473 + changeset.toggleVisibility(); 470 474 }, 471 475 472 - _onkeyopeneditor: function() { 473 - var pht = this.getTranslations(); 476 + _getChangesetForKeyCommand: function() { 474 477 var cursor = this._cursorItem; 475 478 476 479 var changeset; ··· 482 485 changeset = this._getVisibleChangeset(); 483 486 } 484 487 488 + return changeset; 489 + }, 490 + 491 + _onkeyopeneditor: function() { 492 + var pht = this.getTranslations(); 493 + var changeset = this._getChangesetForKeyCommand(); 494 + 485 495 if (!changeset) { 486 496 this._warnUser(pht('You must select a file to edit.')); 487 497 return; ··· 497 507 JX.$U(editor_uri).go(); 498 508 }, 499 509 510 + _onkeyshowpath: function() { 511 + this._onrepositorykey(false); 512 + }, 513 + 514 + _onkeyshowdirectory: function() { 515 + this._onrepositorykey(true); 516 + }, 517 + 518 + _onrepositorykey: function(is_directory) { 519 + var pht = this.getTranslations(); 520 + var changeset = this._getChangesetForKeyCommand(); 521 + 522 + if (!changeset) { 523 + this._warnUser(pht('You must select a file to open.')); 524 + return; 525 + } 526 + 527 + var show_uri; 528 + if (is_directory) { 529 + show_uri = changeset.getShowDirectoryURI(); 530 + } else { 531 + show_uri = changeset.getShowPathURI(); 532 + } 533 + 534 + if (show_uri === null) { 535 + return; 536 + } 537 + 538 + window.open(show_uri); 539 + }, 540 + 500 541 _onkeycollapse: function() { 501 542 var cursor = this._cursorItem; 502 543 ··· 661 702 } 662 703 663 704 if (cursor !== null) { 664 - this._setSelectionState(items[cursor], true); 705 + this._setSelectionState(items[cursor], scroll); 665 706 } 666 707 667 708 return this; ··· 784 825 var changeset_list = this; 785 826 var changeset = this.getChangesetForNode(node); 786 827 787 - var menu = new JX.PHUIXDropdownMenu(button); 828 + var menu = new JX.PHUIXDropdownMenu(button) 829 + .setWidth(240); 788 830 var list = new JX.PHUIXActionListView(); 789 831 790 832 var add_link = function(icon, name, href, local) { 791 - if (!href) { 792 - return; 793 - } 794 - 795 833 var link = new JX.PHUIXActionView() 796 834 .setIcon(icon) 797 835 .setName(name) 798 - .setHref(href) 799 836 .setHandler(function(e) { 800 837 if (local) { 801 838 window.location.assign(href); ··· 805 842 menu.close(); 806 843 e.prevent(); 807 844 }); 845 + 846 + if (href) { 847 + link.setHref(href); 848 + } else { 849 + link 850 + .setDisabled(true) 851 + .setUnresponsive(true); 852 + } 808 853 809 854 list.addItem(link); 810 855 return link; 811 856 }; 812 857 813 - var reveal_item = new JX.PHUIXActionView() 814 - .setIcon('fa-eye'); 815 - list.addItem(reveal_item); 816 - 817 858 var visible_item = new JX.PHUIXActionView() 859 + .setKeyCommand('h') 818 860 .setHandler(function(e) { 819 861 e.prevent(); 820 862 menu.close(); 821 863 864 + changeset.select(false); 822 865 changeset.toggleVisibility(); 823 866 }); 824 867 list.addItem(visible_item); 825 868 826 - add_link('fa-file-text', pht('Browse in Diffusion'), data.diffusionURI); 827 - add_link('fa-file-o', pht('View Standalone'), data.standaloneURI); 869 + var reveal_item = new JX.PHUIXActionView() 870 + .setIcon('fa-eye'); 871 + list.addItem(reveal_item); 872 + 873 + list.addItem( 874 + new JX.PHUIXActionView() 875 + .setDivider(true)); 828 876 829 877 var up_item = new JX.PHUIXActionView() 830 878 .setHandler(function(e) { ··· 901 949 902 950 var engine_item = new JX.PHUIXActionView() 903 951 .setIcon('fa-file-image-o') 904 - .setName(pht('View As...')) 952 + .setName(pht('View As Document Type...')) 905 953 .setHandler(function(e) { 906 954 var params = { 907 955 engine: changeset.getDocumentEngine(), ··· 918 966 }); 919 967 list.addItem(engine_item); 920 968 969 + list.addItem( 970 + new JX.PHUIXActionView() 971 + .setDivider(true)); 972 + 973 + add_link('fa-external-link', pht('View Standalone'), data.standaloneURI); 974 + 921 975 add_link('fa-arrow-left', pht('Show Raw File (Left)'), data.leftURI); 922 976 add_link('fa-arrow-right', pht('Show Raw File (Right)'), data.rightURI); 923 977 978 + add_link( 979 + 'fa-folder-open-o', 980 + pht('Show Directory in Repository'), 981 + changeset.getShowDirectoryURI()) 982 + .setKeyCommand('D'); 983 + 984 + add_link( 985 + 'fa-file-text-o', 986 + pht('Show Path in Repository'), 987 + changeset.getShowPathURI()) 988 + .setKeyCommand('d'); 989 + 924 990 var editor_uri = changeset.getEditorURI(); 925 991 if (editor_uri !== null) { 926 - add_link('fa-pencil', pht('Open in Editor'), editor_uri, true); 992 + add_link('fa-i-cursor', pht('Open in Editor'), editor_uri, true) 993 + .setKeyCommand('\\'); 927 994 } else { 928 995 var configure_uri = changeset.getEditorConfigureURI(); 929 996 if (configure_uri !== null) { ··· 943 1010 reveal_item 944 1011 .setDisabled(false) 945 1012 .setName(pht('Show All Context')) 946 - .setIcon('fa-file-o') 1013 + .setIcon('fa-arrows-v') 947 1014 .setHandler(function(e) { 948 1015 changeset.loadAllContext(); 949 1016 e.prevent(); ··· 952 1019 } else { 953 1020 reveal_item 954 1021 .setDisabled(true) 1022 + .setUnresponsive(true) 955 1023 .setIcon('fa-file') 956 1024 .setName(pht('All Context Shown')) 957 - .setHandler(function(e) { e.prevent(); }); 1025 + .setHref(null); 958 1026 } 959 1027 960 1028 encoding_item.setDisabled(!changeset.isLoaded()); ··· 965 1033 if (changeset.getRendererKey() == '2up') { 966 1034 up_item 967 1035 .setIcon('fa-list-alt') 968 - .setName(pht('View Unified')); 1036 + .setName(pht('View Unified Diff')); 969 1037 } else { 970 1038 up_item 971 - .setIcon('fa-files-o') 972 - .setName(pht('View Side-by-Side')); 1039 + .setIcon('fa-columns') 1040 + .setName(pht('View Side-by-Side Diff')); 973 1041 } 974 1042 } else { 975 1043 up_item
+50 -7
webroot/rsrc/js/phuix/PHUIXActionView.js
··· 18 18 _handler: null, 19 19 _selected: false, 20 20 _divider: false, 21 + _keyCommand: null, 22 + _unresponsive: null, 21 23 22 24 _iconNode: null, 23 25 _nameNode: null, ··· 31 33 32 34 this._buildIconNode(true); 33 35 36 + return this; 37 + }, 38 + 39 + setUnresponsive: function(unresponsive) { 40 + this._unresponsive = unresponsive; 41 + this._buildNameNode(true); 34 42 return this; 35 43 }, 36 44 ··· 75 83 setHandler: function(handler) { 76 84 this._handler = handler; 77 85 this._buildNameNode(true); 86 + this._rebuildClasses(); 78 87 return this; 79 88 }, 80 89 ··· 93 102 setHref: function(href) { 94 103 this._href = href; 95 104 this._buildNameNode(true); 105 + this._rebuildClasses(); 106 + return this; 107 + }, 108 + 109 + setKeyCommand: function(command) { 110 + this._keyCommand = command; 111 + 112 + var key_node = this._buildKeyCommandNode(); 113 + JX.DOM.setContent(key_node, this._keyCommand); 114 + 115 + var node = this.getNode(); 116 + JX.DOM.alterClass(node, 'has-key-command', !!this._keyCommand); 117 + 96 118 return this; 97 119 }, 98 120 ··· 100 122 if (!this._node) { 101 123 var classes = ['phabricator-action-view']; 102 124 103 - if (this._href || this._handler) { 104 - classes.push('phabricator-action-view-href'); 105 - } 106 - 107 125 if (this._icon) { 108 126 classes.push('action-has-icon'); 109 127 } 110 128 111 129 var content = [ 112 130 this._buildIconNode(), 113 - this._buildNameNode() 131 + this._buildNameNode(), 132 + this._buildKeyCommandNode(), 114 133 ]; 115 134 116 135 var attr = { ··· 119 138 this._node = JX.$N('li', attr, content); 120 139 121 140 JX.Stratcom.addSigil(this._node, 'phuix-action-view'); 141 + 142 + this._rebuildClasses(); 122 143 } 123 144 124 145 return this._node; 146 + }, 147 + 148 + _rebuildClasses: function() { 149 + var node = this.getNode(); 150 + 151 + var is_href = !!(this._href || this._handler); 152 + JX.DOM.alterClass(node, 'phabricator-action-view-href', is_href); 125 153 }, 126 154 127 155 _buildIconNode: function(dirty) { ··· 155 183 return this._iconNode; 156 184 }, 157 185 186 + _buildKeyCommandNode: function() { 187 + if (!this._keyCommandNode) { 188 + var attrs = { 189 + className: 'keyboard-shortcut-key' 190 + }; 191 + 192 + this._keyCommandNode = JX.$N('div', attrs); 193 + } 194 + return this._keyCommandNode; 195 + }, 196 + 158 197 _buildNameNode: function(dirty) { 159 198 if (!this._nameNode || dirty) { 160 199 var attr = { ··· 162 201 }; 163 202 164 203 var href = this._href; 165 - if (!href && this._handler) { 204 + if (!href && this._handler && !this._unresponsive) { 166 205 href = '#'; 167 206 } 168 207 if (href) { 169 208 attr.href = href; 170 - 171 209 } 172 210 173 211 var tag = href ? 'a' : 'span'; ··· 185 223 }, 186 224 187 225 _onclick: function(e) { 226 + if (this._unresponsive) { 227 + e.prevent(); 228 + return; 229 + } 230 + 188 231 if (this._handler) { 189 232 this._handler(e); 190 233 }