blob: f6ecc9ea5357497986fdfcda928e27f0d7a74ffb [file] [log] [blame]
Andrew Bonventre78792e82016-03-04 17:48:22 -05001// Copyright (C) 2016 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14(function() {
15 'use strict';
16
17 Polymer({
18 is: 'gr-change-view',
19
20 /**
21 * Fired when the title of the page should change.
22 *
23 * @event title-change
24 */
25
Andrew Bonventre1c75ceb2016-04-05 13:22:32 -040026 /**
27 * Fired if an error occurs when fetching the change data.
28 *
29 * @event page-error
30 */
31
Andrew Bonventre78792e82016-03-04 17:48:22 -050032 properties: {
33 /**
34 * URL params passed from the router.
35 */
36 params: {
37 type: Object,
38 observer: '_paramsChanged',
39 },
40 viewState: {
41 type: Object,
42 notify: true,
43 value: function() { return {}; },
44 },
beckysiegel8eeedff2016-09-21 16:12:45 -070045 backPage: String,
Andrew Bonventre78792e82016-03-04 17:48:22 -050046 serverConfig: Object,
47 keyEventTarget: {
48 type: Object,
49 value: function() { return document.body; },
50 },
51
52 _comments: Object,
53 _change: {
54 type: Object,
55 observer: '_changeChanged',
56 },
57 _commitInfo: Object,
58 _changeNum: String,
Andrew Bonventre28165262016-05-19 17:24:45 -070059 _diffDrafts: {
60 type: Object,
61 value: function() { return {}; },
62 },
Andrew Bonventrecd768c52016-06-01 17:34:21 -040063 _editingCommitMessage: {
64 type: Boolean,
65 value: false,
66 },
67 _hideEditCommitMessage: {
68 type: Boolean,
69 computed: '_computeHideEditCommitMessage(_loggedIn, ' +
Kasper Nilsson92631b42016-08-30 10:27:23 -070070 '_editingCommitMessage, _change)',
Andrew Bonventred0df1742016-08-23 14:47:39 -040071 },
72 _latestCommitMessage: {
73 type: String,
74 value: '',
Andrew Bonventrecd768c52016-06-01 17:34:21 -040075 },
Andrew Bonventrebf253622016-05-10 15:59:55 -040076 _patchRange: Object,
Andrew Bonventre78792e82016-03-04 17:48:22 -050077 _allPatchSets: {
78 type: Array,
79 computed: '_computeAllPatchSets(_change)',
80 },
81 _loggedIn: {
82 type: Boolean,
83 value: false,
84 },
85 _loading: Boolean,
Andrew Bonventre78792e82016-03-04 17:48:22 -050086 _projectConfig: Object,
Andrew Bonventre015b8042016-03-09 21:04:15 -050087 _replyButtonLabel: {
88 type: String,
89 value: 'Reply',
Andrew Bonventre28165262016-05-19 17:24:45 -070090 computed: '_computeReplyButtonLabel(_diffDrafts.*)',
Andrew Bonventre015b8042016-03-09 21:04:15 -050091 },
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -040092 _initialLoadComplete: {
93 type: Boolean,
94 value: false,
95 },
Andrew Bonventre78792e82016-03-04 17:48:22 -050096 },
97
98 behaviors: [
99 Gerrit.KeyboardShortcutBehavior,
100 Gerrit.RESTClientBehavior,
101 ],
102
Andrew Bonventre5474de82016-06-27 16:34:12 -0400103 observers: [
104 '_labelsChanged(_change.labels.*)',
Wyatt Allen95cb4712016-07-28 15:37:58 -0700105 '_paramsAndChangeChanged(params, _change)',
Andrew Bonventre5474de82016-06-27 16:34:12 -0400106 ],
107
Andrew Bonventre78792e82016-03-04 17:48:22 -0500108 attached: function() {
Andrew Bonventre015b8042016-03-09 21:04:15 -0500109 this._getLoggedIn().then(function(loggedIn) {
110 this._loggedIn = loggedIn;
111 }.bind(this));
112
Andrew Bonventre28165262016-05-19 17:24:45 -0700113 this.addEventListener('comment-save', this._handleCommentSave.bind(this));
114 this.addEventListener('comment-discard',
115 this._handleCommentDiscard.bind(this));
Andrew Bonventrecd768c52016-06-01 17:34:21 -0400116 this.addEventListener('editable-content-save',
117 this._handleCommitMessageSave.bind(this));
118 this.addEventListener('editable-content-cancel',
119 this._handleCommitMessageCancel.bind(this));
beckysiegel8e8fe9c2016-09-19 14:06:15 -0700120 this.listen(window, 'scroll', '_handleScroll');
121 },
122
123 detached: function() {
124 this.unlisten(window, 'scroll', '_handleScroll');
Andrew Bonventre78792e82016-03-04 17:48:22 -0500125 },
126
Andrew Bonventrecd768c52016-06-01 17:34:21 -0400127 _handleEditCommitMessage: function(e) {
128 this._editingCommitMessage = true;
129 this.$.commitMessageEditor.focusTextarea();
130 },
131
132 _handleCommitMessageSave: function(e) {
133 var message = e.detail.content;
134
135 this.$.commitMessageEditor.disabled = true;
136 this._saveCommitMessage(message).then(function(resp) {
137 this.$.commitMessageEditor.disabled = false;
138 if (!resp.ok) { return; }
139
Andrew Bonventred0df1742016-08-23 14:47:39 -0400140 this._latestCommitMessage = message;
Andrew Bonventrecd768c52016-06-01 17:34:21 -0400141 this._editingCommitMessage = false;
142 this._reloadWindow();
143 }.bind(this)).catch(function(err) {
144 this.$.commitMessageEditor.disabled = false;
145 }.bind(this));
146 },
147
148 _reloadWindow: function() {
149 window.location.reload();
150 },
151
152 _handleCommitMessageCancel: function(e) {
153 this._editingCommitMessage = false;
154 },
155
156 _saveCommitMessage: function(message) {
157 return this.$.restAPI.saveChangeCommitMessageEdit(
158 this._changeNum, message).then(function(resp) {
159 if (!resp.ok) { return resp; }
160
161 return this.$.restAPI.publishChangeEdit(this._changeNum);
162 }.bind(this));
163 },
164
Kasper Nilsson92631b42016-08-30 10:27:23 -0700165 _computeHideEditCommitMessage: function(loggedIn, editing, change) {
166 if (!loggedIn || editing || change.status === this.ChangeStatus.MERGED) {
167 return true;
168 }
Andrew Bonventrecd768c52016-06-01 17:34:21 -0400169
170 return false;
171 },
172
Andrew Bonventre28165262016-05-19 17:24:45 -0700173 _handleCommentSave: function(e) {
174 if (!e.target.comment.__draft) { return; }
175
176 var draft = e.target.comment;
177 draft.patch_set = draft.patch_set || this._patchRange.patchNum;
178
179 // The use of path-based notification helpers (set, push) can’t be used
180 // because the paths could contain dots in them. A new object must be
181 // created to satisfy Polymer’s dirty checking.
182 // https://github.com/Polymer/polymer/issues/3127
183 // TODO(andybons): Polyfill for Object.assign in IE.
184 var diffDrafts = Object.assign({}, this._diffDrafts);
185 if (!diffDrafts[draft.path]) {
186 diffDrafts[draft.path] = [draft];
187 this._diffDrafts = diffDrafts;
188 return;
189 }
190 for (var i = 0; i < this._diffDrafts[draft.path].length; i++) {
191 if (this._diffDrafts[draft.path][i].id === draft.id) {
192 diffDrafts[draft.path][i] = draft;
193 this._diffDrafts = diffDrafts;
194 return;
195 }
196 }
197 diffDrafts[draft.path].push(draft);
Andrew Bonventre270e1052016-06-09 16:32:32 -0400198 diffDrafts[draft.path].sort(function(c1, c2) {
199 // No line number means that it’s a file comment. Sort it above the
200 // others.
201 return (c1.line || -1) - (c2.line || -1);
202 });
Andrew Bonventre28165262016-05-19 17:24:45 -0700203 this._diffDrafts = diffDrafts;
204 },
205
206 _handleCommentDiscard: function(e) {
207 if (!e.target.comment.__draft) { return; }
208
209 var draft = e.target.comment;
210 if (!this._diffDrafts[draft.path]) {
211 return;
212 }
213 var index = -1;
214 for (var i = 0; i < this._diffDrafts[draft.path].length; i++) {
215 if (this._diffDrafts[draft.path][i].id === draft.id) {
216 index = i;
217 break;
218 }
219 }
220 if (index === -1) {
Andrew Bonventre861c4a22016-05-31 14:48:25 -0400221 // It may be a draft that hasn’t been added to _diffDrafts since it was
222 // never saved.
223 return;
Andrew Bonventre28165262016-05-19 17:24:45 -0700224 }
225
226 draft.patch_set = draft.patch_set || this._patchRange.patchNum;
227
228 // The use of path-based notification helpers (set, push) can’t be used
229 // because the paths could contain dots in them. A new object must be
230 // created to satisfy Polymer’s dirty checking.
231 // https://github.com/Polymer/polymer/issues/3127
232 // TODO(andybons): Polyfill for Object.assign in IE.
233 var diffDrafts = Object.assign({}, this._diffDrafts);
234 diffDrafts[draft.path].splice(index, 1);
235 if (diffDrafts[draft.path].length === 0) {
236 delete diffDrafts[draft.path];
237 }
238 this._diffDrafts = diffDrafts;
239 },
240
Andrew Bonventre78792e82016-03-04 17:48:22 -0500241 _handlePatchChange: function(e) {
Kasper Nilsson3be0e972016-08-17 17:06:18 -0700242 this._changePatchNum(parseInt(e.target.value, 10));
Andrew Bonventre78792e82016-03-04 17:48:22 -0500243 },
244
245 _handleReplyTap: function(e) {
246 e.preventDefault();
Wyatt Allen165d5d32016-06-07 16:23:29 -0700247 this._openReplyDialog();
Andrew Bonventre78792e82016-03-04 17:48:22 -0500248 },
249
250 _handleDownloadTap: function(e) {
251 e.preventDefault();
Kasper Nilsson7c8c6c12016-10-04 12:35:28 -0700252 this.$.downloadOverlay.open().then(function() {
253 this.$.downloadOverlay
254 .setFocusStops(this.$.downloadDialog.getFocusStops());
255 this.$.downloadDialog.focus();
256 }.bind(this));
Andrew Bonventre78792e82016-03-04 17:48:22 -0500257 },
258
259 _handleDownloadDialogClose: function(e) {
260 this.$.downloadOverlay.close();
261 },
262
263 _handleMessageReply: function(e) {
264 var msg = e.detail.message.message;
265 var quoteStr = msg.split('\n').map(
266 function(line) { return '> ' + line; }).join('\n') + '\n\n';
Becky Siegele108cc02016-09-23 14:32:11 -0700267
268 if (quoteStr !== this.$.replyDialog.quote) {
269 this.$.replyDialog.draft = quoteStr;
270 }
271 this.$.replyDialog.quote = quoteStr;
Wyatt Allen165d5d32016-06-07 16:23:29 -0700272 this._openReplyDialog();
Andrew Bonventre78792e82016-03-04 17:48:22 -0500273 },
274
275 _handleReplyOverlayOpen: function(e) {
Andrew Bonventre78792e82016-03-04 17:48:22 -0500276 this.$.replyDialog.focus();
277 },
278
279 _handleReplySent: function(e) {
280 this.$.replyOverlay.close();
281 this._reload();
282 },
283
284 _handleReplyCancel: function(e) {
285 this.$.replyOverlay.close();
286 },
287
Logan Hanks1cc8f032016-08-12 12:09:47 -0700288 _handleReplyAutogrow: function(e) {
289 this.$.replyOverlay.refit();
290 },
291
Logan Hanksadd2bce2016-07-20 13:22:51 -0700292 _handleShowReplyDialog: function(e) {
Logan Hanksa75fb052016-08-01 13:23:38 -0700293 var target = this.$.replyDialog.FocusTarget.REVIEWERS;
294 if (e.detail.value && e.detail.value.ccsOnly) {
295 target = this.$.replyDialog.FocusTarget.CCS;
296 }
297 this._openReplyDialog(target);
Logan Hanksadd2bce2016-07-20 13:22:51 -0700298 },
299
beckysiegel8e8fe9c2016-09-19 14:06:15 -0700300 _handleScroll: function() {
301 this.debounce('scroll', function() {
302 history.replaceState(
303 {
304 scrollTop: document.body.scrollTop,
305 path: location.pathname,
306 },
307 location.pathname);
308 }, 150);
309 },
310
Andrew Bonventre78792e82016-03-04 17:48:22 -0500311 _paramsChanged: function(value) {
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400312 if (value.view !== this.tagName.toLowerCase()) {
313 this._initialLoadComplete = false;
314 return;
315 }
Andrew Bonventre78792e82016-03-04 17:48:22 -0500316
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400317 var patchChanged = this._patchRange &&
318 (this._patchRange.patchNum !== value.patchNum ||
319 this._patchRange.basePatchNum !== value.basePatchNum);
320
321 if (this._changeNum !== value.changeNum) {
322 this._initialLoadComplete = false;
323 }
324
325 var patchRange = {
Andrew Bonventrebf253622016-05-10 15:59:55 -0400326 patchNum: value.patchNum,
327 basePatchNum: value.basePatchNum || 'PARENT',
328 };
329
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400330 if (this._initialLoadComplete && patchChanged) {
331 if (patchRange.patchNum == null) {
332 patchRange.patchNum = this._computeLatestPatchNum(this._allPatchSets);
333 }
334 this._patchRange = patchRange;
335 this._reloadPatchNumDependentResources().then(function() {
336 this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.SHOW_CHANGE, {
337 change: this._change,
338 patchNum: patchRange.patchNum,
339 });
340 }.bind(this));
341 return;
342 }
343
344 this._changeNum = value.changeNum;
345 this._patchRange = patchRange;
346
Andrew Bonventre78792e82016-03-04 17:48:22 -0500347 this._reload().then(function() {
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400348 this._performPostLoadTasks();
Andrew Bonventre78792e82016-03-04 17:48:22 -0500349 }.bind(this));
350 },
351
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400352 _performPostLoadTasks: function() {
Andrew Bonventrea93721b2016-09-20 16:05:50 -0400353 // Allow the message list and related changes to render before scrolling.
354 // Related changes are loaded here (after everything else) because they
355 // take the longest and are secondary information. Because the element may
356 // alter the total height of the page, the call to potentially scroll to
357 // a linked message is performed after related changes is fully loaded.
358 this.$.relatedChanges.reload().then(function() {
beckysiegel8e8fe9c2016-09-19 14:06:15 -0700359 this.async(function() {
Andrew Bonventrefd434af2016-10-15 20:22:00 -0700360 if (history.state && history.state.scrollTop) {
beckysiegel8e8fe9c2016-09-19 14:06:15 -0700361 document.documentElement.scrollTop =
362 document.body.scrollTop = history.state.scrollTop;
Andrew Bonventrefd434af2016-10-15 20:22:00 -0700363 } else {
364 this._maybeScrollToMessage();
beckysiegel8e8fe9c2016-09-19 14:06:15 -0700365 }
366 }, 1);
Andrew Bonventrea93721b2016-09-20 16:05:50 -0400367 }.bind(this));
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400368
369 this._maybeShowReplyDialog();
370
Ravi Mistrydfc0a362016-10-05 10:27:45 -0400371 this._maybeShowRevertDialog();
372
Andrew Bonventre6f7d4fa2016-09-20 15:52:53 -0400373 this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.SHOW_CHANGE, {
374 change: this._change,
375 patchNum: this._patchRange.patchNum,
376 });
377
378 this._initialLoadComplete = true;
379 },
380
Wyatt Allen95cb4712016-07-28 15:37:58 -0700381 _paramsAndChangeChanged: function(value) {
382 // If the change number or patch range is different, then reset the
383 // selected file index.
384 var patchRangeState = this.viewState.patchRange;
385 if (this.viewState.changeNum !== this._changeNum ||
386 patchRangeState.basePatchNum !== this._patchRange.basePatchNum ||
387 patchRangeState.patchNum !== this._patchRange.patchNum) {
388 this._resetFileListViewState();
389 }
390 },
391
Andrew Bonventre6c37cf72016-05-12 16:15:53 -0400392 _maybeScrollToMessage: function() {
393 var msgPrefix = '#message-';
394 var hash = window.location.hash;
395 if (hash.indexOf(msgPrefix) === 0) {
396 this.$.messageList.scrollToMessage(hash.substr(msgPrefix.length));
397 }
398 },
399
Ravi Mistrydfc0a362016-10-05 10:27:45 -0400400 _getLocationSearch: function() {
401 // Not inlining to make it easier to test.
402 return window.location.search;
403 },
404
405 _getUrlParameter: function(param) {
406 var pageURL = this._getLocationSearch().substring(1);
407 var vars = pageURL.split('&');
408 for (var i = 0; i < vars.length; i++) {
409 var name = vars[i].split('=');
410 if (name[0] == param) {
411 return name[0];
412 }
413 }
414 return null;
415 },
416
417 _maybeShowRevertDialog: function() {
Ravi Mistry0ad5e6c2016-10-10 10:37:20 -0400418 this._getLoggedIn().then(function(loggedIn) {
419 if (!loggedIn || this._change.status !== this.ChangeStatus.MERGED) {
420 // Do not display dialog if not logged-in or the change is not merged.
421 return;
422 }
423 if (!!this._getUrlParameter('revert')) {
424 this.$.actions.showRevertDialog();
425 }
426 }.bind(this));
Ravi Mistrydfc0a362016-10-05 10:27:45 -0400427 },
428
Andrew Bonventre6c37cf72016-05-12 16:15:53 -0400429 _maybeShowReplyDialog: function() {
430 this._getLoggedIn().then(function(loggedIn) {
431 if (!loggedIn) { return; }
432
433 if (this.viewState.showReplyDialog) {
Wyatt Allen165d5d32016-06-07 16:23:29 -0700434 this._openReplyDialog();
Andrew Bonventreca00d3822016-05-20 11:25:35 -0700435 this.async(function() { this.$.replyOverlay.center(); }, 1);
Andrew Bonventre6c37cf72016-05-12 16:15:53 -0400436 this.set('viewState.showReplyDialog', false);
437 }
438 }.bind(this));
439 },
440
Andrew Bonventre91c62932016-05-11 14:31:49 -0400441 _resetFileListViewState: function() {
442 this.set('viewState.selectedFileIndex', 0);
Logan Hanks78ad03c2016-08-25 12:35:50 -0700443 if (!!this.viewState.changeNum &&
444 this.viewState.changeNum !== this._changeNum) {
445 // Reset the diff mode to null when navigating from one change to
446 // another, so that the user's preference is restored.
447 this.set('viewState.diffMode', null);
448 }
Andrew Bonventre91c62932016-05-11 14:31:49 -0400449 this.set('viewState.changeNum', this._changeNum);
450 this.set('viewState.patchRange', this._patchRange);
Andrew Bonventrebf253622016-05-10 15:59:55 -0400451 },
452
Andrew Bonventre78792e82016-03-04 17:48:22 -0500453 _changeChanged: function(change) {
454 if (!change) { return; }
Andrew Bonventrebf253622016-05-10 15:59:55 -0400455 this.set('_patchRange.basePatchNum',
456 this._patchRange.basePatchNum || 'PARENT');
457 this.set('_patchRange.patchNum',
458 this._patchRange.patchNum ||
Urs Wolfer449462c2016-07-13 22:17:18 +0200459 this._computeLatestPatchNum(this._allPatchSets));
Andrew Bonventre78792e82016-03-04 17:48:22 -0500460
461 var title = change.subject + ' (' + change.change_id.substr(0, 9) + ')';
462 this.fire('title-change', {title: title});
463 },
464
Kasper Nilsson3be0e972016-08-17 17:06:18 -0700465 /**
466 * Change active patch to the provided patch num.
467 * @param {int} patchNum the patchn number to be viewed.
468 */
469 _changePatchNum: function(patchNum) {
470 var currentPatchNum;
471 if (this._change.current_revision) {
472 currentPatchNum =
473 this._change.revisions[this._change.current_revision]._number;
474 } else {
475 currentPatchNum = this._computeLatestPatchNum(this._allPatchSets);
476 }
477 if (patchNum === currentPatchNum) {
478 page.show(this.changePath(this._changeNum));
479 return;
480 }
481 page.show(this.changePath(this._changeNum) + '/' + patchNum);
482 },
483
Andrew Bonventre78792e82016-03-04 17:48:22 -0500484 _computeChangePermalink: function(changeNum) {
485 return '/' + changeNum;
486 },
487
Viktar Donich264ef462016-08-08 13:26:48 -0700488 _computeChangeStatus: function(change, patchNum) {
Viktar Donich7bb03b82016-08-08 12:41:50 -0700489 var statusString;
490 if (change.status === this.ChangeStatus.NEW) {
Andrew Bonventre78792e82016-03-04 17:48:22 -0500491 var rev = this._getRevisionNumber(change, patchNum);
Viktar Donich7bb03b82016-08-08 12:41:50 -0700492 if (rev && rev.draft === true) {
493 statusString = 'Draft';
494 }
495 } else {
496 statusString = this.changeStatusString(change);
Andrew Bonventre78792e82016-03-04 17:48:22 -0500497 }
Andrew Bonventred5aa2ff2016-11-01 15:03:41 -0700498 return statusString ? ' (' + statusString + ')' : '';
Andrew Bonventre78792e82016-03-04 17:48:22 -0500499 },
500
Urs Wolfer449462c2016-07-13 22:17:18 +0200501 _computeLatestPatchNum: function(allPatchSets) {
502 return allPatchSets[allPatchSets.length - 1];
Andrew Bonventre78792e82016-03-04 17:48:22 -0500503 },
504
Andrew Bonventre791422a2016-08-25 16:07:15 -0400505 _computePatchInfoClass: function(patchNum, allPatchSets) {
506 if (parseInt(patchNum, 10) ===
507 this._computeLatestPatchNum(allPatchSets)) {
508 return '';
509 }
510 return 'patchInfo--oldPatchSet';
511 },
512
Andrew Bonventre78792e82016-03-04 17:48:22 -0500513 _computeAllPatchSets: function(change) {
514 var patchNums = [];
515 for (var rev in change.revisions) {
516 patchNums.push(change.revisions[rev]._number);
517 }
518 return patchNums.sort(function(a, b) {
519 return a - b;
520 });
521 },
522
523 _getRevisionNumber: function(change, patchNum) {
524 for (var rev in change.revisions) {
525 if (change.revisions[rev]._number == patchNum) {
526 return change.revisions[rev];
527 }
528 }
529 },
530
531 _computePatchIndexIsSelected: function(index, patchNum) {
532 return this._allPatchSets[index] == patchNum;
533 },
534
535 _computeLabelNames: function(labels) {
536 return Object.keys(labels).sort();
537 },
538
539 _computeLabelValues: function(labelName, labels) {
540 var result = [];
541 var t = labels[labelName];
542 if (!t) { return result; }
543 var approvals = t.all || [];
544 approvals.forEach(function(label) {
545 if (label.value && label.value != labels[labelName].default_value) {
546 var labelClassName;
547 var labelValPrefix = '';
548 if (label.value > 0) {
549 labelValPrefix = '+';
550 labelClassName = 'approved';
551 } else if (label.value < 0) {
552 labelClassName = 'notApproved';
553 }
554 result.push({
555 value: labelValPrefix + label.value,
556 className: labelClassName,
557 account: label,
558 });
559 }
560 });
561 return result;
562 },
563
Andrew Bonventre28165262016-05-19 17:24:45 -0700564 _computeReplyButtonLabel: function(changeRecord) {
565 var drafts = (changeRecord && changeRecord.base) || {};
Andrew Bonventre015b8042016-03-09 21:04:15 -0500566 var draftCount = Object.keys(drafts).reduce(function(count, file) {
567 return count + drafts[file].length;
568 }, 0);
569
570 var label = 'Reply';
571 if (draftCount > 0) {
572 label += ' (' + draftCount + ')';
573 }
574 return label;
575 },
576
Kasper Nilsson3be0e972016-08-17 17:06:18 -0700577 _switchToMostRecentPatchNum: function() {
578 this._getChangeDetail().then(function() {
579 var patchNum = this._allPatchSets[this._allPatchSets.length - 1];
580 if (patchNum !== this._patchRange.patchNum) {
581 this._changePatchNum(patchNum);
582 }
583 }.bind(this));
584 },
585
Andrew Bonventre78792e82016-03-04 17:48:22 -0500586 _handleKey: function(e) {
Logan Hanks610f80d2016-10-10 17:10:10 -0700587 if (this.shouldSuppressKeyboardShortcut(e)) { return; }
Andrew Bonventre78792e82016-03-04 17:48:22 -0500588 switch (e.keyCode) {
589 case 65: // 'a'
Viktar Donichc282d7b2016-08-10 11:53:12 -0700590 if (this._loggedIn && !e.shiftKey) {
591 e.preventDefault();
592 this._openReplyDialog();
593 }
Andrew Bonventre78792e82016-03-04 17:48:22 -0500594 break;
Kasper Nilsson057d19c2016-09-08 12:16:04 -0700595 case 68: // 'd'
596 e.preventDefault();
597 this.$.downloadOverlay.open();
598 break;
Kasper Nilsson3be0e972016-08-17 17:06:18 -0700599 case 82: // 'r'
600 if (e.shiftKey) {
601 e.preventDefault();
602 this._switchToMostRecentPatchNum();
603 }
604 break;
Andrew Bonventre78792e82016-03-04 17:48:22 -0500605 case 85: // 'u'
606 e.preventDefault();
beckysiegel8eeedff2016-09-21 16:12:45 -0700607 this._determinePageBack();
Andrew Bonventre78792e82016-03-04 17:48:22 -0500608 break;
609 }
610 },
611
beckysiegel8eeedff2016-09-21 16:12:45 -0700612 _determinePageBack: function() {
613 // Default backPage to '/' if user came to change view page
614 // via an email link, etc.
615 page.show(this.backPage || '/');
616 },
617
Kasper Nilssonf0743732016-10-18 13:01:10 -0700618 _handleLabelRemoved: function(splices, path) {
619 for (var i = 0; i < splices.length; i++) {
620 var splice = splices[i];
621 for (var j = 0; j < splice.removed.length; j++) {
622 var removed = splice.removed[j];
623 var changePath = path.split('.');
624 var labelPath = changePath.splice(0, changePath.length - 2);
625 var labelDict = this.get(labelPath);
626 if (labelDict.approved &&
627 labelDict.approved._account_id === removed._account_id) {
628 this._reload();
629 return;
630 }
631 }
632 }
633 },
634
Andrew Bonventre5474de82016-06-27 16:34:12 -0400635 _labelsChanged: function(changeRecord) {
636 if (!changeRecord) { return; }
Kasper Nilssonf0743732016-10-18 13:01:10 -0700637 if (changeRecord.value.indexSplices) {
638 this._handleLabelRemoved(changeRecord.value.indexSplices,
639 changeRecord.path);
640 }
Andrew Bonventre5474de82016-06-27 16:34:12 -0400641 this.$.jsAPI.handleEvent(this.$.jsAPI.EventType.LABEL_CHANGE, {
642 change: this._change,
643 });
644 },
645
Logan Hanksadd2bce2016-07-20 13:22:51 -0700646 _openReplyDialog: function(opt_section) {
Wyatt Allen165d5d32016-06-07 16:23:29 -0700647 this.$.replyOverlay.open().then(function() {
648 this.$.replyOverlay.setFocusStops(this.$.replyDialog.getFocusStops());
Wyatt Allen4f4b3a72016-07-28 12:05:53 -0700649 this.$.replyDialog.open(opt_section);
Wyatt Allen165d5d32016-06-07 16:23:29 -0700650 }.bind(this));
651 },
652
Andrew Bonventre78792e82016-03-04 17:48:22 -0500653 _handleReloadChange: function() {
Andrew Bonventre924d93f2016-09-21 12:32:01 -0400654 this._reload();
Andrew Bonventre78792e82016-03-04 17:48:22 -0500655 },
656
Andrew Bonventre1c75ceb2016-04-05 13:22:32 -0400657 _handleGetChangeDetailError: function(response) {
658 this.fire('page-error', {response: response});
659 },
660
Andrew Bonventre015b8042016-03-09 21:04:15 -0500661 _getDiffDrafts: function() {
662 return this.$.restAPI.getDiffDrafts(this._changeNum).then(
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400663 function(drafts) {
664 return this._diffDrafts = drafts;
665 }.bind(this));
Andrew Bonventre015b8042016-03-09 21:04:15 -0500666 },
667
668 _getLoggedIn: function() {
669 return this.$.restAPI.getLoggedIn();
670 },
671
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400672 _getProjectConfig: function() {
673 return this.$.restAPI.getProjectConfig(this._change.project).then(
674 function(config) {
675 this._projectConfig = config;
676 }.bind(this));
677 },
678
679 _getChangeDetail: function() {
Andrew Bonventre1c75ceb2016-04-05 13:22:32 -0400680 return this.$.restAPI.getChangeDetail(this._changeNum,
681 this._handleGetChangeDetailError.bind(this)).then(
682 function(change) {
Wyatt Allena3623082016-06-21 15:10:40 -0700683 // Issue 4190: Coalesce missing topics to null.
684 if (!change.topic) { change.topic = null; }
Viktar Donichae365562016-07-27 16:17:17 -0700685 if (!change.reviewer_updates) {
686 change.reviewer_updates = null;
687 }
Andrew Bonventre1c75ceb2016-04-05 13:22:32 -0400688 this._change = change;
689 }.bind(this));
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400690 },
691
692 _getComments: function() {
693 return this.$.restAPI.getDiffComments(this._changeNum).then(
694 function(comments) {
695 this._comments = comments;
696 }.bind(this));
697 },
698
Andrew Bonventred0df1742016-08-23 14:47:39 -0400699 _getLatestCommitMessage: function() {
700 return this.$.restAPI.getChangeCommitInfo(this._changeNum,
701 this._computeLatestPatchNum(this._allPatchSets)).then(
702 function(commitInfo) {
703 this._latestCommitMessage = commitInfo.message;
704 }.bind(this));
705 },
706
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400707 _getCommitInfo: function() {
708 return this.$.restAPI.getChangeCommitInfo(
Andrew Bonventrebf253622016-05-10 15:59:55 -0400709 this._changeNum, this._patchRange.patchNum).then(
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400710 function(commitInfo) {
711 this._commitInfo = commitInfo;
712 }.bind(this));
713 },
714
Andrew Bonventre015b8042016-03-09 21:04:15 -0500715 _reloadDiffDrafts: function() {
716 this._diffDrafts = {};
717 this._getDiffDrafts().then(function() {
718 if (this.$.replyOverlay.opened) {
719 this.async(function() { this.$.replyOverlay.center(); }, 1);
720 }
721 }.bind(this));
722 },
723
Andrew Bonventre78792e82016-03-04 17:48:22 -0500724 _reload: function() {
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400725 this._loading = true;
726
Andrew Bonventre015b8042016-03-09 21:04:15 -0500727 this._getLoggedIn().then(function(loggedIn) {
728 if (!loggedIn) { return; }
729
730 this._reloadDiffDrafts();
731 }.bind(this));
732
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400733 var detailCompletes = this._getChangeDetail().then(function() {
734 this._loading = false;
735 }.bind(this));
736 this._getComments();
Andrew Bonventre015b8042016-03-09 21:04:15 -0500737
Andrew Bonventre47c97242016-09-20 14:20:23 -0400738 if (this._patchRange.patchNum) {
739 return this._reloadPatchNumDependentResources().then(function() {
740 return detailCompletes;
741 }).then(function() {
742 return this._reloadDetailDependentResources();
743 }.bind(this));
744 } else {
745 // The patch number is reliant on the change detail request.
746 return detailCompletes.then(function() {
Andrew Bonventreec8e9dd2016-09-21 15:49:13 -0400747 return this._reloadPatchNumDependentResources();
Andrew Bonventre47c97242016-09-20 14:20:23 -0400748 }.bind(this)).then(function() {
Andrew Bonventreec8e9dd2016-09-21 15:49:13 -0400749 return this._reloadDetailDependentResources();
Andrew Bonventre47c97242016-09-20 14:20:23 -0400750 }.bind(this));
751 }
752 },
Andrew Bonventre1c75ceb2016-04-05 13:22:32 -0400753
Andrew Bonventre47c97242016-09-20 14:20:23 -0400754 /**
755 * Kicks off requests for resources that rely on the change detail
756 * (`this._change`) being loaded.
757 */
758 _reloadDetailDependentResources: function() {
759 if (!this._change) { return Promise.resolve(); }
760
761 return this._getProjectConfig().then(function() {
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400762 return Promise.all([
Andrew Bonventred0df1742016-08-23 14:47:39 -0400763 this._getLatestCommitMessage(),
Andrew Bonventreefd0a532016-08-23 17:04:23 -0400764 this.$.actions.reload(),
Andrew Bonventrec27bdb72016-04-01 20:50:21 -0400765 ]);
Andrew Bonventre47c97242016-09-20 14:20:23 -0400766 }.bind(this));
767 },
Andrew Bonventre78792e82016-03-04 17:48:22 -0500768
Andrew Bonventre47c97242016-09-20 14:20:23 -0400769 /**
770 * Kicks off requests for resources that rely on the patch range
771 * (`this._patchRange`) being defined.
772 */
773 _reloadPatchNumDependentResources: function() {
774 return Promise.all([
775 this._getCommitInfo(),
776 this.$.fileList.reload(),
777 ]);
Andrew Bonventre78792e82016-03-04 17:48:22 -0500778 },
779 });
780})();