Merge "Add keyboard shortcuts for diffing against base and latest"
This commit is contained in:
@@ -101,11 +101,14 @@ import {dom} from '@polymer/polymer/lib/legacy/polymer.dom.js';
|
|||||||
|
|
||||||
const DOC_ONLY = 'DOC_ONLY';
|
const DOC_ONLY = 'DOC_ONLY';
|
||||||
const GO_KEY = 'GO_KEY';
|
const GO_KEY = 'GO_KEY';
|
||||||
|
const V_KEY = 'V_KEY';
|
||||||
|
|
||||||
// The maximum age of a keydown event to be used in a jump navigation. This
|
// The maximum age of a keydown event to be used in a jump navigation. This
|
||||||
// is only for cases when the keyup event is lost.
|
// is only for cases when the keyup event is lost.
|
||||||
const GO_KEY_TIMEOUT_MS = 1000;
|
const GO_KEY_TIMEOUT_MS = 1000;
|
||||||
|
|
||||||
|
const V_KEY_TIMEOUT_MS = 1000;
|
||||||
|
|
||||||
const ShortcutSection = {
|
const ShortcutSection = {
|
||||||
ACTIONS: 'Actions',
|
ACTIONS: 'Actions',
|
||||||
DIFFS: 'Diffs',
|
DIFFS: 'Diffs',
|
||||||
@@ -141,6 +144,11 @@ const Shortcut = {
|
|||||||
TOGGLE_DIFF_MODE: 'TOGGLE_DIFF_MODE',
|
TOGGLE_DIFF_MODE: 'TOGGLE_DIFF_MODE',
|
||||||
REFRESH_CHANGE: 'REFRESH_CHANGE',
|
REFRESH_CHANGE: 'REFRESH_CHANGE',
|
||||||
EDIT_TOPIC: 'EDIT_TOPIC',
|
EDIT_TOPIC: 'EDIT_TOPIC',
|
||||||
|
DIFF_AGAINST_BASE: 'DIFF_AGAINST_BASE',
|
||||||
|
DIFF_AGAINST_LATEST: 'DIFF_AGAINST_LATEST',
|
||||||
|
DIFF_BASE_AGAINST_LEFT: 'DIFF_BASE_AGAINST_LEFT',
|
||||||
|
DIFF_RIGHT_AGAINST_LATEST: 'DIFF_RIGHT_AGAINST_LATEST',
|
||||||
|
DIFF_BASE_AGAINST_LATEST: 'DIFF_BASE_AGAINST_LATEST',
|
||||||
|
|
||||||
NEXT_LINE: 'NEXT_LINE',
|
NEXT_LINE: 'NEXT_LINE',
|
||||||
PREV_LINE: 'PREV_LINE',
|
PREV_LINE: 'PREV_LINE',
|
||||||
@@ -233,9 +241,29 @@ _describe(Shortcut.TOGGLE_CHANGE_STAR, ShortcutSection.ACTIONS,
|
|||||||
'Star/unstar change');
|
'Star/unstar change');
|
||||||
_describe(Shortcut.EDIT_TOPIC, ShortcutSection.ACTIONS,
|
_describe(Shortcut.EDIT_TOPIC, ShortcutSection.ACTIONS,
|
||||||
'Add a change topic');
|
'Add a change topic');
|
||||||
|
_describe(Shortcut.DIFF_AGAINST_BASE, ShortcutSection.ACTIONS,
|
||||||
|
'Diff against base');
|
||||||
|
_describe(Shortcut.DIFF_AGAINST_LATEST, ShortcutSection.ACTIONS,
|
||||||
|
'Diff against latest patchset');
|
||||||
|
_describe(Shortcut.DIFF_BASE_AGAINST_LEFT, ShortcutSection.ACTIONS,
|
||||||
|
'Diff base against left');
|
||||||
|
_describe(Shortcut.DIFF_RIGHT_AGAINST_LATEST, ShortcutSection.ACTIONS,
|
||||||
|
'Diff right against latest');
|
||||||
|
_describe(Shortcut.DIFF_BASE_AGAINST_LATEST, ShortcutSection.ACTIONS,
|
||||||
|
'Diff base against latest');
|
||||||
|
|
||||||
_describe(Shortcut.NEXT_LINE, ShortcutSection.DIFFS, 'Go to next line');
|
_describe(Shortcut.NEXT_LINE, ShortcutSection.DIFFS, 'Go to next line');
|
||||||
_describe(Shortcut.PREV_LINE, ShortcutSection.DIFFS, 'Go to previous line');
|
_describe(Shortcut.PREV_LINE, ShortcutSection.DIFFS, 'Go to previous line');
|
||||||
|
_describe(Shortcut.DIFF_AGAINST_BASE, ShortcutSection.DIFFS,
|
||||||
|
'Diff against base');
|
||||||
|
_describe(Shortcut.DIFF_AGAINST_LATEST, ShortcutSection.DIFFS,
|
||||||
|
'Diff against latest patchset');
|
||||||
|
_describe(Shortcut.DIFF_BASE_AGAINST_LEFT, ShortcutSection.DIFFS,
|
||||||
|
'Diff base against left');
|
||||||
|
_describe(Shortcut.DIFF_RIGHT_AGAINST_LATEST, ShortcutSection.DIFFS,
|
||||||
|
'Diff right against latest');
|
||||||
|
_describe(Shortcut.DIFF_BASE_AGAINST_LATEST, ShortcutSection.DIFFS,
|
||||||
|
'Diff base against latest');
|
||||||
_describe(Shortcut.VISIBLE_LINE, ShortcutSection.DIFFS,
|
_describe(Shortcut.VISIBLE_LINE, ShortcutSection.DIFFS,
|
||||||
'Move cursor to currently visible code');
|
'Move cursor to currently visible code');
|
||||||
_describe(Shortcut.NEXT_CHUNK, ShortcutSection.DIFFS,
|
_describe(Shortcut.NEXT_CHUNK, ShortcutSection.DIFFS,
|
||||||
@@ -435,39 +463,52 @@ class ShortcutManager {
|
|||||||
const bindings = this.bindings.get(shortcut);
|
const bindings = this.bindings.get(shortcut);
|
||||||
if (!bindings) { return null; }
|
if (!bindings) { return null; }
|
||||||
if (bindings[0] === GO_KEY) {
|
if (bindings[0] === GO_KEY) {
|
||||||
return [['g'].concat(bindings.slice(1))];
|
return bindings.slice(1).map(
|
||||||
|
binding => this._describeKey(binding)
|
||||||
|
)
|
||||||
|
.map(binding => ['g'].concat(binding));
|
||||||
|
}
|
||||||
|
if (bindings[0] === V_KEY) {
|
||||||
|
return bindings.slice(1).map(
|
||||||
|
binding => this._describeKey(binding)
|
||||||
|
)
|
||||||
|
.map(binding => ['v'].concat(binding));
|
||||||
}
|
}
|
||||||
return bindings
|
return bindings
|
||||||
.filter(binding => binding !== DOC_ONLY)
|
.filter(binding => binding !== DOC_ONLY)
|
||||||
.map(binding => this.describeBinding(binding));
|
.map(binding => this.describeBinding(binding));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_describeKey(key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'shift':
|
||||||
|
return 'Shift';
|
||||||
|
case 'meta':
|
||||||
|
return 'Meta';
|
||||||
|
case 'ctrl':
|
||||||
|
return 'Ctrl';
|
||||||
|
case 'enter':
|
||||||
|
return 'Enter';
|
||||||
|
case 'up':
|
||||||
|
return '↑';
|
||||||
|
case 'down':
|
||||||
|
return '↓';
|
||||||
|
case 'left':
|
||||||
|
return '←';
|
||||||
|
case 'right':
|
||||||
|
return '→';
|
||||||
|
default:
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
describeBinding(binding) {
|
describeBinding(binding) {
|
||||||
if (binding.length === 1) {
|
if (binding.length === 1) {
|
||||||
return [binding];
|
return [binding];
|
||||||
}
|
}
|
||||||
return binding.split(':')[0].split('+').map(part => {
|
return binding.split(':')[0].split('+').map(part =>
|
||||||
switch (part) {
|
this._describeKey(part)
|
||||||
case 'shift':
|
);
|
||||||
return 'Shift';
|
|
||||||
case 'meta':
|
|
||||||
return 'Meta';
|
|
||||||
case 'ctrl':
|
|
||||||
return 'Ctrl';
|
|
||||||
case 'enter':
|
|
||||||
return 'Enter';
|
|
||||||
case 'up':
|
|
||||||
return '↑';
|
|
||||||
case 'down':
|
|
||||||
return '↓';
|
|
||||||
case 'left':
|
|
||||||
return '←';
|
|
||||||
case 'right':
|
|
||||||
return '→';
|
|
||||||
default:
|
|
||||||
return part;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
notifyListeners() {
|
notifyListeners() {
|
||||||
@@ -489,6 +530,8 @@ export const KeyboardShortcutBehavior = [
|
|||||||
// eslint-disable-next-line object-shorthand
|
// eslint-disable-next-line object-shorthand
|
||||||
GO_KEY: GO_KEY,
|
GO_KEY: GO_KEY,
|
||||||
// eslint-disable-next-line object-shorthand
|
// eslint-disable-next-line object-shorthand
|
||||||
|
V_KEY: V_KEY,
|
||||||
|
// eslint-disable-next-line object-shorthand
|
||||||
Shortcut: Shortcut,
|
Shortcut: Shortcut,
|
||||||
// eslint-disable-next-line object-shorthand
|
// eslint-disable-next-line object-shorthand
|
||||||
ShortcutSection: ShortcutSection,
|
ShortcutSection: ShortcutSection,
|
||||||
@@ -498,17 +541,20 @@ export const KeyboardShortcutBehavior = [
|
|||||||
type: Number,
|
type: Number,
|
||||||
value: null,
|
value: null,
|
||||||
},
|
},
|
||||||
|
|
||||||
_shortcut_go_table: {
|
_shortcut_go_table: {
|
||||||
type: Array,
|
type: Array,
|
||||||
value() { return new Map(); },
|
value() { return new Map(); },
|
||||||
},
|
},
|
||||||
|
_shortcut_v_table: {
|
||||||
|
type: Array,
|
||||||
|
value() { return new Map(); },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
modifierPressed(e) {
|
modifierPressed(e) {
|
||||||
e = getKeyboardEvent(e);
|
e = getKeyboardEvent(e);
|
||||||
return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey ||
|
return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey ||
|
||||||
!!this._inGoKeyMode();
|
!!this._inGoKeyMode() || !!this._inVKeyMode();
|
||||||
},
|
},
|
||||||
|
|
||||||
isModifierPressed(e, modifier) {
|
isModifierPressed(e, modifier) {
|
||||||
@@ -566,7 +612,14 @@ export const KeyboardShortcutBehavior = [
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bindings[0] === GO_KEY) {
|
if (bindings[0] === GO_KEY) {
|
||||||
this._shortcut_go_table.set(bindings[1], handler);
|
bindings.slice(1).forEach(binding =>
|
||||||
|
this._shortcut_go_table.set(binding, handler));
|
||||||
|
} else if (bindings[0] === V_KEY) {
|
||||||
|
// for each binding added with the go/v key, we set the handler to be
|
||||||
|
// handleVKeyAction. handleVKeyAction then looks up in th
|
||||||
|
// shortcut_table to see what the relevant handler should be
|
||||||
|
bindings.slice(1).forEach(binding =>
|
||||||
|
this._shortcut_v_table.set(binding, handler));
|
||||||
} else {
|
} else {
|
||||||
this.addOwnKeyBinding(bindings.join(' '), handler);
|
this.addOwnKeyBinding(bindings.join(' '), handler);
|
||||||
}
|
}
|
||||||
@@ -593,6 +646,14 @@ export const KeyboardShortcutBehavior = [
|
|||||||
this.addOwnKeyBinding(key, '_handleGoAction');
|
this.addOwnKeyBinding(key, '_handleGoAction');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.addOwnKeyBinding('v:keydown', '_handleVKeyDown');
|
||||||
|
this.addOwnKeyBinding('v:keyup', '_handleVKeyUp');
|
||||||
|
if (this._shortcut_v_table.size > 0) {
|
||||||
|
this._shortcut_v_table.forEach((handler, key) => {
|
||||||
|
this.addOwnKeyBinding(key, '_handleVAction');
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
@@ -614,6 +675,33 @@ export const KeyboardShortcutBehavior = [
|
|||||||
shortcutManager.removeListener(listener);
|
shortcutManager.removeListener(listener);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_handleVKeyDown(e) {
|
||||||
|
this._shortcut_v_key_last_pressed = Date.now();
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleVKeyUp(e) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this._shortcut_v_key_last_pressed = null;
|
||||||
|
}, V_KEY_TIMEOUT_MS);
|
||||||
|
},
|
||||||
|
|
||||||
|
_inVKeyMode() {
|
||||||
|
return this._shortcut_v_key_last_pressed &&
|
||||||
|
(Date.now() - this._shortcut_v_key_last_pressed <=
|
||||||
|
V_KEY_TIMEOUT_MS);
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleVAction(e) {
|
||||||
|
if (!this._inVKeyMode() ||
|
||||||
|
!this._shortcut_v_table.has(e.detail.key) ||
|
||||||
|
this.shouldSuppressKeyboardShortcut(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const handler = this._shortcut_v_table.get(e.detail.key);
|
||||||
|
this[handler](e);
|
||||||
|
},
|
||||||
|
|
||||||
_handleGoKeyDown(e) {
|
_handleGoKeyDown(e) {
|
||||||
this._shortcut_go_key_last_pressed = Date.now();
|
this._shortcut_go_key_last_pressed = Date.now();
|
||||||
},
|
},
|
||||||
@@ -648,6 +736,7 @@ export const KeyboardShortcutBehavior = [
|
|||||||
export const KeyboardShortcutBinder = {
|
export const KeyboardShortcutBinder = {
|
||||||
DOC_ONLY,
|
DOC_ONLY,
|
||||||
GO_KEY,
|
GO_KEY,
|
||||||
|
V_KEY,
|
||||||
Shortcut,
|
Shortcut,
|
||||||
ShortcutManager,
|
ShortcutManager,
|
||||||
ShortcutSection,
|
ShortcutSection,
|
||||||
|
|||||||
@@ -441,6 +441,13 @@ class GrChangeView extends mixinBehaviors( [
|
|||||||
[this.Shortcut.COLLAPSE_ALL_MESSAGES]: '_handleCollapseAllMessages',
|
[this.Shortcut.COLLAPSE_ALL_MESSAGES]: '_handleCollapseAllMessages',
|
||||||
[this.Shortcut.OPEN_DIFF_PREFS]: '_handleOpenDiffPrefsShortcut',
|
[this.Shortcut.OPEN_DIFF_PREFS]: '_handleOpenDiffPrefsShortcut',
|
||||||
[this.Shortcut.EDIT_TOPIC]: '_handleEditTopic',
|
[this.Shortcut.EDIT_TOPIC]: '_handleEditTopic',
|
||||||
|
[this.Shortcut.DIFF_AGAINST_BASE]: '_handleDiffAgainstBase',
|
||||||
|
[this.Shortcut.DIFF_AGAINST_LATEST]: '_handleDiffAgainstLatest',
|
||||||
|
[this.Shortcut.DIFF_BASE_AGAINST_LEFT]: '_handleDiffBaseAgainstLeft',
|
||||||
|
[this.Shortcut.DIFF_RIGHT_AGAINST_LATEST]:
|
||||||
|
'_handleDiffRightAgainstLatest',
|
||||||
|
[this.Shortcut.DIFF_BASE_AGAINST_LATEST]:
|
||||||
|
'_handleDiffBaseAgainstLatest',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,6 +1411,82 @@ class GrChangeView extends mixinBehaviors( [
|
|||||||
this.$.metadata.editTopic();
|
this.$.metadata.editTopic();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_handleDiffAgainstBase(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Base is already selected.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToChange(this._change, this._patchRange.patchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffBaseAgainstLeft(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Left is already base.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToChange(this._change, this._patchRange.basePatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum)) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Latest is already selected.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToChange(this._change, latestPatchNum,
|
||||||
|
this._patchRange.basePatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffRightAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum)) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Right is already latest.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToChange(this._change, latestPatchNum,
|
||||||
|
this._patchRange.patchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffBaseAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum) &&
|
||||||
|
this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Already diffing base against latest.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToChange(this._change, latestPatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
_handleRefreshChange(e) {
|
_handleRefreshChange(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -333,6 +333,81 @@ suite('gr-change-view tests', () => {
|
|||||||
assert.isTrue(replaceStateStub.called);
|
assert.isTrue(replaceStateStub.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('_handleDiffAgainstBase', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
patchNum: 3,
|
||||||
|
basePatchNum: 1,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
element._handleDiffAgainstBase(new CustomEvent(''));
|
||||||
|
assert(navigateToChangeStub.called);
|
||||||
|
const args = navigateToChangeStub.getCall(0).args;
|
||||||
|
assert.equal(args[1], 3);
|
||||||
|
assert.isNotOk(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffAgainstLatest', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: 1,
|
||||||
|
patchNum: 3,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
element._handleDiffAgainstLatest(new CustomEvent(''));
|
||||||
|
assert(navigateToChangeStub.called);
|
||||||
|
const args = navigateToChangeStub.getCall(0).args;
|
||||||
|
assert.equal(args[1], 10);
|
||||||
|
assert.equal(args[2], 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffBaseAgainstLeft', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
patchNum: 3,
|
||||||
|
basePatchNum: 1,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
element._handleDiffBaseAgainstLeft(new CustomEvent(''));
|
||||||
|
assert(navigateToChangeStub.called);
|
||||||
|
const args = navigateToChangeStub.getCall(0).args;
|
||||||
|
assert.equal(args[1], 1);
|
||||||
|
assert.isNotOk(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffRightAgainstLatest', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: 1,
|
||||||
|
patchNum: 3,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
element._handleDiffRightAgainstLatest(new CustomEvent(''));
|
||||||
|
assert(navigateToChangeStub.called);
|
||||||
|
const args = navigateToChangeStub.getCall(0).args;
|
||||||
|
assert.equal(args[1], 10);
|
||||||
|
assert.equal(args[2], 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffBaseAgainstLatest', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: 1,
|
||||||
|
patchNum: 3,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
element._handleDiffBaseAgainstLatest(new CustomEvent(''));
|
||||||
|
assert(navigateToChangeStub.called);
|
||||||
|
const args = navigateToChangeStub.getCall(0).args;
|
||||||
|
assert.equal(args[1], 10);
|
||||||
|
assert.isNotOk(args[2]);
|
||||||
|
});
|
||||||
|
|
||||||
suite('plugins adding to file tab', () => {
|
suite('plugins adding to file tab', () => {
|
||||||
setup(done => {
|
setup(done => {
|
||||||
// Resolving it here instead of during setup() as other tests depend
|
// Resolving it here instead of during setup() as other tests depend
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ class GrKeyBindingDisplay extends GestureEventListeners(
|
|||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
/** @type {Array<string>} */
|
/** @type {Array<Array<string>>}
|
||||||
|
* Each entry in the binding represents an array that is a keyboard
|
||||||
|
* shortcut containing [modifier, combination]
|
||||||
|
*/
|
||||||
binding: Array,
|
binding: Array,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,6 +300,13 @@ class GrDiffView extends mixinBehaviors( [
|
|||||||
[this.Shortcut.TOGGLE_BLAME]: '_handleToggleBlame',
|
[this.Shortcut.TOGGLE_BLAME]: '_handleToggleBlame',
|
||||||
[this.Shortcut.TOGGLE_HIDE_ALL_COMMENT_THREADS]:
|
[this.Shortcut.TOGGLE_HIDE_ALL_COMMENT_THREADS]:
|
||||||
'_handleToggleHideAllCommentThreads',
|
'_handleToggleHideAllCommentThreads',
|
||||||
|
[this.Shortcut.DIFF_AGAINST_BASE]: '_handleDiffAgainstBase',
|
||||||
|
[this.Shortcut.DIFF_AGAINST_LATEST]: '_handleDiffAgainstLatest',
|
||||||
|
[this.Shortcut.DIFF_BASE_AGAINST_LEFT]: '_handleDiffBaseAgainstLeft',
|
||||||
|
[this.Shortcut.DIFF_RIGHT_AGAINST_LATEST]:
|
||||||
|
'_handleDiffRightAgainstLatest',
|
||||||
|
[this.Shortcut.DIFF_BASE_AGAINST_LATEST]:
|
||||||
|
'_handleDiffBaseAgainstLatest',
|
||||||
|
|
||||||
// Final two are actually handled by gr-comment-thread.
|
// Final two are actually handled by gr-comment-thread.
|
||||||
[this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
|
[this.Shortcut.EXPAND_ALL_COMMENT_THREADS]: null,
|
||||||
@@ -1287,6 +1294,87 @@ class GrDiffView extends mixinBehaviors( [
|
|||||||
this.toggleClass('hideComments');
|
this.toggleClass('hideComments');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_handleDiffAgainstBase(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Base is already selected.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToDiff(
|
||||||
|
this._change, this._path, this._patchRange.patchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffBaseAgainstLeft(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Left is already base.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToDiff(this._change, this._path,
|
||||||
|
this._patchRange.basePatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum)) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Latest is already selected.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GerritNav.navigateToDiff(
|
||||||
|
this._change, this._path, latestPatchNum,
|
||||||
|
this._patchRange.basePatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffRightAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum)) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Right is already latest.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToDiff(this._change, this._path, latestPatchNum,
|
||||||
|
this._patchRange.patchNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handleDiffBaseAgainstLatest(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
const latestPatchNum = this.computeLatestPatchNum(this._allPatchSets);
|
||||||
|
if (this.patchNumEquals(this._patchRange.patchNum, latestPatchNum) &&
|
||||||
|
this.patchNumEquals(this._patchRange.basePatchNum, 'PARENT')) {
|
||||||
|
this.dispatchEvent(new CustomEvent('show-alert', {
|
||||||
|
detail: {
|
||||||
|
message: 'Already diffing base against latest.',
|
||||||
|
},
|
||||||
|
composed: true, bubbles: true,
|
||||||
|
}));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GerritNav.navigateToDiff(this._change, this._path, latestPatchNum);
|
||||||
|
}
|
||||||
|
|
||||||
_computeBlameLoaderClass(isImageDiff, path) {
|
_computeBlameLoaderClass(isImageDiff, path) {
|
||||||
return !this.isMagicPath(path) && !isImageDiff ? 'show' : '';
|
return !this.isMagicPath(path) && !isImageDiff ? 'show' : '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,6 +287,81 @@ suite('gr-diff-view tests', () => {
|
|||||||
assert.isTrue(expandStub.called);
|
assert.isTrue(expandStub.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('diff against base', () => {
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: '5',
|
||||||
|
patchNum: '10',
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
const diffNavStub = sandbox.stub(GerritNav, 'navigateToDiff');
|
||||||
|
element._handleDiffAgainstBase(new CustomEvent(''));
|
||||||
|
const args = diffNavStub.getCall(0).args;
|
||||||
|
assert.equal(args[2], 10);
|
||||||
|
assert.isNotOk(args[3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('diff against latest', () => {
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: '5',
|
||||||
|
patchNum: '10',
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(12);
|
||||||
|
const diffNavStub = sandbox.stub(GerritNav, 'navigateToDiff');
|
||||||
|
element._handleDiffAgainstLatest(new CustomEvent(''));
|
||||||
|
const args = diffNavStub.getCall(0).args;
|
||||||
|
assert.equal(args[2], 12);
|
||||||
|
assert.equal(args[3], 5);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffBaseAgainstLeft', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
patchNum: 3,
|
||||||
|
basePatchNum: 1,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
const diffNavStub = sandbox.stub(GerritNav, 'navigateToDiff');
|
||||||
|
element._handleDiffBaseAgainstLeft(new CustomEvent(''));
|
||||||
|
assert(diffNavStub.called);
|
||||||
|
const args = diffNavStub.getCall(0).args;
|
||||||
|
assert.equal(args[2], 1);
|
||||||
|
assert.isNotOk(args[3]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffRightAgainstLatest', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: 1,
|
||||||
|
patchNum: 3,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
const diffNavStub = sandbox.stub(GerritNav, 'navigateToDiff');
|
||||||
|
element._handleDiffRightAgainstLatest(new CustomEvent(''));
|
||||||
|
assert(diffNavStub.called);
|
||||||
|
const args = diffNavStub.getCall(0).args;
|
||||||
|
assert.equal(args[2], 10);
|
||||||
|
assert.equal(args[3], 3);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('_handleDiffBaseAgainstLatest', () => {
|
||||||
|
element._changeNum = '1';
|
||||||
|
element._patchRange = {
|
||||||
|
basePatchNum: 1,
|
||||||
|
patchNum: 3,
|
||||||
|
};
|
||||||
|
sandbox.stub(element, 'computeLatestPatchNum').returns(10);
|
||||||
|
sandbox.stub(element, 'shouldSuppressKeyboardShortcut').returns(false);
|
||||||
|
const diffNavStub = sandbox.stub(GerritNav, 'navigateToDiff');
|
||||||
|
element._handleDiffBaseAgainstLatest(new CustomEvent(''));
|
||||||
|
assert(diffNavStub.called);
|
||||||
|
const args = diffNavStub.getCall(0).args;
|
||||||
|
assert.equal(args[2], 10);
|
||||||
|
assert.isNotOk(args[3]);
|
||||||
|
});
|
||||||
|
|
||||||
test('keyboard shortcuts with patch range', () => {
|
test('keyboard shortcuts with patch range', () => {
|
||||||
element._changeNum = '42';
|
element._changeNum = '42';
|
||||||
element._patchRange = {
|
element._patchRange = {
|
||||||
|
|||||||
@@ -270,9 +270,9 @@ class GrAppElement extends mixinBehaviors( [
|
|||||||
this.Shortcut.EDIT_TOPIC, 't');
|
this.Shortcut.EDIT_TOPIC, 't');
|
||||||
|
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
this.Shortcut.OPEN_REPLY_DIALOG, 'a');
|
this.Shortcut.OPEN_REPLY_DIALOG, 'a:keyup');
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
this.Shortcut.OPEN_DOWNLOAD_DIALOG, 'd');
|
this.Shortcut.OPEN_DOWNLOAD_DIALOG, 'd:keyup');
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
this.Shortcut.EXPAND_ALL_MESSAGES, 'x');
|
this.Shortcut.EXPAND_ALL_MESSAGES, 'x');
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
@@ -285,6 +285,16 @@ class GrAppElement extends mixinBehaviors( [
|
|||||||
this.Shortcut.UP_TO_CHANGE, 'u');
|
this.Shortcut.UP_TO_CHANGE, 'u');
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
this.Shortcut.TOGGLE_DIFF_MODE, 'm:keyup');
|
this.Shortcut.TOGGLE_DIFF_MODE, 'm:keyup');
|
||||||
|
this.bindShortcut(
|
||||||
|
this.Shortcut.DIFF_AGAINST_BASE, this.V_KEY, 'down', 's');
|
||||||
|
this.bindShortcut(
|
||||||
|
this.Shortcut.DIFF_AGAINST_LATEST, this.V_KEY, 'up', 'w');
|
||||||
|
this.bindShortcut(
|
||||||
|
this.Shortcut.DIFF_BASE_AGAINST_LEFT, this.V_KEY, 'left', 'a');
|
||||||
|
this.bindShortcut(
|
||||||
|
this.Shortcut.DIFF_RIGHT_AGAINST_LATEST, this.V_KEY, 'right', 'd');
|
||||||
|
this.bindShortcut(
|
||||||
|
this.Shortcut.DIFF_BASE_AGAINST_LATEST, this.V_KEY, 'b');
|
||||||
|
|
||||||
this.bindShortcut(
|
this.bindShortcut(
|
||||||
this.Shortcut.NEXT_LINE, 'j', 'down');
|
this.Shortcut.NEXT_LINE, 'j', 'down');
|
||||||
|
|||||||
Reference in New Issue
Block a user