blob: 9af6aa92247727cf0a4bf1d0f98f3dcf5afc66f3 [file] [log] [blame]
// 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';
Polymer({
is: 'gr-change-view',
/**
* Fired when the title of the page should change.
*
* @event title-change
*/
properties: {
/**
* URL params passed from the router.
*/
params: {
type: Object,
observer: '_paramsChanged',
},
viewState: {
type: Object,
notify: true,
value: function() { return {}; },
},
serverConfig: Object,
keyEventTarget: {
type: Object,
value: function() { return document.body; },
},
_comments: Object,
_change: {
type: Object,
observer: '_changeChanged',
},
_commitInfo: Object,
_changeNum: String,
_diffDrafts: Object,
_patchNum: String,
_allPatchSets: {
type: Array,
computed: '_computeAllPatchSets(_change)',
},
_loggedIn: {
type: Boolean,
value: false,
},
_loading: Boolean,
_headerContainerEl: Object,
_headerEl: Object,
_projectConfig: Object,
_boundScrollHandler: {
type: Function,
value: function() { return this._handleBodyScroll.bind(this); },
},
_replyButtonLabel: {
type: String,
value: 'Reply',
computed: '_computeReplyButtonLabel(_diffDrafts)',
},
},
behaviors: [
Gerrit.KeyboardShortcutBehavior,
Gerrit.RESTClientBehavior,
],
ready: function() {
this._headerEl = this.$$('.header');
},
attached: function() {
this._getLoggedIn().then(function(loggedIn) {
this._loggedIn = loggedIn;
}.bind(this));
window.addEventListener('scroll', this._boundScrollHandler);
},
detached: function() {
window.removeEventListener('scroll', this._boundScrollHandler);
},
_handleBodyScroll: function(e) {
var containerEl = this._headerContainerEl ||
this.$$('.headerContainer');
// Calculate where the header is relative to the window.
var top = containerEl.offsetTop;
for (var offsetParent = containerEl.offsetParent;
offsetParent;
offsetParent = offsetParent.offsetParent) {
top += offsetParent.offsetTop;
}
// The element may not be displayed yet, in which case do nothing.
if (top == 0) { return; }
this._headerEl.classList.toggle('pinned', window.scrollY >= top);
},
_resetHeaderEl: function() {
var el = this._headerEl || this.$$('.header');
this._headerEl = el;
el.classList.remove('pinned');
},
_handlePatchChange: function(e) {
var patchNum = e.target.value;
var currentPatchNum =
this._change.revisions[this._change.current_revision]._number;
if (patchNum == currentPatchNum) {
page.show(this.changePath(this._changeNum));
return;
}
page.show(this.changePath(this._changeNum) + '/' + patchNum);
},
_handleReplyTap: function(e) {
e.preventDefault();
this.$.replyOverlay.open();
},
_handleDownloadTap: function(e) {
e.preventDefault();
this.$.downloadOverlay.open();
},
_handleDownloadDialogClose: function(e) {
this.$.downloadOverlay.close();
},
_handleMessageReply: function(e) {
var msg = e.detail.message.message;
var quoteStr = msg.split('\n').map(
function(line) { return '> ' + line; }).join('\n') + '\n\n';
this.$.replyDialog.draft += quoteStr;
this.$.replyOverlay.open();
},
_handleReplyOverlayOpen: function(e) {
this.$.replyDialog.focus();
},
_handleReplySent: function(e) {
this.$.replyOverlay.close();
this._reload();
},
_handleReplyCancel: function(e) {
this.$.replyOverlay.close();
},
_paramsChanged: function(value) {
if (value.view != this.tagName.toLowerCase()) { return; }
this._changeNum = value.changeNum;
this._patchNum = value.patchNum;
if (this.viewState.changeNum != this._changeNum ||
this.viewState.patchNum != this._patchNum) {
this.set('viewState.selectedFileIndex', 0);
this.set('viewState.changeNum', this._changeNum);
this.set('viewState.patchNum', this._patchNum);
}
if (!this._changeNum) {
return;
}
this._reload().then(function() {
this.$.messageList.topMargin = this._headerEl.offsetHeight;
// Allow the message list to render before scrolling.
this.async(function() {
var msgPrefix = '#message-';
var hash = window.location.hash;
if (hash.indexOf(msgPrefix) == 0) {
this.$.messageList.scrollToMessage(hash.substr(msgPrefix.length));
}
}.bind(this), 1);
this._getLoggedIn().then(function(loggedIn) {
if (!loggedIn) { return; }
if (this.viewState.showReplyDialog) {
this.$.replyOverlay.open();
this.set('viewState.showReplyDialog', false);
}
}.bind(this));
}.bind(this));
},
_changeChanged: function(change) {
if (!change) { return; }
this._patchNum = this._patchNum ||
change.revisions[change.current_revision]._number;
var title = change.subject + ' (' + change.change_id.substr(0, 9) + ')';
this.fire('title-change', {title: title});
},
_computeChangePermalink: function(changeNum) {
return '/' + changeNum;
},
_computeChangeStatus: function(change, patchNum) {
var status = change.status;
if (status == this.ChangeStatus.NEW) {
var rev = this._getRevisionNumber(change, patchNum);
// TODO(davido): Figure out, why sometimes revision is not there
if (rev == undefined || !rev.draft) { return ''; }
status = this.ChangeStatus.DRAFT;
}
return '(' + status.toLowerCase() + ')';
},
_computeDetailPath: function(changeNum) {
return '/changes/' + changeNum + '/detail';
},
_computeCommitInfoPath: function(changeNum, patchNum) {
return this.changeBaseURL(changeNum, patchNum) + '/commit?links';
},
_computeCommentsPath: function(changeNum) {
return '/changes/' + changeNum + '/comments';
},
_computeProjectConfigPath: function(project) {
return '/projects/' + encodeURIComponent(project) + '/config';
},
_computeDetailQueryParams: function() {
var options = this.listChangesOptionsToHex(
this.ListChangesOption.ALL_REVISIONS,
this.ListChangesOption.CHANGE_ACTIONS,
this.ListChangesOption.DOWNLOAD_COMMANDS
);
return {O: options};
},
_computeLatestPatchNum: function(change) {
return change.revisions[change.current_revision]._number;
},
_computeAllPatchSets: function(change) {
var patchNums = [];
for (var rev in change.revisions) {
patchNums.push(change.revisions[rev]._number);
}
return patchNums.sort(function(a, b) {
return a - b;
});
},
_getRevisionNumber: function(change, patchNum) {
for (var rev in change.revisions) {
if (change.revisions[rev]._number == patchNum) {
return change.revisions[rev];
}
}
},
_computePatchIndexIsSelected: function(index, patchNum) {
return this._allPatchSets[index] == patchNum;
},
_computeLabelNames: function(labels) {
return Object.keys(labels).sort();
},
_computeLabelValues: function(labelName, labels) {
var result = [];
var t = labels[labelName];
if (!t) { return result; }
var approvals = t.all || [];
approvals.forEach(function(label) {
if (label.value && label.value != labels[labelName].default_value) {
var labelClassName;
var labelValPrefix = '';
if (label.value > 0) {
labelValPrefix = '+';
labelClassName = 'approved';
} else if (label.value < 0) {
labelClassName = 'notApproved';
}
result.push({
value: labelValPrefix + label.value,
className: labelClassName,
account: label,
});
}
});
return result;
},
_computeReplyButtonHighlighted: function(drafts) {
return Object.keys(drafts || {}).length > 0;
},
_computeReplyButtonLabel: function(drafts) {
drafts = drafts || {};
var draftCount = Object.keys(drafts).reduce(function(count, file) {
return count + drafts[file].length;
}, 0);
var label = 'Reply';
if (draftCount > 0) {
label += ' (' + draftCount + ')';
}
return label;
},
_handleKey: function(e) {
if (this.shouldSupressKeyboardShortcut(e)) { return; }
switch (e.keyCode) {
case 65: // 'a'
if (!this._loggedIn) { return; }
e.preventDefault();
this.$.replyOverlay.open();
break;
case 85: // 'u'
e.preventDefault();
page.show('/');
break;
}
},
_handleReloadChange: function() {
page.show(this.changePath(this._changeNum));
},
_getDiffDrafts: function() {
return this.$.restAPI.getDiffDrafts(this._changeNum).then(
function(drafts) { return this._diffDrafts = drafts; }.bind(this));
},
_getLoggedIn: function() {
return this.$.restAPI.getLoggedIn();
},
_reloadDiffDrafts: function() {
this._diffDrafts = {};
this._getDiffDrafts().then(function() {
if (this.$.replyOverlay.opened) {
this.async(function() { this.$.replyOverlay.center(); }, 1);
}
}.bind(this));
},
_reload: function() {
this._getLoggedIn().then(function(loggedIn) {
if (!loggedIn) { return; }
this._reloadDiffDrafts();
}.bind(this));
var detailCompletes = this.$.detailXHR.generateRequest().completes;
this.$.commentsXHR.generateRequest();
var reloadPatchNumDependentResources = function() {
return Promise.all([
this.$.commitInfoXHR.generateRequest().completes,
this.$.actions.reload(),
this.$.fileList.reload(),
]);
}.bind(this);
var reloadDetailDependentResources = function() {
return this.$.relatedChanges.reload();
}.bind(this);
this._resetHeaderEl();
if (this._patchNum) {
return reloadPatchNumDependentResources().then(function() {
return detailCompletes;
}).then(reloadDetailDependentResources);
} else {
// The patch number is reliant on the change detail request.
return detailCompletes.then(reloadPatchNumDependentResources).then(
reloadDetailDependentResources);
}
},
});
})();