Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(39)

Side by Side Diff: chrome/browser/resources/extensions/extension_list.js

Issue 1049483003: [Extensions] Update extensions UI to observe events and add test (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Dan's Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 <include src="extension_error.js"> 5 <include src="extension_error.js">
6 6
7 /////////////////////////////////////////////////////////////////////////////// 7 ///////////////////////////////////////////////////////////////////////////////
8 // ExtensionFocusRow: 8 // ExtensionFocusRow:
9 9
10 /** 10 /**
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 'use strict'; 139 'use strict';
140 140
141 /** 141 /**
142 * Creates a new list of extensions. 142 * Creates a new list of extensions.
143 * @constructor 143 * @constructor
144 * @extends {HTMLDivElement} 144 * @extends {HTMLDivElement}
145 */ 145 */
146 function ExtensionList() { 146 function ExtensionList() {
147 var div = document.createElement('div'); 147 var div = document.createElement('div');
148 div.__proto__ = ExtensionList.prototype; 148 div.__proto__ = ExtensionList.prototype;
149 /** @private {!Array<ExtensionInfo>} */ 149 div.initialize();
150 div.extensions_ = [];
151 return div; 150 return div;
152 } 151 }
153 152
154 /** 153 /**
155 * @type {Object<string, number>} A map from extension id to last reloaded 154 * @type {Object<string, number>} A map from extension id to last reloaded
156 * timestamp. The timestamp is recorded when the user click the 'Reload' 155 * timestamp. The timestamp is recorded when the user click the 'Reload'
157 * link. It is used to refresh the icon of an unpacked extension. 156 * link. It is used to refresh the icon of an unpacked extension.
158 * This persists between calls to decorate. 157 * This persists between calls to decorate.
159 */ 158 */
160 var extensionReloadedTimestamp = {}; 159 var extensionReloadedTimestamp = {};
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
199 */ 198 */
200 incognitoAvailable_: false, 199 incognitoAvailable_: false,
201 200
202 /** 201 /**
203 * Whether or not the app info dialog is enabled. 202 * Whether or not the app info dialog is enabled.
204 * @private {boolean} 203 * @private {boolean}
205 */ 204 */
206 enableAppInfoDialog_: false, 205 enableAppInfoDialog_: false,
207 206
208 /** 207 /**
208 * Initializes the list.
209 */
210 initialize: function() {
211 /** @private {!Array<ExtensionInfo>} */
212 this.extensions_ = [];
213
214 /** @type {Promise} */
215 this.extensionsUpdated = null;
216
217 chrome.developerPrivate.onItemStateChanged.addListener(
218 function(eventData) {
219 var EventType = chrome.developerPrivate.EventType;
220 switch (eventData.event_type) {
221 case EventType.VIEW_REGISTERED:
222 case EventType.VIEW_UNREGISTERED:
223 // For now, view notifications are handled through the WebUI.
224 // TODO(devlin): Transition these.
225 break;
226 case EventType.INSTALLED:
227 case EventType.LOADED:
228 case EventType.UNLOADED:
229 case EventType.ERROR_ADDED:
230 if (eventData.extensionInfo)
231 this.updateExtension_(eventData.extensionInfo);
232 break;
233 case EventType.UNINSTALLED:
234 var childNode = $(eventData.item_id);
235 if (childNode)
236 childNode.parentNode.removeChild(childNode);
237 break;
238 default:
239 assertNotReached();
240 }
241 }.bind(this));
242 },
243
244 /**
209 * Updates the extensions on the page. 245 * Updates the extensions on the page.
210 * @param {boolean} incognitoAvailable Whether or not incognito is allowed. 246 * @param {boolean} incognitoAvailable Whether or not incognito is allowed.
211 * @param {boolean} enableAppInfoDialog Whether or not the app info dialog 247 * @param {boolean} enableAppInfoDialog Whether or not the app info dialog
212 * is enabled. 248 * is enabled.
213 * @return {Promise} A promise that is resolved once the extensions data is 249 * @return {Promise} A promise that is resolved once the extensions data is
214 * fully updated. 250 * fully updated.
215 */ 251 */
216 updateExtensionsData: function(incognitoAvailable, enableAppInfoDialog) { 252 updateExtensionsData: function(incognitoAvailable, enableAppInfoDialog) {
217 // If we start to need more information about the extension configuration, 253 // If we start to need more information about the extension configuration,
218 // consider passing in the full object from the ExtensionSettings. 254 // consider passing in the full object from the ExtensionSettings.
219 this.incognitoAvailable_ = incognitoAvailable; 255 this.incognitoAvailable_ = incognitoAvailable;
220 this.enableAppInfoDialog_ = enableAppInfoDialog; 256 this.enableAppInfoDialog_ = enableAppInfoDialog;
221 return new Promise(function(resolve, reject) { 257 this.extensionsUpdated = new Promise(function(resolve, reject) {
222 chrome.developerPrivate.getExtensionsInfo( 258 chrome.developerPrivate.getExtensionsInfo(
223 {includeDisabled: true, includeTerminated: true}, 259 {includeDisabled: true, includeTerminated: true},
224 function(extensions) { 260 function(extensions) {
225 // Sort in order of unpacked vs. packed, followed by name, followed by 261 // Sort in order of unpacked vs. packed, followed by name, followed by
226 // id. 262 // id.
227 extensions.sort(function(a, b) { 263 extensions.sort(function(a, b) {
228 function compare(x, y) { 264 function compare(x, y) {
229 return x < y ? -1 : (x > y ? 1 : 0); 265 return x < y ? -1 : (x > y ? 1 : 0);
230 } 266 }
231 function compareLocation(x, y) { 267 function compareLocation(x, y) {
232 return x.location == chrome.developerPrivate.Location.UNPACKED ? 268 return x.location == chrome.developerPrivate.Location.UNPACKED ?
233 -1 : (x.location == y.location ? 0 : 1); 269 -1 : (x.location == y.location ? 0 : 1);
234 } 270 }
235 return compareLocation(a, b) || 271 return compareLocation(a, b) ||
236 compare(a.name.toLowerCase(), b.name.toLowerCase()) || 272 compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
237 compare(a.id, b.id); 273 compare(a.id, b.id);
238 }); 274 });
239 this.extensions_ = extensions; 275 this.extensions_ = extensions;
240 this.showExtensionNodes_(); 276 this.showExtensionNodes_();
241 resolve(); 277 resolve();
242 }.bind(this)); 278 }.bind(this));
243 }.bind(this)); 279 }.bind(this));
280 return this.extensionsUpdated;
244 }, 281 },
245 282
246 /** @return {number} The number of extensions being displayed. */ 283 /** @return {number} The number of extensions being displayed. */
247 getNumExtensions: function() { 284 getNumExtensions: function() {
248 return this.extensions_.length; 285 return this.extensions_.length;
249 }, 286 },
250 287
251 getIdQueryParam_: function() { 288 getIdQueryParam_: function() {
252 return parseQueryParams(document.location)['id']; 289 return parseQueryParams(document.location)['id'];
253 }, 290 },
254 291
255 getOptionsQueryParam_: function() { 292 getOptionsQueryParam_: function() {
256 return parseQueryParams(document.location)['options']; 293 return parseQueryParams(document.location)['options'];
257 }, 294 },
258 295
259 /** 296 /**
260 * Creates or updates all extension items from scratch. 297 * Creates or updates all extension items from scratch.
261 * @private 298 * @private
262 */ 299 */
263 showExtensionNodes_: function() { 300 showExtensionNodes_: function() {
264 // Remove the rows from |focusGrid_| without destroying them. 301 // Remove the rows from |focusGrid_| without destroying them.
265 this.focusGrid_.rows.length = 0; 302 this.focusGrid_.rows.length = 0;
266 303
267 // Any node that is not updated will be removed. 304 // Any node that is not updated will be removed.
268 var seenIds = []; 305 var seenIds = [];
269 306
270 // Iterate over the extension data and add each item to the list. 307 // Iterate over the extension data and add each item to the list.
271 this.extensions_.forEach(function(extension, i) { 308 this.extensions_.forEach(function(extension) {
272 var nextExt = this.extensions_[i + 1];
273 var node = $(extension.id);
274 seenIds.push(extension.id); 309 seenIds.push(extension.id);
275 310 this.updateExtension_(extension);
276 if (node)
277 this.updateNode_(extension, node);
278 else
279 this.createNode_(extension, nextExt ? $(nextExt.id) : null);
280 }, this); 311 }, this);
281 312
282 // Remove extensions that are no longer installed. 313 // Remove extensions that are no longer installed.
283 var nodes = document.querySelectorAll('.extension-list-item-wrapper[id]'); 314 var nodes = document.querySelectorAll('.extension-list-item-wrapper[id]');
284 for (var i = 0; i < nodes.length; ++i) { 315 for (var i = 0; i < nodes.length; ++i) {
285 var node = nodes[i]; 316 var node = nodes[i];
286 if (seenIds.indexOf(node.id) < 0) { 317 if (seenIds.indexOf(node.id) < 0) {
287 if (node.contains(document.activeElement)) { 318 if (node.contains(document.activeElement)) {
288 var focusableNode = nodes[i + 1] || nodes[i - 1]; 319 var focusableNode = nodes[i + 1] || nodes[i - 1];
289 if (focusableNode) { 320 if (focusableNode) {
(...skipping 685 matching lines...) Expand 10 before | Expand all | Expand 10 after
975 var self = this; 1006 var self = this;
976 $('overlay').addEventListener('cancelOverlay', function f() { 1007 $('overlay').addEventListener('cancelOverlay', function f() {
977 self.optionsShown_ = false; 1008 self.optionsShown_ = false;
978 $('overlay').removeEventListener('cancelOverlay', f); 1009 $('overlay').removeEventListener('cancelOverlay', f);
979 }); 1010 });
980 1011
981 // TODO(dbeam): why do we need to focus <extensionoptions> before and 1012 // TODO(dbeam): why do we need to focus <extensionoptions> before and
982 // after its showing animation? Makes very little sense to me. 1013 // after its showing animation? Makes very little sense to me.
983 overlay.setInitialFocus(); 1014 overlay.setInitialFocus();
984 }, 1015 },
1016
1017 /**
1018 * Updates the node for the extension.
1019 * @param {!ExtensionInfo} extension The information about the extension to
1020 * update.
1021 * @private
1022 */
1023 updateExtension_: function(extension) {
1024 var node = /** @type {ExtensionFocusRow} */ ($(extension.id));
1025 if (node) {
1026 this.updateNode_(extension, node);
1027 } else {
1028 var nextExt = this.extensions_[this.extensions_.indexOf(extension) + 1];
1029 this.createNode_(extension, nextExt ? $(nextExt.id) : null);
1030 }
1031 }
985 }; 1032 };
986 1033
987 return { 1034 return {
988 ExtensionList: ExtensionList 1035 ExtensionList: ExtensionList
989 }; 1036 };
990 }); 1037 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698