blob: 640c092e35a323ec54d026dc1c35529cd78797b5 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* The different pages that can be shown at a time.
* Note: This must remain in sync with the order in manager.html!
* @enum {string}
*/
var Page = {
ITEM_LIST: '0',
DETAIL_VIEW: '1',
KEYBOARD_SHORTCUTS: '2',
ERROR_PAGE: '3',
};
cr.define('extensions', function() {
'use strict';
/**
* Compares two extensions to determine which should come first in the list.
* @param {chrome.developerPrivate.ExtensionInfo} a
* @param {chrome.developerPrivate.ExtensionInfo} b
* @return {number}
*/
var compareExtensions = function(a, b) {
function compare(x, y) {
return x < y ? -1 : (x > y ? 1 : 0);
}
function compareLocation(x, y) {
if (x.location == y.location)
return 0;
if (x.location == chrome.developerPrivate.Location.UNPACKED)
return -1;
if (y.location == chrome.developerPrivate.Location.UNPACKED)
return 1;
return 0;
}
return compareLocation(a, b) ||
compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
compare(a.id, b.id);
};
var Manager = Polymer({
is: 'extensions-manager',
behaviors: [I18nBehavior],
properties: {
/** @type {extensions.Sidebar} */
sidebar: Object,
/** @type {extensions.ItemDelegate} */
itemDelegate: Object,
inDevMode: {
type: Boolean,
value: false,
},
filter: {
type: String,
value: '',
},
/** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
extensions: {
type: Array,
value: function() { return []; },
},
/** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
apps: {
type: Array,
value: function() { return []; },
},
},
listeners: {
'items-list.extension-item-show-details': 'onShouldShowItemDetails_',
'items-list.extension-item-show-errors': 'onShouldShowItemErrors_',
},
created: function() {
this.readyPromiseResolver = new PromiseResolver();
},
ready: function() {
/** @type {extensions.Sidebar} */
this.sidebar =
/** @type {extensions.Sidebar} */(this.$$('extensions-sidebar'));
this.listHelper_ = new ListHelper(this);
this.sidebar.setListDelegate(this.listHelper_);
this.readyPromiseResolver.resolve();
},
get keyboardShortcuts() {
return this.$['keyboard-shortcuts'];
},
get packDialog() {
return this.$['pack-dialog'];
},
get optionsDialog() {
return this.$['options-dialog'];
},
get errorPage() {
return this.$['error-page'];
},
/**
* Shows the details view for a given item.
* @param {!chrome.developerPrivate.ExtensionInfo} data
*/
showItemDetails: function(data) {
this.$['items-list'].willShowItemSubpage(data.id);
this.$['details-view'].data = data;
this.changePage(Page.DETAIL_VIEW);
},
/**
* @param {!CustomEvent} event
* @private
*/
onFilterChanged_: function(event) {
this.filter = /** @type {string} */ (event.detail);
},
/**
* @param {chrome.developerPrivate.ExtensionType} type The type of item.
* @return {string} The ID of the list that the item belongs in.
* @private
*/
getListId_: function(type) {
var listId;
var ExtensionType = chrome.developerPrivate.ExtensionType;
switch (type) {
case ExtensionType.HOSTED_APP:
case ExtensionType.LEGACY_PACKAGED_APP:
case ExtensionType.PLATFORM_APP:
listId = 'apps';
break;
case ExtensionType.EXTENSION:
case ExtensionType.SHARED_MODULE:
listId = 'extensions';
break;
case ExtensionType.THEME:
assertNotReached(
'Don\'t send themes to the chrome://extensions page');
break;
}
assert(listId);
return listId;
},
/**
* @param {string} listId The list to look for the item in.
* @param {string} itemId The id of the item to look for.
* @return {number} The index of the item in the list, or -1 if not found.
* @private
*/
getIndexInList_: function(listId, itemId) {
return this[listId].findIndex(function(item) {
return item.id == itemId;
});
},
/**
* @return {boolean} Whether the list should be visible.
* @private
*/
computeListHidden_: function() {
return this.$['items-list'].items.length == 0;
},
/**
* Creates and adds a new extensions-item element to the list, inserting it
* into its sorted position in the relevant section.
* @param {!chrome.developerPrivate.ExtensionInfo} item The extension
* the new element is representing.
*/
addItem: function(item) {
var listId = this.getListId_(item.type);
// We should never try and add an existing item.
assert(this.getIndexInList_(listId, item.id) == -1);
var insertBeforeChild = this[listId].findIndex(function(listEl) {
return compareExtensions(listEl, item) > 0;
});
if (insertBeforeChild == -1)
insertBeforeChild = this[listId].length;
this.splice(listId, insertBeforeChild, 0, item);
},
/**
* @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
* item to update.
*/
updateItem: function(item) {
var listId = this.getListId_(item.type);
var index = this.getIndexInList_(listId, item.id);
// We should never try and update a non-existent item.
assert(index >= 0);
this.set([listId, index], item);
},
/**
* @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
* item to remove.
*/
removeItem: function(item) {
var listId = this.getListId_(item.type);
var index = this.getIndexInList_(listId, item.id);
// We should never try and remove a non-existent item.
assert(index >= 0);
this.splice(listId, index, 1);
},
/**
* @param {Page} page
* @return {!(extensions.KeyboardShortcuts |
* extensions.DetailView |
* extensions.ItemList)}
* @private
*/
getPage_: function(page) {
switch (page) {
case Page.ITEM_LIST:
return this.$['items-list'];
case Page.DETAIL_VIEW:
return this.$['details-view'];
case Page.KEYBOARD_SHORTCUTS:
return this.$['keyboard-shortcuts'];
case Page.ERROR_PAGE:
return this.$['error-page'];
}
assertNotReached();
},
/**
* Changes the active page selection.
* @param {Page} toPage
*/
changePage: function(toPage) {
var fromPage = this.$.pages.selected;
if (fromPage == toPage)
return;
var entry;
var exit;
if (fromPage == Page.ITEM_LIST && (toPage == Page.DETAIL_VIEW ||
toPage == Page.ERROR_PAGE)) {
entry = extensions.Animation.HERO;
exit = extensions.Animation.HERO;
} else if (toPage == Page.ITEM_LIST) {
entry = extensions.Animation.FADE_IN;
exit = extensions.Animation.SCALE_DOWN;
} else {
assert(toPage == Page.DETAIL_VIEW ||
toPage == Page.KEYBOARD_SHORTCUTS);
entry = extensions.Animation.FADE_IN;
exit = extensions.Animation.FADE_OUT;
}
this.getPage_(fromPage).animationHelper.setExitAnimation(exit);
this.getPage_(toPage).animationHelper.setEntryAnimation(entry);
this.$.pages.selected = toPage;
},
/**
* Handles the event for the user clicking on a details button.
* @param {!CustomEvent} e
* @private
*/
onShouldShowItemDetails_: function(e) {
this.showItemDetails(e.detail.data);
},
/**
* Handles the event for the user clicking on the errors button.
* @param {!CustomEvent} e
* @private
*/
onShouldShowItemErrors_: function(e) {
var data = e.detail.data;
this.$['items-list'].willShowItemSubpage(data.id);
this.$['error-page'].data = data;
this.changePage(Page.ERROR_PAGE);
},
/** @private */
onDetailsViewClose_: function() {
this.changePage(Page.ITEM_LIST);
},
/** @private */
onErrorPageClose_: function() {
this.changePage(Page.ITEM_LIST);
}
});
/**
* @param {extensions.Manager} manager
* @constructor
* @implements {extensions.SidebarListDelegate}
*/
function ListHelper(manager) {
this.manager_ = manager;
}
ListHelper.prototype = {
/** @override */
showType: function(type) {
var items;
switch (type) {
case extensions.ShowingType.EXTENSIONS:
items = this.manager_.extensions;
break;
case extensions.ShowingType.APPS:
items = this.manager_.apps;
break;
}
this.manager_.$/* hack */ ['items-list'].set('items', assert(items));
this.manager_.changePage(Page.ITEM_LIST);
},
/** @override */
showKeyboardShortcuts: function() {
this.manager_.changePage(Page.KEYBOARD_SHORTCUTS);
},
/** @override */
showPackDialog: function() {
this.manager_.packDialog.show();
}
};
return {Manager: Manager};
});