Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2889911
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
18 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/webroot/rsrc/css/aphront/phabricator-nav-view.css b/webroot/rsrc/css/aphront/phabricator-nav-view.css
index 5f1de3d1a6..79178ea962 100644
--- a/webroot/rsrc/css/aphront/phabricator-nav-view.css
+++ b/webroot/rsrc/css/aphront/phabricator-nav-view.css
@@ -1,255 +1,267 @@
/**
* @provides phabricator-nav-view-css
*/
.jx-drag-col {
cursor: col-resize;
}
.phabricator-nav-col {
position: fixed;
top: 44px;
left: 0;
bottom: 0;
overflow-y: auto;
overflow-x: hidden;
white-space: nowrap;
z-index: 3;
}
.phabricator-nav-app {
width: 149px;
background: #262b2e;
border-right: 1px solid #222222;
box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.25);
}
.phabricator-nav-local {
width: 179px;
background: #ececec;
border-right: 1px solid #999c9e;
box-shadow: inset -3px 0 4px rgba(0, 0, 0, 0.05);
background-image: url(/rsrc/image/menu_texture.png);
}
.device-tablet .phabricator-nav-local,
.device-phone .phabricator-nav-local {
width: 299px;
}
.phabricator-nav-drag {
position: fixed;
top: 0;
left: 217px;
width: 7px;
bottom: 0;
z-index: 4;
cursor: col-resize;
background: #f5f5f5;
border-style: solid;
border-width: 0 1px 0 1px;
border-color: #fff #999c9e #fff #999c9e;
box-shadow: inset -1px 0px 1px rgba(0, 0, 0, 0.15);
background-image: url(/rsrc/image/divot.png);
background-position: center;
background-repeat: no-repeat;
}
.device-tablet .phabricator-nav-drag,
.device-phone .phabricator-nav-drag {
display: none;
}
.phabricator-nav-col a,
.phabricator-nav-col span {
display: block;
}
.phabricator-nav-local {
left: 150px;
}
.device-desktop .phabricator-nav-local {
left: 38px;
}
.phabricator-nav-content {
margin-left: 150px;
}
.has-local-nav .phabricator-nav-content {
margin-left: 330px;
}
.device-desktop .phabricator-nav-content {
margin-left: 38px;
}
.device-desktop .has-local-nav .phabricator-nav-content {
margin-left: 216px;
}
+.device-desktop .local-nav-collapsed .phabricator-nav-local {
+ width: 0px !important;
+}
+
+.device-desktop .local-nav-collapsed .phabricator-nav-drag {
+ display: none;
+}
+
+.device-desktop .local-nav-collapsed .phabricator-nav-content {
+ margin-left: 2.5em !important;
+}
+
.phabricator-nav-col span {
display: block;
font-weight: bold;
padding: 6px 6px 6px 12px;
color: #222222;
}
.phabricator-nav-col a {
display: block;
padding: 3px 6px 3px 24px;
font-weight: bold;
}
.phabricator-nav-col a.aphront-side-nav-selected {
background-color: #a1bbe5;
}
a.phabricator-nav-app-item {
color: #e9e9e9;
font-weight: normal;
padding: 4px;
padding-left: 40px;
vertical-align: middle;
line-height: 30px;
height: 30px;
position: relative;
}
/**
* On the desktop, constrain the size of the <a /> so that the tooltip is
* positioned correctly. Without this rule, it ends up too far to the right.
*/
.device-desktop a.phabricator-nav-app-item {
padding-left: 38px;
padding-right: 0px;
}
span.phabricator-nav-app-item-icon {
position: absolute;
display: block;
left: 5px;
top: 6px;
background-repeat: no-repeat;
width: 30px;
height: 30px;
padding: 0;
margin: 0;
}
.device-desktop .phabricator-nav-app {
width: 37px;
}
.device-desktop .phabricator-nav-head {
display: none;
}
.device-tablet .phabricator-nav-col,
.device-phone .phabricator-nav-col {
position: absolute;
top: 0px;
}
.device-tablet .phabricator-nav-app,
.device-phone .phabricator-nav-app {
left: -450px;
}
.device-tablet .phabricator-nav-local,
.device-phone .phabricator-nav-local {
left: -300px;
}
.device-phone .phabricator-nav-head-tablet {
display: none;
}
.device-tablet .phabricator-nav-head-phone {
display: none;
}
.device-tablet .phabricator-nav,
.device-phone .phabricator-nav {
overflow-x: hidden;
position: relative;
}
.device-tablet .phabricator-nav-content,
.device-phone .phabricator-nav-content {
width: 100%;
}
.device-tablet .phabricator-nav-content,
.device-phone .phabricator-nav-content {
margin-left: 0;
position: relative;
}
.phabricator-nav-head {
display: block;
position: relative;
height: 43px;
background: #fafafa;
overflow: hidden;
border-bottom: 1px solid #5d5d5d;
text-align: center;
box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.10),
0px 1px 2px rgba(0, 0, 0, 0.10);
}
.nav-button {
background-color: #f3f3f3;
height: 32px;
width: 40px;
margin: 5px 0px;
display: inline-block;
border: 1px solid #999999;
box-shadow: inset -1px -1px 3px rgba(0, 0, 0, 0.10);
background-repeat: no-repeat;
}
.nav-button-selected {
background-color: #c9c9c9;
box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.20);
}
.nav-button + .nav-button {
margin-left: -1px;
}
.nav-button-w {
border-radius: 6px 0 0 6px;
}
.nav-button-e {
border-radius: 0 6px 6px 0;
}
.nav-button-apps {
background-image: url(/rsrc/image/button_apps.png);
background-size: 24px auto;
background-position: center;
}
.nav-button-menu {
background-image: url(/rsrc/image/button_menu.png);
background-size: 24px auto;
background-position: center;
}
.nav-button-content {
background-image: url(/rsrc/image/button_content.png);
background-size: 24px auto;
background-position: center;
}
diff --git a/webroot/rsrc/js/application/core/behavior-phabricator-nav.js b/webroot/rsrc/js/application/core/behavior-phabricator-nav.js
index ada68224b4..d61ecf0f41 100644
--- a/webroot/rsrc/js/application/core/behavior-phabricator-nav.js
+++ b/webroot/rsrc/js/application/core/behavior-phabricator-nav.js
@@ -1,208 +1,215 @@
/**
* @provides javelin-behavior-phabricator-nav
* @requires javelin-behavior
* javelin-behavior-device
* javelin-stratcom
* javelin-dom
* javelin-magical-init
* javelin-vector
* javelin-util
* javelin-fx
* @javelin
*/
JX.behavior('phabricator-nav', function(config) {
var app = JX.$(config.appID);
var content = JX.$(config.contentID);
var local = config.localID ? JX.$(config.localID) : null;
+ var main = JX.$(config.mainID);
// - Sliding Menu Animations ---------------------------------------------------
var animations = [];
function slide_menu(position) {
var app_width = 150;
var local_width = local ? 300 : 0;
var shifts = {
0: 0,
1: app_width - 10,
2: app_width + local_width
};
var shift = shifts[position];
while (animations.length) {
animations.pop().stop();
}
animations.push(build_animation(app, -shift));
local && animations.push(build_animation(local, -shift + app_width));
animations.push(build_animation(content, -shift + app_width + local_width));
select_button(position);
}
function build_animation(element, target) {
return new JX.FX(element)
.setDuration(100)
.start({left: [JX.$V(element).x, target]});
}
// - Sliding Menu Buttons ------------------------------------------------------
var button_positions = {
0: [JX.$('phone-menu1'), JX.$('tablet-menu1')],
1: [JX.$('phone-menu2')],
2: [JX.$('phone-menu3'), JX.$('tablet-menu2')]
};
for (var k in button_positions) {
for (var ii = 0; ii < button_positions[k].length; ii++) {
var onclick = function(p, e) {
e.kill();
slide_menu(p);
};
onclick = JX.bind(null, onclick, k);
JX.DOM.listen(
button_positions[k][ii],
['touchstart', 'mousedown'],
null,
onclick);
}
}
function select_button(position) {
for (var k in button_positions) {
for (var ii = 0; ii < button_positions[k].length; ii++) {
JX.DOM.alterClass(
button_positions[k][ii],
'nav-button-selected',
(k == position));
}
}
}
// - Flexible Navigation Column ------------------------------------------------
if (config.dragID) {
var dragging;
var track;
var drag = JX.$(config.dragID);
JX.enableDispatch(document.body, 'mousemove');
JX.DOM.listen(drag, 'mousedown', null, function(e) {
dragging = JX.$V(e);
// Show the "col-resize" cursor on the whole document while we're
// dragging, since the mouse will slip off the actual bar fairly often and
// we don't want it to flicker.
JX.DOM.alterClass(document.body, 'jx-drag-col', true);
track = [
{
element: local,
parameter: 'width',
start: JX.Vector.getDim(local).x,
scale: 1,
width: JX.Vector.getDim(local).x,
minWidth: 1,
minScale: 1
},
{
element: drag,
parameter: 'left',
start: JX.$V(drag).x,
scale: 1
},
{
element: content,
parameter: 'marginLeft',
start: parseInt(getComputedStyle(content).marginLeft, 10),
scale: 1,
width: JX.Vector.getDim(content).x,
minWidth: 300,
minScale: -1
}
];
e.kill();
});
JX.Stratcom.listen('mousemove', null, function(e) {
if (!dragging) {
return;
}
var dx = JX.$V(e).x - dragging.x;
var panel;
for (var k = 0; k < track.length; k++) {
panel = track[k];
if (!panel.minWidth) {
continue;
}
var new_width = panel.width + (dx * panel.minScale);
if (new_width < panel.minWidth) {
dx = (panel.minWidth - panel.width) * panel.minScale;
}
}
for (var k = 0; k < track.length; k++) {
panel = track[k];
var v = (panel.start + (dx * panel.scale));
panel.element.style[panel.parameter] = v + 'px';
}
});
JX.Stratcom.listen('mouseup', null, function(e) {
if (!dragging) {
return;
}
JX.DOM.alterClass(document.body, 'jx-drag-col', false);
dragging = false;
});
+
+ var collapsed = false;
+ JX.Stratcom.listen('differential-filetree-toggle', null, function(e) {
+ collapsed = !collapsed;
+ JX.DOM.alterClass(main, 'local-nav-collapsed', collapsed);
+ });
}
// - Scroll --------------------------------------------------------------------
// When the user scrolls down on the desktop, we move the application and
// local navs up until they hit the top of the page.
JX.Stratcom.listen(['scroll', 'resize'], null, function(e) {
if (JX.Device.getDevice() != 'desktop') {
return;
}
var y = Math.max(0, 44 - JX.Vector.getScroll().y);
app.style.top = y + 'px';
if (local) {
local.style.top = y + 'px';
}
});
// - Navigation Reset ----------------------------------------------------------
JX.Stratcom.listen('phabricator-device-change', null, function(event) {
app.style.left = '';
app.style.top = '';
if (local) {
local.style.left = '';
local.style.width = '';
local.style.top = '';
}
if (drag) {
drag.style.left = '';
}
content.style.marginLeft = '';
select_button(2);
});
});
diff --git a/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js b/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
index 8509a19490..d152deac87 100644
--- a/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
+++ b/webroot/rsrc/js/application/differential/behavior-keyboard-nav.js
@@ -1,273 +1,278 @@
/**
* @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);
(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.$('toc');
manager.scrollTo(toc);
})
.register();
+ new JX.KeyboardShortcut('f', 'Toggle file tree.')
+ .setHandler(function(manager) {
+ JX.Stratcom.invoke('differential-filetree-toggle');
+ })
+ .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();
}
});
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Jan 19, 12:49 (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1124752
Default Alt Text
(18 KB)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment