diff --git a/src/applications/differential/parser/changeset/DifferentialChangesetParser.php b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php index 4682350451..b0caa6a16a 100644 --- a/src/applications/differential/parser/changeset/DifferentialChangesetParser.php +++ b/src/applications/differential/parser/changeset/DifferentialChangesetParser.php @@ -1,7 +1,7 @@ true, 'sigil' => 'show-more', 'meta' => array( + 'type' => 'all', 'ref' => $reference, - 'range' => "{$top}-{$len}/{$top}-{$len}", + 'range' => "{$top}-{$len}/{$top}-{$len}", ), ), 'Show All '.$len.' Lines'); diff --git a/src/applications/differential/view/changesetdetailview/DifferentialChangesetDetailView.php b/src/applications/differential/view/changesetdetailview/DifferentialChangesetDetailView.php index 74c788064f..c623b8a07c 100644 --- a/src/applications/differential/view/changesetdetailview/DifferentialChangesetDetailView.php +++ b/src/applications/differential/view/changesetdetailview/DifferentialChangesetDetailView.php @@ -1,7 +1,7 @@ changeset = $changeset; @@ -43,6 +44,13 @@ class DifferentialChangesetDetailView extends AphrontView { return $this; } + public function getID() { + if (!$this->id) { + $this->id = celerity_generate_unique_node_id(); + } + return $this->id; + } + public function render() { require_celerity_resource('differential-changeset-view-css'); require_celerity_resource('syntax-highlighting-css'); @@ -67,7 +75,7 @@ class DifferentialChangesetDetailView extends AphrontView { ''; } - $id = celerity_generate_unique_node_id(); + $id = $this->getID(); if ($this->symbolIndex) { Javelin::initBehavior( diff --git a/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php b/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php index 3dd0c07f60..20dd1c36a6 100644 --- a/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php +++ b/src/applications/differential/view/changesetlistview/DifferentialChangesetListView.php @@ -101,6 +101,8 @@ class DifferentialChangesetListView extends AphrontView { $ref = $this->references[$key]; + $detail = new DifferentialChangesetDetailView(); + $detail_button = null; if ($this->standaloneViews) { $detail_uri = new PhutilURI($this->renderURI); @@ -125,6 +127,7 @@ class DifferentialChangesetListView extends AphrontView { 'leftURI' => (string)$detail_uri->alter('view', 'old'), 'rightURI' => (string)$detail_uri->alter('view', 'new'), 'diffusionURI' => $diffusion_uri, + 'containerID' => $detail->getID(), ), 'href' => $detail_uri, 'target' => '_blank', @@ -133,12 +136,12 @@ class DifferentialChangesetListView extends AphrontView { "View Options \xE2\x96\xBC"); } - $uniq_id = celerity_generate_unique_node_id(); - $detail = new DifferentialChangesetDetailView(); $detail->setChangeset($changeset); $detail->addButton($detail_button); $detail->setSymbolIndex(idx($this->symbolIndexes, $key)); + + $uniq_id = celerity_generate_unique_node_id(); $detail->appendChild( phutil_render_tag( 'div', diff --git a/webroot/rsrc/js/application/core/DropdownMenuItem.js b/webroot/rsrc/js/application/core/DropdownMenuItem.js index b3535aee30..392a7e07a5 100644 --- a/webroot/rsrc/js/application/core/DropdownMenuItem.js +++ b/webroot/rsrc/js/application/core/DropdownMenuItem.js @@ -8,19 +8,19 @@ JX.install('PhabricatorMenuItem', { construct : function(name, action) { - this._name = name; + this.setName(name); this._action = action; }, members : { - _name : null, _action : null, render : function() { if (this.getDisabled()) { - return JX.$N('span', this._name); + return JX.$N('span', this.getName()); } else { - return JX.$N('a', { href : '#', meta : { item : this } }, this._name); + var attrs = { href : '#', meta : { item : this } }; + return JX.$N('a', attrs, this.getName()); } }, @@ -30,6 +30,7 @@ JX.install('PhabricatorMenuItem', { }, properties : { + name : '', disabled : false } diff --git a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js index f0e3b6f0c0..c881ce327b 100644 --- a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js +++ b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js @@ -10,33 +10,70 @@ JX.behavior('differential-dropdown-menus', function(config) { - var buttons = JX.DOM.scry(window.document, 'a', 'differential-view-options'); + function build_menu(button, data) { - for (var ii = 0; ii < buttons.length; ii++) { - var data = JX.Stratcom.getData(buttons[ii]); + function show_more() { + var container = JX.$(data.containerID); + var nodes = JX.DOM.scry(container, 'tr', 'context-target'); + for (var ii = 0; ii < nodes.length; ii++) { + var show = JX.DOM.scry(nodes[ii], 'a', 'show-more'); + for (var jj = 0; jj < show.length; jj++) { + if (JX.Stratcom.getData(show[jj]).type != 'all') { + continue; + } + var event_data = { + context : nodes[ii], + show : show[jj] + }; + JX.Stratcom.invoke('differential-reveal-context', null, event_data); + } + } + } - var diffusion_item = new JX.PhabricatorMenuItem( - 'Browse in Diffusion', - JX.bind(null, window.open, data.diffusionURI)) + function link_to(name, uri) { + var item = new JX.PhabricatorMenuItem( + name, + JX.bind(null, window.open, uri)); + item.setDisabled(!uri); + return item; + } + var reveal_item = new JX.PhabricatorMenuItem('', show_more); + + var diffusion_item = link_to('Browse in Diffusion', data.diffusionURI); if (!data.diffusionURI) { diffusion_item.setDisabled(true); } - new JX.PhabricatorDropdownMenu(buttons[ii]) + var menu = new JX.PhabricatorDropdownMenu(buttons[ii]) + .addItem(reveal_item) .addItem(diffusion_item) - .addItem( - new JX.PhabricatorMenuItem( - 'View Standalone', - JX.bind(null, window.open, data.detailURI))) - .addItem( - new JX.PhabricatorMenuItem( - 'Show Raw File (Left)', - JX.bind(null, window.open, data.leftURI))) - .addItem( - new JX.PhabricatorMenuItem( - 'Show Raw File (Right)', - JX.bind(null, window.open, data.rightURI))); + .addItem(link_to('View Standalone', data.detailURI)) + .addItem(link_to('Show Raw File (Left)', data.leftURI)) + .addItem(link_to('Show Raw File (Right)', data.rightURI)); + + menu.listen( + 'open', + function() { + + // When the user opens the menu, check if there are any "Show More" + // links in the changeset body. If there aren't, disable the "Show + // Entire File" menu item since it won't change anything. + + var nodes = JX.DOM.scry(JX.$(data.containerID), 'a', 'show-more'); + if (nodes.length) { + reveal_item.setDisabled(false); + reveal_item.setName('Show Entire File'); + } else { + reveal_item.setDisabled(true); + reveal_item.setName('Entire File Shown'); + } + }); + } + + var buttons = JX.DOM.scry(window.document, 'a', 'differential-view-options'); + for (var ii = 0; ii < buttons.length; ii++) { + build_menu(buttons[ii], JX.Stratcom.getData(buttons[ii])); } }); diff --git a/webroot/rsrc/js/application/differential/behavior-show-more.js b/webroot/rsrc/js/application/differential/behavior-show-more.js index 28423cbd2c..81ea38790a 100644 --- a/webroot/rsrc/js/application/differential/behavior-show-more.js +++ b/webroot/rsrc/js/application/differential/behavior-show-more.js @@ -9,28 +9,40 @@ JX.behavior('differential-show-more', function(config) { - function onresponse(origin, response) { + function onresponse(context, response) { var div = JX.$N('div', {}, JX.$H(response)); - var anchor = origin.getNode('context-target'); - var root = anchor.parentNode; - copyRows(root, div, anchor); - root.removeChild(anchor); + var root = context.parentNode; + copyRows(root, div, context); + root.removeChild(context); } JX.Stratcom.listen( 'click', 'show-more', function(e) { - var context = e.getNodes()['context-target']; + var event_data = { + context : e.getNodes()['context-target'], + show : e.getNodes()['show-more'] + }; + + JX.Stratcom.invoke('differential-reveal-context', null, event_data); + e.kill(); + }); + + JX.Stratcom.listen( + 'differential-reveal-context', + null, + function(e) { + var context = e.getData().context; + var data = JX.Stratcom.getData(e.getData().show); + var container = JX.DOM.find(context, 'td'); JX.DOM.setContent(container, 'Loading...'); JX.DOM.alterClass(context, 'differential-show-more-loading', true); - var data = e.getNodeData('show-more'); data['whitespace'] = config.whitespace; new JX.Workflow(config.uri, data) - .setHandler(JX.bind(null, onresponse, e)) + .setHandler(JX.bind(null, onresponse, context)) .start(); - e.kill(); }); });