Cleanup: use iron-a11y-keys-behavior for keyboard shortcuts
+ This does not cover on-keydown handlers within elements. A follow-up change will account for those. + Keyboard shortcuts are disabled within gr-overlay, input, and textarea elements. + Added tests for new behavior (plus some missing ones covering broken behavior). + Removed blur hacks used on elements to placate the kb shortcuts due to restrictions that have been removed. Bug: Issue 4198 Change-Id: Ide8009a3bfc340a35a8ec8b9189a85b49c8a95aa
This commit is contained in:
@@ -14,69 +14,30 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<link rel="import" href="../bower_components/polymer/polymer.html">
|
<link rel="import" href="../bower_components/polymer/polymer.html">
|
||||||
|
<link rel="import" href="../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(function(window) {
|
(function(window) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/** @polymerBehavior Gerrit.KeyboardShortcutBehavior */
|
var KeyboardShortcutBehaviorImpl = {
|
||||||
var KeyboardShortcutBehavior = {
|
|
||||||
// Set of identifiers currently blocking keyboard shortcuts. Stored as
|
|
||||||
// a map of string to the value of true.
|
|
||||||
_disablers: {},
|
|
||||||
|
|
||||||
properties: {
|
|
||||||
keyEventTarget: {
|
|
||||||
type: Object,
|
|
||||||
value: function() { return this; },
|
|
||||||
},
|
|
||||||
|
|
||||||
_boundKeyHandler: {
|
|
||||||
type: Function,
|
|
||||||
readonly: true,
|
|
||||||
value: function() { return this._handleKey.bind(this); },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
attached: function() {
|
|
||||||
this.keyEventTarget.addEventListener('keydown', this._boundKeyHandler);
|
|
||||||
},
|
|
||||||
|
|
||||||
detached: function() {
|
|
||||||
this.keyEventTarget.removeEventListener('keydown', this._boundKeyHandler);
|
|
||||||
},
|
|
||||||
|
|
||||||
shouldSuppressKeyboardShortcut: function(e) {
|
shouldSuppressKeyboardShortcut: function(e) {
|
||||||
for (var c in KeyboardShortcutBehavior._disablers) {
|
e = Polymer.dom(e.detail ? e.detail.keyboardEvent : e);
|
||||||
if (KeyboardShortcutBehavior._disablers[c] === true) {
|
if (e.path[0].tagName === 'INPUT' || e.path[0].tagName === 'TEXTAREA') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
for (var i = 0; i < e.path.length; i++) {
|
||||||
|
if (e.path[i].tagName === 'GR-OVERLAY') { return true; }
|
||||||
}
|
}
|
||||||
var getModifierState = e.getModifierState ?
|
return false;
|
||||||
e.getModifierState.bind(e) :
|
|
||||||
function() { return false; };
|
|
||||||
var target = e.detail ? e.detail.keyboardEvent : e.target;
|
|
||||||
return getModifierState('Control') ||
|
|
||||||
getModifierState('Alt') ||
|
|
||||||
getModifierState('Meta') ||
|
|
||||||
getModifierState('Fn') ||
|
|
||||||
target.tagName == 'INPUT' ||
|
|
||||||
target.tagName == 'TEXTAREA' ||
|
|
||||||
target.tagName == 'SELECT' ||
|
|
||||||
target.tagName == 'BUTTON' ||
|
|
||||||
target.tagName == 'A' ||
|
|
||||||
target.tagName == 'GR-BUTTON';
|
|
||||||
},
|
|
||||||
|
|
||||||
disable: function(id) {
|
|
||||||
KeyboardShortcutBehavior._disablers[id] = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
enable: function(id) {
|
|
||||||
delete KeyboardShortcutBehavior._disablers[id];
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
window.Gerrit = window.Gerrit || {};
|
window.Gerrit = window.Gerrit || {};
|
||||||
window.Gerrit.KeyboardShortcutBehavior = KeyboardShortcutBehavior;
|
/** @polymerBehavior Gerrit.KeyboardShortcutBehavior */
|
||||||
|
window.Gerrit.KeyboardShortcutBehavior = [
|
||||||
|
Polymer.IronA11yKeysBehavior,
|
||||||
|
KeyboardShortcutBehaviorImpl,
|
||||||
|
];
|
||||||
})(window);
|
})(window);
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -30,49 +30,76 @@ limitations under the License.
|
|||||||
</template>
|
</template>
|
||||||
</test-fixture>
|
</test-fixture>
|
||||||
|
|
||||||
|
<test-fixture id="within-overlay">
|
||||||
|
<template>
|
||||||
|
<gr-overlay>
|
||||||
|
<test-element></test-element>
|
||||||
|
</gr-overlay>
|
||||||
|
</template>
|
||||||
|
</test-fixture>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
suite('keyboard-shortcut-behavior tests', function() {
|
suite('keyboard-shortcut-behavior tests', function() {
|
||||||
var element;
|
var element;
|
||||||
|
var overlay;
|
||||||
|
|
||||||
suiteSetup(function() {
|
suiteSetup(function() {
|
||||||
// Define a Polymer element that uses this behavior.
|
// Define a Polymer element that uses this behavior.
|
||||||
Polymer({
|
Polymer({
|
||||||
is: 'test-element',
|
is: 'test-element',
|
||||||
behaviors: [Gerrit.KeyboardShortcutBehavior],
|
behaviors: [Gerrit.KeyboardShortcutBehavior],
|
||||||
properties: {
|
keyBindings: {
|
||||||
keyEventTarget: {
|
'k': '_handleKey'
|
||||||
value: function() { return document.body; },
|
|
||||||
},
|
|
||||||
log: {
|
|
||||||
value: function() { return []; },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleKey: function(e) {
|
|
||||||
if (!this.shouldSuppressKeyboardShortcut(e)) {
|
|
||||||
this.log.push(e.keyCode);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
_handleKey: function() {},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
setup(function() {
|
setup(function() {
|
||||||
element = fixture('basic');
|
element = fixture('basic');
|
||||||
|
overlay = fixture('within-overlay');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('blocks keydown events iff one or more disablers', function() {
|
test('doesn’t block kb shortcuts for non-whitelisted els', function(done) {
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 97); // 'a'
|
var divEl = document.createElement('div');
|
||||||
Gerrit.KeyboardShortcutBehavior.enable('x'); // should have no effect
|
element.appendChild(divEl);
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 98); // 'b'
|
element._handleKey = function(e) {
|
||||||
Gerrit.KeyboardShortcutBehavior.disable('x'); // blocking starts here
|
assert.isFalse(element.shouldSuppressKeyboardShortcut(e));
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 99); // 'c'
|
done();
|
||||||
Gerrit.KeyboardShortcutBehavior.disable('y');
|
};
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 100); // 'd'
|
MockInteractions.keyDownOn(divEl, 75, null, 'k');
|
||||||
Gerrit.KeyboardShortcutBehavior.enable('x');
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 101); // 'e'
|
|
||||||
Gerrit.KeyboardShortcutBehavior.enable('y'); // blocking ends here
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 102); // 'f'
|
|
||||||
assert.deepEqual(element.log, [97, 98, 102]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('blocks kb shortcuts for input els', function(done) {
|
||||||
|
var inputEl = document.createElement('input');
|
||||||
|
element.appendChild(inputEl);
|
||||||
|
element._handleKey = function(e) {
|
||||||
|
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
MockInteractions.keyDownOn(inputEl, 75, null, 'k');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('blocks kb shortcuts for textarea els', function(done) {
|
||||||
|
var textareaEl = document.createElement('textarea');
|
||||||
|
element.appendChild(textareaEl);
|
||||||
|
element._handleKey = function(e) {
|
||||||
|
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
MockInteractions.keyDownOn(textareaEl, 75, null, 'k');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('blocks kb shortcuts for anything in a gr-overlay', function(done) {
|
||||||
|
var divEl = document.createElement('div');
|
||||||
|
var element = overlay.querySelector('test-element');
|
||||||
|
element.appendChild(divEl);
|
||||||
|
element._handleKey = function(e) {
|
||||||
|
assert.isTrue(element.shouldSuppressKeyboardShortcut(e));
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
MockInteractions.keyDownOn(divEl, 75, null, 'k');
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -78,6 +78,12 @@
|
|||||||
Gerrit.RESTClientBehavior,
|
Gerrit.RESTClientBehavior,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'j': '_handleJKey',
|
||||||
|
'k': '_handleKKey',
|
||||||
|
'o enter': '_handleEnterKey',
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
this._loadPreferences();
|
this._loadPreferences();
|
||||||
},
|
},
|
||||||
@@ -149,31 +155,37 @@
|
|||||||
account._account_id != change.owner._account_id;
|
account._account_id != change.owner._account_id;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_getAggregateGroupsLen: function(groups) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
groups = groups || [];
|
||||||
|
|
||||||
if (this.groups == null) { return; }
|
|
||||||
var len = 0;
|
var len = 0;
|
||||||
this.groups.forEach(function(group) {
|
this.groups.forEach(function(group) {
|
||||||
len += group.length;
|
len += group.length;
|
||||||
});
|
});
|
||||||
switch (e.keyCode) {
|
return len;
|
||||||
case 74: // 'j'
|
},
|
||||||
|
|
||||||
|
_handleJKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.selectedIndex == len - 1) { return; }
|
var len = this._getAggregateGroupsLen(this.groups);
|
||||||
|
if (this.selectedIndex === len - 1) { return; }
|
||||||
this.selectedIndex += 1;
|
this.selectedIndex += 1;
|
||||||
break;
|
},
|
||||||
case 75: // 'k'
|
|
||||||
|
_handleKKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this.selectedIndex == 0) { return; }
|
if (this.selectedIndex === 0) { return; }
|
||||||
this.selectedIndex -= 1;
|
this.selectedIndex -= 1;
|
||||||
break;
|
},
|
||||||
case 79: // 'o'
|
|
||||||
case 13: // 'enter'
|
_handleEnterKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
page.show(this._changeURLForIndex(this.selectedIndex));
|
page.show(this._changeURLForIndex(this.selectedIndex));
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_changeURLForIndex: function(index) {
|
_changeURLForIndex: function(index) {
|
||||||
|
|||||||
@@ -131,25 +131,25 @@ limitations under the License.
|
|||||||
|
|
||||||
flush(function() {
|
flush(function() {
|
||||||
assert.isTrue(elementItems[0].selected);
|
assert.isTrue(elementItems[0].selected);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
||||||
assert.equal(element.selectedIndex, 1);
|
assert.equal(element.selectedIndex, 1);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
||||||
|
|
||||||
var showStub = sinon.stub(page, 'show');
|
var showStub = sinon.stub(page, 'show');
|
||||||
assert.equal(element.selectedIndex, 2);
|
assert.equal(element.selectedIndex, 2);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
|
MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'enter');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/2/'),
|
assert(showStub.lastCall.calledWithExactly('/c/2/'),
|
||||||
'Should navigate to /c/2/');
|
'Should navigate to /c/2/');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
assert.equal(element.selectedIndex, 1);
|
assert.equal(element.selectedIndex, 1);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'enter'
|
MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'enter');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/1/'),
|
assert(showStub.lastCall.calledWithExactly('/c/1/'),
|
||||||
'Should navigate to /c/1/');
|
'Should navigate to /c/1/');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'k'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
assert.equal(element.selectedIndex, 0);
|
assert.equal(element.selectedIndex, 0);
|
||||||
|
|
||||||
showStub.restore();
|
showStub.restore();
|
||||||
|
|||||||
@@ -110,6 +110,13 @@
|
|||||||
'_paramsAndChangeChanged(params, _change)',
|
'_paramsAndChangeChanged(params, _change)',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'shift+r': '_handleCapitalRKey',
|
||||||
|
'a': '_handleAKey',
|
||||||
|
'd': '_handleDKey',
|
||||||
|
'u': '_handleUKey',
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
this._getLoggedIn().then(function(loggedIn) {
|
this._getLoggedIn().then(function(loggedIn) {
|
||||||
this._loggedIn = loggedIn;
|
this._loggedIn = loggedIn;
|
||||||
@@ -579,30 +586,29 @@
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_handleAKey: function(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
switch (e.keyCode) {
|
if (!this._loggedIn || e.detail.keyboardEvent.shiftKey) { return; }
|
||||||
case 65: // 'a'
|
|
||||||
if (this._loggedIn && !e.shiftKey) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._openReplyDialog();
|
this._openReplyDialog();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 68: // 'd'
|
_handleDKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.downloadOverlay.open();
|
this.$.downloadOverlay.open();
|
||||||
break;
|
},
|
||||||
case 82: // 'r'
|
|
||||||
if (e.shiftKey) {
|
_handleCapitalRKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._switchToMostRecentPatchNum();
|
this._switchToMostRecentPatchNum();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 85: // 'u'
|
_handleUKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._determinePageBack();
|
this._determinePageBack();
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_determinePageBack: function() {
|
_determinePageBack: function() {
|
||||||
|
|||||||
@@ -53,27 +53,27 @@ limitations under the License.
|
|||||||
suite('keyboard shortcuts', function() {
|
suite('keyboard shortcuts', function() {
|
||||||
test('U should navigate to / if no backPage set', function() {
|
test('U should navigate to / if no backPage set', function() {
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'U'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/'));
|
assert(showStub.lastCall.calledWithExactly('/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('U should navigate to backPage if set', function() {
|
test('U should navigate to backPage if set', function() {
|
||||||
element.backPage = '/dashboard/self';
|
element.backPage = '/dashboard/self';
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'U'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/dashboard/self'));
|
assert(showStub.lastCall.calledWithExactly('/dashboard/self'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('A should toggle overlay', function() {
|
test('A should toggle overlay', function() {
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'A'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
var overlayEl = element.$.replyOverlay;
|
var overlayEl = element.$.replyOverlay;
|
||||||
assert.isFalse(overlayEl.opened);
|
assert.isFalse(overlayEl.opened);
|
||||||
element._loggedIn = true;
|
element._loggedIn = true;
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
|
||||||
assert.isFalse(overlayEl.opened);
|
assert.isFalse(overlayEl.opened);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'A'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(overlayEl.opened);
|
assert.isTrue(overlayEl.opened);
|
||||||
overlayEl.close();
|
overlayEl.close();
|
||||||
assert.isFalse(overlayEl.opened);
|
assert.isFalse(overlayEl.opened);
|
||||||
@@ -117,13 +117,12 @@ limitations under the License.
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 'shift + R'
|
MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift', 'r');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 82, 'shift');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('d should open download overlay', function() {
|
test('d should open download overlay', function() {
|
||||||
var stub = sandbox.stub(element.$.downloadOverlay, 'open');
|
var stub = sandbox.stub(element.$.downloadOverlay, 'open');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 68); // 'd'
|
MockInteractions.pressAndReleaseKeyOn(element, 68, null, 'd');
|
||||||
assert.isTrue(stub.called);
|
assert.isTrue(stub.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -179,8 +179,7 @@ limitations under the License.
|
|||||||
<select
|
<select
|
||||||
id="modeSelect"
|
id="modeSelect"
|
||||||
is="gr-select"
|
is="gr-select"
|
||||||
bind-value="{{diffViewMode}}"
|
bind-value="{{diffViewMode}}">
|
||||||
on-change="_handleDropdownChange">
|
|
||||||
<option value="SIDE_BY_SIDE">Side By Side</option>
|
<option value="SIDE_BY_SIDE">Side By Side</option>
|
||||||
<option value="UNIFIED_DIFF">Unified</option>
|
<option value="UNIFIED_DIFF">Unified</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -106,6 +106,22 @@
|
|||||||
Gerrit.URLEncodingBehavior,
|
Gerrit.URLEncodingBehavior,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'shift+left': '_handleShiftLeftKey',
|
||||||
|
'shift+right': '_handleShiftRightKey',
|
||||||
|
'i': '_handleIKey',
|
||||||
|
'shift+i': '_handleCapitalIKey',
|
||||||
|
'down j': '_handleDownKey',
|
||||||
|
'up k': '_handleUpKey',
|
||||||
|
'c': '_handleCKey',
|
||||||
|
'[': '_handleLeftBracketKey',
|
||||||
|
']': '_handleRightBracketKey',
|
||||||
|
'o enter': '_handleEnterKey',
|
||||||
|
'n': '_handleNKey',
|
||||||
|
'p': '_handlePKey',
|
||||||
|
'shift+a': '_handleCapitalAKey',
|
||||||
|
},
|
||||||
|
|
||||||
reload: function() {
|
reload: function() {
|
||||||
if (!this.changeNum || !this.patchRange.patchNum) {
|
if (!this.changeNum || !this.patchRange.patchNum) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
@@ -216,9 +232,6 @@
|
|||||||
this.set(['_shownFiles', i, '__expanded'], true);
|
this.set(['_shownFiles', i, '__expanded'], true);
|
||||||
this.set(['_files', i, '__expanded'], true);
|
this.set(['_files', i, '__expanded'], true);
|
||||||
}
|
}
|
||||||
if (e && e.target) {
|
|
||||||
e.target.blur();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_collapseAllDiffs: function(e) {
|
_collapseAllDiffs: function(e) {
|
||||||
@@ -228,9 +241,6 @@
|
|||||||
this.set(['_files', i, '__expanded'], false);
|
this.set(['_files', i, '__expanded'], false);
|
||||||
}
|
}
|
||||||
this.$.cursor.handleDiffUpdate();
|
this.$.cursor.handleDiffUpdate();
|
||||||
if (e && e.target) {
|
|
||||||
e.target.blur();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeCommentsString: function(comments, patchNum, path) {
|
_computeCommentsString: function(comments, patchNum, path) {
|
||||||
@@ -298,26 +308,26 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_handleShiftLeftKey: function(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
switch (e.keyCode) {
|
if (!this._showInlineDiffs) { return; }
|
||||||
case 37: // left
|
|
||||||
if (e.shiftKey && this._showInlineDiffs) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.cursor.moveLeft();
|
this.$.cursor.moveLeft();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 39: // right
|
_handleShiftRightKey: function(e) {
|
||||||
if (e.shiftKey && this._showInlineDiffs) {
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (!this._showInlineDiffs) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.cursor.moveRight();
|
this.$.cursor.moveRight();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 73: // 'i'
|
_handleIKey: function(e) {
|
||||||
if (e.shiftKey) {
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
if (this.selectedIndex === undefined) { return; }
|
||||||
this._toggleInlineDiffs();
|
|
||||||
} else if (this.selectedIndex !== undefined) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var expanded = this._files[this.selectedIndex].__expanded;
|
var expanded = this._files[this.selectedIndex].__expanded;
|
||||||
// Until Polymer 2.0, manual management of reflection between _files
|
// Until Polymer 2.0, manual management of reflection between _files
|
||||||
@@ -325,10 +335,18 @@
|
|||||||
this.set(['_shownFiles', this.selectedIndex, '__expanded'],
|
this.set(['_shownFiles', this.selectedIndex, '__expanded'],
|
||||||
!expanded);
|
!expanded);
|
||||||
this.set(['_files', this.selectedIndex, '__expanded'], !expanded);
|
this.set(['_files', this.selectedIndex, '__expanded'], !expanded);
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 40: // down
|
_handleCapitalIKey: function(e) {
|
||||||
case 74: // 'j'
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this._toggleInlineDiffs();
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleDownKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this._showInlineDiffs) {
|
if (this._showInlineDiffs) {
|
||||||
this.$.cursor.moveDown();
|
this.$.cursor.moveDown();
|
||||||
@@ -337,9 +355,11 @@
|
|||||||
Math.min(this._numFilesShown, this.selectedIndex + 1);
|
Math.min(this._numFilesShown, this.selectedIndex + 1);
|
||||||
this._scrollToSelectedFile();
|
this._scrollToSelectedFile();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 38: // up
|
|
||||||
case 75: // 'k'
|
_handleUpKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this._showInlineDiffs) {
|
if (this._showInlineDiffs) {
|
||||||
this.$.cursor.moveUp();
|
this.$.cursor.moveUp();
|
||||||
@@ -347,8 +367,11 @@
|
|||||||
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
||||||
this._scrollToSelectedFile();
|
this._scrollToSelectedFile();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 67: // 'c'
|
|
||||||
|
_handleCKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
var isRangeSelected = this.diffs.some(function(diff) {
|
var isRangeSelected = this.diffs.some(function(diff) {
|
||||||
return diff.isRangeSelected();
|
return diff.isRangeSelected();
|
||||||
}, this);
|
}, this);
|
||||||
@@ -356,53 +379,64 @@
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._addDraftAtTarget();
|
this._addDraftAtTarget();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 219: // '['
|
|
||||||
|
_handleLeftBracketKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._openSelectedFile(this._files.length - 1);
|
this._openSelectedFile(this._files.length - 1);
|
||||||
break;
|
},
|
||||||
case 221: // ']'
|
|
||||||
|
_handleRightBracketKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._openSelectedFile(0);
|
this._openSelectedFile(0);
|
||||||
break;
|
},
|
||||||
case 13: // <enter>
|
|
||||||
case 79: // 'o'
|
_handleEnterKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (this._showInlineDiffs) {
|
if (this._showInlineDiffs) {
|
||||||
this._openCursorFile();
|
this._openCursorFile();
|
||||||
} else {
|
} else {
|
||||||
this._openSelectedFile();
|
this._openSelectedFile();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 78: // 'n'
|
|
||||||
if (this._showInlineDiffs) {
|
_handleNKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (!this._showInlineDiffs) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
this.$.cursor.moveToNextCommentThread();
|
this.$.cursor.moveToNextCommentThread();
|
||||||
} else {
|
} else {
|
||||||
this.$.cursor.moveToNextChunk();
|
this.$.cursor.moveToNextChunk();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 80: // 'p'
|
_handlePKey: function(e) {
|
||||||
if (this._showInlineDiffs) {
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (!this._showInlineDiffs) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
this.$.cursor.moveToPreviousCommentThread();
|
this.$.cursor.moveToPreviousCommentThread();
|
||||||
} else {
|
} else {
|
||||||
this.$.cursor.moveToPreviousChunk();
|
this.$.cursor.moveToPreviousChunk();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 65: // 'a'
|
_handleCapitalAKey: function(e) {
|
||||||
if (e.shiftKey) { // Hide left diff.
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._forEachDiff(function(diff) {
|
this._forEachDiff(function(diff) {
|
||||||
diff.toggleLeftDiff();
|
diff.toggleLeftDiff();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_toggleInlineDiffs: function() {
|
_toggleInlineDiffs: function() {
|
||||||
@@ -555,10 +589,6 @@
|
|||||||
return DiffViewMode.SIDE_BY_SIDE;
|
return DiffViewMode.SIDE_BY_SIDE;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleDropdownChange: function(e) {
|
|
||||||
e.target.blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
_fileListActionsVisible: function(numFilesShown, maxFilesForBulkActions) {
|
_fileListActionsVisible: function(numFilesShown, maxFilesForBulkActions) {
|
||||||
return numFilesShown <= maxFilesForBulkActions;
|
return numFilesShown <= maxFilesForBulkActions;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ limitations under the License.
|
|||||||
return [{toggleLeftDiff: toggleLeftDiffStub}];
|
return [{toggleLeftDiff: toggleLeftDiffStub}];
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'A'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
|
||||||
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
||||||
diffsStub.restore();
|
diffsStub.restore();
|
||||||
});
|
});
|
||||||
@@ -168,25 +168,25 @@ limitations under the License.
|
|||||||
assert.isTrue(elementItems[0].hasAttribute('selected'));
|
assert.isTrue(elementItems[0].hasAttribute('selected'));
|
||||||
assert.isFalse(elementItems[1].hasAttribute('selected'));
|
assert.isFalse(elementItems[1].hasAttribute('selected'));
|
||||||
assert.isFalse(elementItems[2].hasAttribute('selected'));
|
assert.isFalse(elementItems[2].hasAttribute('selected'));
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
||||||
assert.equal(element.selectedIndex, 1);
|
assert.equal(element.selectedIndex, 1);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'J'
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
||||||
|
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
assert.equal(element.selectedIndex, 2);
|
assert.equal(element.selectedIndex, 2);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 13); // 'ENTER'
|
MockInteractions.pressAndReleaseKeyOn(element, 13, null, 'enter');
|
||||||
assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
|
assert(showStub.lastCall.calledWith('/c/42/2/myfile.txt'),
|
||||||
'Should navigate to /c/42/2/myfile.txt');
|
'Should navigate to /c/42/2/myfile.txt');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
assert.equal(element.selectedIndex, 1);
|
assert.equal(element.selectedIndex, 1);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 79); // 'O'
|
MockInteractions.pressAndReleaseKeyOn(element, 79, null, 'o');
|
||||||
assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
|
assert(showStub.lastCall.calledWith('/c/42/2/file_added_in_rev2.txt'),
|
||||||
'Should navigate to /c/42/2/file_added_in_rev2.txt');
|
'Should navigate to /c/42/2/file_added_in_rev2.txt');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 75); // 'K'
|
MockInteractions.pressAndReleaseKeyOn(element, 75, null, 'k');
|
||||||
assert.equal(element.selectedIndex, 0);
|
assert.equal(element.selectedIndex, 0);
|
||||||
|
|
||||||
showStub.restore();
|
showStub.restore();
|
||||||
@@ -194,23 +194,23 @@ limitations under the License.
|
|||||||
|
|
||||||
test('i key shows/hides selected inline diff', function() {
|
test('i key shows/hides selected inline diff', function() {
|
||||||
element.selectedIndex = 0;
|
element.selectedIndex = 0;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
assert.isFalse(element.diffs[0].hasAttribute('hidden'));
|
assert.isFalse(element.diffs[0].hasAttribute('hidden'));
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
assert.isTrue(element.diffs[0].hasAttribute('hidden'));
|
assert.isTrue(element.diffs[0].hasAttribute('hidden'));
|
||||||
element.selectedIndex = 1;
|
element.selectedIndex = 1;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 73); // 'I'
|
MockInteractions.pressAndReleaseKeyOn(element, 73, null, 'i');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
assert.isFalse(element.diffs[1].hasAttribute('hidden'));
|
assert.isFalse(element.diffs[1].hasAttribute('hidden'));
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift'); // 'I'
|
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
for (var index in element.diffs) {
|
for (var index in element.diffs) {
|
||||||
assert.isFalse(element.diffs[index].hasAttribute('hidden'));
|
assert.isFalse(element.diffs[index].hasAttribute('hidden'));
|
||||||
}
|
}
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift'); // 'I'
|
MockInteractions.pressAndReleaseKeyOn(element, 73, 'shift', 'i');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
for (var index in element.diffs) {
|
for (var index in element.diffs) {
|
||||||
assert.isTrue(element.diffs[index].hasAttribute('hidden'));
|
assert.isTrue(element.diffs[index].hasAttribute('hidden'));
|
||||||
|
|||||||
@@ -113,17 +113,11 @@
|
|||||||
for (var i = 0; i < messageEls.length; i++) {
|
for (var i = 0; i < messageEls.length; i++) {
|
||||||
messageEls[i].expanded = this._expanded;
|
messageEls[i].expanded = this._expanded;
|
||||||
}
|
}
|
||||||
if (e && e.target) {
|
|
||||||
e.target.blur();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleAutomatedMessageToggleTap: function(e) {
|
_handleAutomatedMessageToggleTap: function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._hideAutomated = !this._hideAutomated;
|
this._hideAutomated = !this._hideAutomated;
|
||||||
if (e && e.target) {
|
|
||||||
e.target.blur();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleScrollTo: function(e) {
|
_handleScrollTo: function(e) {
|
||||||
|
|||||||
@@ -94,6 +94,10 @@
|
|||||||
'searchButton.tap': '_preventDefaultAndNavigateToInputVal',
|
'searchButton.tap': '_preventDefaultAndNavigateToInputVal',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'/': '_handleForwardSlashKey',
|
||||||
|
},
|
||||||
|
|
||||||
properties: {
|
properties: {
|
||||||
value: {
|
value: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -292,18 +296,12 @@
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_handleForwardSlashKey: function(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
switch (e.keyCode) {
|
|
||||||
case 191: // '/' or '?' with shift key.
|
|
||||||
// TODO(andybons): Localization using e.key/keypress event.
|
|
||||||
if (e.shiftKey) { break; }
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var s = this.$.searchInput;
|
this.$.searchInput.focus();
|
||||||
s.focus();
|
this.$.searchInput.selectAll();
|
||||||
s.setSelectionRange(0, s.value.length);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -70,13 +70,15 @@ limitations under the License.
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
element.value = 'test';
|
element.value = 'test';
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13);
|
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13,
|
||||||
|
null, 'enter');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('search query should be double-escaped', function() {
|
test('search query should be double-escaped', function() {
|
||||||
var showStub = sinon.stub(page, 'show');
|
var showStub = sinon.stub(page, 'show');
|
||||||
element.$.searchInput.text = 'fate/stay';
|
element.$.searchInput.text = 'fate/stay';
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13);
|
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13,
|
||||||
|
null, 'enter');
|
||||||
assert.equal(showStub.lastCall.args[0], '/q/fate%252Fstay');
|
assert.equal(showStub.lastCall.args[0], '/q/fate%252Fstay');
|
||||||
showStub.restore();
|
showStub.restore();
|
||||||
});
|
});
|
||||||
@@ -85,7 +87,8 @@ limitations under the License.
|
|||||||
var showStub = sinon.stub(page, 'show');
|
var showStub = sinon.stub(page, 'show');
|
||||||
var blurSpy = sinon.spy(element.$.searchInput.$.input, 'blur');
|
var blurSpy = sinon.spy(element.$.searchInput.$.input, 'blur');
|
||||||
element.$.searchInput.text = 'fate/stay';
|
element.$.searchInput.text = 'fate/stay';
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13);
|
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13,
|
||||||
|
null, 'enter');
|
||||||
assert.isTrue(blurSpy.called);
|
assert.isTrue(blurSpy.called);
|
||||||
showStub.restore();
|
showStub.restore();
|
||||||
blurSpy.restore();
|
blurSpy.restore();
|
||||||
@@ -94,10 +97,19 @@ limitations under the License.
|
|||||||
test('empty search query does not trigger nav', function() {
|
test('empty search query does not trigger nav', function() {
|
||||||
var showSpy = sinon.spy(page, 'show');
|
var showSpy = sinon.spy(page, 'show');
|
||||||
element.value = '';
|
element.value = '';
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13);
|
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13,
|
||||||
|
null, 'enter');
|
||||||
assert.isFalse(showSpy.called);
|
assert.isFalse(showSpy.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('keyboard shortcuts', function() {
|
||||||
|
var focusSpy = sinon.spy(element.$.searchInput, 'focus');
|
||||||
|
var selectAllSpy = sinon.spy(element.$.searchInput, 'selectAll');
|
||||||
|
MockInteractions.pressAndReleaseKeyOn(document.body, 191, null, '/');
|
||||||
|
assert.isTrue(focusSpy.called);
|
||||||
|
assert.isTrue(selectAllSpy.called);
|
||||||
|
});
|
||||||
|
|
||||||
suite('_getSearchSuggestions',
|
suite('_getSearchSuggestions',
|
||||||
function() {
|
function() {
|
||||||
setup(function() {
|
setup(function() {
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
'_commentsChanged(comments.splices)',
|
'_commentsChanged(comments.splices)',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'e shift+e': '_handleEKey',
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
this._getLoggedIn().then(function(loggedIn) {
|
this._getLoggedIn().then(function(loggedIn) {
|
||||||
this._showActions = loggedIn;
|
this._showActions = loggedIn;
|
||||||
@@ -88,12 +92,12 @@
|
|||||||
this._orderedComments = this._sortedComments(this.comments);
|
this._orderedComments = this._sortedComments(this.comments);
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_handleEKey: function(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
if (e.keyCode === 69) { // 'e'
|
|
||||||
e.preventDefault();
|
// Don’t preventDefault in this case because it will render the event
|
||||||
this._expandCollapseComments(e.shiftKey);
|
// useless for other handlers (other gr-diff-comment-thread elements).
|
||||||
}
|
this._expandCollapseComments(e.detail.keyboardEvent.shiftKey);
|
||||||
},
|
},
|
||||||
|
|
||||||
_expandCollapseComments: function(actionIsCollapse) {
|
_expandCollapseComments: function(actionIsCollapse) {
|
||||||
|
|||||||
@@ -280,10 +280,10 @@ limitations under the License.
|
|||||||
}];
|
}];
|
||||||
element.comments = comments;
|
element.comments = comments;
|
||||||
var expandCollapseStub = sinon.stub(element, '_expandCollapseComments');
|
var expandCollapseStub = sinon.stub(element, '_expandCollapseComments');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 69); // 'e'
|
MockInteractions.pressAndReleaseKeyOn(element, 69, null, 'e');
|
||||||
assert.isTrue(expandCollapseStub.lastCall.calledWith(false));
|
assert.isTrue(expandCollapseStub.lastCall.calledWith(false));
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 69, 'shift'); // 'e'
|
MockInteractions.pressAndReleaseKeyOn(element, 69, 'shift', 'e');
|
||||||
assert.isTrue(expandCollapseStub.lastCall.calledWith(true));
|
assert.isTrue(expandCollapseStub.lastCall.calledWith(true));
|
||||||
expandCollapseStub.restore();
|
expandCollapseStub.restore();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -279,34 +279,34 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_handleReply: function(e) {
|
_handleReply: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
this.fire('reply', this._getEventPayload(), {bubbles: false});
|
this.fire('reply', this._getEventPayload(), {bubbles: false});
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleQuote: function(e) {
|
_handleQuote: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
this.fire(
|
this.fire(
|
||||||
'reply', this._getEventPayload({quote: true}), {bubbles: false});
|
'reply', this._getEventPayload({quote: true}), {bubbles: false});
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleDone: function(e) {
|
_handleDone: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
this.fire('done', this._getEventPayload(), {bubbles: false});
|
this.fire('done', this._getEventPayload(), {bubbles: false});
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleEdit: function(e) {
|
_handleEdit: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
this._messageText = this.comment.message;
|
this._messageText = this.comment.message;
|
||||||
this.editing = true;
|
this.editing = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleSave: function(e) {
|
_handleSave: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
this.save();
|
this.save();
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleCancel: function(e) {
|
_handleCancel: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
if (this.comment.message == null || this.comment.message.length == 0) {
|
if (this.comment.message == null || this.comment.message.length == 0) {
|
||||||
this._fireDiscard();
|
this._fireDiscard();
|
||||||
return;
|
return;
|
||||||
@@ -321,7 +321,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_handleDiscard: function(e) {
|
_handleDiscard: function(e) {
|
||||||
this._preventDefaultAndBlur(e);
|
e.preventDefault();
|
||||||
if (!this.comment.__draft) {
|
if (!this.comment.__draft) {
|
||||||
throw Error('Cannot discard a non-draft comment.');
|
throw Error('Cannot discard a non-draft comment.');
|
||||||
}
|
}
|
||||||
@@ -345,11 +345,6 @@
|
|||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
_preventDefaultAndBlur: function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
Polymer.dom(e).rootTarget.blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
_saveDraft: function(draft) {
|
_saveDraft: function(draft) {
|
||||||
return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft);
|
return this.$.restAPI.saveDiffDraft(this.changeNum, this.patchNum, draft);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -217,8 +217,7 @@ limitations under the License.
|
|||||||
id="modeSelect"
|
id="modeSelect"
|
||||||
is="gr-select"
|
is="gr-select"
|
||||||
bind-value="{{changeViewState.diffMode}}"
|
bind-value="{{changeViewState.diffMode}}"
|
||||||
hidden$="[[_computeModeSelectHidden(_isImageDiff)]]"
|
hidden$="[[_computeModeSelectHidden(_isImageDiff)]]">
|
||||||
on-change="_handleDropdownChange">
|
|
||||||
<option value="SIDE_BY_SIDE">Side By Side</option>
|
<option value="SIDE_BY_SIDE">Side By Side</option>
|
||||||
<option value="UNIFIED_DIFF">Unified</option>
|
<option value="UNIFIED_DIFF">Unified</option>
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
@@ -100,6 +100,22 @@
|
|||||||
'_getFiles(_changeNum, _patchRange.*)',
|
'_getFiles(_changeNum, _patchRange.*)',
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'esc': '_handleEscKey',
|
||||||
|
'shift+left': '_handleShiftLeftKey',
|
||||||
|
'shift+right': '_handleShiftRightKey',
|
||||||
|
'up k': '_handleUpKey',
|
||||||
|
'down j': '_handleDownKey',
|
||||||
|
'c': '_handleCKey',
|
||||||
|
'[': '_handleLeftBracketKey',
|
||||||
|
']': '_handleRightBracketKey',
|
||||||
|
'n shift+n': '_handleNKey',
|
||||||
|
'p shift+p': '_handlePKey',
|
||||||
|
'a shift+a': '_handleAKey',
|
||||||
|
'u': '_handleUKey',
|
||||||
|
',': '_handleCommaKey',
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
this._getLoggedIn().then(function(loggedIn) {
|
this._getLoggedIn().then(function(loggedIn) {
|
||||||
this._loggedIn = loggedIn;
|
this._loggedIn = loggedIn;
|
||||||
@@ -185,101 +201,127 @@
|
|||||||
this._patchRange.patchNum, this._path, reviewed);
|
this._patchRange.patchNum, this._path, reviewed);
|
||||||
},
|
},
|
||||||
|
|
||||||
_checkForModifiers: function(e) {
|
_handleEscKey: function(e) {
|
||||||
return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleKey: function(e) {
|
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
switch (e.keyCode) {
|
|
||||||
case 27: // escape
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.diff.displayLine = false;
|
this.$.diff.displayLine = false;
|
||||||
break;
|
},
|
||||||
case 37: // left
|
|
||||||
if (e.shiftKey) {
|
_handleShiftLeftKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.cursor.moveLeft();
|
this.$.cursor.moveLeft();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 39: // right
|
_handleShiftRightKey: function(e) {
|
||||||
if (e.shiftKey) {
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.cursor.moveRight();
|
this.$.cursor.moveRight();
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 40: // down
|
_handleUpKey: function(e) {
|
||||||
case 74: // 'j'
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
e.preventDefault();
|
|
||||||
this.$.diff.displayLine = true;
|
|
||||||
this.$.cursor.moveDown();
|
|
||||||
break;
|
|
||||||
case 38: // up
|
|
||||||
case 75: // 'k'
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.diff.displayLine = true;
|
this.$.diff.displayLine = true;
|
||||||
this.$.cursor.moveUp();
|
this.$.cursor.moveUp();
|
||||||
break;
|
},
|
||||||
case 67: // 'c'
|
|
||||||
if (this._checkForModifiers(e)) { return; }
|
_handleDownKey: function(e) {
|
||||||
if (!this.$.diff.isRangeSelected()) {
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this.$.diff.displayLine = true;
|
||||||
|
this.$.cursor.moveDown();
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleCKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
if (this.$.diff.isRangeSelected()) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var line = this.$.cursor.getTargetLineElement();
|
var line = this.$.cursor.getTargetLineElement();
|
||||||
if (line) {
|
if (line) {
|
||||||
this.$.diff.addDraftAtLine(line);
|
this.$.diff.addDraftAtLine(line);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
break;
|
|
||||||
case 219: // '['
|
_handleLeftBracketKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._navToFile(this._path, this._fileList, -1);
|
this._navToFile(this._path, this._fileList, -1);
|
||||||
break;
|
},
|
||||||
case 221: // ']'
|
|
||||||
|
_handleRightBracketKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._navToFile(this._path, this._fileList, 1);
|
this._navToFile(this._path, this._fileList, 1);
|
||||||
break;
|
},
|
||||||
case 78: // 'n'
|
|
||||||
|
_handleNKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.shiftKey) {
|
if (e.detail.keyboardEvent.shiftKey) {
|
||||||
this.$.cursor.moveToNextCommentThread();
|
this.$.cursor.moveToNextCommentThread();
|
||||||
} else {
|
} else {
|
||||||
this.$.cursor.moveToNextChunk();
|
this.$.cursor.moveToNextChunk();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 80: // 'p'
|
|
||||||
|
_handlePKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (e.shiftKey) {
|
if (e.detail.keyboardEvent.shiftKey) {
|
||||||
this.$.cursor.moveToPreviousCommentThread();
|
this.$.cursor.moveToPreviousCommentThread();
|
||||||
} else {
|
} else {
|
||||||
this.$.cursor.moveToPreviousChunk();
|
this.$.cursor.moveToPreviousChunk();
|
||||||
}
|
}
|
||||||
break;
|
},
|
||||||
case 65: // 'a'
|
|
||||||
if (e.shiftKey) { // Hide left diff.
|
_handleAKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
if (e.detail.keyboardEvent.shiftKey) { // Hide left diff.
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.$.diff.toggleLeftDiff();
|
this.$.diff.toggleLeftDiff();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._loggedIn) { break; }
|
if (!this._loggedIn) { return; }
|
||||||
|
|
||||||
this.set('changeViewState.showReplyDialog', true);
|
this.set('changeViewState.showReplyDialog', true);
|
||||||
/* falls through */ // required by JSHint
|
|
||||||
case 85: // 'u'
|
|
||||||
if (this._changeNum && this._patchRange.patchNum) {
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
this._navToChangeView();
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleUKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this._navToChangeView();
|
||||||
|
},
|
||||||
|
|
||||||
|
_handleCommaKey: function(e) {
|
||||||
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this._openPrefs();
|
||||||
|
},
|
||||||
|
|
||||||
|
_navToChangeView: function() {
|
||||||
|
if (!this._changeNum || !this._patchRange.patchNum) { return; }
|
||||||
|
|
||||||
page.show(this._getChangePath(
|
page.show(this._getChangePath(
|
||||||
this._changeNum,
|
this._changeNum,
|
||||||
this._patchRange,
|
this._patchRange,
|
||||||
this._change && this._change.revisions));
|
this._change && this._change.revisions));
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 188: // ','
|
|
||||||
e.preventDefault();
|
|
||||||
this._openPrefs();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_navToFile: function(path, fileList, direction) {
|
_navToFile: function(path, fileList, direction) {
|
||||||
@@ -556,10 +598,6 @@
|
|||||||
history.replaceState(null, null, '#' + this.$.cursor.getAddress());
|
history.replaceState(null, null, '#' + this.$.cursor.getAddress());
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleDropdownChange: function(e) {
|
|
||||||
e.target.blur();
|
|
||||||
},
|
|
||||||
|
|
||||||
_computeDownloadLink: function(changeNum, patchRange, path) {
|
_computeDownloadLink: function(changeNum, patchRange, path) {
|
||||||
var url = this.changeBaseURL(changeNum, patchRange.patchNum);
|
var url = this.changeBaseURL(changeNum, patchRange.patchNum);
|
||||||
url += '/patch?zip&path=' + encodeURIComponent(path);
|
url += '/patch?zip&path=' + encodeURIComponent(path);
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ limitations under the License.
|
|||||||
|
|
||||||
test('toggle left diff with a hotkey', function() {
|
test('toggle left diff with a hotkey', function() {
|
||||||
var toggleLeftDiffStub = sandbox.stub(element.$.diff, 'toggleLeftDiff');
|
var toggleLeftDiffStub = sandbox.stub(element.$.diff, 'toggleLeftDiff');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift'); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, 'shift', 'a');
|
||||||
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
assert.isTrue(toggleLeftDiffStub.calledOnce);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,29 +82,29 @@ limitations under the License.
|
|||||||
element.changeViewState.selectedFileIndex = 1;
|
element.changeViewState.selectedFileIndex = 1;
|
||||||
|
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'u'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/'),
|
||||||
'Should navigate to /c/42/');
|
'Should navigate to /c/42/');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 221); // ']'
|
MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/10/wheatley.md'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/wheatley.md'),
|
||||||
'Should navigate to /c/42/10/wheatley.md');
|
'Should navigate to /c/42/10/wheatley.md');
|
||||||
element._path = 'wheatley.md';
|
element._path = 'wheatley.md';
|
||||||
assert.equal(element.changeViewState.selectedFileIndex, 2);
|
assert.equal(element.changeViewState.selectedFileIndex, 2);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/10/glados.txt'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/glados.txt'),
|
||||||
'Should navigate to /c/42/10/glados.txt');
|
'Should navigate to /c/42/10/glados.txt');
|
||||||
element._path = 'glados.txt';
|
element._path = 'glados.txt';
|
||||||
assert.equal(element.changeViewState.selectedFileIndex, 1);
|
assert.equal(element.changeViewState.selectedFileIndex, 1);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/10/chell.go'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/10/chell.go'),
|
||||||
'Should navigate to /c/42/10/chell.go');
|
'Should navigate to /c/42/10/chell.go');
|
||||||
element._path = 'chell.go';
|
element._path = 'chell.go';
|
||||||
assert.equal(element.changeViewState.selectedFileIndex, 0);
|
assert.equal(element.changeViewState.selectedFileIndex, 0);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/'),
|
||||||
'Should navigate to /c/42/');
|
'Should navigate to /c/42/');
|
||||||
assert.equal(element.changeViewState.selectedFileIndex, 0);
|
assert.equal(element.changeViewState.selectedFileIndex, 0);
|
||||||
@@ -112,33 +112,33 @@ limitations under the License.
|
|||||||
var showPrefsStub = sandbox.stub(element.$.prefsOverlay, 'open',
|
var showPrefsStub = sandbox.stub(element.$.prefsOverlay, 'open',
|
||||||
function() { return Promise.resolve({}); });
|
function() { return Promise.resolve({}); });
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 188); // ','
|
MockInteractions.pressAndReleaseKeyOn(element, 188, null, ',');
|
||||||
assert(showPrefsStub.calledOnce);
|
assert(showPrefsStub.calledOnce);
|
||||||
|
|
||||||
var scrollStub = sandbox.stub(element.$.cursor, 'moveToNextChunk');
|
var scrollStub = sandbox.stub(element.$.cursor, 'moveToNextChunk');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 78); // 'n'
|
MockInteractions.pressAndReleaseKeyOn(element, 78, null, 'n');
|
||||||
assert(scrollStub.calledOnce);
|
assert(scrollStub.calledOnce);
|
||||||
|
|
||||||
scrollStub = sandbox.stub(element.$.cursor, 'moveToPreviousChunk');
|
scrollStub = sandbox.stub(element.$.cursor, 'moveToPreviousChunk');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 80); // 'p'
|
MockInteractions.pressAndReleaseKeyOn(element, 80, null, 'p');
|
||||||
assert(scrollStub.calledOnce);
|
assert(scrollStub.calledOnce);
|
||||||
|
|
||||||
scrollStub = sandbox.stub(element.$.cursor, 'moveToNextCommentThread');
|
scrollStub = sandbox.stub(element.$.cursor, 'moveToNextCommentThread');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 78, ['shift']); // 'N'
|
MockInteractions.pressAndReleaseKeyOn(element, 78, 'shift', 'n');
|
||||||
assert(scrollStub.calledOnce);
|
assert(scrollStub.calledOnce);
|
||||||
|
|
||||||
scrollStub = sandbox.stub(element.$.cursor,
|
scrollStub = sandbox.stub(element.$.cursor,
|
||||||
'moveToPreviousCommentThread');
|
'moveToPreviousCommentThread');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 80, ['shift']); // 'P'
|
MockInteractions.pressAndReleaseKeyOn(element, 80, 'shift', 'p');
|
||||||
assert(scrollStub.calledOnce);
|
assert(scrollStub.calledOnce);
|
||||||
|
|
||||||
var computeContainerClassStub = sandbox.stub(element.$.diff,
|
var computeContainerClassStub = sandbox.stub(element.$.diff,
|
||||||
'_computeContainerClass');
|
'_computeContainerClass');
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 74); // 'j'
|
MockInteractions.pressAndReleaseKeyOn(element, 74, null, 'j');
|
||||||
assert(computeContainerClassStub.lastCall.calledWithExactly(
|
assert(computeContainerClassStub.lastCall.calledWithExactly(
|
||||||
false, 'SIDE_BY_SIDE', true));
|
false, 'SIDE_BY_SIDE', true));
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 27); // 'escape'
|
MockInteractions.pressAndReleaseKeyOn(element, 27, null, 'esc');
|
||||||
assert(computeContainerClassStub.lastCall.calledWithExactly(
|
assert(computeContainerClassStub.lastCall.calledWithExactly(
|
||||||
false, 'SIDE_BY_SIDE', false));
|
false, 'SIDE_BY_SIDE', false));
|
||||||
});
|
});
|
||||||
@@ -175,39 +175,39 @@ limitations under the License.
|
|||||||
|
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
||||||
'only work when the user is logged in.');
|
'only work when the user is logged in.');
|
||||||
assert.isNull(window.sessionStorage.getItem(
|
assert.isNull(window.sessionStorage.getItem(
|
||||||
'changeView.showReplyDialog'));
|
'changeView.showReplyDialog'));
|
||||||
|
|
||||||
element._loggedIn = true;
|
element._loggedIn = true;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(element.changeViewState.showReplyDialog);
|
assert.isTrue(element.changeViewState.showReplyDialog);
|
||||||
|
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
||||||
'Should navigate to /c/42/5..10');
|
'Should navigate to /c/42/5..10');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'u'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
||||||
'Should navigate to /c/42/5..10');
|
'Should navigate to /c/42/5..10');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 221); // ']'
|
MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/wheatley.md'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/wheatley.md'),
|
||||||
'Should navigate to /c/42/5..10/wheatley.md');
|
'Should navigate to /c/42/5..10/wheatley.md');
|
||||||
element._path = 'wheatley.md';
|
element._path = 'wheatley.md';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/glados.txt'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/glados.txt'),
|
||||||
'Should navigate to /c/42/5..10/glados.txt');
|
'Should navigate to /c/42/5..10/glados.txt');
|
||||||
element._path = 'glados.txt';
|
element._path = 'glados.txt';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/chell.go'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10/chell.go'),
|
||||||
'Should navigate to /c/42/5..10/chell.go');
|
'Should navigate to /c/42/5..10/chell.go');
|
||||||
element._path = 'chell.go';
|
element._path = 'chell.go';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/5..10'),
|
||||||
'Should navigate to /c/42/5..10');
|
'Should navigate to /c/42/5..10');
|
||||||
});
|
});
|
||||||
@@ -229,39 +229,39 @@ limitations under the License.
|
|||||||
|
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
||||||
'only work when the user is logged in.');
|
'only work when the user is logged in.');
|
||||||
assert.isNull(window.sessionStorage.getItem(
|
assert.isNull(window.sessionStorage.getItem(
|
||||||
'changeView.showReplyDialog'));
|
'changeView.showReplyDialog'));
|
||||||
|
|
||||||
element._loggedIn = true;
|
element._loggedIn = true;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(element.changeViewState.showReplyDialog);
|
assert.isTrue(element.changeViewState.showReplyDialog);
|
||||||
|
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'u'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 221); // ']'
|
MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/wheatley.md'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/wheatley.md'),
|
||||||
'Should navigate to /c/42/1/wheatley.md');
|
'Should navigate to /c/42/1/wheatley.md');
|
||||||
element._path = 'wheatley.md';
|
element._path = 'wheatley.md';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/glados.txt'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/glados.txt'),
|
||||||
'Should navigate to /c/42/1/glados.txt');
|
'Should navigate to /c/42/1/glados.txt');
|
||||||
element._path = 'glados.txt';
|
element._path = 'glados.txt';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/chell.go'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/chell.go'),
|
||||||
'Should navigate to /c/42/1/chell.go');
|
'Should navigate to /c/42/1/chell.go');
|
||||||
element._path = 'chell.go';
|
element._path = 'chell.go';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
});
|
});
|
||||||
@@ -278,39 +278,39 @@ limitations under the License.
|
|||||||
|
|
||||||
var showStub = sandbox.stub(page, 'show');
|
var showStub = sandbox.stub(page, 'show');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
assert.isTrue(showStub.notCalled, 'The `a` keyboard shortcut should ' +
|
||||||
'only work when the user is logged in.');
|
'only work when the user is logged in.');
|
||||||
assert.isNull(window.sessionStorage.getItem(
|
assert.isNull(window.sessionStorage.getItem(
|
||||||
'changeView.showReplyDialog'));
|
'changeView.showReplyDialog'));
|
||||||
|
|
||||||
element._loggedIn = true;
|
element._loggedIn = true;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 65); // 'a'
|
MockInteractions.pressAndReleaseKeyOn(element, 65, null, 'a');
|
||||||
assert.isTrue(element.changeViewState.showReplyDialog);
|
assert.isTrue(element.changeViewState.showReplyDialog);
|
||||||
|
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 85); // 'u'
|
MockInteractions.pressAndReleaseKeyOn(element, 85, null, 'u');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 221); // ']'
|
MockInteractions.pressAndReleaseKeyOn(element, 221, null, ']');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/wheatley.md'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/wheatley.md'),
|
||||||
'Should navigate to /c/42/1/wheatley.md');
|
'Should navigate to /c/42/1/wheatley.md');
|
||||||
element._path = 'wheatley.md';
|
element._path = 'wheatley.md';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/glados.txt'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/glados.txt'),
|
||||||
'Should navigate to /c/42/1/glados.txt');
|
'Should navigate to /c/42/1/glados.txt');
|
||||||
element._path = 'glados.txt';
|
element._path = 'glados.txt';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1/chell.go'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1/chell.go'),
|
||||||
'Should navigate to /c/42/1/chell.go');
|
'Should navigate to /c/42/1/chell.go');
|
||||||
element._path = 'chell.go';
|
element._path = 'chell.go';
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element, 219); // '['
|
MockInteractions.pressAndReleaseKeyOn(element, 219, null, '[');
|
||||||
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
assert(showStub.lastCall.calledWithExactly('/c/42/1'),
|
||||||
'Should navigate to /c/42/1');
|
'Should navigate to /c/42/1');
|
||||||
});
|
});
|
||||||
@@ -457,7 +457,6 @@ limitations under the License.
|
|||||||
test('diff mode selector correctly toggles the diff', function() {
|
test('diff mode selector correctly toggles the diff', function() {
|
||||||
var select = element.$.modeSelect;
|
var select = element.$.modeSelect;
|
||||||
var diffDisplay = element.$.diff;
|
var diffDisplay = element.$.diff;
|
||||||
var blurSpy = sandbox.spy(select, 'blur');
|
|
||||||
element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
|
element._userPrefs = {diff_view: 'SIDE_BY_SIDE'};
|
||||||
|
|
||||||
// The mode selected in the view state reflects the selected option.
|
// The mode selected in the view state reflects the selected option.
|
||||||
@@ -477,7 +476,6 @@ limitations under the License.
|
|||||||
assert.equal(element._getDiffViewMode(), newMode);
|
assert.equal(element._getDiffViewMode(), newMode);
|
||||||
assert.equal(element._getDiffViewMode(), select.value);
|
assert.equal(element._getDiffViewMode(), select.value);
|
||||||
assert.equal(element._getDiffViewMode(), diffDisplay.viewMode);
|
assert.equal(element._getDiffViewMode(), diffDisplay.viewMode);
|
||||||
assert(blurSpy.called, 'select should be blurred after selection');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('diff mode selector initializes from preferences', function() {
|
test('diff mode selector initializes from preferences', function() {
|
||||||
@@ -557,14 +555,6 @@ limitations under the License.
|
|||||||
assert.equal(element.$.cursor.side, 'left');
|
assert.equal(element.$.cursor.side, 'left');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('_checkForModifiers', function() {
|
|
||||||
assert.isTrue(element._checkForModifiers({altKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({ctrlKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({metaKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({shiftKey: true}));
|
|
||||||
assert.isFalse(element._checkForModifiers({}));
|
|
||||||
});
|
|
||||||
|
|
||||||
test('_shortenPath with long path should add ellipsis', function() {
|
test('_shortenPath with long path should add ellipsis', function() {
|
||||||
var path =
|
var path =
|
||||||
'level1/level2/level3/level4/file.js';
|
'level1/level2/level3/level4/file.js';
|
||||||
|
|||||||
@@ -51,6 +51,10 @@
|
|||||||
'mousedown': '_handleMouseDown', // See https://crbug.com/gerrit/4767
|
'mousedown': '_handleMouseDown', // See https://crbug.com/gerrit/4767
|
||||||
},
|
},
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'c': '_handleCKey',
|
||||||
|
},
|
||||||
|
|
||||||
placeAbove: function(el) {
|
placeAbove: function(el) {
|
||||||
var rect = this._getTargetBoundingRect(el);
|
var rect = this._getTargetBoundingRect(el);
|
||||||
var boxRect = this.getBoundingClientRect();
|
var boxRect = this.getBoundingClientRect();
|
||||||
@@ -74,17 +78,11 @@
|
|||||||
return rect;
|
return rect;
|
||||||
},
|
},
|
||||||
|
|
||||||
_checkForModifiers: function(e) {
|
_handleCKey: function(e) {
|
||||||
return e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_handleKey: function(e) {
|
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
if (e.keyCode === 67) { // 'c'
|
|
||||||
if (this._checkForModifiers(e)) { return; }
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this._fireCreateComment();
|
this._fireCreateComment();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleMouseDown: function(e) {
|
_handleMouseDown: function(e) {
|
||||||
|
|||||||
@@ -49,12 +49,12 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('ignores regular keys', function() {
|
test('ignores regular keys', function() {
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 27); // 'esc'
|
MockInteractions.pressAndReleaseKeyOn(document.body, 27, null, 'esc');
|
||||||
assert.isFalse(element.fire.called);
|
assert.isFalse(element.fire.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('reacts to hotkey', function() {
|
test('reacts to hotkey', function() {
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 67); // 'c'
|
MockInteractions.pressAndReleaseKeyOn(document.body, 67, null, 'c');
|
||||||
assert.isTrue(element.fire.called);
|
assert.isTrue(element.fire.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ limitations under the License.
|
|||||||
};
|
};
|
||||||
element.side = 'left';
|
element.side = 'left';
|
||||||
element.range = range;
|
element.range = range;
|
||||||
MockInteractions.pressAndReleaseKeyOn(document.body, 67); // 'c'
|
MockInteractions.pressAndReleaseKeyOn(document.body, 67, null, 'c');
|
||||||
assert(element.fire.calledWithExactly(
|
assert(element.fire.calledWithExactly(
|
||||||
'create-comment',
|
'create-comment',
|
||||||
{
|
{
|
||||||
@@ -117,13 +117,5 @@ limitations under the License.
|
|||||||
document.createRange.restore();
|
document.createRange.restore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test('_checkForModifiers', function() {
|
|
||||||
assert.isTrue(element._checkForModifiers({altKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({ctrlKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({metaKey: true}));
|
|
||||||
assert.isTrue(element._checkForModifiers({shiftKey: true}));
|
|
||||||
assert.isFalse(element._checkForModifiers({}));
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -62,6 +62,10 @@
|
|||||||
Gerrit.KeyboardShortcutBehavior,
|
Gerrit.KeyboardShortcutBehavior,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'?': '_showKeyboardShortcuts',
|
||||||
|
},
|
||||||
|
|
||||||
attached: function() {
|
attached: function() {
|
||||||
this.$.restAPI.getAccount().then(function(account) {
|
this.$.restAPI.getAccount().then(function(account) {
|
||||||
this._account = account;
|
this._account = account;
|
||||||
@@ -194,12 +198,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_showKeyboardShortcuts(e) {
|
||||||
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
if (this.shouldSuppressKeyboardShortcut(e)) { return; }
|
||||||
|
|
||||||
if (e.keyCode === 191 && e.shiftKey) { // '/' or '?' with shift key.
|
|
||||||
this.$.keyboardShortcuts.open();
|
this.$.keyboardShortcuts.open();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKeyboardShortcutDialogClose: function() {
|
_handleKeyboardShortcutDialogClose: function() {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||||
|
<link rel="import" href="../../../bower_components/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html">
|
||||||
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
|
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
|
||||||
<link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
|
<link rel="import" href="../../shared/gr-cursor-manager/gr-cursor-manager.html">
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,10 @@
|
|||||||
this.$.input.focus();
|
this.$.input.focus();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
selectAll: function() {
|
||||||
|
this.$.input.setSelectionRange(0, this.$.input.value.length);
|
||||||
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
this.text = '';
|
this.text = '';
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ limitations under the License.
|
|||||||
var cancelHandler = sinon.spy();
|
var cancelHandler = sinon.spy();
|
||||||
element.addEventListener('cancel', cancelHandler);
|
element.addEventListener('cancel', cancelHandler);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 27); // Esc
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc');
|
||||||
assert.isTrue(cancelHandler.called);
|
assert.isTrue(cancelHandler.called);
|
||||||
assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
|
assert.isTrue(element.$.suggestions.hasAttribute('hidden'));
|
||||||
|
|
||||||
@@ -128,19 +128,22 @@ limitations under the License.
|
|||||||
|
|
||||||
assert.equal(element.$.cursor.index, 0);
|
assert.equal(element.$.cursor.index, 0);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40); // Down
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
|
||||||
|
'down');
|
||||||
|
|
||||||
assert.equal(element.$.cursor.index, 1);
|
assert.equal(element.$.cursor.index, 1);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40); // Down
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null,
|
||||||
|
'down');
|
||||||
|
|
||||||
assert.equal(element.$.cursor.index, 2);
|
assert.equal(element.$.cursor.index, 2);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 38); // Up
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 38, null, 'up');
|
||||||
|
|
||||||
assert.equal(element.$.cursor.index, 1);
|
assert.equal(element.$.cursor.index, 1);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13); // Enter
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
|
||||||
|
'enter');
|
||||||
|
|
||||||
assert.equal(element.value, 1);
|
assert.equal(element.value, 1);
|
||||||
assert.isTrue(commitHandler.called);
|
assert.isTrue(commitHandler.called);
|
||||||
@@ -163,7 +166,8 @@ limitations under the License.
|
|||||||
var commitHandler = sinon.spy();
|
var commitHandler = sinon.spy();
|
||||||
element.addEventListener('commit', commitHandler);
|
element.addEventListener('commit', commitHandler);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13); // Enter
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
|
||||||
|
'enter');
|
||||||
|
|
||||||
assert.isTrue(commitHandler.called);
|
assert.isTrue(commitHandler.called);
|
||||||
assert.equal(element.text, 'suggestion');
|
assert.equal(element.text, 'suggestion');
|
||||||
@@ -184,7 +188,8 @@ limitations under the License.
|
|||||||
var commitHandler = sinon.spy();
|
var commitHandler = sinon.spy();
|
||||||
element.addEventListener('commit', commitHandler);
|
element.addEventListener('commit', commitHandler);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13); // Enter
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
|
||||||
|
'enter');
|
||||||
|
|
||||||
assert.isTrue(commitHandler.called);
|
assert.isTrue(commitHandler.called);
|
||||||
assert.equal(element.text, '');
|
assert.equal(element.text, '');
|
||||||
@@ -234,7 +239,8 @@ limitations under the License.
|
|||||||
var commitHandler = sinon.spy();
|
var commitHandler = sinon.spy();
|
||||||
element.addEventListener('commit', commitHandler);
|
element.addEventListener('commit', commitHandler);
|
||||||
|
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13); // Enter
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null,
|
||||||
|
'enter');
|
||||||
|
|
||||||
assert.isTrue(commitHandler.called);
|
assert.isTrue(commitHandler.called);
|
||||||
assert.equal(element.text, 'blah 0');
|
assert.equal(element.text, 'blah 0');
|
||||||
@@ -245,10 +251,10 @@ limitations under the License.
|
|||||||
test('tab key completes only when suggestions exist', function() {
|
test('tab key completes only when suggestions exist', function() {
|
||||||
var commitStub = sinon.stub(element, '_commit');
|
var commitStub = sinon.stub(element, '_commit');
|
||||||
element._suggestions = [];
|
element._suggestions = [];
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9); // tab
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
|
||||||
assert.isFalse(commitStub.called);
|
assert.isFalse(commitStub.called);
|
||||||
element._suggestions = ['tunnel snakes rule!'];
|
element._suggestions = ['tunnel snakes rule!'];
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9); // tab
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
|
||||||
assert.isTrue(commitStub.called);
|
assert.isTrue(commitStub.called);
|
||||||
commitStub.restore();
|
commitStub.restore();
|
||||||
});
|
});
|
||||||
@@ -258,11 +264,11 @@ limitations under the License.
|
|||||||
element.addEventListener('commit', commitHandler);
|
element.addEventListener('commit', commitHandler);
|
||||||
element._suggestions = ['tunnel snakes rule!'];
|
element._suggestions = ['tunnel snakes rule!'];
|
||||||
element.tabCompleteWithoutCommit = true;
|
element.tabCompleteWithoutCommit = true;
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9); // tab
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
|
||||||
assert.isFalse(commitHandler.called);
|
assert.isFalse(commitHandler.called);
|
||||||
element.tabCompleteWithoutCommit = false;
|
element.tabCompleteWithoutCommit = false;
|
||||||
element._suggestions = ['tunnel snakes rule!'];
|
element._suggestions = ['tunnel snakes rule!'];
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9); // tab
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
|
||||||
assert.isTrue(commitHandler.called);
|
assert.isTrue(commitHandler.called);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -301,7 +307,7 @@ limitations under the License.
|
|||||||
test('input-keydown event fired', function() {
|
test('input-keydown event fired', function() {
|
||||||
var listener = sinon.spy();
|
var listener = sinon.spy();
|
||||||
element.addEventListener('input-keydown', listener);
|
element.addEventListener('input-keydown', listener);
|
||||||
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9); // tab
|
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab');
|
||||||
flushAsynchronousOperations();
|
flushAsynchronousOperations();
|
||||||
assert.isTrue(listener.called);
|
assert.isTrue(listener.called);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
tabindex: '0',
|
tabindex: '0',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
keyBindings: {
|
||||||
|
'space enter': '_handleCommitKey',
|
||||||
|
},
|
||||||
|
|
||||||
_disabledChanged: function(disabled) {
|
_disabledChanged: function(disabled) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
this._enabledTabindex = this.getAttribute('tabindex');
|
this._enabledTabindex = this.getAttribute('tabindex');
|
||||||
@@ -46,13 +50,9 @@
|
|||||||
this.setAttribute('tabindex', disabled ? '-1' : this._enabledTabindex);
|
this.setAttribute('tabindex', disabled ? '-1' : this._enabledTabindex);
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleKey: function(e) {
|
_handleCommitKey: function(e) {
|
||||||
switch (e.keyCode) {
|
|
||||||
case 32: // 'spacebar'
|
|
||||||
case 13: // 'enter'
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.click();
|
this.click();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ limitations under the License.
|
|||||||
|
|
||||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||||
<link rel="import" href="../../../bower_components/iron-overlay-behavior/iron-overlay-behavior.html">
|
<link rel="import" href="../../../bower_components/iron-overlay-behavior/iron-overlay-behavior.html">
|
||||||
<link rel="import" href="../../../behaviors/keyboard-shortcut-behavior.html">
|
|
||||||
|
|
||||||
<dom-module id="gr-overlay">
|
<dom-module id="gr-overlay">
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -24,28 +24,13 @@
|
|||||||
Polymer.IronOverlayBehavior,
|
Polymer.IronOverlayBehavior,
|
||||||
],
|
],
|
||||||
|
|
||||||
detached: function() {
|
|
||||||
Gerrit.KeyboardShortcutBehavior.enable(this._id());
|
|
||||||
},
|
|
||||||
|
|
||||||
open: function() {
|
open: function() {
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
Gerrit.KeyboardShortcutBehavior.disable(this._id());
|
|
||||||
Polymer.IronOverlayBehaviorImpl.open.apply(this, arguments);
|
Polymer.IronOverlayBehaviorImpl.open.apply(this, arguments);
|
||||||
this._awaitOpen(resolve);
|
this._awaitOpen(resolve);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
|
|
||||||
close: function() {
|
|
||||||
Gerrit.KeyboardShortcutBehavior.enable(this._id());
|
|
||||||
Polymer.IronOverlayBehaviorImpl.close.apply(this, arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel: function() {
|
|
||||||
Gerrit.KeyboardShortcutBehavior.enable(this._id());
|
|
||||||
Polymer.IronOverlayBehaviorImpl.cancel.apply(this, arguments);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the focus stops that iron-overlay-behavior tries to find.
|
* Override the focus stops that iron-overlay-behavior tries to find.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user