summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/resources/md_extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/resources/md_extensions')
-rw-r--r--chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp12
-rw-r--r--chromium/chrome/browser/resources/md_extensions/icons.html21
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.css113
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.html86
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item.js194
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.css15
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.html22
-rw-r--r--chromium/chrome/browser/resources/md_extensions/item_list.js57
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.css11
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.html26
-rw-r--r--chromium/chrome/browser/resources/md_extensions/manager.js215
-rw-r--r--chromium/chrome/browser/resources/md_extensions/service.html5
-rw-r--r--chromium/chrome/browser/resources/md_extensions/service.js158
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.css8
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.html42
-rw-r--r--chromium/chrome/browser/resources/md_extensions/sidebar.js114
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toolbar.html4
-rw-r--r--chromium/chrome/browser/resources/md_extensions/toolbar.js23
18 files changed, 1091 insertions, 35 deletions
diff --git a/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp b/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
index 2b001ed20fb..868cae39a5e 100644
--- a/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
+++ b/chromium/chrome/browser/resources/md_extensions/compiled_resources.gyp
@@ -7,12 +7,22 @@
'target_name': 'manager',
'variables': {
'depends': [
- '../../../../ui/webui/resources/cr_elements/v1_0/cr_search_field/cr_search_field.js',
+ '../../../../ui/webui/resources/cr_elements/cr_search_field/cr_search_field.js',
'../../../../ui/webui/resources/js/assert.js',
+ '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
'../../../../ui/webui/resources/js/cr.js',
+ '../../../../ui/webui/resources/js/i18n_behavior.js',
+ 'item.js',
+ 'item_list.js',
+ 'manager.js',
+ 'service.js',
+ 'sidebar.js',
+ 'toolbar.js',
],
'externs': [
'<(EXTERNS_DIR)/chrome_send.js',
+ '<(EXTERNS_DIR)/developer_private.js',
+ '<(EXTERNS_DIR)/management.js',
],
},
'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'],
diff --git a/chromium/chrome/browser/resources/md_extensions/icons.html b/chromium/chrome/browser/resources/md_extensions/icons.html
new file mode 100644
index 00000000000..72b51e217d4
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/icons.html
@@ -0,0 +1,21 @@
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html">
+
+<iron-iconset-svg name="extensions-icons" size="24">
+ <svg>
+ <defs>
+ <g id="pack">
+ <path d="M0 0h24v24H0z" fill="none"></path>
+ <path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-5 6h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2v2zm0 8h-2v-2h-2v-2h2v2h2v2z"></path>
+ </g>
+ <g id="update">
+ <defs>
+ <path id="a" d="M0 0h24v24H0V0z"></path>
+ </defs>
+ <clipPath id="b">
+ <use xlink:href="#a" overflow="visible"></use>
+ </clipPath>
+ <path d="M7.3 5.3c-1.3 1.3-2 3-2 4.7 0 1.7.7 3.4 2 4.7l1.2-1.2c-1-1-1.5-2.3-1.5-3.5 0-1.3.5-2.6 1.5-3.5L7.3 5.3zm11.8-2.4l-1.2 1.2c1.6 1.6 2.4 3.8 2.4 5.9s-.8 4.3-2.4 5.9l1.2 1.2c2-2 2.9-4.5 2.9-7.1s-1-5.1-2.9-7.1zm-13 1.2L4.9 2.9C3 4.9 2 7.4 2 10s1 5.1 2.9 7.1l1.2-1.2c-1.6-1.6-2.4-3.8-2.4-5.9s.8-4.3 2.4-5.9zm10.6 1.2l-1.2 1.2c1 1 1.5 2.3 1.5 3.5 0 1.3-.5 2.6-1.5 3.5l1.2 1.2c1.3-1.3 2-3 2-4.7-.1-1.7-.7-3.4-2-4.7zM12 7.5c-1.4 0-2.5 1.1-2.5 2.5 0 1 .6 1.9 1.5 2.3V21h2v-8.7c.9-.4 1.5-1.3 1.5-2.3 0-1.4-1.1-2.5-2.5-2.5z" clip-path="url(#b)"></path>
+ </g>
+ </svg>
+</iron-icon-set>
diff --git a/chromium/chrome/browser/resources/md_extensions/item.css b/chromium/chrome/browser/resources/md_extensions/item.css
new file mode 100644
index 00000000000..447cd33833b
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item.css
@@ -0,0 +1,113 @@
+/* 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. */
+
+.content-section {
+ padding: 20px;
+}
+
+#icon-wrapper {
+ align-self: center;
+ display: flex;
+ justify-content: center;
+ margin: 0 24px;
+}
+
+#icon {
+ height: 32px;
+ width: 32px;
+}
+
+/* TODO(devlin): Combine this with downloads style. */
+#card-wrapper {
+ background: white;
+ box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .05), 0 1px 4px 0 rgba(0, 0, 0, .08),
+ 0 3px 1px -2px rgba(0, 0, 0, .2);
+ color: #5A5A5A;
+ min-height: 103px;
+ width: 622px;
+}
+
+#card {
+ display: flex;
+}
+
+#card.disabled {
+ opacity: 0.6;
+}
+
+#content {
+ -webkit-border-start: 1px solid #C5C5C5;
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+}
+
+#name {
+ color: #222;
+ font-weight: 500;
+ margin-bottom: 8px;
+}
+
+#controls {
+ padding-top: 20px;
+}
+
+#version {
+ -webkit-margin-start: 50px;
+ flex: 1;
+}
+
+.checkbox {
+ --paper-checkbox-checked-color: rgb(66, 133, 244);
+ --primary-text-color: #5A5A5A;
+}
+
+#details-container {
+ border-top: 1px solid #C5C5C5;
+ color: #5A5A5A;
+}
+
+#extension-id {
+ padding-bottom: 10px;
+}
+
+#inspect-views {
+ padding-bottom: 20px;
+}
+
+#inspect-views paper-button {
+ color: rgb(51, 103, 214);
+}
+
+paper-button {
+ /* TODO(devlin): Decide whether all webui should do this. */
+ cursor: pointer;
+}
+
+#warnings-container {
+ border-top: 1px solid #C5C5C5;
+ display: flex;
+ padding: 10px;
+}
+
+#warnings-container div {
+ color: #333;
+}
+
+#warnings-container iron-icon {
+ -webkit-margin-end: 10px;
+ flex-shrink: 0;
+}
+
+#warnings-container.severe iron-icon {
+ color: rgb(219, 68, 55);
+}
+
+#warnings-container.mild iron-icon {
+ color: rgb(240, 147, 0);
+}
+
+#blacklisted-warning:empty {
+ display: none;
+}
diff --git a/chromium/chrome/browser/resources/md_extensions/item.html b/chromium/chrome/browser/resources/md_extensions/item.html
new file mode 100644
index 00000000000..69d8cbcf173
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item.html
@@ -0,0 +1,86 @@
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
+<link rel="import" href="chrome://resources/html/load_time_data.html">
+<link rel="import" href="chrome://extensions/strings.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
+
+<dom-module id="extensions-item">
+ <template>
+ <div id="card-wrapper" class$="[[computeClasses_(data.state)]]">
+ <div id="card">
+ <div id="icon-wrapper">
+ <img alt="" id="icon" src="[[data.iconUrl]]">
+ </div>
+ <div id="content">
+ <div class="content-section">
+ <div class="layout horizontal justified center">
+ <div id="name">[[data.name]]</div>
+ <paper-icon-button icon="[[computeExpandIcon_(showingDetails_)]]"
+ id="show-details" on-tap="onShowDetailsTap_">
+ </paper-icon-button>
+ </div>
+ <div id="description">[[data.description]]</div>
+ <div id="controls" class="layout horizontal center">
+ <paper-checkbox id="enabled" class="checkbox"
+ checked="[[isEnabled_(data.state)]]"
+ on-change="onEnableChange_">
+ [[computeEnableCheckboxLabel_(data.state)]]
+ </paper-checkbox>
+ <span id="version">[[data.version]]</span>
+ <paper-icon-button icon="delete" id="delete-button"
+ on-tap="onDeleteTap_"></paper-icon-button>
+ </div>
+ </div>
+ <template is="dom-if" if="[[showingDetails_]]">
+ <div id="details-container" class="content-section">
+ <template is="dom-if" if="[[inDevMode]]">
+ <div id="extension-id"></div>
+ <div id="inspect-views">
+ <span>[[i18n('itemInspectViews')]]</span>
+ <template is="dom-repeat" items="[[data.views]]">
+ <paper-button on-tap="onInspectTap_">
+ [[computeInspectLabel_(item)]]
+ </paper-button>
+ </template>
+ </div>
+ </template>
+ <div class="layout horizontal justified center">
+ <paper-checkbox id="allow-incognito" class="checkbox"
+ checked="[[data.incognitoAccess.isActive]]"
+ on-change="onAllowIncognitoChange_">
+ [[i18n('itemAllowIncognito')]]
+ </paper-checkbox>
+ <paper-button id="details-button" on-tap="onDetailsTap_">
+ [[i18n('itemDetails')]]
+ </paper-button>
+ </div>
+ </div>
+ </template>
+ </div>
+ </div>
+ <template is="dom-if" if="[[hasWarnings_(data.*)]]">
+ <div id="warnings-container"
+ class$="[[computeWarningsClasses_(data.blacklistText)]]">
+ <iron-icon icon="warning"></iron-icon>
+ <div>
+ <div id="corrupted-warning"
+ hidden="[[!data.disableReasons.corruptInstall]]">
+ [[i18n('itemCorruptInstall')]]
+ </div>
+ <div id="suspicious-warning"
+ hidden="[[!data.disableReasons.suspiciousInstall]]">
+ [[i18n('itemSuspiciousInstall')]]
+ </div>
+ <div id="blacklisted-warning">[[data.blacklistText]]</div>
+ </div>
+ </div>
+ </template>
+ </div>
+ </template>
+ <link rel="import" type="css" href="chrome://extensions/item.css">
+ <script src="chrome://extensions/item.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/item.js b/chromium/chrome/browser/resources/md_extensions/item.js
new file mode 100644
index 00000000000..9c0ead59b2e
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item.js
@@ -0,0 +1,194 @@
+// 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.
+
+cr.define('extensions', function() {
+ /** @interface */
+ var ItemDelegate = function() {};
+
+ ItemDelegate.prototype = {
+ /** @param {string} id */
+ deleteItem: assertNotReached,
+
+ /**
+ * @param {string} id
+ * @param {boolean} isEnabled
+ */
+ setItemEnabled: assertNotReached,
+
+ /** @param {string} id */
+ showItemDetails: assertNotReached,
+
+ /**
+ * @param {string} id
+ * @param {boolean} isAllowedIncognito
+ */
+ setItemAllowedIncognito: assertNotReached,
+
+ /**
+ * @param {string} id,
+ * @param {chrome.developerPrivate.ExtensionView} view
+ */
+ inspectItemView: assertNotReached,
+ };
+
+ var Item = Polymer({
+ is: 'extensions-item',
+
+ properties: {
+ // The item's delegate, or null.
+ delegate: {
+ type: Object,
+ },
+
+ // Whether or not dev mode is enabled.
+ inDevMode: {
+ type: Boolean,
+ value: false,
+ },
+
+ // Whether or not the expanded view of the item is shown.
+ showingDetails_: {
+ type: Boolean,
+ value: false,
+ },
+
+ // The underlying ExtensionInfo itself. Public for use in declarative
+ // bindings.
+ /** @type {chrome.developerPrivate.ExtensionInfo} */
+ data: {
+ type: Object,
+ },
+ },
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ observers: [
+ 'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
+ ],
+
+ /** @private */
+ observeIdVisibility_: function(inDevMode, showingDetails, id) {
+ Polymer.dom.flush();
+ var idElement = this.$$('#extension-id');
+ if (idElement) {
+ assert(this.data);
+ idElement.innerHTML = this.i18n('itemId', this.data.id);
+ }
+ this.fire('extension-item-size-changed', {item: this.data});
+ },
+
+ /** @private */
+ onShowDetailsTap_: function() {
+ this.showingDetails_ = !this.showingDetails_;
+ },
+
+ /** @private */
+ onDeleteTap_: function() {
+ this.delegate.deleteItem(this.data.id);
+ },
+
+ /** @private */
+ onEnableChange_: function() {
+ this.delegate.setItemEnabled(this.data.id, this.$.enabled.checked);
+ },
+
+ /** @private */
+ onDetailsTap_: function() {
+ this.delegate.showItemDetails(this.data.id);
+ },
+
+ /** @private */
+ onAllowIncognitoChange_: function() {
+ this.delegate.setItemAllowedIncognito(
+ this.data.id, this.$$('#allow-incognito').checked);
+ },
+
+ /**
+ * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
+ * @private
+ */
+ onInspectTap_: function(e) {
+ this.delegate.inspectItemView(this.data.id, e.model.item);
+ },
+
+ /**
+ * Returns true if the extension is enabled, including terminated
+ * extensions.
+ * @return {boolean}
+ * @private
+ */
+ isEnabled_: function() {
+ switch (this.data.state) {
+ case chrome.developerPrivate.ExtensionState.ENABLED:
+ case chrome.developerPrivate.ExtensionState.TERMINATED:
+ return true;
+ case chrome.developerPrivate.ExtensionState.DISABLED:
+ return false;
+ }
+ assertNotReached(); // FileNotFound.
+ },
+
+ /** @private */
+ computeClasses_: function() {
+ return this.isEnabled_() ? 'enabled' : 'disabled';
+ },
+
+ /** @private */
+ computeExpandIcon_: function() {
+ return this.showingDetails_ ? 'expand-less' : 'expand-more';
+ },
+
+ /** @private */
+ computeEnableCheckboxLabel_: function() {
+ return this.i18n(this.isEnabled_() ? 'itemEnabled' : 'itemDisabled');
+ },
+
+ /**
+ * @param {chrome.developerPrivate.ExtensionView} view
+ * @suppress {checkTypes} Needed for URL externs. :(
+ * @private
+ */
+ computeInspectLabel_: function(view) {
+ // Trim the "chrome-extension://<id>/".
+ var url = new URL(view.url);
+ var label = view.url;
+ if (url.protocol == 'chrome-extension:')
+ label = url.pathname.substring(1);
+ if (label == '_generated_background_page.html')
+ label = this.i18n('viewBackgroundPage');
+ // Add any qualifiers.
+ label += (view.incognito ? ' ' + this.i18n('viewIncognito') : '') +
+ (view.renderProcessId == -1 ?
+ ' ' + this.i18n('viewInactive') : '') +
+ (view.isIframe ? ' ' + this.i18n('viewIframe') : '');
+ return label;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasWarnings_: function() {
+ return this.data.disableReasons.corruptInstall ||
+ this.data.disableReasons.suspiciousInstall ||
+ !!this.data.blacklistText;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeWarningsClasses_: function() {
+ return this.data.blacklistText ? 'severe' : 'mild';
+ },
+ });
+
+ return {
+ Item: Item,
+ ItemDelegate: ItemDelegate,
+ };
+});
+
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.css b/chromium/chrome/browser/resources/md_extensions/item_list.css
new file mode 100644
index 00000000000..9163291f92b
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.css
@@ -0,0 +1,15 @@
+/* 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. */
+
+h2 {
+ color: #5a5a5a;
+ font-size: 1.1em;
+ font-weight: normal;
+ margin-bottom: 0;
+ margin-top: 30px;
+}
+
+.wrapper {
+ padding: 10px 0;
+}
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.html b/chromium/chrome/browser/resources/md_extensions/item_list.html
new file mode 100644
index 00000000000..18a2b35efcc
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.html
@@ -0,0 +1,22 @@
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
+<link rel="import" href="chrome://extensions/item.html">
+
+<dom-module id="extensions-item-list">
+ <template>
+ <h2>[[header]]</h2>
+ <iron-list id="list" items="[[computeShownItems_(items.*, filter)]]"
+ as="item">
+ <template>
+ <div class="wrapper">
+ <extensions-item data="[[item]]" delegate="[[delegate]]"
+ id="[[item.id]]" in-dev-mode="[[inDevMode]]">
+ </extensions-item>
+ </div>
+ </template>
+ </iron-list>
+ </template>
+ <link rel="import" type="css" href="chrome://extensions/item_list.css">
+ <script src="chrome://extensions/item_list.js"></script>
+</dom-module>
diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.js b/chromium/chrome/browser/resources/md_extensions/item_list.js
new file mode 100644
index 00000000000..2e6d9c3257d
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/item_list.js
@@ -0,0 +1,57 @@
+// 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.
+
+cr.define('extensions', function() {
+ var ItemList = Polymer({
+ is: 'extensions-item-list',
+
+ properties: {
+ /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
+ items: Array,
+
+ /** @type {extensions.ItemDelegate} */
+ delegate: Object,
+
+ header: String,
+
+ inDevMode: {
+ type: Boolean,
+ value: false,
+ },
+
+ filter: String,
+ },
+
+ listeners: {
+ 'list.extension-item-size-changed': 'itemSizeChanged_',
+ },
+
+ /**
+ * Updates the size for a given item.
+ * @param {CustomEvent} e
+ * @private
+ * @suppress {checkTypes} Closure doesn't know $.list is an IronList.
+ */
+ itemSizeChanged_: function(e) {
+ this.$.list.updateSizeForItem(e.detail.item);
+ },
+
+ /**
+ * Computes the list of items to be shown.
+ * @param {Object} changeRecord The changeRecord for |items|.
+ * @param {string} filter The updated filter string.
+ * @return {Array<!chrome.developerPrivate.ExtensionInfo>}
+ * @private
+ */
+ computeShownItems_: function(changeRecord, filter) {
+ return this.items.filter(function(item) {
+ return item.name.toLowerCase().includes(this.filter.toLowerCase());
+ }, this);
+ },
+ });
+
+ return {
+ ItemList: ItemList,
+ };
+});
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.css b/chromium/chrome/browser/resources/md_extensions/manager.css
index 999634de029..cef4d23721d 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.css
+++ b/chromium/chrome/browser/resources/md_extensions/manager.css
@@ -11,3 +11,14 @@
display: flex;
};
}
+
+#items {
+ -webkit-margin-start: 30px;
+ overflow-y: auto;
+ padding-bottom: 30px;
+ width: 100%;
+}
+
+extensions-item {
+ display: inline-block;
+}
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.html b/chromium/chrome/browser/resources/md_extensions/manager.html
index 504de93f902..e5d30a16f98 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.html
+++ b/chromium/chrome/browser/resources/md_extensions/manager.html
@@ -1,6 +1,9 @@
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html">
+<link rel="import" href="chrome://extensions/item_list.html">
+<link rel="import" href="chrome://extensions/service.html">
<link rel="import" href="chrome://extensions/sidebar.html">
<link rel="import" href="chrome://extensions/toolbar.html">
@@ -9,7 +12,28 @@
<paper-header-panel id="panel">
<extensions-toolbar class="paper-header" id="toolbar">
</extensions-toolbar>
- <extensions-sidebar></extensions-sidebar>
+ <extensions-sidebar in-dev-mode="[[inDevMode]]"
+ hide-extensions-button="[[computeListHidden_(extensions, extensions.splices)]]"
+ hide-apps-button="[[computeListHidden_(apps, apps.splices)]]"
+ hide-websites-button="[[computeListHidden_(websites, websites.splices)]]">
+ </extensions-sidebar>
+ <div id="items">
+ <extensions-item-list id="extensions-list" items="[[extensions]]"
+ delegate="[[service]]" header="[[i18n('sidebarExtensions')]]"
+ in-dev-mode="[[inDevMode]]" filter="[[filter]]"
+ hidden$="[[computeListHidden_(extensions, extensions.splices)]]">
+ </extensions-item-list>
+ <extensions-item-list id="apps-list" items="[[apps]]"
+ delegate="[[service]]" header="[[i18n('sidebarApps')]]"
+ in-dev-mode="[[inDevMode]]" filter="[[filter]]"
+ hidden$="[[computeListHidden_(apps, apps.splices)]]">
+ </extensions-item-list>
+ <extensions-item-list id="websites-list" items="[[websites]]"
+ delegate="[[service]]" header="[[i18n('sidebarWebsites')]]"
+ in-dev-mode="[[inDevMode]]" filter="[[filter]]"
+ hidden$="[[computeListHidden_(websites, websites.splices)]]">
+ </extensions-item-list>
+ </div>
</paper-header-panel>
</template>
<link rel="import" type="css" href="chrome://extensions/manager.css">
diff --git a/chromium/chrome/browser/resources/md_extensions/manager.js b/chromium/chrome/browser/resources/md_extensions/manager.js
index 729ee73338e..60c33b48dc5 100644
--- a/chromium/chrome/browser/resources/md_extensions/manager.js
+++ b/chromium/chrome/browser/resources/md_extensions/manager.js
@@ -3,9 +3,222 @@
// found in the LICENSE file.
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'
+ is: 'extensions-manager',
+
+ properties: {
+ /** @type {extensions.Sidebar} */
+ sidebar: Object,
+
+ /** @type {extensions.Service} */
+ service: 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 []; },
+ },
+
+ /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ websites: {
+ type: Array,
+ value: function() { return []; },
+ },
+ },
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ ready: function() {
+ /** @type {extensions.Sidebar} */
+ this.sidebar =
+ /** @type {extensions.Sidebar} */(this.$$('extensions-sidebar'));
+ this.service = extensions.Service.getInstance();
+ this.service.managerReady(this);
+ this.scrollHelper_ = new ScrollHelper(this);
+ this.sidebar.setScrollDelegate(this.scrollHelper_);
+ this.$.toolbar.setSearchDelegate(new SearchHelper(this));
+ },
+
+ /**
+ * @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:
+ listId = 'websites';
+ break;
+ 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;
+ });
+ },
+
+ /**
+ * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} list
+ * @return {boolean} Whether the list should be visible.
+ */
+ computeListHidden_: function(list) {
+ return list.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 {extensions.Manager} manager
+ * @constructor
+ * @implements {extensions.SidebarScrollDelegate}
+ */
+ function ScrollHelper(manager) {
+ this.items_ = manager.$.items;
+ }
+
+ ScrollHelper.prototype = {
+ /** @override */
+ scrollToExtensions: function() {
+ this.items_.scrollTop =
+ this.items_.querySelector('#extensions-list').offsetTop;
+ },
+
+ /** @override */
+ scrollToApps: function() {
+ this.items_.scrollTop =
+ this.items_.querySelector('#apps-list').offsetTop;
+ },
+
+ /** @override */
+ scrollToWebsites: function() {
+ this.items_.scrollTop =
+ this.items_.querySelector('#websites-list').offsetTop;
+ },
+ };
+
+ /**
+ * @param {extensions.Manager} manager
+ * @constructor
+ * @implements {SearchFieldDelegate}
+ */
+ function SearchHelper(manager) {
+ this.manager_ = manager;
+ }
+
+ SearchHelper.prototype = {
+ /** @override */
+ onSearchTermSearch: function(searchTerm) {
+ this.manager_.filter = searchTerm;
+ },
+ };
+
return {Manager: Manager};
});
diff --git a/chromium/chrome/browser/resources/md_extensions/service.html b/chromium/chrome/browser/resources/md_extensions/service.html
new file mode 100644
index 00000000000..fe1be3facc3
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/service.html
@@ -0,0 +1,5 @@
+<link rel="import" href="chrome://resources/html/assert.html">
+<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://extensions/service.html">
+<link rel="import" href="chrome://extensions/item.html">
+<script src="chrome://extensions/service.js"></script>
diff --git a/chromium/chrome/browser/resources/md_extensions/service.js b/chromium/chrome/browser/resources/md_extensions/service.js
new file mode 100644
index 00000000000..a0837206eb1
--- /dev/null
+++ b/chromium/chrome/browser/resources/md_extensions/service.js
@@ -0,0 +1,158 @@
+// 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.
+
+cr.define('extensions', function() {
+ 'use strict';
+
+ /**
+ * @constructor
+ * @implements {extensions.ItemDelegate}
+ * @implements {extensions.SidebarDelegate}
+ */
+ function Service() {}
+
+ Service.prototype = {
+ /** @private {boolean} */
+ promptIsShowing_: false,
+
+ /** @param {extensions.Manager} manager */
+ managerReady: function(manager) {
+ /** @private {extensions.Manager} */
+ this.manager_ = manager;
+ /** @private {extensions.Sidebar} */
+ this.sidebar_ = manager.sidebar;
+ this.sidebar_.setDelegate(this);
+ chrome.developerPrivate.onProfileStateChanged.addListener(
+ this.onProfileStateChanged_.bind(this));
+ chrome.developerPrivate.onItemStateChanged.addListener(
+ this.onItemStateChanged_.bind(this));
+ chrome.developerPrivate.getExtensionsInfo(
+ {includeDisabled: true, includeTerminated: true},
+ function(extensions) {
+ /** @private {Array<chrome.developerPrivate.ExtensionInfo>} */
+ this.extensions_ = extensions;
+ for (let extension of extensions)
+ this.manager_.addItem(extension);
+ }.bind(this));
+ chrome.developerPrivate.getProfileConfiguration(
+ this.onProfileStateChanged_.bind(this));
+ },
+
+ /**
+ * @param {chrome.developerPrivate.ProfileInfo} profileInfo
+ * @private
+ */
+ onProfileStateChanged_: function(profileInfo) {
+ /** @private {chrome.developerPrivate.ProfileInfo} */
+ this.profileInfo_ = profileInfo;
+ this.manager_.set('inDevMode', profileInfo.inDeveloperMode);
+ },
+
+ /**
+ * @param {chrome.developerPrivate.EventData} eventData
+ * @private
+ */
+ onItemStateChanged_: function(eventData) {
+ var currentIndex = this.extensions_.findIndex(function(extension) {
+ return extension.id == eventData.item_id;
+ });
+
+ var EventType = chrome.developerPrivate.EventType;
+ switch (eventData.event_type) {
+ case EventType.VIEW_REGISTERED:
+ case EventType.VIEW_UNREGISTERED:
+ case EventType.INSTALLED:
+ case EventType.LOADED:
+ case EventType.UNLOADED:
+ case EventType.ERROR_ADDED:
+ case EventType.ERRORS_REMOVED:
+ case EventType.PREFS_CHANGED:
+ // |extensionInfo| can be undefined in the case of an extension
+ // being unloaded right before uninstallation. There's nothing to do
+ // here.
+ if (!eventData.extensionInfo)
+ break;
+
+ if (currentIndex >= 0) {
+ this.extensions_[currentIndex] = eventData.extensionInfo;
+ this.manager_.updateItem(eventData.extensionInfo);
+ } else {
+ this.extensions_.push(eventData.extensionInfo);
+ this.manager_.addItem(eventData.extensionInfo);
+ }
+ break;
+ case EventType.UNINSTALLED:
+ this.manager_.removeItem(this.extensions_[currentIndex]);
+ this.extensions_.splice(currentIndex, 1);
+ break;
+ default:
+ assertNotReached();
+ }
+ },
+
+ /** @override */
+ deleteItem: function(id) {
+ if (this.promptIsShowing_)
+ return;
+ this.promptIsShowing_ = true;
+ chrome.management.uninstall(id, {showConfirmDialog: true}, function() {
+ // The "last error" was almost certainly the user canceling the dialog.
+ // Do nothing. We only check it so we don't get noisy logs.
+ /** @suppress {suspiciousCode} */
+ chrome.runtime.lastError;
+ this.promptIsShowing_ = false;
+ }.bind(this));
+ },
+
+ /** @override */
+ setItemEnabled: function(id, isEnabled) {
+ chrome.management.setEnabled(id, isEnabled);
+ },
+
+ /** @override */
+ showItemDetails: function(id) {},
+
+ /** @override */
+ setItemAllowedIncognito: function(id, isAllowedIncognito) {
+ chrome.developerPrivate.updateExtensionConfiguration({
+ extensionId: id,
+ incognitoAccess: isAllowedIncognito,
+ });
+ },
+
+ /** @override */
+ inspectItemView: function(id, view) {
+ chrome.developerPrivate.openDevTools({
+ extensionId: id,
+ renderProcessId: view.renderProcessId,
+ renderViewId: view.renderViewId,
+ incognito: view.incognito,
+ });
+ },
+
+ /** @override */
+ setProfileInDevMode: function(inDevMode) {
+ chrome.developerPrivate.updateProfileConfiguration(
+ {inDeveloperMode: inDevMode});
+ },
+
+ /** @override */
+ loadUnpacked: function() {
+ chrome.developerPrivate.loadUnpacked({failQuietly: true});
+ },
+
+ /** @override */
+ packExtension: function() {
+ },
+
+ /** @override */
+ updateAllExtensions: function() {
+ chrome.developerPrivate.autoUpdate();
+ },
+ };
+
+ cr.addSingletonGetter(Service);
+
+ return {Service: Service};
+});
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.css b/chromium/chrome/browser/resources/md_extensions/sidebar.css
index a7c4b14fac5..30618144e0b 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.css
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.css
@@ -5,7 +5,7 @@
:host {
-webkit-margin-start: 30px;
margin-top: 30px;
- position: fixed;
+ white-space: nowrap;
}
#section-menu {
@@ -32,7 +32,7 @@ paper-item {
-webkit-margin-start: 15px;
}
-#developer-mode {
+#devtools-container {
border-bottom: 1px solid #C5C5C5;
border-top: 1px solid #C5C5C5;
margin: 10px 0;
@@ -43,3 +43,7 @@ paper-item {
--primary-text-color: #5A5A5A;
-webkit-margin-start: 10px;
}
+
+#devtools-controls {
+ -webkit-margin-start: 20px;
+}
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.html b/chromium/chrome/browser/resources/md_extensions/sidebar.html
index 9bb9b02a211..a56a9e46de7 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.html
@@ -1,29 +1,57 @@
<link rel="import" href="chrome://resources/html/cr.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html">
+<link rel="import" href="chrome://extensions/icons.html">
<dom-module id="extensions-sidebar">
<template>
<paper-menu id="section-menu">
- <paper-item class="section-menu-item" id="sections-extensions">
+ <paper-item class="section-menu-item" id="sections-extensions"
+ on-tap="onExtensionsTap_" hidden$="[[hideExtensionsButton]]">
<iron-icon icon="extension"></iron-icon>
<span i18n-content="sidebarExtensions"></span>
</paper-item>
- <paper-item class="section-menu-item" id="sections-apps">
+ <paper-item class="section-menu-item" id="sections-apps"
+ on-tap="onAppsTap_" hidden$="[[hideAppsButton]]">
<iron-icon icon="apps"></iron-icon>
<span i18n-content="sidebarApps"></span>
</paper-item>
- <paper-item class="section-menu-item" id="sections-websites">
+ <paper-item class="section-menu-item" id="sections-websites"
+ on-tap="onWebsitesTap_" hidden$="[[hideWebsitesButton]]">
<iron-icon icon="cloud"></iron-icon>
<span i18n-content="sidebarWebsites"></span>
</paper-item>
</paper-menu>
- <paper-item id="developer-mode">
- <span i18n-content="developerMode"></span>
- <paper-checkbox id="developer-mode-checkbox"></paper-checkbox>
- </paper-item>
+ <div id="devtools-container">
+ <paper-item id="developer-mode">
+ <span i18n-content="developerMode"></span>
+ <paper-checkbox id="developer-mode-checkbox"
+ checked="[[inDevMode]]"
+ on-change="onDevModeChange_"></paper-checkbox>
+ </paper-item>
+ <template is="dom-if" if="[[inDevMode]]">
+ <div id="devtools-controls">
+ <paper-item class="section-menu-item" id="load-unpacked"
+ on-tap="onLoadUnpackedTap_">
+ <iron-icon icon="file-download"></iron-icon>
+ <span>[[i18n('sidebarLoadUnpacked')]]</span>
+ </paper-item>
+ <paper-item class="section-menu-item" id="pack-extensions"
+ on-tap="onPackTap_">
+ <iron-icon icon="extensions-icons:pack"></iron-icon>
+ <span>[[i18n('sidebarPack')]]</span>
+ </paper-item>
+ <paper-item class="section-menu-item" id="update-now"
+ on-tap="onUpdateNowTap_">
+ <iron-icon icon="extensions-icons:update"></iron-icon>
+ <span>[[i18n('sidebarUpdateNow')]]</span>
+ </paper-item>
+ </div>
+ </template>
+ </div>
<paper-item id="more-extensions" i18n-content="getMoreExtensions">
</paper-item>
<paper-item id="keyboard-shortcuts" i18n-content="keyboardShortcuts">
diff --git a/chromium/chrome/browser/resources/md_extensions/sidebar.js b/chromium/chrome/browser/resources/md_extensions/sidebar.js
index 10dfdf60e1e..622c5ec3ada 100644
--- a/chromium/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chromium/chrome/browser/resources/md_extensions/sidebar.js
@@ -3,10 +3,122 @@
// found in the LICENSE file.
cr.define('extensions', function() {
+ /** @interface */
+ var SidebarDelegate = function() {};
+
+ SidebarDelegate.prototype = {
+ /**
+ * Toggles whether or not the profile is in developer mode.
+ * @param {boolean} inDevMode
+ */
+ setProfileInDevMode: assertNotReached,
+
+ /** Opens the dialog to load unpacked extensions. */
+ loadUnpacked: assertNotReached,
+
+ /** Opens the dialog to pack an extension. */
+ packExtension: assertNotReached,
+
+ /** Updates all extensions. */
+ updateAllExtensions: assertNotReached,
+ };
+
+ /** @interface */
+ var SidebarScrollDelegate = function() {};
+
+ SidebarScrollDelegate.prototype = {
+ /** Scrolls to the extensions section. */
+ scrollToExtensions: assertNotReached,
+
+ /** Scrolls to the apps section. */
+ scrollToApps: assertNotReached,
+
+ /** Scrolls to the websites section. */
+ scrollToWebsites: assertNotReached,
+ };
+
var Sidebar = Polymer({
is: 'extensions-sidebar',
+
+ properties: {
+ inDevMode: {
+ type: Boolean,
+ value: false,
+ },
+
+ hideExtensionsButton: {
+ type: Boolean,
+ value: false,
+ },
+
+ hideAppsButton: {
+ type: Boolean,
+ value: false,
+ },
+
+ hideWebsitesButton: {
+ type: Boolean,
+ value: false,
+ },
+ },
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ /** @param {extensions.SidebarDelegate} delegate */
+ setDelegate: function(delegate) {
+ /** @private {extensions.SidebarDelegate} */
+ this.delegate_ = delegate;
+ },
+
+ /** @param {extensions.SidebarScrollDelegate} scrollDelegate */
+ setScrollDelegate: function(scrollDelegate) {
+ /** @private {extensions.SidebarScrollDelegate} */
+ this.scrollDelegate_ = scrollDelegate;
+ },
+
+ /** @private */
+ onExtensionsTap_: function() {
+ this.scrollDelegate_.scrollToExtensions();
+ },
+
+ /** @private */
+ onAppsTap_: function() {
+ this.scrollDelegate_.scrollToApps();
+ },
+
+ /** @private */
+ onWebsitesTap_: function() {
+ this.scrollDelegate_.scrollToWebsites();
+ },
+
+ /** @private */
+ onDevModeChange_: function() {
+ this.delegate_.setProfileInDevMode(
+ this.$['developer-mode-checkbox'].checked);
+ },
+
+ /** @private */
+ onLoadUnpackedTap_: function() {
+ this.delegate_.loadUnpacked();
+ },
+
+ /** @private */
+ onPackTap_: function() {
+ this.delegate_.packExtension();
+ },
+
+ /** @private */
+ onUpdateNowTap_: function() {
+ this.delegate_.updateAllExtensions();
+ },
});
- return {Sidebar: Sidebar};
+ return {
+ Sidebar: Sidebar,
+ SidebarDelegate: SidebarDelegate,
+ SidebarScrollDelegate: SidebarScrollDelegate,
+ };
});
diff --git a/chromium/chrome/browser/resources/md_extensions/toolbar.html b/chromium/chrome/browser/resources/md_extensions/toolbar.html
index f269d333385..8cc0aee2c8e 100644
--- a/chromium/chrome/browser/resources/md_extensions/toolbar.html
+++ b/chromium/chrome/browser/resources/md_extensions/toolbar.html
@@ -1,6 +1,6 @@
-<link rel="import" href="chrome://resources/html/cr.html">
<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
-<link rel="import" href="chrome://resources/cr_elements/v1_0/cr_search_field/cr_search_field.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
+<link rel="import" href="chrome://resources/html/cr.html">
<dom-module id="extensions-toolbar">
<template>
diff --git a/chromium/chrome/browser/resources/md_extensions/toolbar.js b/chromium/chrome/browser/resources/md_extensions/toolbar.js
index fade7d418ee..3da624cc6de 100644
--- a/chromium/chrome/browser/resources/md_extensions/toolbar.js
+++ b/chromium/chrome/browser/resources/md_extensions/toolbar.js
@@ -6,28 +6,11 @@ cr.define('extensions', function() {
var Toolbar = Polymer({
is: 'extensions-toolbar',
- /** @param {string} searchTerm */
- onSearchTermSearch: function(searchTerm) {
+ /** @param {SearchFieldDelegate} delegate */
+ setSearchDelegate: function(delegate) {
+ this.$['search-field'].setDelegate(delegate);
},
});
- /**
- * @constructor
- * @implements {SearchFieldDelegate}
- */
- // TODO(devlin): This is a bit excessive, and it would be better to just have
- // Toolbar implement SearchFieldDelegate. But for now, we don't know how to
- // make that happen with closure compiler.
- function ToolbarSearchFieldDelegate(toolbar) {
- this.toolbar_ = toolbar;
- }
-
- ToolbarSearchFieldDelegate.prototype = {
- /** @override */
- onSearchTermSearch: function(searchTerm) {
- this.toolbar_.onSearchTermSearch(searchTerm);
- }
- };
-
return {Toolbar: Toolbar};
});