summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-25 15:05:36 +0000
committerbauerb@chromium.org <bauerb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-25 15:05:36 +0000
commitfcc5ab7f60a292e2969f2db9cbeab66a907e6eac (patch)
treee28c11d36702b6bacadf606fe7c1504300d4f537
parent509206877839c46cbe63ae0c0c2b57ab3e8bffde (diff)
downloadchromium_src-fcc5ab7f60a292e2969f2db9cbeab66a907e6eac.zip
chromium_src-fcc5ab7f60a292e2969f2db9cbeab66a907e6eac.tar.gz
chromium_src-fcc5ab7f60a292e2969f2db9cbeab66a907e6eac.tar.bz2
Landing patch from http://codereview.chromium.org/8746019/ (Javascript readability CL for bauerb).
The original CL didn't contain updates to the generated docs, and I can't change the base URL on it to include them. TBR=mkwst@chromium.org BUG=none TEST=none Review URL: http://codereview.chromium.org/9169044 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@119069 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/common/extensions/docs/api_index.html2
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/chrome_stubs.js68
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/main.js10
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list.js155
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list_test.html68
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings.js152
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings_test.html143
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list.js145
-rw-r--r--chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list_test.html64
-rw-r--r--chrome/common/extensions/docs/experimental.html1
-rw-r--r--chrome/common/extensions/docs/samples.html8
-rw-r--r--chrome/common/extensions/docs/samples.json6
12 files changed, 662 insertions, 160 deletions
diff --git a/chrome/common/extensions/docs/api_index.html b/chrome/common/extensions/docs/api_index.html
index 3444593..78dc513 100644
--- a/chrome/common/extensions/docs/api_index.html
+++ b/chrome/common/extensions/docs/api_index.html
@@ -374,7 +374,7 @@ Here are the supported chrome.* APIs:
</p>
<ul>
- <li><a href="bookmarks.html" js="">bookmarks</a></li><li><a href="browserAction.html" js="">browserAction</a></li><li><a href="contentSettings.html" js="">contentSettings</a></li><li><a href="contextMenus.html" js="">contextMenus</a></li><li><a href="cookies.html" js="">cookies</a></li><li><a href="debugger.html" js="">debugger</a></li><li><a href="extension.html" js="">extension</a></li><li><a href="fileBrowserHandler.html" js="">fileBrowserHandler</a></li><li><a href="history.html" js="">history</a></li><li><a href="i18n.html" js="">i18n</a></li><li><a href="idle.html" js="">idle</a></li><li><a href="management.html" js="">management</a></li><li><a href="omnibox.html" js="">omnibox</a></li><li><a href="pageAction.html" js="">pageAction</a></li><li><a href="pageCapture.html" js="">pageCapture</a></li><li><a href="permissions.html" js="">permissions</a></li><li><a href="proxy.html" js="">proxy</a></li><li><a href="storage.html" js="">storage</a></li><li><a href="tabs.html" js="">tabs</a></li><li><a href="tts.html" js="">tts</a></li><li><a href="ttsEngine.html" js="">ttsEngine</a></li><li><a href="types.html" js="">types</a></li><li><a href="webNavigation.html" js="">webNavigation</a></li><li><a href="webRequest.html" js="">webRequest</a></li><li><a href="windows.html" js="">windows</a></li>
+ <li><a href="bookmarks.html" js="">bookmarks</a></li><li><a href="browserAction.html" js="">browserAction</a></li><li><a href="contentSettings.html" js="">contentSettings</a></li><li><a href="contextMenus.html" js="">contextMenus</a></li><li><a href="cookies.html" js="">cookies</a></li><li><a href="debugger.html" js="">debugger</a></li><li><a href="extension.html" js="">extension</a></li><li><a href="fileBrowserHandler.html" js="">fileBrowserHandler</a></li><li><a href="history.html" js="">history</a></li><li><a href="i18n.html" js="">i18n</a></li><li><a href="idle.html" js="">idle</a></li><li><a href="management.html" js="">management</a></li><li><a href="omnibox.html" js="">omnibox</a></li><li><a href="pageAction.html" js="">pageAction</a></li><li><a href="pageCapture.html" js="">pageCapture</a></li><li><a href="permissions.html" js="">permissions</a></li><li><a href="privacy.html" js="">privacy</a></li><li><a href="proxy.html" js="">proxy</a></li><li><a href="storage.html" js="">storage</a></li><li><a href="tabs.html" js="">tabs</a></li><li><a href="tts.html" js="">tts</a></li><li><a href="ttsEngine.html" js="">ttsEngine</a></li><li><a href="types.html" js="">types</a></li><li><a href="webNavigation.html" js="">webNavigation</a></li><li><a href="webRequest.html" js="">webRequest</a></li><li><a href="windows.html" js="">windows</a></li>
</ul>
<h2 id="experimental">Experimental APIs</h2>
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/chrome_stubs.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/chrome_stubs.js
new file mode 100644
index 0000000..38b7514
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/chrome_stubs.js
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 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.
+
+/**
+ * @fileoverview Stubs for Chrome extension APIs that aren't available to
+ * regular web pages, to allow tests to run.
+ */
+
+chrome = chrome || {};
+chrome.extension = chrome.extension || {};
+chrome.contentSettings = chrome.contentSettings || {};
+
+var _rules = {};
+chrome.contentSettings.plugins = {
+ 'set': function(details, callback) {
+ assertObjectEquals({'id': 'myplugin'}, details.resourceIdentifier);
+ var pattern = details.primaryPattern;
+ var setting = details.setting;
+ if (pattern == '__invalid_pattern') {
+ chrome.extension.lastError = {'message': 'Invalid pattern'};
+ } else if (setting == '__invalid_setting') {
+ throw Error('Invalid setting');
+ } else {
+ chrome.extension.lastError = undefined;
+ _rules[pattern] = setting;
+ }
+ callback();
+ },
+
+ 'clear': function(details, callback) {
+ assertObjectEquals({}, details);
+ _rules = {};
+ callback();
+ }
+};
+
+chrome.i18n = chrome.i18n || {};
+chrome.i18n.getMessage = function(id) {
+ var messages = {
+ 'patternColumnHeader': 'Hostname Pattern',
+ 'settingColumnHeader': 'Behavior',
+ 'allowRule': 'Allow',
+ 'blockRule': 'Block',
+ 'addNewPattern': 'Add a new hostname pattern',
+ };
+ return messages[id];
+}
+
+/**
+ * Creates a new Settings object with a set of rules for a dummy plug-in.
+ * Because we provide stub implementations for the Chrome contentSettings
+ * extension API, we know that the methods will execute immediately instead of
+ * asynchronously.
+ * @param {!Object} rules A map from content settings pattern to setting.
+ * @return {!pluginSettings.Settings} A newly created Settings object with the
+ * passed in set of rules.
+ */
+function createSettings(rules) {
+ var settings = new pluginSettings.Settings('myplugin');
+ if (rules) {
+ for (var pattern in rules) {
+ settings.set(pattern, rules[pattern], function() {});
+ }
+ }
+ return settings;
+}
+
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/main.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/main.js
index 1b61566..89aeca6 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/main.js
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/main.js
@@ -1,12 +1,17 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
+/**
+ * @fileoverview Main entry point that creates a new plug-in list on document
+ * load.
+ */
+
document.addEventListener('DOMContentLoaded', function() {
chrome.contentSettings.plugins.getResourceIdentifiers(function(r) {
if (chrome.extension.lastError) {
$('error').textContent =
- "Error: " + chrome.extension.lastError.message;
+ 'Error: ' + chrome.extension.lastError.message;
return;
}
var pluginList = $('plugin-list');
@@ -14,3 +19,4 @@ document.addEventListener('DOMContentLoaded', function() {
pluginList.dataModel = new cr.ui.ArrayDataModel(r);
});
});
+
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list.js
index 53d9da8..f1d3032 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list.js
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list.js
@@ -1,64 +1,122 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
+/**
+ * @fileoverview Defines a list of plug-ins that shows for each plug-in a list
+ * of content setting rules.
+ */
+
cr.define('pluginSettings.ui', function() {
const List = cr.ui.List;
const ListItem = cr.ui.ListItem;
const ListSingleSelectionModel = cr.ui.ListSingleSelectionModel;
/**
+ * CSS classes used by this class.
+ * @enum {string}
+ */
+ const CSSClass = {
+
+ /**
+ * Hides an element.
+ */
+ HIDDEN: 'hidden',
+
+ /**
+ * A plug-in list.
+ */
+ PLUGIN_LIST: 'plugin-list',
+
+ /**
+ * Set on a plug-in list entry to show details about the plug-in.
+ */
+ PLUGIN_SHOW_DETAILS: 'plugin-show-details',
+
+ /**
+ * The plug-in name.
+ */
+ PLUGIN_NAME: 'plugin-name',
+
+ /**
+ * The number of rules set for a plug-in.
+ */
+ NUM_RULES: 'num-rules',
+
+ /**
+ * The element containing details about a plug-in.
+ */
+ PLUGIN_DETAILS: 'plugin-details',
+
+ /**
+ * The element containing the column headers for the list of rules.
+ */
+ COLUMN_HEADERS: 'column-headers',
+
+ /**
+ * The header for the pattern column.
+ */
+ PATTERN_COLUMN_HEADER: 'pattern-column-header',
+
+ /**
+ * The header for the setting column.
+ */
+ SETTING_COLUMN_HEADER: 'setting-column-header',
+ };
+
+ /**
* Returns the item's height, like offsetHeight but such that it works better
* when the page is zoomed. See the similar calculation in @{code cr.ui.List}.
* This version also accounts for the animation done in this file.
- * @param {Element} item The item to get the height of.
+ * @param {!Element} item The item to get the height of.
* @return {number} The height of the item, calculated with zooming in mind.
*/
function getItemHeight(item) {
var height = item.style.height;
// Use the fixed animation target height if set, in case the element is
// currently being animated and we'd get an intermediate height below.
- if (height && height.substr(-2) == 'px')
+ if (height && height.substr(-2) == 'px') {
return parseInt(height.substr(0, height.length - 2));
+ }
return item.getBoundingClientRect().height;
}
/**
* Creates a new plug-in list item element.
- * @param {PluginList} list The plug-in list containing this item.
- * @param {Object} info Information about the plug-in.
+ * @param {!PluginList} list The plug-in list containing this item.
+ * @param {!Object} info Information about the plug-in.
* @constructor
* @extends {cr.ui.ListItem}
*/
function PluginListItem(list, info) {
var el = cr.doc.createElement('li');
- el.list_ = list;
- el.info_ = info;
- el.__proto__ = PluginListItem.prototype;
- el.decorate();
- return el;
- }
-
- PluginListItem.prototype = {
- __proto__: ListItem.prototype,
/**
* The plug-in list containing this item.
- * @type {PluginList}
+ * @type {!PluginList}
* @private
*/
- list_: null,
+ el.list_ = list;
/**
* Information about the plug-in.
- * @type {Object}
+ * @type {!Object}
* @private
*/
- info_: null,
+ el.info_ = info;
+
+ el.__proto__ = PluginListItem.prototype;
+ el.decorate();
+ return el;
+ }
+
+ PluginListItem.prototype = {
+ __proto__: ListItem.prototype,
/**
- * The element containing details about the plug-in.
- * @type {HTMLDivElemebt}
+ * The element containing details about the plug-in. This is only null in
+ * the prototype.
+ * @type {?HTMLDivElement}
* @private
*/
detailsElement_: null,
@@ -75,28 +133,29 @@ cr.define('pluginSettings.ui', function() {
var titleEl = this.ownerDocument.createElement('div');
var nameEl = this.ownerDocument.createElement('span');
- nameEl.className = 'plugin-name';
+ nameEl.className = CSSClass.PLUGIN_NAME;
nameEl.textContent = info.description;
nameEl.title = info.description;
titleEl.appendChild(nameEl);
this.numRulesEl_ = this.ownerDocument.createElement('span');
- this.numRulesEl_.className = 'num-rules';
+ this.numRulesEl_.className = CSSClass.NUM_RULES;
titleEl.appendChild(this.numRulesEl_);
contentElement.appendChild(titleEl);
this.detailsElement_ = this.ownerDocument.createElement('div');
- this.detailsElement_.className = 'plugin-details hidden';
+ this.detailsElement_.classList.add(CSSClass.PLUGIN_DETAILS);
+ this.detailsElement_.classList.add(CSSClass.HIDDEN);
var columnHeadersEl = this.ownerDocument.createElement('div');
- columnHeadersEl.className = 'column-headers';
+ columnHeadersEl.className = CSSClass.COLUMN_HEADERS;
var patternColumnEl = this.ownerDocument.createElement('div');
patternColumnEl.textContent =
- chrome.i18n.getMessage("patternColumnHeader");
- patternColumnEl.className = 'pattern-column-header';
+ chrome.i18n.getMessage('patternColumnHeader');
+ patternColumnEl.className = CSSClass.PATTERN_COLUMN_HEADER;
var settingColumnEl = this.ownerDocument.createElement('div');
settingColumnEl.textContent =
- chrome.i18n.getMessage("settingColumnHeader");
- settingColumnEl.className = 'setting-column-header';
+ chrome.i18n.getMessage('settingColumnHeader');
+ settingColumnEl.className = CSSClass.SETTING_COLUMN_HEADER;
columnHeadersEl.appendChild(patternColumnEl);
columnHeadersEl.appendChild(settingColumnEl);
this.detailsElement_.appendChild(columnHeadersEl);
@@ -106,8 +165,9 @@ cr.define('pluginSettings.ui', function() {
var settings = new pluginSettings.Settings(this.info_.id);
this.updateRulesCount_(settings);
- settings.addEventListener('change',
- this.updateRulesCount_.bind(this, settings));
+ settings.addEventListener(
+ 'change',
+ this.updateRulesCount_.bind(this, settings));
// Create the rule list asynchronously, to make sure that it is already
// fully integrated in the DOM tree.
@@ -116,6 +176,8 @@ cr.define('pluginSettings.ui', function() {
/**
* Create the list of content setting rules applying to this plug-in.
+ * @param {!pluginSettings.Settings} The settings object storing the content
+ * setting rules.
* @private
*/
loadRules_: function(settings) {
@@ -126,6 +188,13 @@ cr.define('pluginSettings.ui', function() {
rulesEl.setPluginSettings(settings);
},
+ /**
+ * Called when the list of rules changes to update the rule count shown when
+ * the list is not expanded.
+ * @param {!pluginSettings.Settings} The settings object storing the content
+ * setting rules.
+ * @private
+ */
updateRulesCount_: function(settings) {
this.numRulesEl_.textContent = '(' + settings.getAll().length + ' rules)';
},
@@ -135,28 +204,34 @@ cr.define('pluginSettings.ui', function() {
* @type {boolean}
*/
expanded_: false,
+ /**
+ * Whether this item is expanded or not.
+ * @type {boolean}
+ */
get expanded() {
return this.expanded_;
},
set expanded(expanded) {
- if (this.expanded_ == expanded)
+ if (this.expanded_ == expanded) {
return;
+ }
this.expanded_ = expanded;
if (expanded) {
var oldExpanded = this.list_.expandItem;
this.list_.expandItem = this;
- this.detailsElement_.classList.remove('hidden');
- if (oldExpanded)
+ this.detailsElement_.classList.remove(CSSClass.HIDDEN);
+ if (oldExpanded) {
oldExpanded.expanded = false;
- this.classList.add('plugin-show-details');
+ }
+ this.classList.add(CSSClass.PLUGIN_SHOW_DETAILS);
} else {
if (this.list_.expandItem == this) {
this.list_.leadItemHeight = 0;
this.list_.expandItem = null;
}
this.style.height = '';
- this.detailsElement_.classList.add('hidden');
- this.classList.remove('plugin-show-details');
+ this.detailsElement_.classList.add(CSSClass.HIDDEN);
+ this.classList.remove(CSSClass.PLUGIN_SHOW_DETAILS);
}
},
};
@@ -176,7 +251,7 @@ cr.define('pluginSettings.ui', function() {
*/
decorate: function() {
List.prototype.decorate.call(this);
- this.classList.add('plugin-list');
+ this.classList.add(CSSClass.PLUGIN_LIST);
var sm = new ListSingleSelectionModel();
sm.addEventListener('change', this.handleSelectionChange_.bind(this));
this.selectionModel = sm;
@@ -185,7 +260,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Creates a new plug-in list item.
- * @param {Object} info Information about the plug-in.
+ * @param {!Object} info Information about the plug-in.
*/
createItem: function(info) {
return new PluginListItem(this, info);
@@ -193,6 +268,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Called when the selection changes.
+ * @param {!cr.Event} ce The change event.
* @private
*/
handleSelectionChange_: function(ce) {
@@ -202,8 +278,9 @@ cr.define('pluginSettings.ui', function() {
if (!change.selected) {
// TODO(bsmith) explain window timeout (from cookies_list.js)
window.setTimeout(function() {
- if (!listItem.selected || !listItem.lead)
+ if (!listItem.selected || !listItem.lead) {
listItem.expanded = false;
+ }
}, 0);
} else if (listItem.lead) {
listItem.expanded = true;
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list_test.html b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list_test.html
new file mode 100644
index 0000000..9fd852a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_list_test.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+#error {
+ display: none;
+}
+</style>
+<link rel="stylesheet" href="../domui/css/button.css">
+<link rel="stylesheet" href="../domui/css/chrome_shared.css">
+<link rel="stylesheet" href="../domui/css/list.css">
+<link rel="stylesheet" href="../domui/css/select.css">
+
+<link rel="stylesheet" href="../options/css/list.css">
+
+<link rel="stylesheet" href="../css/plugin_list.css">
+<link rel="stylesheet" href="../css/rule_list.css">
+
+<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
+<script src="../domui/js/cr.js"></script>
+<script src="../domui/js/cr/event_target.js"></script>
+<script src="../domui/js/cr/ui.js"></script>
+<script src="../domui/js/cr/ui/array_data_model.js"></script>
+<script src="../domui/js/cr/ui/list_item.js"></script>
+<script src="../domui/js/cr/ui/list_selection_controller.js"></script>
+<script src="../domui/js/cr/ui/list_selection_model.js"></script>
+<script src="../domui/js/cr/ui/list_single_selection_model.js"></script>
+<script src="../domui/js/cr/ui/list.js"></script>
+<script src="../domui/js/util.js"></script>
+
+<script src="../options/js/deletable_item_list.js"></script>
+<script src="../options/js/inline_editable_list.js"></script>
+
+<script src="plugin_list.js" type="text/javascript"></script>
+<script src="plugin_settings.js" type="text/javascript"></script>
+<script src="rule_list.js" type="text/javascript"></script>
+
+<script>
+goog.require('goog.testing.jsunit');
+</script>
+<script src="chrome_stubs.js" type="text/javascript"></script>
+</head>
+<body>
+<div id="error"></div>
+<script>
+function testConstruction() {
+ var pluginList = document.createElement('list');
+ document.body.appendChild(pluginList);
+ pluginSettings.ui.PluginList.decorate(pluginList);
+ var plugins = [
+ {
+ 'id': 'myplugin',
+ 'description': 'My Plugin'
+ }
+ ];
+ var rules = {
+ 'http://example.com/*': 'block',
+ 'http://moose.org/*': 'allow',
+ };
+ createSettings(rules);
+ pluginList.dataModel = new cr.ui.ArrayDataModel(plugins);
+ assertEquals('My Plugin',
+ pluginList.querySelector('.plugin-name').textContent);
+ assertEquals('(2 rules)', pluginList.querySelector('.num-rules').textContent);
+}
+</script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings.js
index 9929e89..253240d 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings.js
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings.js
@@ -1,7 +1,12 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
+/**
+ * @fileoverview Defines a class that provides some convenient wrapper methods
+ * around the Chrome contentSettings extension API.
+ */
+
cr.define('pluginSettings', function() {
const EventTarget = cr.EventTarget;
const Event = cr.Event;
@@ -14,18 +19,16 @@ cr.define('pluginSettings', function() {
* @extends {cr.EventTarget}
*/
function Settings(plugin) {
- this.plugin_ = plugin;
- }
-
- Settings.prototype = {
- __proto__: cr.EventTarget.prototype,
-
/**
* Identifies the plug-in for which this object stores settings.
* @type {string}
* @private
*/
- plugin_: null,
+ this.plugin_ = plugin;
+ }
+
+ Settings.prototype = {
+ __proto__: cr.EventTarget.prototype,
/**
* Clears all content settings, and recreates them from local storage. If a
@@ -37,64 +40,96 @@ cr.define('pluginSettings', function() {
* @private
*/
recreateRules_: function(callback) {
- chrome.contentSettings.plugins.clear({}, function() {
- if (chrome.extension.lastError) {
- console.error("Error clearing rules");
- callback();
- return;
- }
- var length = window.localStorage.length;
- if (length == 0) {
- callback();
- return;
- }
- var count = length;
- var errors = [];
- for (var i = 0; i < length; i++) {
- var key = window.localStorage.key(i);
- var keyArray = JSON.parse(key);
- var plugin = keyArray[0];
- var pattern = keyArray[1];
- var setting = window.localStorage.getItem(key);
- chrome.contentSettings.plugins.set({
+ chrome.contentSettings.plugins.clear(
+ {}, this.didClearRules_.bind(this, callback));
+ },
+
+ /**
+ * Recreates all content settings from local storage.
+ * @param {function()} callback Called when the content settings have been
+ * recreated, or on error.
+ * @private
+ */
+ didClearRules_: function(callback) {
+ if (chrome.extension.lastError) {
+ console.error('Error clearing rules');
+ callback();
+ return;
+ }
+ var length = window.localStorage.length;
+ if (length == 0) {
+ cr.dispatchSimpleEvent(settings, 'change');
+ callback();
+ return;
+ }
+ var counter = {
+ 'value': length
+ };
+ for (var i = 0; i < length; i++) {
+ var key = window.localStorage.key(i);
+ var keyArray = JSON.parse(key);
+ var plugin = keyArray[0];
+ var pattern = keyArray[1];
+ var setting = window.localStorage.getItem(key)
+ chrome.contentSettings.plugins.set(
+ {
'primaryPattern': pattern,
- 'resourceIdentifier': { 'id': plugin },
+ 'resourceIdentifier': {'id': plugin},
'setting': setting,
- }, function() {
- if (chrome.extension.lastError) {
- console.error('Error restoring [' + plugin_ + ', ' +
- pattern + setting + ']: ' +
- chrome.extension.lastError.message);
- window.localStorage.removeItem(key);
- }
- count--;
- if (count == 0)
- callback();
- });
- }
- });
+ },
+ this.didSetContentSetting_.bind(
+ this, key, setting, counter, callback));
+ }
+ },
+
+ /**
+ * Checks if we're finished with recreating content settings and calls the
+ * passed in callback if so.
+ * @param {string} key The local storage key under which the content
+ * setting was stored.
+ * @param {string} value The content setting value in local storage.
+ * @param {{value:number}} counter Contains the number of callbacks still
+ * outstanding.
+ * @param {function()} callback Called when the content settings have been
+ * recreated, or on error.
+ * @private
+ */
+ didSetContentSetting_: function(plugin, pattern, key, counter, callback) {
+ if (chrome.extension.lastError) {
+ console.error(
+ 'Error restoring [' + key + ': ' + value + ']: ' +
+ chrome.extension.lastError.message);
+ window.localStorage.removeItem(key);
+ }
+ counter.value--;
+ if (counter.value == 0) {
+ cr.dispatchSimpleEvent(this, 'change');
+ callback();
+ }
},
/**
* Creates a content setting rule and calls the passed in callback with the
- * result.
+ * result.
* @param {string} pattern The content setting pattern for the rule.
* @param {string} setting The setting for the rule.
- * @param {function(?string)} callback Called when the content settings have
- * been updated, or on error.
+ * @param {function(?string)} callback Called when the content settings
+ * have been updated, or on error.
*/
set: function(pattern, setting, callback) {
var plugin = this.plugin_;
+ var settings = this;
chrome.contentSettings.plugins.set({
- 'primaryPattern': pattern,
- 'resourceIdentifier': { 'id': plugin },
- 'setting': setting,
+ 'primaryPattern': pattern,
+ 'resourceIdentifier': { 'id': plugin },
+ 'setting': setting,
}, function() {
if (chrome.extension.lastError) {
callback(chrome.extension.lastError.message);
} else {
window.localStorage.setItem(JSON.stringify([plugin, pattern]),
setting);
+ cr.dispatchSimpleEvent(settings, 'change');
callback();
}
});
@@ -102,10 +137,10 @@ cr.define('pluginSettings', function() {
/**
* Removes the content setting rule with a given pattern, and calls the
- * passed in callback afterwards.
+ * passed in callback afterwards.
* @param {string} pattern The content setting pattern for the rule.
- * @param {function()?} callback Called when the content settings have
- * been updated.
+ * @param {function()} callback Called when the content settings have
+ * been updated.
*/
clear: function(pattern, callback) {
window.localStorage.removeItem(
@@ -115,12 +150,12 @@ cr.define('pluginSettings', function() {
/**
* Updates the content setting rule with a given pattern to a new pattern
- * and setting and calls the passed in callback with the result.
+ * and setting and calls the passed in callback with the result.
* @param {string} oldPattern The old content setting pattern for the rule.
* @param {string} newPattern The new content setting pattern for the rule.
* @param {string} setting The setting for the rule.
- * @param {function(?string)} callback Called when the content settings have
- * been updated, or on error.
+ * @param {function(?string)} callback Called when the content settings
+ * have been updated, or on error.
*/
update: function(oldPattern, newPattern, setting, callback) {
if (oldPattern == newPattern) {
@@ -136,8 +171,7 @@ cr.define('pluginSettings', function() {
settings.set(newPattern, setting, function(error) {
if (error) {
// If setting the new rule failed, restore the old rule.
- settings.setInternal_(oldPattern, oldSetting,
- function(restoreError) {
+ settings.set(oldPattern, oldSetting, function(restoreError) {
if (restoreError) {
console.error('Error restoring [' + settings.plugin_ + ', ' +
oldPattern + oldSetting + ']: ' + restoreError);
@@ -162,12 +196,11 @@ cr.define('pluginSettings', function() {
},
/**
- * @return {array} A list of all content setting rules for this plug-in.
+ * @return {!Array} A list of all content setting rules for this plug-in.
*/
getAll: function() {
- var length = window.localStorage.length;
var rules = [];
- for (var i = 0; i < length; i++) {
+ for (var i = 0; i < window.localStorage.length; i++) {
var key = window.localStorage.key(i);
var keyArray = JSON.parse(key);
if (keyArray[0] == this.plugin_) {
@@ -185,4 +218,3 @@ cr.define('pluginSettings', function() {
Settings: Settings,
}
});
-
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings_test.html b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings_test.html
new file mode 100644
index 0000000..7bcad36
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/plugin_settings_test.html
@@ -0,0 +1,143 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
+<script src="../domui/js/cr.js"></script>
+<script src="../domui/js/cr/event_target.js"></script>
+<script src="plugin_settings.js" type="text/javascript"></script>
+<script>
+goog.require('goog.testing.jsunit');
+</script>
+<script src="chrome_stubs.js" type="text/javascript"></script>
+</head>
+<body>
+<script>
+function testConstruction() {
+ var settings = createSettings();
+}
+
+function testSet() {
+ var settings = createSettings();
+ var rules = {
+ 'http://example.com/*': 'block',
+ 'http://google.com/*': 'allow',
+ 'http://moose.org/*': 'allow',
+ };
+ var numCallbacks = 0;
+ for (var pattern in rules) {
+ settings.set(pattern, rules[pattern], function(error) {
+ numCallbacks++;
+ assertUndefined(error);
+ });
+ }
+ assertEquals(Object.keys(rules).length, numCallbacks);
+ assertObjectEquals(rules, _rules);
+}
+
+function testSetInvalid() {
+ var settings = createSettings();
+ // Attempting to set an invalid pattern should return an error in the
+ // callback.
+ var callbackCalled = false;
+ settings.set('__invalid_pattern', 'block', function(error) {
+ callbackCalled = true;
+ assertEquals('Invalid pattern', error);
+ });
+ assertTrue(callbackCalled);
+ assertObjectEquals({}, _rules);
+
+ // Attempting to set an invalid setting should immediately throw an exception.
+ callbackCalled = false;
+ assertThrows(function() {
+ settings.set('http://example.com/*', '__invalid_setting', function() {
+ callbackCalled = true;
+ });
+ });
+ assertFalse(callbackCalled);
+ assertObjectEquals({}, _rules);
+}
+
+function testGet() {
+ var rules = {
+ 'http://example.com/*': 'block',
+ 'http://google.com/*': 'allow',
+ 'http://moose.org/*': 'allow',
+ };
+ var settings = createSettings(rules);
+ for (var pattern in rules)
+ assertEquals(rules[pattern], settings.get(pattern));
+}
+
+function testGetAll() {
+ var settings = createSettings({
+ 'http://example.com/*': 'block',
+ 'http://google.com/*': 'allow',
+ 'http://moose.org/*': 'allow',
+ });
+ var rules = settings.getAll();
+ // Sort the rules lexicographically by their pattern.
+ rules.sort(function(a, b) {
+ if (a.primaryPattern == b.primaryPattern) {
+ return 0;
+ }
+ if (a.primaryPattern > b.primaryPattern) {
+ return 1;
+ }
+ return -1;
+ });
+ assertEquals(3, rules.length);
+ assertObjectEquals({'primaryPattern': 'http://example.com/*',
+ 'setting': 'block'},
+ rules[0]);
+ assertObjectEquals({'primaryPattern': 'http://google.com/*',
+ 'setting': 'allow'},
+ rules[1]);
+ assertObjectEquals({'primaryPattern': 'http://moose.org/*',
+ 'setting': 'allow'},
+ rules[2]);
+}
+
+function testUpdate() {
+ var settings = createSettings({
+ 'http://example.com/*': 'block',
+ 'http://google.com/*': 'allow',
+ 'http://moose.org/*': 'allow',
+ });
+ var numCallbacks = 0;
+ settings.update('http://google.com/*', 'http://google.com/*', 'ask',
+ function(error) {
+ numCallbacks++;
+ assertUndefined(error);
+ });
+ assertEquals('ask', _rules['http://google.com/*']);
+
+ settings.update('http://google.com/*', 'http://blurp.net/*', 'ask',
+ function(error) {
+ numCallbacks++;
+ assertUndefined(error);
+ });
+ assertUndefined(_rules['http://google.com/*']);
+ assertEquals('ask', _rules['http://blurp.net/*']);
+
+ // Attempting to update a rule to an invalid pattern should return an error
+ // and leave the rules unchanged.
+ settings.update('http://example.com/*', '__invalid_pattern', 'ask',
+ function(error) {
+ numCallbacks++;
+ assertEquals('Invalid pattern', error);
+ });
+ assertUndefined(_rules['__invalid_pattern']);
+ assertEquals('block', _rules['http://example.com/*']);
+
+ assertEquals(3, numCallbacks);
+}
+
+function tearDown() {
+ // Clear local storage and |rules_| to make sure no state leaks into the next
+ // test.
+ window.localStorage.clear();
+ _rules = {};
+}
+</script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list.js b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list.js
index db83cee..9919958 100644
--- a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list.js
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list.js
@@ -1,23 +1,63 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 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.
+/**
+ * @fileoverview Defines a list of content setting rules.
+ */
+
cr.define('pluginSettings.ui', function() {
const InlineEditableItemList = options.InlineEditableItemList;
const InlineEditableItem = options.InlineEditableItem;
const ArrayDataModel = cr.ui.ArrayDataModel;
/**
- * Creates a new rule list item.
- * @param {RuleList} list The rule list containing this item.
- * @param {Object} rule The content setting rule.
+ * CSS classes used by this class.
+ * @enum {string}
+ */
+ const CSSClass = {
+ /**
+ * A list of content setting rules.
+ */
+ RULE_LIST: 'rule-list',
+
+ /**
+ * The element containing the content setting pattern for a rule.
+ */
+ RULE_PATTERN: 'rule-pattern',
+
+ /**
+ * The element containing the behavior (allow or block) for a rule.
+ */
+ RULE_BEHAVIOR: 'rule-behavior',
+
+ /**
+ * Static text (as opposed to an editable text field).
+ */
+ STATIC_TEXT: 'static-text',
+ };
+ /**
+ * A single item in a list of rules.
+ * @param {!RuleList} list The rule list containing this item.
+ * @param {!Object} rule The content setting rule.
* @constructor
* @extends {options.InlineEditableItem}
*/
function RuleListItem(list, rule) {
var el = cr.doc.createElement('li');
+ /**
+ * The content setting rule.
+ * @type {!Object}
+ * @private
+ */
el.dataItem_ = rule;
+
+ /**
+ * The rule list containing this item.
+ * @type {!RuleList}
+ * @private
+ */
el.list_ = list;
el.__proto__ = RuleListItem.prototype;
el.decorate();
@@ -29,63 +69,51 @@ cr.define('pluginSettings.ui', function() {
__proto__: InlineEditableItem.prototype,
/**
- * The content setting rule.
- * @type {Object}
- * @private
- */
- dataItem_: null,
-
- /**
- * The rule list containing this item.
- * @type {RuleList}
- * @private
- */
- list_: null,
-
- /**
- * The text input element for the pattern.
- * @type {HTMLInputElement}
+ * The text input element for the pattern. This is only null in the
+ * prototype.
+ * @type {?HTMLInputElement}
* @private
*/
input_: null,
/**
- * The popup button for the setting.
- * @type {HTMLSelectElement}
+ * The popup button for the setting. This is only null in the prototype.
+ * @type {?HTMLSelectElement}
* @private
*/
select_: null,
/**
* The static text field containing the pattern.
- * @type {HTMLDivElement}
+ * @type {?HTMLDivElement}
* @private
*/
patternLabel_: null,
/**
* The static text field containing the setting.
- * @type {HTMLDivElement}
+ * @type {?HTMLDivElement}
* @private
*/
settingLabel_: null,
/**
- * Called when an element is decorated as a list item.
+ * Decorates an elements as a list item.
*/
decorate: function() {
InlineEditableItem.prototype.decorate.call(this);
this.isPlaceholder = !this.pattern;
var patternCell = this.createEditableTextCell(this.pattern);
- patternCell.className = 'rule-pattern';
- patternCell.classList.add('weakrtl');
+ patternCell.className = CSSClass.RULE_PATTERN;
this.contentElement.appendChild(patternCell);
var input = patternCell.querySelector('input');
- if (this.pattern)
- this.patternLabel_ = patternCell.querySelector('.static-text');
- else
- input.placeholder = chrome.i18n.getMessage("addNewPattern");
+ if (this.pattern) {
+ this.patternLabel_ =
+ patternCell.querySelector('.' + CSSClass.STATIC_TEXT);
+ } else {
+ input.placeholder = chrome.i18n.getMessage('addNewPattern');
+ }
// TODO(stuartmorgan): Create an createEditableSelectCell abstracting
// this code.
@@ -94,7 +122,7 @@ cr.define('pluginSettings.ui', function() {
if (this.pattern) {
var settingLabel = cr.doc.createElement('span');
settingLabel.textContent = this.settingForDisplay();
- settingLabel.className = 'rule-behavior';
+ settingLabel.className = CSSClass.RULE_BEHAVIOR;
settingLabel.setAttribute('displaymode', 'static');
this.contentElement.appendChild(settingLabel);
this.settingLabel_ = settingLabel;
@@ -103,19 +131,20 @@ cr.define('pluginSettings.ui', function() {
// Setting select element for edit mode.
var select = cr.doc.createElement('select');
var optionAllow = cr.doc.createElement('option');
- optionAllow.textContent = chrome.i18n.getMessage("allowRule");
+ optionAllow.textContent = chrome.i18n.getMessage('allowRule');
optionAllow.value = 'allow';
select.appendChild(optionAllow);
var optionBlock = cr.doc.createElement('option');
- optionBlock.textContent = chrome.i18n.getMessage("blockRule");
+ optionBlock.textContent = chrome.i18n.getMessage('blockRule');
optionBlock.value = 'block';
select.appendChild(optionBlock);
this.contentElement.appendChild(select);
- select.className = 'rule-behavior';
- if (this.pattern)
+ select.className = CSSClass.RULE_BEHAVIOR;
+ if (this.pattern) {
select.setAttribute('displaymode', 'edit');
+ }
this.input_ = input;
this.select_ = select;
@@ -155,10 +184,12 @@ cr.define('pluginSettings.ui', function() {
*/
settingForDisplay: function() {
var setting = this.setting;
- if (setting == 'allow')
- return chrome.i18n.getMessage("allowRule");
- else if (setting == 'block')
- return chrome.i18n.getMessage("blockRule");
+ if (setting == 'allow') {
+ return chrome.i18n.getMessage('allowRule');
+ }
+ if (setting == 'block') {
+ return chrome.i18n.getMessage('blockRule');
+ }
},
/**
@@ -177,8 +208,9 @@ cr.define('pluginSettings.ui', function() {
var settingOption =
this.select_.querySelector('[value=\'' + this.setting + '\']');
- if (settingOption)
+ if (settingOption) {
settingOption.selected = true;
+ }
},
/** @inheritDoc */
@@ -190,7 +222,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Called when committing an edit.
- * @param {Event} e The end event.
+ * @param {!Event} e The end event.
* @private
*/
onEditCommitted_: function(e) {
@@ -202,7 +234,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Called when cancelling an edit; resets the control states.
- * @param {Event} e The cancel event.
+ * @param {!Event} e The cancel event.
* @private
*/
onEditCancelled_: function() {
@@ -228,7 +260,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Create a new list item to add a rule.
- * @param {RuleList} list The rule list containing this item.
+ * @param {!RuleList} list The rule list containing this item.
* @constructor
* @extends {AddRuleListItem}
*/
@@ -280,7 +312,7 @@ cr.define('pluginSettings.ui', function() {
};
/**
- * Creates a new rule list.
+ * A list of content setting rules.
* @constructor
* @extends {cr.ui.List}
*/
@@ -291,7 +323,7 @@ cr.define('pluginSettings.ui', function() {
/**
* The content settings model for this list.
- * @type {Settings}
+ * @type {?Settings}
*/
settings: null,
@@ -301,7 +333,7 @@ cr.define('pluginSettings.ui', function() {
decorate: function() {
InlineEditableItemList.prototype.decorate.call(this);
- this.classList.add('rule-list');
+ this.classList.add(CSSClass.RULE_LIST);
this.autoExpands = true;
this.reset();
@@ -309,7 +341,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Creates an item to go in the list.
- * @param {Object} entry The element from the data model for this row.
+ * @param {?Object} entry The element from the data model for this row.
*/
createItem: function(entry) {
if (entry) {
@@ -323,7 +355,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Sets the rules in the js model.
- * @param {Object} entries A list of dictionaries of values, each dictionary
+ * @param {!Array} entries A list of dictionaries of values, each dictionary
* represents a rule.
*/
setRules_: function(entries) {
@@ -341,16 +373,17 @@ cr.define('pluginSettings.ui', function() {
* @private
*/
settingsChanged_: function(error) {
- if (error)
+ if (error) {
$('error').textContent = 'Error: ' + error;
- else
+ } else {
$('error').textContent = '';
+ }
this.setRules_(this.settings.getAll());
},
/**
- * @return {function()} A bound callback to update the UI after the settings
- * have been changed.
+ * @return {function()} A bound callback to update the UI after the
+ * settings have been changed.
*/
settingsChangedCallback: function() {
return this.settingsChanged_.bind(this);
@@ -358,7 +391,7 @@ cr.define('pluginSettings.ui', function() {
/**
* Binds this list to the content settings model.
- * @param {Settings} settings The content settings model.
+ * @param {!Settings} settings The content settings model.
*/
setPluginSettings: function(settings) {
this.settings = settings;
@@ -376,8 +409,9 @@ cr.define('pluginSettings.ui', function() {
/** @inheritDoc */
deleteItemAtIndex: function(index) {
var listItem = this.getListItemByIndex(index);
- if (listItem.undeletable)
+ if (listItem.undeletable) {
return;
+ }
this.settings.clear(listItem.pattern, this.settingsChangedCallback());
},
@@ -389,4 +423,3 @@ cr.define('pluginSettings.ui', function() {
RuleList: RuleList,
}
});
-
diff --git a/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list_test.html b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list_test.html
new file mode 100644
index 0000000..fee89f5
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/plugin_settings/js/rule_list_test.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+<link rel="stylesheet" href="../domui/css/button.css">
+<link rel="stylesheet" href="../domui/css/chrome_shared.css">
+<link rel="stylesheet" href="../domui/css/list.css">
+<link rel="stylesheet" href="../domui/css/select.css">
+
+<link rel="stylesheet" href="../options/css/list.css">
+
+<link rel="stylesheet" href="../css/rule_list.css">
+
+<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
+<script src="../domui/js/cr.js"></script>
+<script src="../domui/js/cr/event_target.js"></script>
+<script src="../domui/js/cr/ui.js"></script>
+<script src="../domui/js/cr/ui/array_data_model.js"></script>
+<script src="../domui/js/cr/ui/list_item.js"></script>
+<script src="../domui/js/cr/ui/list_selection_controller.js"></script>
+<script src="../domui/js/cr/ui/list_selection_model.js"></script>
+<script src="../domui/js/cr/ui/list_single_selection_model.js"></script>
+<script src="../domui/js/cr/ui/list.js"></script>
+<script src="../domui/js/util.js"></script>
+
+<script src="../options/js/deletable_item_list.js"></script>
+<script src="../options/js/inline_editable_list.js"></script>
+
+<script src="plugin_settings.js" type="text/javascript"></script>
+<script src="rule_list.js" type="text/javascript"></script>
+
+<script>
+goog.require('goog.testing.jsunit');
+</script>
+<script src="chrome_stubs.js" type="text/javascript"></script>
+</head>
+<body>
+<list id="rule-list"></list>
+<div id="error"></div>
+<script>
+function testConstruction() {
+ var rulesEl = document.createElement('list');
+ document.body.appendChild(rulesEl);
+ pluginSettings.ui.RuleList.decorate(rulesEl);
+ var rules = {
+ 'http://example.com/*': 'block',
+ 'http://moose.org/*': 'allow',
+ };
+ rulesEl.setPluginSettings(createSettings(rules));
+ var ruleElements = rulesEl.querySelectorAll('[role=listitem]');
+ assertEquals(3, ruleElements.length);
+ assertEquals('http://example.com/*',
+ ruleElements[0].querySelector('.rule-pattern').textContent);
+ assertEquals('http://moose.org/*',
+ ruleElements[1].querySelector('.rule-pattern').textContent);
+ assertEquals('', ruleElements[2].querySelector('.rule-pattern').textContent);
+ assertEquals('Block',
+ ruleElements[0].querySelector('.rule-behavior').textContent);
+ assertEquals('Allow',
+ ruleElements[1].querySelector('.rule-behavior').textContent);
+ assertEquals('allow', ruleElements[2].querySelector('.rule-behavior').value);
+}
+</script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/experimental.html b/chrome/common/extensions/docs/experimental.html
index c757619..0f64673 100644
--- a/chrome/common/extensions/docs/experimental.html
+++ b/chrome/common/extensions/docs/experimental.html
@@ -397,7 +397,6 @@ on the following experimental APIs:
<a href="experimental.devtools.audits.html">experimental.devtools.audits</a></li><li>
<a href="experimental.devtools.console.html">experimental.devtools.console</a></li><li>
<a href="experimental.infobars.html">experimental.infobars</a></li><li>
- <a href="experimental.privacy.html">experimental.privacy</a></li><li>
<a href="experimental.speechInput.html">experimental.speechInput</a></li>
</ul>
diff --git a/chrome/common/extensions/docs/samples.html b/chrome/common/extensions/docs/samples.html
index 325077c..7227b75 100644
--- a/chrome/common/extensions/docs/samples.html
+++ b/chrome/common/extensions/docs/samples.html
@@ -3309,14 +3309,22 @@
</li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/domui/js/util.js">domui/js/util.js</a></code>
</li><li>
+ <code><a target="_blank" href="examples/extensions/plugin_settings/js/chrome_stubs.js">js/chrome_stubs.js</a></code>
+ </li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/js/main.js">js/main.js</a></code>
</li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/js/plugin_list.js">js/plugin_list.js</a></code>
</li><li>
+ <code><a target="_blank" href="examples/extensions/plugin_settings/js/plugin_list_test.html">js/plugin_list_test.html</a></code>
+ </li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/js/plugin_settings.js">js/plugin_settings.js</a></code>
</li><li>
+ <code><a target="_blank" href="examples/extensions/plugin_settings/js/plugin_settings_test.html">js/plugin_settings_test.html</a></code>
+ </li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/js/rule_list.js">js/rule_list.js</a></code>
</li><li>
+ <code><a target="_blank" href="examples/extensions/plugin_settings/js/rule_list_test.html">js/rule_list_test.html</a></code>
+ </li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/manifest.json">manifest.json</a></code>
</li><li>
<code><a target="_blank" href="examples/extensions/plugin_settings/options.html">options.html</a></code>
diff --git a/chrome/common/extensions/docs/samples.json b/chrome/common/extensions/docs/samples.json
index 9191245..4f3c1c6 100644
--- a/chrome/common/extensions/docs/samples.json
+++ b/chrome/common/extensions/docs/samples.json
@@ -1845,17 +1845,21 @@
"domui\/js\/cr\/ui\/list_selection_model.js",
"domui\/js\/cr\/ui\/list_single_selection_model.js",
"domui\/js\/util.js",
+ "js\/chrome_stubs.js",
"js\/main.js",
"js\/plugin_list.js",
+ "js\/plugin_list_test.html",
"js\/plugin_settings.js",
+ "js\/plugin_settings_test.html",
"js\/rule_list.js",
+ "js\/rule_list_test.html",
"manifest.json",
"options.html",
"options\/css\/list.css",
"options\/js\/deletable_item_list.js",
"options\/js\/inline_editable_list.js"
],
- "source_hash": "914933e586fe84d71ba8b01c88309288b9d4e515",
+ "source_hash": "5091cd6db218262813b6d98264cf580c6469ce23",
"zip_path": "examples\/extensions\/plugin_settings.zip"
},
{