blob: de990393632a0f88c47a93999b0f858037043864 [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-reviewer-list',
properties: {
change: Object,
mutable: {
type: Boolean,
value: false,
},
disabled: {
type: Boolean,
value: false,
reflectToAttribute: true,
},
suggestFrom: {
type: Number,
value: 3,
},
_reviewers: {
type: Array,
value: function() { return []; },
},
_autocompleteData: {
type: Array,
value: function() { return []; },
observer: '_autocompleteDataChanged',
},
_inputVal: {
type: String,
value: '',
observer: '_inputValChanged',
},
_inputRequestHandle: Number,
_inputRequestTimeout: {
type: Number,
value: 250,
},
_showInput: {
type: Boolean,
value: false,
},
_hideAutocomplete: {
type: Boolean,
value: true,
observer: '_hideAutocompleteChanged',
},
_selectedIndex: {
type: Number,
value: 0,
},
_boundBodyClickHandler: {
type: Function,
value: function() {
return this._handleBodyClick.bind(this);
},
},
// Used for testing.
_lastAutocompleteRequest: Object,
_xhrPromise: Object,
},
behaviors: [
Gerrit.KeyboardShortcutBehavior,
],
observers: [
'_reviewersChanged(change.reviewers.*, change.owner)',
],
detached: function() {
this._clearInputRequestHandle();
},
_clearInputRequestHandle: function() {
if (this._inputRequestHandle != null) {
this.cancelAsync(this._inputRequestHandle);
this._inputRequestHandle = null;
}
},
_reviewersChanged: function(changeRecord, owner) {
var result = [];
var reviewers = changeRecord.base;
for (var key in reviewers) {
if (key == 'REVIEWER' || key == 'CC') {
result = result.concat(reviewers[key]);
}
}
this._reviewers = result.filter(function(reviewer) {
return reviewer._account_id != owner._account_id;
});
},
_computeCanRemoveReviewer: function(reviewer, mutable) {
if (!mutable) { return false; }
for (var i = 0; i < this.change.removable_reviewers.length; i++) {
if (this.change.removable_reviewers[i]._account_id ==
reviewer._account_id) {
return true;
}
}
return false;
},
_computeSelected: function(index, selectedIndex) {
return index == selectedIndex;
},
_handleBodyClick: function(e) {
var eventPath = Polymer.dom(e).path;
for (var i = 0; i < eventPath.length; i++) {
if (eventPath[i] == this) {
return;
}
}
this._selectedIndex = -1;
this._autocompleteData = [];
},
_handleRemove: function(e) {
e.preventDefault();
var target = Polymer.dom(e).rootTarget;
var accountID = parseInt(target.getAttribute('data-account-id'), 10);
this.disabled = true;
this._xhrPromise =
this._removeReviewer(accountID).then(function(response) {
this.disabled = false;
if (!response.ok) { return response; }
var reviewers = this.change.reviewers;
['REVIEWER', 'CC'].forEach(function(type) {
reviewers[type] = reviewers[type] || [];
for (var i = 0; i < reviewers[type].length; i++) {
if (reviewers[type][i]._account_id == accountID) {
this.splice('change.reviewers.' + type, i, 1);
break;
}
}
}, this);
}.bind(this)).catch(function(err) {
this.disabled = false;
throw err;
}.bind(this));
},
_handleAddTap: function(e) {
e.preventDefault();
this._showInput = true;
this.$.input.focus();
},
_handleCancelTap: function(e) {
e.preventDefault();
this._cancel();
},
_handleMouseEnterItem: function(e) {
this._selectedIndex =
parseInt(Polymer.dom(e).rootTarget.getAttribute('data-index'), 10);
},
_handleItemTap: function(e) {
var reviewerEl;
var eventPath = Polymer.dom(e).path;
for (var i = 0; i < eventPath.length; i++) {
var el = eventPath[i];
if (el.classList && el.classList.contains('reviewer')) {
reviewerEl = el;
break;
}
}
this._selectedIndex =
parseInt(reviewerEl.getAttribute('data-index'), 10);
this._sendAddRequest();
},
_autocompleteDataChanged: function(data) {
this._hideAutocomplete = data.length == 0;
},
_hideAutocompleteChanged: function(hidden) {
if (hidden) {
document.body.removeEventListener('click',
this._boundBodyClickHandler);
this._selectedIndex = -1;
} else {
document.body.addEventListener('click', this._boundBodyClickHandler);
this._selectedIndex = 0;
}
},
_inputValChanged: function(val) {
var sendRequest = function() {
if (this.disabled || val == null || val.trim().length == 0) {
return;
}
if (val.length < this.suggestFrom) {
this._clearInputRequestHandle();
this._hideAutocomplete = true;
this._selectedIndex = -1;
return;
}
this._lastAutocompleteRequest =
this._getSuggestedReviewers(this.change._number, val).then(
this._handleReviewersResponse.bind(this));
}.bind(this);
this._clearInputRequestHandle();
if (this._inputRequestTimeout == 0) {
sendRequest();
} else {
this._inputRequestHandle =
this.async(sendRequest, this._inputRequestTimeout);
}
},
_handleReviewersResponse: function(response) {
this._autocompleteData = response.filter(function(reviewer) {
var account = reviewer.account;
if (!account) { return true; }
for (var i = 0; i < this._reviewers.length; i++) {
if (account._account_id == this.change.owner._account_id ||
account._account_id == this._reviewers[i]._account_id) {
return false;
}
}
return true;
}, this);
},
_getSuggestedReviewers: function(changeNum, inputVal) {
return this.$.restAPI.getChangeSuggestedReviewers(changeNum, inputVal);
},
_handleKey: function(e) {
if (this._hideAutocomplete) {
if (e.keyCode == 27) { // 'esc'
e.preventDefault();
this._cancel();
}
return;
}
switch (e.keyCode) {
case 38: // 'up':
e.preventDefault();
this._selectedIndex = Math.max(this._selectedIndex - 1, 0);
break;
case 40: // 'down'
e.preventDefault();
this._selectedIndex = Math.min(this._selectedIndex + 1,
this._autocompleteData.length - 1);
break;
case 27: // 'esc'
e.preventDefault();
this._hideAutocomplete = true;
break;
case 13: // 'enter'
e.preventDefault();
this._sendAddRequest();
break;
}
},
_cancel: function() {
this._showInput = false;
this._selectedIndex = 0;
this._inputVal = '';
this._autocompleteData = [];
this.$.addReviewer.focus();
},
_sendAddRequest: function() {
this._clearInputRequestHandle();
var reviewerID;
var reviewer = this._autocompleteData[this._selectedIndex];
if (reviewer.account) {
reviewerID = reviewer.account._account_id;
} else if (reviewer.group) {
reviewerID = reviewer.group.id;
}
this._autocompleteData = [];
this.disabled = true;
this._xhrPromise = this._addReviewer(reviewerID).then(function(response) {
this.change.reviewers['CC'] = this.change.reviewers['CC'] || [];
this.disabled = false;
if (!response.ok) { return response; }
return this.$.restAPI.getResponseObject(response).then(function(obj) {
obj.reviewers.forEach(function(r) {
this.push('change.removable_reviewers', r);
this.push('change.reviewers.CC', r);
}, this);
this._inputVal = '';
this.$.input.focus();
}.bind(this));
}.bind(this)).catch(function(err) {
this.disabled = false;
throw err;
}.bind(this));
},
_addReviewer: function(id) {
return this.$.restAPI.addChangeReviewer(this.change._number, id);
},
_removeReviewer: function(id) {
return this.$.restAPI.removeChangeReviewer(this.change._number, id);
},
});
})();