1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5cr.define('identity_internals', function() {
6  'use strict';
7
8  /**
9   * Creates an identity token item.
10   * @param {!Object} tokenInfo Object containing token information.
11   * @constructor
12   */
13  function TokenListItem(tokenInfo) {
14    var el = cr.doc.createElement('div');
15    el.data_ = tokenInfo;
16    el.__proto__ = TokenListItem.prototype;
17    el.decorate();
18    return el;
19  }
20
21  TokenListItem.prototype = {
22    __proto__: HTMLDivElement.prototype,
23
24    /** @override */
25    decorate: function() {
26      this.textContent = '';
27      this.id = this.data_.accessToken;
28
29      var table = this.ownerDocument.createElement('table');
30      var tbody = this.ownerDocument.createElement('tbody');
31      tbody.appendChild(this.createEntry_(
32          'accessToken', this.data_.accessToken, 'access-token'));
33      tbody.appendChild(this.createEntry_(
34          'extensionName', this.data_.extensionName, 'extension-name'));
35      tbody.appendChild(this.createEntry_(
36          'extensionId', this.data_.extensionId, 'extension-id'));
37      tbody.appendChild(this.createEntry_(
38          'tokenStatus', this.data_.status, 'token-status'));
39      tbody.appendChild(this.createEntry_(
40          'expirationTime', this.data_.expirationTime, 'expiration-time'));
41      tbody.appendChild(this.createEntryForScopes_());
42      table.appendChild(tbody);
43      var tfoot = this.ownerDocument.createElement('tfoot');
44      tfoot.appendChild(this.createButtons_());
45      table.appendChild(tfoot);
46      this.appendChild(table);
47    },
48
49    /**
50     * Creates an entry for a single property of the token.
51     * @param {string} label An i18n label of the token's property name.
52     * @param {string} value A value of the token property.
53     * @param {string} accessor Additional class to tag the field for testing.
54     * @return {HTMLElement} An HTML element with the property name and value.
55     */
56    createEntry_: function(label, value, accessor) {
57      var row = this.ownerDocument.createElement('tr');
58      var labelField = this.ownerDocument.createElement('td');
59      labelField.classList.add('label');
60      labelField.textContent = loadTimeData.getString(label);
61      row.appendChild(labelField);
62      var valueField = this.ownerDocument.createElement('td');
63      valueField.classList.add('value');
64      valueField.classList.add(accessor);
65      valueField.textContent = value;
66      row.appendChild(valueField);
67      return row;
68    },
69
70    /**
71     * Creates an entry for a list of token scopes.
72     * @return {!HTMLElement} An HTML element with scopes.
73     */
74    createEntryForScopes_: function() {
75      var row = this.ownerDocument.createElement('tr');
76      var labelField = this.ownerDocument.createElement('td');
77      labelField.classList.add('label');
78      labelField.textContent = loadTimeData.getString('scopes');
79      row.appendChild(labelField);
80      var valueField = this.ownerDocument.createElement('td');
81      valueField.classList.add('value');
82      valueField.classList.add('scope-list');
83      this.data_.scopes.forEach(function(scope) {
84        valueField.appendChild(this.ownerDocument.createTextNode(scope));
85        valueField.appendChild(this.ownerDocument.createElement('br'));
86      }, this);
87      row.appendChild(valueField);
88      return row;
89    },
90
91    /**
92     * Creates buttons for the token.
93     * @return {HTMLElement} An HTML element with actionable buttons for the
94     *     token.
95     */
96    createButtons_: function() {
97      var row = this.ownerDocument.createElement('tr');
98      var buttonHolder = this.ownerDocument.createElement('td');
99      buttonHolder.colSpan = 2;
100      buttonHolder.classList.add('token-actions');
101      buttonHolder.appendChild(this.createRevokeButton_());
102      row.appendChild(buttonHolder);
103      return row;
104    },
105
106    /**
107     * Creates a revoke button with an event sending a revoke token message
108     * to the controller.
109     * @return {!HTMLButtonElement} The created revoke button.
110     * @private
111     */
112    createRevokeButton_: function() {
113      var revokeButton = this.ownerDocument.createElement('button');
114      revokeButton.classList.add('revoke-button');
115      revokeButton.addEventListener('click', function() {
116        chrome.send('identityInternalsRevokeToken',
117                    [this.data_.extensionId, this.data_.accessToken]);
118      }.bind(this));
119      revokeButton.textContent = loadTimeData.getString('revoke');
120      return revokeButton;
121    },
122  };
123
124  /**
125   * Creates a new list of identity tokens.
126   * @param {Object=} opt_propertyBag Optional properties.
127   * @constructor
128   * @extends {cr.ui.div}
129   */
130  var TokenList = cr.ui.define('div');
131
132  TokenList.prototype = {
133    __proto__: HTMLDivElement.prototype,
134
135    /** @override */
136    decorate: function() {
137      this.textContent = '';
138      this.showTokenNodes_();
139    },
140
141    /**
142     * Populates the list of tokens.
143     */
144    showTokenNodes_: function() {
145      this.data_.forEach(function(tokenInfo) {
146        this.appendChild(new TokenListItem(tokenInfo));
147      }, this);
148    },
149
150    /**
151     * Removes a token node related to the specifed token ID from both the
152     * internals data source as well as the user internface.
153     * @param {string} accessToken The id of the token to remove.
154     * @private
155     */
156    removeTokenNode_: function(accessToken) {
157      var tokenIndex;
158      for (var index = 0; index < this.data_.length; index++) {
159        if (this.data_[index].accessToken == accessToken) {
160          tokenIndex = index;
161          break;
162        }
163      }
164
165      // Remove from the data_ source if token found.
166      if (tokenIndex)
167        this.data_.splice(tokenIndex, 1);
168
169      // Remove from the user interface.
170      var tokenNode = $(accessToken);
171      if (tokenNode)
172        this.removeChild(tokenNode);
173    },
174  };
175
176  var tokenList_;
177
178  /**
179   * Initializes the UI by asking the contoller for list of identity tokens.
180   */
181  function initialize() {
182    chrome.send('identityInternalsGetTokens');
183    tokenList_ = $('token-list');
184    tokenList_.data_ = [];
185    tokenList_.__proto__ = TokenList.prototype;
186    tokenList_.decorate();
187  }
188
189  /**
190   * Callback function accepting a list of tokens to be displayed.
191   * @param {!Token[]} tokens A list of tokens to be displayed
192   */
193  function returnTokens(tokens) {
194    tokenList_.data_ = tokens;
195    tokenList_.showTokenNodes_();
196  }
197
198  /**
199   * Callback function that removes a token from UI once it has been revoked.
200   * @param {!Array.<string>} accessTokens Array with a single element, which is
201   * an access token to be removed.
202   */
203  function tokenRevokeDone(accessTokens) {
204    assert(accessTokens.length > 0);
205    tokenList_.removeTokenNode_(accessTokens[0]);
206  }
207
208  // Return an object with all of the exports.
209  return {
210    initialize: initialize,
211    returnTokens: returnTokens,
212    tokenRevokeDone: tokenRevokeDone,
213  };
214});
215
216document.addEventListener('DOMContentLoaded', identity_internals.initialize);
217