Wyatt Allen 8eba594232 Tidies keyboard shortcut dialogs and updated cursor styles
Reorganizes the keyboard shortcut list for change view with smaller
groups of shortcuts. Also tidies up the dialog for the diff view a bit.

Updates the style for the selected line in the diff view and fixes the
focus when the diff expand/collapse buttons are activated. The scroll
behavior is changed slightly.

Change-Id: I8e520f725f4706aaad6e8bd8b99dd0e274d2f830
2016-05-20 13:43:14 -07:00

289 lines
7.2 KiB
JavaScript

// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
(function() {
'use strict';
var DiffSides = {
LEFT: 'left',
RIGHT: 'right',
};
var DiffViewMode = {
SIDE_BY_SIDE: 'SIDE_BY_SIDE',
UNIFIED: 'UNIFIED_DIFF',
};
var LEFT_SIDE_CLASS = 'target-side-left';
var RIGHT_SIDE_CLASS = 'target-side-right';
Polymer({
is: 'gr-diff-cursor',
properties: {
/**
* Either DiffSides.LEFT or DiffSides.RIGHT.
*/
side: {
type: String,
value: DiffSides.RIGHT,
},
diffRow: {
type: Object,
notify: true,
observer: '_rowChanged',
},
/**
* The diff views to cursor through and listen to.
*/
diffs: {
type: Array,
value: function() {
return [];
},
},
foldOffsetTop: {
type: Number,
value: 0,
},
},
observers: [
'_updateSideClass(side)',
'_diffsChanged(diffs.splices)',
],
moveLeft: function() {
this.side = DiffSides.LEFT;
if (this._isTargetBlank()) {
this.moveUp()
}
},
moveRight: function() {
this.side = DiffSides.RIGHT;
if (this._isTargetBlank()) {
this.moveUp()
}
},
moveDown: function() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
this.$.cursorManager.next(this._rowHasSide.bind(this));
} else {
this.$.cursorManager.next();
}
},
moveUp: function() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
this.$.cursorManager.previous(this._rowHasSide.bind(this));
} else {
this.$.cursorManager.previous();
}
},
moveToNextChunk: function() {
this.$.cursorManager.next(this._isFirstRowOfChunk.bind(this));
this._fixSide();
},
moveToPreviousChunk: function() {
this.$.cursorManager.previous(this._isFirstRowOfChunk.bind(this));
this._fixSide();
},
moveToNextCommentThread: function() {
this.$.cursorManager.next(this._rowHasThread.bind(this));
this._fixSide();
},
moveToPreviousCommentThread: function() {
this.$.cursorManager.previous(this._rowHasThread.bind(this));
this._fixSide();
},
/**
* Get the line number element targeted by the cursor row and side.
* @return {DOMElement}
*/
getTargetLineElement: function() {
var lineElSelector = '.lineNum';
if (!this.diffRow) {
return;
}
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE) {
lineElSelector += this.side === DiffSides.LEFT ? '.left' : '.right';
}
return this.diffRow.querySelector(lineElSelector);
},
getTargetDiffElement: function() {
// Find the parent diff element of the cursor row.
for (var diff = this.diffRow; diff; diff = diff.parentElement) {
if (diff.tagName === 'GR-DIFF') { return diff; }
}
return null;
},
moveToFirstChunk: function() {
this.$.cursorManager.moveToStart();
this.moveToNextChunk();
},
reInitCursor: function() {
this._updateStops();
this.moveToFirstChunk();
},
handleDiffUpdate: function() {
this._updateStops();
if (!this.diffRow) {
this.reInitCursor();
}
},
_getViewMode: function() {
if (!this.diffRow) {
return null;
}
if (this.diffRow.classList.contains('side-by-side')) {
return DiffViewMode.SIDE_BY_SIDE;
} else {
return DiffViewMode.UNIFIED;
}
},
_rowHasSide: function(row) {
var selector = '.content';
selector += this.side === DiffSides.LEFT ? '.left' : '.right';
return row.querySelector(selector);
},
_isFirstRowOfChunk: function(row) {
var parentClassList = row.parentNode.classList;
return parentClassList.contains('section') &&
parentClassList.contains('delta') &&
!row.previousSibling;
},
_rowHasThread: function(row) {
return row.querySelector('gr-diff-comment-thread');
},
/**
* If we jumped to a row where there is no content on the current side then
* switch to the alternate side.
*/
_fixSide: function() {
if (this._getViewMode() === DiffViewMode.SIDE_BY_SIDE &&
this._isTargetBlank()) {
this.side = this.side === DiffSides.LEFT ?
DiffSides.RIGHT : DiffSides.LEFT;
}
},
_isTargetBlank: function() {
if (!this.diffRow) {
return false;
}
var actions = this._getActionsForRow();
return (this.side === DiffSides.LEFT && !actions.left) ||
(this.side === DiffSides.RIGHT && !actions.right);
},
_rowChanged: function(newRow, oldRow) {
if (oldRow) {
oldRow.classList.remove(LEFT_SIDE_CLASS, RIGHT_SIDE_CLASS);
}
this._updateSideClass();
},
_updateSideClass: function() {
if (!this.diffRow) {
return;
}
this.toggleClass(LEFT_SIDE_CLASS, this.side === DiffSides.LEFT,
this.diffRow);
this.toggleClass(RIGHT_SIDE_CLASS, this.side === DiffSides.RIGHT,
this.diffRow);
},
_isActionType: function(type) {
return type !== 'blank' && type !== 'contextControl';
},
_getActionsForRow: function() {
var actions = {left: false, right: false};
if (this.diffRow) {
actions.left = this._isActionType(
this.diffRow.getAttribute('left-type'));
actions.right = this._isActionType(
this.diffRow.getAttribute('right-type'));
}
return actions;
},
_getStops: function() {
return this.diffs.reduce(
function(stops, diff) {
return stops.concat(diff.getCursorStops());
}, []);
},
_updateStops: function() {
this.$.cursorManager.stops = this._getStops();
},
/**
* Setup and tear down on-render listeners for any diffs that are added or
* removed from the cursor.
* @private
*/
_diffsChanged: function(changeRecord) {
if (!changeRecord) { return; }
this._updateStops();
var splice;
var i;
for (var spliceIdx = 0;
changeRecord.indexSplices &&
spliceIdx < changeRecord.indexSplices.length;
spliceIdx++) {
splice = changeRecord.indexSplices[spliceIdx];
for (i = splice.index;
i < splice.index + splice.addedCount;
i++) {
this.listen(this.diffs[i], 'render', 'handleDiffUpdate');
}
for (i = 0;
i < splice.removed && splicee.removed.length;
i++) {
this.unlisten(splice.removed[i], 'render', 'handleDiffUpdate');
}
}
},
});
})();