// 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-account-list', properties: { accounts: { type: Array, value: function() { return []; }, }, change: Object, filter: Function, placeholder: String, pendingConfirmation: { type: Object, value: null, notify: true, }, readonly: Boolean, }, listeners: { 'remove': '_handleRemove', }, get accountChips() { return Polymer.dom(this.root).querySelectorAll('gr-account-chip'); }, get focusStart() { return this.$.entry.focusStart; }, _handleAdd: function(e) { var reviewer = e.detail.value; // Append new account or group to the accounts property. We add our own // internal properties to the account/group here, so we clone the object // to avoid cluttering up the shared change object. // TODO(logan): Polyfill for Object.assign in IE. if (reviewer.account) { var account = Object.assign({}, reviewer.account, {_pendingAdd: true}); this.push('accounts', account); } else if (reviewer.group) { if (reviewer.confirm) { this.pendingConfirmation = reviewer; return; } var group = Object.assign({}, reviewer.group, {_pendingAdd: true, _group: true}); this.push('accounts', group); } this.pendingConfirmation = null; }, confirmGroup: function(group) { group = Object.assign( {}, group, {confirmed: true, _pendingAdd: true, _group: true}); this.push('accounts', group); this.pendingConfirmation = null; }, _computeChipClass: function(account) { var classes = []; if (account._group) { classes.push('group'); } if (account._pendingAdd) { classes.push('pendingAdd'); } return classes.join(' '); }, _computeRemovable: function(account) { return !this.readonly && !!account._pendingAdd; }, _handleRemove: function(e) { var toRemove = e.detail.account; this._removeAccount(toRemove); this.$.entry.focus(); }, _removeAccount: function(toRemove) { if (!toRemove || !this._computeRemovable(toRemove)) { return; } for (var i = 0; i < this.accounts.length; i++) { var matches; var account = this.accounts[i]; if (toRemove._group) { matches = toRemove.id === account.id; } else { matches = toRemove._account_id === account._account_id; } if (matches) { this.splice('accounts', i, 1); return; } } console.warn('received remove event for missing account', toRemove); }, _handleInputKeydown: function(e) { var input = e.detail.input; if (input.selectionStart !== input.selectionEnd || input.selectionStart !== 0) { return; } switch (e.detail.keyCode) { case 8: // Backspace this._removeAccount(this.accounts[this.accounts.length - 1]); break; case 37: // Left arrow var chips = this.accountChips; if (chips[chips.length - 1]) { chips[chips.length - 1].focus(); } break; } }, _handleChipKeydown: function(e) { var chip = e.target; var chips = this.accountChips; var index = chips.indexOf(chip); switch (e.keyCode) { case 8: // Backspace case 13: // Enter case 32: // Spacebar case 46: // Delete this._removeAccount(chip.account); // Splice from this array to avoid inconsistent ordering of // event handling. chips.splice(index, 1); if (index < chips.length) { chips[index].focus(); } else if (index > 0) { chips[index - 1].focus(); } else { this.$.entry.focus(); } break; case 37: // Left arrow if (index > 0) { chip.blur(); chips[index - 1].focus(); } break; case 39: // Right arrow chip.blur(); if (index < chips.length - 1) { chips[index + 1].focus(); } else { this.$.entry.focus(); } break; } }, additions: function() { return this.accounts.filter(function(account) { return account._pendingAdd; }).map(function(account) { if (account._group) { return {group: account}; } else { return {account: account}; } }); }, }); })();