diff --git a/resources/celerity/map.php b/resources/celerity/map.php index 336ff4b9e9..781046914d 100644 --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -10,9 +10,9 @@ return array( 'conpherence.pkg.css' => '3c8a0668', 'conpherence.pkg.js' => '020aebcf', 'core.pkg.css' => 'a4a2417c', - 'core.pkg.js' => '4355a8d3', + 'core.pkg.js' => 'd092ddaf', 'differential.pkg.css' => '607c84be', - 'differential.pkg.js' => '688775a9', + 'differential.pkg.js' => '58e09368', 'diffusion.pkg.css' => '42c75c37', 'diffusion.pkg.js' => 'a98c0bf7', 'maniphest.pkg.css' => '35995d6d', @@ -59,6 +59,7 @@ return array( 'rsrc/css/application/countdown/timer.css' => 'bff8012f', 'rsrc/css/application/daemon/bulk-job.css' => '73af99f5', 'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d', + 'rsrc/css/application/diff/diff-tree-view.css' => 'ce58c3d1', 'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d', 'rsrc/css/application/differential/add-comment.css' => '7e5900d9', 'rsrc/css/application/differential/changeset-view.css' => '489b6995', @@ -155,7 +156,7 @@ return array( 'rsrc/css/phui/phui-fontkit.css' => '1ec937e5', 'rsrc/css/phui/phui-form-view.css' => '01b796c0', 'rsrc/css/phui/phui-form.css' => '1f177cb7', - 'rsrc/css/phui/phui-formation-view.css' => 'e87a0801', + 'rsrc/css/phui/phui-formation-view.css' => '82a3b73e', 'rsrc/css/phui/phui-head-thing.css' => 'd7f293df', 'rsrc/css/phui/phui-header-view.css' => '36c86a58', 'rsrc/css/phui/phui-hovercard.css' => '6ca90fa0', @@ -378,11 +379,11 @@ return array( 'rsrc/js/application/dashboard/behavior-dashboard-move-panels.js' => 'a2ab19be', 'rsrc/js/application/dashboard/behavior-dashboard-query-panel-select.js' => '1e413dc9', 'rsrc/js/application/dashboard/behavior-dashboard-tab-panel.js' => '0116d3e8', - 'rsrc/js/application/diff/DiffChangeset.js' => 'd1eda7b4', - 'rsrc/js/application/diff/DiffChangesetList.js' => '469beba0', + 'rsrc/js/application/diff/DiffChangeset.js' => 'ea6e377d', + 'rsrc/js/application/diff/DiffChangesetList.js' => '5a351998', 'rsrc/js/application/diff/DiffInline.js' => '16e97ebc', - 'rsrc/js/application/diff/DiffPathView.js' => 'e5166692', - 'rsrc/js/application/diff/DiffTreeView.js' => '4055adeb', + 'rsrc/js/application/diff/DiffPathView.js' => '8337f4c7', + 'rsrc/js/application/diff/DiffTreeView.js' => 'a5823e4d', 'rsrc/js/application/diff/behavior-preview-link.js' => 'f51e9c17', 'rsrc/js/application/differential/behavior-diff-radios.js' => '925fe8cd', 'rsrc/js/application/differential/behavior-populate.js' => 'b86ef6c2', @@ -457,7 +458,7 @@ return array( 'rsrc/js/core/FileUpload.js' => 'ab85e184', 'rsrc/js/core/Hovercard.js' => '074f0783', 'rsrc/js/core/KeyboardShortcut.js' => '1a844c06', - 'rsrc/js/core/KeyboardShortcutManager.js' => 'ef926938', + 'rsrc/js/core/KeyboardShortcutManager.js' => '81debc48', 'rsrc/js/core/MultirowRowManager.js' => '5b54c823', 'rsrc/js/core/Notification.js' => 'a9b91e3f', 'rsrc/js/core/Prefab.js' => '5793d835', @@ -529,7 +530,7 @@ return array( 'rsrc/js/phuix/PHUIXDropdownMenu.js' => '7acfd98b', 'rsrc/js/phuix/PHUIXExample.js' => 'c2c500a7', 'rsrc/js/phuix/PHUIXFormControl.js' => '38c1f3fb', - 'rsrc/js/phuix/PHUIXFormationColumnView.js' => '8afd2cb1', + 'rsrc/js/phuix/PHUIXFormationColumnView.js' => '4bcc1f78', 'rsrc/js/phuix/PHUIXFormationFlankView.js' => '6648270a', 'rsrc/js/phuix/PHUIXFormationView.js' => 'cef53b3e', 'rsrc/js/phuix/PHUIXIconView.js' => 'a5257c4e', @@ -561,6 +562,7 @@ return array( 'conpherence-thread-manager' => 'aec8e38c', 'conpherence-transaction-css' => '3a3f5e7e', 'd3' => '9d068042', + 'diff-tree-view-css' => 'ce58c3d1', 'differential-changeset-view-css' => '489b6995', 'differential-core-view-css' => '7300a73e', 'differential-revision-add-comment-css' => '7e5900d9', @@ -780,11 +782,11 @@ return array( 'phabricator-darklog' => '3b869402', 'phabricator-darkmessage' => '26cd4b73', 'phabricator-dashboard-css' => '5a205b9d', - 'phabricator-diff-changeset' => 'd1eda7b4', - 'phabricator-diff-changeset-list' => '469beba0', + 'phabricator-diff-changeset' => 'ea6e377d', + 'phabricator-diff-changeset-list' => '5a351998', 'phabricator-diff-inline' => '16e97ebc', - 'phabricator-diff-path-view' => 'e5166692', - 'phabricator-diff-tree-view' => '4055adeb', + 'phabricator-diff-path-view' => '8337f4c7', + 'phabricator-diff-tree-view' => 'a5823e4d', 'phabricator-drag-and-drop-file-upload' => '4370900d', 'phabricator-draggable-list' => '0169e425', 'phabricator-fatal-config-template-css' => '20babf50', @@ -794,7 +796,7 @@ return array( 'phabricator-filetree-view-css' => '56cdd875', 'phabricator-flag-css' => '2b77be8d', 'phabricator-keyboard-shortcut' => '1a844c06', - 'phabricator-keyboard-shortcut-manager' => 'ef926938', + 'phabricator-keyboard-shortcut-manager' => '81debc48', 'phabricator-main-menu-view' => 'bcec20f0', 'phabricator-nav-view-css' => 'f8a0c1bf', 'phabricator-notification' => 'a9b91e3f', @@ -852,7 +854,7 @@ return array( 'phui-fontkit-css' => '1ec937e5', 'phui-form-css' => '1f177cb7', 'phui-form-view-css' => '01b796c0', - 'phui-formation-view-css' => 'e87a0801', + 'phui-formation-view-css' => '82a3b73e', 'phui-head-thing-view-css' => 'd7f293df', 'phui-header-view-css' => '36c86a58', 'phui-hovercard' => '074f0783', @@ -895,7 +897,7 @@ return array( 'phuix-button-view' => '55a24e84', 'phuix-dropdown-menu' => '7acfd98b', 'phuix-form-control-view' => '38c1f3fb', - 'phuix-formation-column-view' => '8afd2cb1', + 'phuix-formation-column-view' => '4bcc1f78', 'phuix-formation-flank-view' => '6648270a', 'phuix-formation-view' => 'cef53b3e', 'phuix-icon-view' => 'a5257c4e', @@ -1267,9 +1269,6 @@ return array( 'phabricator-drag-and-drop-file-upload', 'phabricator-draggable-list', ), - '4055adeb' => array( - 'javelin-dom', - ), '407ee861' => array( 'javelin-behavior', 'javelin-uri', @@ -1319,11 +1318,6 @@ return array( 'javelin-util', 'phabricator-busy', ), - '469beba0' => array( - 'javelin-install', - 'phuix-button-view', - 'phabricator-diff-tree-view', - ), '47a0728b' => array( 'javelin-behavior', 'javelin-dom', @@ -1369,6 +1363,10 @@ return array( 'javelin-util', 'javelin-request', ), + '4bcc1f78' => array( + 'javelin-install', + 'javelin-dom', + ), '4dffaeb2' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1474,6 +1472,11 @@ return array( 'javelin-dom', 'javelin-history', ), + '5a351998' => array( + 'javelin-install', + 'phuix-button-view', + 'phabricator-diff-tree-view', + ), '5a6f6a06' => array( 'javelin-behavior', 'javelin-quicksand', @@ -1647,6 +1650,16 @@ return array( 'javelin-install', 'javelin-typeahead-source', ), + '81debc48' => array( + 'javelin-install', + 'javelin-util', + 'javelin-stratcom', + 'javelin-dom', + 'javelin-vector', + ), + '8337f4c7' => array( + 'javelin-dom', + ), 83754533 => array( 'javelin-install', 'javelin-util', @@ -1691,10 +1704,6 @@ return array( 'javelin-dom', 'phabricator-draggable-list', ), - '8afd2cb1' => array( - 'javelin-install', - 'javelin-dom', - ), '8b5c7d65' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1866,6 +1875,9 @@ return array( 'javelin-install', 'javelin-dom', ), + 'a5823e4d' => array( + 'javelin-dom', + ), 'a61c2d11' => array( 'javelin-behavior', 'phabricator-keyboard-shortcut', @@ -2096,18 +2108,6 @@ return array( 'javelin-workflow', 'javelin-util', ), - 'd1eda7b4' => array( - 'javelin-dom', - 'javelin-util', - 'javelin-stratcom', - 'javelin-install', - 'javelin-workflow', - 'javelin-router', - 'javelin-behavior-device', - 'javelin-vector', - 'phabricator-diff-inline', - 'phabricator-diff-path-view', - ), 'd3799cb4' => array( 'javelin-install', ), @@ -2134,9 +2134,6 @@ return array( 'javelin-dom', 'phuix-dropdown-menu', ), - 'e5166692' => array( - 'javelin-dom', - ), 'e5bdb730' => array( 'javelin-behavior', 'javelin-stratcom', @@ -2164,6 +2161,18 @@ return array( 'javelin-install', 'javelin-event', ), + 'ea6e377d' => array( + 'javelin-dom', + 'javelin-util', + 'javelin-stratcom', + 'javelin-install', + 'javelin-workflow', + 'javelin-router', + 'javelin-behavior-device', + 'javelin-vector', + 'phabricator-diff-inline', + 'phabricator-diff-path-view', + ), 'ebe83a6b' => array( 'javelin-install', ), @@ -2178,13 +2187,6 @@ return array( 'javelin-dom', 'javelin-stratcom', ), - 'ef926938' => array( - 'javelin-install', - 'javelin-util', - 'javelin-stratcom', - 'javelin-dom', - 'javelin-vector', - ), 'f166c949' => array( 'javelin-behavior', 'javelin-behavior-device', diff --git a/src/applications/differential/engine/DifferentialFileTreeEngine.php b/src/applications/differential/engine/DifferentialFileTreeEngine.php index a07e620678..e16c20ac3c 100644 --- a/src/applications/differential/engine/DifferentialFileTreeEngine.php +++ b/src/applications/differential/engine/DifferentialFileTreeEngine.php @@ -43,13 +43,15 @@ final class DifferentialFileTreeEngine return $content; } + require_celerity_resource('diff-tree-view-css'); + $width = $this->getWidth(); $is_visible = $this->getIsVisible(); $formation_view = new PHUIFormationView(); $flank_view = $formation_view->newFlankColumn() - ->setHeaderText(pht('Affected Paths')) + ->setHeaderText(pht('Paths')) ->setIsResizable(true) ->setIsFixed(true) ->setIsVisible($is_visible) @@ -60,45 +62,34 @@ final class DifferentialFileTreeEngine $viewer = $this->getViewer(); if ($viewer->isLoggedIn()) { $flank_view + ->setExpanderTooltip(pht('Show Paths Panel')) ->setVisibleSettingKey($this->getVisibleSettingKey()) ->setWidthSettingKey($this->getWidthSettingKey()); } - $flank_view->setHead( - array( - phutil_tag('div', array(), - array( - id(new PHUIIconView())->setIcon('fa-list'), - pht('Table of Contents'), - '[t]', - )), - )); + $head_view = id(new PHUIListView()) + ->addMenuItem( + id(new PHUIListItemView()) + ->setIcon('fa-list') + ->setName(pht('Table of Contents')) + ->setKeyCommand('t') + ->setHref('#')); + $flank_view->setHead($head_view); - $flank_view->setBody( - phutil_tag( - 'div', - array( - 'class' => 'phui-flank-loading', - ), - pht('Loading...'))); - - $flank_view->setTail( - array( - phutil_tag('div', array(), - array( - id(new PHUIIconView())->setIcon('fa-chevron-left'), - pht('Hide Panel'), - '[f]', - )), - phutil_tag( - 'div', - array(), - array( - id(new PHUIIconView())->setIcon('fa-keyboard-o'), - pht('Keyboard Reference'), - '[?]', - )), - )); + $tail_view = id(new PHUIListView()) + ->addMenuItem( + id(new PHUIListItemView()) + ->setIcon('fa-chevron-left') + ->setName(pht('Hide Panel')) + ->setKeyCommand('f') + ->setHref('#')) + ->addMenuItem( + id(new PHUIListItemView()) + ->setIcon('fa-keyboard-o') + ->setName(pht('Keyboard Reference')) + ->setKeyCommand('?') + ->setHref('#')); + $flank_view->setTail($tail_view); $main_column = $formation_view->newContentColumn() ->appendChild($content); diff --git a/src/applications/differential/view/DifferentialChangesetDetailView.php b/src/applications/differential/view/DifferentialChangesetDetailView.php index 43a59a8f4b..ae675b6496 100644 --- a/src/applications/differential/view/DifferentialChangesetDetailView.php +++ b/src/applications/differential/view/DifferentialChangesetDetailView.php @@ -287,7 +287,7 @@ final class DifferentialChangesetDetailView extends AphrontView { return null; } - return '/settings/panel/display/'; + return '/settings/panel/editor/'; } } diff --git a/src/view/formation/PHUIFormationColumnDynamicView.php b/src/view/formation/PHUIFormationColumnDynamicView.php index c967ee72e8..1a3d3bbbbd 100644 --- a/src/view/formation/PHUIFormationColumnDynamicView.php +++ b/src/view/formation/PHUIFormationColumnDynamicView.php @@ -10,6 +10,16 @@ abstract class PHUIFormationColumnDynamicView private $visibleSettingKey; private $minimumWidth; private $maximumWidth; + private $expanderTooltip; + + public function setExpanderTooltip($expander_tooltip) { + $this->expanderTooltip = $expander_tooltip; + return $this; + } + + public function getExpanderTooltip() { + return $this->expanderTooltip; + } public function setIsVisible($is_visible) { $this->isVisible = $is_visible; diff --git a/src/view/formation/PHUIFormationColumnView.php b/src/view/formation/PHUIFormationColumnView.php index 0d76756540..48fcc6c69d 100644 --- a/src/view/formation/PHUIFormationColumnView.php +++ b/src/view/formation/PHUIFormationColumnView.php @@ -50,4 +50,8 @@ abstract class PHUIFormationColumnView return null; } + public function getExpanderTooltip() { + return null; + } + } diff --git a/src/view/formation/PHUIFormationView.php b/src/view/formation/PHUIFormationView.php index 72d699486b..4c84a17b50 100644 --- a/src/view/formation/PHUIFormationView.php +++ b/src/view/formation/PHUIFormationView.php @@ -167,14 +167,19 @@ final class PHUIFormationView private function generateExpanders(array $items) { foreach ($items as $item) { $control_item = $item->getControlItem(); - if ($control_item) { - $expander = $this->newColumnExpanderView(); - - $expander->setColumnItem($item); - $item->setExpander($expander); - - $control_item->appendExpander($expander); + if (!$control_item) { + continue; } + + $expander = $this->newColumnExpanderView(); + + $tip = $item->getColumn()->getExpanderTooltip(); + $expander->setTooltip($tip); + + $expander->setColumnItem($item); + $item->setExpander($expander); + + $control_item->appendExpander($expander); } return $items; diff --git a/src/view/phui/PHUIListItemView.php b/src/view/phui/PHUIListItemView.php index 5de58b5492..87dda76cb9 100644 --- a/src/view/phui/PHUIListItemView.php +++ b/src/view/phui/PHUIListItemView.php @@ -36,6 +36,7 @@ final class PHUIListItemView extends AphrontTagView { private $count; private $rel; private $dropdownMenu; + private $keyCommand; public function setOpenInNewWindow($open_in_new_window) { $this->openInNewWindow = $open_in_new_window; @@ -220,6 +221,15 @@ final class PHUIListItemView extends AphrontTagView { return 'li'; } + public function setKeyCommand($key_command) { + $this->keyCommand = $key_command; + return $this; + } + + public function getKeyCommand() { + return $this->keyCommand; + } + protected function getTagAttributes() { $classes = array(); $classes[] = 'phui-list-item-view'; @@ -277,12 +287,12 @@ final class PHUIListItemView extends AphrontTagView { $name = null; $icon = null; $meta = null; - $sigil = null; + $sigil = array(); if ($this->name) { if ($this->getRenderNameAsTooltip()) { Javelin::initBehavior('phabricator-tooltips'); - $sigil = 'has-tooltip'; + $sigil[] = 'has-tooltip'; $meta = array( 'tip' => $this->name, 'align' => 'E', @@ -290,7 +300,7 @@ final class PHUIListItemView extends AphrontTagView { } else { if ($this->tooltip) { Javelin::initBehavior('phabricator-tooltips'); - $sigil = 'has-tooltip'; + $sigil[] = 'has-tooltip'; $meta = array( 'tip' => $this->tooltip, 'align' => 'E', @@ -383,13 +393,25 @@ final class PHUIListItemView extends AphrontTagView { $icons = $this->getIcons(); + $key_command = null; + if ($this->keyCommand) { + $key_command = phutil_tag( + 'span', + array( + 'class' => 'keyboard-shortcut-key', + ), + $this->keyCommand); + $sigil[] = 'has-key-command'; + $meta['keyCommand'] = $this->keyCommand; + } + $list_item = javelin_tag( $this->href ? 'a' : 'div', array( 'href' => $this->href, 'class' => implode(' ', $classes), 'meta' => $meta, - 'sigil' => $sigil, + 'sigil' => implode(' ', $sigil), 'target' => $this->getOpenInNewWindow() ? '_blank' : null, 'rel' => $this->rel, ), @@ -400,6 +422,7 @@ final class PHUIListItemView extends AphrontTagView { $this->renderChildren(), $name, $count, + $key_command, $caret, )); diff --git a/webroot/rsrc/css/application/diff/diff-tree-view.css b/webroot/rsrc/css/application/diff/diff-tree-view.css new file mode 100644 index 0000000000..0526f995bf --- /dev/null +++ b/webroot/rsrc/css/application/diff/diff-tree-view.css @@ -0,0 +1,47 @@ +/** + * @provides diff-tree-view-css + */ + +.diff-tree-view { + margin: 4px; +} + +.diff-tree-path { + position: relative; + height: 20px; + color: {$greytext}; + line-height: 20px; +} + +.diff-tree-path-icon { + position: absolute; + width: 20px; + height: 20px; + text-align: center; +} + +.diff-tree-path-name { + margin-left: 24px; + margin-right: 24px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.diff-tree-path-changeset { + cursor: pointer; + color: {$darkbluetext}; +} + +.diff-tree-path-focused { + background: {$darkgreybackground}; +} + +.diff-tree-path-selected { + background: {$yellow}; +} + +.device-desktop .diff-tree-path-changeset:hover { + background: {$lightblueborder}; + transition: 0.1s; +} diff --git a/webroot/rsrc/css/phui/phui-formation-view.css b/webroot/rsrc/css/phui/phui-formation-view.css index 180d017c70..79c352ad72 100644 --- a/webroot/rsrc/css/phui/phui-formation-view.css +++ b/webroot/rsrc/css/phui/phui-formation-view.css @@ -54,7 +54,7 @@ .phui-flank-header { padding: 8px; - background: {$greybackground}; + background: {$bluebackground}; border-bottom: 1px solid {$lightgreyborder}; } @@ -144,8 +144,40 @@ width: 100%; } -.phui-flank-loading { - color: {$lightgreytext}; - text-align: center; - margin: 16px; +.phui-flank-view .phui-list-view { + margin: 4px; +} + +.phui-flank-view .phui-list-item-view { + height: 20px; + padding: 4px 0; +} + +.phui-flank-view .phui-list-item-view .phui-icon-view { + width: 20px; + height: 20px; + text-align: center; + margin-right: 4px; +} + +.phui-flank-view .phui-list-item-view .phui-list-item-href { + display: block; + color: {$darkbluetext}; + text-decoration: none; +} + +.device-desktop .phui-flank-view .phui-list-item-view:hover { + background: {$lightblueborder}; + transition: 0.1s; +} + +.phui-flank-view .keyboard-shortcut-key { + position: absolute; + right: 4px; + top: 4px; + height: 18px; + width: 18px; + line-height: 18px; + padding: 0; + color: {$lightgreytext}; } diff --git a/webroot/rsrc/js/application/diff/DiffChangeset.js b/webroot/rsrc/js/application/diff/DiffChangeset.js index 9c445853cb..ec4886cafb 100644 --- a/webroot/rsrc/js/application/diff/DiffChangeset.js +++ b/webroot/rsrc/js/application/diff/DiffChangeset.js @@ -897,9 +897,14 @@ JX.install('DiffChangeset', { getPathView: function() { if (!this._pathView) { - this._pathView = new JX.DiffPathView() + var view = new JX.DiffPathView() .setChangeset(this) .setPath(this._pathParts); + + view.getIcon() + .setIcon(this.getIcon()); + + this._pathView = view; } return this._pathView; diff --git a/webroot/rsrc/js/application/diff/DiffChangesetList.js b/webroot/rsrc/js/application/diff/DiffChangesetList.js index 305b585082..a3292d19c1 100644 --- a/webroot/rsrc/js/application/diff/DiffChangesetList.js +++ b/webroot/rsrc/js/application/diff/DiffChangesetList.js @@ -194,6 +194,13 @@ JX.install('DiffChangesetList', { 'Jump to previous inline comment, including collapsed comments.'); this._installJumpKey('P', label, -1, 'comment', true); + var formation = this.getFormationView(); + if (formation) { + var filetree = formation.getColumn(0); + var toggletree = JX.bind(filetree, filetree.toggleVisibility); + this._installKey('f', 'diff-vis', label, toggletree); + } + if (!standalone) { label = pht('Hide or show the current file.'); this._installKey('h', 'diff-vis', label, this._onkeytogglefile); @@ -683,6 +690,13 @@ JX.install('DiffChangesetList', { return; } + var tree = this._getTreeView(); + if (cursor.changeset) { + tree.setSelectedPath(cursor.changeset.getPathView()); + } else { + tree.setSelectedPath(null); + } + this.setFocus(cursor.nodes.begin, cursor.nodes.end); if (scroll) { @@ -1139,6 +1153,11 @@ JX.install('DiffChangesetList', { }, setFocus: function(node, extended_node) { + if (!node) { + var tree = this._getTreeView(); + tree.setSelectedPath(null); + } + this._focusStart = node; this._focusEnd = extended_node; this._redrawFocus(); @@ -1493,7 +1512,7 @@ JX.install('DiffChangesetList', { if (!changeset) { this._bannerChangeset = null; JX.DOM.remove(node); - tree.setSelectedPath(null); + tree.setFocusedPath(null); if (formation) { formation.repaint(); @@ -1513,7 +1532,7 @@ JX.install('DiffChangesetList', { for (var ii = 0; ii < paths.length; ii++) { var path = paths[ii]; if (path.getChangeset() === changeset) { - tree.setSelectedPath(path); + tree.setFocusedPath(path); } } diff --git a/webroot/rsrc/js/application/diff/DiffPathView.js b/webroot/rsrc/js/application/diff/DiffPathView.js index 0fb0f0d19a..9439c1b89d 100644 --- a/webroot/rsrc/js/application/diff/DiffPathView.js +++ b/webroot/rsrc/js/application/diff/DiffPathView.js @@ -9,19 +9,25 @@ JX.install('DiffPathView', { construct: function() { }, - properties: { - changeset: null - }, - members: { _node: null, _path: null, _depth: 0, _selected: false, + _focused: false, + _icon: null, + + _indentNode: null, + _pathNode: null, + _changeset: null, getNode: function() { if (!this._node) { - this._node = JX.$N('li'); + var attrs = { + className: 'diff-tree-path' + }; + + this._node = JX.$N('li', attrs, this._getIndentNode()); var onclick = JX.bind(this, this._onclick); JX.DOM.listen(this._node, 'click', null, onclick); @@ -29,25 +35,62 @@ JX.install('DiffPathView', { return this._node; }, + getIcon: function() { + if (!this._icon) { + this._icon = new JX.PHUIXIconView(); + } + return this._icon; + }, + setPath: function(path) { this._path = path; - this._redraw(); + + var display = this._path[this._path.length - 1]; + JX.DOM.setContent(this._getPathNode(), display); + return this; }, + setChangeset: function(changeset) { + this._changeset = changeset; + + var node = this.getNode(); + JX.DOM.alterClass(node, 'diff-tree-path-changeset', !!changeset); + + return this; + }, + + getChangeset: function() { + return this._changeset; + }, + getPath: function() { return this._path; }, setDepth: function(depth) { this._depth = depth; - this._redraw(); + + this._getIndentNode().style.marginLeft = (8 * this._depth) + 'px'; + return this; }, setIsSelected: function(selected) { this._selected = selected; - this._redraw(); + + var node = this.getNode(); + JX.DOM.alterClass(node, 'diff-tree-path-selected', this._selected); + + return this; + }, + + setIsFocused: function(focused) { + this._focused = focused; + + var node = this.getNode(); + JX.DOM.alterClass(node, 'diff-tree-path-focused', this._focused); + return this; }, @@ -64,18 +107,37 @@ JX.install('DiffPathView', { e.kill(); }, - _redraw: function() { - var node = this.getNode(); + _getIndentNode: function() { + if (!this._indentNode) { + var content = [ + this._getIconNode(), + this._getPathNode(), + ]; - node.style.paddingLeft = (8 * this._depth) + 'px'; - - var display = this._path[this._path.length - 1]; - - if (this._selected) { - display = ['*', display]; + this._indentNode = JX.$N('div', {}, content); } - JX.DOM.setContent(node, display); + return this._indentNode; + }, + + _getPathNode: function() { + if (!this._pathNode) { + var attrs = { + className: 'diff-tree-path-name' + }; + this._pathNode = JX.$N('div', attrs); + } + return this._pathNode; + }, + + _getIconNode: function() { + if (!this._iconNode) { + var attrs = { + className: 'diff-tree-path-icon', + }; + this._iconNode = JX.$N('div', attrs, this.getIcon().getNode()); + } + return this._iconNode; } } diff --git a/webroot/rsrc/js/application/diff/DiffTreeView.js b/webroot/rsrc/js/application/diff/DiffTreeView.js index 3055f127bc..b4b423ef75 100644 --- a/webroot/rsrc/js/application/diff/DiffTreeView.js +++ b/webroot/rsrc/js/application/diff/DiffTreeView.js @@ -21,10 +21,15 @@ JX.install('DiffTreeView', { _dirty: false, _paths: null, _selectedPath: null, + _focusedPath: null, getNode: function() { if (!this._node) { - this._node = JX.$N('ul'); + var attrs = { + className: 'diff-tree-view' + }; + + this._node = JX.$N('ul', attrs); } if (this._dirty) { @@ -64,6 +69,21 @@ JX.install('DiffTreeView', { return this; }, + setFocusedPath: function(path) { + if (this._focusedPath) { + this._focusedPath.setIsFocused(false); + this._focusedPath = null; + } + + if (path) { + path.setIsFocused(true); + } + + this._focusedPath = path; + + return this; + }, + redraw: function() { if (!this._dirty) { return; @@ -83,6 +103,10 @@ JX.install('DiffTreeView', { if (!path) { path = new JX.DiffPathView() .setPath(tree.parts); + + path.getIcon() + .setIcon('fa-folder-open-o'); + tree.pathObject = path; } diff --git a/webroot/rsrc/js/core/KeyboardShortcutManager.js b/webroot/rsrc/js/core/KeyboardShortcutManager.js index 03406051a1..8cc8da1a08 100644 --- a/webroot/rsrc/js/core/KeyboardShortcutManager.js +++ b/webroot/rsrc/js/core/KeyboardShortcutManager.js @@ -16,6 +16,9 @@ JX.install('KeyboardShortcutManager', { JX.Stratcom.listen('keypress', null, JX.bind(this, this._onkeypress)); JX.Stratcom.listen('keydown', null, JX.bind(this, this._onkeydown)); JX.Stratcom.listen('keyup', null, JX.bind(this, this._onkeyup)); + + var onelement = JX.bind(this, this._onelement); + JX.Stratcom.listen('click', 'has-key-command', onelement); }, statics : { @@ -118,18 +121,29 @@ JX.install('KeyboardShortcutManager', { var key = this._getKey(e); + var handled = this._handleKey(key); + + if (handled) { + e.kill(); + } + }, + + _handleKey: function(key) { var shortcuts = this._shortcuts; + for (var ii = 0; ii < shortcuts.length; ii++) { var keys = shortcuts[ii].getKeys(); for (var jj = 0; jj < keys.length; jj++) { if (keys[jj] == key) { shortcuts[ii].getHandler()(this); - e.kill(); // Consume the event - return; + return true; } } } + + return false; }, + _onkeydown : function(e) { this._handleTooltipKeyEvent(e, true); @@ -143,6 +157,12 @@ JX.install('KeyboardShortcutManager', { _getKey : function(e) { return e.getSpecialKey() || String.fromCharCode(e.getRawEvent().charCode); }, + _onelement: function(e) { + var data = e.getNodeData('has-key-command'); + this._handleKey(data.keyCommand); + + e.kill(); + }, _handleTooltipKeyEvent : function(e, is_keydown) { if (e.getRawEvent().keyCode != 18) { // If this isn't the alt/option key, don't do anything. diff --git a/webroot/rsrc/js/phuix/PHUIXFormationColumnView.js b/webroot/rsrc/js/phuix/PHUIXFormationColumnView.js index 2adc462a8d..16831cc488 100644 --- a/webroot/rsrc/js/phuix/PHUIXFormationColumnView.js +++ b/webroot/rsrc/js/phuix/PHUIXFormationColumnView.js @@ -135,7 +135,14 @@ JX.install('PHUIXFormationColumnView', { _setVisibility: function(visible, e) { e.kill(); + this.setVisibility(visible); + }, + toggleVisibility: function() { + return this.setVisibility(!this.getIsVisible()); + }, + + setVisibility: function(visible) { this.setIsVisible(visible); this.repaint(); @@ -143,6 +150,8 @@ JX.install('PHUIXFormationColumnView', { if (visible_key) { this._adjustSetting(visible_key, visible ? 1 : 0); } + + return this; }, _adjustSetting: function(key, value) {