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

Entirely replace the old filetree UI with the "flank" UI

Summary:
Ref T13516. Deletes all old filetree / flex / active / collapse nav code in favor of the new code.

Restores the inline tips in the path tree.

Test Plan: {F7374175}

Maniphest Tasks: T13516

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

+121 -896
+38 -71
resources/celerity/map.php
··· 9 9 'names' => array( 10 10 'conpherence.pkg.css' => '3c8a0668', 11 11 'conpherence.pkg.js' => '020aebcf', 12 - 'core.pkg.css' => 'a4a2417c', 13 - 'core.pkg.js' => 'd092ddaf', 14 - 'differential.pkg.css' => '607c84be', 15 - 'differential.pkg.js' => '58e09368', 12 + 'core.pkg.css' => '4d5d0922', 13 + 'core.pkg.js' => '544bc792', 14 + 'differential.pkg.css' => 'cb99cd21', 15 + 'differential.pkg.js' => 'b3589d05', 16 16 'diffusion.pkg.css' => '42c75c37', 17 17 'diffusion.pkg.js' => 'a98c0bf7', 18 18 'maniphest.pkg.css' => '35995d6d', ··· 29 29 'rsrc/css/aphront/multi-column.css' => 'fbc00ba3', 30 30 'rsrc/css/aphront/notification.css' => '30240bd2', 31 31 'rsrc/css/aphront/panel-view.css' => '46923d46', 32 - 'rsrc/css/aphront/phabricator-nav-view.css' => 'f8a0c1bf', 32 + 'rsrc/css/aphront/phabricator-nav-view.css' => '423f92cc', 33 33 'rsrc/css/aphront/table-view.css' => '0bb61df1', 34 34 'rsrc/css/aphront/tokenizer.css' => '34e2a838', 35 35 'rsrc/css/aphront/tooltip.css' => 'e3f2412f', ··· 40 40 'rsrc/css/application/base/main-menu-view.css' => 'bcec20f0', 41 41 'rsrc/css/application/base/notification-menu.css' => '4df1ee30', 42 42 'rsrc/css/application/base/phui-theme.css' => '35883b37', 43 - 'rsrc/css/application/base/standard-page-view.css' => 'ed076e5a', 43 + 'rsrc/css/application/base/standard-page-view.css' => 'a374f94c', 44 44 'rsrc/css/application/chatlog/chatlog.css' => 'abdc76ee', 45 45 'rsrc/css/application/conduit/conduit-api.css' => 'ce2cfc41', 46 46 'rsrc/css/application/config/config-options.css' => '16c920ae', ··· 59 59 'rsrc/css/application/countdown/timer.css' => 'bff8012f', 60 60 'rsrc/css/application/daemon/bulk-job.css' => '73af99f5', 61 61 'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d', 62 - 'rsrc/css/application/diff/diff-tree-view.css' => 'ce58c3d1', 62 + 'rsrc/css/application/diff/diff-tree-view.css' => '8f487a99', 63 63 'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d', 64 64 'rsrc/css/application/differential/add-comment.css' => '7e5900d9', 65 65 'rsrc/css/application/differential/changeset-view.css' => '489b6995', ··· 115 115 'rsrc/css/core/core.css' => '1b29ed61', 116 116 'rsrc/css/core/remarkup.css' => 'c286eaef', 117 117 'rsrc/css/core/syntax.css' => '220b85f9', 118 - 'rsrc/css/core/z-index.css' => '99c0f5eb', 118 + 'rsrc/css/core/z-index.css' => '612e9522', 119 119 'rsrc/css/diviner/diviner-shared.css' => '4bd263b0', 120 120 'rsrc/css/font/font-awesome.css' => '3883938a', 121 121 'rsrc/css/font/font-lato.css' => '23631304', 122 122 'rsrc/css/font/phui-font-icon-base.css' => 'd7994e06', 123 - 'rsrc/css/layout/phabricator-filetree-view.css' => '56cdd875', 124 123 'rsrc/css/layout/phabricator-source-code-view.css' => '03d7ac28', 125 124 'rsrc/css/phui/button/phui-button-bar.css' => 'a4aa75c4', 126 125 'rsrc/css/phui/button/phui-button-simple.css' => '1ff278aa', ··· 379 378 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 380 379 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 381 380 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', 382 - 'rsrc/js/application/diff/DiffChangeset.js' => 'ea6e377d', 383 - 'rsrc/js/application/diff/DiffChangesetList.js' => '5a351998', 381 + 'rsrc/js/application/diff/DiffChangeset.js' => '2a3101b1', 382 + 'rsrc/js/application/diff/DiffChangesetList.js' => '57035863', 384 383 'rsrc/js/application/diff/DiffInline.js' => '16e97ebc', 385 - 'rsrc/js/application/diff/DiffPathView.js' => '8337f4c7', 384 + 'rsrc/js/application/diff/DiffPathView.js' => 'c0ed32ce', 386 385 'rsrc/js/application/diff/DiffTreeView.js' => 'a5823e4d', 387 386 'rsrc/js/application/diff/behavior-preview-link.js' => 'f51e9c17', 388 387 'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd', ··· 466 465 'rsrc/js/core/TextAreaUtils.js' => 'f340a484', 467 466 'rsrc/js/core/Title.js' => '43bc9360', 468 467 'rsrc/js/core/ToolTip.js' => '83754533', 469 - 'rsrc/js/core/behavior-active-nav.js' => '7353f43d', 470 468 'rsrc/js/core/behavior-audio-source.js' => '3dc5ad43', 471 469 'rsrc/js/core/behavior-autofocus.js' => '65bb0011', 472 470 'rsrc/js/core/behavior-badge-view.js' => '92cdd7b6', ··· 477 475 'rsrc/js/core/behavior-device.js' => '0cf79f45', 478 476 'rsrc/js/core/behavior-drag-and-drop-textarea.js' => '7ad020a5', 479 477 'rsrc/js/core/behavior-fancy-datepicker.js' => '956f3eeb', 480 - 'rsrc/js/core/behavior-file-tree.js' => 'a61c2d11', 481 478 'rsrc/js/core/behavior-form.js' => '55d7b788', 482 479 'rsrc/js/core/behavior-gesture.js' => 'b58d1a2a', 483 480 'rsrc/js/core/behavior-global-drag-and-drop.js' => '1cab0e9a', ··· 492 489 'rsrc/js/core/behavior-more.js' => '506aa3f4', 493 490 'rsrc/js/core/behavior-object-selector.js' => '98ef467f', 494 491 'rsrc/js/core/behavior-oncopy.js' => 'ff7b3f22', 495 - 'rsrc/js/core/behavior-phabricator-nav.js' => 'f166c949', 496 492 'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '54262396', 497 493 'rsrc/js/core/behavior-read-only-warning.js' => 'b9109f8f', 498 494 'rsrc/js/core/behavior-redirect.js' => '407ee861', ··· 562 558 'conpherence-thread-manager' => 'aec8e38c', 563 559 'conpherence-transaction-css' => '3a3f5e7e', 564 560 'd3' => '9d068042', 565 - 'diff-tree-view-css' => 'ce58c3d1', 561 + 'diff-tree-view-css' => '8f487a99', 566 562 'differential-changeset-view-css' => '489b6995', 567 563 'differential-core-view-css' => '7300a73e', 568 564 'differential-revision-add-comment-css' => '7e5900d9', ··· 644 640 'javelin-behavior-maniphest-list-editor' => 'c687e867', 645 641 'javelin-behavior-owners-path-editor' => 'ff688a7a', 646 642 'javelin-behavior-passphrase-credential-control' => '48fe33d0', 647 - 'javelin-behavior-phabricator-active-nav' => '7353f43d', 648 643 'javelin-behavior-phabricator-autofocus' => '65bb0011', 649 644 'javelin-behavior-phabricator-clipboard-copy' => 'cf32921f', 650 - 'javelin-behavior-phabricator-file-tree' => 'a61c2d11', 651 645 'javelin-behavior-phabricator-gesture' => 'b58d1a2a', 652 646 'javelin-behavior-phabricator-gesture-example' => '242dedd0', 653 647 'javelin-behavior-phabricator-keyboard-pager' => '1325b731', 654 648 'javelin-behavior-phabricator-keyboard-shortcuts' => '42c44e8b', 655 649 'javelin-behavior-phabricator-line-linker' => '590e6527', 656 - 'javelin-behavior-phabricator-nav' => 'f166c949', 657 650 'javelin-behavior-phabricator-notification-example' => '29819b75', 658 651 'javelin-behavior-phabricator-object-selector' => '98ef467f', 659 652 'javelin-behavior-phabricator-oncopy' => 'ff7b3f22', ··· 782 775 'phabricator-darklog' => '3b869402', 783 776 'phabricator-darkmessage' => '26cd4b73', 784 777 'phabricator-dashboard-css' => '5a205b9d', 785 - 'phabricator-diff-changeset' => 'ea6e377d', 786 - 'phabricator-diff-changeset-list' => '5a351998', 778 + 'phabricator-diff-changeset' => '2a3101b1', 779 + 'phabricator-diff-changeset-list' => '57035863', 787 780 'phabricator-diff-inline' => '16e97ebc', 788 - 'phabricator-diff-path-view' => '8337f4c7', 781 + 'phabricator-diff-path-view' => 'c0ed32ce', 789 782 'phabricator-diff-tree-view' => 'a5823e4d', 790 783 'phabricator-drag-and-drop-file-upload' => '4370900d', 791 784 'phabricator-draggable-list' => '0169e425', ··· 793 786 'phabricator-favicon' => '7930776a', 794 787 'phabricator-feed-css' => 'd8b6e3f8', 795 788 'phabricator-file-upload' => 'ab85e184', 796 - 'phabricator-filetree-view-css' => '56cdd875', 797 789 'phabricator-flag-css' => '2b77be8d', 798 790 'phabricator-keyboard-shortcut' => '1a844c06', 799 791 'phabricator-keyboard-shortcut-manager' => '81debc48', 800 792 'phabricator-main-menu-view' => 'bcec20f0', 801 - 'phabricator-nav-view-css' => 'f8a0c1bf', 793 + 'phabricator-nav-view-css' => '423f92cc', 802 794 'phabricator-notification' => 'a9b91e3f', 803 795 'phabricator-notification-css' => '30240bd2', 804 796 'phabricator-notification-menu-css' => '4df1ee30', ··· 810 802 'phabricator-shaped-request' => 'abf88db8', 811 803 'phabricator-slowvote-css' => '1694baed', 812 804 'phabricator-source-code-view-css' => '03d7ac28', 813 - 'phabricator-standard-page-view' => 'ed076e5a', 805 + 'phabricator-standard-page-view' => 'a374f94c', 814 806 'phabricator-textareautils' => 'f340a484', 815 807 'phabricator-title' => '43bc9360', 816 808 'phabricator-tooltip' => '83754533', 817 809 'phabricator-ui-example-css' => 'b4795059', 818 - 'phabricator-zindex-css' => '99c0f5eb', 810 + 'phabricator-zindex-css' => '612e9522', 819 811 'phame-css' => 'bb442327', 820 812 'pholio-css' => '88ef5ef1', 821 813 'pholio-edit-css' => '4df55b3b', ··· 1163 1155 'javelin-stratcom', 1164 1156 'javelin-behavior', 1165 1157 ), 1158 + '2a3101b1' => array( 1159 + 'javelin-dom', 1160 + 'javelin-util', 1161 + 'javelin-stratcom', 1162 + 'javelin-install', 1163 + 'javelin-workflow', 1164 + 'javelin-router', 1165 + 'javelin-behavior-device', 1166 + 'javelin-vector', 1167 + 'phabricator-diff-inline', 1168 + 'phabricator-diff-path-view', 1169 + ), 1166 1170 '2a8b62d9' => array( 1167 1171 'multirow-row-manager', 1168 1172 'javelin-install', ··· 1432 1436 'javelin-stratcom', 1433 1437 'javelin-dom', 1434 1438 ), 1439 + 57035863 => array( 1440 + 'javelin-install', 1441 + 'phuix-button-view', 1442 + 'phabricator-diff-tree-view', 1443 + ), 1435 1444 '5793d835' => array( 1436 1445 'javelin-install', 1437 1446 'javelin-util', ··· 1471 1480 'javelin-stratcom', 1472 1481 'javelin-dom', 1473 1482 'javelin-history', 1474 - ), 1475 - '5a351998' => array( 1476 - 'javelin-install', 1477 - 'phuix-button-view', 1478 - 'phabricator-diff-tree-view', 1479 1483 ), 1480 1484 '5a6f6a06' => array( 1481 1485 'javelin-behavior', ··· 1583 1587 'javelin-util', 1584 1588 'javelin-reactor-node-calmer', 1585 1589 ), 1586 - '7353f43d' => array( 1587 - 'javelin-behavior', 1588 - 'javelin-stratcom', 1589 - 'javelin-vector', 1590 - 'javelin-dom', 1591 - 'javelin-uri', 1592 - ), 1593 1590 '73ecc1f8' => array( 1594 1591 'javelin-behavior', 1595 1592 'javelin-behavior-device', ··· 1656 1653 'javelin-stratcom', 1657 1654 'javelin-dom', 1658 1655 'javelin-vector', 1659 - ), 1660 - '8337f4c7' => array( 1661 - 'javelin-dom', 1662 1656 ), 1663 1657 83754533 => array( 1664 1658 'javelin-install', ··· 1878 1872 'a5823e4d' => array( 1879 1873 'javelin-dom', 1880 1874 ), 1881 - 'a61c2d11' => array( 1882 - 'javelin-behavior', 1883 - 'phabricator-keyboard-shortcut', 1884 - 'javelin-stratcom', 1885 - ), 1886 1875 'a9942052' => array( 1887 1876 'javelin-behavior', 1888 1877 'javelin-dom', ··· 2046 2035 'c03f2fb4' => array( 2047 2036 'javelin-install', 2048 2037 ), 2038 + 'c0ed32ce' => array( 2039 + 'javelin-dom', 2040 + ), 2049 2041 'c2c500a7' => array( 2050 2042 'javelin-install', 2051 2043 'javelin-dom', ··· 2160 2152 'e9c80beb' => array( 2161 2153 'javelin-install', 2162 2154 'javelin-event', 2163 - ), 2164 - 'ea6e377d' => array( 2165 - 'javelin-dom', 2166 - 'javelin-util', 2167 - 'javelin-stratcom', 2168 - 'javelin-install', 2169 - 'javelin-workflow', 2170 - 'javelin-router', 2171 - 'javelin-behavior-device', 2172 - 'javelin-vector', 2173 - 'phabricator-diff-inline', 2174 - 'phabricator-diff-path-view', 2175 2155 ), 2176 2156 'ebe83a6b' => array( 2177 2157 'javelin-install', ··· 2187 2167 'javelin-dom', 2188 2168 'javelin-stratcom', 2189 2169 ), 2190 - 'f166c949' => array( 2191 - 'javelin-behavior', 2192 - 'javelin-behavior-device', 2193 - 'javelin-stratcom', 2194 - 'javelin-dom', 2195 - 'javelin-magical-init', 2196 - 'javelin-vector', 2197 - 'javelin-request', 2198 - 'javelin-util', 2199 - ), 2200 2170 'f340a484' => array( 2201 2171 'javelin-install', 2202 2172 'javelin-dom', ··· 2377 2347 'javelin-behavior-aphlict-dropdown', 2378 2348 'javelin-behavior-history-install', 2379 2349 'javelin-behavior-phabricator-gesture', 2380 - 'javelin-behavior-phabricator-active-nav', 2381 - 'javelin-behavior-phabricator-nav', 2382 2350 'javelin-behavior-phabricator-remarkup-assist', 2383 2351 'phabricator-textareautils', 2384 2352 'phabricator-file-upload', ··· 2424 2392 'phabricator-content-source-view-css', 2425 2393 'inline-comment-summary-css', 2426 2394 'phui-inline-comment-view-css', 2427 - 'phabricator-filetree-view-css', 2428 2395 ), 2429 2396 'differential.pkg.js' => array( 2430 2397 'phabricator-drag-and-drop-file-upload',
-3
resources/celerity/packages.php
··· 54 54 'javelin-behavior-aphlict-dropdown', 55 55 'javelin-behavior-history-install', 56 56 'javelin-behavior-phabricator-gesture', 57 - 'javelin-behavior-phabricator-active-nav', 58 - 'javelin-behavior-phabricator-nav', 59 57 'javelin-behavior-phabricator-remarkup-assist', 60 58 'phabricator-textareautils', 61 59 'phabricator-file-upload', ··· 187 185 'phabricator-content-source-view-css', 188 186 'inline-comment-summary-css', 189 187 'phui-inline-comment-view-css', 190 - 'phabricator-filetree-view-css', 191 188 ), 192 189 'differential.pkg.js' => array( 193 190 'phabricator-drag-and-drop-file-upload',
-4
src/__phutil_library_map__.php
··· 466 466 'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php', 467 467 'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php', 468 468 'DifferentialChangesetEngine' => 'applications/differential/engine/DifferentialChangesetEngine.php', 469 - 'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php', 470 469 'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php', 471 470 'DifferentialChangesetListController' => 'applications/differential/controller/DifferentialChangesetListController.php', 472 471 'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php', ··· 4769 4768 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', 4770 4769 'PhabricatorShiftChartFunction' => 'applications/fact/chart/PhabricatorShiftChartFunction.php', 4771 4770 'PhabricatorShortSite' => 'aphront/site/PhabricatorShortSite.php', 4772 - 'PhabricatorShowFiletreeSetting' => 'applications/settings/setting/PhabricatorShowFiletreeSetting.php', 4773 4771 'PhabricatorSignDocumentsUserLogType' => 'applications/people/userlog/PhabricatorSignDocumentsUserLogType.php', 4774 4772 'PhabricatorSimpleEditType' => 'applications/transactions/edittype/PhabricatorSimpleEditType.php', 4775 4773 'PhabricatorSinChartFunction' => 'applications/fact/chart/PhabricatorSinChartFunction.php', ··· 6517 6515 ), 6518 6516 'DifferentialChangesetDetailView' => 'AphrontView', 6519 6517 'DifferentialChangesetEngine' => 'Phobject', 6520 - 'DifferentialChangesetFileTreeSideNavBuilder' => 'Phobject', 6521 6518 'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer', 6522 6519 'DifferentialChangesetListController' => 'DifferentialController', 6523 6520 'DifferentialChangesetListView' => 'AphrontView', ··· 11519 11516 'PhabricatorSetupIssueView' => 'AphrontView', 11520 11517 'PhabricatorShiftChartFunction' => 'PhabricatorPureChartFunction', 11521 11518 'PhabricatorShortSite' => 'PhabricatorSite', 11522 - 'PhabricatorShowFiletreeSetting' => 'PhabricatorSelectSetting', 11523 11519 'PhabricatorSignDocumentsUserLogType' => 'PhabricatorUserLogType', 11524 11520 'PhabricatorSimpleEditType' => 'PhabricatorEditType', 11525 11521 'PhabricatorSinChartFunction' => 'PhabricatorPureChartFunction',
-1
src/applications/differential/view/DifferentialChangesetDetailView.php
··· 193 193 'autoload' => $this->getAutoload(), 194 194 'displayPath' => hsprintf('%s', $display_parts), 195 195 'icon' => $display_icon, 196 - 'treeNodeID' => 'tree-node-'.$changeset->getAnchorName(), 197 196 'pathParts' => $path_parts, 198 197 199 198 'editorURI' => $this->getEditorURI(),
-158
src/applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php
··· 1 - <?php 2 - 3 - final class DifferentialChangesetFileTreeSideNavBuilder extends Phobject { 4 - 5 - private $title; 6 - private $baseURI; 7 - private $anchorName; 8 - private $collapsed = false; 9 - private $width; 10 - 11 - public function setAnchorName($anchor_name) { 12 - $this->anchorName = $anchor_name; 13 - return $this; 14 - } 15 - public function getAnchorName() { 16 - return $this->anchorName; 17 - } 18 - 19 - public function setBaseURI(PhutilURI $base_uri) { 20 - $this->baseURI = $base_uri; 21 - return $this; 22 - } 23 - public function getBaseURI() { 24 - return $this->baseURI; 25 - } 26 - 27 - public function setTitle($title) { 28 - $this->title = $title; 29 - return $this; 30 - } 31 - public function getTitle() { 32 - return $this->title; 33 - } 34 - 35 - public function setCollapsed($collapsed) { 36 - $this->collapsed = $collapsed; 37 - return $this; 38 - } 39 - 40 - public function setWidth($width) { 41 - $this->width = $width; 42 - return $this; 43 - } 44 - 45 - public function build(array $changesets) { 46 - assert_instances_of($changesets, 'DifferentialChangeset'); 47 - 48 - $nav = id(new AphrontSideNavFilterView()) 49 - ->setBaseURI($this->getBaseURI()) 50 - ->setFlexible(true) 51 - ->setCollapsed($this->collapsed) 52 - ->setWidth($this->width); 53 - 54 - $anchor = $this->getAnchorName(); 55 - 56 - $tree = new PhutilFileTree(); 57 - foreach ($changesets as $changeset) { 58 - try { 59 - $tree->addPath($changeset->getFilename(), $changeset); 60 - } catch (Exception $ex) { 61 - // TODO: See T1702. When viewing the versus diff of diffs, we may 62 - // have files with the same filename. For example, if you have a setup 63 - // like this in SVN: 64 - // 65 - // a/ 66 - // README 67 - // b/ 68 - // README 69 - // 70 - // ...and you run "arc diff" once from a/, and again from b/, you'll 71 - // get two diffs with path README. However, in the versus diff view we 72 - // will compute their absolute repository paths and detect that they 73 - // aren't really the same file. This is correct, but causes us to 74 - // throw when inserting them. 75 - // 76 - // We should probably compute the smallest unique path for each file 77 - // and show these as "a/README" and "b/README" when diffed against 78 - // one another. However, we get this wrong in a lot of places (the 79 - // other TOC shows two "README" files, and we generate the same anchor 80 - // hash for both) so I'm just stopping the bleeding until we can get 81 - // a proper fix in place. 82 - } 83 - } 84 - 85 - require_celerity_resource('phabricator-filetree-view-css'); 86 - 87 - $filetree = array(); 88 - 89 - $path = $tree; 90 - while (($path = $path->getNextNode())) { 91 - $data = $path->getData(); 92 - 93 - $classes = array(); 94 - $classes[] = 'phabricator-filetree-item'; 95 - 96 - $name = $path->getName(); 97 - $style = 'padding-left: '.(2 + (3 * $path->getDepth())).'px'; 98 - 99 - $href = null; 100 - if ($data) { 101 - $href = '#'.$data->getAnchorName(); 102 - $title = $name; 103 - 104 - $icon = $data->newFileTreeIcon(); 105 - $classes[] = $data->getFileTreeClass(); 106 - 107 - $count = phutil_tag( 108 - 'span', 109 - array( 110 - 'class' => 'filetree-progress-hint', 111 - 'id' => 'tree-node-'.$data->getAnchorName(), 112 - )); 113 - } else { 114 - $name .= '/'; 115 - $title = $path->getFullPath().'/'; 116 - $icon = id(new PHUIIconView()) 117 - ->setIcon('fa-folder-open blue'); 118 - 119 - $count = null; 120 - } 121 - 122 - $name_element = phutil_tag( 123 - 'span', 124 - array( 125 - 'class' => 'phabricator-filetree-name', 126 - ), 127 - $name); 128 - 129 - 130 - $filetree[] = javelin_tag( 131 - $href ? 'a' : 'span', 132 - array( 133 - 'href' => $href, 134 - 'style' => $style, 135 - 'title' => $title, 136 - 'class' => implode(' ', $classes), 137 - ), 138 - array($count, $icon, $name_element)); 139 - } 140 - $tree->destroy(); 141 - 142 - $filetree = phutil_tag( 143 - 'div', 144 - array( 145 - 'class' => 'phabricator-filetree', 146 - ), 147 - $filetree); 148 - 149 - Javelin::initBehavior('phabricator-file-tree', array()); 150 - 151 - $nav->addLabel(pht('Changed Files')); 152 - $nav->addCustomBlock($filetree); 153 - $nav->setActive(true); 154 - $nav->selectFilter(null); 155 - return $nav; 156 - } 157 - 158 - }
+15 -29
src/applications/diffusion/controller/DiffusionCommitController.php
··· 457 457 $commit, 458 458 $timeline); 459 459 460 - $filetree_on = $viewer->compareUserSetting( 461 - PhabricatorShowFiletreeSetting::SETTINGKEY, 462 - PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE); 463 - 464 - $nav = null; 465 - if ($show_changesets && $filetree_on) { 466 - $pref_collapse = PhabricatorFiletreeVisibleSetting::SETTINGKEY; 467 - $collapsed = $viewer->getUserSetting($pref_collapse); 468 - 469 - $pref_width = PhabricatorFiletreeWidthSetting::SETTINGKEY; 470 - $width = $viewer->getUserSetting($pref_width); 471 - 472 - $nav = id(new DifferentialChangesetFileTreeSideNavBuilder()) 473 - ->setTitle($commit->getDisplayName()) 474 - ->setBaseURI(new PhutilURI($commit->getURI())) 475 - ->build($changesets) 476 - ->setCrumbs($crumbs) 477 - ->setCollapsed((bool)$collapsed) 478 - ->setWidth((int)$width); 479 - } 460 + $filetree = id(new DifferentialFileTreeEngine()) 461 + ->setViewer($viewer) 462 + ->setChangesets($changesets) 463 + ->setDisabled(!$show_changesets); 480 464 481 465 $description_box = id(new PHUIObjectBoxView()) 482 466 ->setHeaderText(pht('Description')) ··· 509 493 $add_comment, 510 494 )); 511 495 496 + $main_content = array( 497 + $crumbs, 498 + $view, 499 + ); 500 + 501 + $main_content = $filetree->newView($main_content); 502 + if (!$filetree->getDisabled()) { 503 + $change_list->setFormationView($main_content); 504 + } 505 + 512 506 $page = $this->newPage() 513 507 ->setTitle($commit->getDisplayName()) 514 - ->setCrumbs($crumbs) 515 508 ->setPageObjectPHIDS(array($commit->getPHID())) 516 - ->appendChild( 517 - array( 518 - $view, 519 - )); 520 - 521 - if ($nav) { 522 - $page->setNavigation($nav); 523 - } 509 + ->appendChild($main_content); 524 510 525 511 return $page; 526 512
-42
src/applications/settings/setting/PhabricatorShowFiletreeSetting.php
··· 1 - <?php 2 - 3 - final class PhabricatorShowFiletreeSetting 4 - extends PhabricatorSelectSetting { 5 - 6 - const SETTINGKEY = 'diff-filetree'; 7 - 8 - const VALUE_DISABLE_FILETREE = 0; 9 - const VALUE_ENABLE_FILETREE = 1; 10 - 11 - public function getSettingName() { 12 - return pht('Show Filetree'); 13 - } 14 - 15 - protected function getSettingOrder() { 16 - return 300; 17 - } 18 - 19 - public function getSettingPanelKey() { 20 - return PhabricatorDiffPreferencesSettingsPanel::PANELKEY; 21 - } 22 - 23 - protected function getControlInstructions() { 24 - return pht( 25 - 'When viewing a revision or commit, you can enable a sidebar showing '. 26 - 'affected files. When this option is enabled, press {nav %s} to show '. 27 - 'or hide the sidebar.', 28 - 'f'); 29 - } 30 - 31 - public function getSettingDefaultValue() { 32 - return self::VALUE_DISABLE_FILETREE; 33 - } 34 - 35 - protected function getSelectOptions() { 36 - return array( 37 - self::VALUE_DISABLE_FILETREE => pht('Disable Filetree'), 38 - self::VALUE_ENABLE_FILETREE => pht('Enable Filetree'), 39 - ); 40 - } 41 - 42 - }
+1 -90
src/view/layout/AphrontSideNavFilterView.php
··· 20 20 private $items = array(); 21 21 private $baseURI; 22 22 private $selectedFilter = false; 23 - private $flexible; 24 - private $collapsed = false; 25 - private $active; 26 23 private $menu; 27 24 private $crumbs; 28 25 private $classes = array(); ··· 30 27 private $mainID; 31 28 private $isProfileMenu; 32 29 private $footer = array(); 33 - private $width; 34 30 35 31 public function setMenuID($menu_id) { 36 32 $this->menuID = $menu_id; ··· 66 62 67 63 public function getIsProfileMenu() { 68 64 return $this->isProfileMenu; 69 - } 70 - 71 - public function setActive($active) { 72 - $this->active = $active; 73 - return $this; 74 - } 75 - 76 - public function setFlexible($flexible) { 77 - $this->flexible = $flexible; 78 - return $this; 79 - } 80 - 81 - public function setCollapsed($collapsed) { 82 - $this->collapsed = $collapsed; 83 - return $this; 84 - } 85 - 86 - public function setWidth($width) { 87 - $this->width = $width; 88 - return $this; 89 65 } 90 66 91 67 public function getMenuView() { ··· 227 203 $local_menu = null; 228 204 $main_id = $this->getMainID(); 229 205 230 - $width = $this->width; 231 - if ($width) { 232 - $width = min($width, 600); 233 - $width = max($width, 150); 234 - } else { 235 - $width = null; 236 - } 237 - 238 - if ($width && !$this->collapsed) { 239 - $width_drag_style = 'left: '.$width.'px'; 240 - $width_panel_style = 'width: '.$width.'px'; 241 - $width_margin_style = 'margin-left: '.($width + 7).'px'; 242 - } else { 243 - $width_drag_style = null; 244 - $width_panel_style = null; 245 - $width_margin_style = null; 246 - } 247 - 248 - if ($this->flexible) { 249 - $drag_id = celerity_generate_unique_node_id(); 250 - $flex_bar = phutil_tag( 251 - 'div', 252 - array( 253 - 'class' => 'phabricator-nav-drag', 254 - 'id' => $drag_id, 255 - 'style' => $width_drag_style, 256 - ), 257 - ''); 258 - } else { 259 - $flex_bar = null; 260 - } 261 - 262 206 $nav_menu = null; 263 207 if ($this->menu->getItems()) { 264 208 $local_id = celerity_generate_unique_node_id(); 265 209 $background_id = celerity_generate_unique_node_id(); 266 210 267 - if (!$this->collapsed) { 268 - $nav_classes[] = 'has-local-nav'; 269 - } 211 + $nav_classes[] = 'has-local-nav'; 270 212 271 213 $local_menu = phutil_tag( 272 214 'div', 273 215 array( 274 216 'class' => 'phabricator-nav-local phabricator-side-menu', 275 217 'id' => $local_id, 276 - 'style' => $width_panel_style, 277 218 ), 278 219 $this->menu->setID($this->getMenuID())); 279 220 } ··· 284 225 $nav_classes[] = 'has-crumbs'; 285 226 } 286 227 287 - if ($this->flexible) { 288 - if (!$this->collapsed) { 289 - $nav_classes[] = 'has-drag-nav'; 290 - } else { 291 - $nav_classes[] = 'has-closed-nav'; 292 - } 293 - 294 - Javelin::initBehavior( 295 - 'phabricator-nav', 296 - array( 297 - 'mainID' => $main_id, 298 - 'localID' => $local_id, 299 - 'dragID' => $drag_id, 300 - 'contentID' => $content_id, 301 - 'backgroundID' => $background_id, 302 - 'collapsed' => $this->collapsed, 303 - 'width' => $width, 304 - )); 305 - 306 - if ($this->active) { 307 - Javelin::initBehavior( 308 - 'phabricator-active-nav', 309 - array( 310 - 'localID' => $local_id, 311 - )); 312 - } 313 - } 314 - 315 228 $nav_classes = array_merge($nav_classes, $this->classes); 316 229 317 230 $menu = phutil_tag( ··· 322 235 ), 323 236 array( 324 237 $local_menu, 325 - $flex_bar, 326 238 phutil_tag( 327 239 'div', 328 240 array( 329 241 'class' => 'phabricator-nav-content plb', 330 242 'id' => $content_id, 331 - 'style' => $width_margin_style, 332 243 ), 333 244 array( 334 245 $crumbs,
+2 -54
webroot/rsrc/css/aphront/phabricator-nav-view.css
··· 2 2 * @provides phabricator-nav-view-css 3 3 */ 4 4 5 - .jx-drag-col { 6 - cursor: col-resize; 7 - } 8 - 9 - .device-desktop .has-closed-nav div.phabricator-nav-local, 10 - .device-desktop .has-closed-nav div.phabricator-nav-drag, 11 - .device .phui-navigation-shell div.phabricator-nav-local, 12 - .device .phui-navigation-shell div.phabricator-nav-drag { 5 + .device .phui-navigation-shell div.phabricator-nav-local { 13 6 display: none; 14 7 } 15 8 16 - .device-desktop .has-local-nav .phabricator-nav-local, 17 - .device-desktop .has-local-nav .phabricator-nav-drag { 9 + .device-desktop .has-local-nav .phabricator-nav-local { 18 10 display: block; 19 11 } 20 12 ··· 40 32 width: auto; 41 33 } 42 34 43 - .phabricator-nav-drag { 44 - position: fixed; 45 - top: 0; 46 - bottom: 0; 47 - left: 310px; 48 - width: 7px; 49 - 50 - cursor: col-resize; 51 - background: #f5f5f5; 52 - border-style: solid; 53 - border-width: 0 1px 0 1px; 54 - border-color: #fff #999c9e #fff #999c9e; 55 - 56 - box-shadow: inset -1px 0px 1px rgba({$alphablack}, 0.15); 57 - 58 - background-image: url(/rsrc/image/divot.png); 59 - background-position: center; 60 - background-repeat: no-repeat; 61 - } 62 35 63 36 .phabricator-nav-content { 64 37 overflow: hidden; 65 - } 66 - 67 - .device-desktop .phabricator-standard-page-body .has-drag-nav 68 - .phabricator-nav-content { 69 - margin-left: 317px; 70 - } 71 - 72 - .device-desktop .phabricator-standard-page-body .has-drag-nav 73 - .phabricator-nav-local { 74 - max-width: none; 75 - } 76 - 77 - .has-drag-nav ul.phui-list-view { 78 - height: 100%; 79 - overflow-y: auto; 80 - overflow-x: hidden; 81 - } 82 - 83 - .device-desktop .phui-navigation-shell .has-drag-nav .phabricator-nav-local { 84 - width: 310px; 85 - padding: 0; 86 - 87 - /* See PHI568. If we don't paint the background explicitly, the content can 88 - render underneath it when scrolled horizontally. */ 89 - background: {$page.background}; 90 38 } 91 39 92 40 .device-phone .phabricator-side-menu-home .phabricator-nav-content {
+6 -3
webroot/rsrc/css/application/base/standard-page-view.css
··· 81 81 } 82 82 83 83 .keyboard-focus-focus-reticle { 84 - background: rgba(255, 255, 211, 0.15); 85 84 position: absolute; 86 - border: 1px solid {$yellow}; 87 - pointer-events: none; 85 + 86 + box-sizing: border-box; 87 + border-width: 0 6px 0 0; 88 + border-style: solid; 89 + border-color: {$yellow}; 90 + background: {$lightyellow}; 88 91 } 89 92 90 93 a.handle-status-closed {
+31 -3
webroot/rsrc/css/application/diff/diff-tree-view.css
··· 3 3 */ 4 4 5 5 .diff-tree-view { 6 - margin: 4px; 6 + margin: 0 4px; 7 7 } 8 8 9 9 .diff-tree-path { 10 - position: relative; 11 10 height: 20px; 12 11 color: {$greytext}; 13 12 line-height: 20px; 14 13 } 15 14 15 + .diff-tree-path-indent { 16 + position: relative; 17 + } 18 + 16 19 .diff-tree-path-icon { 17 20 position: absolute; 18 21 width: 20px; ··· 22 25 23 26 .diff-tree-path-name { 24 27 margin-left: 24px; 25 - margin-right: 24px; 28 + margin-right: 44px; 26 29 white-space: nowrap; 27 30 overflow: hidden; 28 31 text-overflow: ellipsis; ··· 45 48 background: {$lightblueborder}; 46 49 transition: 0.1s; 47 50 } 51 + 52 + .diff-tree-path-inlines { 53 + display: none; 54 + position: absolute; 55 + right: 4px; 56 + border-radius: 4px; 57 + text-align: center; 58 + top: 2px; 59 + height: 16px; 60 + line-height: 14px; 61 + width: 36px; 62 + font-size: {$smallerfontsize}; 63 + color: {$greytext}; 64 + } 65 + 66 + .diff-tree-path-inlines-visible { 67 + display: block; 68 + background: {$lightblueborder}; 69 + } 70 + 71 + .diff-tree-path-inlines-completed { 72 + background: {$darkgreybackground}; 73 + color: {$lightgreytext}; 74 + opacity: 0.75; 75 + }
-4
webroot/rsrc/css/core/z-index.css
··· 64 64 z-index: 4; 65 65 } 66 66 67 - .phabricator-nav-drag { 68 - z-index: 4; 69 - } 70 - 71 67 .conpherence-message-pane .conpherence-search-main { 72 68 z-index: 4; 73 69 }
-91
webroot/rsrc/css/layout/phabricator-filetree-view.css
··· 1 - /** 2 - * @provides phabricator-filetree-view-css 3 - */ 4 - 5 - .phabricator-filetree { 6 - padding: 4px 0; 7 - } 8 - 9 - /* NOTE: Until the whole side nav situation gets cleaned up, we need to be 10 - highly specific in specifying selectors here, to override side nav styles. 11 - */ 12 - 13 - .phabricator-filetree .phabricator-filetree-item { 14 - margin: 0; 15 - padding: 0; 16 - display: block; 17 - border-left: 4px solid transparent; 18 - } 19 - 20 - .phabricator-filetree span.phabricator-filetree-icon { 21 - background-repeat: no-repeat; 22 - background-position: 0 2px; 23 - width: 16px; 24 - height: 20px; 25 - padding: 0; 26 - float: left; 27 - } 28 - 29 - .phabricator-filetree span.phabricator-filetree-name { 30 - padding: 0; 31 - margin-left: 4px; 32 - font-size: 12px; 33 - font-weight: normal; 34 - line-height: 20px; 35 - white-space: nowrap; 36 - } 37 - 38 - .phabricator-filetree span.phabricator-filetree-item 39 - .phabricator-filetree-name { 40 - color: {$darkbluetext}; 41 - } 42 - 43 - .phabricator-filetree a.phabricator-filetree-item 44 - .phabricator-filetree-name { 45 - color: {$darkbluetext}; 46 - } 47 - 48 - .phabricator-filetree a.phabricator-filetree-item:hover { 49 - text-decoration: none; 50 - background-color: {$hovergrey}; 51 - } 52 - 53 - .phabricator-filetree .filetree-added { 54 - background: {$sh-greenbackground}; 55 - } 56 - 57 - .phabricator-filetree .filetree-deleted { 58 - background: {$sh-redbackground}; 59 - } 60 - 61 - .phabricator-filetree .filetree-movecopy { 62 - background: {$sh-orangebackground}; 63 - } 64 - 65 - .phabricator-filetree .phabricator-active-nav-focus { 66 - background-color: {$hovergrey}; 67 - border-left: 4px solid {$sky}; 68 - } 69 - 70 - .phabricator-filetree .filetree-progress-hint { 71 - width: 24px; 72 - margin-right: 6px; 73 - display: inline-block; 74 - padding: 0 4px; 75 - border-radius: 4px; 76 - font-size: smaller; 77 - background: {$greybackground}; 78 - text-align: center; 79 - opacity: 0.5; 80 - } 81 - 82 - .phabricator-filetree .filetree-comments-visible { 83 - background: {$lightblue}; 84 - opacity: 0.75; 85 - color: {$darkgreytext}; 86 - } 87 - 88 - .phabricator-filetree .filetree-comments-completed { 89 - background: {$darkgreybackground}; 90 - color: {$greytext}; 91 - }
+6 -11
webroot/rsrc/js/application/diff/DiffChangeset.js
··· 67 67 68 68 _changesetList: null, 69 69 _icon: null, 70 - _treeNodeID: null, 71 70 72 71 _editorURI: null, 73 72 _editorConfigureURI: null, ··· 770 769 }, 771 770 772 771 redrawFileTree: function() { 773 - var tree; 774 - try { 775 - tree = JX.$(this._treeNodeID); 776 - } catch (e) { 777 - return; 778 - } 779 - 780 772 var inlines = this._inlines; 781 773 var done = []; 782 774 var undone = []; ··· 833 825 is_completed = false; 834 826 } 835 827 836 - JX.DOM.setContent(tree, hint); 837 - JX.DOM.alterClass(tree, 'filetree-comments-visible', is_visible); 838 - JX.DOM.alterClass(tree, 'filetree-comments-completed', is_completed); 828 + var node = this.getPathView().getInlineNode(); 829 + 830 + JX.DOM.setContent(node, hint); 831 + 832 + JX.DOM.alterClass(node, 'diff-tree-path-inlines-visible', is_visible); 833 + JX.DOM.alterClass(node, 'diff-tree-path-inlines-completed', is_completed); 839 834 }, 840 835 841 836 toggleVisibility: function() {
+4 -3
webroot/rsrc/js/application/diff/DiffChangesetList.js
··· 1177 1177 // space between the focused element and the outline. 1178 1178 var p = JX.Vector.getPos(node); 1179 1179 var s = JX.Vector.getAggregateScrollForNode(node); 1180 + var d = JX.Vector.getDim(node); 1180 1181 1181 - p.add(s).add(-4, -4).setPos(reticle); 1182 + p.add(s).add(d.x + 1, 0).setPos(reticle); 1182 1183 // Compute the size we need to extend to the full extent of the focused 1183 1184 // nodes. 1184 1185 JX.Vector.getPos(extended_node) 1185 1186 .add(-p.x, -p.y) 1186 - .add(JX.Vector.getDim(extended_node)) 1187 - .add(8, 8) 1187 + .add(0, JX.Vector.getDim(extended_node).y) 1188 + .add(10, 0) 1188 1189 .setDim(reticle); 1189 1190 1190 1191 JX.DOM.getContentFrame().appendChild(reticle);
+18 -2
webroot/rsrc/js/application/diff/DiffPathView.js
··· 20 20 _indentNode: null, 21 21 _pathNode: null, 22 22 _changeset: null, 23 + _inlineNode: null, 23 24 24 25 getNode: function() { 25 26 if (!this._node) { ··· 71 72 setDepth: function(depth) { 72 73 this._depth = depth; 73 74 74 - this._getIndentNode().style.marginLeft = (8 * this._depth) + 'px'; 75 + this._getIndentNode().style.marginLeft = (6 * this._depth) + 'px'; 75 76 76 77 return this; 77 78 }, ··· 109 110 110 111 _getIndentNode: function() { 111 112 if (!this._indentNode) { 113 + var attrs = { 114 + className: 'diff-tree-path-indent' 115 + }; 116 + 112 117 var content = [ 118 + this.getInlineNode(), 113 119 this._getIconNode(), 114 120 this._getPathNode(), 115 121 ]; 116 122 117 - this._indentNode = JX.$N('div', {}, content); 123 + this._indentNode = JX.$N('div', attrs, content); 118 124 } 119 125 120 126 return this._indentNode; ··· 138 144 this._iconNode = JX.$N('div', attrs, this.getIcon().getNode()); 139 145 } 140 146 return this._iconNode; 147 + }, 148 + 149 + getInlineNode: function() { 150 + if (!this._inlineNode) { 151 + var attrs = { 152 + className: 'diff-tree-path-inlines', 153 + }; 154 + this._inlineNode = JX.$N('div', attrs, '-'); 155 + } 156 + return this._inlineNode; 141 157 } 142 158 143 159 }
-87
webroot/rsrc/js/core/behavior-active-nav.js
··· 1 - /** 2 - * @provides javelin-behavior-phabricator-active-nav 3 - * @requires javelin-behavior 4 - * javelin-stratcom 5 - * javelin-vector 6 - * javelin-dom 7 - * javelin-uri 8 - */ 9 - 10 - JX.behavior('phabricator-active-nav', function(config) { 11 - 12 - var local = JX.$(config.localID); 13 - 14 - /** 15 - * Select the navigation item corresponding to a given anchor. 16 - */ 17 - var selectnav = function(anchor) { 18 - var links = JX.DOM.scry(local, 'a'); 19 - var link; 20 - var link_anchor; 21 - var selected; 22 - for (var ii = 0; ii < links.length; ii++) { 23 - link = links[ii]; 24 - link_anchor = JX.$U(link.href).getFragment(); 25 - 26 - selected = (link_anchor == anchor); 27 - JX.DOM.alterClass( 28 - link, 29 - 'phabricator-active-nav-focus', 30 - selected); 31 - } 32 - }; 33 - 34 - 35 - /** 36 - * Identify the current anchor based on the document scroll position. 37 - */ 38 - var updateposition = function() { 39 - // Find all the markers in the document. 40 - var scroll_position = JX.Vector.getScroll().y; 41 - var document_size = JX.Vector.getDocument(); 42 - var viewport_size = JX.Vector.getViewport(); 43 - 44 - // If we're scrolled all the way down, we always want to select the last 45 - // anchor. 46 - var is_at_bottom = (viewport_size.y + scroll_position >= document_size.y); 47 - 48 - var markers = JX.DOM.scry(document.body, 'legend', 'marker'); 49 - 50 - // Sort the markers by Y position, descending. 51 - var markinfo = []; 52 - var ii; 53 - for (ii = 0; ii < markers.length; ii++) { 54 - markinfo.push({ 55 - marker: markers[ii], 56 - position: JX.$V(markers[ii]).y - 15 57 - }); 58 - } 59 - markinfo.sort(function(u, v) { return (v.position - u.position); }); 60 - 61 - // Find the first marker above the current scroll position, or the first 62 - // marker in the document if we're above all the markers. 63 - var active = null; 64 - for (ii = 0; ii < markinfo.length; ii++) { 65 - active = markinfo[ii].marker; 66 - if (markinfo[ii].position <= scroll_position) { 67 - break; 68 - } 69 - if (is_at_bottom) { 70 - break; 71 - } 72 - } 73 - 74 - // If we get above the first marker, select it. 75 - selectnav(active && JX.Stratcom.getData(active).anchor); 76 - }; 77 - 78 - var pending = null; 79 - var onviewportchange = function() { 80 - pending && clearTimeout(pending); 81 - pending = setTimeout(updateposition, 100); 82 - }; 83 - 84 - JX.Stratcom.listen('scroll', null, onviewportchange); 85 - JX.Stratcom.listen('resize', null, onviewportchange); 86 - JX.Stratcom.listen('hashchange', null, onviewportchange); 87 - });
-17
webroot/rsrc/js/core/behavior-file-tree.js
··· 1 - /** 2 - * @provides javelin-behavior-phabricator-file-tree 3 - * @requires javelin-behavior 4 - * phabricator-keyboard-shortcut 5 - * javelin-stratcom 6 - */ 7 - 8 - JX.behavior('phabricator-file-tree', function() { 9 - 10 - new JX.KeyboardShortcut('f', 'Toggle file tree.') 11 - .setGroup('diff-vis') 12 - .setHandler(function() { 13 - JX.Stratcom.invoke('differential-filetree-toggle'); 14 - }) 15 - .register(); 16 - 17 - });
-223
webroot/rsrc/js/core/behavior-phabricator-nav.js
··· 1 - /** 2 - * @provides javelin-behavior-phabricator-nav 3 - * @requires javelin-behavior 4 - * javelin-behavior-device 5 - * javelin-stratcom 6 - * javelin-dom 7 - * javelin-magical-init 8 - * javelin-vector 9 - * javelin-request 10 - * javelin-util 11 - * @javelin 12 - */ 13 - 14 - JX.behavior('phabricator-nav', function(config) { 15 - 16 - var content = JX.$(config.contentID); 17 - var local = JX.$(config.localID); 18 - var main = JX.$(config.mainID); 19 - var drag = JX.$(config.dragID); 20 - 21 - // - Flexible Navigation Column ------------------------------------------------ 22 - 23 - var dragging; 24 - var track; 25 - 26 - var collapsed = config.collapsed; 27 - var narrowed; 28 - var visible = null; 29 - 30 - JX.enableDispatch(document.body, 'mousemove'); 31 - 32 - JX.DOM.listen(drag, 'mousedown', null, function(e) { 33 - if (!e.isNormalMouseEvent()) { 34 - return; 35 - } 36 - 37 - dragging = JX.$V(e); 38 - 39 - // Show the "col-resize" cursor on the whole document while we're 40 - // dragging, since the mouse will slip off the actual bar fairly often and 41 - // we don't want it to flicker. 42 - JX.DOM.alterClass(document.body, 'jx-drag-col', true); 43 - 44 - track = [ 45 - { 46 - element: local, 47 - parameter: 'width', 48 - start: JX.Vector.getDim(local).x, 49 - width: JX.Vector.getDim(local).x, 50 - minWidth: 1 51 - }, 52 - { 53 - element: drag, 54 - parameter: 'left', 55 - start: get_width() 56 - }, 57 - { 58 - element: content, 59 - parameter: 'marginLeft', 60 - start: parseInt(getComputedStyle(content).marginLeft, 10), 61 - width: JX.Vector.getDim(content).x, 62 - minWidth: 300, 63 - minScale: -1 64 - } 65 - ]; 66 - 67 - e.kill(); 68 - }); 69 - 70 - JX.Stratcom.listen('mousemove', null, function(e) { 71 - if (!dragging) { 72 - return; 73 - } 74 - 75 - var dx = JX.$V(e).x - dragging.x; 76 - var panel; 77 - var k; 78 - 79 - for (k = 0; k < track.length; k++) { 80 - panel = track[k]; 81 - if (!panel.minWidth) { 82 - continue; 83 - } 84 - var new_width = panel.width + (dx * (panel.minScale || 1)); 85 - if (new_width < panel.minWidth) { 86 - dx = (panel.minWidth - panel.width) * panel.minScale; 87 - } 88 - } 89 - 90 - for (k = 0; k < track.length; k++) { 91 - panel = track[k]; 92 - var v = (panel.start + (dx * (panel.scale || 1))); 93 - panel.element.style[panel.parameter] = v + 'px'; 94 - } 95 - }); 96 - 97 - JX.Stratcom.listen('mouseup', null, function() { 98 - if (!dragging) { 99 - return; 100 - } 101 - 102 - JX.DOM.alterClass(document.body, 'jx-drag-col', false); 103 - dragging = false; 104 - 105 - new JX.Request('/settings/adjust/', JX.bag) 106 - .setData( 107 - { 108 - key: 'filetree.width', 109 - value: get_width() 110 - }) 111 - .send(); 112 - }); 113 - 114 - function get_width() { 115 - // See PHI568. If the document has scrolled horizontally, the "x" position 116 - // of the bar will be the actual width of the menu plus the horizontal 117 - // scroll position (because the element is "position: fixed"). Subtract the 118 - // document scroll position when saving the element width so that scrolling 119 - // to the right and then toggling the filetree UI does not make it grow 120 - // any wider. 121 - return (JX.$V(drag).x - JX.Vector.getScroll().x); 122 - } 123 - 124 - function repaint() { 125 - narrowed = !JX.Device.isDesktop(); 126 - 127 - var was_visible = visible; 128 - visible = (!collapsed && !narrowed); 129 - 130 - if (was_visible === visible) { 131 - return; 132 - } 133 - 134 - if (!visible) { 135 - savedrag(); 136 - } 137 - 138 - JX.DOM.alterClass(main, 'has-local-nav', visible); 139 - JX.DOM.alterClass(main, 'has-drag-nav', visible); 140 - JX.DOM.alterClass(main, 'has-closed-nav', !visible); 141 - 142 - if (visible) { 143 - restoredrag(); 144 - } 145 - } 146 - 147 - var saved_width = config.width; 148 - function savedrag() { 149 - saved_width = get_width(); 150 - 151 - local.style.width = ''; 152 - drag.style.left = ''; 153 - content.style.marginLeft = ''; 154 - } 155 - 156 - function restoredrag() { 157 - if (!saved_width) { 158 - return; 159 - } 160 - 161 - local.style.width = saved_width + 'px'; 162 - drag.style.left = saved_width + 'px'; 163 - content.style.marginLeft = (saved_width + JX.Vector.getDim(drag).x) + 'px'; 164 - } 165 - 166 - JX.Stratcom.listen('differential-filetree-toggle', null, function() { 167 - collapsed = !collapsed; 168 - 169 - repaint(); 170 - 171 - new JX.Request('/settings/adjust/', JX.bag) 172 - .setData({ key : 'nav-collapsed', value : (collapsed ? 1 : 0) }) 173 - .send(); 174 - 175 - // Invoke a resize event so page elements can redraw if they need to. One 176 - // example is the selection reticles in Differential. 177 - JX.Stratcom.invoke('resize'); 178 - }); 179 - 180 - 181 - // - Scroll -------------------------------------------------------------------- 182 - 183 - // When the user scrolls or resizes the window, anchor the menu to to the top 184 - // of the navigation bar. 185 - 186 - function onresize() { 187 - repaint(); 188 - 189 - if (!visible) { 190 - return; 191 - } 192 - 193 - // When the buoyant header is visible, move the menu down below it. This 194 - // is a bit of a hack. 195 - var banner_height = 0; 196 - try { 197 - var banner = JX.$('diff-banner'); 198 - banner_height = JX.Vector.getDim(banner).y; 199 - } catch (error) { 200 - // Ignore if there's no banner on the page. 201 - } 202 - 203 - local.style.top = Math.max( 204 - 0, 205 - banner_height, 206 - JX.$V(content).y - Math.max(0, JX.Vector.getScroll().y)) + 'px'; 207 - } 208 - 209 - local.style.position = 'fixed'; 210 - local.style.bottom = 0; 211 - local.style.left = 0; 212 - 213 - JX.Stratcom.listen(['scroll', 'resize'], null, onresize); 214 - 215 - repaint(); 216 - 217 - // - Navigation Reset ---------------------------------------------------------- 218 - 219 - JX.Stratcom.listen('phabricator-device-change', null, function() { 220 - repaint(); 221 - }); 222 - 223 - });