| // 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); |
| } |
| }, |
| }); |
| })(); |