408 lines
11 KiB
JavaScript
408 lines
11 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 COMMIT_MESSAGE_PATH = '/COMMIT_MSG';
|
||
|
||
Polymer({
|
||
is: 'gr-file-list',
|
||
|
||
properties: {
|
||
patchRange: Object,
|
||
patchNum: String,
|
||
changeNum: String,
|
||
comments: Object,
|
||
drafts: Object,
|
||
revisions: Object,
|
||
projectConfig: Object,
|
||
selectedIndex: {
|
||
type: Number,
|
||
notify: true,
|
||
},
|
||
keyEventTarget: {
|
||
type: Object,
|
||
value: function() { return document.body; },
|
||
},
|
||
change: Object,
|
||
|
||
_files: {
|
||
type: Array,
|
||
observer: '_filesChanged',
|
||
},
|
||
_loggedIn: {
|
||
type: Boolean,
|
||
value: false,
|
||
},
|
||
_reviewed: {
|
||
type: Array,
|
||
value: function() { return []; },
|
||
},
|
||
_diffPrefs: Object,
|
||
_userPrefs: Object,
|
||
_localPrefs: Object,
|
||
_showInlineDiffs: Boolean,
|
||
},
|
||
|
||
behaviors: [
|
||
Gerrit.KeyboardShortcutBehavior,
|
||
],
|
||
|
||
reload: function() {
|
||
if (!this.changeNum || !this.patchRange.patchNum) {
|
||
return Promise.resolve();
|
||
}
|
||
|
||
this._collapseAllDiffs();
|
||
|
||
var promises = [];
|
||
var _this = this;
|
||
|
||
promises.push(this._getFiles().then(function(files) {
|
||
_this._files = files;
|
||
}));
|
||
promises.push(this._getLoggedIn().then(function(loggedIn) {
|
||
return _this._loggedIn = loggedIn;
|
||
}).then(function(loggedIn) {
|
||
if (!loggedIn) { return; }
|
||
|
||
return _this._getReviewedFiles().then(function(reviewed) {
|
||
_this._reviewed = reviewed;
|
||
});
|
||
}));
|
||
|
||
this._localPrefs = this.$.storage.getPreferences();
|
||
promises.push(this._getDiffPreferences().then(function(prefs) {
|
||
this._diffPrefs = prefs;
|
||
}.bind(this)));
|
||
|
||
promises.push(this._getPreferences().then(function(prefs) {
|
||
this._userPrefs = prefs;
|
||
}.bind(this)));
|
||
},
|
||
|
||
get diffs() {
|
||
return Polymer.dom(this.root).querySelectorAll('gr-diff');
|
||
},
|
||
|
||
_getDiffPreferences: function() {
|
||
return this.$.restAPI.getDiffPreferences();
|
||
},
|
||
|
||
_getPreferences: function() {
|
||
return this.$.restAPI.getPreferences();
|
||
},
|
||
|
||
_computePatchSets: function(revisions) {
|
||
var patchNums = [];
|
||
for (var commit in revisions) {
|
||
patchNums.push(revisions[commit]._number);
|
||
}
|
||
return patchNums.sort(function(a, b) { return a - b; });
|
||
},
|
||
|
||
_computePatchSetDisabled: function(patchNum, currentPatchNum) {
|
||
return parseInt(patchNum, 10) >= parseInt(currentPatchNum, 10);
|
||
},
|
||
|
||
_computePatchSetSelected: function(patchNum, basePatchNum) {
|
||
return parseInt(patchNum, 10) === parseInt(basePatchNum, 10);
|
||
},
|
||
|
||
_handlePatchChange: function(e) {
|
||
this.set('patchRange.basePatchNum', Polymer.dom(e).rootTarget.value);
|
||
page.show('/c/' + encodeURIComponent(this.changeNum) + '/' +
|
||
encodeURIComponent(this._patchRangeStr(this.patchRange)));
|
||
},
|
||
|
||
_forEachDiff: function(fn) {
|
||
var diffs = this.diffs;
|
||
for (var i = 0; i < diffs.length; i++) {
|
||
fn(diffs[i]);
|
||
}
|
||
},
|
||
|
||
_expandAllDiffs: function(e) {
|
||
this._showInlineDiffs = true;
|
||
this._forEachDiff(function(diff) {
|
||
diff.hidden = false;
|
||
diff.reload();
|
||
});
|
||
if (e && e.target) {
|
||
e.target.blur();
|
||
}
|
||
},
|
||
|
||
_collapseAllDiffs: function(e) {
|
||
this._showInlineDiffs = false;
|
||
this._forEachDiff(function(diff) {
|
||
diff.hidden = true;
|
||
});
|
||
this.$.cursor.handleDiffUpdate();
|
||
if (e && e.target) {
|
||
e.target.blur();
|
||
}
|
||
},
|
||
|
||
_computeCommentsString: function(comments, patchNum, path) {
|
||
return this._computeCountString(comments, patchNum, path, 'comment');
|
||
},
|
||
|
||
_computeDraftsString: function(drafts, patchNum, path) {
|
||
return this._computeCountString(drafts, patchNum, path, 'draft');
|
||
},
|
||
|
||
_computeCountString: function(comments, patchNum, path, noun) {
|
||
if (!comments) { return ''; }
|
||
|
||
var patchComments = (comments[path] || []).filter(function(c) {
|
||
return parseInt(c.patch_set, 10) === parseInt(patchNum, 10);
|
||
});
|
||
var num = patchComments.length;
|
||
if (num === 0) { return ''; }
|
||
return num + ' ' + noun + (num > 1 ? 's' : '');
|
||
},
|
||
|
||
_computeReviewed: function(file, _reviewed) {
|
||
return _reviewed.indexOf(file.__path) !== -1;
|
||
},
|
||
|
||
_handleReviewedChange: function(e) {
|
||
var path = Polymer.dom(e).rootTarget.getAttribute('data-path');
|
||
var index = this._reviewed.indexOf(path);
|
||
var reviewed = index !== -1;
|
||
if (reviewed) {
|
||
this.splice('_reviewed', index, 1);
|
||
} else {
|
||
this.push('_reviewed', path);
|
||
}
|
||
|
||
this._saveReviewedState(path, !reviewed).catch(function(err) {
|
||
alert('Couldn’t change file review status. Check the console ' +
|
||
'and contact the PolyGerrit team for assistance.');
|
||
throw err;
|
||
}.bind(this));
|
||
},
|
||
|
||
_saveReviewedState: function(path, reviewed) {
|
||
return this.$.restAPI.saveFileReviewed(this.changeNum,
|
||
this.patchRange.patchNum, path, reviewed);
|
||
},
|
||
|
||
_getLoggedIn: function() {
|
||
return this.$.restAPI.getLoggedIn();
|
||
},
|
||
|
||
_getReviewedFiles: function() {
|
||
return this.$.restAPI.getReviewedFiles(this.changeNum,
|
||
this.patchRange.patchNum);
|
||
},
|
||
|
||
_getFiles: function() {
|
||
return this.$.restAPI.getChangeFilesAsSpeciallySortedArray(
|
||
this.changeNum, this.patchRange);
|
||
},
|
||
|
||
_handleKey: function(e) {
|
||
if (this.shouldSupressKeyboardShortcut(e)) { return; }
|
||
|
||
switch (e.keyCode) {
|
||
case 37: // left
|
||
if (e.shiftKey && this._showInlineDiffs) {
|
||
e.preventDefault();
|
||
this.$.cursor.moveLeft();
|
||
}
|
||
break;
|
||
case 39: // right
|
||
if (e.shiftKey && this._showInlineDiffs) {
|
||
e.preventDefault();
|
||
this.$.cursor.moveRight();
|
||
}
|
||
break;
|
||
case 73: // 'i'
|
||
if (!e.shiftKey) { return; }
|
||
e.preventDefault();
|
||
this._toggleInlineDiffs();
|
||
break;
|
||
case 40: // down
|
||
case 74: // 'j'
|
||
e.preventDefault();
|
||
if (this._showInlineDiffs) {
|
||
this.$.cursor.moveDown();
|
||
} else {
|
||
this.selectedIndex =
|
||
Math.min(this._files.length - 1, this.selectedIndex + 1);
|
||
this._scrollToSelectedFile();
|
||
}
|
||
break;
|
||
case 38: // up
|
||
case 75: // 'k'
|
||
e.preventDefault();
|
||
if (this._showInlineDiffs) {
|
||
this.$.cursor.moveUp();
|
||
} else {
|
||
this.selectedIndex = Math.max(0, this.selectedIndex - 1);
|
||
this._scrollToSelectedFile();
|
||
}
|
||
break;
|
||
case 67: // 'c'
|
||
var isRangeSelected = this.diffs.some(function(diff) {
|
||
return diff.isRangeSelected();
|
||
}, this);
|
||
if (this._showInlineDiffs && !isRangeSelected) {
|
||
e.preventDefault();
|
||
this._addDraftAtTarget();
|
||
}
|
||
break;
|
||
case 219: // '['
|
||
e.preventDefault();
|
||
this._openSelectedFile(this._files.length - 1);
|
||
break;
|
||
case 221: // ']'
|
||
e.preventDefault();
|
||
this._openSelectedFile(0);
|
||
break;
|
||
case 13: // <enter>
|
||
case 79: // 'o'
|
||
e.preventDefault();
|
||
if (this._showInlineDiffs) {
|
||
this._openCursorFile();
|
||
} else {
|
||
this._openSelectedFile();
|
||
}
|
||
break;
|
||
case 78: // 'n'
|
||
if (this._showInlineDiffs) {
|
||
e.preventDefault();
|
||
if (e.shiftKey) {
|
||
this.$.cursor.moveToNextCommentThread();
|
||
} else {
|
||
this.$.cursor.moveToNextChunk();
|
||
}
|
||
}
|
||
break;
|
||
case 80: // 'p'
|
||
if (this._showInlineDiffs) {
|
||
e.preventDefault();
|
||
if (e.shiftKey) {
|
||
this.$.cursor.moveToPreviousCommentThread();
|
||
} else {
|
||
this.$.cursor.moveToPreviousChunk();
|
||
}
|
||
}
|
||
break;
|
||
case 65: // 'a'
|
||
if (e.shiftKey) { // Hide left diff.
|
||
e.preventDefault();
|
||
this._forEachDiff(function(diff) {
|
||
diff.toggleLeftDiff();
|
||
});
|
||
}
|
||
break;
|
||
}
|
||
},
|
||
|
||
_toggleInlineDiffs: function() {
|
||
if (this._showInlineDiffs) {
|
||
this._collapseAllDiffs();
|
||
} else {
|
||
this._expandAllDiffs();
|
||
}
|
||
},
|
||
|
||
_openCursorFile: function() {
|
||
var diff = this.$.cursor.getTargetDiffElement();
|
||
page.show(this._computeDiffURL(diff.changeNum, diff.patchRange,
|
||
diff.path));
|
||
},
|
||
|
||
_openSelectedFile: function(opt_index) {
|
||
if (opt_index != null) {
|
||
this.selectedIndex = opt_index;
|
||
}
|
||
page.show(this._computeDiffURL(this.changeNum, this.patchRange,
|
||
this._files[this.selectedIndex].__path));
|
||
},
|
||
|
||
_addDraftAtTarget: function() {
|
||
var diff = this.$.cursor.getTargetDiffElement();
|
||
var target = this.$.cursor.getTargetLineElement();
|
||
if (diff && target) {
|
||
diff.addDraftAtLine(target);
|
||
}
|
||
},
|
||
|
||
_scrollToSelectedFile: function() {
|
||
var el = this.$$('.row[selected]');
|
||
var top = 0;
|
||
for (var node = el; node; node = node.offsetParent) {
|
||
top += node.offsetTop;
|
||
}
|
||
|
||
// Don't scroll if it's already in view.
|
||
if (top > window.pageYOffset &&
|
||
top < window.pageYOffset + window.innerHeight - el.clientHeight) {
|
||
return;
|
||
}
|
||
|
||
window.scrollTo(0, top - document.body.clientHeight / 2);
|
||
},
|
||
|
||
_computeFileSelected: function(index, selectedIndex) {
|
||
return index === selectedIndex;
|
||
},
|
||
|
||
_computeFileStatus: function(status) {
|
||
return status || 'M';
|
||
},
|
||
|
||
_computeDiffURL: function(changeNum, patchRange, path) {
|
||
return '/c/' +
|
||
encodeURIComponent(changeNum) +
|
||
'/' +
|
||
encodeURIComponent(this._patchRangeStr(patchRange)) +
|
||
'/' +
|
||
path;
|
||
},
|
||
|
||
_patchRangeStr: function(patchRange) {
|
||
return patchRange.basePatchNum !== 'PARENT' ?
|
||
patchRange.basePatchNum + '..' + patchRange.patchNum :
|
||
patchRange.patchNum + '';
|
||
},
|
||
|
||
_computeFileDisplayName: function(path) {
|
||
return path === COMMIT_MESSAGE_PATH ? 'Commit message' : path;
|
||
},
|
||
|
||
_computeClass: function(baseClass, path) {
|
||
var classes = [baseClass];
|
||
if (path === COMMIT_MESSAGE_PATH) {
|
||
classes.push('invisible');
|
||
}
|
||
return classes.join(' ');
|
||
},
|
||
|
||
_filesChanged: function() {
|
||
this.async(function() {
|
||
var diffElements = Polymer.dom(this.root).querySelectorAll('gr-diff');
|
||
|
||
// Overwrite the cursor's list of diffs:
|
||
this.$.cursor.splice.apply(this.$.cursor,
|
||
['diffs', 0, this.$.cursor.diffs.length].concat(diffElements));
|
||
}.bind(this), 1);
|
||
},
|
||
});
|
||
})();
|