Page MenuHomePhorge

No OneTemporary

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

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)

Event Timeline