Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/differential/view/DifferentialChangesetListView.php b/src/applications/differential/view/DifferentialChangesetListView.php
index 3a43f095c6..a819390bfb 100644
--- a/src/applications/differential/view/DifferentialChangesetListView.php
+++ b/src/applications/differential/view/DifferentialChangesetListView.php
@@ -1,309 +1,311 @@
<?php
/*
* Copyright 2012 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
final class DifferentialChangesetListView extends AphrontView {
private $changesets = array();
private $visibleChangesets = array();
private $references = array();
private $inlineURI;
private $renderURI = '/differential/changeset/';
private $whitespace;
private $standaloneURI;
private $leftRawFileURI;
private $rightRawFileURI;
private $user;
private $symbolIndexes = array();
private $repository;
private $diff;
private $vsMap = array();
public function setChangesets($changesets) {
$this->changesets = $changesets;
return $this;
}
public function setVisibleChangesets($visible_changesets) {
$this->visibleChangesets = $visible_changesets;
return $this;
}
public function setInlineCommentControllerURI($uri) {
$this->inlineURI = $uri;
return $this;
}
public function setUser(PhabricatorUser $user) {
$this->user = $user;
return $this;
}
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function setDiff(DifferentialDiff $diff) {
$this->diff = $diff;
return $this;
}
public function setRenderingReferences(array $references) {
$this->references = $references;
return $this;
}
public function setSymbolIndexes(array $indexes) {
$this->symbolIndexes = $indexes;
return $this;
}
public function setRenderURI($render_uri) {
$this->renderURI = $render_uri;
return $this;
}
public function setWhitespace($whitespace) {
$this->whitespace = $whitespace;
return $this;
}
public function setVsMap(array $vs_map) {
$this->vsMap = $vs_map;
return $this;
}
public function getVsMap() {
return $this->vsMap;
}
public function setStandaloneURI($uri) {
$this->standaloneURI = $uri;
return $this;
}
public function setRawFileURIs($l, $r) {
$this->leftRawFileURI = $l;
$this->rightRawFileURI = $r;
return $this;
}
public function render() {
require_celerity_resource('differential-changeset-view-css');
$changesets = $this->changesets;
Javelin::initBehavior('buoyant', array());
+ Javelin::initBehavior('differential-toggle-files', array());
+
$output = array();
$mapping = array();
foreach ($changesets as $key => $changeset) {
$file = $changeset->getFilename();
$class = 'differential-changeset';
if (!$this->inlineURI) {
$class .= ' differential-changeset-noneditable';
}
$ref = $this->references[$key];
$detail = new DifferentialChangesetDetailView();
$view_options = $this->renderViewOptionsDropdown(
$detail,
$ref,
$changeset);
$detail->setChangeset($changeset);
$detail->addButton($view_options);
$detail->setSymbolIndex(idx($this->symbolIndexes, $key));
$detail->setVsChangesetID(idx($this->vsMap, $changeset->getID()));
$detail->setEditable(true);
$uniq_id = 'diff-'.$changeset->getAnchorName();
if (isset($this->visibleChangesets[$key])) {
$load = 'Loading...';
$mapping[$uniq_id] = $ref;
} else {
$load = javelin_render_tag(
'a',
array(
'href' => '#'.$uniq_id,
'meta' => array(
'id' => $uniq_id,
'ref' => $ref,
'kill' => true,
),
'sigil' => 'differential-load',
'mustcapture' => true,
),
'Load');
}
$detail->appendChild(
phutil_render_tag(
'div',
array(
'id' => $uniq_id,
),
'<div class="differential-loading">'.$load.'</div>'));
$output[] = $detail->render();
}
require_celerity_resource('aphront-tooltip-css');
Javelin::initBehavior('differential-populate', array(
'registry' => $mapping,
'whitespace' => $this->whitespace,
'uri' => $this->renderURI,
));
Javelin::initBehavior('differential-show-more', array(
'uri' => $this->renderURI,
'whitespace' => $this->whitespace,
));
Javelin::initBehavior('differential-comment-jump', array());
if ($this->inlineURI) {
$undo_templates = $this->renderUndoTemplates();
Javelin::initBehavior('differential-edit-inline-comments', array(
'uri' => $this->inlineURI,
'undo_templates' => $undo_templates,
'stage' => 'differential-review-stage',
));
}
return phutil_render_tag(
'div',
array(
'class' => 'differential-review-stage',
'id' => 'differential-review-stage',
),
implode("\n", $output));
}
/**
* Render the "Undo" markup for the inline comment undo feature.
*/
private function renderUndoTemplates() {
$link = javelin_render_tag(
'a',
array(
'href' => '#',
'sigil' => 'differential-inline-comment-undo',
),
'Undo');
$div = phutil_render_tag(
'div',
array(
'class' => 'differential-inline-undo',
),
'Changes discarded. '.$link);
$template =
'<table><tr>'.
'<th></th><td>%s</td>'.
'<th></th><td colspan="2">%s</td>'.
'</tr></table>';
return array(
'l' => sprintf($template, $div, ''),
'r' => sprintf($template, '', $div),
);
}
private function renderViewOptionsDropdown(
DifferentialChangesetDetailView $detail,
$ref,
DifferentialChangeset $changeset) {
$meta = array();
$qparams = array(
'ref' => $ref,
'whitespace' => $this->whitespace,
);
if ($this->standaloneURI) {
$uri = new PhutilURI($this->standaloneURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['standaloneURI'] = (string)$uri;
}
$repository = $this->repository;
if ($repository) {
$meta['diffusionURI'] = (string)$repository->getDiffusionBrowseURIForPath(
$changeset->getAbsoluteRepositoryPath($repository, $this->diff));
}
$change = $changeset->getChangeType();
if ($this->leftRawFileURI) {
if ($change != DifferentialChangeType::TYPE_ADD) {
$uri = new PhutilURI($this->leftRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['leftURI'] = (string)$uri;
}
}
if ($this->rightRawFileURI) {
if ($change != DifferentialChangeType::TYPE_DELETE &&
$change != DifferentialChangeType::TYPE_MULTICOPY) {
$uri = new PhutilURI($this->rightRawFileURI);
$uri->setQueryParams($uri->getQueryParams() + $qparams);
$meta['rightURI'] = (string)$uri;
}
}
$user = $this->user;
if ($user && $repository) {
$path = ltrim(
$changeset->getAbsoluteRepositoryPath($repository, $this->diff),
'/');
$line = 1; // TODO: get first changed line
$callsign = $repository->getCallsign();
$editor_link = $user->loadEditorLink($path, $line, $callsign);
if ($editor_link) {
$meta['editor'] = $editor_link;
} else {
$meta['editorConfigure'] = '/settings/page/preferences/';
}
}
$meta['containerID'] = $detail->getID();
Javelin::initBehavior(
'differential-dropdown-menus',
array());
return javelin_render_tag(
'a',
array(
'class' => 'button small grey',
'meta' => $meta,
'href' => idx($meta, 'detailURI', '#'),
'target' => '_blank',
'sigil' => 'differential-view-options',
),
"View Options \xE2\x96\xBC");
}
}
diff --git a/webroot/rsrc/js/application/differential/behavior-comment-jump.js b/webroot/rsrc/js/application/differential/behavior-comment-jump.js
index 217c85b078..f4d5f91228 100644
--- a/webroot/rsrc/js/application/differential/behavior-comment-jump.js
+++ b/webroot/rsrc/js/application/differential/behavior-comment-jump.js
@@ -1,29 +1,32 @@
/**
* @provides javelin-behavior-differential-comment-jump
* @requires javelin-behavior
* javelin-util
* javelin-dom
*/
JX.behavior('differential-comment-jump', function(config) {
function handle_jump(offset) {
return (function(e) {
var parent = JX.$('differential-review-stage');
var clicked = e.getNode('differential-inline-comment');
var inlines = JX.DOM.scry(parent, 'div', 'differential-inline-comment');
var jumpto = null;
for (var ii = 0; ii < inlines.length; ii++) {
if (inlines[ii] == clicked) {
jumpto = inlines[(ii + offset + inlines.length) % inlines.length];
break;
}
}
+ JX.Stratcom.invoke('differential-toggle-file-request', null, {
+ element: jumpto,
+ });
JX.DOM.scrollTo(jumpto);
e.kill();
});
}
JX.Stratcom.listen('click', 'differential-inline-prev', handle_jump(-1));
JX.Stratcom.listen('click', 'differential-inline-next', handle_jump(+1));
});
diff --git a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
index 280dfec42a..78498d0ae4 100644
--- a/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
+++ b/webroot/rsrc/js/application/differential/behavior-dropdown-menus.js
@@ -1,118 +1,133 @@
/**
* @provides javelin-behavior-differential-dropdown-menus
* @requires javelin-behavior
* javelin-dom
* javelin-util
* javelin-stratcom
* phabricator-dropdown-menu
* phabricator-menu-item
*/
JX.behavior('differential-dropdown-menus', function(config) {
function show_more(container) {
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);
}
}
}
function build_menu(button, data) {
function link_to(name, uri) {
var item = new JX.PhabricatorMenuItem(
name,
JX.bind(null, window.open, uri),
uri);
item.setDisabled(!uri);
return item;
}
var reveal_item = new JX.PhabricatorMenuItem('', function () {
show_more(JX.$(data.containerID));
});
var diffusion_item;
if (data.diffusionURI) {
// Show this only if we have a link, since when this appears in Diffusion
// it is otherwise potentially confusing.
diffusion_item = link_to('Browse in Diffusion', data.diffusionURI);
}
var menu = new JX.PhabricatorDropdownMenu(buttons[ii])
.addItem(reveal_item);
+ var visible_item = new JX.PhabricatorMenuItem('', function () {
+ JX.Stratcom.invoke('differential-toggle-file', null, {
+ diff: JX.DOM.scry(JX.$(data.containerID), 'table', 'differential-diff'),
+ });
+ });
+ menu.addItem(visible_item);
+
if (diffusion_item) {
menu.addItem(diffusion_item);
}
menu.addItem(link_to('View Standalone', data.standaloneURI));
if (data.leftURI) {
menu.addItem(link_to('Show Raw File (Left)', data.leftURI));
}
if (data.rightURI) {
menu.addItem(link_to('Show Raw File (Right)', data.rightURI));
}
if (data.editor) {
menu.addItem(new JX.PhabricatorMenuItem(
'Open in Editor',
JX.bind(null, location.assign, data.editor), // Open in the same window.
data.editor));
}
if (data.editorConfigure) {
menu.addItem(link_to('Configure Editor', data.editorConfigure));
}
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 diff = JX.DOM.find(JX.$(data.containerID),
+ 'table', 'differential-diff');
+ if (JX.Stratcom.getData(diff).hidden) {
+ visible_item.setName('Expand File');
+ } else {
+ visible_item.setName('Collapse File');
+ }
});
}
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]));
}
JX.Stratcom.listen(
'click',
'differential-reveal-all',
function(e) {
var containers = JX.DOM.scry(
JX.$('differential-review-stage'),
'div',
'differential-changeset');
for (var i=0; i < containers.length; i++) {
show_more(containers[i]);
}
e.kill();
});
});
diff --git a/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js b/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
index a36305a478..2377445369 100644
--- a/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
+++ b/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
@@ -1,241 +1,273 @@
/**
* @provides javelin-behavior-differential-keyboard-navigation
* @requires javelin-behavior
* javelin-dom
* javelin-stratcom
* phabricator-keyboard-shortcut
*/
JX.behavior('differential-keyboard-navigation', function(config) {
var cursor = -1;
var changesets;
var selection_begin = null;
var selection_end = null;
+ var refreshFocus = function() {};
+
function init() {
if (changesets) {
return;
}
changesets = JX.DOM.scry(document.body, 'div', 'differential-changeset');
}
function getBlocks(cursor) {
// TODO: This might not be terribly fast; we can't currently memoize it
// because it can change as ajax requests come in (e.g., content loads).
var rows = JX.DOM.scry(changesets[cursor], 'tr');
var blocks = [[changesets[cursor], changesets[cursor]]];
var start = null;
var type;
var ii;
+ // Don't show code blocks inside a collapsed file.
+ var diff = JX.DOM.scry(changesets[cursor], 'table', 'differential-diff');
+ if (diff.length == 1 && JX.Stratcom.getData(diff[0]).hidden) {
+ return blocks;
+ }
+
function push() {
if (start) {
blocks.push([start, rows[ii - 1]]);
}
start = null;
}
for (ii = 0; ii < rows.length; ii++) {
type = getRowType(rows[ii]);
if (type == 'comment') {
// If we see these types of rows, make a block for each one.
push();
}
if (!type) {
push();
} else if (type && !start) {
start = rows[ii];
}
}
push();
return blocks;
}
function getRowType(row) {
// NOTE: Being somewhat over-general here to allow other types of objects
// to be easily focused in the future (inline comments, 'show more..').
if (row.className.indexOf('inline') !== -1) {
return 'comment';
}
if (row.className.indexOf('differential-changeset') !== -1) {
return 'file';
}
var cells = JX.DOM.scry(row, 'td');
for (var ii = 0; ii < cells.length; ii++) {
// NOTE: The semantic use of classnames here is for performance; don't
// emulate this elsewhere since it's super terrible.
if (cells[ii].className.indexOf('old') !== -1 ||
cells[ii].className.indexOf('new') !== -1) {
return 'change';
}
}
return null;
}
function jump(manager, delta, jump_to_type) {
init();
if (cursor < 0) {
if (delta < 0) {
// If the user goes "back" without a selection, just reject the action.
return;
} else {
cursor = 0;
}
}
while (true) {
var blocks = getBlocks(cursor);
var focus;
if (delta < 0) {
focus = blocks.length;
} else {
focus = -1;
}
for (var ii = 0; ii < blocks.length; ii++) {
if (blocks[ii][0] == selection_begin) {
focus = ii;
break;
}
}
while (true) {
focus += delta;
if (blocks[focus]) {
var row_type = getRowType(blocks[focus][0]);
if (jump_to_type && row_type != jump_to_type) {
continue;
}
selection_begin = blocks[focus][0];
selection_end = blocks[focus][1];
manager.scrollTo(selection_begin);
- manager.focusOn(selection_begin, selection_end);
+ (refreshFocus = function() {
+ manager.focusOn(selection_begin, selection_end);
+ })();
return;
} else {
var adjusted = (cursor + delta);
if (adjusted < 0 || adjusted >= changesets.length) {
// Stop cursor movement when the user reaches either end.
return;
}
cursor = adjusted;
// Break the inner loop and go to the next file.
break;
}
}
}
}
// When inline comments are updated, wipe out our cache of blocks since
// comments may have been added or deleted.
JX.Stratcom.listen(
null,
'differential-inline-comment-update',
function() {
changesets = null;
});
+ // Same thing when a file is hidden or shown; don't want to highlight
+ // invisible code.
+ JX.Stratcom.listen(
+ 'differential-toggle-file-toggled',
+ null,
+ function() {
+ changesets = null;
+ init();
+ refreshFocus();
+ });
var haunt_mode = 0;
function haunt() {
haunt_mode = (haunt_mode + 1) % 3;
var el = JX.$(config.haunt);
for (var ii = 1; ii <= 2; ii++) {
JX.DOM.alterClass(el, 'differential-haunt-mode-'+ii, (haunt_mode == ii));
}
}
new JX.KeyboardShortcut('j', 'Jump to next change.')
.setHandler(function(manager) {
jump(manager, 1);
})
.register();
new JX.KeyboardShortcut('k', 'Jump to previous change.')
.setHandler(function(manager) {
jump(manager, -1);
})
.register();
new JX.KeyboardShortcut('J', 'Jump to next file.')
.setHandler(function(manager) {
jump(manager, 1, 'file');
})
.register();
new JX.KeyboardShortcut('K', 'Jump to previous file.')
.setHandler(function(manager) {
jump(manager, -1, 'file');
})
.register();
new JX.KeyboardShortcut('n', 'Jump to next inline comment.')
.setHandler(function(manager) {
jump(manager, 1, 'comment');
})
.register();
new JX.KeyboardShortcut('p', 'Jump to previous inline comment.')
.setHandler(function(manager) {
jump(manager, -1, 'comment');
})
.register();
new JX.KeyboardShortcut('t', 'Jump to the table of contents.')
.setHandler(function(manager) {
var toc = JX.$('differential-review-toc');
manager.scrollTo(toc);
})
.register();
+ new JX.KeyboardShortcut('h', 'Collapse or expand the file display.')
+ .setHandler(function(manager) {
+ if (!changesets || !changesets[cursor]) {
+ return;
+ }
+ JX.Stratcom.invoke('differential-toggle-file', null, {
+ diff: JX.DOM.scry(changesets[cursor], 'table', 'differential-diff'),
+ });
+ })
+ .register();
+
+
function inline_op(node, op) {
if (!JX.DOM.scry(node, 'a', 'differential-inline-' + op)) {
// No link for this operation, e.g. editing a comment you can't edit.
return;
}
var data = {
node: JX.DOM.find(node, 'div', 'differential-inline-comment'),
op: op
};
JX.Stratcom.invoke('differential-inline-action', null, data);
}
new JX.KeyboardShortcut('r', 'Reply to selected inline comment.')
.setHandler(function(manager) {
inline_op(selection_begin, 'reply');
})
.register();
new JX.KeyboardShortcut('e', 'Edit selected inline comment.')
.setHandler(function(manager) {
inline_op(selection_begin, 'edit');
})
.register();
if (config.haunt) {
new JX.KeyboardShortcut('z', 'Cycle comment panel haunting modes.')
.setHandler(haunt)
.register();
}
});
diff --git a/webroot/rsrc/js/application/differential/behavior-toggle-files.js b/webroot/rsrc/js/application/differential/behavior-toggle-files.js
new file mode 100644
index 0000000000..4d623b35d4
--- /dev/null
+++ b/webroot/rsrc/js/application/differential/behavior-toggle-files.js
@@ -0,0 +1,62 @@
+/**
+ * @provides javelin-behavior-differential-toggle-files
+ * @requires javelin-behavior
+ * javelin-dom
+ * javelin-stratcom
+ * phabricator-keyboard-shortcut
+ */
+
+JX.behavior('differential-toggle-files', function(config) {
+
+ JX.Stratcom.listen(
+ 'differential-toggle-file',
+ null,
+ function(e) {
+ if (e.getData().diff.length != 1) {
+ return;
+ }
+ var diff = e.getData().diff[0],
+ data = JX.Stratcom.getData(diff);
+ if(data.hidden) {
+ data.hidden = false;
+ JX.DOM.show(diff);
+ } else {
+ data.hidden = true;
+ JX.DOM.hide(diff);
+ }
+ JX.Stratcom.invoke('differential-toggle-file-toggled');
+ });
+
+ JX.Stratcom.listen(
+ 'differential-toggle-file-request',
+ null,
+ function(e) {
+ var elt = e.getData().element;
+ while (elt !== document.body) {
+ if (JX.Stratcom.hasSigil(elt, 'differential-diff') &&
+ JX.Stratcom.getData(elt).hidden) {
+ JX.Stratcom.invoke('differential-toggle-file', null, {
+ diff: [ elt ],
+ });
+ return;
+ }
+ elt = elt.parentNode;
+ }
+ });
+
+ JX.Stratcom.listen(
+ 'hashchange',
+ null,
+ function(e) {
+ var id = window.location.hash;
+ if (!id.match(/^#/)) {
+ return;
+ }
+ JX.Stratcom.invoke('differential-toggle-file-request', null, {
+ element: JX.$(id.substr(1)),
+ });
+ // This event is processed after the hash has changed, so it doesn't
+ // automatically jump there like we want.
+ JX.DOM.scrollTo(JX.$(id.substr(1)));
+ });
+});

File Metadata

Mime Type
text/x-diff
Expires
Tue, Mar 17, 12:15 AM (1 d, 14 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
963748
Default Alt Text
(23 KB)

Event Timeline