summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions
diff options
context:
space:
mode:
authorKristian Monsen <kristianm@google.com>2011-06-28 21:49:31 +0100
committerKristian Monsen <kristianm@google.com>2011-07-08 17:55:00 +0100
commitddb351dbec246cf1fab5ec20d2d5520909041de1 (patch)
tree158e3fb57bdcac07c7f1e767fde3c70687c9fbb1 /chrome/common/extensions
parent6b92e04f5f151c896e3088e86f70db7081009308 (diff)
downloadexternal_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.zip
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.gz
external_chromium-ddb351dbec246cf1fab5ec20d2d5520909041de1.tar.bz2
Merge Chromium at r12.0.742.93: Initial merge by git
Change-Id: Ic5ee2fec31358bbee305f7e915442377bfa6cda6
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r--chrome/common/extensions/api/extension_api.json658
-rw-r--r--chrome/common/extensions/docs/api_index.html15
-rw-r--r--chrome/common/extensions/docs/apps.html12
-rw-r--r--chrome/common/extensions/docs/bookmarks.html7
-rw-r--r--chrome/common/extensions/docs/build/directory.py3
-rw-r--r--chrome/common/extensions/docs/content_scripts.html4
-rw-r--r--chrome/common/extensions/docs/contextMenus.html16
-rw-r--r--chrome/common/extensions/docs/cookies.html78
-rw-r--r--chrome/common/extensions/docs/docs.html3
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess.zipbin0 -> 7716 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json15
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/popup.html39
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-128.pngbin0 -> 2192 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-16.pngbin0 -> 591 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-19.pngbin0 -> 272 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-48.pngbin0 -> 879 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample.css61
-rw-r--r--chrome/common/extensions/docs/examples/api/preferences/enableReferrer.zipbin0 -> 7276 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/preferences/enableReferrer/advicedog.jpgbin0 -> 2518 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json10
-rw-r--r--chrome/common/extensions/docs/examples/api/preferences/enableReferrer/popup.html129
-rw-r--r--chrome/common/extensions/docs/examples/api/tabs/pin.zipbin0 -> 2153 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/tabs/pin/README2
-rw-r--r--chrome/common/extensions/docs/examples/api/tabs/pin/background.html22
-rw-r--r--chrome/common/extensions/docs/examples/api/tabs/pin/inject.js13
-rw-r--r--chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json15
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic.zipbin0 -> 22569 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json52
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html29
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.pngbin0 -> 3789 bytes
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json16
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js371
-rw-r--r--chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html103
-rw-r--r--chrome/common/extensions/docs/examples/extensions/imageinfo.zipbin45362 -> 45362 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration.zipbin0 -> 144472 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json50
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/background.html29
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon128.pngbin0 -> 5343 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon16.pngbin0 -> 588 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon32.pngbin0 -> 772 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon48.pngbin0 -> 1644 bytes
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json21
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/popup.html300
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_error_handler.js105
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js778
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/jsunittest.js964
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.html113
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.js519
-rw-r--r--chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/unittest.css58
-rw-r--r--chrome/common/extensions/docs/experimental.contentSettings.misc.html152
-rw-r--r--chrome/common/extensions/docs/experimental.debugger.html1559
-rw-r--r--chrome/common/extensions/docs/experimental.extension.html373
-rw-r--r--chrome/common/extensions/docs/experimental.html5
-rw-r--r--chrome/common/extensions/docs/experimental.webInspector.audits.html65
-rw-r--r--chrome/common/extensions/docs/experimental.webInspector.html586
-rw-r--r--chrome/common/extensions/docs/experimental.webInspector.panels.html60
-rw-r--r--chrome/common/extensions/docs/experimental.webInspector.resources.html57
-rw-r--r--chrome/common/extensions/docs/experimental.webNavigation.html39
-rw-r--r--chrome/common/extensions/docs/experimental.webRequest.html620
-rw-r--r--chrome/common/extensions/docs/extension.html396
-rw-r--r--chrome/common/extensions/docs/i18n.html12
-rw-r--r--chrome/common/extensions/docs/images/devtools-audits-category.pngbin0 -> 28263 bytes
-rw-r--r--chrome/common/extensions/docs/images/devtools-audits-results.pngbin0 -> 13979 bytes
-rw-r--r--chrome/common/extensions/docs/images/devtools-panels.pngbin0 -> 30565 bytes
-rw-r--r--chrome/common/extensions/docs/images/index/gmail.pngbin4548 -> 0 bytes
-rw-r--r--chrome/common/extensions/docs/images/index/news.pngbin7300 -> 0 bytes
-rw-r--r--chrome/common/extensions/docs/images/index/rss.pngbin2491 -> 0 bytes
-rw-r--r--chrome/common/extensions/docs/images/intermediate/README.txt7
-rw-r--r--chrome/common/extensions/docs/images/overview/arch-1.gif (renamed from chrome/common/extensions/docs/images/arch-1.gif)bin8028 -> 8028 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/arch-2.gif (renamed from chrome/common/extensions/docs/images/arch-2.gif)bin3877 -> 3877 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/arch-3.gif (renamed from chrome/common/extensions/docs/images/arch-3.gif)bin3388 -> 3388 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/arch-cs.gif (renamed from chrome/common/extensions/docs/images/arch-cs.gif)bin5183 -> 5183 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/browser-action-with-popup.pngbin0 -> 9763 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/browser-action.pngbin0 -> 7632 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/flash-app.png (renamed from chrome/common/extensions/docs/images/index/flashapp.png)bin82340 -> 82340 bytes
-rw-r--r--chrome/common/extensions/docs/images/overview/page-action.pngbin0 -> 7756 bytes
-rw-r--r--chrome/common/extensions/docs/index.html2
-rw-r--r--chrome/common/extensions/docs/js/api_page_generator.js50
-rw-r--r--chrome/common/extensions/docs/management.html68
-rw-r--r--chrome/common/extensions/docs/override.html48
-rw-r--r--chrome/common/extensions/docs/overview.html126
-rw-r--r--chrome/common/extensions/docs/permission_warnings.html13
-rw-r--r--chrome/common/extensions/docs/samples.html270
-rw-r--r--chrome/common/extensions/docs/samples.json2515
-rw-r--r--chrome/common/extensions/docs/static/api_index.html15
-rw-r--r--chrome/common/extensions/docs/static/apps.html12
-rw-r--r--chrome/common/extensions/docs/static/bookmarks.html7
-rw-r--r--chrome/common/extensions/docs/static/content_scripts.html4
-rw-r--r--chrome/common/extensions/docs/static/docs.html3
-rw-r--r--chrome/common/extensions/docs/static/experimental.debugger.html24
-rw-r--r--chrome/common/extensions/docs/static/experimental.webInspector.audits.html65
-rw-r--r--chrome/common/extensions/docs/static/experimental.webInspector.html77
-rw-r--r--chrome/common/extensions/docs/static/experimental.webInspector.panels.html50
-rw-r--r--chrome/common/extensions/docs/static/experimental.webInspector.resources.html44
-rw-r--r--chrome/common/extensions/docs/static/experimental.webNavigation.html23
-rw-r--r--chrome/common/extensions/docs/static/experimental.webRequest.html22
-rw-r--r--chrome/common/extensions/docs/static/i18n.html12
-rw-r--r--chrome/common/extensions/docs/static/index.html2
-rw-r--r--chrome/common/extensions/docs/static/override.html42
-rw-r--r--chrome/common/extensions/docs/static/overview.html132
-rw-r--r--chrome/common/extensions/docs/static/permission_warnings.html13
-rw-r--r--chrome/common/extensions/docs/static/themes.html8
-rw-r--r--chrome/common/extensions/docs/static/whats_new.html69
-rw-r--r--chrome/common/extensions/docs/tabs.html6
-rw-r--r--chrome/common/extensions/docs/themes.html8
-rw-r--r--chrome/common/extensions/docs/whats_new.html69
-rw-r--r--chrome/common/extensions/docs/windows.html78
-rw-r--r--chrome/common/extensions/extension.cc784
-rw-r--r--chrome/common/extensions/extension.h234
-rw-r--r--chrome/common/extensions/extension_constants.cc40
-rw-r--r--chrome/common/extensions/extension_constants.h27
-rw-r--r--chrome/common/extensions/extension_file_util.cc16
-rw-r--r--chrome/common/extensions/extension_file_util.h3
-rw-r--r--chrome/common/extensions/extension_file_util_unittest.cc14
-rw-r--r--chrome/common/extensions/extension_l10n_util.cc21
-rw-r--r--chrome/common/extensions/extension_l10n_util_unittest.cc42
-rw-r--r--chrome/common/extensions/extension_localization_peer.cc15
-rw-r--r--chrome/common/extensions/extension_localization_peer.h6
-rw-r--r--chrome/common/extensions/extension_localization_peer_unittest.cc18
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc78
-rw-r--r--chrome/common/extensions/extension_message_bundle.cc8
-rw-r--r--chrome/common/extensions/extension_message_bundle.h6
-rw-r--r--chrome/common/extensions/extension_message_bundle_unittest.cc6
-rw-r--r--chrome/common/extensions/extension_messages.cc149
-rw-r--r--chrome/common/extensions/extension_messages.h285
-rw-r--r--chrome/common/extensions/extension_resource.cc16
-rw-r--r--chrome/common/extensions/extension_resource.h5
-rw-r--r--chrome/common/extensions/extension_resource_unittest.cc4
-rw-r--r--chrome/common/extensions/extension_set.h2
-rw-r--r--chrome/common/extensions/extension_set_unittest.cc10
-rw-r--r--chrome/common/extensions/extension_unittest.cc539
-rw-r--r--chrome/common/extensions/extension_unpacker.cc13
-rw-r--r--chrome/common/extensions/extension_unpacker.h4
-rw-r--r--chrome/common/extensions/extension_unpacker_unittest.cc17
-rw-r--r--chrome/common/extensions/file_browser_handler.cc32
-rw-r--r--chrome/common/extensions/file_browser_handler.h64
-rw-r--r--chrome/common/extensions/update_manifest.cc4
-rw-r--r--chrome/common/extensions/update_manifest_unittest.cc4
-rw-r--r--chrome/common/extensions/url_pattern.cc12
-rw-r--r--chrome/common/extensions/url_pattern.h15
-rw-r--r--chrome/common/extensions/url_pattern_unittest.cc4
-rw-r--r--chrome/common/extensions/user_script.cc19
-rw-r--r--chrome/common/extensions/user_script.h9
143 files changed, 13057 insertions, 1886 deletions
diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json
index d23f1ae..04389d0 100644
--- a/chrome/common/extensions/api/extension_api.json
+++ b/chrome/common/extensions/api/extension_api.json
@@ -191,6 +191,44 @@
}
},
{
+ "name": "isAllowedIncognitoAccess",
+ "type": "function",
+ "description": "Retrieves the state of the extension's access to Incognito-mode (as determined by the user-controlled 'Allowed in Incognito' checkbox.",
+ "min_version": "12.0.706.0",
+ "parameters": [
+ {
+ "type": "function",
+ "name": "callback",
+ "parameters": [
+ {
+ "name": "isAllowedAccess",
+ "type": "boolean",
+ "description": "True if the extension has access to Incognito mode, false otherwise."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "isAllowedFileSchemeAccess",
+ "type": "function",
+ "description": "Retrieves the state of the extension's access to the 'file://' scheme (as determined by the user-controlled 'Allow access to File URLs' checkbox.",
+ "min_version": "12.0.706.0",
+ "parameters": [
+ {
+ "type": "function",
+ "name": "callback",
+ "parameters": [
+ {
+ "name": "isAllowedAccess",
+ "type": "boolean",
+ "description": "True if the extension can access the 'file://' scheme, false otherwise."
+ }
+ ]
+ }
+ ]
+ },
+ {
"name": "setUpdateUrlData",
"type": "function",
"description": "Sets the value of the ap CGI parameter used in the extension's update URL. This value is ignored for extensions that are hosted in the Chrome Extension Gallery.",
@@ -680,8 +718,8 @@
"incognito": {"type": "boolean", "description": "Whether the window is incognito."},
"type": {
"type": "string",
- "description": "The type of browser window this is.",
- "enum": ["normal", "popup", "app"]
+ "description": "The type of browser window this is. The 'panel' type requires the 'experimental' permission.",
+ "enum": ["normal", "popup", "panel", "app"]
}
}
}
@@ -791,12 +829,13 @@
"top": {"type": "integer", "optional": true, "description": "The number of pixels to position the new window from the top edge of the screen. If not specified, the new window is offset naturally from the last focusd window."},
"width": {"type": "integer", "minimum": 0, "optional": true, "description": "The width in pixels of the new window. If not specified defaults to a natural width."},
"height": {"type": "integer", "minimum": 0, "optional": true, "description": "The height in pixels of the new window. If not specified defaults to a natural height."},
+ "focused": {"type": "boolean", "optional": true, "description": "If true, opens an active window. If false, opens an inactive window."},
"incognito": {"type": "boolean", "optional": true, "description": "Whether the new window should be an incognito window."},
"type": {
"type": "string",
"optional": true,
- "description": "Specifies what type of browser window to create.",
- "enum": ["normal", "popup"]
+ "description": "Specifies what type of browser window to create. The 'panel' type requires the 'experimental' permission.",
+ "enum": ["normal", "popup", "panel"]
}
},
"optional": true
@@ -828,7 +867,7 @@
"top": {"type": "integer", "optional": true, "description": "The offset from the top edge of the screen to move the window to in pixels."},
"width": {"type": "integer", "minimum": 0, "optional": true, "description": "The width to resize the window to in pixels."},
"height": {"type": "integer", "minimum": 0, "optional": true, "description": "The height to resize the window to in pixels."},
- "focused": {"type": "boolean", "optional": true, "description": "It true, brings the window to the front. If false, brings the next window in the z-order to the front."}
+ "focused": {"type": "boolean", "optional": true, "description": "If true, brings the window to the front. If false, brings the next window in the z-order to the front."}
}
},
{
@@ -1202,7 +1241,7 @@
{
"name": "captureVisibleTab",
"type": "function",
- "description": "Captures the visible area of the currently selected tab in the specified window.",
+ "description": "Captures the visible area of the currently selected tab in the specified window. You must have <a href='manifest.html#permissions'>host permission</a> for the URL displayed by the tab.",
"parameters": [
{
"type": "integer",
@@ -1215,7 +1254,6 @@
"type": "object",
"name": "options",
"optional": true,
- "min_version": "5.0.372.0",
"description": "Set parameters of image capture, such as the format of the resulting image.",
"properties": {
"format": {
@@ -2777,12 +2815,13 @@
"properties": {
"type": {
"type": "string",
+ "enum": ["normal", "checkbox", "radio", "separator"],
"optional": true,
- "description": "The type of menu item - one of 'normal', 'checkbox', 'radio', or 'separator'. Defaults to 'normal' if not specified."
+ "description": "The type of menu item. Defaults to 'normal' if not specified."
},
"title": {
"type": "string",
- "optional": "true",
+ "optional": true,
"description": "The text to be displayed in the item; this is <em>required</em> unless <em>type</em> is 'separator'. When the context is 'selection', you can use <code>%s</code> within the string to show the selected text. For example, if this parameter's value is \"Translate '%s' to Pig Latin\" and the user selects the word \"cool\", the context menu item for the selection is \"Translate 'cool' to Pig Latin\"."
},
"checked": {
@@ -2792,10 +2831,13 @@
},
"contexts": {
"type": "array",
- "items": {"type": "string"},
+ "items": {
+ "type": "string",
+ "enum": ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"]
+ },
"minItems": 1,
"optional": true,
- "description": "List of contexts this menu item will appear in. Legal values are: 'all', 'page', 'selection', 'link', 'editable', 'image', 'video', and 'audio'. Defaults to ['page']."
+ "description": "List of contexts this menu item will appear in. Defaults to ['page'] if not specified."
},
"onclick": {
"type": "function",
@@ -2859,11 +2901,12 @@
"properties": {
"type": {
"type": "string",
+ "enum": ["normal", "checkbox", "radio", "separator"],
"optional": true
},
"title": {
"type": "string",
- "optional": "true"
+ "optional": true
},
"checked": {
"type": "boolean",
@@ -2871,7 +2914,10 @@
},
"contexts": {
"type": "array",
- "items": {"type": "string"},
+ "items": {
+ "type": "string",
+ "enum": ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"]
+ },
"minItems": 1,
"optional": true
},
@@ -3080,6 +3126,39 @@
"events": []
},
{
+ "namespace": "chromeosInfoPrivate",
+ "nodoc": "true",
+ "functions": [
+ {
+ "name": "get",
+ "description": "Fetches customization values for the given property names. See property names in the declaration of the returned dictionary.",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "propertyNames",
+ "type": "array",
+ "item": {"type": "string", "description": "Chrome OS Property name"}
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "propertiesDictionary",
+ "type": "object",
+ "description": "Dictionary which contains all requested properties",
+ "properties": {
+ "hwid": {"type": "string", "optional": "true", "description": "Hardware ID"},
+ "homeProvider" : {"type": "string", "optional": "true", "description": "Home provider which is used by the cellular device"}
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ },
+ {
"namespace": "cookies",
"types": [
{
@@ -3191,6 +3270,7 @@
"type": "function",
"name": "callback",
"optional": true,
+ "min_version": "11.0.674.0",
"parameters": [
{
"name": "cookie", "$ref": "Cookie", "optional": true, "description": "Contains details about the cookie that's been set. If setting failed for any reason, this will be \"null\", and \"chrome.extension.lastError\" will be set."
@@ -3218,6 +3298,7 @@
"type": "function",
"name": "callback",
"optional": true,
+ "min_version": "11.0.674.0",
"parameters": [
{
"name": "details",
@@ -3255,14 +3336,15 @@
{
"name": "onChanged",
"type": "function",
- "description": "Fired when a cookie is set or removed.",
+ "description": "Fired when a cookie is set or removed. As a special case, note that updating a cookie's properties is implemented as a two step process: the cookie to be updated is first removed entirely, generating a notification with \"cause\" of \"overwrite\" . Afterwards, a new cookie is written with the updated values, generating a second notification with \"cause\" \"explicit\".",
"parameters": [
{
"type": "object",
"name": "changeInfo",
"properties": {
"removed": {"type": "boolean", "description": "True if a cookie was removed."},
- "cookie": {"$ref": "Cookie", "description": "Information about the cookie that was set or removed."}
+ "cookie": {"$ref": "Cookie", "description": "Information about the cookie that was set or removed."},
+ "cause": {"min_version": "12.0.707.0", "type": "string", "enum": ["evicted", "expired", "explicit", "expired_overwrite", "overwrite"], "description": "The underlying reason behind the cookie's change. If a cookie was inserted, or removed via an explicit call to \"chrome.cookies.remove\", \"cause\" will be \"explicit\". If a cookie was automatically removed due to expiry, \"cause\" will be \"expired\". If a cookie was removed due to being overwritten with an already-expired expiration date, \"cause\" will be set to \"expired_overwrite\". If a cookie was automatically removed due to garbage collection, \"cause\" will be \"evicted\". If a cookie was automatically removed due to a \"set\" call that overwrote it, \"cause\" will be \"overwrite\". Plan your response accordingly."}
}
}
]
@@ -3337,7 +3419,7 @@
"tabId": {"type": "integer", "description": "The ID of the tab in which the navigation is about to occur."},
"url": {"type": "string"},
"frameId": {"type": "integer", "description": "0 indicates the navigation happens in the tab content window; positive value indicates navigation in a subframe. Frame IDs are unique within a tab."},
- "requestId": {"type": "integer", "description": "The ID of the request to retrieve the document of this navigation. Note that this event is fired prior to the corresponding chrome.experimental.webRequest.onBeforeRequest."},
+ "requestId": {"type": "string", "description": "The ID of the request to retrieve the document of this navigation. Note that this event is fired prior to the corresponding chrome.experimental.webRequest.onBeforeRequest."},
"timeStamp": {"type": "number", "description": "The time when the browser was about to start the navigation, in milliseconds since the epoch."}
}
}
@@ -3456,6 +3538,23 @@
"tabId": { "type": "integer", "optional": true },
"windowId": { "type": "integer", "optional": true }
}
+ },
+ {
+ "id": "BlockingResponse",
+ "type": "object",
+ "description": "Return value for event handlers that have the 'blocking' extraInfoSpec applied. Allows the event handler to modify network requests.",
+ "properties": {
+ "cancel": {
+ "type": "boolean",
+ "optional": true,
+ "description": "If true, the request is cancelled. Used in onBeforeRequest, this prevents the request from being sent."
+ },
+ "redirectUrl": {
+ "type": "string",
+ "optional": true,
+ "description": "If set, the original request is prevented from being sent and is instead redirected to the given URL."
+ }
+ }
}
],
"functions": [
@@ -3479,12 +3578,28 @@
"description": "Array of extra information that should be passed to the listener function.",
"items": {
"type": "string",
- "enum": ["requestLine", "requestHeaders", "statusLine", "responseHeaders", "redirectRequestLine", "redirectRequestHeaders"]
+ "enum": ["requestLine", "requestHeaders", "statusLine", "responseHeaders", "redirectRequestLine", "redirectRequestHeaders", "blocking"]
}
},
{"type": "string", "name": "eventName"},
{"type": "string", "name": "subEventName"}
]
+ },
+ {
+ "name": "eventHandled",
+ "nodoc": true,
+ "type": "function",
+ "description": "Used internally to send a response for a blocked event.",
+ "parameters": [
+ {"type": "string", "name": "eventName"},
+ {"type": "string", "name": "subEventName"},
+ {"type": "string", "name": "requestId"},
+ {
+ "$ref": "BlockingResponse",
+ "optional": true,
+ "name": "response"
+ }
+ ]
}
],
"events": [
@@ -3497,7 +3612,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request."},
+ "requestId": {"type": "string", "description": "The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request."},
"url": {"type": "string"},
"method": {"type": "string", "description": "Standard HTTP method."},
"tabId": {"type": "integer", "description": "The ID of the tab in which the request takes place. Set to null if the request isn't related to a tab."},
@@ -3508,6 +3623,22 @@
]
},
{
+ "name": "onBeforeSendHeaders",
+ "type": "function",
+ "description": "Fires before sending an HTTP request, once the request headers are available.",
+ "parameters": [
+ {
+ "type": "object",
+ "name": "details",
+ "properties": {
+ "requestId": {"type": "string", "description": "The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request."},
+ "url": {"type": "string"},
+ "timeStamp": {"type": "number", "description": "The time when the browser was about to send headers, in milliseconds since the epoch."}
+ }
+ }
+ ]
+ },
+ {
"name": "onRequestSent",
"type": "function",
"description": "Fires when a request is sent to the server.",
@@ -3516,7 +3647,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request."},
+ "requestId": {"type": "string", "description": "The ID of the request."},
"url": {"type": "string"},
"ip": {"type": "string", "description": "The server IP address that is actually connected to. Note that it may be a literal IPv6 address."},
"timeStamp": {"type": "number", "description": "The time when the browser finished sending the request, in milliseconds since the epoch."}
@@ -3533,7 +3664,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request."},
+ "requestId": {"type": "string", "description": "The ID of the request."},
"url": {"type": "string"},
"statusCode": {"type": "integer", "description": "Standard HTTP status code returned by the server."},
"timeStamp": {"type": "number", "description": "The time when the status line and response headers were received, in milliseconds since the epoch."}
@@ -3550,7 +3681,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request."},
+ "requestId": {"type": "string", "description": "The ID of the request."},
"url": {"type": "string", "description": "The URL of the current request."},
"statusCode": {"type": "integer", "description": "Standard HTTP status code returned by the server."},
"redirectUrl": {"type": "string", "description": "The new URL."},
@@ -3568,7 +3699,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request."},
+ "requestId": {"type": "string", "description": "The ID of the request."},
"url": {"type": "string", "description": "The URL of the current request."},
"statusCode": {"type": "integer", "description": "Standard HTTP status code returned by the server."},
"timeStamp": {"type": "number", "description": "The time when the response was received completely, in milliseconds since the epoch."}
@@ -3585,7 +3716,7 @@
"type": "object",
"name": "details",
"properties": {
- "requestId": {"type": "integer", "description": "The ID of the request."},
+ "requestId": {"type": "string", "description": "The ID of the request."},
"url": {"type": "string", "description": "The URL of the current request."},
"error": {"type": "string", "description": "The error description."},
"timeStamp": {"type": "number", "description": "The time when the error occurred, in milliseconds since the epoch."}
@@ -3760,11 +3891,7 @@
"description": "Proxy settings to be used. The value of this preference is a ProxyConfig object.",
"value": [
"proxy",
- {"$ref": "ProxyConfig"},
- {
- "get": "experimental.proxy.get",
- "set": "experimental.proxy.set"
- }
+ {"$ref": "ProxyConfig"}
]
}
},
@@ -4216,6 +4343,10 @@
"description": "The <a href='manifest.html#version'>version</a> of this extension or app.",
"type": "string"
},
+ "mayDisable": {
+ "description": "Whether this extension can be disabled or uninstalled by the user.",
+ "type": "boolean"
+ },
"enabled": {
"description": "Whether it is currently enabled or disabled.",
"type": "boolean"
@@ -4396,7 +4527,266 @@
}
]
},
-
+ {
+ "namespace":"fileBrowserHandler",
+ "nodoc": "true",
+ "types": [
+ {
+ "id": "FileHandlerExecuteEventDetails",
+ "type": "object",
+ "description": "Event details payload for fileBrowserHandler.onExecute event.",
+ "properties": {
+ "entries": {
+ "type": "any",
+ "description": "Array of Entry instances representing files that are targets of this action (selected in ChromeOS file browser)."
+ },
+ "tab_id" : {
+ "type": "integer",
+ "optional": true,
+ "description": "The ID of the tab that raised this event. Tab IDs are unique within a browser session."
+ }
+ }
+ }
+ ],
+ "events": [
+ {
+ "name": "onExecute",
+ "type": "function",
+ "description": "Fired when file system action is executed from ChromeOS file browser.",
+ "parameters": [
+ {
+ "name": "id",
+ "type": "string",
+ "description": "File browser action id as specified in the listener component's manifest."
+ },
+ {
+ "name": "details",
+ "$ref": "FileHandlerExecuteEventDetails",
+ "description": "File handler execute event details."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "namespace":"fileBrowserPrivate",
+ "nodoc": "true",
+ "types": [
+ {
+ "id": "FileBrowserTask",
+ "type": "object",
+ "description": "Represents information about available browser tasks. A task is an abstraction of an operation that the file browser can perform over a selected file set.",
+ "properties": {
+ "taskId": {"type": "string", "description": "The unique identifier of the task."},
+ "title": {"type": "string", "description": "Task title."},
+ "iconUrl": {"type": "string", "description": "Task icon url (from chrome://extension-icon/...)"}
+ }
+ },
+ {
+ "id": "VolumeInfo",
+ "type": "object",
+ "description": "Mounted disk volume information.",
+ "properties": {
+ "mountPath": {
+ "type": "string",
+ "description": "Disk volume mount point path. The value corresponds to its Entry.fullPath in File API."
+ },
+ "label": {
+ "type": "string",
+ "description": "Volume label."
+ },
+ "deviceType": {
+ "type": "string",
+ "enum": ["flash", "hdd", "optical", "undefined"],
+ "description": "Device type."
+ },
+ "readOnly": {
+ "type": "boolean",
+ "description": "Flag that specifies if volume is mounted in read-only mode."
+ },
+ "totalSizeKB": {
+ "type": "integer",
+ "description": "Total disk volume size in KBs"
+ }
+ }
+ },
+ {
+ "id": "MountEvent",
+ "type": "object",
+ "description": "Payload data for disk mount / unmount event.",
+ "properties": {
+ "eventType": {
+ "type": "string",
+ "enum": ["added", "removed"],
+ "description": "Event type that tells listeners which disk volume even was raised."
+ },
+ "volumeInfo": {
+ "$ref": "VolumeInfo",
+ "description":"Volume information that this mount event applies to."
+ }
+ }
+ }
+ ],
+ "functions": [
+ {
+ "name": "cancelDialog",
+ "type": "function",
+ "description": "Cancel file selection.",
+ "parameters": []
+ },
+ {
+ "name": "executeTask",
+ "description": "Executes file browser task over selected files",
+ "parameters": [
+ {
+ "name": "taskId",
+ "type": "string",
+ "description": "The unique identifier of task to execute."
+ },
+ {
+ "name": "fileURLs",
+ "type": "array",
+ "description": "Array of file URLs",
+ "items": { "type": "string" }
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "optional": "false",
+ "parameters": [
+ {
+ "name": "success",
+ "type": "boolean",
+ "optional": "true",
+ "description": "True of task execution was successfully initiated."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "getFileTasks",
+ "description": "Gets the of tasks that can be performed over selected files.",
+ "parameters": [
+ {
+ "name": "fileURLs",
+ "type": "array",
+ "description": "Array of selected file URLs",
+ "items": { "type": "string" }
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "optional": "false",
+ "parameters": [
+ {
+ "name": "tasks",
+ "type": "array",
+ "items": {"$ref": "FileBrowserTask"},
+ "description": "The list of available tasks that can be performed on all of the passed file paths."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "getStrings",
+ "type": "function",
+ "description": "Get Strings.",
+ "parameters": [
+ {
+ "type": "function",
+ "name": "callback",
+ "parameters": [
+ {
+ "type": "object",
+ "properties": {},
+ "additionalProperties": {"type": "string"}
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "requestLocalFileSystem",
+ "description": "Requests access to local file system",
+ "parameters": [
+ {
+ "name": "callback",
+ "type": "function",
+ "optional": "false",
+ "parameters": [
+ {
+ "name" : "fileSystem",
+ "type": "object",
+ "optional": "true",
+ "description": "A DOMFileSystem instance for local file system access. null if the caller has no appropriate permissions."
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "selectFiles",
+ "type": "function",
+ "description": "Select multiple files.",
+ "parameters": [
+ {
+ "type": "array",
+ "description": "Array of selected paths",
+ "items": {"type": "string"}
+ }
+ ]
+ },
+ {
+ "name": "selectFile",
+ "type": "function",
+ "description": "Select a file.",
+ "parameters": [
+ {
+ "type": "string",
+ "description": "A selected path"
+ },
+ {
+ "type": "integer",
+ "description": "Index of Filter"
+ }
+ ]
+ },
+ {
+ "name": "viewFiles",
+ "type": "function",
+ "description": "View multiple files.",
+ "parameters": [
+ {
+ "name": "fileUrls",
+ "type": "array",
+ "description": "Array of selected paths",
+ "items": {"type": "string"}
+ },
+ {
+ "name": "id",
+ "type": "string",
+ "description": "File browser handler id as for internal tasks."
+ }
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "onDiskChanged",
+ "type": "function",
+ "description": "Fired when disk mount/unmount event is detected.",
+ "parameters": [
+ {
+ "$ref": "MountEvent",
+ "name": "fullPath",
+ "description": "Mount event information."
+ }
+ ]
+ }
+ ]
+ },
{
"namespace":"webstorePrivate",
"nodoc": "true",
@@ -4436,6 +4826,44 @@
]
},
{
+ "name": "beginInstallWithManifest",
+ "description": "Initiates the install process for the given extension. This must be called during a user gesture.",
+ "parameters": [
+ {
+ "name": "id",
+ "type": "string",
+ "description": "The id of the extension to be installled.",
+ "minLength": 32,
+ "maxLength": 32
+ },
+ {
+ "name": "icon_data",
+ "type": "string",
+ "description": "An icon as a base64-encoded image, displayed in a confirmation dialog."
+ },
+ {
+ "name": "manifest_json",
+ "type": "string",
+ "description": "A string with the contents of the extension's manifest.json file. During the install process, the browser will check that the downloaded extension's manifest matches what was passed in here.",
+ "minLength": 1
+ },
+ {
+ "name": "callback",
+ "type": "function",
+ "description": "Called when the user has either accepted/rejected the dialog, or some error occurred (such as invalid manifest or icon image data).",
+ "optional": "true",
+ "parameters": [
+ {
+ "name": "result",
+ "type": "string",
+ "description": "A string result code, which will be empty upon success. The possible values in the case of errors include 'unknown_error', 'user_cancelled', 'manifest_error', 'icon_error', 'invalid_id', 'permission_denied', and 'no_gesture'."
+ }
+ ]
+ }
+ ]
+
+ },
+ {
"name": "completeInstall",
"description": "",
"parameters": [
@@ -4545,7 +4973,7 @@
"incognito": {
"type": "boolean",
"optional": true,
- "description": "Whether to return the setting that applies to the incognito session only (default false)."
+ "description": "Whether to return the setting that applies to the incognito session (default false)."
}
}
},
@@ -4563,9 +4991,14 @@
"type": "any"
},
"levelOfControl": {
- "description": "One of<br>NotControllable = cannot be controlled by any extension<br>ControlledByOtherExtensions = controlled by extensions with higher precedence<br>ControllableByThisExtension = can be controlled by this extension<br>ControlledByThisExtension = controlled by this extension",
+ "description": "One of<br><var>NotControllable</var>: cannot be controlled by any extension<br><var>ControlledByOtherExtensions</var>: controlled by extensions with higher precedence<br><var>ControllableByThisExtension</var>: can be controlled by this extension<br><var>ControlledByThisExtension</var>: controlled by this extension",
"type": "string",
"enum": ["NotControllable", "ControlledByOtherExtensions", "ControllableByThisExtension", "ControlledByThisExtension"]
+ },
+ "incognitoSpecific": {
+ "description": "Whether the effective value is specific to the incognito session.<br>This property will <em>only</em> be present if the <var>incognito</var> property in the <var>details</var> parameter of <code>get()</code> was true.",
+ "type": "boolean",
+ "optional": true
}
}
}
@@ -4584,7 +5017,7 @@
"description": "What setting to change.",
"properties": {
"value": {
- "description": "The value of the preference.",
+ "description": "The value of the preference. <br>Note that every preference has a specific value type, which is described together with the preference. An extension should <em>not</em> set a preference value of a different type.",
"type": "any"
},
"incognito": {
@@ -4629,6 +5062,34 @@
}
]
}
+ ],
+ "events": [
+ {
+ "name": "onChange",
+ "description": "Fired when the value of the preference changes.",
+ "parameters": [
+ {
+ "type": "object",
+ "name": "details",
+ "properties": {
+ "value": {
+ "description": "The value of the preference.",
+ "type": "any"
+ },
+ "levelOfControl": {
+ "description": "One of<br><var>NotControllable</var>: cannot be controlled by any extension<br><var>ControlledByOtherExtensions</var>: controlled by extensions with higher precedence<br><var>ControllableByThisExtension</var>: can be controlled by this extension<br><var>ControlledByThisExtension</var>: controlled by this extension",
+ "type": "string",
+ "enum": ["NotControllable", "ControlledByOtherExtensions", "ControllableByThisExtension", "ControlledByThisExtension"]
+ },
+ "incognitoSpecific": {
+ "description": "Whether the value that has changed is specific to the incognito session.<br>This property will <em>only</em> be present if the user has enabled the extension in incognito mode.",
+ "type": "boolean",
+ "optional": true
+ }
+ }
+ }
+ ]
+ }
]
}
]
@@ -4640,7 +5101,140 @@
"$ref": "Preference",
"value": ["blockThirdPartyCookies", {"type": "boolean"}],
"description": "Whether third party cookies should be blocked. The value of this preference is of type boolean."
+ },
+ "enableReferrers": {
+ "$ref": "Preference",
+ "value": ["enableReferrers", {"type":"boolean"}],
+ "description": "Whether referrers should be enabled. The value of this preference is of type boolean."
+ },
+ "enableHyperlinkAuditing": {
+ "$ref": "Preference",
+ "value": ["enableHyperlinkAuditing", {"type":"boolean"}],
+ "description": "Whether to enable hyperlink auditing (\"&lt;a ping&gt;\"). The value of this preference is of type boolean."
}
}
+ },
+ {
+ "namespace": "experimental.debugger",
+ "functions": [
+ {
+ "name": "attach",
+ "type": "function",
+ "description": "Attaches debugger to the tab with given id.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "description": "The id of the tab to which you want to attach."
+ },
+ {
+ "type": "function",
+ "name": "callback",
+ "optional": true,
+ "parameters": [],
+ "description": "If an error occurs while attaching to the tab, the callback will be called with no arguments and <a href='extension.html#property-lastError'>chrome.extension.lastError</a> will be set to the error message."
+ }
+ ]
+ },
+ {
+ "name": "detach",
+ "type": "function",
+ "description": "Detaches debugger from a tab with given id.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "description": "The id of the tab from which you want to detach."
+ },
+ {
+ "type": "function",
+ "name": "callback",
+ "optional": true,
+ "parameters": [],
+ "description": "If an error occurs while detaching from the tab, the callback will be called with no arguments and <a href='extension.html#property-lastError'>chrome.extension.lastError</a> will be set to the error message."
+ }
+ ]
+ },
+ {
+ "name": "sendRequest",
+ "type": "function",
+ "description": "Send given request to the debugger.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "description": "The id of the tab to which you want to send debugging request."
+ },
+ {
+ "type": "string",
+ "name": "method",
+ "description": "Method name."
+ },
+ {
+ "type": "object",
+ "name": "params",
+ "optional": true,
+ "properties": {},
+ "additionalProperties": { "type": "any" },
+ "description": "JSON object matching Developer Tools / Web Inspector Protocol scheme."
+ },
+ {
+ "type": "function",
+ "name": "callback",
+ "optional": true,
+ "parameters": [
+ {
+ "type": "object",
+ "name": "result",
+ "optional": true,
+ "properties": {},
+ "additionalProperties": { "type": "any" },
+ "description": "JSON object with the request response."
+ }
+ ],
+ "description": "Request response body. If an error occurs while posting the message, the callback will be called with no arguments and <a href='extension.html#property-lastError'>chrome.extension.lastError</a> will be set to the error message."
+ }
+ ]
+ }
+ ],
+ "events": [
+ {
+ "name": "onEvent",
+ "type": "function",
+ "description": "Fired whenever debugger issues instrumentation event.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "description": "The id of the tab that generated debug evet."
+ },
+ {
+ "type": "string",
+ "name": "method",
+ "description": "Method name."
+ },
+ {
+ "type": "object",
+ "name": "params",
+ "optional": true,
+ "properties": {},
+ "additionalProperties": { "type": "any" },
+ "description": "JSON object matching Developer Tools / Web Inspector Protocol event data scheme."
+ }
+ ]
+ },
+ {
+ "name": "onDetach",
+ "type": "function",
+ "description": "Fired when browser terminates debugging session for the tab.",
+ "parameters": [
+ {
+ "type": "integer",
+ "name": "tabId",
+ "description": "The id of the tab that was detached."
+ }
+ ]
+ }
+ ]
}
]
diff --git a/chrome/common/extensions/docs/api_index.html b/chrome/common/extensions/docs/api_index.html
index fcfd737..8ac3789 100644
--- a/chrome/common/extensions/docs/api_index.html
+++ b/chrome/common/extensions/docs/api_index.html
@@ -348,23 +348,26 @@ Here are the supported chrome.* APIs:
<h2 id="experimental">Experimental APIs</h2>
<p>
-Google Chrome also has some
+Google Chrome also has
<a href="experimental.html">experimental APIs</a>,
-which give you access to
-functionality such as process information and history.
+some of which will become supported APIs
+in future releases of Chrome.
</p>
<h2 id="conventions">API conventions</h2>
<p>
Unless the doc says otherwise,
-methods in the chrome.* APIs are asynchronous:
+methods in the chrome.* APIs are <b>asynchronous</b>:
they return immediately,
without waiting for the operation to finish.
If you need to know the outcome of an operation,
then you pass a callback function into the method.
-For more information, see the video
-<a href="http://www.youtube.com/watch?v=bmxr75CV36A&amp;feature=PlayList&amp;p=CA101D6A85FE9D4B&amp;index=2">Extension API Design</a>.
+For more information, watch this video:
+</p>
+
+<p>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/bmxr75CV36A?rel=0" frameborder="0" allowfullscreen=""></iframe>
</p>
</div>
diff --git a/chrome/common/extensions/docs/apps.html b/chrome/common/extensions/docs/apps.html
index 8130ad6..e5f48ae 100644
--- a/chrome/common/extensions/docs/apps.html
+++ b/chrome/common/extensions/docs/apps.html
@@ -381,12 +381,14 @@ instead of a hosted app if any of the following are true:
</ul>
<p>
-The following articles can help you understand
+To learn more about
the differences between web apps and websites,
-extensions and packaged apps, and packaged apps and hosted apps:
+extensions and packaged apps, and packaged apps and hosted apps,
+read these:
</p>
<ul>
+ <li> <a href="http://code.google.com/chrome/webstore/docs/choosing.html">Choosing an App Type</a> </li>
<li> <a href="http://code.google.com/chrome/apps/articles/thinking_in_web_apps.html">Thinking in Web Apps</a> </li>
<li> <a href="http://code.google.com/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
</ul>
@@ -415,11 +417,7 @@ Here is a typical manifest for a packaged app:
"icons": {
"16": "icon_16.png",
"128": "icon_128.png"
- },
- "permissions": [
- "unlimitedStorage",
- "notifications"
- ]
+ }
}
</pre>
diff --git a/chrome/common/extensions/docs/bookmarks.html b/chrome/common/extensions/docs/bookmarks.html
index 71ff4c2..2937e60 100644
--- a/chrome/common/extensions/docs/bookmarks.html
+++ b/chrome/common/extensions/docs/bookmarks.html
@@ -391,8 +391,8 @@ For example:</p>
<p>
Bookmarks are organized in a tree,
where each node in the tree
-is either a bookmark or a group
-(a folder that can contain nodes).
+is either a bookmark or a folder
+(sometimes called a <em>group</em>).
Each node in the tree
is represented by a
<a href="#type-BookmarkTreeNode"><code>BookmarkTreeNode</code></a> object.
@@ -410,6 +410,9 @@ See <a href="#type-BookmarkTreeNode"><code>BookmarkTreeNode</code></a>
for information about the properties a node can have.
</p>
+<p class="note"><b>Note:</b> You cannot use this API to add or remove entries
+in the root folder. You also cannot rename, move, or remove the special
+"Bookmarks Bar" and "Other Bookmarks" folders.</p>
<h2 id="overview-examples">Examples</h2>
diff --git a/chrome/common/extensions/docs/build/directory.py b/chrome/common/extensions/docs/build/directory.py
index a58ea87..055948d 100644
--- a/chrome/common/extensions/docs/build/directory.py
+++ b/chrome/common/extensions/docs/build/directory.py
@@ -225,7 +225,8 @@ class SamplesManifest(object):
Args:
path: The path to write the samples manifest file to.
"""
- manifest_text = json.dumps(self._manifest_data, indent=2, sort_keys=True)
+ manifest_text = json.dumps(self._manifest_data, indent=2,
+ sort_keys=True, separators=(',', ': '))
output_path = os.path.realpath(path)
try:
output_file = open(output_path, 'w')
diff --git a/chrome/common/extensions/docs/content_scripts.html b/chrome/common/extensions/docs/content_scripts.html
index e044dca..1097608 100644
--- a/chrome/common/extensions/docs/content_scripts.html
+++ b/chrome/common/extensions/docs/content_scripts.html
@@ -792,7 +792,7 @@ The first video describes content scripts and isolated worlds.
</p>
<p>
-<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/laLudeUmXHM&amp;hl=en_US&amp;fs=1&amp;"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/laLudeUmXHM&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></object>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/laLudeUmXHM?rel=0" frameborder="0" allowfullscreen=""></iframe>
</p>
<p>
@@ -802,7 +802,7 @@ sending a request to its parent extension.
</p>
<p>
-<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/B4M_a7xejYI&amp;hl=en_US&amp;fs=1&amp;"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/v/B4M_a7xejYI&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></object>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/B4M_a7xejYI?rel=0" frameborder="0" allowfullscreen=""></iframe>
</p>
</div>
diff --git a/chrome/common/extensions/docs/contextMenus.html b/chrome/common/extensions/docs/contextMenus.html
index f76f8c3..6ccc1b5 100644
--- a/chrome/common/extensions/docs/contextMenus.html
+++ b/chrome/common/extensions/docs/contextMenus.html
@@ -481,7 +481,7 @@ You can find samples of this API on the
<div style="display:inline">
(
<span class="optional">optional</span>
- <span class="enum" style="display: none; ">enumerated</span>
+ <span class="enum">enumerated</span>
<span id="typeTemplate">
<span style="display: none; ">
<a> Type</a>
@@ -491,7 +491,7 @@ You can find samples of this API on the
array of <span><span></span></span>
</span>
<span>string</span>
- <span style="display: none; "></span>
+ <span>["normal", "checkbox", "radio", "separator"]</span>
</span>
</span>
)
@@ -502,7 +502,7 @@ You can find samples of this API on the
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>The type of menu item - one of 'normal', 'checkbox', 'radio', or 'separator'. Defaults to 'normal' if not specified.</dd>
+ <dd>The type of menu item. Defaults to 'normal' if not specified.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -701,7 +701,7 @@ You can find samples of this API on the
array of <span><span></span></span>
</span>
<span>string</span>
- <span style="display: none; "></span>
+ <span>["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"]</span>
</span>
</span></span>
</span>
@@ -717,7 +717,7 @@ You can find samples of this API on the
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>List of contexts this menu item will appear in. Legal values are: 'all', 'page', 'selection', 'link', 'editable', 'image', 'video', and 'audio'. Defaults to ['page'].</dd>
+ <dd>List of contexts this menu item will appear in. Defaults to ['page'] if not specified.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1855,7 +1855,7 @@ You can find samples of this API on the
<div style="display:inline">
(
<span class="optional">optional</span>
- <span class="enum" style="display: none; ">enumerated</span>
+ <span class="enum">enumerated</span>
<span id="typeTemplate">
<span style="display: none; ">
<a> Type</a>
@@ -1865,7 +1865,7 @@ You can find samples of this API on the
array of <span><span></span></span>
</span>
<span>string</span>
- <span style="display: none; "></span>
+ <span>["normal", "checkbox", "radio", "separator"]</span>
</span>
</span>
)
@@ -2081,7 +2081,7 @@ You can find samples of this API on the
array of <span><span></span></span>
</span>
<span>string</span>
- <span style="display: none; "></span>
+ <span>["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio"]</span>
</span>
</span></span>
</span>
diff --git a/chrome/common/extensions/docs/cookies.html b/chrome/common/extensions/docs/cookies.html
index 14c8cf6..f7bcea4 100644
--- a/chrome/common/extensions/docs/cookies.html
+++ b/chrome/common/extensions/docs/cookies.html
@@ -2137,9 +2137,9 @@ see <a href="samples.html">Samples</a>.
<dd style="display: none; ">
Description of this parameter from the json schema.
</dd>
- <dd style="display: none; ">
+ <dd>
This parameter was added in version
- <b><span></span></b>.
+ <b><span>11.0.674.0</span></b>.
You must omit this parameter in earlier versions,
and you may omit it in any version. If you require this
parameter, the manifest key
@@ -3212,9 +3212,9 @@ see <a href="samples.html">Samples</a>.
<dd style="display: none; ">
Description of this parameter from the json schema.
</dd>
- <dd style="display: none; ">
+ <dd>
This parameter was added in version
- <b><span></span></b>.
+ <b><span>11.0.674.0</span></b>.
You must omit this parameter in earlier versions,
and you may omit it in any version. If you require this
parameter, the manifest key
@@ -3378,7 +3378,7 @@ see <a href="samples.html">Samples</a>.
<div class="description">
<p class="todo" style="display: none; ">Undocumented.</p>
- <p>Fired when a cookie is set or removed.</p>
+ <p>Fired when a cookie is set or removed. As a special case, note that updating a cookie's properties is implemented as a two step process: the cookie to be updated is first removed entirely, generating a notification with "cause" of "overwrite" . Afterwards, a new cookie is written with the updated values, generating a second notification with "cause" "explicit".</p>
<!-- PARAMETERS -->
<div>
@@ -3567,6 +3567,74 @@ see <a href="samples.html">Samples</a>.
</dd>
</div>
+ </div><div>
+ <div>
+ <dt>
+ <var>cause</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span>["evicted", "expired", "explicit", "expired_overwrite", "overwrite"]</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The underlying reason behind the cookie's change. If a cookie was inserted, or removed via an explicit call to "chrome.cookies.remove", "cause" will be "explicit". If a cookie was automatically removed due to expiry, "cause" will be "expired". If a cookie was removed due to being overwritten with an already-expired expiration date, "cause" will be set to "expired_overwrite". If a cookie was automatically removed due to garbage collection, "cause" will be "evicted". If a cookie was automatically removed due to a "set" call that overwrote it, "cause" will be "overwrite". Plan your response accordingly.</dd>
+ <dd>
+ This parameter was added in version
+ <b><span>12.0.707.0</span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
</div>
</dl>
</dd>
diff --git a/chrome/common/extensions/docs/docs.html b/chrome/common/extensions/docs/docs.html
index 81fce56..d61024b 100644
--- a/chrome/common/extensions/docs/docs.html
+++ b/chrome/common/extensions/docs/docs.html
@@ -319,8 +319,7 @@ This documentation tells you how to write extensions
and packaged apps for the
<a href="http://www.google.com/chrome">Google Chrome browser</a>.
Because extensions came first,
-the APIs and these docs say <em>extension</em> everywhere,
-even though almost everything applies to packaged apps, as well.
+the APIs and these docs say <em>extension</em> everywhere.
</p>
<p class="caution">
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess.zip b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess.zip
new file mode 100644
index 0000000..9855524
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json
new file mode 100644
index 0000000..a75a5fe
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json
@@ -0,0 +1,15 @@
+{
+ "name" : "`extension.isAllowed???Access` Example",
+ "version" : "1.0.0",
+ "description" : "Demonstrates the `extension.isAllowed???Access` APIs",
+ "permissions" : [ "file://*" ],
+ "browser_action" : {
+ "default_popup": "popup.html",
+ "default_icon" : "sample-19.png"
+ },
+ "icons" : {
+ "16" : "sample-16.png",
+ "48" : "sample-48.png",
+ "128" : "sample-128.png"
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/popup.html b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/popup.html
new file mode 100644
index 0000000..1c3da61
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/popup.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<!--
+ * Copyright (c) 2010 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.
+-->
+<html>
+ <head>
+ <title>extension.isAllowedAccess Sample</title>
+ <link rel="stylesheet" href="./sample.css">
+ </head>
+ <body>
+ <h1>extension.isAllowedAccess Sample</h1>
+ <section>
+ <ol>
+ <li><p>
+ <span>1</span> chrome.extension.isAllowedFileSchemeAccess:
+ <code id="file">unknown</code> (unpacked extensions always have
+ file scheme access, you'll need to install this as a packed
+ extension to toggle it properly)
+ </p></li>
+ <li><p>
+ <span>2</span> chrome.extension.isAllowedIncognitoAccess:
+ <code id="incognito">unknown</code>
+ </p></li>
+ </ol>
+ </section>
+ <script>
+ chrome.extension.isAllowedFileSchemeAccess(function(state) {
+ var el = document.getElementById('file');
+ el.textContent = el.className = state ? 'true': 'false';
+ });
+ chrome.extension.isAllowedIncognitoAccess(function(state) {
+ var el = document.getElementById('incognito');
+ el.textContent = el.className = state ? 'true': 'false';
+ });
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-128.png b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-128.png
new file mode 100644
index 0000000..d733b1e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-128.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-16.png b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-16.png
new file mode 100644
index 0000000..dcc5c14
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-16.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-19.png b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-19.png
new file mode 100644
index 0000000..01e0aa8
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-19.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-48.png b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-48.png
new file mode 100644
index 0000000..3af1eb8
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample-48.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample.css b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample.css
new file mode 100644
index 0000000..2f35d4a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample.css
@@ -0,0 +1,61 @@
+body {
+ margin: 5px 10px 10px;
+}
+
+h1 {
+ color: #53637D;
+ font: 26px/1.2 Helvetica, sans-serif;
+ font-size: 200%;
+ margin: 0;
+ padding-bottom: 4px;
+ text-shadow: white 0 1px 2px;
+}
+
+body > section {
+ border-radius: 5px;
+ background: -webkit-linear-gradient(rgba(234, 238, 243, 0.2), #EAEEF3),
+ -webkit-linear-gradient(left, #EAEEF3, #EAEEF3 97%, #D3D7DB);
+ font: 14px/1 Arial,Sans Serif;
+ padding: 10px;
+ width: 563px;
+ max-height: 400px;
+ overflow-y: auto;
+ box-shadow: inset 0px 2px 5px rgba(0,0,0,0.5);
+}
+
+body > section > ol {
+ padding: 0;
+ margin: 0;
+ list-style: none inside;
+}
+
+body > section > ol > li {
+ position: relative;
+ margin: 0.5em 0 0.5em 40px;
+}
+
+code {
+ word-wrap: break-word;
+ background: rgba(255,255,0, 0.5);
+}
+ code.true {
+ background: rgba(0, 255, 0, 0.5);
+ }
+ code.false {
+ background: rgba(255, 0, 0, 0.5);
+ }
+
+li > p > span:first-child {
+ position: absolute;
+ top: 0px;
+ left: -40px;
+ width: 30px;
+ text-align: right;
+ font: 30px/1 Helvetica, sans-serif;
+ font-weight: 700;
+}
+
+p {
+ min-height: 30px;
+ line-height: 1.2;
+}
diff --git a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer.zip b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer.zip
new file mode 100644
index 0000000..3669d90
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/advicedog.jpg b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/advicedog.jpg
new file mode 100644
index 0000000..9274fbd
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/advicedog.jpg
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
new file mode 100644
index 0000000..03b0e5a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json
@@ -0,0 +1,10 @@
+{
+ "name" : "Enable/disable referrers API example extension",
+ "version" : "0.1",
+ "description" : "Sample extension which demonstrates how to access a preference.",
+ "permissions": [ "experimental", "contentSettings" ],
+ "browser_action": {
+ "default_icon": "advicedog.jpg",
+ "popup": "popup.html"
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/popup.html b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/popup.html
new file mode 100644
index 0000000..43b5dae
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/popup.html
@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <script>
+var cs = chrome.experimental.contentSettings;
+var pref = cs.misc.enableReferrers;
+
+/**
+ * Returns whether the |levelOfControl| means that the extension can change the
+ * preference value.
+ *
+ * @param levelOfControl{string}
+ */
+function settingIsControllable(levelOfControl) {
+ return (levelOfControl == "ControllableByThisExtension" ||
+ levelOfControl == "ControlledByThisExtension");
+}
+
+/**
+ * Updates the UI to reflect the state of the preference.
+ *
+ * @param settings{object} A settings object, as returned from |get()| or the
+ * |onchange| event.
+ */
+function updateUI(settings) {
+ var disableUI = !settingIsControllable(settings.levelOfControl);
+ document.getElementById("regularValue").disabled = disableUI;
+ document.getElementById("useSeparateIncognitoSettings").disabled = disableUI;
+ if (settings.hasOwnProperty('incognitoSpecific')) {
+ var hasIncognitoValue = settings.incognitoSpecific;
+ document.getElementById("useSeparateIncognitoSettings").checked =
+ hasIncognitoValue;
+ document.getElementById("incognitoValue").disabled =
+ disableUI || !hasIncognitoValue;
+ document.getElementById("incognitoValue").checked = settings.value;
+ } else {
+ document.getElementById("regularValue").checked = settings.value;
+ }
+}
+
+/**
+ * Wrapper for |updateUI| which is used as callback for the |get()| method and
+ * which logs the result.
+ * If there was an error getting the preference, does nothing.
+ *
+ * @param settings{object} A settings object, as returned from |get()|.
+ */
+function updateUIFromGet(settings) {
+ if (settings) {
+ console.log('pref.get result:' + JSON.stringify(settings));
+ updateUI(settings);
+ }
+}
+
+/**
+ * Wrapper for |updateUI| which is used as handler for the |onchange| event
+ * and which logs the result.
+ *
+ * @param settings{object} A settings object, as returned from the |onchange|
+ * event.
+ */
+function updateUIFromOnChange(settings) {
+ console.log('pref.onChange event:' + JSON.stringify(settings));
+ updateUI(settings);
+}
+
+/*
+ * Initializes the UI.
+ */
+function init() {
+ chrome.extension.isAllowedIncognitoAccess(function(allowed) {
+ if (allowed) {
+ pref.get({'incognito': true}, updateUIFromGet);
+ document.getElementById("incognito").style.display = "block";
+ document.getElementById("incognito-forbidden").style.display = "none";
+ }
+ });
+ pref.get({}, updateUIFromGet);
+ pref.onChange.addListener(updateUIFromOnChange);
+}
+
+/**
+ * Called from the UI to change the preference value.
+ *
+ * @param enabled{boolean} The new preference value.
+ * @param incognito{boolean} Whether the value is specific to incognito mode.
+ */
+function setPrefValue(enabled, incognito) {
+ pref.set({'value':enabled, 'incognito': incognito});
+}
+
+/**
+ * Called from the UI to change whether to use separate settings for
+ * incognito mode.
+ *
+ * @param value{boolean} whether to use separate settings for
+ * incognito mode.
+ */
+function setUseSeparateIncognitoSettings(value) {
+ if (!value) {
+ pref.clear({'incognito': true});
+ } else {
+ // Explicitly set the value for incognito mode.
+ pref.get({'incognito': true}, function(settings) {
+ pref.set({'incognito': true, 'value': settings.value});
+ });
+ }
+ document.getElementById("incognitoValue").disabled = !value;
+}
+
+ </script>
+</head>
+<body onload="init()">
+
+<div style="width: 300px">
+<input type="checkbox" onclick="setPrefValue(this.checked)" id="regularValue" /> Enable referrers
+
+<div id="incognito" style="display:none">
+<input type="checkbox" onclick="setUseSeparateIncognitoSettings(this.checked)" id="useSeparateIncognitoSettings" /> Use separate setting for incognito mode:
+<br>
+<input type="checkbox" onclick="setPrefValue(this.checked, true)" id="incognitoValue" disabled="disabled"/> Enable referrers in incognito sessions
+</div>
+<div id="incognito-forbidden">
+Select "Allow in incognito" to access incognito preferences
+</div>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/chrome/common/extensions/docs/examples/api/tabs/pin.zip b/chrome/common/extensions/docs/examples/api/tabs/pin.zip
new file mode 100644
index 0000000..63f48d2
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/tabs/pin.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/tabs/pin/README b/chrome/common/extensions/docs/examples/api/tabs/pin/README
new file mode 100644
index 0000000..d9d5c65
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/tabs/pin/README
@@ -0,0 +1,2 @@
+Demo Chrome Extension that uses the Tab Pinning API. Enables a new keyboard
+shortcut (Ctrl + Shift + P) to toggle pinning and unpinning of the current tab.
diff --git a/chrome/common/extensions/docs/examples/api/tabs/pin/background.html b/chrome/common/extensions/docs/examples/api/tabs/pin/background.html
new file mode 100644
index 0000000..47aa9fa
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/tabs/pin/background.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ * Copyright (c) 2011 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.
+-->
+<head>
+<title>Keyboard Pin</title>
+<script>
+chrome.extension.onRequest.addListener(
+ function(request, sender, sendResponse) {
+ if (request.toggle_pin) {
+ // Get the currently selected tab
+ chrome.tabs.getSelected(null, function(tab) {
+ // Toggle the pinned status
+ chrome.tabs.update(tab.id, {'pinned': !tab.pinned});
+ });
+ }
+ }
+);
+</script>
+</head>
diff --git a/chrome/common/extensions/docs/examples/api/tabs/pin/inject.js b/chrome/common/extensions/docs/examples/api/tabs/pin/inject.js
new file mode 100644
index 0000000..3117e40
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/tabs/pin/inject.js
@@ -0,0 +1,13 @@
+// Copyright (c) 2011 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.
+window.addEventListener("keydown", function(event) {
+ // Bind to both command (for Mac) and control (for Win/Linux)
+ var modifier = event.ctrlKey || event.metaKey;
+ if (modifier && event.shiftKey && event.keyCode == 80) {
+ // Send message to background page to toggle tab
+ chrome.extension.sendRequest({toggle_pin: true}, function(response) {
+ // Do stuff on successful response
+ });
+ }
+}, false);
diff --git a/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json b/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json
new file mode 100644
index 0000000..e7969cd
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json
@@ -0,0 +1,15 @@
+{
+ "name": "Keyboard Pin",
+ "version": "0.1",
+ "description": "Creates a keyboard shortcut (C + Shift + P) to toggle the pinned state of the currently selected tab",
+ "permissions": [
+ "tabs"
+ ],
+ "background_page": "background.html",
+ "content_scripts": [
+ {
+ "matches": ["<all_urls>"],
+ "js": ["inject.js"]
+ }
+ ]
+}
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip b/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip
new file mode 100644
index 0000000..496714e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json b/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
new file mode 100644
index 0000000..704131d
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json
@@ -0,0 +1,52 @@
+{
+ "extName": {
+ "message": "WebNavigation Tech Demo",
+ "description": "The extension name."
+ },
+ "extDescription": {
+ "message": "Demonstration of the WebNavigation extension API.",
+ "description": "The extension description."
+ },
+
+ "navigationDescription": {
+ "message": ", requested $NUM$ times. Loaded in an average of $LOAD$ miliseconds.",
+ "description": "The message posted in the popup for each stored navigation.",
+ "placeholders": {
+ "NUM": {
+ "content": "$1",
+ "example": "4 (The number of times this URL was accessed.)"
+ },
+ "LOAD": {
+ "content": "$2",
+ "example": "12.345 (The average load time in miliseconds.)"
+ }
+ }
+ },
+
+ "inHandler": {
+ "message": "In webNavigation[`%s`] handler: %o",
+ "description": "Notification displayed for each webNavigation event."
+ },
+
+ "inHandlerError": {
+ "message": "In webNavigation[`%s`] handler: No data!",
+ "description": "Notification displayed in a webNavigation event handler without data!"
+ },
+
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCommitted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCommitted` is triggered on a non-pending request."
+ },
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCompleted` is triggered on a non-pending request."
+ },
+ "errorErrorOccurredWithoutPending": {
+ "message": "Wha? `onErrorOccurred` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onErrorOccurred` is triggered on a non-pending request."
+ },
+ "errorCommittedWithoutPending": {
+ "message": "Wha? `onCompleted` for `%s` called, though it's not pending: %o",
+ "description": "Error logged when `onCompleted` is triggered on a non-pending request."
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html b/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html
new file mode 100644
index 0000000..138e8d0
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<!--
+ * Copyright (c) 2011 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.
+-->
+<html>
+ <head>
+ <title>WebNavigation Sample Extension Background Page</title>
+ </head>
+ <body>
+ <script src='./navigation_collector.js'></script>
+ <script>
+ var nav = new NavigationCollector();
+
+ var eventList = ['onBeforeNavigate', 'onBeforeRetarget', 'onCommitted',
+ 'onCompleted', 'onDOMContentLoaded', 'onErrorOccurred'];
+
+ eventList.forEach(function(e) {
+ chrome.experimental.webNavigation[e].addListener(function(data) {
+ if (typeof data)
+ console.log(chrome.i18n.getMessage('inHandler'), e, data);
+ else
+ console.error(chrome.i18n.getMessage('inHandlerError'), e);
+ });
+ });
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png b/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png
new file mode 100644
index 0000000..103ff36
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/icon.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json b/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
new file mode 100644
index 0000000..538417e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "__MSG_extName__",
+ "version": "0.1",
+ "description": "__MSG_extDescription__",
+ "default_locale": "en",
+ "background_page": "background.html",
+ "browser_action": {
+ "default_icon": "icon.png",
+ "popup": "popup.html"
+ },
+ "permissions": [
+ "extension",
+ "experimental",
+ "webNavigation"
+ ]
+}
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js b/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js
new file mode 100644
index 0000000..9a7b608
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js
@@ -0,0 +1,371 @@
+// Copyright (c) 2011 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.
+
+/**
+ * Implements the NavigationCollector object that powers the extension.
+ *
+ * @author mkwst@google.com (Mike West)
+ */
+
+/**
+ * Collects navigation events, and provides a list of successful requests
+ * that you can do interesting things with. Calling the constructor will
+ * automatically bind handlers to the relevant webnavigation API events,
+ * and to a `getMostRequestedUrls` extension message for internal
+ * communication between background pages and popups.
+ *
+ * @constructor
+ */
+function NavigationCollector() {
+ /**
+ * A list of currently pending requests, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, {start: number}>}
+ * @private
+ */
+ this.pending_ = {};
+
+ /**
+ * A list of completed requests, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, Array.<NavigationCollector.Request>>}
+ * @private
+ */
+ this.completed_ = {};
+
+ /**
+ * A list of requests that errored off, implemented as a hash of each
+ * request's tab ID, frame ID, and URL in order to ensure uniqueness.
+ *
+ * @type {Object.<string, Array.<NavigationCollector.Request>>}
+ * @private
+ */
+ this.errored_ = {};
+
+ // Bind handlers to the 'webNavigation' events that we're interested
+ // in handling in order to build up a complete picture of the whole
+ // navigation event.
+ chrome.experimental.webNavigation.onBeforeRetarget.addListener(
+ this.onBeforeRetargetListener_.bind(this));
+ chrome.experimental.webNavigation.onBeforeNavigate.addListener(
+ this.onBeforeNavigateListener_.bind(this));
+ chrome.experimental.webNavigation.onCompleted.addListener(
+ this.onCompletedListener_.bind(this));
+ chrome.experimental.webNavigation.onCommitted.addListener(
+ this.onCommittedListener_.bind(this));
+ chrome.experimental.webNavigation.onErrorOccurred.addListener(
+ this.onErrorOccurredListener_.bind(this));
+
+ // Bind handler to extension messages for communication from popup.
+ chrome.extension.onRequest.addListener(this.onRequestListener_.bind(this));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The possible transition types that explain how the navigation event
+ * was generated (i.e. "The user clicked on a link." or "The user submitted
+ * a form").
+ *
+ * @see http://code.google.com/chrome/extensions/trunk/history.html
+ * @enum {string}
+ */
+NavigationCollector.NavigationType = {
+ AUTO_BOOKMARK: 'auto_bookmark',
+ AUTO_SUBFRAME: 'auto_subframe',
+ FORM_SUBMIT: 'form_submit',
+ GENERATED: 'generated',
+ KEYWORD: 'keyword',
+ KEYWORD_GENERATED: 'keyword_generated',
+ LINK: 'link',
+ MANUAL_SUBFRAME: 'manual_subframe',
+ RELOAD: 'reload',
+ START_PAGE: 'start_page',
+ TYPED: 'typed'
+};
+
+/**
+ * The possible transition qualifiers:
+ *
+ * * CLIENT_REDIRECT: Redirects caused by JavaScript, or a refresh meta tag
+ * on a page.
+ *
+ * * SERVER_REDIRECT: Redirected by the server via a 301/302 response.
+ *
+ * * FORWARD_BACK: User used the forward or back buttons to navigate through
+ * her browsing history.
+ *
+ * @enum {string}
+ */
+NavigationCollector.NavigationQualifier = {
+ CLIENT_REDIRECT: 'client_redirect',
+ FORWARD_BACK: 'forward_back',
+ SERVER_REDIRECT: 'server_redirect'
+};
+
+/**
+ * @typedef {{url: string, transitionType: NavigationCollector.NavigationType,
+ * transitionQualifier: Array.<NavigationCollector.NavigationQualifier>,
+ * openedInNewTab: boolean, sourceUrl: ?string, duration: number}}
+ */
+NavigationCollector.Request;
+
+///////////////////////////////////////////////////////////////////////////////
+
+NavigationCollector.prototype = {
+ /**
+ * Returns a somewhat unique ID for a given WebNavigation request.
+ *
+ * @param {!{tabId: number, frameId: number, url: string}} data Information
+ * about the navigation event we'd like an ID for.
+ * @return {!string} ID created by combining the tab ID and frame ID (as the
+ * API ensures that these will be unique across a single navigation
+ * event)
+ * @private
+ */
+ parseId_: function(data) {
+ return data.tabId + '-' + data.frameId;
+ },
+
+
+ /**
+ * Creates an empty entry in the pending array, and prepopulates the
+ * errored and completed arrays for ease of insertion later.
+ *
+ * @param {!string} id The request's ID, as produced by parseId_.
+ * @param {!string} url The request's URL.
+ */
+ prepareDataStorage_: function(id, url) {
+ this.pending_[id] = this.pending_[id] || {
+ openedInNewTab: false,
+ sourceUrl: null,
+ start: null,
+ transitionQualifiers: [],
+ transitionType: null
+ };
+ this.completed_[url] = this.completed_[url] || [];
+ this.errored_[url] = this.errored_[url] || [];
+ },
+
+
+ /**
+ * Handler for the 'onBeforeRetarget' event. Updates the pending request
+ * with a sourceUrl, and notes that it was opened in a new tab.
+ *
+ * Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onBeforeRetargetListener_: function(data) {
+ var id = this.parseId_(data);
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].openedInNewTab = true;
+ this.pending_[id].sourceUrl = data.sourceUrl;
+ this.pending_[id].start = data.timeStamp;
+ },
+
+
+ /**
+ * Handler for the 'onBeforeNavigate' event. Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onBeforeNavigateListener_: function(data) {
+ var id = this.parseId_(data);
+ this.prepareDataStorage_(id, data.url);
+ this.pending_[id].start = this.pending_[id].start || data.timeStamp;
+ },
+
+
+ /**
+ * Handler for the 'onCommitted' event. Updates the pending request with
+ * transition information.
+ *
+ * Pushes the request onto the
+ * 'pending_' object, and stores it for later use.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onCommittedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.warn(
+ chrome.i18n.getMessage('errorCommittedWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.pending_[id].transitionType = data.transitionType;
+ this.pending_[id].transitionQualifiers =
+ data.transitionQualifiers;
+ }
+ },
+
+
+ /**
+ * Handler for the 'onCompleted` event. Pulls the request's data from the
+ * 'pending_' object, combines it with the completed event's data, and pushes
+ * a new NavigationCollector.Request object onto 'completed_'.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onCompletedListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.warn(
+ chrome.i18n.getMessage('errorCompletedWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.completed_[data.url].push({
+ duration: (data.timeStamp - this.pending_[id].start),
+ openedInNewWindow: this.pending_[id].openedInNewWindow,
+ sourceUrl: this.pending_[id].sourceUrl,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ }
+ },
+
+
+ /**
+ * Handler for the 'onErrorOccurred` event. Pulls the request's data from the
+ * 'pending_' object, combines it with the completed event's data, and pushes
+ * a new NavigationCollector.Request object onto 'errored_'.
+ *
+ * @param {!Object} data The event data generated for this request.
+ * @private
+ */
+ onErrorOccurredListener_: function(data) {
+ var id = this.parseId_(data);
+ if (!this.pending_[id]) {
+ console.error(
+ chrome.i18n.getMessage('errorErrorOccurredWithoutPending'),
+ data.url,
+ data);
+ } else {
+ this.errored_[data.url].push({
+ duration: (data.timeStamp - this.pending_[id].start),
+ openedInNewWindow: this.pending_[id].openedInNewWindow,
+ sourceUrl: this.pending_[id].sourceUrl,
+ transitionQualifiers: this.pending_[id].transitionQualifiers,
+ transitionType: this.pending_[id].transitionType,
+ url: data.url
+ });
+ delete this.pending_[id];
+ }
+ },
+
+ /**
+ * Handle request messages from the popup.
+ *
+ * @param {!{type:string}} request The external request to answer.
+ * @param {!MessageSender} sender Info about the script context that sent
+ * the request.
+ * @param {!function} sendResponse Function to call to send a response.
+ * @private
+ */
+ onRequestListener_: function(request, sender, sendResponse) {
+ if (request.type === 'getMostRequestedUrls')
+ sendResponse({result: this.getMostRequestedUrls(request.num)});
+ else
+ sendResponse({});
+ },
+
+///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * @return {Object.<string, NavigationCollector.Request>} The complete list of
+ * successful navigation requests.
+ */
+ get completed() {
+ return this.completed_;
+ },
+
+
+ /**
+ * @return {Object.<string, Navigationcollector.Request>} The complete list of
+ * unsuccessful navigation requests.
+ */
+ get errored() {
+ return this.errored_;
+ },
+
+
+ /**
+ * Get a list of the X most requested URLs.
+ *
+ * @param {number=} num The number of successful navigation requests to
+ * return. If 0 is passed in, or the argument left off entirely, all
+ * successful requests are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * successful navigation requests, sorted in decending order of frequency.
+ */
+ getMostRequestedUrls: function(num) {
+ return this.getMostFrequentUrls_(this.completed, num);
+ },
+
+
+ /**
+ * Get a list of the X most errored URLs.
+ *
+ * @param {number=} num The number of unsuccessful navigation requests to
+ * return. If 0 is passed in, or the argument left off entirely, all
+ * successful requests are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * unsuccessful navigation requests, sorted in decending order
+ * of frequency.
+ */
+ getMostErroredUrls: function(num) {
+ return this.getMostErroredUrls_(this.errored, num);
+ },
+
+
+ /**
+ * Get a list of the most frequent URLs in a list.
+ *
+ * @param {NavigationCollector.Request} list A list of URLs to parse.
+ * @param {number=} num The number of navigation requests to return. If
+ * 0 is passed in, or the argument left off entirely, all requests
+ * are returned.
+ * @return {Object.<string, NavigationCollector.Request>} The list of
+ * navigation requests, sorted in decending order of frequency.
+ * @private
+ */
+ getMostFrequentUrls_: function(list, num) {
+ var result = [];
+ var avg;
+ // Convert the 'completed_' object to an array.
+ for (var x in list) {
+ avg = 0;
+ if (list.hasOwnProperty(x)) {
+ list[x].forEach(function(o) {
+ avg += o.duration;
+ });
+ avg = avg / list[x].length;
+ result.push({
+ url: x,
+ numRequests: list[x].length,
+ requestList: list[x],
+ average: avg
+ });
+ }
+ }
+ // Sort the array.
+ result.sort(function(a, b) {
+ return b.numRequests - a.numRequests;
+ });
+ // Return the requested number of results.
+ return num ? result.slice(0, num) : result;
+ }
+};
diff --git a/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html b/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html
new file mode 100644
index 0000000..55956aa
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html
@@ -0,0 +1,103 @@
+<!doctype html>
+<!--
+ * Copyright (c) 2011 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.
+-->
+<html>
+ <head>
+ <title>WebNavigation Tech Demo Popup</title>
+ <style>
+ body {
+ margin: 5px 10px 10px;
+ }
+
+ h1 {
+ color: #53637D;
+ font: 26px/1.2 Helvetica, sans-serif;
+ font-size: 200%;
+ margin: 0;
+ padding-bottom: 4px;
+ text-shadow: white 0 1px 2px;
+ }
+
+ body > section {
+ border-radius: 5px;
+ background: -webkit-linear-gradient(rgba(234, 238, 243, 0.2), #EAEEF3),
+ -webkit-linear-gradient(
+ left, #EAEEF3, #EAEEF3 97%, #D3D7DB);
+ font: 14px/1 Arial,Sans Serif;
+ padding: 10px;
+ width: 563px;
+ max-height: 400px;
+ overflow-y: auto;
+ box-shadow: inset 0px 2px 5px rgba(0,0,0,0.5);
+ }
+
+ body > section > ol {
+ padding: 0;
+ margin: 0;
+ list-style: none inside;
+ }
+
+ body > section > ol > li {
+ position: relative;
+ margin: 0.5em 0 0.5em 40px;
+ }
+
+ code {
+ word-wrap: break-word;
+ background: rgba(255,255,0, 0.5);
+ }
+
+ em {
+ position: absolute;
+ top: 0px;
+ left: -40px;
+ width: 30px;
+ text-align: right;
+ font: 30px/1 Helvetica, sans-serif;
+ font-weight: 700;
+ }
+
+ p {
+ min-height: 30px;
+ line-height: 1.2;
+ }
+ </style>
+ </head>
+ <body>
+ <h1>Most Requested URLs</h1>
+ <section></section>
+ <script>
+ chrome.extension.sendRequest(
+ {'type': 'getMostRequestedUrls'},
+ function generateList(response) {
+ var section = document.querySelector('body>section');
+ var results = response.result;
+ var ol = document.createElement('ol');
+ var li, p, em, code, text;
+ var i;
+ for (i = 0; i < results.length; i++ ) {
+ li = document.createElement('li');
+ p = document.createElement('p');
+ em = document.createElement('em');
+ em.textContent = i + 1;
+ code = document.createElement('code');
+ code.textContent = results[i].url;
+ text = document.createTextNode(
+ chrome.i18n.getMessage('navigationDescription',
+ [results[i].numRequests,
+ results[i].average]));
+ p.appendChild(em);
+ p.appendChild(code);
+ p.appendChild(text);
+ li.appendChild(p);
+ ol.appendChild(li);
+ }
+ section.innerHTML = '';
+ section.appendChild(ol);
+ });
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/imageinfo.zip b/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
index 7d14906..4a61c1d 100644
--- a/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
+++ b/chrome/common/extensions/docs/examples/extensions/imageinfo.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip b/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip
new file mode 100644
index 0000000..5b7cb0a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration.zip
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json
new file mode 100644
index 0000000..b05ac21
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json
@@ -0,0 +1,50 @@
+{
+ "extName": {
+ "message": "Proxy Settings",
+ "description": "The extension name."
+ },
+ "extDescription": {
+ "message": "Set Chrome-specific proxies; a demonstration of Chrome's Proxy API",
+ "description": "The extension description."
+ },
+ "headerDirectConnection": {
+ "message": "Direct Connection",
+ "description": "Header for 'Direct Connection' configuration `fieldset`."
+ },
+ "errorNoExtensionAccess": {
+ "message": "Sorry. This browser's proxy settings cannot be controlled via extensions.",
+ "description": "Error message displayed when `levelOfControl` is 'NotControllable'."
+ },
+ "errorOtherExtensionControls": {
+ "message": "Sorry. This browser's proxy settings are being controlled by another extension. Please visit chrome://extensions for details.",
+ "description": "Error message displayed when `levelOfControl` is 'ControlledByOtherExtensions'."
+ },
+ "errorSettingRegularProxy": {
+ "message": "Setting regular proxy settings failed. Sorry!",
+ "description": "Error message, displayed when failing to set regular proxy settings."
+ },
+ "errorSettingIncognitoProxy": {
+ "message": "Setting incognito proxy settings failed. Sorry!",
+ "description": "Error message, displayed when failing to set incognito proxy settings."
+ },
+ "successfullySetProxy": {
+ "message": "Your proxy settings have been saved successfully; this window will close automagically. Have a nice day!",
+ "description": "Success message, displayed after proxy settings have been written."
+ },
+ "errorPopupTitle": {
+ "message": "Error: $1",
+ "description": "Error message used as popup title."
+ },
+ "errorProxyError": {
+ "message": "ProxyError: $1",
+ "description": "Error message displayed in popup when an error occurs."
+ },
+ "errorIdNotFound": {
+ "message": "Element with ID `$1` doesn't exist in the document",
+ "description": "Error message thrown when the given `id` doesn't exist"
+ },
+ "errorIdNotForm": {
+ "message": "Element with ID `$1` isn't a form element.",
+ "description": "Error message thrown when the given `id` isn't a form element."
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/background.html b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/background.html
new file mode 100644
index 0000000..870c505
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/background.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html>
+ <head>
+ <title>Proxy Configuration Extension Background Page</title>
+ </head>
+ <body>
+ <!--
+ Here, we'll hook into the proxy extension API's `onProxyError`
+ event, and use it to set a warning badge on the browser action's icon.
+ Additionally, we'll store proxy settings locally, and reset them when the
+ background page initializes. This is essential, as incognito settings
+ are wiped on restart.
+ -->
+ <script src="./proxy_form_controller.js"></script>
+ <script src="./proxy_error_handler.js"></script>
+ <script>
+ var errorHandler = new ProxyErrorHandler();
+
+ // If this extension has already set the proxy settings, then reset it
+ // once as the background page initializes. This is essential, as
+ // incognito settings are wiped on restart.
+ var persistedSettings = ProxyFormController.getPersistedSettings();
+ if (persistedSettings !== null) {
+ chrome.experimental.proxy.settings.set(
+ {'value': persistedSettings.regular});
+ }
+ </script>
+ </body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon128.png b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon128.png
new file mode 100644
index 0000000..0e4f441
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon128.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon16.png b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon16.png
new file mode 100644
index 0000000..ddab866
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon16.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon32.png b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon32.png
new file mode 100644
index 0000000..29504c0
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon32.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon48.png b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon48.png
new file mode 100644
index 0000000..b85ae2e
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/icon48.png
Binary files differ
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json
new file mode 100644
index 0000000..9bf0834
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json
@@ -0,0 +1,21 @@
+{
+ "name": "__MSG_extName__",
+ "version": "0.2",
+ "description": "__MSG_extDescription__",
+ "default_locale": "en",
+ "browser_action": {
+ "default_icon": "icon16.png",
+ "popup": "popup.html"
+ },
+ "icons": {
+ "16": "icon16.png",
+ "32": "icon32.png",
+ "48": "icon48.png",
+ "128": "icon128.png"
+ },
+ "background_page": "background.html",
+ "permissions": [
+ "experimental",
+ "proxy"
+ ]
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/popup.html b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/popup.html
new file mode 100644
index 0000000..9152e24
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/popup.html
@@ -0,0 +1,300 @@
+<!doctype html>
+<html>
+<head>
+ <title>Popup for Proxy API Test</title>
+ <style>
+ body {
+ margin: 5px 10px 10px;
+ }
+
+ h1 {
+ color: #53637D;
+ font: 26px/1.2 Helvetica, sans-serif;
+ font-size: 200%;
+ margin: 0;
+ padding-bottom: 4px;
+ text-shadow: white 0 1px 2px;
+ }
+
+ div[role='main'] {
+ border-radius: 5px;
+ background: #EAEEF3;
+ font: 14px/1 Arial,Sans Serif;
+ padding: 10px;
+ width: 563px;
+ box-shadow: inset 0px 2px 5px rgba(0,0,0,0.5);
+ -webkit-transition: background-color 0.5s ease-out;
+ overflow: hidden;
+ }
+
+ div[role='main'].incognito {
+ background: #496281 url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACUAAAAhCAYAAABeD2IVAAAFz0lEQVRYw8VYC0xcRRQtUEprERQ1VkohSGNpwaCYYNBUjS2K+KEVTUkDiqY0hWD5xxhDINgQqIZviRAkSiiWNDRxWypNpaatEQk/CwvlWyks3+XPAssu7I7nbmabx+suPzfrTU7yljfz5sy95947w5YtpjcLwBLYBuzgsAGs+DuzGZGwBh4BHIDdwHPA8xxuwBOcnIWpPUAL7wQeB54CngYcAWdO4kXgDeBoWFhYSk5OTtmFCxeuxsbGpuBv3sCTwFZTkrLmXtgH+AJ+QAAQCBzz8/P7MiUl5aebN29Kh4eHFVNTU2xoaIgNDAywe/fusYyMjO858R2mJEUe2ldZWfljd3f3P+3t7bK2trZBuVyuYCJbXFxkXV1drLOzU4e7d++yzMzMasz3AexMSYq89CoRYuuwvr6+B6Q6OjpYUVFRG+Yf4iE0iZYoc5woVK2trUPrIUXh05Mir9XW1qow/33gmf8idj0ZypjHuIgj5ubm1OshpdFoVoTwzp07zMbGJsTb23s/16fFZlKcyDjY29u7+fr6HoJFV1dXt7EN2MjIyANSUqmUubq6Jtna2r7OvWW7kUy04IR2+fj4HDx+/HhUYmJiIQQuhZ5mN0JKqVSuEHtWVlbd6dOns+3s7N7h9YtKynbuhFWNQuYQGBh4ODs7u2B0dHRauNDMzIx2eXmZabXadRG7f/++jhSylV25ckXOk2D4yJEjSVjnNV7ntq9Fily6Jzg4+CTEOqf/OJFoampSFRQUjDc3Ny+QF9RqtU47hozGE3mUDIbxOtTX1ytQt5T6MQipFGu9zDPbYq0i+ey5c+dyxAvBSxrsXHXixIlmVOsOaGykp6dnYXZ2lt49BHhIWVdXN1VaWipLS0trCQ8P/xseUwrD6+HhEUJO4BFa3VMREREx4+PjCkNhunjx4iAWuI0x16KjowlVYkA7uncYczUyMpJ+3z579mzXwsLCA9fimcXHx6djvb3cGatmHrnTBxr4jSZShaYwCQnC89PQXFNUVNSvMTExv6C/XYqLi6sg0DMISRISEq7h+QY81dHY2DgpDq9CoWCYm8Fbl8FmLaxLROoA8OGpU6dKL1++LCMdGdIPEkF569atIYlE0oNNdGFsNz03NDTI0QOVhrRG31GpVCR4JcrEV1jnFWOZaMVrBx07vIDDQBiQil3XQENDMplseWlpiW3WBOLXovWoy8vLBxA+CTT6NdZ5gR9vtooFvis1NfWTioqKn6uqqv6ihius4NCYZn5+Xuf2zRAi4OSgQQIsT05OrnA71qrmR6BtQlL0wwVpL1nPIqQzCgFpzlB50HuFxlF2TkxMUKiXxBKgb4Dooqen5zHeX63FWUfl/22k/aix+qM3IkEeS05Obs7Pz6+vqakZgAcUY2Njur8T2cHBwSXobbSwsPCPgICAAny7QJgstAaVjry8vEquKwexpiz5WccrJCTkDO1yLWIILcP474DPgQ8oMahpA9+C0FxJSUk7nr/h2vwMSAfhJWFJQAKN8Xku4tCJveWP3d8gb6zWToh0aGjoJYz/FHgToGYbTMmBUM0RnJyccvE7GkiEVlv1cylhpqenGbI7l4v8UWNVfRsn5efs7Jxx/vz5fr0+VvGWuqysrMbNzS0R88KDgoLyEMo+/XvyDI4tcmHC6GsUSkgL5rxFCWbsxGDFY/oSdn+mt7d3gj5w/fp15VrENmokbvRANTbyBdbbz8/tBgsn1agD/v7+cUh7lfAj2KmGmdAoI9PT0//kOnQ01vesedF8t7+/X27oQ0hbrSmJoXBKucD3GAsd3VS8cDIoY2YykgM6RS4/Zj8kckt+sfTDeaeHmdFwHxzj98Y94qKpOz+5u7ufZGY28haOyOX89rzCW9SZ3YuLi39g/4Mhy4ex/kHejFeQ2tvS0vI79ShqE+YEmjxLSkoK5aQsheGjW6snv8EeBT42Az4C3uP/l3DhyWYhvuPZ84PWbt6tzQFH7pCdvCzoSP0LtBi6oflBr2wAAAAASUVORK5CYII=') no-repeat 533px bottom;
+ }
+
+ form {
+ width: 563px;
+ -webkit-transition: -webkit-transform 0.25s ease;
+ }
+
+ form.offscreen {
+ -webkit-transform: translateX(-600px);
+ }
+
+ fieldset {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ }
+
+ legend {
+ position: absolute;
+ left: -999em;
+ }
+
+ form > fieldset {
+ border-radius: 5px;
+ border: 1px solid transparent;
+ padding: 10px 10px 10px 30px;
+ margin: 5px 0;
+ -webkit-transition: all 0.5s ease;
+ }
+
+ form > fieldset:hover {
+ background: rgba(255,255,255,0.1);
+ border-color: rgba(0,0,0,0.1);
+ }
+
+ form > fieldset.active {
+ background: rgba(255,255,255,0.25);
+ border-color: rgba(0,0,0,0.25);
+ }
+
+ form > fieldset > input {
+ margin-left: -20px;
+ }
+
+ section {
+ margin: 5px 0 0;
+ }
+
+ section fieldset:not(:first-child):not(:last-child) {
+ -webkit-transition: all 0.5s ease;
+ overflow: hidden;
+ max-height: 1.6em;
+ }
+
+ section.single fieldset:not(:first-child):not(:last-child) {
+ max-height: 0px;
+ }
+
+ section fieldset:last-child {
+ margin-top: 5px;
+ }
+
+ section fieldset:last-child label {
+ display: block;
+ }
+
+ section fieldset:last-child textarea {
+ width: 412px;
+ }
+
+ section > fieldset {
+ position: relative;
+ padding-left: 60px;
+ }
+
+ section > fieldset > legend {
+ left: 0;
+ top: 4px;
+ width: 53px;
+ text-align: right;
+ }
+
+ input[type='url']:invalid:not(:active):not(:focus) {
+ border-color: rgba(255,0,0,0.5);
+ background: rgba(255,0,0,0.25);
+ }
+
+ input:invalid:not(:active):not(:focus):after {
+ content: "This isn't a valid URL!";
+ display:block;
+ }
+
+ input[type="checkbox"] {
+ margin: 5px 0 5px 35px;
+ }
+
+ input[type="text"] {
+ width: 200px;
+ margin: 0 10px 0 0;
+ }
+
+ input[type="number"] {
+ width: 50px;
+ margin: 2px 10px 0 5px;
+ }
+
+ section label, section legend {
+ color: #999;
+ -webkit-transition: color 0.5s ease;
+ }
+
+ .incognito section label, .incognito section legend {
+ color: #BBB;
+ }
+
+ .active section label, .active section legend, form > fieldset > label {
+ color: #000;
+ -webkit-transition: color 0.5s ease;
+ }
+
+ .incognito .active section label, .incognito .active section legend, .incognito form > fieldset > label {
+ color: #FFF;
+ }
+
+ input[type="submit"], button {
+ border-radius: 2px;
+ box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.1);
+ -webkit-user-select: none;
+ background: -webkit-linear-gradient(#FAFAFA, #F4F4F4 40%, #E5E5E5);
+ border: 1px solid #AAA;
+ color: #444;
+ margin-bottom: 0;
+ min-width: 4em;
+ padding: 3px 12px;
+ margin-top: 0;
+ font-size: 1.1em;
+ }
+
+ .overlay {
+ display: block;
+ text-align: center;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 350px;
+ padding: 20px;
+ margin: -80px 0 0 -195px;
+ opacity: 0;
+ background: rgba(0, 0, 0, 0.75);
+ border-radius: 5px;
+ color: #FFF;
+ font: 1.5em/1.2 Helvetica Neue, sans-serif;
+ -webkit-transition: all 1.0s ease;
+ }
+ .overlay a {
+ color: #FFF;
+ }
+
+ .overlay.visible {
+ opacity: 1;
+ }
+ </style>
+</head>
+<body>
+ <h1>Proxy Configuration</h1>
+ <div role="main">
+ <form id="proxyForm">
+ <fieldset id="system">
+ <legend>System Settings</legend>
+ <input type="radio" name="proxyType" id="proxyTypeSystem" value="system">
+ <label for="proxyTypeSystem">Use the <em>system's proxy settings</em>.</label>
+ </fieldset>
+ <fieldset id="direct">
+ <legend>Direct Connection</legend>
+ <input type="radio" name="proxyType" id="proxyTypeDirect" value="direct">
+ <label for="proxyTypeDirect">Your computer is <em>directly connected</em> to the internet; no need for a proxy.</label>
+ </fieldset>
+ <fieldset id="pac_script">
+ <legend>Automatic Configuration</legend>
+ <input type="radio" name="proxyType" id="proxyTypeAutoconfig" value="autoconfig">
+ <label for="proxyTypeAutoconfig">Your proxy supports <em>automatic configuration</em>.</label>
+
+ <section>
+ <label for="autoconfigURL">Autoconfiguration URL (PAC file)</label>
+ <input type="url" name="autoconfigURL" id="autoconfigURL">
+ <input type="hidden" name="autoconfigData" id="autoconfigData">
+ </section>
+ </fieldset>
+ <fieldset id="fixed_servers">
+ <legend>Manual Proxy</legend>
+ <input type="radio" name="proxyType" id="proxyTypeManual" value="manual">
+ <label for="proxyTypeManual">Configure your proxy settings <em>manually</em>.</label>
+ <section>
+ <fieldset>
+ <legend>HTTP</legend>
+ <label for="proxyHostHttp">Host</label>
+ <select id="proxySchemeHttp" name="proxySchemeHttp">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostHttp" id="proxyHostHttp">
+
+ <label for="proxyPortHttp">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortHttp" id="proxyPortHttp">
+
+ <input type="checkbox" name="singleProxyForEverything" id="singleProxyForEverything">
+ <label for="singleProxyForEverything">Use the same proxy server for all protocols</label>
+ </fieldset>
+ <fieldset>
+ <legend>HTTPS</legend>
+ <label for="proxyHostHttps">Host</label>
+ <select id="proxySchemeHttps" name="proxySchemeHttps">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostHttps" id="proxyHostHttps">
+
+ <label for="proxyPortHttps">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortHttps" id="proxyPortHttps">
+ </fieldset>
+ <fieldset>
+ <legend>FTP</legend>
+ <label for="proxyHostFtp">Host</label>
+ <select id="proxySchemeFtp" name="proxySchemeFtp">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostFtp" id="proxyHostFtp">
+
+ <label for="proxyPortFtp">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortFtp" id="proxyPortFtp">
+ </fieldset>
+ <fieldset>
+ <legend>Fallback</legend>
+ <label for="proxyHostFallback">Host</label>
+ <select id="proxySchemeFallback" name="proxySchemeFallback">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostFallback" id="proxyHostFallback">
+
+ <label for="proxyPortFallback">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortFallback" id="proxyPortFallback">
+ </fieldset>
+ <fieldset>
+ <label for="bypassList">Bypass proxy for these hosts:</label>
+ <textarea id="bypassList" name="bypassList" placeholder="<local>,192.168.1.1/16, .example.com"></textarea>
+ </fieldset>
+ </section>
+ </fieldset>
+ <input type="submit" value="Save proxy settings">
+ <button value="incognito">Configure incognito window settings.</button>
+ </form>
+ </div>
+ <script src="./proxy_form_controller.js"></script>
+ <script>
+ var c = new ProxyFormController( 'proxyForm' );
+ </script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_error_handler.js b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_error_handler.js
new file mode 100644
index 0000000..bf6d80a
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_error_handler.js
@@ -0,0 +1,105 @@
+// Copyright (c) 2011 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 This file implements the ProxyErrorHandler class, which will
+ * flag proxy errors in a visual way for the extension's user.
+ *
+ * @author Mike West <mkwst@google.com>
+ */
+
+
+/**
+ * The proxy error handling object. Binds to the 'onProxyError' event, and
+ * changes the extensions badge to reflect the error state (yellow for
+ * non-fatal errors, red for fatal).
+ *
+ * @constructor
+ */
+function ProxyErrorHandler() {
+ // Handle proxy error events.
+ chrome.experimental.proxy.onProxyError.addListener(
+ this.handleError_.bind(this));
+
+ // Handle message events from popup.
+ chrome.extension.onRequest.addListener(
+ this.handleOnRequest_.bind(this));
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @typedef {{fatal: boolean, error: string, details: string}}
+ */
+ProxyErrorHandler.ErrorDetails;
+
+///////////////////////////////////////////////////////////////////////////////
+
+ProxyErrorHandler.prototype = {
+ /**
+ * Details of the most recent error.
+ * @type {?ProxyErrorHandler.ErrorDetails}
+ * @private
+ */
+ lastError_: null,
+
+ /**
+ * Handle request messages from the popup.
+ *
+ * @param {!{type:string}} request The external request to answer.
+ * @param {!MessageSender} sender Info about the script context that sent
+ * the request.
+ * @param {!function} sendResponse Function to call to send a response.
+ * @private
+ */
+ handleOnRequest_: function(request, sender, sendResponse) {
+ if (request.type === 'getError') {
+ sendResponse({result: this.getErrorDetails()});
+ } else if (request.type === 'clearError') {
+ this.clearErrorDetails();
+ sendResponse({result: true});
+ }
+ },
+
+ /**
+ * Handles the error event, storing the error details for later use, and
+ * badges the browser action icon.
+ *
+ * @param {!ProxyErrorHandler.ErrorDetails} details The error details.
+ * @private
+ */
+ handleError_: function(details) {
+ var RED = [255, 0, 0, 255];
+ var YELLOW = [255, 205, 0, 255];
+
+ // Badge the popup icon.
+ var color = details.fatal ? RED : YELLOW;
+ chrome.browserAction.setBadgeBackgroundColor({color: color});
+ chrome.browserAction.setBadgeText({text: 'X'});
+ chrome.browserAction.setTitle({
+ 'title': chrome.i18n.getMessage('errorPopupTitle', details.error)
+ });
+
+ // Store the error for display in the popup.
+ this.lastError_ = JSON.stringify(details);
+ },
+
+
+ /**
+ * Returns details of the last error handled.
+ *
+ * @return {?ProxyErrorHandler.ErrorDetails}
+ */
+ getErrorDetails: function() {
+ return this.lastError_;
+ },
+
+
+ /**
+ * Clears last handled error.
+ */
+ clearErrorDetails: function() {
+ this.lastError_ = null;
+ }
+}
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js
new file mode 100644
index 0000000..6b4fc09
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js
@@ -0,0 +1,778 @@
+// Copyright (c) 2011 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 This file implements the ProxyFormController class, which
+ * wraps a form element with logic that enables implementation of proxy
+ * settings.
+ *
+ * @author mkwst@google.com (Mike West)
+ */
+
+/**
+ * Wraps the proxy configuration form, binding proper handlers to its various
+ * `change`, `click`, etc. events in order to take appropriate action in
+ * response to user events.
+ *
+ * @param {string} id The form's DOM ID.
+ * @constructor
+ */
+var ProxyFormController = function(id) {
+ /**
+ * The wrapped form element
+ * @type {Node}
+ * @private
+ */
+ this.form_ = document.getElementById(id);
+
+ // Throw an error if the element either doesn't exist, or isn't a form.
+ if (!this.form_)
+ throw chrome.i18n.getMessage('errorIdNotFound', id);
+ else if (this.form_.nodeName !== 'FORM')
+ throw chrome.i18n.getMessage('errorIdNotForm', id);
+
+ /**
+ * Cached references to the `fieldset` groups that define the configuration
+ * options presented to the user.
+ *
+ * @type {NodeList}
+ * @private
+ */
+ this.configGroups_ = document.querySelectorAll('#' + id + ' > fieldset');
+
+ this.bindEventHandlers_();
+ this.readCurrentState_();
+
+ // Handle errors
+ this.handleProxyErrors_();
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * The proxy types we're capable of handling.
+ * @enum {string}
+ */
+ProxyFormController.ProxyTypes = {
+ AUTO: 'auto_detect',
+ PAC: 'pac_script',
+ DIRECT: 'direct',
+ FIXED: 'fixed_servers',
+ SYSTEM: 'system'
+};
+
+/**
+ * The window types we're capable of handling.
+ * @enum {int}
+ */
+ProxyFormController.WindowTypes = {
+ REGULAR: 1,
+ INCOGNITO: 2
+};
+
+/**
+ * The extension's level of control of Chrome's roxy setting
+ * @enum {string}
+ */
+ProxyFormController.LevelOfControl = {
+ NOT_CONTROLLABLE: 'NotControllable',
+ OTHER_EXTENSION: 'ControlledByOtherExtension',
+ AVAILABLE: 'ControllableByThisExtension',
+ CONTROLLING: 'ControlledByThisExtension'
+};
+
+/**
+ * The response type from 'proxy.settings.get'
+ *
+ * @typedef {{value: ProxyConfig,
+ * levelOfControl: ProxyFormController.LevelOfControl}}
+ */
+ProxyFormController.WrappedProxyConfig;
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Retrieves proxy settings that have been persisted across restarts.
+ *
+ * @return {?ProxyConfig} The persisted proxy configuration, or null if no
+ * value has been persisted.
+ * @static
+ */
+ProxyFormController.getPersistedSettings = function() {
+ var result = JSON.parse(window.localStorage['proxyConfig']);
+ return result ? result : null;
+};
+
+
+/**
+ * Persists proxy settings across restarts.
+ *
+ * @param {!ProxyConfig} config The proxy config to persist.
+ * @static
+ */
+ProxyFormController.setPersistedSettings = function(config) {
+ window.localStorage['proxyConfig'] = JSON.stringify(config);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+ProxyFormController.prototype = {
+ /**
+ * The form's current state.
+ * @type {regular: ?ProxyConfig, incognito: ?ProxyConfig}
+ * @private
+ */
+ config_: {regular: null, incognito: null},
+
+ /**
+ * Do we have access to incognito mode?
+ * @type {boolean}
+ * @private
+ */
+ isAllowedIncognitoAccess_: false,
+
+ /**
+ * @return {string} The PAC file URL (or an empty string).
+ */
+ get pacURL() {
+ return document.getElementById('autoconfigURL').value;
+ },
+
+
+ /**
+ * @param {!string} value The PAC file URL.
+ */
+ set pacURL(value) {
+ document.getElementById('autoconfigURL').value = value;
+ },
+
+
+ /**
+ * @return {string} The PAC file data (or an empty string).
+ */
+ get manualPac() {
+ return document.getElementById('autoconfigData').value;
+ },
+
+
+ /**
+ * @param {!string} value The PAC file data.
+ */
+ set manualPac(value) {
+ document.getElementById('autoconfigData').value = value;
+ },
+
+
+ /**
+ * @return {Array.<string>} A list of hostnames that should bypass the proxy.
+ */
+ get bypassList() {
+ return document.getElementById('bypassList').value.split(/\s*(?:,|^)\s*/m);
+ },
+
+
+ /**
+ * @param {?Array.<string>} data A list of hostnames that should bypass
+ * the proxy. If empty, the bypass list is emptied.
+ */
+ set bypassList(data) {
+ if (!data)
+ data = [];
+ document.getElementById('bypassList').value = data.join(', ');
+ },
+
+
+ /**
+ * @see http://code.google.com/chrome/extensions/trunk/experimental.proxy.html
+ * @return {?ProxyServer} An object containing the proxy server host, port,
+ * and scheme. If null, there is no single proxy.
+ */
+ get singleProxy() {
+ var checkbox = document.getElementById('singleProxyForEverything');
+ return checkbox.checked ? this.httpProxy : null;
+ },
+
+
+ /**
+ * @see http://code.google.com/chrome/extensions/trunk/experimental.proxy.html
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If null, the single proxy checkbox will be unchecked.
+ */
+ set singleProxy(data) {
+ var checkbox = document.getElementById('singleProxyForEverything');
+ checkbox.checked = !!data;
+
+ if (data)
+ this.httpProxy = data;
+
+ if (checkbox.checked)
+ checkbox.parentNode.parentNode.classList.add('single');
+ else
+ checkbox.parentNode.parentNode.classList.remove('single');
+ },
+
+ /**
+ * @return {?ProxyServer} An object containing the proxy server host, port
+ * and scheme.
+ */
+ get httpProxy() {
+ return this.getProxyImpl_('Http');
+ },
+
+
+ /**
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If empty, empties the proxy setting.
+ */
+ set httpProxy(data) {
+ this.setProxyImpl_('Http', data);
+ },
+
+
+ /**
+ * @return {?ProxyServer} An object containing the proxy server host, port
+ * and scheme.
+ */
+ get httpsProxy() {
+ return this.getProxyImpl_('Https');
+ },
+
+
+ /**
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If empty, empties the proxy setting.
+ */
+ set httpsProxy(data) {
+ this.setProxyImpl_('Https', data);
+ },
+
+
+ /**
+ * @return {?ProxyServer} An object containing the proxy server host, port
+ * and scheme.
+ */
+ get ftpProxy() {
+ return this.getProxyImpl_('Ftp');
+ },
+
+
+ /**
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If empty, empties the proxy setting.
+ */
+ set ftpProxy(data) {
+ this.setProxyImpl_('Ftp', data);
+ },
+
+
+ /**
+ * @return {?ProxyServer} An object containing the proxy server host, port
+ * and scheme.
+ */
+ get fallbackProxy() {
+ return this.getProxyImpl_('Fallback');
+ },
+
+
+ /**
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If empty, empties the proxy setting.
+ */
+ set fallbackProxy(data) {
+ this.setProxyImpl_('Fallback', data);
+ },
+
+
+ /**
+ * @param {string} type The type of proxy that's being set ("Http",
+ * "Https", etc.).
+ * @return {?ProxyServer} An object containing the proxy server host,
+ * port, and scheme.
+ * @private
+ */
+ getProxyImpl_: function(type) {
+ var result = {
+ scheme: document.getElementById('proxyScheme' + type).value,
+ host: document.getElementById('proxyHost' + type).value,
+ port: parseInt(document.getElementById('proxyPort' + type).value, 10)
+ };
+ return (result.scheme && result.host && result.port) ? result : undefined;
+ },
+
+
+ /**
+ * A generic mechanism for setting proxy data.
+ *
+ * @see http://code.google.com/chrome/extensions/trunk/experimental.proxy.html
+ * @param {string} type The type of proxy that's being set ("Http",
+ * "Https", etc.).
+ * @param {?ProxyServer} data An object containing the proxy server host,
+ * port, and scheme. If empty, empties the proxy setting.
+ * @private
+ */
+ setProxyImpl_: function(type, data) {
+ if (!data)
+ data = {scheme: 'http', host: '', port: ''};
+
+ document.getElementById('proxyScheme' + type).value = data.scheme;
+ document.getElementById('proxyHost' + type).value = data.host;
+ document.getElementById('proxyPort' + type).value = data.port;
+ },
+
+///////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Calls the proxy API to read the current settings, and populates the form
+ * accordingly.
+ *
+ * @private
+ */
+ readCurrentState_: function() {
+ chrome.extension.isAllowedIncognitoAccess(
+ this.handleIncognitoAccessResponse_.bind(this));
+ },
+
+ /**
+ * Handles the respnse from `chrome.extension.isAllowedIncognitoAccess`
+ * We can't render the form until we know what our access level is, so
+ * we wait until we have confirmed incognito access levels before
+ * asking for the proxy state.
+ *
+ * @param {boolean} state The state of incognito access.
+ * @private
+ */
+ handleIncognitoAccessResponse_: function(state) {
+ this.isAllowedIncognitoAccess_ = state;
+ chrome.experimental.proxy.settings.get({incognito: false},
+ this.handleRegularState_.bind(this));
+ if (this.isAllowedIncognitoAccess_) {
+ chrome.experimental.proxy.settings.get({incognito: true},
+ this.handleIncognitoState_.bind(this));
+ }
+ },
+
+ /**
+ * Handles the response from 'proxy.settings.get' for regular settings.
+ *
+ * @param {ProxyFormController.WrappedProxyConfig} c The proxy data and
+ * extension's level of control thereof.
+ * @private
+ */
+ handleRegularState_: function(c) {
+ if (c.levelOfControl === ProxyFormController.LevelOfControl.AVAILABLE ||
+ c.levelOfControl === ProxyFormController.LevelOfControl.CONTROLLING) {
+ this.recalcFormValues_(c.value);
+ this.config_.regular = c.value;
+ } else {
+ this.handleLackOfControl_(c.levelOfControl);
+ }
+ },
+
+ /**
+ * Handles the response from 'proxy.settings.get' for incognito settings.
+ *
+ * @param {ProxyFormController.WrappedProxyConfig} c The proxy data and
+ * extension's level of control thereof.
+ * @private
+ */
+ handleIncognitoState_: function(c) {
+ if (c.levelOfControl === ProxyFormController.LevelOfControl.AVAILABLE ||
+ c.levelOfControl === ProxyFormController.LevelOfControl.CONTROLLING) {
+ if (this.isIncognitoMode_())
+ this.recalcFormValues_(c.value);
+
+ this.config_.incognito = c.value;
+ } else {
+ this.handleLackOfControl_(c.levelOfControl);
+ }
+ },
+
+ /**
+ * Binds event handlers for the various bits and pieces of the form that
+ * are interesting to the controller.
+ *
+ * @private
+ */
+ bindEventHandlers_: function() {
+ this.form_.addEventListener('click', this.dispatchFormClick_.bind(this));
+ },
+
+
+ /**
+ * When a `click` event is triggered on the form, this function handles it by
+ * analyzing the context, and dispatching the click to the correct handler.
+ *
+ * @param {Event} e The event to be handled.
+ * @private
+ * @return {boolean} True if the event should bubble, false otherwise.
+ */
+ dispatchFormClick_: function(e) {
+ var t = e.target;
+
+ // Case 1: "Apply"
+ if (t.nodeName === 'INPUT' && t.getAttribute('type') === 'submit') {
+ return this.applyChanges_(e);
+
+ // Case 2: "Use the same proxy for all protocols" in an active section
+ } else if (t.nodeName === 'INPUT' &&
+ t.getAttribute('type') === 'checkbox' &&
+ t.parentNode.parentNode.parentNode.classList.contains('active')
+ ) {
+ return this.toggleSingleProxyConfig_(e);
+
+ // Case 3: "Flip to incognito mode."
+ } else if (t.nodeName === 'BUTTON') {
+ return this.toggleIncognitoMode_(e);
+
+ // Case 4: Click on something random: maybe changing active config group?
+ } else {
+ // Walk up the tree until we hit `form > fieldset` or fall off the top
+ while (t && (t.nodeName !== 'FIELDSET' ||
+ t.parentNode.nodeName !== 'FORM')) {
+ t = t.parentNode;
+ }
+ if (t) {
+ this.changeActive_(t);
+ return false;
+ }
+ }
+ return true;
+ },
+
+
+ /**
+ * Sets the form's active config group.
+ *
+ * @param {DOMElement} fieldset The configuration group to activate.
+ * @private
+ */
+ changeActive_: function(fieldset) {
+ for (var i = 0; i < this.configGroups_.length; i++) {
+ var el = this.configGroups_[i];
+ var radio = el.querySelector("input[type='radio']");
+ if (el === fieldset) {
+ el.classList.add('active');
+ radio.checked = true;
+ } else {
+ el.classList.remove('active');
+ }
+ }
+ this.recalcDisabledInputs_();
+ },
+
+
+ /**
+ * Recalculates the `disabled` state of the form's input elements, based
+ * on the currently active group, and that group's contents.
+ *
+ * @private
+ */
+ recalcDisabledInputs_: function() {
+ var i, j;
+ for (i = 0; i < this.configGroups_.length; i++) {
+ var el = this.configGroups_[i];
+ var inputs = el.querySelectorAll(
+ "input:not([type='radio']), select, textarea");
+ if (el.classList.contains('active')) {
+ for (j = 0; j < inputs.length; j++) {
+ inputs[j].removeAttribute('disabled');
+ }
+ } else {
+ for (j = 0; j < inputs.length; j++) {
+ inputs[j].setAttribute('disabled', 'disabled');
+ }
+ }
+ }
+ },
+
+
+ /**
+ * Handler called in response to click on form's submission button. Generates
+ * the proxy configuration and passes it to `useCustomProxySettings`, or
+ * handles errors in user input.
+ *
+ * @param {Event} e DOM event generated by the user's click.
+ * @private
+ */
+ applyChanges_: function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+
+ if (this.isIncognitoMode_())
+ this.config_.incognito = this.generateProxyConfig_();
+ else
+ this.config_.regular = this.generateProxyConfig_();
+
+ chrome.experimental.proxy.settings.set(
+ {value: this.config_.regular, incognito: false},
+ this.callbackForRegularSettings_.bind(this));
+ },
+
+ /**
+ * Called in response to setting a regular window's proxy settings: checks
+ * for `lastError`, and then sets incognito settings (if they exist).
+ *
+ * @private
+ */
+ callbackForRegularSettings_: function() {
+ if (chrome.extension.lastError) {
+ this.generateAlert_(chrome.i18n.getMessage('errorSettingRegularProxy'));
+ return;
+ }
+ if (this.config_.incognito) {
+ chrome.experimental.proxy.settings.set(
+ {value: this.config_.incognito, incognito: true},
+ this.callbackForIncognitoSettings_.bind(this));
+ } else {
+ ProxyFormController.setPersistedSettings(this.config_);
+ this.generateAlert_(chrome.i18n.getMessage('successfullySetProxy'));
+ }
+ },
+
+ /**
+ * Called in response to setting an incognito window's proxy settings: checks
+ * for `lastError` and sets a success message.
+ *
+ * @private
+ */
+ callbackForIncognitoSettings_: function() {
+ if (chrome.extension.lastError) {
+ this.generateAlert_(chrome.i18n.getMessage('errorSettingIncognitoProxy'));
+ return;
+ }
+ ProxyFormController.setPersistedSettings(this.config_);
+ this.generateAlert_(
+ chrome.i18n.getMessage('successfullySetProxy'));
+ },
+
+ /**
+ * Generates an alert overlay inside the proxy's popup, then closes the popup
+ * after a short delay.
+ *
+ * @param {string} msg The message to be displayed in the overlay.
+ * @param {?boolean} close Should the window be closed? Defaults to true.
+ * @private
+ */
+ generateAlert_: function(msg, close) {
+ var success = document.createElement('div');
+ success.classList.add('overlay');
+ success.setAttribute('role', 'alert');
+ success.textContent = msg;
+ document.body.appendChild(success);
+
+ setTimeout(function() { success.classList.add('visible'); }, 10);
+ setTimeout(function() {
+ if (close === false)
+ success.classList.remove('visible');
+ else
+ window.close();
+ }, 3000);
+ },
+
+
+ /**
+ * Parses the proxy configuration form, and generates a ProxyConfig object
+ * that can be passed to `useCustomProxyConfig`.
+ *
+ * @see http://code.google.com/chrome/extensions/trunk/experimental.proxy.html
+ * @return {ProxyConfig} The proxy configuration represented by the form.
+ * @private
+ */
+ generateProxyConfig_: function() {
+ var active = document.getElementsByClassName('active')[0];
+ switch (active.id) {
+ case ProxyFormController.ProxyTypes.SYSTEM:
+ return {mode: 'system'};
+ case ProxyFormController.ProxyTypes.DIRECT:
+ return {mode: 'direct'};
+ case ProxyFormController.ProxyTypes.PAC:
+ var pacScriptURL = this.pacURL;
+ var pacManual = this.manualPac;
+ if (pacScriptURL)
+ return {mode: 'pac_script', pacScript: {url: pacScriptURL}};
+ else if (pacManual)
+ return {mode: 'pac_script', pacScript: {data: pacManual}};
+ else
+ return {mode: 'auto_detect'};
+ case ProxyFormController.ProxyTypes.FIXED:
+ var config = {mode: 'fixed_servers'};
+ if (this.singleProxy) {
+ config.rules = {singleProxy: this.singleProxy};
+ } else {
+ config.rules = {
+ proxyForHttp: this.httpProxy,
+ proxyForHttps: this.httpsProxy,
+ proxyForFtp: this.ftpProxy,
+ fallbackProxy: this.fallbackProxy,
+ bypassList: this.bypassList
+ };
+ }
+ return config;
+ }
+ },
+
+
+ /**
+ * Sets the proper display classes based on the "Use the same proxy server
+ * for all protocols" checkbox. Expects to be called as an event handler
+ * when that field is clicked.
+ *
+ * @param {Event} e The `click` event to respond to.
+ * @private
+ */
+ toggleSingleProxyConfig_: function(e) {
+ var checkbox = e.target;
+ if (checkbox.nodeName === 'INPUT' &&
+ checkbox.getAttribute('type') === 'checkbox') {
+ if (checkbox.checked)
+ checkbox.parentNode.parentNode.classList.add('single');
+ else
+ checkbox.parentNode.parentNode.classList.remove('single');
+ }
+ },
+
+
+ /**
+ * Returns the form's current incognito status.
+ *
+ * @return {boolean} True if the form is in incognito mode, false otherwise.
+ * @private
+ */
+ isIncognitoMode_: function(e) {
+ return this.form_.parentNode.classList.contains('incognito');
+ },
+
+
+ /**
+ * Toggles the form's incognito mode. Saves the current state to an object
+ * property for later use, clears the form, and toggles the appropriate state.
+ *
+ * @param {Event} e The `click` event to respond to.
+ * @private
+ */
+ toggleIncognitoMode_: function(e) {
+ var div = this.form_.parentNode;
+ var button = document.getElementsByTagName('button')[0];
+
+ // Cancel the button click.
+ e.preventDefault();
+ e.stopPropagation();
+
+ // If we can't access Incognito settings, throw a message and return.
+ if (!this.isAllowedIncognitoAccess_) {
+ var msg = "I'm sorry, Dave, I'm afraid I can't do that. Give me access " +
+ "to Incognito settings by checking the checkbox labeled " +
+ "'Allow in Incognito mode', which is visible at " +
+ "chrome://extensions.";
+ this.generateAlert_(msg, false);
+ return;
+ }
+
+ if (this.isIncognitoMode_()) {
+ // In incognito mode, switching to cognito.
+ this.config_.incognito = this.generateProxyConfig_();
+ div.classList.remove('incognito');
+ this.recalcFormValues_(this.config_.regular);
+ button.innerText = 'Configure incognito window settings.';
+ } else {
+ // In cognito mode, switching to incognito.
+ this.config_.regular = this.generateProxyConfig_();
+ div.classList.add('incognito');
+ this.recalcFormValues_(this.config_.incognito);
+ button.innerText = 'Configure regular window settings.';
+ }
+ },
+
+
+ /**
+ * Sets the form's values based on a ProxyConfig.
+ *
+ * @param {!ProxyConfig} c The ProxyConfig object.
+ * @private
+ */
+ recalcFormValues_: function(c) {
+ // Normalize `auto_detect`
+ if (c.mode === 'auto_detect')
+ c.mode = 'pac_script';
+ // Activate one of the groups, based on `mode`.
+ this.changeActive_(document.getElementById(c.mode));
+ // Populate the PAC script
+ if (c.pacScript) {
+ if (c.pacScript.url)
+ this.pacURL = c.pacScript.url;
+ } else {
+ this.pacURL = '';
+ }
+ // Evaluate the `rules`
+ if (c.rules) {
+ var rules = c.rules;
+ if (rules.singleProxy) {
+ this.singleProxy = rules.singleProxy;
+ } else {
+ this.singleProxy = null;
+ this.httpProxy = rules.proxyForHttp;
+ this.httpsProxy = rules.proxyForHttps;
+ this.ftpProxy = rules.proxyForFtp;
+ this.fallbackProxy = rules.fallbackProxy;
+ }
+ this.bypassList = rules.bypassList;
+ } else {
+ this.singleProxy = null;
+ this.httpProxy = null;
+ this.httpsProxy = null;
+ this.ftpProxy = null;
+ this.fallbackProxy = null;
+ this.bypassList = '';
+ }
+ },
+
+
+ /**
+ * Handles the case in which this extension doesn't have the ability to
+ * control the Proxy settings, either because of an overriding policy
+ * or an extension with higher priority.
+ *
+ * @param {ProxyFormController.LevelOfControl} l The level of control this
+ * extension has over the proxy settings.
+ * @private
+ */
+ handleLackOfControl_: function(l) {
+ var msg;
+ if (l === ProxyFormController.LevelOfControl.NO_ACCESS)
+ msg = chrome.i18n.getMessage('errorNoExtensionAccess');
+ else if (l === ProxyFormController.LevelOfControl.OTHER_EXTENSION)
+ msg = chrome.i18n.getMessage('errorOtherExtensionControls');
+ this.generateAlert_(msg);
+ },
+
+
+ /**
+ * Handle the case in which errors have been generated outside the context
+ * of this popup.
+ *
+ * @private
+ */
+ handleProxyErrors_: function() {
+ chrome.extension.sendRequest(
+ {type: 'getError'},
+ this.handleProxyErrorHandlerResponse_.bind(this));
+ },
+
+ /**
+ * Handles response from ProxyErrorHandler
+ *
+ * @param {{result: !string}} response The message sent in response to this
+ * popup's request.
+ */
+ handleProxyErrorHandlerResponse_: function(response) {
+ if (response.result !== null) {
+ var error = response.result;
+ console.error(error); // TODO(mkwst): Do something more interesting
+ this.generateAlert_(
+ chrome.i18n.getMessage('errorProxyError', error.error),
+ false);
+ }
+ chrome.extension.sendRequest({type: 'clearError'});
+ }
+};
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/jsunittest.js b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/jsunittest.js
new file mode 100644
index 0000000..8e1eab0
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/jsunittest.js
@@ -0,0 +1,964 @@
+/* Jsunittest, version 0.6.0
+ * (c) 2008 Dr Nic Williams
+ *
+ * Jsunittest is freely distributable under
+ * the terms of an MIT-style license.
+ * For details, see the web site: http://jsunittest.rubyforge.org
+ *
+ *--------------------------------------------------------------------------*/
+
+var JsUnitTest = {
+ Version: '0.6.0',
+};
+
+var DrNicTest = {
+ Unit: {},
+ inspect: function(object) {
+ try {
+ if (typeof object == "undefined") return 'undefined';
+ if (object === null) return 'null';
+ if (typeof object == "string") {
+ var useDoubleQuotes = arguments[1];
+ var escapedString = this.gsub(object, /[\x00-\x1f\\]/, function(match) {
+ var character = String.specialChar[match[0]];
+ return character ? character : '\\u00' + match[0].charCodeAt().toPaddedString(2, 16);
+ });
+ if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ };
+ return String(object);
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+ $: function(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push(this.$(arguments[i]));
+ return elements;
+ }
+ if (typeof element == "string")
+ element = document.getElementById(element);
+ return element;
+ },
+ gsub: function(source, pattern, replacement) {
+ var result = '', match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += DrNicTest.String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+ scan: function(source, pattern, iterator) {
+ this.gsub(source, pattern, iterator);
+ return String(source);
+ },
+ escapeHTML: function(data) {
+ return data.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
+ },
+ arrayfromargs: function(args) {
+ var myarray = new Array();
+ var i;
+
+ for (i=0;i<args.length;i++)
+ myarray[i] = args[i];
+
+ return myarray;
+ },
+ hashToSortedArray: function(hash) {
+ var results = [];
+ for (key in hash) {
+ results.push([key, hash[key]]);
+ }
+ return results.sort();
+ },
+ flattenArray: function(array) {
+ var results = arguments[1] || [];
+ for (var i=0; i < array.length; i++) {
+ var object = array[i];
+ if (object != null && typeof object == "object" &&
+ 'splice' in object && 'join' in object) {
+ this.flattenArray(object, results);
+ } else {
+ results.push(object);
+ }
+ };
+ return results;
+ },
+ selectorMatch: function(expression, element) {
+ var tokens = [];
+ var patterns = {
+ // combinators must be listed first
+ // (and descendant needs to be last combinator)
+ laterSibling: /^\s*~\s*/,
+ child: /^\s*>\s*/,
+ adjacent: /^\s*\+\s*/,
+ descendant: /^\s/,
+
+ // selectors follow
+ tagName: /^\s*(\*|[\w\-]+)(\b|$)?/,
+ id: /^#([\w\-\*]+)(\b|$)/,
+ className: /^\.([\w\-\*]+)(\b|$)/,
+ pseudo:
+ /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/,
+ attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/,
+ attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/
+ };
+
+ var assertions = {
+ tagName: function(element, matches) {
+ return matches[1].toUpperCase() == element.tagName.toUpperCase();
+ },
+
+ className: function(element, matches) {
+ return Element.hasClassName(element, matches[1]);
+ },
+
+ id: function(element, matches) {
+ return element.id === matches[1];
+ },
+
+ attrPresence: function(element, matches) {
+ return Element.hasAttribute(element, matches[1]);
+ },
+
+ attr: function(element, matches) {
+ var nodeValue = Element.readAttribute(element, matches[1]);
+ return nodeValue && operators[matches[2]](nodeValue, matches[5] || matches[6]);
+ }
+ };
+ var e = this.expression, ps = patterns, as = assertions;
+ var le, p, m;
+
+ while (e && le !== e && (/\S/).test(e)) {
+ le = e;
+ for (var i in ps) {
+ p = ps[i];
+ if (m = e.match(p)) {
+ // use the Selector.assertions methods unless the selector
+ // is too complex.
+ if (as[i]) {
+ tokens.push([i, Object.clone(m)]);
+ e = e.replace(m[0], '');
+ }
+ }
+ }
+ }
+
+ var match = true, name, matches;
+ for (var i = 0, token; token = tokens[i]; i++) {
+ name = token[0], matches = token[1];
+ if (!assertions[name](element, matches)) {
+ match = false; break;
+ }
+ }
+
+ return match;
+ },
+ toQueryParams: function(query, separator) {
+ var query = query || window.location.search;
+ var match = query.replace(/^\s+/, '').replace(/\s+$/, '').match(/([^?#]*)(#.*)?$/);
+ if (!match) return { };
+
+ var hash = {};
+ var parts = match[1].split(separator || '&');
+ for (var i=0; i < parts.length; i++) {
+ var pair = parts[i].split('=');
+ if (pair[0]) {
+ var key = decodeURIComponent(pair.shift());
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ if (value != undefined) value = decodeURIComponent(value);
+
+ if (key in hash) {
+ var object = hash[key];
+ var isArray = object != null && typeof object == "object" &&
+ 'splice' in object && 'join' in object
+ if (!isArray) hash[key] = [hash[key]];
+ hash[key].push(value);
+ }
+ else hash[key] = value;
+ }
+ };
+ return hash;
+ },
+
+ String: {
+ interpret: function(value) {
+ return value == null ? '' : String(value);
+ }
+ }
+};
+
+DrNicTest.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == "function") return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+};
+
+DrNicTest.Template = function(template, pattern) {
+ this.template = template; //template.toString();
+ this.pattern = pattern || DrNicTest.Template.Pattern;
+};
+
+DrNicTest.Template.prototype.evaluate = function(object) {
+ if (typeof object.toTemplateReplacements == "function")
+ object = object.toTemplateReplacements();
+
+ return DrNicTest.gsub(this.template, this.pattern, function(match) {
+ if (object == null) return '';
+
+ var before = match[1] || '';
+ if (before == '\\') return match[2];
+
+ var ctx = object, expr = match[3];
+ var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/;
+ match = pattern.exec(expr);
+ if (match == null) return before;
+
+ while (match != null) {
+ var comp = (match[1].indexOf('[]') === 0) ? match[2].gsub('\\\\]', ']') : match[1];
+ ctx = ctx[comp];
+ if (null == ctx || '' == match[3]) break;
+ expr = expr.substring('[' == match[3] ? match[1].length : match[0].length);
+ match = pattern.exec(expr);
+ }
+
+ return before + DrNicTest.String.interpret(ctx);
+ });
+}
+
+DrNicTest.Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+DrNicTest.Event = {};
+// written by Dean Edwards, 2005
+// with input from Tino Zijdel, Matthias Miller, Diego Perini
+// namespaced by Dr Nic Williams 2008
+
+// http://dean.edwards.name/weblog/2005/10/add-event/
+// http://dean.edwards.name/weblog/2005/10/add-event2/
+DrNicTest.Event.addEvent = function(element, type, handler) {
+ if (element.addEventListener) {
+ element.addEventListener(type, handler, false);
+ } else {
+ // assign each event handler a unique ID
+ if (!handler.$$guid) handler.$$guid = addEvent.guid++;
+ // create a hash table of event types for the element
+ if (!element.events) element.events = {};
+ // create a hash table of event handlers for each element/event pair
+ var handlers = element.events[type];
+ if (!handlers) {
+ handlers = element.events[type] = {};
+ // store the existing event handler (if there is one)
+ if (element["on" + type]) {
+ handlers[0] = element["on" + type];
+ }
+ }
+ // store the event handler in the hash table
+ handlers[handler.$$guid] = handler;
+ // assign a global event handler to do all the work
+ element["on" + type] = handleEvent;
+ }
+};
+// a counter used to create unique IDs
+DrNicTest.Event.addEvent.guid = 1;
+
+DrNicTest.Event.removeEvent = function(element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else {
+ // delete the event handler from the hash table
+ if (element.events && element.events[type]) {
+ delete element.events[type][handler.$$guid];
+ }
+ }
+};
+
+DrNicTest.Event.handleEvent = function(event) {
+ var returnValue = true;
+ // grab the event object (IE uses a global event object)
+ event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
+ // get a reference to the hash table of event handlers
+ var handlers = this.events[event.type];
+ // execute each event handler
+ for (var i in handlers) {
+ this.$$handleEvent = handlers[i];
+ if (this.$$handleEvent(event) === false) {
+ returnValue = false;
+ }
+ }
+ return returnValue;
+};
+
+DrNicTest.Event.fixEvent = function(event) {
+ // add W3C standard event methods
+ event.preventDefault = fixEvent.preventDefault;
+ event.stopPropagation = fixEvent.stopPropagation;
+ return event;
+};
+DrNicTest.Event.fixEvent.preventDefault = function() {
+ this.returnValue = false;
+};
+DrNicTest.Event.fixEvent.stopPropagation = function() {
+ this.cancelBubble = true;
+};
+
+DrNicTest.Unit.Logger = function(element) {
+ this.element = DrNicTest.$(element);
+ if (this.element) this._createLogTable();
+};
+
+DrNicTest.Unit.Logger.prototype.start = function(testName) {
+ if (!this.element) return;
+ var tbody = this.element.getElementsByTagName('tbody')[0];
+ tbody.innerHTML = tbody.innerHTML + '<tr><td>' + testName + '</td><td></td><td></td></tr>';
+};
+
+DrNicTest.Unit.Logger.prototype.setStatus = function(status) {
+ var logline = this.getLastLogLine();
+ logline.className = status;
+ var statusCell = logline.getElementsByTagName('td')[1];
+ statusCell.innerHTML = status;
+};
+
+DrNicTest.Unit.Logger.prototype.finish = function(status, summary) {
+ if (!this.element) return;
+ this.setStatus(status);
+ this.message(summary);
+};
+
+DrNicTest.Unit.Logger.prototype.message = function(message) {
+ if (!this.element) return;
+ var cell = this.getMessageCell();
+ cell.innerHTML = this._toHTML(message);
+};
+
+DrNicTest.Unit.Logger.prototype.summary = function(summary) {
+ if (!this.element) return;
+ var div = this.element.getElementsByTagName('div')[0];
+ div.innerHTML = this._toHTML(summary);
+};
+
+DrNicTest.Unit.Logger.prototype.getLastLogLine = function() {
+ var tbody = this.element.getElementsByTagName('tbody')[0];
+ var loglines = tbody.getElementsByTagName('tr');
+ return loglines[loglines.length - 1];
+};
+
+DrNicTest.Unit.Logger.prototype.getMessageCell = function() {
+ var logline = this.getLastLogLine();
+ return logline.getElementsByTagName('td')[2];
+};
+
+DrNicTest.Unit.Logger.prototype._createLogTable = function() {
+ var html = '<div class="logsummary">running...</div>' +
+ '<table class="logtable">' +
+ '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
+ '<tbody class="loglines"></tbody>' +
+ '</table>';
+ this.element.innerHTML = html;
+};
+
+DrNicTest.Unit.Logger.prototype.appendActionButtons = function(actions) {
+ // actions = $H(actions);
+ // if (!actions.any()) return;
+ // var div = new Element("div", {className: 'action_buttons'});
+ // actions.inject(div, function(container, action) {
+ // var button = new Element("input").setValue(action.key).observe("click", action.value);
+ // button.type = "button";
+ // return container.insert(button);
+ // });
+ // this.getMessageCell().insert(div);
+};
+
+DrNicTest.Unit.Logger.prototype._toHTML = function(txt) {
+ return DrNicTest.escapeHTML(txt).replace(/\n/g,"<br/>");
+};
+DrNicTest.Unit.MessageTemplate = function(string) {
+ var parts = [];
+ var str = DrNicTest.scan((string || ''), /(?=[^\\])\?|(?:\\\?|[^\?])+/, function(part) {
+ parts.push(part[0]);
+ });
+ this.parts = parts;
+};
+
+DrNicTest.Unit.MessageTemplate.prototype.evaluate = function(params) {
+ var results = [];
+ for (var i=0; i < this.parts.length; i++) {
+ var part = this.parts[i];
+ var result = (part == '?') ? DrNicTest.inspect(params.shift()) : part.replace(/\\\?/, '?');
+ results.push(result);
+ };
+ return results.join('');
+};
+// A generic function for performming AJAX requests
+// It takes one argument, which is an object that contains a set of options
+// All of which are outline in the comments, below
+// From John Resig's book Pro JavaScript Techniques
+// published by Apress, 2006-8
+DrNicTest.ajax = function( options ) {
+
+ // Load the options object with defaults, if no
+ // values were provided by the user
+ options = {
+ // The type of HTTP Request
+ type: options.type || "POST",
+
+ // The URL the request will be made to
+ url: options.url || "",
+
+ // How long to wait before considering the request to be a timeout
+ timeout: options.timeout || 5000,
+
+ // Functions to call when the request fails, succeeds,
+ // or completes (either fail or succeed)
+ onComplete: options.onComplete || function(){},
+ onError: options.onError || function(){},
+ onSuccess: options.onSuccess || function(){},
+
+ // The data type that'll be returned from the server
+ // the default is simply to determine what data was returned from the
+ // and act accordingly.
+ data: options.data || ""
+ };
+
+ // Create the request object
+ var xml = new XMLHttpRequest();
+
+ // Open the asynchronous POST request
+ xml.open(options.type, options.url, true);
+
+ // We're going to wait for a request for 5 seconds, before giving up
+ var timeoutLength = 5000;
+
+ // Keep track of when the request has been succesfully completed
+ var requestDone = false;
+
+ // Initalize a callback which will fire 5 seconds from now, cancelling
+ // the request (if it has not already occurred).
+ setTimeout(function(){
+ requestDone = true;
+ }, timeoutLength);
+
+ // Watch for when the state of the document gets updated
+ xml.onreadystatechange = function(){
+ // Wait until the data is fully loaded,
+ // and make sure that the request hasn't already timed out
+ if ( xml.readyState == 4 && !requestDone ) {
+
+ // Check to see if the request was successful
+ if ( httpSuccess( xml ) ) {
+
+ // Execute the success callback with the data returned from the server
+ options.onSuccess( httpData( xml, options.type ) );
+
+ // Otherwise, an error occurred, so execute the error callback
+ } else {
+ options.onError();
+ }
+
+ // Call the completion callback
+ options.onComplete();
+
+ // Clean up after ourselves, to avoid memory leaks
+ xml = null;
+ }
+ };
+
+ // Establish the connection to the server
+ xml.send();
+
+ // Determine the success of the HTTP response
+ function httpSuccess(r) {
+ try {
+ // If no server status is provided, and we're actually
+ // requesting a local file, then it was successful
+ return !r.status && location.protocol == "file:" ||
+
+ // Any status in the 200 range is good
+ ( r.status >= 200 && r.status < 300 ) ||
+
+ // Successful if the document has not been modified
+ r.status == 304 ||
+
+ // Safari returns an empty status if the file has not been modified
+ navigator.userAgent.indexOf("Safari") >= 0 && typeof r.status == "undefined";
+ } catch(e){}
+
+ // If checking the status failed, then assume that the request failed too
+ return false;
+ }
+
+ // Extract the correct data from the HTTP response
+ function httpData(r,type) {
+ // Get the content-type header
+ var ct = r.getResponseHeader("content-type");
+
+ // If no default type was provided, determine if some
+ // form of XML was returned from the server
+ var data = !type && ct && ct.indexOf("xml") >= 0;
+
+ // Get the XML Document object if XML was returned from
+ // the server, otherwise return the text contents returned by the server
+ data = type == "xml" || data ? r.responseXML : r.responseText;
+
+ // If the specified type is "script", execute the returned text
+ // response as if it was JavaScript
+ if ( type == "script" )
+ eval.call( window, data );
+
+ // Return the response data (either an XML Document or a text string)
+ return data;
+ }
+
+}
+DrNicTest.Unit.Assertions = {
+ buildMessage: function(message, template) {
+ var args = DrNicTest.arrayfromargs(arguments).slice(2);
+ return (message ? message + '\n' : '') +
+ new DrNicTest.Unit.MessageTemplate(template).evaluate(args);
+ },
+
+ flunk: function(message) {
+ this.assertBlock(message || 'Flunked', function() { return false });
+ },
+
+ assertBlock: function(message, block) {
+ try {
+ block.call(this) ? this.pass() : this.fail(message);
+ } catch(e) { this.error(e) }
+ },
+
+ assert: function(expression, message) {
+ message = this.buildMessage(message || 'assert', 'got <?>', expression);
+ this.assertBlock(message, function() { return expression });
+ },
+
+ assertEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertEqual', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected == actual });
+ },
+
+ assertNotEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotEqual', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected != actual });
+ },
+
+ assertEnumEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertEnumEqual', 'expected <?>, actual: <?>', expected, actual);
+ var expected_array = DrNicTest.flattenArray(expected);
+ var actual_array = DrNicTest.flattenArray(actual);
+ this.assertBlock(message, function() {
+ if (expected_array.length == actual_array.length) {
+ for (var i=0; i < expected_array.length; i++) {
+ if (expected_array[i] != actual_array[i]) return false;
+ };
+ return true;
+ }
+ return false;
+ });
+ },
+
+ assertEnumNotEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertEnumNotEqual', '<?> was the same as <?>', expected, actual);
+ var expected_array = DrNicTest.flattenArray(expected);
+ var actual_array = DrNicTest.flattenArray(actual);
+ this.assertBlock(message, function() {
+ if (expected_array.length == actual_array.length) {
+ for (var i=0; i < expected_array.length; i++) {
+ if (expected_array[i] != actual_array[i]) return true;
+ };
+ return false;
+ }
+ return true;
+ });
+ },
+
+ assertHashEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertHashEqual', 'expected <?>, actual: <?>', expected, actual);
+ var expected_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(expected));
+ var actual_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(actual));
+ var block = function() {
+ if (expected_array.length == actual_array.length) {
+ for (var i=0; i < expected_array.length; i++) {
+ if (expected_array[i] != actual_array[i]) return false;
+ };
+ return true;
+ }
+ return false;
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertHashNotEqual: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertHashNotEqual', '<?> was the same as <?>', expected, actual);
+ var expected_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(expected));
+ var actual_array = DrNicTest.flattenArray(DrNicTest.hashToSortedArray(actual));
+ // from now we recursively zip & compare nested arrays
+ var block = function() {
+ if (expected_array.length == actual_array.length) {
+ for (var i=0; i < expected_array.length; i++) {
+ if (expected_array[i] != actual_array[i]) return true;
+ };
+ return false;
+ }
+ return true;
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertIdentical: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertIdentical', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected === actual });
+ },
+
+ assertNotIdentical: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotIdentical', 'expected <?>, actual: <?>', expected, actual);
+ this.assertBlock(message, function() { return expected !== actual });
+ },
+
+ assertNull: function(obj, message) {
+ message = this.buildMessage(message || 'assertNull', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj === null });
+ },
+
+ assertNotNull: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotNull', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj !== null });
+ },
+
+ assertUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return typeof obj == "undefined" });
+ },
+
+ assertNotUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return typeof obj != "undefined" });
+ },
+
+ assertNullOrUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNullOrUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj == null });
+ },
+
+ assertNotNullOrUndefined: function(obj, message) {
+ message = this.buildMessage(message || 'assertNotNullOrUndefined', 'got <?>', obj);
+ this.assertBlock(message, function() { return obj != null });
+ },
+
+ assertMatch: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertMatch', 'regex <?> did not match <?>', expected, actual);
+ this.assertBlock(message, function() { return new RegExp(expected).exec(actual) });
+ },
+
+ assertNoMatch: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNoMatch', 'regex <?> matched <?>', expected, actual);
+ this.assertBlock(message, function() { return !(new RegExp(expected).exec(actual)) });
+ },
+
+ assertHidden: function(element, message) {
+ message = this.buildMessage(message || 'assertHidden', '? isn\'t hidden.', element);
+ this.assertBlock(message, function() { return element.style.display == 'none' });
+ },
+
+ assertInstanceOf: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertInstanceOf', '<?> was not an instance of the expected type', actual);
+ this.assertBlock(message, function() { return actual instanceof expected });
+ },
+
+ assertNotInstanceOf: function(expected, actual, message) {
+ message = this.buildMessage(message || 'assertNotInstanceOf', '<?> was an instance of the expected type', actual);
+ this.assertBlock(message, function() { return !(actual instanceof expected) });
+ },
+
+ assertRespondsTo: function(method, obj, message) {
+ message = this.buildMessage(message || 'assertRespondsTo', 'object doesn\'t respond to <?>', method);
+ this.assertBlock(message, function() { return (method in obj && typeof obj[method] == 'function') });
+ },
+
+ assertRaise: function(exceptionName, method, message) {
+ message = this.buildMessage(message || 'assertRaise', '<?> exception expected but none was raised', exceptionName);
+ var block = function() {
+ try {
+ method();
+ return false;
+ } catch(e) {
+ if (e.name == exceptionName) return true;
+ else throw e;
+ }
+ };
+ this.assertBlock(message, block);
+ },
+
+ assertNothingRaised: function(method, message) {
+ try {
+ method();
+ this.assert(true, "Expected nothing to be thrown");
+ } catch(e) {
+ message = this.buildMessage(message || 'assertNothingRaised', '<?> was thrown when nothing was expected.', e);
+ this.flunk(message);
+ }
+ },
+
+ _isVisible: function(element) {
+ element = DrNicTest.$(element);
+ if(!element.parentNode) return true;
+ this.assertNotNull(element);
+ if(element.style && element.style.display == 'none')
+ return false;
+
+ return arguments.callee.call(this, element.parentNode);
+ },
+
+ assertVisible: function(element, message) {
+ message = this.buildMessage(message, '? was not visible.', element);
+ this.assertBlock(message, function() { return this._isVisible(element) });
+ },
+
+ assertNotVisible: function(element, message) {
+ message = this.buildMessage(message, '? was not hidden and didn\'t have a hidden parent either.', element);
+ this.assertBlock(message, function() { return !this._isVisible(element) });
+ },
+
+ assertElementsMatch: function() {
+ var pass = true, expressions = DrNicTest.arrayfromargs(arguments);
+ var elements = expressions.shift();
+ if (elements.length != expressions.length) {
+ message = this.buildMessage('assertElementsMatch', 'size mismatch: ? elements, ? expressions (?).', elements.length, expressions.length, expressions);
+ this.flunk(message);
+ pass = false;
+ }
+ for (var i=0; i < expressions.length; i++) {
+ var expression = expressions[i];
+ var element = DrNicTest.$(elements[i]);
+ if (DrNicTest.selectorMatch(expression, element)) {
+ pass = true;
+ break;
+ }
+ message = this.buildMessage('assertElementsMatch', 'In index <?>: expected <?> but got ?', index, expression, element);
+ this.flunk(message);
+ pass = false;
+ };
+ this.assert(pass, "Expected all elements to match.");
+ },
+
+ assertElementMatches: function(element, expression, message) {
+ this.assertElementsMatch([element], expression);
+ }
+};
+DrNicTest.Unit.Runner = function(testcases) {
+ var argumentOptions = arguments[1] || {};
+ var options = this.options = {};
+ options.testLog = ('testLog' in argumentOptions) ? argumentOptions.testLog : 'testlog';
+ options.resultsURL = this.queryParams.resultsURL;
+ options.testLog = DrNicTest.$(options.testLog);
+
+ this.tests = this.getTests(testcases);
+ this.currentTest = 0;
+ this.logger = new DrNicTest.Unit.Logger(options.testLog);
+
+ var self = this;
+ DrNicTest.Event.addEvent(window, "load", function() {
+ setTimeout(function() {
+ self.runTests();
+ }, 0.1);
+ });
+};
+
+DrNicTest.Unit.Runner.prototype.queryParams = DrNicTest.toQueryParams();
+
+DrNicTest.Unit.Runner.prototype.portNumber = function() {
+ if (window.location.search.length > 0) {
+ var matches = window.location.search.match(/\:(\d{3,5})\//);
+ if (matches) {
+ return parseInt(matches[1]);
+ }
+ }
+ return null;
+};
+
+DrNicTest.Unit.Runner.prototype.getTests = function(testcases) {
+ var tests = [], options = this.options;
+ if (this.queryParams.tests) tests = this.queryParams.tests.split(',');
+ else if (options.tests) tests = options.tests;
+ else if (options.test) tests = [option.test];
+ else {
+ for (testname in testcases) {
+ if (testname.match(/^test/)) tests.push(testname);
+ }
+ }
+ var results = [];
+ for (var i=0; i < tests.length; i++) {
+ var test = tests[i];
+ if (testcases[test])
+ results.push(
+ new DrNicTest.Unit.Testcase(test, testcases[test], testcases.setup, testcases.teardown)
+ );
+ };
+ return results;
+};
+
+DrNicTest.Unit.Runner.prototype.getResult = function() {
+ var results = {
+ tests: this.tests.length,
+ assertions: 0,
+ failures: 0,
+ errors: 0
+ };
+
+ for (var i=0; i < this.tests.length; i++) {
+ var test = this.tests[i];
+ results.assertions += test.assertions;
+ results.failures += test.failures;
+ results.errors += test.errors;
+ };
+ return results;
+};
+
+DrNicTest.Unit.Runner.prototype.postResults = function() {
+ if (this.options.resultsURL) {
+ // new Ajax.Request(this.options.resultsURL,
+ // { method: 'get', parameters: this.getResult(), asynchronous: false });
+ var results = this.getResult();
+ var url = this.options.resultsURL + "?";
+ url += "assertions="+ results.assertions + "&";
+ url += "failures=" + results.failures + "&";
+ url += "errors=" + results.errors;
+ DrNicTest.ajax({
+ url: url,
+ type: 'GET'
+ })
+ }
+};
+
+DrNicTest.Unit.Runner.prototype.runTests = function() {
+ var test = this.tests[this.currentTest], actions;
+
+ if (!test) return this.finish();
+ if (!test.isWaiting) this.logger.start(test.name);
+ test.run();
+ var self = this;
+ if(test.isWaiting) {
+ this.logger.message("Waiting for " + test.timeToWait + "ms");
+ // setTimeout(this.runTests.bind(this), test.timeToWait || 1000);
+ setTimeout(function() {
+ self.runTests();
+ }, test.timeToWait || 1000);
+ return;
+ }
+
+ this.logger.finish(test.status(), test.summary());
+ if (actions = test.actions) this.logger.appendActionButtons(actions);
+ this.currentTest++;
+ // tail recursive, hopefully the browser will skip the stackframe
+ this.runTests();
+};
+
+DrNicTest.Unit.Runner.prototype.finish = function() {
+ this.postResults();
+ this.logger.summary(this.summary());
+};
+
+DrNicTest.Unit.Runner.prototype.summary = function() {
+ return new DrNicTest.Template('#{tests} tests, #{assertions} assertions, #{failures} failures, #{errors} errors').evaluate(this.getResult());
+};
+DrNicTest.Unit.Testcase = function(name, test, setup, teardown) {
+ this.name = name;
+ this.test = test || function() {};
+ this.setup = setup || function() {};
+ this.teardown = teardown || function() {};
+ this.messages = [];
+ this.actions = {};
+};
+// import DrNicTest.Unit.Assertions
+
+for (method in DrNicTest.Unit.Assertions) {
+ DrNicTest.Unit.Testcase.prototype[method] = DrNicTest.Unit.Assertions[method];
+}
+
+DrNicTest.Unit.Testcase.prototype.isWaiting = false;
+DrNicTest.Unit.Testcase.prototype.timeToWait = 1000;
+DrNicTest.Unit.Testcase.prototype.assertions = 0;
+DrNicTest.Unit.Testcase.prototype.failures = 0;
+DrNicTest.Unit.Testcase.prototype.errors = 0;
+// DrNicTest.Unit.Testcase.prototype.isRunningFromRake = window.location.port == 4711;
+DrNicTest.Unit.Testcase.prototype.isRunningFromRake = window.location.port;
+
+DrNicTest.Unit.Testcase.prototype.wait = function(time, nextPart) {
+ this.isWaiting = true;
+ this.test = nextPart;
+ this.timeToWait = time;
+};
+
+DrNicTest.Unit.Testcase.prototype.run = function(rethrow) {
+ try {
+ try {
+ if (!this.isWaiting) this.setup();
+ this.isWaiting = false;
+ this.test();
+ } finally {
+ if(!this.isWaiting) {
+ this.teardown();
+ }
+ }
+ }
+ catch(e) {
+ if (rethrow) throw e;
+ this.error(e, this);
+ }
+};
+
+DrNicTest.Unit.Testcase.prototype.summary = function() {
+ var msg = '#{assertions} assertions, #{failures} failures, #{errors} errors\n';
+ return new DrNicTest.Template(msg).evaluate(this) +
+ this.messages.join("\n");
+};
+
+DrNicTest.Unit.Testcase.prototype.pass = function() {
+ this.assertions++;
+};
+
+DrNicTest.Unit.Testcase.prototype.fail = function(message) {
+ this.failures++;
+ var line = "";
+ try {
+ throw new Error("stack");
+ } catch(e){
+ line = (/\.html:(\d+)/.exec(e.stack || '') || ['',''])[1];
+ }
+ this.messages.push("Failure: " + message + (line ? " Line #" + line : ""));
+};
+
+DrNicTest.Unit.Testcase.prototype.info = function(message) {
+ this.messages.push("Info: " + message);
+};
+
+DrNicTest.Unit.Testcase.prototype.error = function(error, test) {
+ this.errors++;
+ this.actions['retry with throw'] = function() { test.run(true) };
+ this.messages.push(error.name + ": "+ error.message + "(" + DrNicTest.inspect(error) + ")");
+};
+
+DrNicTest.Unit.Testcase.prototype.status = function() {
+ if (this.failures > 0) return 'failed';
+ if (this.errors > 0) return 'error';
+ return 'passed';
+};
+
+DrNicTest.Unit.Testcase.prototype.benchmark = function(operation, iterations) {
+ var startAt = new Date();
+ (iterations || 1).times(operation);
+ var timeTaken = ((new Date())-startAt);
+ this.info((arguments[2] || 'Operation') + ' finished ' +
+ iterations + ' iterations in ' + (timeTaken/1000)+'s' );
+ return timeTaken;
+};
+
+Test = DrNicTest
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.html b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.html
new file mode 100644
index 0000000..096e709
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+<head>
+ <title>Popup for Proxy API Test</title>
+ <link rel="stylesheet" type="text/css" href="./unittest.css">
+ <script src="./jsunittest.js"></script>
+ <script src="../proxy_form_controller.js"></script>
+</head>
+<body>
+ <h1>Proxy Configuration Unit Tests</h1>
+
+ <h2>ProxyFormController</h2>
+ <div id="proxyformcontrollerlog"></div>
+
+ <div id="fixture">
+ <form id="proxyForm">
+ <fieldset id="system">
+ <legend>System Settings</legend>
+ <input type="radio" name="proxyType" id="proxyTypeSystem" value="system">
+ <label for="proxyTypeSystem">Use the <em>system's proxy settings</em>.</label>
+ </fieldset>
+ <fieldset id="direct">
+ <legend>Direct Connection</legend>
+ <input type="radio" name="proxyType" id="proxyTypeDirect" value="direct">
+ <label for="proxyTypeDirect">Your computer is <em>directly connected</em> to the internet; no need for a proxy.</label>
+ </fieldset>
+ <fieldset id="pac_script">
+ <legend>Automatic Configuration</legend>
+ <input type="radio" name="proxyType" id="proxyTypeAutoconfig" value="autoconfig">
+ <label for="proxyTypeAutoconfig">Your proxy supports <em>automatic configuration</em>.</label>
+
+ <section>
+ <label for="autoconfigURL">Autoconfiguration URL (PAC file)</label>
+ <input type="url" name="autoconfigURL" id="autoconfigURL">
+ <input type="hidden" name="autoconfigData" id="autoconfigData">
+ </section>
+ </fieldset>
+ <fieldset id="fixed_servers">
+ <legend>Manual Proxy</legend>
+ <input type="radio" name="proxyType" id="proxyTypeManual" value="manual">
+ <label for="proxyTypeManual">Configure your proxy settings <em>manually</em>.</label>
+ <section>
+ <fieldset>
+ <legend>HTTP</legend>
+ <label for="proxyHostHttp">Host</label>
+ <select id="proxySchemeHttp" name="proxySchemeHttp">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostHttp" id="proxyHostHttp">
+
+ <label for="proxyPortHttp">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortHttp" id="proxyPortHttp">
+
+ <input type="checkbox" name="singleProxyForEverything" id="singleProxyForEverything">
+ <label for="singleProxyForEverything">Use the same proxy server for all protocols</label>
+ </fieldset>
+ <fieldset>
+ <legend>HTTPS</legend>
+ <label for="proxyHostHttps">Host</label>
+ <select id="proxySchemeHttps" name="proxySchemeHttps">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostHttps" id="proxyHostHttps">
+
+ <label for="proxyPortHttps">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortHttps" id="proxyPortHttps">
+ </fieldset>
+ <fieldset>
+ <legend>FTP</legend>
+ <label for="proxyHostFtp">Host</label>
+ <select id="proxySchemeFtp" name="proxySchemeFtp">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostFtp" id="proxyHostFtp">
+
+ <label for="proxyPortFtp">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortFtp" id="proxyPortFtp">
+ </fieldset>
+ <fieldset>
+ <legend>Fallback</legend>
+ <label for="proxyHostFallback">Host</label>
+ <select id="proxySchemeFallback" name="proxySchemeFallback">
+ <option selected value="http">http://</option>
+ <option value="https">https://</option>
+ <option value="socks4">socks4://</option>
+ <option value="socks5">socks5://</option>
+ </select>
+ <input type="text" name="proxyHostFallback" id="proxyHostFallback">
+
+ <label for="proxyPortFallback">Port</label>
+ <input type="number" min="1" step="1" name="proxyPortFallback" id="proxyPortFallback">
+ </fieldset>
+ <fieldset>
+ <label for="bypassList">Bypass proxy for these hosts:</label>
+ <textarea id="bypassList" name="bypassList" placeholder="localhost,192.168.1.1/16, .example.com"></textarea>
+ </fieldset>
+ </section>
+ </fieldset>
+ <input type="submit" value="Save proxy settings">
+ </form>
+ </div>
+ <script src="./proxy_form_controller_test.js"></script>
+</body>
+</html>
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.js b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.js
new file mode 100644
index 0000000..b577cb6
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.js
@@ -0,0 +1,519 @@
+// Copyright (c) 2011 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.
+
+// Stub out the `chrome.experimental.proxy` API
+chrome.experimental = chrome.experimental || {
+ proxy: {
+ settings: {
+ get: function() {},
+ clear: function() {},
+ set: function() {}
+ }
+ }
+};
+// Stub out i18n
+chrome.i18n = chrome.i18n || {
+ getMessage: function(x) { return x; }
+};
+// Stub out messaging and access.
+chrome.extension = chrome.extension || {
+ sendRequest: function() {},
+ isAllowedIncognitoAccess: function(funk) {
+ funk(true);
+ }
+};
+var fixture = document.getElementById('fixture');
+var baselineHTML = fixture.innerHTML;
+var groupIDs = [ProxyFormController.ProxyTypes.DIRECT,
+ ProxyFormController.ProxyTypes.SYSTEM,
+ ProxyFormController.ProxyTypes.PAC,
+ ProxyFormController.ProxyTypes.FIXED];
+
+var mockFunctionFactory = function(returnValue, logging) {
+ var called = [];
+ returnValue = returnValue || null;
+
+ var funky = function() {
+ called.push(arguments);
+ if (arguments[1] && typeof(arguments[1]) === 'function') {
+ var funk = arguments[1];
+ funk(returnValue);
+ }
+ return returnValue;
+ };
+ funky.getCallList = function() { return called; };
+ funky.getValue = function() { return returnValue; };
+ return funky;
+};
+
+var chrome = chrome || {};
+
+var proxyform = new Test.Unit.Runner({
+ setup: function() {
+ fixture.innerHTML = baselineHTML;
+ this.controller_ = new ProxyFormController('proxyForm');
+ this.clickEvent_ = document.createEvent('MouseEvents');
+ this.clickEvent_.initMouseEvent('click', true, true, window,
+ 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ // Reset mock functions.
+ chrome.experimental = {
+ proxy: {
+ settings: {
+ get: mockFunctionFactory({
+ value: {mode: 'system' },
+ levelOfControl: 'ControllableByThisExtension' }),
+ clear: mockFunctionFactory({
+ value: {mode: 'system' },
+ levelOfControl: 'ControllableByThisExtension' }),
+ set: mockFunctionFactory({
+ value: {mode: 'system' },
+ levelOfControl: 'ControllableByThisExtension' })
+ }
+ }
+ };
+ },
+
+ teardown: function() {
+ fixture.removeChild(fixture.childNodes[0]);
+ delete(this.controller_);
+ },
+
+ // Clicking on various bits of the interface should set correct classes,
+ // and select correct radio buttons.
+ testActivationClicks: function() {
+ var self = this;
+ var i;
+ groupIDs.forEach(function(id) {
+ var group = document.getElementById(id);
+ var all = group.querySelectorAll('*');
+ for (i = 0; i < all.length; i++) {
+ group.classList.remove('active');
+ all[i].dispatchEvent(self.clickEvent_);
+ self.assert(group.classList.contains('active'));
+ }
+ });
+ },
+
+ // Elements inside an active group should not be disabled, and vice versa
+ testDisabledElements: function() {
+ var self = this;
+ var i, j;
+ groupIDs.forEach(function(id) {
+ var group = document.getElementById(id);
+ var all = group.querySelectorAll('*');
+ // First, check that activating a group enables its form elements
+ for (i = 0; i < all.length; i++) {
+ group.classList.remove('active');
+ var inputs = group.querySelectorAll('input:not([type="radio"]),select');
+ for (j = 0; j < inputs.length; j++) {
+ inputs[j].setAttribute('disabled', 'disabled');
+ }
+ all[i].dispatchEvent(self.clickEvent_);
+ for (j = 0; j < inputs.length; j++) {
+ self.assert(!inputs[j].hasAttribute('disabled'));
+ }
+ }
+ });
+ },
+
+ // Clicking the "Use single proxy" checkbox should set the correct
+ // classes on the form.
+ testSingleProxyToggle: function() {
+ var group = document.getElementById(
+ ProxyFormController.ProxyTypes.FIXED);
+ var checkbox = document.getElementById('singleProxyForEverything');
+ var section = checkbox.parentNode.parentNode;
+ // Checkbox only works in active group, `testActivationClicks` tests
+ // the inactive click behavior.
+ group.classList.add('active');
+
+ checkbox.checked = false;
+ checkbox.dispatchEvent(this.clickEvent_);
+ this.assert(section.classList.contains('single'));
+ checkbox.dispatchEvent(this.clickEvent_);
+ this.assert(!section.classList.contains('single'));
+ },
+
+ // On instantiation, ProxyFormController should read the current state
+ // from `chrome.experimental.getCurrentProxySettings`, and react
+ // accordingly. Let's see if that happens with the next four sets of
+ // assertsions.
+ testSetupFormSystem: function() {
+ chrome.experimental.proxy.settings.get = mockFunctionFactory({
+ value: {mode: 'system'},
+ levelOfControl: 'ControllableByThisExtension'
+ });
+
+ fixture.innerHTML = baselineHTML;
+ this.controller_ = new ProxyFormController('proxyForm');
+ // Wait for async calls to fire
+ this.wait(100, function() {
+ this.assertEqual(
+ 2,
+ chrome.experimental.proxy.settings.get.getCallList().length);
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.SYSTEM)
+ .classList.contains('active'));
+ });
+ },
+
+ testSetupFormDirect: function() {
+ chrome.experimental.proxy.settings.get =
+ mockFunctionFactory({value: {mode: 'direct'},
+ levelOfControl: 'ControllableByThisExtension'}, true);
+
+ fixture.innerHTML = baselineHTML;
+ this.controller_ = new ProxyFormController('proxyForm');
+ // Wait for async calls to fire
+ this.wait(100, function() {
+ this.assertEqual(
+ 2,
+ chrome.experimental.proxy.settings.get.getCallList().length);
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.DIRECT)
+ .classList.contains('active'));
+ });
+ },
+
+ testSetupFormPac: function() {
+ chrome.experimental.proxy.settings.get =
+ mockFunctionFactory({value: {mode: 'pac_script' },
+ levelOfControl: 'ControllableByThisExtension'});
+
+ fixture.innerHTML = baselineHTML;
+ this.controller_ = new ProxyFormController('proxyForm');
+ // Wait for async calls to fire
+ this.wait(100, function() {
+ this.assertEqual(
+ 2,
+ chrome.experimental.proxy.settings.get.getCallList().length);
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC)
+ .classList.contains('active'));
+ });
+ },
+
+ testSetupFormFixed: function() {
+ chrome.experimental.proxy.settings.get =
+ mockFunctionFactory({value: {mode: 'fixed_servers' },
+ levelOfControl: 'ControllableByThisExtension'});
+
+ fixture.innerHTML = baselineHTML;
+ this.controller_ = new ProxyFormController('proxyForm');
+ // Wait for async calls to fire
+ this.wait(100, function() {
+ this.assertEqual(
+ 2,
+ chrome.experimental.proxy.settings.get.getCallList().length);
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.FIXED)
+ .classList.contains('active'));
+ });
+ },
+
+ // Test that `recalcFormValues_` correctly sets DOM field values when
+ // given a `ProxyConfig` structure
+ testRecalcFormValuesGroups: function() {
+ // Test `AUTO` normalization to `PAC`
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.AUTO,
+ rules: {},
+ pacScript: ''
+ });
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC)
+ .classList.contains('active'));
+
+ // DIRECT
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.DIRECT,
+ rules: {},
+ pacScript: ''
+ });
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.DIRECT)
+ .classList.contains('active'));
+
+ // FIXED
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.FIXED,
+ rules: {},
+ pacScript: ''
+ });
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.FIXED)
+ .classList.contains('active'));
+
+ // PAC
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.PAC,
+ rules: {},
+ pacScript: ''
+ });
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC)
+ .classList.contains('active'));
+
+ // SYSTEM
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.SYSTEM,
+ rules: {},
+ pacScript: ''
+ });
+ this.assert(
+ document.getElementById(ProxyFormController.ProxyTypes.SYSTEM)
+ .classList.contains('active'));
+ },
+
+ testRecalcFormValuesFixedSingle: function() {
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.FIXED,
+ rules: {
+ singleProxy: {
+ scheme: 'socks5',
+ host: 'singleproxy.example.com',
+ port: '1234'
+ }
+ }
+ });
+ var single = this.controller_.singleProxy;
+ this.assertEqual('socks5', single.scheme);
+ this.assertEqual('singleproxy.example.com', single.host);
+ this.assertEqual(1234, single.port);
+ },
+
+ testRecalcFormValuesPacScript: function() {
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.PAC,
+ rules: {},
+ pacScript: {url: 'http://example.com/this/is/a/pac.script'}
+ });
+ this.assertEqual(
+ 'http://example.com/this/is/a/pac.script',
+ document.getElementById('autoconfigURL').value);
+ },
+
+ testRecalcFormValuesSingle: function() {
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.FIXED,
+ rules: {
+ singleProxy: {
+ scheme: 'https',
+ host: 'example.com',
+ port: 80
+ }
+ }
+ });
+ // Single!
+ this.assert(
+ document.querySelector('#' + ProxyFormController.ProxyTypes.FIXED +
+ ' > section').classList.contains('single'));
+
+ var single = this.controller_.singleProxy;
+ this.assertEqual('https', single.scheme);
+ this.assertEqual('example.com', single.host);
+ this.assertEqual(80, single.port);
+ },
+
+ testRecalcFormValuesMultiple: function() {
+ this.controller_.recalcFormValues_({
+ mode: ProxyFormController.ProxyTypes.FIXED,
+ rules: {
+ proxyForHttp: {
+ scheme: 'http',
+ host: 'http.example.com',
+ port: 1
+ },
+ proxyForHttps: {
+ scheme: 'https',
+ host: 'https.example.com',
+ port: 2
+ },
+ proxyForFtp: {
+ scheme: 'socks4',
+ host: 'socks4.example.com',
+ port: 3
+ },
+ fallbackProxy: {
+ scheme: 'socks5',
+ host: 'socks5.example.com',
+ port: 4
+ }
+ }
+ });
+ // Not Single!
+ this.assert(
+ !document.querySelector('#' + ProxyFormController.ProxyTypes.FIXED
+ + ' > section').classList.contains('single'));
+ var server = this.controller_.singleProxy;
+ this.assertNull(server);
+
+ server = this.controller_.httpProxy;
+ this.assertEqual('http', server.scheme);
+ this.assertEqual('http.example.com', server.host);
+ this.assertEqual(1, server.port);
+
+ server = this.controller_.httpsProxy;
+ this.assertEqual('https', server.scheme);
+ this.assertEqual('https.example.com', server.host);
+ this.assertEqual(2, server.port);
+
+ server = this.controller_.ftpProxy;
+ this.assertEqual('socks4', server.scheme);
+ this.assertEqual('socks4.example.com', server.host);
+ this.assertEqual(3, server.port);
+
+ server = this.controller_.fallbackProxy;
+ this.assertEqual('socks5', server.scheme);
+ this.assertEqual('socks5.example.com', server.host);
+ this.assertEqual(4, server.port);
+ },
+
+ testBypassList: function() {
+ this.controller_.bypassList = ['1.example.com',
+ '2.example.com',
+ '3.example.com'];
+ this.assertEnumEqual(
+ document.getElementById('bypassList').value,
+ '1.example.com, 2.example.com, 3.example.com');
+ this.assertEnumEqual(
+ this.controller_.bypassList,
+ ['1.example.com', '2.example.com', '3.example.com']);
+ },
+
+ // Test that "system" rules are correctly generated
+ testProxyRulesGenerationSystem: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.SYSTEM));
+
+ this.assertHashEqual(
+ {mode: 'system'},
+ this.controller_.generateProxyConfig_());
+ },
+
+ // Test that "direct" rules are correctly generated
+ testProxyRulesGenerationDirect: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.DIRECT));
+
+ this.assertHashEqual(
+ {mode: 'direct'},
+ this.controller_.generateProxyConfig_());
+ },
+
+ // Test that auto detection rules are correctly generated when "automatic"
+ // is selected, and no PAC file URL is given
+ testProxyRulesGenerationAuto: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC));
+
+ this.assertHashEqual(
+ {mode: 'auto_detect'},
+ this.controller_.generateProxyConfig_());
+ },
+
+ // Test that PAC URL rules are correctly generated when "automatic"
+ // is selected, and a PAC file URL is given
+ testProxyRulesGenerationPacURL: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC));
+ this.controller_.pacURL = 'http://example.com/pac.pac';
+ var result = this.controller_.generateProxyConfig_();
+ this.assertEqual('pac_script', result.mode);
+ this.assertEqual('http://example.com/pac.pac', result.pacScript.url);
+ },
+
+ // Manual PAC definitions
+ testProxyRulesGenerationPacData: function() {
+ var pacData = 'function FindProxyForURL(url,host) { return "DIRECT"; }';
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC));
+ this.controller_.manualPac = pacData;
+ var result = this.controller_.generateProxyConfig_();
+ this.assertEqual('pac_script', result.mode);
+ this.assertEqual(pacData, result.pacScript.data);
+ },
+
+ // PAC URLs override manual PAC definitions
+ testProxyRulesGenerationPacURLOverridesData: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.PAC));
+ this.controller_.pacURL = 'http://example.com/pac.pac';
+ this.controller_.manualPac =
+ 'function FindProxyForURL(url,host) { return "DIRECT"; }';
+ var result = this.controller_.generateProxyConfig_();
+ this.assertEqual('pac_script', result.mode);
+ this.assertEqual('http://example.com/pac.pac', result.pacScript.url);
+ },
+
+ // Test that fixed, manual servers are correctly transformed into a
+ // `ProxyRules` structure.
+ testProxyRulesGenerationSingle: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.FIXED));
+
+ this.controller_.singleProxy = {
+ scheme: 'http',
+ host: 'example.com',
+ port: '80'
+ };
+
+ var result = this.controller_.generateProxyConfig_();
+ this.assertEqual('fixed_servers', result.mode);
+ this.assertEqual('http', result.rules.singleProxy.scheme);
+ this.assertEqual('example.com', result.rules.singleProxy.host);
+ this.assertEqual(80, result.rules.singleProxy.port);
+ this.assertEqual(undefined, result.rules.proxyForHttp);
+ this.assertEqual(undefined, result.rules.proxyForHttps);
+ this.assertEqual(undefined, result.rules.proxyForFtp);
+ this.assertEqual(undefined, result.rules.fallbackProxy);
+ },
+
+ // Test that proxy configuration rules are correctly generated
+ // for separate manually entered servers.
+ testProxyRulesGenerationSeparate: function() {
+ this.controller_.changeActive_(
+ document.getElementById(ProxyFormController.ProxyTypes.FIXED));
+
+ this.controller_.singleProxy = false;
+ this.controller_.httpProxy = {
+ scheme: 'http',
+ host: 'http.example.com',
+ port: 80
+ };
+ this.controller_.httpsProxy = {
+ scheme: 'https',
+ host: 'https.example.com',
+ port: 443
+ };
+ this.controller_.ftpProxy = {
+ scheme: 'socks4',
+ host: 'ftp.example.com',
+ port: 80
+ };
+ this.controller_.fallbackProxy = {
+ scheme: 'socks5',
+ host: 'fallback.example.com',
+ port: 80
+ };
+
+ var result = this.controller_.generateProxyConfig_();
+ this.assertEqual('fixed_servers', result.mode);
+ this.assertEqual(undefined, result.rules.singleProxy);
+ this.assertEqual('http', result.rules.proxyForHttp.scheme);
+ this.assertEqual('http.example.com', result.rules.proxyForHttp.host);
+ this.assertEqual('80', result.rules.proxyForHttp.port);
+ this.assertEqual('https', result.rules.proxyForHttps.scheme);
+ this.assertEqual('https.example.com', result.rules.proxyForHttps.host);
+ this.assertEqual('443', result.rules.proxyForHttps.port);
+ this.assertEqual('socks4', result.rules.proxyForFtp.scheme);
+ this.assertEqual('ftp.example.com', result.rules.proxyForFtp.host);
+ this.assertEqual('80', result.rules.proxyForFtp.port);
+ this.assertEqual('socks5', result.rules.fallbackProxy.scheme);
+ this.assertEqual('fallback.example.com', result.rules.fallbackProxy.host);
+ this.assertEqual('80', result.rules.fallbackProxy.port);
+ }
+}, { testLog: 'proxyformcontrollerlog' });
+
+var c = new ProxyFormController('proxyForm');
diff --git a/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/unittest.css b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/unittest.css
new file mode 100644
index 0000000..d62b1c5
--- /dev/null
+++ b/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/unittest.css
@@ -0,0 +1,58 @@
+body, div, p, h1, h2, h3, ul, ol, span, a, table, td, form, img, li {
+ font-family: sans-serif;
+}
+
+body {
+ font-size:0.8em;
+}
+
+#log {
+ padding-bottom: 1em;
+ border-bottom: 2px solid #000;
+ margin-bottom: 2em;
+}
+
+.logsummary {
+ margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 1ex;
+ border: 1px solid #000;
+ font-weight: bold;
+}
+
+.logtable {
+ width:100%;
+ border-collapse: collapse;
+ border: 1px dotted #666;
+}
+
+.logtable td, .logtable th {
+ text-align: left;
+ padding: 3px 8px;
+ border: 1px dotted #666;
+}
+
+.logtable .passed {
+ background-color: #cfc;
+}
+
+.logtable .failed, .logtable .error {
+ background-color: #fcc;
+}
+
+.logtable .warning {
+ background-color: #FC6;
+}
+
+.logtable td div.action_buttons {
+ display: inline;
+}
+
+.logtable td div.action_buttons input {
+ margin: 0 5px;
+ font-size: 10px;
+}
+
+#fixture {
+ display: none;
+}
diff --git a/chrome/common/extensions/docs/experimental.contentSettings.misc.html b/chrome/common/extensions/docs/experimental.contentSettings.misc.html
index 61631d8..dc1ce80 100644
--- a/chrome/common/extensions/docs/experimental.contentSettings.misc.html
+++ b/chrome/common/extensions/docs/experimental.contentSettings.misc.html
@@ -273,6 +273,10 @@
<ol>
<li>
<a href="#property-blockThirdPartyCookies">blockThirdPartyCookies</a>
+ </li><li>
+ <a href="#property-enableReferrers">enableReferrers</a>
+ </li><li>
+ <a href="#property-enableHyperlinkAuditing">enableHyperlinkAuditing</a>
</li>
</ol>
</li>
@@ -398,6 +402,154 @@
</dd>
</div>
+ </div><div>
+ <a name="property-enableReferrers"></a>
+ <h4>enableReferrers</h4>
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.contentSettings.misc.</span><span>enableReferrers</span>
+ </div>
+ <div>
+ <dt>
+ <var>enableReferrers</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span>
+ <a href="experimental.extension.html#type-Preference">Preference</a>
+ </span>
+ <span style="display: none; ">
+ <span>
+ array of <span><span></span></span>
+ </span>
+ <span>paramType</span>
+ <span></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Whether referrers should be enabled. The value of this preference is of type boolean.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <a name="property-enableHyperlinkAuditing"></a>
+ <h4>enableHyperlinkAuditing</h4>
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.contentSettings.misc.</span><span>enableHyperlinkAuditing</span>
+ </div>
+ <div>
+ <dt>
+ <var>enableHyperlinkAuditing</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span>
+ <a href="experimental.extension.html#type-Preference">Preference</a>
+ </span>
+ <span style="display: none; ">
+ <span>
+ array of <span><span></span></span>
+ </span>
+ <span>paramType</span>
+ <span></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Whether to enable hyperlink auditing ("&lt;a ping&gt;"). The value of this preference is of type boolean.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
</div>
</div> <!-- /apiGroup -->
diff --git a/chrome/common/extensions/docs/experimental.debugger.html b/chrome/common/extensions/docs/experimental.debugger.html
new file mode 100644
index 0000000..46036a2
--- /dev/null
+++ b/chrome/common/extensions/docs/experimental.debugger.html
@@ -0,0 +1,1559 @@
+<!DOCTYPE html><!-- This page is a placeholder for generated extensions api doc. Note:
+ 1) The <head> information in this page is significant, should be uniform
+ across api docs and should be edited only with knowledge of the
+ templating mechanism.
+ 3) All <body>.innerHTML is genereated as an rendering step. If viewed in a
+ browser, it will be re-generated from the template, json schema and
+ authored overview content.
+ 4) The <body>.innerHTML is also generated by an offline step so that this
+ page may easily be indexed by search engines.
+--><html xmlns="http://www.w3.org/1999/xhtml"><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <link href="css/ApiRefStyles.css" rel="stylesheet" type="text/css">
+ <link href="css/print.css" rel="stylesheet" type="text/css" media="print">
+ <script type="text/javascript" src="../../../third_party/jstemplate/jstemplate_compiled.js">
+ </script>
+ <script type="text/javascript" src="js/api_page_generator.js"></script>
+ <script type="text/javascript" src="js/bootstrap.js"></script>
+ <script type="text/javascript" src="js/sidebar.js"></script>
+ <title>chrome.experimental.debugger - Google Chrome Extensions - Google Code</title></head>
+ <body> <div id="gc-container" class="labs">
+ <div id="devModeWarning">
+ You are viewing extension docs in chrome via the 'file:' scheme: are you expecting to see local changes when you refresh? You'll need run chrome with --allow-file-access-from-files.
+ </div>
+ <!-- SUBTEMPLATES: DO NOT MOVE FROM THIS LOCATION -->
+ <!-- In particular, sub-templates that recurse, must be used by allowing
+ jstemplate to make a copy of the template in this section which
+ are not operated on by way of the jsskip="true" -->
+ <div style="display:none">
+
+ <!-- VALUE -->
+ <div id="valueTemplate">
+ <dt>
+ <var>paramName</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum">enumerated</span>
+ <span id="typeTemplate">
+ <span>
+ <a> Type</a>
+ </span>
+ <span>
+ <span>
+ array of <span><span></span></span>
+ </span>
+ <span>paramType</span>
+ <span></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd>
+ Description of this parameter from the json schema.
+ </dd>
+ <dd>
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ </div> <!-- /VALUE -->
+
+ <div id="functionParametersTemplate">
+ <h5>Parameters</h5>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /SUBTEMPLATES -->
+
+ <a id="top"></a>
+ <div id="skipto">
+ <a href="#gc-pagecontent">Skip to page content</a>
+ <a href="#gc-toc">Skip to main navigation</a>
+ </div>
+ <!-- API HEADER -->
+ <table id="header" width="100%" cellspacing="0" border="0">
+ <tbody><tr>
+ <td valign="middle"><a href="http://code.google.com/"><img src="images/code_labs_logo.gif" height="43" width="161" alt="Google Code Labs" style="border:0; margin:0;"></a></td>
+ <td valign="middle" width="100%" style="padding-left:0.6em;">
+ <form action="http://www.google.com/cse" id="cse" style="margin-top:0.5em">
+ <div id="gsc-search-box">
+ <input type="hidden" name="cx" value="002967670403910741006:61_cvzfqtno">
+ <input type="hidden" name="ie" value="UTF-8">
+ <input type="text" name="q" value="" size="55">
+ <input class="gsc-search-button" type="submit" name="sa" value="Search">
+ <br>
+ <span class="greytext">e.g. "page action" or "tabs"</span>
+ </div>
+ </form>
+
+ <script type="text/javascript" src="http://www.google.com/jsapi"></script>
+ <script type="text/javascript">google.load("elements", "1", {packages: "transliteration"});</script>
+ <script type="text/javascript" src="http://www.google.com/coop/cse/t13n?form=cse&amp;t13n_langs=en"></script>
+ <script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=cse&amp;lang=en"></script>
+ </td>
+ </tr>
+ </tbody></table>
+
+ <div id="codesiteContent" class="">
+
+ <a id="gc-topnav-anchor"></a>
+ <div id="gc-topnav">
+ <h1>Google Chrome Extensions (<a href="http://code.google.com/labs/">Labs</a>)</h1>
+ <ul id="home" class="gc-topnav-tabs">
+ <li id="home_link">
+ <a href="index.html" title="Google Chrome Extensions home page">Home</a>
+ </li>
+ <li id="docs_link">
+ <a href="docs.html" title="Official Google Chrome Extensions documentation">Docs</a>
+ </li>
+ <li id="faq_link">
+ <a href="faq.html" title="Answers to frequently asked questions about Google Chrome Extensions">FAQ</a>
+ </li>
+ <li id="samples_link">
+ <a href="samples.html" title="Sample extensions (with source code)">Samples</a>
+ </li>
+ <li id="group_link">
+ <a href="http://groups.google.com/a/chromium.org/group/chromium-extensions" title="Google Chrome Extensions developer forum">Group</a>
+ </li>
+ </ul>
+ </div> <!-- end gc-topnav -->
+
+ <div class="g-section g-tpl-170">
+ <!-- SIDENAV -->
+ <div class="g-unit g-first" id="gc-toc">
+ <ul>
+ <li><a href="getstarted.html">Getting Started</a></li>
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="whats_new.html">What's New?</a></li>
+ <li><h2><a href="devguide.html">Developer's Guide</a></h2>
+ <ul>
+ <li>Browser UI
+ <ul>
+ <li><a href="browserAction.html">Browser Actions</a></li>
+ <li><a href="contextMenus.html">Context Menus</a></li>
+ <li><a href="notifications.html">Desktop Notifications</a></li>
+ <li><a href="omnibox.html">Omnibox</a></li>
+ <li><a href="options.html">Options Pages</a></li>
+ <li><a href="override.html">Override Pages</a></li>
+ <li><a href="pageAction.html">Page Actions</a></li>
+ </ul>
+ </li>
+ <li>Browser Interaction
+ <ul>
+ <li><a href="bookmarks.html">Bookmarks</a></li>
+ <li><a href="cookies.html">Cookies</a></li>
+ <li><a href="events.html">Events</a></li>
+ <li><a href="history.html">History</a></li>
+ <li><a href="management.html">Management</a></li>
+ <li><a href="tabs.html">Tabs</a></li>
+ <li><a href="windows.html">Windows</a></li>
+ </ul>
+ </li>
+ <li>Implementation
+ <ul>
+ <li><a href="a11y.html">Accessibility</a></li>
+ <li><a href="background_pages.html">Background Pages</a></li>
+ <li><a href="content_scripts.html">Content Scripts</a></li>
+ <li><a href="xhr.html">Cross-Origin XHR</a></li>
+ <li><a href="idle.html">Idle</a></li>
+ <li><a href="i18n.html">Internationalization</a></li>
+ <li><a href="messaging.html">Message Passing</a></li>
+ <li><a href="npapi.html">NPAPI Plugins</a></li>
+ </ul>
+ </li>
+ <li>Finishing
+ <ul>
+ <li><a href="hosting.html">Hosting</a></li>
+ <li><a href="external_extensions.html">Other Deployment Options</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li><h2><a href="apps.html">Packaged Apps</a></h2></li>
+ <li><h2><a href="tutorials.html">Tutorials</a></h2>
+ <ul>
+ <li><a href="tut_debugging.html">Debugging</a></li>
+ <li><a href="tut_analytics.html">Google Analytics</a></li>
+ <li><a href="tut_oauth.html">OAuth</a></li>
+ </ul>
+ </li>
+ <li><h2>Reference</h2>
+ <ul>
+ <li>Formats
+ <ul>
+ <li><a href="manifest.html">Manifest Files</a></li>
+ <li><a href="match_patterns.html">Match Patterns</a></li>
+ </ul>
+ </li>
+ <li><a href="permission_warnings.html">Permission Warnings</a></li>
+ <li><a href="api_index.html">chrome.* APIs</a></li>
+ <li><a href="api_other.html">Other APIs</a></li>
+ </ul>
+ </li>
+ <li><h2><a href="samples.html">Samples</a></h2></li>
+ <div class="line"> </div>
+ <li><h2>More</h2>
+ <ul>
+ <li><a href="http://code.google.com/chrome/webstore/docs/index.html">Chrome Web Store</a></li>
+ <li><a href="http://code.google.com/chrome/apps/docs/developers_guide.html">Hosted Apps</a></li>
+ <li><a href="themes.html">Themes</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <script>
+ initToggles();
+ </script>
+
+ <div class="g-unit" id="gc-pagecontent">
+ <div id="pageTitle">
+ <h1 class="page_title">chrome.experimental.debugger</h1>
+ </div>
+ <!-- TABLE OF CONTENTS -->
+ <div id="toc">
+ <h2>Contents</h2>
+ <ol>
+ <li>
+ <a href="#H2-0">Notes</a>
+ <ol>
+ <li style="display: none; ">
+ <a>h3Name</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#apiReference">API reference: chrome.experimental.debugger</a>
+ <ol>
+ <li style="display: none; ">
+ <a href="#properties">Properties</a>
+ <ol>
+ <li>
+ <a href="#property-anchor">propertyName</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#global-methods">Methods</a>
+ <ol>
+ <li>
+ <a href="#method-attach">attach</a>
+ </li><li>
+ <a href="#method-detach">detach</a>
+ </li><li>
+ <a href="#method-sendRequest">sendRequest</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#global-events">Events</a>
+ <ol>
+ <li>
+ <a href="#event-onDetach">onDetach</a>
+ </li><li>
+ <a href="#event-onEvent">onEvent</a>
+ </li>
+ </ol>
+ </li>
+ <li style="display: none; ">
+ <a href="#types">Types</a>
+ <ol>
+ <li>
+ <a href="#id-anchor">id</a>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </div>
+ <!-- /TABLE OF CONTENTS -->
+
+ <!-- Standard content lead-in for experimental API pages -->
+ <p id="classSummary">
+ For information on how to use experimental APIs, see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
+ </p>
+
+ <!-- STATIC CONTENT PLACEHOLDER -->
+ <div id="static"><!-- BEGIN AUTHORED CONTENT -->
+
+
+<a name="H2-0"></a><h2>Notes</h2>
+
+<p>
+Debugger API exposes Google Chrome debugging interface to the extensions.
+Debugging messages that are being sent and received are all JSON objects
+with the structure defined by the Developer Tools / Web Inspector Protocol.
+We are currently drafting this protocol, it is by no means ready and stable,
+but we can already expose the way to attach to a given tab and instrument it.
+Although not finalized, this API is feature rich. There is a proof of concept
+implementation of the Chrome Developer Tools front-end running as an extension
+using the debugger API.
+</p>
+
+<p>
+Note that attaching to the page by means of the debugger API and using embedded
+Chrome Developer Tools with it are mutually exclusive. If extension is attached
+to the page and user invokes Developer Tools, debugging session is being
+terminated. Extension can then re-establish it via attaching to a tab later.
+</p>
+
+<!-- END AUTHORED CONTENT -->
+</div>
+
+ <!-- API PAGE -->
+ <div class="apiPage">
+ <a name="apiReference"></a>
+ <h2>API reference: chrome.experimental.debugger</h2>
+
+ <!-- PROPERTIES -->
+ <div class="apiGroup" style="display: none; ">
+ <a name="properties"></a>
+ <h3 id="properties">Properties</h3>
+
+ <div>
+ <a></a>
+ <h4>getLastError</h4>
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.extension</span><span>lastError</span>
+ </div>
+ <div>
+ </div>
+ </div>
+
+ </div> <!-- /apiGroup -->
+
+ <!-- METHODS -->
+ <div id="methodsTemplate" class="apiGroup">
+ <a name="global-methods"></a>
+ <h3>Methods</h3>
+
+ <!-- iterates over all functions -->
+ <div class="apiItem">
+ <a name="method-attach"></a> <!-- method-anchor -->
+ <h4>attach</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.debugger.attach</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>tabId</span></var></span><span class="optional"><span>, </span><span>function</span>
+ <var><span>callback</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Attaches debugger to the tab with given id.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab to which you want to attach.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>callback</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>function</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>If an error occurs while attaching to the tab, the callback will be called with no arguments and <a href="extension.html#property-lastError">chrome.extension.lastError</a> will be set to the error message.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p style="display: none; ">
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span></span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p style="display: none; ">
+ This function was added in version <b><span></span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
+ <a name="method-detach"></a> <!-- method-anchor -->
+ <h4>detach</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.debugger.detach</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>tabId</span></var></span><span class="optional"><span>, </span><span>function</span>
+ <var><span>callback</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Detaches debugger from a tab with given id.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab from which you want to detach.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>callback</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>function</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>If an error occurs while detaching from the tab, the callback will be called with no arguments and <a href="extension.html#property-lastError">chrome.extension.lastError</a> will be set to the error message.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p style="display: none; ">
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span></span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p style="display: none; ">
+ This function was added in version <b><span></span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
+ <a name="method-sendRequest"></a> <!-- method-anchor -->
+ <h4>sendRequest</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.experimental.debugger.sendRequest</span>(<span class="null"><span style="display: none; ">, </span><span>integer</span>
+ <var><span>tabId</span></var></span><span class="null"><span>, </span><span>string</span>
+ <var><span>method</span></var></span><span class="optional"><span>, </span><span>object</span>
+ <var><span>params</span></var></span><span class="optional"><span>, </span><span>function</span>
+ <var><span>callback</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Send given request to the debugger.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab to which you want to send debugging request.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>method</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Method name.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>params</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>JSON object matching Developer Tools / Web Inspector Protocol scheme.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>callback</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>function</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Request response body. If an error occurs while posting the message, the callback will be called with no arguments and <a href="extension.html#property-lastError">chrome.extension.lastError</a> will be set to the error message.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p style="display: none; ">
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>object result</span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>result</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>JSON object with the request response.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p style="display: none; ">
+ This function was added in version <b><span></span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ <!-- EVENTS -->
+ <div id="eventsTemplate" class="apiGroup">
+ <a name="global-events"></a>
+ <h3>Events</h3>
+ <!-- iterates over all events -->
+ <div class="apiItem">
+ <a name="event-onDetach"></a>
+ <h4>onDetach</h4>
+
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span class="subdued">chrome.experimental.debugger.</span><span>onDetach</span><span class="subdued">.addListener</span>(function(<span>integer tabId</span>) <span class="subdued">{...}</span>);
+ </div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Fired when browser terminates debugging session for the tab.</p>
+
+ <!-- PARAMETERS -->
+ <div>
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab that was detached.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /decription -->
+
+ </div><div class="apiItem">
+ <a name="event-onEvent"></a>
+ <h4>onEvent</h4>
+
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span class="subdued">chrome.experimental.debugger.</span><span>onEvent</span><span class="subdued">.addListener</span>(function(<span>integer tabId, string method, object params</span>) <span class="subdued">{...}</span>);
+ </div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Fired whenever debugger issues instrumentation event.</p>
+
+ <!-- PARAMETERS -->
+ <div>
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>tabId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>integer</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The id of the tab that generated debug evet.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>method</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Method name.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>params</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>JSON object matching Developer Tools / Web Inspector Protocol event data scheme.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /decription -->
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ <!-- TYPES -->
+ <div class="apiGroup" style="display: none; ">
+ <a name="types"></a>
+ <h3 id="types">Types</h3>
+
+ <!-- iterates over all types -->
+ <div class="apiItem">
+ <a></a>
+ <h4>type name</h4>
+
+ <div>
+ </div>
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ </div> <!-- /apiPage -->
+ </div> <!-- /gc-pagecontent -->
+ </div> <!-- /g-section -->
+ </div> <!-- /codesiteContent -->
+ <div id="gc-footer" --="">
+ <div class="text">
+ <p>
+ Except as otherwise <a href="http://code.google.com/policies.html#restrictions">noted</a>,
+ the content of this page is licensed under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
+ Attribution 3.0 License</a>, and code samples are licensed under the
+ <a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
+ </p>
+ <p>
+ ©2011 Google
+ </p>
+
+<!-- begin analytics -->
+<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+ // chrome doc tracking
+ try {
+ var engdocs = _gat._getTracker("YT-10763712-2");
+ engdocs._trackPageview();
+ } catch(err) {}
+
+ // code.google.com site-wide tracking
+ try {
+ _uacct="UA-18071-1";
+ _uanchor=1;
+ _uff=0;
+ urchinTracker();
+ }
+ catch(e) {/* urchinTracker not available. */}
+</script>
+<!-- end analytics -->
+ </div>
+ </div> <!-- /gc-footer -->
+ </div> <!-- /gc-container -->
+</body></html>
diff --git a/chrome/common/extensions/docs/experimental.extension.html b/chrome/common/extensions/docs/experimental.extension.html
index 4d203ae..542e85c 100644
--- a/chrome/common/extensions/docs/experimental.extension.html
+++ b/chrome/common/extensions/docs/experimental.extension.html
@@ -873,7 +873,7 @@
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>Whether to return the setting that applies to the incognito session only (default false).</dd>
+ <dd>Whether to return the setting that applies to the incognito session (default false).</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1172,7 +1172,75 @@
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>One of<br>NotControllable = cannot be controlled by any extension<br>ControlledByOtherExtensions = controlled by extensions with higher precedence<br>ControllableByThisExtension = can be controlled by this extension<br>ControlledByThisExtension = controlled by this extension</dd>
+ <dd>One of<br><var>NotControllable</var>: cannot be controlled by any extension<br><var>ControlledByOtherExtensions</var>: controlled by extensions with higher precedence<br><var>ControllableByThisExtension</var>: can be controlled by this extension<br><var>ControlledByThisExtension</var>: controlled by this extension</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>incognitoSpecific</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Whether the effective value is specific to the incognito session.<br>This property will <em>only</em> be present if the <var>incognito</var> property in the <var>details</var> parameter of <code>get()</code> was true.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1336,7 +1404,7 @@
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>The value of the preference.</dd>
+ <dd>The value of the preference. <br>Note that every preference has a specific value type, which is described together with the preference. An extension should <em>not</em> set a preference value of a different type.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -1580,10 +1648,309 @@
</dd>
<!-- OBJECT EVENT FIELDS -->
+ <dd>
+ <div class="apiGroup" style="">
+ <a name="global-Preference-events"></a>
+ <h3>Events of Preference</h3>
+ <!-- iterates over all events -->
+ <div class="apiItem">
+ <a name="event-Preference-onChange"></a>
+ <h4>onChange</h4>
+
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span class="subdued">preference.</span><span>onChange</span><span class="subdued">.addListener</span>(function(<span>object details</span>) <span class="subdued">{...}</span>);
+ </div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Fired when the value of the preference changes.</p>
+
+ <!-- PARAMETERS -->
+ <div>
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>details</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>value</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>any</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The value of the preference.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>levelOfControl</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span>["NotControllable", "ControlledByOtherExtensions", "ControllableByThisExtension", "ControlledByThisExtension"]</span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>One of<br><var>NotControllable</var>: cannot be controlled by any extension<br><var>ControlledByOtherExtensions</var>: controlled by extensions with higher precedence<br><var>ControllableByThisExtension</var>: can be controlled by this extension<br><var>ControlledByThisExtension</var>: controlled by this extension</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>incognitoSpecific</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Whether the value that has changed is specific to the incognito session.<br>This property will <em>only</em> be present if the user has enabled the extension in incognito mode.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
<dd style="display: none; ">
<div></div>
</dd>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /decription -->
+
+ </div> <!-- /apiItem -->
+
+ </div>
+ </dd>
+
<!-- FUNCTION PARAMETERS -->
<dd style="display: none; ">
<div></div>
diff --git a/chrome/common/extensions/docs/experimental.html b/chrome/common/extensions/docs/experimental.html
index b7af23f..7c542b6 100644
--- a/chrome/common/extensions/docs/experimental.html
+++ b/chrome/common/extensions/docs/experimental.html
@@ -323,12 +323,17 @@ on the following experimental APIs:
<li>
<a href="experimental.clipboard.html">experimental.clipboard</a></li><li>
<a href="experimental.contentSettings.misc.html">experimental.contentSettings.misc</a></li><li>
+ <a href="experimental.debugger.html">experimental.debugger</a></li><li>
<a href="experimental.extension.html">experimental.extension</a></li><li>
<a href="experimental.infobars.html">experimental.infobars</a></li><li>
<a href="experimental.processes.html">experimental.processes</a></li><li>
<a href="experimental.proxy.html">experimental.proxy</a></li><li>
<a href="experimental.sidebar.html">experimental.sidebar</a></li><li>
<a href="experimental.tts.html">experimental.tts</a></li><li>
+ <a href="experimental.webInspector.audits.html">experimental.webInspector.audits</a></li><li>
+ <a href="experimental.webInspector.inspectedWindow.html">experimental.webInspector.inspectedWindow</a></li><li>
+ <a href="experimental.webInspector.panels.html">experimental.webInspector.panels</a></li><li>
+ <a href="experimental.webInspector.resources.html">experimental.webInspector.resources</a></li><li>
<a href="experimental.webNavigation.html">experimental.webNavigation</a></li><li>
<a href="experimental.webRequest.html">experimental.webRequest</a></li>
</ul>
diff --git a/chrome/common/extensions/docs/experimental.webInspector.audits.html b/chrome/common/extensions/docs/experimental.webInspector.audits.html
index 2520d1c..ff20c3a 100644
--- a/chrome/common/extensions/docs/experimental.webInspector.audits.html
+++ b/chrome/common/extensions/docs/experimental.webInspector.audits.html
@@ -257,10 +257,10 @@
<div id="toc">
<h2>Contents</h2>
<ol>
- <li style="display: none; ">
- <a>h2Name</a>
+ <li>
+ <a href="#H2-0">Notes</a>
<ol>
- <li>
+ <li style="display: none; ">
<a>h3Name</a>
</li>
</ol>
@@ -320,7 +320,64 @@
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"></div>
+ <div id="static"><!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.audits</code> module to add new audit
+categories and rules to WebInspector's Audit panel.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API.
+</p>
+
+<a name="H2-0"></a><h2>Notes</h2>
+
+<p>
+Each audit category is represented by a line on <em>Select audits to run</em>
+screen in the Audits panel. The following example adds a category named
+<em>Readability</em>:</p>
+<pre>var category = webInspector.audits.addCategory("Readability", 2);
+</pre>
+<img src="images/devtools-audits-category.png" style="margin-left: 20px" width="489" height="342" alt="Extension audit category on the launch screen of Audits panel">
+<p>
+If the category's checkbox is checked, the <code>onAuditStarted</code> event of
+that category will be fired when user clicks the <em>Run</em> button.
+</p>
+<p>The event handler in your extension receives <code>AuditResults</code>
+as an argument and should add one or more results using <code>addResult()</code>
+method. This may be done asynchronously, i.e. after the handler returns. The
+run of the category is considered to be complete once the extension adds the
+number of results declared when adding the category with
+<code>experimental.webInspector.audits.addCategory()</code> or
+calls AuditResult's <code>done()</code> method.
+</p>
+<p>The results may include additional details visualized as an expandable
+tree by the Audits panel. You may build the details tree using
+<code>createResult()</code> and <code>addChild()</code> methods. The child node
+may include specially formatted fragments created by
+<code>auditResults.snippet()</code> or <code>auditResults.url()</code>.
+</p>
+The following example adds a handler for onAuditStarted event that creates two
+audit results and populates one of them with the additional details:
+
+<pre>category.onAuditStarted.addListener(function(results) {
+ var details = results.createResult("Details...");
+ var styles = details.addChild("2 styles with small font");
+ var elements = details.addChild("3 elements with small font");
+
+ results.addResult("Font Size (5)",
+ "5 elements use font size below 10pt",
+ results.Severity.Severe,
+ details);
+ results.addResult("Contrast",
+ "Text should stand out from background",
+ results.Severity.Info);
+});
+</pre>
+<p>The audit result tree produced by the snippet above will look like this:
+</p>
+<img src="images/devtools-audits-results.png" style="margin-left: 20px" width="330" height="169" alt="Audit results example">
+<!-- END AUTHORED CONTENT -->
+</div>
<!-- API PAGE -->
<div class="apiPage">
diff --git a/chrome/common/extensions/docs/experimental.webInspector.html b/chrome/common/extensions/docs/experimental.webInspector.html
new file mode 100644
index 0000000..6169522
--- /dev/null
+++ b/chrome/common/extensions/docs/experimental.webInspector.html
@@ -0,0 +1,586 @@
+<!DOCTYPE html><!-- This page is a placeholder for generated extensions api doc. Note:
+ 1) The <head> information in this page is significant, should be uniform
+ across api docs and should be edited only with knowledge of the
+ templating mechanism.
+ 3) All <body>.innerHTML is genereated as an rendering step. If viewed in a
+ browser, it will be re-generated from the template, json schema and
+ authored overview content.
+ 4) The <body>.innerHTML is also generated by an offline step so that this
+ page may easily be indexed by search engines.
+--><html xmlns="http://www.w3.org/1999/xhtml"><head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <link href="css/ApiRefStyles.css" rel="stylesheet" type="text/css">
+ <link href="css/print.css" rel="stylesheet" type="text/css" media="print">
+ <script type="text/javascript" src="../../../third_party/jstemplate/jstemplate_compiled.js">
+ </script>
+ <script type="text/javascript" src="js/api_page_generator.js"></script>
+ <script type="text/javascript" src="js/bootstrap.js"></script>
+ <script type="text/javascript" src="js/sidebar.js"></script>
+ <title>experimental.webInspector.* APIs - Google Chrome Extensions - Google Code</title></head>
+ <body> <div id="gc-container" class="labs">
+ <div id="devModeWarning">
+ You are viewing extension docs in chrome via the 'file:' scheme: are you expecting to see local changes when you refresh? You'll need run chrome with --allow-file-access-from-files.
+ </div>
+ <!-- SUBTEMPLATES: DO NOT MOVE FROM THIS LOCATION -->
+ <!-- In particular, sub-templates that recurse, must be used by allowing
+ jstemplate to make a copy of the template in this section which
+ are not operated on by way of the jsskip="true" -->
+ <div style="display:none">
+
+ <!-- VALUE -->
+ <div id="valueTemplate">
+ <dt>
+ <var>paramName</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum">enumerated</span>
+ <span id="typeTemplate">
+ <span>
+ <a> Type</a>
+ </span>
+ <span>
+ <span>
+ array of <span><span></span></span>
+ </span>
+ <span>paramType</span>
+ <span></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd>
+ Description of this parameter from the json schema.
+ </dd>
+ <dd>
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd>
+ <div></div>
+ </dd>
+
+ </div> <!-- /VALUE -->
+
+ <div id="functionParametersTemplate">
+ <h5>Parameters</h5>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /SUBTEMPLATES -->
+
+ <a id="top"></a>
+ <div id="skipto">
+ <a href="#gc-pagecontent">Skip to page content</a>
+ <a href="#gc-toc">Skip to main navigation</a>
+ </div>
+ <!-- API HEADER -->
+ <table id="header" width="100%" cellspacing="0" border="0">
+ <tbody><tr>
+ <td valign="middle"><a href="http://code.google.com/"><img src="images/code_labs_logo.gif" height="43" width="161" alt="Google Code Labs" style="border:0; margin:0;"></a></td>
+ <td valign="middle" width="100%" style="padding-left:0.6em;">
+ <form action="http://www.google.com/cse" id="cse" style="margin-top:0.5em">
+ <div id="gsc-search-box">
+ <input type="hidden" name="cx" value="002967670403910741006:61_cvzfqtno">
+ <input type="hidden" name="ie" value="UTF-8">
+ <input type="text" name="q" value="" size="55">
+ <input class="gsc-search-button" type="submit" name="sa" value="Search">
+ <br>
+ <span class="greytext">e.g. "page action" or "tabs"</span>
+ </div>
+ </form>
+
+ <script type="text/javascript" src="http://www.google.com/jsapi"></script>
+ <script type="text/javascript">google.load("elements", "1", {packages: "transliteration"});</script>
+ <script type="text/javascript" src="http://www.google.com/coop/cse/t13n?form=cse&amp;t13n_langs=en"></script>
+ <script type="text/javascript" src="http://www.google.com/coop/cse/brand?form=cse&amp;lang=en"></script>
+ </td>
+ </tr>
+ </tbody></table>
+
+ <div id="codesiteContent" class="">
+
+ <a id="gc-topnav-anchor"></a>
+ <div id="gc-topnav">
+ <h1>Google Chrome Extensions (<a href="http://code.google.com/labs/">Labs</a>)</h1>
+ <ul id="home" class="gc-topnav-tabs">
+ <li id="home_link">
+ <a href="index.html" title="Google Chrome Extensions home page">Home</a>
+ </li>
+ <li id="docs_link">
+ <a href="docs.html" title="Official Google Chrome Extensions documentation">Docs</a>
+ </li>
+ <li id="faq_link">
+ <a href="faq.html" title="Answers to frequently asked questions about Google Chrome Extensions">FAQ</a>
+ </li>
+ <li id="samples_link">
+ <a href="samples.html" title="Sample extensions (with source code)">Samples</a>
+ </li>
+ <li id="group_link">
+ <a href="http://groups.google.com/a/chromium.org/group/chromium-extensions" title="Google Chrome Extensions developer forum">Group</a>
+ </li>
+ </ul>
+ </div> <!-- end gc-topnav -->
+
+ <div class="g-section g-tpl-170">
+ <!-- SIDENAV -->
+ <div class="g-unit g-first" id="gc-toc">
+ <ul>
+ <li><a href="getstarted.html">Getting Started</a></li>
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="whats_new.html">What's New?</a></li>
+ <li><h2><a href="devguide.html">Developer's Guide</a></h2>
+ <ul>
+ <li>Browser UI
+ <ul>
+ <li><a href="browserAction.html">Browser Actions</a></li>
+ <li><a href="contextMenus.html">Context Menus</a></li>
+ <li><a href="notifications.html">Desktop Notifications</a></li>
+ <li><a href="omnibox.html">Omnibox</a></li>
+ <li><a href="options.html">Options Pages</a></li>
+ <li><a href="override.html">Override Pages</a></li>
+ <li><a href="pageAction.html">Page Actions</a></li>
+ </ul>
+ </li>
+ <li>Browser Interaction
+ <ul>
+ <li><a href="bookmarks.html">Bookmarks</a></li>
+ <li><a href="cookies.html">Cookies</a></li>
+ <li><a href="events.html">Events</a></li>
+ <li><a href="history.html">History</a></li>
+ <li><a href="management.html">Management</a></li>
+ <li><a href="tabs.html">Tabs</a></li>
+ <li><a href="windows.html">Windows</a></li>
+ </ul>
+ </li>
+ <li>Implementation
+ <ul>
+ <li><a href="a11y.html">Accessibility</a></li>
+ <li><a href="background_pages.html">Background Pages</a></li>
+ <li><a href="content_scripts.html">Content Scripts</a></li>
+ <li><a href="xhr.html">Cross-Origin XHR</a></li>
+ <li><a href="idle.html">Idle</a></li>
+ <li><a href="i18n.html">Internationalization</a></li>
+ <li><a href="messaging.html">Message Passing</a></li>
+ <li><a href="npapi.html">NPAPI Plugins</a></li>
+ </ul>
+ </li>
+ <li>Finishing
+ <ul>
+ <li><a href="hosting.html">Hosting</a></li>
+ <li><a href="external_extensions.html">Other Deployment Options</a></li>
+ </ul>
+ </li>
+ </ul>
+ </li>
+ <li><h2><a href="apps.html">Packaged Apps</a></h2></li>
+ <li><h2><a href="tutorials.html">Tutorials</a></h2>
+ <ul>
+ <li><a href="tut_debugging.html">Debugging</a></li>
+ <li><a href="tut_analytics.html">Google Analytics</a></li>
+ <li><a href="tut_oauth.html">OAuth</a></li>
+ </ul>
+ </li>
+ <li><h2>Reference</h2>
+ <ul>
+ <li>Formats
+ <ul>
+ <li><a href="manifest.html">Manifest Files</a></li>
+ <li><a href="match_patterns.html">Match Patterns</a></li>
+ </ul>
+ </li>
+ <li><a href="permission_warnings.html">Permission Warnings</a></li>
+ <li><a href="api_index.html">chrome.* APIs</a></li>
+ <li><a href="api_other.html">Other APIs</a></li>
+ </ul>
+ </li>
+ <li><h2><a href="samples.html">Samples</a></h2></li>
+ <div class="line"> </div>
+ <li><h2>More</h2>
+ <ul>
+ <li><a href="http://code.google.com/chrome/webstore/docs/index.html">Chrome Web Store</a></li>
+ <li><a href="http://code.google.com/chrome/apps/docs/developers_guide.html">Hosted Apps</a></li>
+ <li><a href="themes.html">Themes</a></li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+ <script>
+ initToggles();
+ </script>
+
+ <div class="g-unit" id="gc-pagecontent">
+ <div id="pageTitle">
+ <h1 class="page_title">experimental.webInspector.* APIs</h1>
+ </div>
+ <!-- TABLE OF CONTENTS -->
+ <div id="toc" style="display: none; ">
+ <h2>Contents</h2>
+ <ol>
+ <li>
+ <a>h2Name</a>
+ <ol>
+ <li>
+ <a>h3Name</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#apiReference">API reference</a>
+ <ol>
+ <li>
+ <a href="#properties">Properties</a>
+ <ol>
+ <li>
+ <a href="#property-anchor">propertyName</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a>Methods</a>
+ <ol>
+ <li>
+ <a href="#method-anchor">methodName</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a>Events</a>
+ <ol>
+ <li>
+ <a href="#event-anchor">eventName</a>
+ </li>
+ </ol>
+ </li>
+ <li>
+ <a href="#types">Types</a>
+ <ol>
+ <li>
+ <a href="#id-anchor">id</a>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </li>
+ </ol>
+ </div>
+ <!-- /TABLE OF CONTENTS -->
+
+ <!-- Standard content lead-in for experimental API pages -->
+ <p id="classSummary" style="display: none; ">
+ For information on how to use experimental APIs, see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
+ </p>
+
+ <!-- STATIC CONTENT PLACEHOLDER -->
+ <div id="static"><div id="pageData-name" class="pageData">experimental.webInspector.* APIs</div>
+
+<p>
+The following API modules provide support for extending
+Chrome Development Tools (aka WebInspector):
+</p>
+
+<a name="api-list"></a>
+<ul>
+ <li>
+ <a href="experimental.webInspector.audits.html">experimental.webInspector.audits</a></li><li>
+ <a href="experimental.webInspector.inspectedWindow.html">experimental.webInspector.inspectedWindow</a></li><li>
+ <a href="experimental.webInspector.panels.html">experimental.webInspector.panels</a></li><li>
+ <a href="experimental.webInspector.resources.html">experimental.webInspector.resources</a></li>
+</ul>
+
+<p class="warning">
+<b>Caution:</b>
+Don't depend on these experimental APIs. They might disappear, and they
+<em>will</em> change.
+Also, the Chrome Developer Dashboard doesn't allow you to
+upload extensions that use experimental APIs.
+</p>
+
+<h2 id="using">How to use WebInspector APIs</h2>
+
+<ol>
+ <li>
+ WebInspector APIs are currently experimental, so please start with
+ <a href="experimental.html">the steps for using experimental extension
+ APIs</a>.
+ </li>
+ <li>
+ Specify the "devtools_page" field in your extension's manifest and make
+ sure you have "experimental" permission:
+<pre>{
+ "name": ...
+ "version": "1.0",
+ "minimum_chrome_version": "10.0",
+ <b>"devtools_page": "devtools.html"</b>,
+ "permissions": [ <b>"experimental"</b> ... ],
+ ...
+}
+</pre>
+ </li>
+ <li>
+ An instance of the devtools_page specified in your extension's manifest
+ will be created for every Developer Tools window opened. The page may add
+ other extension pages as panels and sidebars to the Developer Tools window
+ using <a href="experimental.webInspector.panels">experimental.webInspector.panels</a>
+ API.
+ </li>
+ <li>The APIs available to extension pages within the Developer Tools
+ window include all <a href="#api-list">experimental.webInspector modules
+ listed above</a> and <a href="extension.html">chrome.extension</a> API.
+ Other extension APIs are not available to the Developer Tools pages, but
+ you may invoke them by sending a request to the background page of your
+ extension, similarly to how it's done in the
+ <a href="overview.html#contentScripts">content scripts</a>.
+ </li><li>Please note that, unlike other Chrome Extension APIs, the WebInspector
+ APIs lack "chrome" prefix. This is because the APIs, as the WebInspector
+ itself, are a part of WebKit and may eventually appear in other browsers.
+ </li>
+ <li>
+ <a href="http://groups.google.com/group/google-chrome-developer-tools/topics">Give us feedback!</a>
+ Your comments and suggestions help us improve the APIs and decide which
+ ones should move from experimental to supported.
+ </li>
+</ol>
+
+<h2 id="other">More information</h2>
+
+<p>
+For information on the standard APIs that extensions can use, see
+<a href="api_index.html">chrome.* APIs</a> and
+<a href="api_other.html">Other APIs</a>.
+</p>
+</div>
+
+ <!-- API PAGE -->
+ <div class="apiPage" style="display: none; ">
+ <a name="apiReference"></a>
+ <h2>API reference: chrome.apiname </h2>
+
+ <!-- PROPERTIES -->
+ <div class="apiGroup">
+ <a name="properties"></a>
+ <h3 id="properties">Properties</h3>
+
+ <div>
+ <a></a>
+ <h4>getLastError</h4>
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.extension</span><span>lastError</span>
+ </div>
+ <div>
+ </div>
+ </div>
+
+ </div> <!-- /apiGroup -->
+
+ <!-- METHODS -->
+ <div id="methodsTemplate" class="apiGroup">
+ <a></a>
+ <h3>Methods</h3>
+
+ <!-- iterates over all functions -->
+ <div class="apiItem">
+ <a></a> <!-- method-anchor -->
+ <h4>method name</h4>
+
+ <div class="summary"><span>void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.module.methodName</span>(<span><span>, </span><span></span>
+ <var><span></span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo">Undocumented.</p>
+ <p>
+ A description from the json schema def of the function goes here.
+ </p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4>Returns</h4>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p>
+ This function was added in version <b><span></span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ <!-- EVENTS -->
+ <div id="eventsTemplate" class="apiGroup">
+ <a></a>
+ <h3>Events</h3>
+ <!-- iterates over all events -->
+ <div class="apiItem">
+ <a></a>
+ <h4>event name</h4>
+
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span class="subdued">chrome.bookmarks</span><span>onEvent</span><span class="subdued">.addListener</span>(function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>);
+ </div>
+
+ <div class="description">
+ <p class="todo">Undocumented.</p>
+ <p>
+ A description from the json schema def of the event goes here.
+ </p>
+
+ <!-- PARAMETERS -->
+ <div>
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /decription -->
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ <!-- TYPES -->
+ <div class="apiGroup">
+ <a name="types"></a>
+ <h3 id="types">Types</h3>
+
+ <!-- iterates over all types -->
+ <div class="apiItem">
+ <a></a>
+ <h4>type name</h4>
+
+ <div>
+ </div>
+
+ </div> <!-- /apiItem -->
+
+ </div> <!-- /apiGroup -->
+
+ </div> <!-- /apiPage -->
+ </div> <!-- /gc-pagecontent -->
+ </div> <!-- /g-section -->
+ </div> <!-- /codesiteContent -->
+ <div id="gc-footer" --="">
+ <div class="text">
+ <p>
+ Except as otherwise <a href="http://code.google.com/policies.html#restrictions">noted</a>,
+ the content of this page is licensed under the <a rel="license" href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
+ Attribution 3.0 License</a>, and code samples are licensed under the
+ <a rel="license" href="http://code.google.com/google_bsd_license.html">BSD License</a>.
+ </p>
+ <p>
+ ©2011 Google
+ </p>
+
+<!-- begin analytics -->
+<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
+<script src="http://www.google-analytics.com/ga.js" type="text/javascript"></script>
+
+<script type="text/javascript">
+ // chrome doc tracking
+ try {
+ var engdocs = _gat._getTracker("YT-10763712-2");
+ engdocs._trackPageview();
+ } catch(err) {}
+
+ // code.google.com site-wide tracking
+ try {
+ _uacct="UA-18071-1";
+ _uanchor=1;
+ _uff=0;
+ urchinTracker();
+ }
+ catch(e) {/* urchinTracker not available. */}
+</script>
+<!-- end analytics -->
+ </div>
+ </div> <!-- /gc-footer -->
+ </div> <!-- /gc-container -->
+</body></html>
diff --git a/chrome/common/extensions/docs/experimental.webInspector.panels.html b/chrome/common/extensions/docs/experimental.webInspector.panels.html
index 29a1295..8ee8763 100644
--- a/chrome/common/extensions/docs/experimental.webInspector.panels.html
+++ b/chrome/common/extensions/docs/experimental.webInspector.panels.html
@@ -257,10 +257,17 @@
<div id="toc">
<h2>Contents</h2>
<ol>
- <li style="display: none; ">
- <a>h2Name</a>
+ <li>
+ <a href="#H2-0">Notes</a>
<ol>
- <li>
+ <li style="display: none; ">
+ <a>h3Name</a>
+ </li>
+ </ol>
+ </li><li>
+ <a href="#overview-examples">Examples</a>
+ <ol>
+ <li style="display: none; ">
<a>h3Name</a>
</li>
</ol>
@@ -320,7 +327,52 @@
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"></div>
+ <div id="static"><!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.panels</code> module to integrate your
+extension into Developer Tools window UI: create your own panels, access
+existing panels and add sidebars.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API.
+</p>
+
+<a name="H2-0"></a><h2>Notes</h2>
+
+<p>
+Each extension panel and sidebar is displayed as a separate HTML page. All
+extension pages displayed in the Developer Tools window have access to all
+modules in <code>experimental.webInspector</code> API, as well as to
+<a href="extension.html">chrome.extension</a> API. Other extension APIs are not
+available to the pages within Developer Tools window, but you may invoke them
+by sending a request to the background page of your extension, similarly to how
+it's done in the <a href="overview.html#contentScripts">content scripts</a>.
+</p>
+
+<h2 id="overview-examples">Examples</h2>
+<p>The following code adds a panel contained in <code>Panel.html</code>,
+represented by <code>FontPicker.png</code> on the Developer Tools toolbar
+and labeled as <em>Font Picker</em>:</p>
+
+<pre>webInspector.panels.create("Font Picker", "FontPicker.png", "Panel.html");
+</pre>
+<p>The following code adds a sidebar pane contained in
+<code>Sidebar.html</code> and titled <em>Font Properties</em> to the Elements
+panel, then sets its height to <code>8ex</code>:
+</p><pre>webInspector.panels.elements.createSidebarPane("Font Properties", "Sidebar.html",
+ function(sidebar) {
+ sidebar.setHeight("8ex");
+ }
+}));
+</pre>
+<p>
+This screenshot demonstrates the effect the above examples would have on
+Developer Tools window:
+
+<img src="images/devtools-panels.png" style="margin-left: 20px" width="686" height="289" alt="Extension icon panel on DevTools toolbar">
+</p>
+<!-- END AUTHORED CONTENT -->
+</div>
<!-- API PAGE -->
<div class="apiPage">
diff --git a/chrome/common/extensions/docs/experimental.webInspector.resources.html b/chrome/common/extensions/docs/experimental.webInspector.resources.html
index 60036e2..50b031a 100644
--- a/chrome/common/extensions/docs/experimental.webInspector.resources.html
+++ b/chrome/common/extensions/docs/experimental.webInspector.resources.html
@@ -257,10 +257,17 @@
<div id="toc">
<h2>Contents</h2>
<ol>
- <li style="display: none; ">
- <a>h2Name</a>
+ <li>
+ <a href="#H2-0">Notes</a>
<ol>
- <li>
+ <li style="display: none; ">
+ <a>h3Name</a>
+ </li>
+ </ol>
+ </li><li>
+ <a href="#overview-examples">Examples</a>
+ <ol>
+ <li style="display: none; ">
<a>h3Name</a>
</li>
</ol>
@@ -312,7 +319,49 @@
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"></div>
+ <div id="static"><!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.resources</code> module to retrieve the
+information about network resources displayed by DevTools' Network panel.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API.
+</p>
+
+<a name="H2-0"></a><h2>Notes</h2>
+
+<p>
+Network resource information is represented in HTTP Archive format
+(<em>HAR</em>). The description of HAR is outside of scope of this document,
+please refer to
+<a href="http://groups.google.com/group/http-archive-specification/web/har-1-2-spec">
+HAR v1.2 Specification</a>.
+</p><p>
+In terms of HAR, the <code>webInspector.resources.getHAR()</code> method
+returns entire <em>HAR log</em>, while
+<code>webInspector.resources.onFinish</code> event provides <em>HAR entry</em>
+as an argument to the event callback.
+</p>
+<p>Note that resource content is not provided as part of HAR for efficieny
+reasons. You may call resource's <code>getContent()</code> method to retrieve
+content.
+</p><p>Some resources may be missing in the array of entries returned by <code>
+getHAR()</code> in case WebInspector was opened after the page was loaded —
+reload the page to get all resources. In general, the list of resources returned
+by <code>getHAR()</code> should match that displayed by the Network panel.
+</p><h2 id="overview-examples">Examples</h2>
+
+<p>The following code logs URLs of all images larger than 40KB as they are
+loaded:</p>
+
+<pre>experimental.webInspector.resources.onFinished.addListener(function(resource) {
+ if (resource.response.bodySize &gt; 40*1024)
+ webInspector.log("Large image: " + resource.request.url);
+});
+</pre>
+
+<!-- END AUTHORED CONTENT -->
+</div>
<!-- API PAGE -->
<div class="apiPage">
diff --git a/chrome/common/extensions/docs/experimental.webNavigation.html b/chrome/common/extensions/docs/experimental.webNavigation.html
index 7d733d1..c3041ff 100644
--- a/chrome/common/extensions/docs/experimental.webNavigation.html
+++ b/chrome/common/extensions/docs/experimental.webNavigation.html
@@ -16,7 +16,7 @@
<script type="text/javascript" src="js/api_page_generator.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/sidebar.js"></script>
- <title>chrome.experimental.webNavigation - Google Chrome Extensions - Google Code</title></head>
+ <title>WebNavigation API - Google Chrome Extensions - Google Code</title></head>
<body> <div id="gc-container" class="labs">
<div id="devModeWarning">
You are viewing extension docs in chrome via the 'file:' scheme: are you expecting to see local changes when you refresh? You'll need run chrome with --allow-file-access-from-files.
@@ -251,16 +251,16 @@
<div class="g-unit" id="gc-pagecontent">
<div id="pageTitle">
- <h1 class="page_title">chrome.experimental.webNavigation</h1>
+ <h1 class="page_title">WebNavigation API</h1>
</div>
<!-- TABLE OF CONTENTS -->
<div id="toc">
<h2>Contents</h2>
<ol>
- <li style="display: none; ">
- <a>h2Name</a>
+ <li>
+ <a href="#H2-0">A note about timestamps</a>
<ol>
- <li>
+ <li style="display: none; ">
<a>h3Name</a>
</li>
</ol>
@@ -317,12 +317,35 @@
<!-- /TABLE OF CONTENTS -->
<!-- Standard content lead-in for experimental API pages -->
- <p id="classSummary">
+ <p id="classSummary" style="display: none; ">
For information on how to use experimental APIs, see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"></div>
+ <div id="static"><div id="pageData-name" class="pageData">WebNavigation API</div>
+
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>chrome.experimental.webNavigation</code> module to recieve
+notifications about the status of navigations requests in-flight. This
+module is still very much experimental. For information on how to use
+experimental APIs, see the <a href="experimental.html">chrome.experimental.*
+APIs</a> page.
+</p>
+
+<a name="H2-0"></a><h2>A note about timestamps</h2>
+<p>
+It's important to note that some technical oddities in the OS's handling
+of distinct Chrome processes can cause the clock to be skewed between the
+browser itself and extension processes. That means that WebNavigation's events'
+<code>timeStamp</code> property is only guaranteed to be <i>internally</i>
+consistent. Comparing one event to another event will give you the correct
+offset between them, but comparing them to the current time inside the
+extension (via <code>(new Date()).getTime()</code>, for instance) might give
+unexpected results.
+</p>
+<!-- END AUTHORED CONTENT -->
+</div>
<!-- API PAGE -->
<div class="apiPage">
@@ -717,7 +740,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
diff --git a/chrome/common/extensions/docs/experimental.webRequest.html b/chrome/common/extensions/docs/experimental.webRequest.html
index 0e11c39..65f7ce6 100644
--- a/chrome/common/extensions/docs/experimental.webRequest.html
+++ b/chrome/common/extensions/docs/experimental.webRequest.html
@@ -16,7 +16,7 @@
<script type="text/javascript" src="js/api_page_generator.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/sidebar.js"></script>
- <title>chrome.experimental.webRequest - Google Chrome Extensions - Google Code</title></head>
+ <title>WebRequest API - Google Chrome Extensions - Google Code</title></head>
<body> <div id="gc-container" class="labs">
<div id="devModeWarning">
You are viewing extension docs in chrome via the 'file:' scheme: are you expecting to see local changes when you refresh? You'll need run chrome with --allow-file-access-from-files.
@@ -251,16 +251,16 @@
<div class="g-unit" id="gc-pagecontent">
<div id="pageTitle">
- <h1 class="page_title">chrome.experimental.webRequest</h1>
+ <h1 class="page_title">WebRequest API</h1>
</div>
<!-- TABLE OF CONTENTS -->
<div id="toc">
<h2>Contents</h2>
<ol>
- <li style="display: none; ">
- <a>h2Name</a>
+ <li>
+ <a href="#H2-0">A note about timestamps</a>
<ol>
- <li>
+ <li style="display: none; ">
<a>h3Name</a>
</li>
</ol>
@@ -281,6 +281,8 @@
<ol>
<li style="display: none; ">
<a href="#method-anchor">methodName</a>
+ </li><li style="display: none; ">
+ <a href="#method-anchor">methodName</a>
</li>
</ol>
</li>
@@ -292,6 +294,8 @@
</li><li>
<a href="#event-onBeforeRequest">onBeforeRequest</a>
</li><li>
+ <a href="#event-onBeforeSendHeaders">onBeforeSendHeaders</a>
+ </li><li>
<a href="#event-onCompleted">onCompleted</a>
</li><li>
<a href="#event-onErrorOccurred">onErrorOccurred</a>
@@ -307,6 +311,8 @@
<ol>
<li>
<a href="#type-RequestFilter">RequestFilter</a>
+ </li><li>
+ <a href="#type-BlockingResponse">BlockingResponse</a>
</li>
</ol>
</li>
@@ -317,12 +323,34 @@
<!-- /TABLE OF CONTENTS -->
<!-- Standard content lead-in for experimental API pages -->
- <p id="classSummary">
+ <p id="classSummary" style="display: none; ">
For information on how to use experimental APIs, see the <a href="experimental.html">chrome.experimental.* APIs</a> page.
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"></div>
+ <div id="static"><div id="pageData-name" class="pageData">WebRequest API</div>
+
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>chrome.experimental.webRequest</code> module to intercept, block,
+or modify requests in-flight. This module is still very much experimental. For
+information on how to use experimental APIs, see the
+<a href="experimental.html">chrome.experimental.* APIs</a> page.
+</p>
+
+<a name="H2-0"></a><h2>A note about timestamps</h2>
+<p>
+It's important to note that some technical oddities in the OS's handling
+of distinct Chrome processes can cause the clock to be skewed between the
+browser itself and extension processes. That means that WebRequest's events'
+<code>timeStamp</code> property is only guaranteed to be <i>internally</i>
+consistent. Comparing one event to another event will give you the correct
+offset between them, but comparing them to the current time inside the
+extension (via <code>(new Date()).getTime()</code>, for instance) might give
+unexpected results.
+</p>
+<!-- END AUTHORED CONTENT -->
+</div>
<!-- API PAGE -->
<div class="apiPage">
@@ -419,6 +447,72 @@
</p>
</div> <!-- /description -->
+ </div><div class="apiItem" style="display: none; ">
+ <a></a> <!-- method-anchor -->
+ <h4>method name</h4>
+
+ <div class="summary"><span>void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.module.methodName</span>(<span><span>, </span><span></span>
+ <var><span></span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo">Undocumented.</p>
+ <p>
+ A description from the json schema def of the function goes here.
+ </p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4>Returns</h4>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p>
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>Type param1, Type param2</span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p>
+ This function was added in version <b><span></span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
</div> <!-- /apiItem -->
</div> <!-- /apiGroup -->
@@ -511,7 +605,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -940,7 +1034,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -1357,6 +1451,301 @@
</div> <!-- /decription -->
</div><div class="apiItem">
+ <a name="event-onBeforeSendHeaders"></a>
+ <h4>onBeforeSendHeaders</h4>
+
+ <div class="summary">
+ <!-- Note: intentionally longer 80 columns -->
+ <span class="subdued">chrome.experimental.webRequest.</span><span>onBeforeSendHeaders</span><span class="subdued">.addListener</span>(function(<span>object details</span>) <span class="subdued">{...}</span>);
+ </div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Fires before sending an HTTP request, once the request headers are available.</p>
+
+ <!-- PARAMETERS -->
+ <div>
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>details</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>requestId</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The ID of the request. Request IDs are unique within a browser session. As a result, they could be used to relate different events of the same request.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>url</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>timeStamp</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>number</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>The time when the browser was about to send headers, in milliseconds since the epoch.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div> <!-- /decription -->
+
+ </div><div class="apiItem">
<a name="event-onCompleted"></a>
<h4>onCompleted</h4>
@@ -1439,7 +1828,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -1800,7 +2189,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -2161,7 +2550,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -2524,7 +2913,7 @@
<span style="display: none; ">
array of <span><span></span></span>
</span>
- <span>integer</span>
+ <span>string</span>
<span style="display: none; "></span>
</span>
</span>
@@ -3181,6 +3570,211 @@
</div>
+ </div><div class="apiItem">
+ <a name="type-BlockingResponse"></a>
+ <h4>BlockingResponse</h4>
+
+ <div>
+ <dt>
+ <var style="display: none; ">paramName</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>object</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Return value for event handlers that have the 'blocking' extraInfoSpec applied. Allows the event handler to modify network requests.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>cancel</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>If true, the request is cancelled. Used in onBeforeRequest, this prevents the request from being sent.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
+ <var>redirectUrl</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>string</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>If set, the original request is prevented from being sent and is instead redirected to the given URL.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+
</div> <!-- /apiItem -->
</div> <!-- /apiGroup -->
diff --git a/chrome/common/extensions/docs/extension.html b/chrome/common/extensions/docs/extension.html
index 9e99f0e..c8d6378 100644
--- a/chrome/common/extensions/docs/extension.html
+++ b/chrome/common/extensions/docs/extension.html
@@ -294,6 +294,10 @@
</li><li>
<a href="#method-getViews">getViews</a>
</li><li>
+ <a href="#method-isAllowedFileSchemeAccess">isAllowedFileSchemeAccess</a>
+ </li><li>
+ <a href="#method-isAllowedIncognitoAccess">isAllowedIncognitoAccess</a>
+ </li><li>
<a href="#method-sendRequest">sendRequest</a>
</li><li>
<a href="#method-setUpdateUrlData">setUpdateUrlData</a>
@@ -1813,6 +1817,398 @@ For details, see
</div> <!-- /description -->
</div><div class="apiItem">
+ <a name="method-isAllowedFileSchemeAccess"></a> <!-- method-anchor -->
+ <h4>isAllowedFileSchemeAccess</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.extension.isAllowedFileSchemeAccess</span>(<span class="null"><span style="display: none; ">, </span><span>function</span>
+ <var><span>callback</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Retrieves the state of the extension's access to the 'file://' scheme (as determined by the user-controlled 'Allow access to File URLs' checkbox.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>callback</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>function</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p style="display: none; ">
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>boolean isAllowedAccess</span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>isAllowedAccess</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>True if the extension can access the 'file://' scheme, false otherwise.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p>
+ This function was added in version <b><span>12.0.706.0</span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
+ <a name="method-isAllowedIncognitoAccess"></a> <!-- method-anchor -->
+ <h4>isAllowedIncognitoAccess</h4>
+
+ <div class="summary"><span style="display: none; ">void</span>
+ <!-- Note: intentionally longer 80 columns -->
+ <span>chrome.extension.isAllowedIncognitoAccess</span>(<span class="null"><span style="display: none; ">, </span><span>function</span>
+ <var><span>callback</span></var></span>)</div>
+
+ <div class="description">
+ <p class="todo" style="display: none; ">Undocumented.</p>
+ <p>Retrieves the state of the extension's access to Incognito-mode (as determined by the user-controlled 'Allowed in Incognito' checkbox.</p>
+
+ <!-- PARAMETERS -->
+ <h4>Parameters</h4>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>callback</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>function</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo">
+ Undocumented.
+ </dd>
+ <dd style="display: none; ">
+ Description of this parameter from the json schema.
+ </dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+
+ <!-- RETURNS -->
+ <h4 style="display: none; ">Returns</h4>
+ <dl>
+ <div style="display: none; ">
+ <div>
+ </div>
+ </div>
+ </dl>
+
+ <!-- CALLBACK -->
+ <div>
+ <div>
+ <h4>Callback function</h4>
+ <p>
+ The callback <em>parameter</em> should specify a function
+ that looks like this:
+ </p>
+ <p style="display: none; ">
+ If you specify the <em>callback</em> parameter, it should
+ specify a function that looks like this:
+ </p>
+
+ <!-- Note: intentionally longer 80 columns -->
+ <pre>function(<span>boolean isAllowedAccess</span>) <span class="subdued">{...}</span>;</pre>
+ <dl>
+ <div>
+ <div>
+ <dt>
+ <var>isAllowedAccess</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>True if the extension has access to Incognito mode, false otherwise.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div>
+ </dl>
+ </div>
+ </div>
+
+ <!-- MIN_VERSION -->
+ <p>
+ This function was added in version <b><span>12.0.706.0</span></b>.
+ If you require this function, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </p>
+ </div> <!-- /description -->
+
+ </div><div class="apiItem">
<a name="method-sendRequest"></a> <!-- method-anchor -->
<h4>sendRequest</h4>
diff --git a/chrome/common/extensions/docs/i18n.html b/chrome/common/extensions/docs/i18n.html
index fc3351f..086f828 100644
--- a/chrome/common/extensions/docs/i18n.html
+++ b/chrome/common/extensions/docs/i18n.html
@@ -623,8 +623,8 @@ padding-right: 1.5em;
<h2 id="overview-locales">Locales</h2>
<p>
-Extensions can use all the locales that Google Chrome supports,
-plus a few (such as <code>en</code>)
+You can choose from many locales,
+including some (such as <code>en</code>)
that let a single translation support multiple variations of a language
(such as <code>en_GB</code> and <code>en_US</code>).
</p>
@@ -633,12 +633,8 @@ that let a single translation support multiple variations of a language
<h3 id="locales-supported">Supported locales</h3>
<p>
-Your extension can use any of the following locales:
-</p>
-
-<p>
-<code>am ar bg bn ca cs da de el en en_GB en_US es es_419 et fi fil fr gu he hi hr hu id it ja kn ko lt
-lv ml mr nb nl or pl pt pt_BR pt_PT ro ru sk sl sr sv sw ta te th tr uk vi zh zh_CN zh_TW</code>
+Extensions can use any of the
+<a href="http://code.google.com/chrome/webstore/docs/i18n.html#localeTable">locales that the Chrome Web Store supports</a>.
</p>
diff --git a/chrome/common/extensions/docs/images/devtools-audits-category.png b/chrome/common/extensions/docs/images/devtools-audits-category.png
new file mode 100644
index 0000000..b05fc7d
--- /dev/null
+++ b/chrome/common/extensions/docs/images/devtools-audits-category.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/devtools-audits-results.png b/chrome/common/extensions/docs/images/devtools-audits-results.png
new file mode 100644
index 0000000..9185055
--- /dev/null
+++ b/chrome/common/extensions/docs/images/devtools-audits-results.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/devtools-panels.png b/chrome/common/extensions/docs/images/devtools-panels.png
new file mode 100644
index 0000000..93cbdfa
--- /dev/null
+++ b/chrome/common/extensions/docs/images/devtools-panels.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/index/gmail.png b/chrome/common/extensions/docs/images/index/gmail.png
deleted file mode 100644
index dda74da..0000000
--- a/chrome/common/extensions/docs/images/index/gmail.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/images/index/news.png b/chrome/common/extensions/docs/images/index/news.png
deleted file mode 100644
index 0dedda4..0000000
--- a/chrome/common/extensions/docs/images/index/news.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/images/index/rss.png b/chrome/common/extensions/docs/images/index/rss.png
deleted file mode 100644
index 304e8ff..0000000
--- a/chrome/common/extensions/docs/images/index/rss.png
+++ /dev/null
Binary files differ
diff --git a/chrome/common/extensions/docs/images/intermediate/README.txt b/chrome/common/extensions/docs/images/intermediate/README.txt
index bae6a9b..271d373 100644
--- a/chrome/common/extensions/docs/images/intermediate/README.txt
+++ b/chrome/common/extensions/docs/images/intermediate/README.txt
@@ -2,6 +2,13 @@ This directory contains files that we've used to create images. If you
need to change images, edit these files instead of the gif/png files
that are derived from them.
+Most of the images in this directory are either OmniGraffle files or
+full-size images that we reduced or combined to produce the images
+that we display in the doc.
+
+NOTE: No page should point to images/intermediate/<any file>
+
+
overview-arch.graffle
-----
An OmniGraffle file used to create the arch-* figures in overview.html.
diff --git a/chrome/common/extensions/docs/images/arch-1.gif b/chrome/common/extensions/docs/images/overview/arch-1.gif
index 16d4a84..16d4a84 100644
--- a/chrome/common/extensions/docs/images/arch-1.gif
+++ b/chrome/common/extensions/docs/images/overview/arch-1.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/images/arch-2.gif b/chrome/common/extensions/docs/images/overview/arch-2.gif
index e6281c5..e6281c5 100644
--- a/chrome/common/extensions/docs/images/arch-2.gif
+++ b/chrome/common/extensions/docs/images/overview/arch-2.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/images/arch-3.gif b/chrome/common/extensions/docs/images/overview/arch-3.gif
index 968f388..968f388 100644
--- a/chrome/common/extensions/docs/images/arch-3.gif
+++ b/chrome/common/extensions/docs/images/overview/arch-3.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/images/arch-cs.gif b/chrome/common/extensions/docs/images/overview/arch-cs.gif
index 619ea2a..619ea2a 100644
--- a/chrome/common/extensions/docs/images/arch-cs.gif
+++ b/chrome/common/extensions/docs/images/overview/arch-cs.gif
Binary files differ
diff --git a/chrome/common/extensions/docs/images/overview/browser-action-with-popup.png b/chrome/common/extensions/docs/images/overview/browser-action-with-popup.png
new file mode 100644
index 0000000..b1ca45e
--- /dev/null
+++ b/chrome/common/extensions/docs/images/overview/browser-action-with-popup.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/overview/browser-action.png b/chrome/common/extensions/docs/images/overview/browser-action.png
new file mode 100644
index 0000000..8bf54df
--- /dev/null
+++ b/chrome/common/extensions/docs/images/overview/browser-action.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/index/flashapp.png b/chrome/common/extensions/docs/images/overview/flash-app.png
index c3052b4..c3052b4 100644
--- a/chrome/common/extensions/docs/images/index/flashapp.png
+++ b/chrome/common/extensions/docs/images/overview/flash-app.png
Binary files differ
diff --git a/chrome/common/extensions/docs/images/overview/page-action.png b/chrome/common/extensions/docs/images/overview/page-action.png
new file mode 100644
index 0000000..257a233
--- /dev/null
+++ b/chrome/common/extensions/docs/images/overview/page-action.png
Binary files differ
diff --git a/chrome/common/extensions/docs/index.html b/chrome/common/extensions/docs/index.html
index 3888f88..8b84fd9 100644
--- a/chrome/common/extensions/docs/index.html
+++ b/chrome/common/extensions/docs/index.html
@@ -420,7 +420,7 @@ For more information, see the
</p>
<p>
-<object width="300" height="250"><param name="movie" value="http://www.youtube.com/p/38DF05697DE372B1&amp;hl=en_US&amp;fs=1"><param name="allowFullScreen" value="true"><param name="allowscriptaccess" value="always"><embed src="http://www.youtube.com/p/38DF05697DE372B1&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" width="300" height="250" allowscriptaccess="always" allowfullscreen="true"></object>
+<iframe title="YouTube video player" width="300" height="199" src="http://www.youtube.com/embed/wRDPTnY3yO8?rel=0" frameborder="0" allowfullscreen=""></iframe>
</p>
</td>
</tr>
diff --git a/chrome/common/extensions/docs/js/api_page_generator.js b/chrome/common/extensions/docs/js/api_page_generator.js
index 185aafc..b5afc6f 100644
--- a/chrome/common/extensions/docs/js/api_page_generator.js
+++ b/chrome/common/extensions/docs/js/api_page_generator.js
@@ -1,3 +1,7 @@
+// Copyright (c) 2011 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 This file is the controller for generating extension
* doc pages.
@@ -14,12 +18,13 @@
*
*/
-var USE_DEVTOOLS_SCHEMA = /\.webInspector\.[^/]*\.html/.test(location.href);
var API_TEMPLATE = "template/api_template.html";
var WEBKIT_PATH = "../../../../third_party/WebKit";
-var SCHEMA = USE_DEVTOOLS_SCHEMA ?
- WEBKIT_PATH + "/Source/WebCore/inspector/front-end/ExtensionAPISchema.json"
- : "../api/extension_api.json";
+var SCHEMA = "../api/extension_api.json";
+var DEVTOOLS_SCHEMA = WEBKIT_PATH +
+ "/Source/WebCore/inspector/front-end/ExtensionAPISchema.json";
+var USE_DEVTOOLS_SCHEMA =
+ /\.webInspector[^/]*\.html/.test(location.pathname);
var API_MODULE_PREFIX = USE_DEVTOOLS_SCHEMA ? "" : "chrome.";
var SAMPLES = "samples.json";
var REQUEST_TIMEOUT = 2000;
@@ -101,7 +106,6 @@ function fetchStatic() {
fetchContent(staticResource(pageBase), function(overviewContent) {
document.getElementById("static").innerHTML = overviewContent;
fetchSchema();
-
}, function(error) {
// Not fatal. Some api pages may not have matching static content.
fetchSchema();
@@ -111,16 +115,34 @@ function fetchStatic() {
function fetchSchema() {
// Now the page is composed with the authored content, we fetch the schema
// and populate the templates.
- fetchContent(SCHEMA, function(schemaContent) {
- schema = JSON.parse(schemaContent);
+ var is_experimental_index = /\/experimental\.html$/.test(location.pathname);
+
+ var schemas_to_retrieve = [];
+ if (!USE_DEVTOOLS_SCHEMA || is_experimental_index)
+ schemas_to_retrieve.push(SCHEMA);
+ if (USE_DEVTOOLS_SCHEMA || is_experimental_index)
+ schemas_to_retrieve.push(DEVTOOLS_SCHEMA);
+
+ var schemas_retrieved = 0;
+ schema = [];
+
+ function onSchemaContent(content) {
+ schema = schema.concat(JSON.parse(content));
+ if (++schemas_retrieved < schemas_to_retrieve.length)
+ return;
if (pageName.toLowerCase() == "samples") {
fetchSamples();
} else {
renderTemplate();
}
- }, function(error) {
- alert("Failed to load " + SCHEMA);
- });
+ }
+
+ for (var i = 0; i < schemas_to_retrieve.length; ++i) {
+ var schema_path = schemas_to_retrieve[i];
+ fetchContent(schema_path, onSchemaContent, function(error) {
+ alert("Failed to load " + schema_path);
+ });
+ }
}
function fetchSamples() {
@@ -325,6 +347,14 @@ function experimentalAPIs() {
}).sort();
}
+function webInspectorAPIs() {
+ return schema.filter(function(module) {
+ return !module.nodoc && module.namespace.indexOf("webInspector.") !== 0;
+ }).map(function(module) {
+ return module.namespace;
+ }).sort();
+}
+
function getDataFromPageHTML(id) {
var node = document.getElementById(id);
if (!node)
diff --git a/chrome/common/extensions/docs/management.html b/chrome/common/extensions/docs/management.html
index 5312d8c..a7dc6f2 100644
--- a/chrome/common/extensions/docs/management.html
+++ b/chrome/common/extensions/docs/management.html
@@ -2440,6 +2440,74 @@ For example:</p>
</div><div>
<div>
<dt>
+ <var>mayDisable</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional" style="display: none; ">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>Whether this extension can be disabled or uninstalled by the user.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
<var>enabled</var>
<em>
diff --git a/chrome/common/extensions/docs/override.html b/chrome/common/extensions/docs/override.html
index f2aa1dd..ba947fc 100644
--- a/chrome/common/extensions/docs/override.html
+++ b/chrome/common/extensions/docs/override.html
@@ -16,7 +16,7 @@
<script type="text/javascript" src="js/api_page_generator.js"></script>
<script type="text/javascript" src="js/bootstrap.js"></script>
<script type="text/javascript" src="js/sidebar.js"></script>
- <title>Override - Google Chrome Extensions - Google Code</title></head>
+ <title>Override Pages - Google Chrome Extensions - Google Code</title></head>
<body> <div id="gc-container" class="labs">
<div id="devModeWarning">
You are viewing extension docs in chrome via the 'file:' scheme: are you expecting to see local changes when you refresh? You'll need run chrome with --allow-file-access-from-files.
@@ -251,7 +251,7 @@
<div class="g-unit" id="gc-pagecontent">
<div id="pageTitle">
- <h1 class="page_title">Override</h1>
+ <h1 class="page_title">Override Pages</h1>
</div>
<!-- TABLE OF CONTENTS -->
<div id="toc">
@@ -326,7 +326,10 @@
</p>
<!-- STATIC CONTENT PLACEHOLDER -->
- <div id="static"><style>
+ <div id="static"><div id="pageData-name" class="pageData">Override Pages</div>
+<div id="pageData-showTOC" class="pageData">true</div>
+
+<style>
#pics {
margin:2em 1em 1.5em;
}
@@ -346,9 +349,6 @@
}
</style>
-<div id="pageData-title" class="pageData">Override Pages</div>
-<div id="pageData-showTOC" class="pageData">true</div>
-
<p>
Override pages are a way to substitute an HTML file from your extension
for a page that Google Chrome normally provides.
@@ -388,19 +388,23 @@ An extension can replace any one of the following pages:
<p class="note">
<b>Note:</b>
A single extension can override
-only one page.
+<b>only one page</b>.
+For example, an extension can't override both
+the Bookmark Manager and History pages.
</p>
-<p class="note">
-<b>Note:</b>
-If you want to override the page in incognito windows as well, make sure to
-specify "spanning" mode for the <a href="manifest.html#incognito">incognito</a>
-manifest property.
-</p>
-
-<p class="note">
-<b>Note:</b>
-You cannot override the New Tab page in incognito windows.
+<p>
+Incognito windows are treated specially.
+New Tab pages cannot be overridden in incognito windows.
+Other override pages work in incognito windows
+as long as the
+<a href="manifest.html#incognito">incognito</a>
+manifest property is set to "spanning"
+(which is the default value for extensions
+but not for packaged apps).
+See <a href="overview.html#incognito">Saving data and incognito mode</a>
+in the Overview for more details on how you should treat
+incognito windows.
</p>
<p>
@@ -502,15 +506,9 @@ For an effective override page, follow these guidelines:
<h2 id="examples"> Examples </h2>
<p>
-You can find simple examples of defining override pages in the
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/override/">examples/api/override</a>
-directory.
-For other examples and for help in viewing the source code, see
-<a href="samples.html">Samples</a>.
+See the
+<a href="samples.html#chrome_url_overrides">override samples</a>.
</p>
-
-
-<!-- [PENDING: Maybe have a gallery of NTPs?] -->
</div>
<!-- API PAGE -->
diff --git a/chrome/common/extensions/docs/overview.html b/chrome/common/extensions/docs/overview.html
index 89a18cb..f91d3aa 100644
--- a/chrome/common/extensions/docs/overview.html
+++ b/chrome/common/extensions/docs/overview.html
@@ -279,7 +279,9 @@
<a href="#arch">Architecture</a>
<ol>
<li>
- <a href="#pages">Pages</a>
+ <a href="#background_page">The background page</a>
+ </li><li>
+ <a href="#pages">UI pages</a>
</li><li>
<a href="#contentScripts">Content scripts</a>
</li>
@@ -408,14 +410,14 @@ depending on the page.
<table class="columns">
<tbody><tr>
- <td>
- <img src="images/index/gmail.png" width="150" height="79" alt="screenshot">
+ <td width="33%">
+ <img src="images/overview/browser-action.png" width="147" height="100" alt="screenshot">
</td>
- <td>
- <img src="images/index/news.png" width="150" height="79" alt="screenshot">
+ <td width="33%">
+ <img src="images/overview/page-action.png" width="147" height="100" alt="screenshot">
</td>
<td>
- <img src="images/index/rss.png" width="150" height="79" alt="screenshot">
+ <img src="images/overview/browser-action-with-popup.png" width="147" height="100" alt="screenshot">
</td>
</tr>
@@ -426,18 +428,18 @@ depending on the page.
(icon in the toolbar).
</td>
<td>
- This <a href="samples.html#news">news reader extension</a>
- features a browser action that,
- when clicked,
- shows a <em>popup</em>.
- </td>
- <td>
This <a href="samples.html#mappy">map extension</a>
uses a <em>page action</em>
(icon in the address bar)
and <em>content script</em>
(code injected into a web page).
</td>
+ <td>
+ This <a href="samples.html#news">news extension</a>
+ features a browser action that,
+ when clicked,
+ shows a <em>popup</em>.
+ </td>
</tr>
</tbody></table>
@@ -462,7 +464,7 @@ For example, the following packaged app
displays a Flash file within an HTML page.
</p>
-<img src="images/index/flashapp.png" width="372" height="300" alt="screenshot">
+<img src="images/overview/flash-app.png" width="372" height="300" alt="screenshot">
<p>
For more information,
@@ -568,38 +570,89 @@ For details, see
<h2 id="arch">Architecture</h2>
<p>
-Most extensions have a
-<a href="background_pages.html">background page</a>,
+Many extensions have a <em>background page</em>,
an invisible page
that holds the main logic of the extension.
+An extension can also contain other pages
+that present the extension's UI.
+If an extension needs to interact with web pages that the user loads
+(as opposed to pages that are included in the extension),
+then the extension must use a content script.
</p>
-<img src="images/arch-1.gif" width="232" height="168" alt="Two windows and a box representing a background page (background.html). One window has a yellow icon; the other has both a yellow icon and a blue icon. The yellow icons are connected to the background page.">
+
+<h3 id="background_page">The background page</h3>
<p>
-The preceding figure shows a browser
+The following figure shows a browser
that has at least two extensions installed:
a browser action (yellow icon)
and a page action (blue icon).
-The browser action's background page,
-which is defined by an HTML file
-(<code>background.html</code>),
-has JavaScript code that controls
+Both the browser action and the page action
+have background pages defined by HTML files.
+This figure shows the browser action's background page,
+which is defined by <code>background.html</code>
+and has JavaScript code that controls
the behavior of the browser action in both windows.
</p>
+<img src="images/overview/arch-1.gif" width="232" height="168" alt="Two windows and a box representing a background page (background.html). One window has a yellow icon; the other has both a yellow icon and a blue icon. The yellow icons are connected to the background page.">
-<h3 id="pages">Pages</h3>
+<p>
+Although background pages can be useful,
+don't use one if you don't need it.
+Background pages are always open,
+so when a user installs many extensions that have background pages,
+Chrome's performance can suffer.
+</p>
+
+<!-- PENDING: Perhaps show a picture of many background page processes.
+ This could build on a figure that shows the process architecture,
+ and perhaps the differences between packaged apps and extensions. -->
+
+<p>
+Here are some examples of extensions that usually
+<b>do not need</b> a background page:
+</p>
+
+<ul>
+ <li> An extension with a browser action that
+ presents its UI solely through a popup
+ (and perhaps an options page).
+ </li>
+ <li>
+ An extension that provides an <em>override page</em>—a
+ page that replaces a standard Chrome page.
+ </li>
+ <li>
+ An extension with a content script
+ that doesn't use cross-origin XMLHttpRequests or localStorage,
+ and that doesn't need to use
+ <a href="api_index.html">extension APIs</a>.
+ </li>
+ <li>
+ An extension that has no UI except for an options page.
+ </li>
+</ul>
<p>
-The background page isn't the only HTML page
-that an extension can have.
+See <a href="background_pages.html">Background Pages</a>
+for more details.
+</p>
+
+<h3 id="pages">UI pages</h3>
+
+<p>
+Extensions can contain ordinary HTML pages that display the extension's UI.
For example, a browser action can have a popup,
which is implemented by an HTML file.
-Extensions can also
-use <a href="tabs.html#Method-create"><code>chrome.tabs.create()</code></a>
+Any extension can have an options page,
+which lets users customize how the extension works.
+Another type of special page is the override page.
+And finally, you can
+use <a href="tabs.html#method-create"><code>chrome.tabs.create()</code></a>
or <code>window.open()</code>
-to display HTML files that are in the extension.
+to display any other HTML files that are in the extension.
</p>
<p>
@@ -608,23 +661,30 @@ have complete access to each other's DOMs,
and they can invoke functions on each other.
</p>
+<!-- PENDING: Change the following example and figure
+to use something that's not a popup?
+(It might lead people to think that popups need background pages.) -->
+
<p>
The following figure shows the architecture
of a browser action's popup.
The popup's contents are a web page
defined by an HTML file
(<code>popup.html</code>).
+This extension also happens to have a background page
+(<code>background.html</code>).
The popup doesn't need to duplicate code
that's in the background page
-(<code>background.html</code>)
because the popup can invoke functions on the background page.
</p>
-<img src="images/arch-2.gif" width="256" height="168" alt="A browser window containing a browser action that's displaying a popup. The popup's HTML file (popup.html) can communicate with the extension's background page (background.html).">
+<img src="images/overview/arch-2.gif" width="256" height="168" alt="A browser window containing a browser action that's displaying a popup. The popup's HTML file (popup.html) can communicate with the extension's background page (background.html).">
<p>
-See the <a href="browserAction.html">Browser Actions</a> page and
-the <a href="#pageComm">Communication between pages</a> section
+See <a href="browserAction.html">Browser Actions</a>,
+<a href="options.html">Options</a>,
+<a href="override.html">Override Pages</a>,
+and the <a href="#pageComm">Communication between pages</a> section
for more details.
</p>
@@ -661,7 +721,7 @@ the DOM for the displayed web page.
It cannot, however, modify the DOM of its parent extension's background page.
</p>
-<img src="images/arch-3.gif" width="238" height="169" alt="A browser window with a browser action (controlled by background.html) and a content script (controlled by contentscript.js).">
+<img src="images/overview/arch-3.gif" width="238" height="169" alt="A browser window with a browser action (controlled by background.html) and a content script (controlled by contentscript.js).">
<p>
Content scripts aren't completely cut off from their parent extensions.
@@ -673,7 +733,7 @@ Or a background page might send a message
asking a content script to change the appearance of its browser page.
</p>
-<img src="images/arch-cs.gif" width="238" height="194" alt="Like the previous figure, but showing more of the parent extension's files, as well as a communication path between the content script and the parent extension.">
+<img src="images/overview/arch-cs.gif" width="238" height="194" alt="Like the previous figure, but showing more of the parent extension's files, as well as a communication path between the content script and the parent extension.">
<!-- [PENDING: Add overview of message passing.] -->
diff --git a/chrome/common/extensions/docs/permission_warnings.html b/chrome/common/extensions/docs/permission_warnings.html
index 66b96dd..4ba491f 100644
--- a/chrome/common/extensions/docs/permission_warnings.html
+++ b/chrome/common/extensions/docs/permission_warnings.html
@@ -338,7 +338,7 @@
<!--
NOTE: When this doc is updated, the online help should also be updated:
-http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=186213
+http://www.google.com/support/chrome_webstore/bin/answer.py?hl=en&answer=186213
We should periodically look at
http://src.chromium.org/viewvc/chrome/trunk/src/chrome/app/generated_resources.grd?view=markup
@@ -535,17 +535,24 @@ that trigger them.
<!-- HasEffectiveAccessToAllHosts() -->
Any of the following:
<ul>
- <li> "proxy" permission (experimental) </li>
+ <li> "proxy" permission </li>
+ <li> "debugger" permission </li>
<li> A match pattern in the "permissions" field
that matches all hosts </li>
<li> A&nbsp;"content_scripts" field with a "matches" entry
that matches all hosts </li>
+ <li> "devtools_page" (experimental) </li>
</ul>
</td>
<td>
<p>
The "proxy" permission is required by the
- <a href="http://code.google.com/chrome/extensions/dev/experimental.proxy.html">experimental proxy</a> module.
+ <a href="experimental.proxy.html">experimental proxy</a> module.
+ </p>
+
+ <p>
+ The "debugger" permission is required by the
+ <a href="experimental.debugger.html">experimental debugger</a> module.
</p>
<p>
diff --git a/chrome/common/extensions/docs/samples.html b/chrome/common/extensions/docs/samples.html
index bda40f4..07ee87b 100644
--- a/chrome/common/extensions/docs/samples.html
+++ b/chrome/common/extensions/docs/samples.html
@@ -313,7 +313,7 @@
<!-- STATIC CONTENT PLACEHOLDER -->
<div id="static"><link rel="stylesheet" href="css/samples.css">
-<script>var search_data = {"0262260daf0c8f7b28feff2ef23b05e7abf9d1e0":"A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON","ea2894c41cb8e80a4433a3e6c5772dadce9be90d":"A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT","ede3c47b7757245be42ec33fd5ca63df4b490066":"A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT","fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a":"ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE","9a6e4ec46997fb92b324974afa08a3d007e2537f":"ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED","a1f7cf79dd555b04fa8d603247a040e644996293":"APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE","9747e3d6a3eab39bc7c17f11a80573c62d44c7e5":"BLANK NEW TAB PAGE CHROME_URL_OVERRIDES","903e7277139e1e6caec123d3319cab295d8d1b3a":"CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED","0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5":"CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL","ac31228200b41a87982e386cc90d3a6eee4ad885":"CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE","7d5d6cf195bc25480256618e360aa38c6e6fba82":"CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED","5d81304a17cf7ac2887484f730fbd2b01e51e166":"CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE","4daa6becd0899a54776d9cf7f09613ed1a9f4d77":"COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL","6871d09f4a96bf9d4b6cc724d00e909cee0f3902":"CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","028eb5364924344029bcbe1d527f132fc72b34e5":"EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE","763a08e9b06595d785568a8d392b95a2f3700258":"EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP","e3df888a89e35bdeb9c8bc8d03be5e1851b97c68":"EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE","8b0dd31216235941bdd8eb33fda915ef5cf79a82":"GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","4e35caa9742fb82dbd628892d23a781614f6eff6":"GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca":"GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","1682e05ea9a1bde985123b04f6f8ac50a8a64033":"GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","14b9651fda4e57b2a5914ba73a779812201b750a":"HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP","2020d72f2577f53caf8e94e3dbac0fb849ceaa4d":"IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE","0ea1588bd07b20338fc21f725de1542a5fdf9726":"IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES","646325c25f572a1d15edc73d057f821d847a4fbe":"IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE","ec97ec20ca2f095d081e39f1565fc12af09ef067":"MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST","b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d":"MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT","51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e":"MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST","4f6785ec4f937add6728615682dd37c9a42d9548":"MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE","597015d3bcce3da693b02314afd607bec4f55291":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE","6444e5c8ae112a6a433909c5e770669cd16e2e5f":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","3aea027164cb9b732ba4a8c51cb93708891726ef":"NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","f799e26ceef2367cf836f24bcb47df4398b0df58":"NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE","e787b322bddbc6289bb31b7d7550b1bf6456a80b":"OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED","8d0a50b57c26bb498be592e871001ffed91541b4":"PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW","80b86ccc6e8520660fa591caa565826f0ed1b12c":"PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED","d74c3c18a1c1dd18b035149105a306f837c8823e":"PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT","e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd":"PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE","beff6ecd9677dea0a7c648c5042165b48bb66f09":"PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED","56a8d2ac24ca7bba78fd88ad57f43fc13c784497":"SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","38f6e1e17756ede38b1364c7114a738ca717dcbb":"SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","fc89b35755483af30b66cd72cefa34a43a3e8312":"SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE","230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64":"TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE","e1697cacebad05218798bf3e8a0f724517f0e8c3":"TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED","b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6":"TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE"}</script>
+<script>var search_data = {"0262260daf0c8f7b28feff2ef23b05e7abf9d1e0":"A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON","ea2894c41cb8e80a4433a3e6c5772dadce9be90d":"A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT","ede3c47b7757245be42ec33fd5ca63df4b490066":"A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT","fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a":"ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE","9a6e4ec46997fb92b324974afa08a3d007e2537f":"ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED","a1f7cf79dd555b04fa8d603247a040e644996293":"APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE","9747e3d6a3eab39bc7c17f11a80573c62d44c7e5":"BLANK NEW TAB PAGE CHROME_URL_OVERRIDES","903e7277139e1e6caec123d3319cab295d8d1b3a":"CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED","0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5":"CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL","ac31228200b41a87982e386cc90d3a6eee4ad885":"CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE","7d5d6cf195bc25480256618e360aa38c6e6fba82":"CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED","5d81304a17cf7ac2887484f730fbd2b01e51e166":"CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE","4daa6becd0899a54776d9cf7f09613ed1a9f4d77":"COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL","6871d09f4a96bf9d4b6cc724d00e909cee0f3902":"CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","028eb5364924344029bcbe1d527f132fc72b34e5":"EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE","0bf0930a32829dfb77170535ecb27adc2de3998a":"ENABLE/DISABLE REFERRERS API EXAMPLE EXTENSION SAMPLE EXTENSION WHICH DEMONSTRATES HOW TO ACCESS A PREFERENCE. BROWSER_ACTION CONTENTSETTINGS EXPERIMENTAL POPUP CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS","763a08e9b06595d785568a8d392b95a2f3700258":"EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP","e3df888a89e35bdeb9c8bc8d03be5e1851b97c68":"EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE","8b0dd31216235941bdd8eb33fda915ef5cf79a82":"GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","4e35caa9742fb82dbd628892d23a781614f6eff6":"GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca":"GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE","1682e05ea9a1bde985123b04f6f8ac50a8a64033":"GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","14b9651fda4e57b2a5914ba73a779812201b750a":"HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP","2020d72f2577f53caf8e94e3dbac0fb849ceaa4d":"IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE","0ea1588bd07b20338fc21f725de1542a5fdf9726":"IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES","646325c25f572a1d15edc73d057f821d847a4fbe":"IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE","65b2fe595b7ac38dddd89cca50f5efd0017b0bd4":"KEYBOARD PIN CREATES A KEYBOARD SHORTCUT (C + SHIFT + P) TO TOGGLE THE PINNED STATE OF THE CURRENTLY SELECTED TAB BACKGROUND_PAGE TABS CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE","ec97ec20ca2f095d081e39f1565fc12af09ef067":"MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST","b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d":"MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT","51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e":"MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST","4f6785ec4f937add6728615682dd37c9a42d9548":"MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE","597015d3bcce3da693b02314afd607bec4f55291":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE","6444e5c8ae112a6a433909c5e770669cd16e2e5f":"NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","3aea027164cb9b732ba4a8c51cb93708891726ef":"NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE","f799e26ceef2367cf836f24bcb47df4398b0df58":"NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE","e787b322bddbc6289bb31b7d7550b1bf6456a80b":"OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED","8d0a50b57c26bb498be592e871001ffed91541b4":"PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW","80b86ccc6e8520660fa591caa565826f0ed1b12c":"PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED","d74c3c18a1c1dd18b035149105a306f837c8823e":"PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT","e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd":"PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE","beff6ecd9677dea0a7c648c5042165b48bb66f09":"PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED","3e8e226d87e431296bb110b4f6eb7eec2ca7a826":"PROXY SETTINGS SET CHROME-SPECIFIC PROXIES; A DEMONSTRATION OF CHROMES PROXY API BACKGROUND_PAGE BROWSER_ACTION EXPERIMENTAL POPUP PROXY CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXPERIMENTAL.PROXY.ONPROXYERROR CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE","56a8d2ac24ca7bba78fd88ad57f43fc13c784497":"SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE","38f6e1e17756ede38b1364c7114a738ca717dcbb":"SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST","fc89b35755483af30b66cd72cefa34a43a3e8312":"SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE","230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64":"TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE","e1697cacebad05218798bf3e8a0f724517f0e8c3":"TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED","b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6":"TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE","a3c674f7eb93621c590562ad3fa04de4f03f53a0":"WEBNAVIGATION TECH DEMO DEMONSTRATION OF THE WEBNAVIGATION EXTENSION API. BACKGROUND_PAGE BROWSER_ACTION EXPERIMENTAL EXTENSION POPUP WEBNAVIGATION CHROME.EXPERIMENTAL.WEBNAVIGATION.ONBEFORENAVIGATE CHROME.EXPERIMENTAL.WEBNAVIGATION.ONBEFORERETARGET CHROME.EXPERIMENTAL.WEBNAVIGATION.ONCOMMITTED CHROME.EXPERIMENTAL.WEBNAVIGATION.ONCOMPLETED CHROME.EXPERIMENTAL.WEBNAVIGATION.ONERROROCCURRED CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE","0fa4abe6545f0316fea7cfa07c53aa48c4f3d018":"`EXTENSION.ISALLOWED???ACCESS` EXAMPLE DEMONSTRATES THE `EXTENSION.ISALLOWED???ACCESS` APIS BROWSER_ACTION CHROME.EXTENSION.ISALLOWEDFILESCHEMEACCESS CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS"}</script>
<script src="js/sample_search.js"></script>
@@ -1091,6 +1091,48 @@
<a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/email_this_page/">Browse source</a>
- <a href="examples/extensions/email_this_page.zip">Download source</a>
</div>
+</div><div class="sample" id="0bf0930a32829dfb77170535ecb27adc2de3998a">
+ <img class="icon" style="display: none; ">
+ <img class="icon" src="images/sample-default-icon.png">
+ <h2 class="name">
+ <a href="#0bf0930a32829dfb77170535ecb27adc2de3998a">Enable/disable referrers API example extension</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>browser_action</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>contentSettings</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>experimental</strong><span style="display: none; ">, </span>
+ <span> and</span>
+ </span><span>
+ <strong>popup</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p>Sample extension which demonstrates how to access a preference.</p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="extension.html#method-isAllowedIncognitoAccess">chrome.extension.isAllowedIncognitoAccess</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/popup.html?content-type=text/plain">popup.html</a></code>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/preferences/enableReferrer/">Browse source</a>
+ - <a href="examples/api/preferences/enableReferrer.zip">Download source</a>
+ </div>
</div><div class="sample" id="763a08e9b06595d785568a8d392b95a2f3700258">
<img class="icon" src="examples/tutorials/analytics/analytics-extension-icon-128.png">
<img class="icon" src="images/sample-default-icon.png" style="display: none; ">
@@ -1717,6 +1759,52 @@
<a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/imageinfo/">Browse source</a>
- <a href="examples/extensions/imageinfo.zip">Download source</a>
</div>
+</div><div class="sample" id="65b2fe595b7ac38dddd89cca50f5efd0017b0bd4">
+ <img class="icon" style="display: none; ">
+ <img class="icon" src="images/sample-default-icon.png">
+ <h2 class="name">
+ <a href="#65b2fe595b7ac38dddd89cca50f5efd0017b0bd4">Keyboard Pin</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>background_page</strong><span style="display: none; ">, </span>
+ <span> and</span>
+ </span><span>
+ <strong>tabs</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p>Creates a keyboard shortcut (C + Shift + P) to toggle the pinned state of the currently selected tab</p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="extension.html#event-onRequest">chrome.extension.onRequest</a></code>
+ </li><li>
+ <code><a href="extension.html#method-sendRequest">chrome.extension.sendRequest</a></code>
+ </li><li>
+ <code><a href="tabs.html#method-get">chrome.tabs.get</a></code>
+ </li><li>
+ <code><a href="tabs.html#method-getSelected">chrome.tabs.getSelected</a></code>
+ </li><li>
+ <code><a href="tabs.html#method-update">chrome.tabs.update</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/tabs/pin/background.html?content-type=text/plain">background.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/tabs/pin/inject.js?content-type=text/plain">inject.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/tabs/pin/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/tabs/pin/">Browse source</a>
+ - <a href="examples/api/tabs/pin.zip">Download source</a>
+ </div>
</div><div class="sample" id="ec97ec20ca2f095d081e39f1565fc12af09ef067">
<img class="icon" src="examples/extensions/mappy/icon.png">
<img class="icon" src="images/sample-default-icon.png" style="display: none; ">
@@ -2441,6 +2529,81 @@
<a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/processes/process_monitor/">Browse source</a>
- <a href="examples/api/processes/process_monitor.zip">Download source</a>
</div>
+</div><div class="sample" id="3e8e226d87e431296bb110b4f6eb7eec2ca7a826">
+ <img class="icon" src="examples/extensions/proxy_configuration/icon128.png">
+ <img class="icon" src="images/sample-default-icon.png" style="display: none; ">
+ <h2 class="name">
+ <a href="#3e8e226d87e431296bb110b4f6eb7eec2ca7a826">Proxy Settings</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>background_page</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>browser_action</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>experimental</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>popup</strong><span style="display: none; ">, </span>
+ <span> and</span>
+ </span><span>
+ <strong>proxy</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p>Set Chrome-specific proxies; a demonstration of Chrome's Proxy API</p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="browserAction.html#method-setBadgeBackgroundColor">chrome.browserAction.setBadgeBackgroundColor</a></code>
+ </li><li>
+ <code><a href="browserAction.html#method-setBadgeText">chrome.browserAction.setBadgeText</a></code>
+ </li><li>
+ <code><a href="browserAction.html#method-setTitle">chrome.browserAction.setTitle</a></code>
+ </li><li>
+ <code><a href="experimental.proxy.html#event-onProxyError">chrome.experimental.proxy.onProxyError</a></code>
+ </li><li>
+ <code><a href="extension.html#method-isAllowedIncognitoAccess">chrome.extension.isAllowedIncognitoAccess</a></code>
+ </li><li>
+ <code><a href="extension.html#event-onRequest">chrome.extension.onRequest</a></code>
+ </li><li>
+ <code><a href="extension.html#method-sendRequest">chrome.extension.sendRequest</a></code>
+ </li><li>
+ <code><a href="i18n.html#method-getMessage">chrome.i18n.getMessage</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/_locales/en/messages.json?content-type=text/plain">_locales/en/messages.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/background.html?content-type=text/plain">background.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/popup.html?content-type=text/plain">popup.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_error_handler.js?content-type=text/plain">proxy_error_handler.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/proxy_form_controller.js?content-type=text/plain">proxy_form_controller.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/jsunittest.js?content-type=text/plain">test/jsunittest.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.html?content-type=text/plain">test/proxy_form_controller_test.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/proxy_form_controller_test.js?content-type=text/plain">test/proxy_form_controller_test.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/test/unittest.css?content-type=text/plain">test/unittest.css</a></code>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/extensions/proxy_configuration/">Browse source</a>
+ - <a href="examples/extensions/proxy_configuration.zip">Download source</a>
+ </div>
</div><div class="sample" id="56a8d2ac24ca7bba78fd88ad57f43fc13c784497">
<img class="icon" src="examples/extensions/oauth_contacts/img/icon-128.png">
<img class="icon" src="images/sample-default-icon.png" style="display: none; ">
@@ -2795,6 +2958,111 @@
<a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/history/showHistory/">Browse source</a>
- <a href="examples/api/history/showHistory.zip">Download source</a>
</div>
+</div><div class="sample" id="a3c674f7eb93621c590562ad3fa04de4f03f53a0">
+ <img class="icon" style="display: none; ">
+ <img class="icon" src="images/sample-default-icon.png">
+ <h2 class="name">
+ <a href="#a3c674f7eb93621c590562ad3fa04de4f03f53a0">WebNavigation Tech Demo</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>background_page</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>browser_action</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>experimental</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>extension</strong><span>, </span>
+ <span style="display: none; "> and</span>
+ </span><span>
+ <strong>popup</strong><span style="display: none; ">, </span>
+ <span> and</span>
+ </span><span>
+ <strong>webNavigation</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p>Demonstration of the WebNavigation extension API.</p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="experimental.webNavigation.html#event-onBeforeNavigate">chrome.experimental.webNavigation.onBeforeNavigate</a></code>
+ </li><li>
+ <code><a href="experimental.webNavigation.html#event-onBeforeRetarget">chrome.experimental.webNavigation.onBeforeRetarget</a></code>
+ </li><li>
+ <code><a href="experimental.webNavigation.html#event-onCommitted">chrome.experimental.webNavigation.onCommitted</a></code>
+ </li><li>
+ <code><a href="experimental.webNavigation.html#event-onCompleted">chrome.experimental.webNavigation.onCompleted</a></code>
+ </li><li>
+ <code><a href="experimental.webNavigation.html#event-onErrorOccurred">chrome.experimental.webNavigation.onErrorOccurred</a></code>
+ </li><li>
+ <code><a href="extension.html#event-onRequest">chrome.extension.onRequest</a></code>
+ </li><li>
+ <code><a href="extension.html#method-sendRequest">chrome.extension.sendRequest</a></code>
+ </li><li>
+ <code><a href="i18n.html#method-getMessage">chrome.i18n.getMessage</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/_locales/en/messages.json?content-type=text/plain">_locales/en/messages.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/background.html?content-type=text/plain">background.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/navigation_collector.js?content-type=text/plain">navigation_collector.js</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/popup.html?content-type=text/plain">popup.html</a></code>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/webNavigation/basic/">Browse source</a>
+ - <a href="examples/api/webNavigation/basic.zip">Download source</a>
+ </div>
+</div><div class="sample" id="0fa4abe6545f0316fea7cfa07c53aa48c4f3d018">
+ <img class="icon" src="examples/api/extension/isAllowedAccess/sample-128.png">
+ <img class="icon" src="images/sample-default-icon.png" style="display: none; ">
+ <h2 class="name">
+ <a href="#0fa4abe6545f0316fea7cfa07c53aa48c4f3d018">`extension.isAllowed???Access` Example</a>
+ </h2>
+ <p class="metadata features">Uses
+ <span>
+ <strong>browser_action</strong><span style="display: none; ">, </span>
+ <span style="display: none; "> and</span>
+ </span>
+ </p>
+ <p>Demonstrates the `extension.isAllowed???Access` APIs</p>
+ <div class="apicalls"><strong>Calls:</strong>
+ <ul>
+ <li>
+ <code><a href="extension.html#method-isAllowedFileSchemeAccess">chrome.extension.isAllowedFileSchemeAccess</a></code>
+ </li><li>
+ <code><a href="extension.html#method-isAllowedIncognitoAccess">chrome.extension.isAllowedIncognitoAccess</a></code>
+ </li>
+ </ul>
+ </div>
+ <div class="sourcefiles"><strong>Source files:</strong>
+ <ul>
+ <li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/manifest.json?content-type=text/plain">manifest.json</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/popup.html?content-type=text/plain">popup.html</a></code>
+ </li><li>
+ <code><a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/sample.css?content-type=text/plain">sample.css</a></code>
+ </li>
+ </ul>
+ </div>
+ <div>
+ <a target="_blank" href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/extension/isAllowedAccess/">Browse source</a>
+ - <a href="examples/api/extension/isAllowedAccess.zip">Download source</a>
+ </div>
</div>
<div id="noresults" style="display:none">
diff --git a/chrome/common/extensions/docs/samples.json b/chrome/common/extensions/docs/samples.json
index 9a62535..c3e1ff6 100644
--- a/chrome/common/extensions/docs/samples.json
+++ b/chrome/common/extensions/docs/samples.json
@@ -1,1582 +1,1743 @@
{
"api": {
- "chrome.bookmarks.create": "bookmarks.html#method-create",
- "chrome.bookmarks.export": "bookmarks.html#method-export",
- "chrome.bookmarks.get": "bookmarks.html#method-get",
- "chrome.bookmarks.getChildren": "bookmarks.html#method-getChildren",
- "chrome.bookmarks.getRecent": "bookmarks.html#method-getRecent",
- "chrome.bookmarks.getTree": "bookmarks.html#method-getTree",
- "chrome.bookmarks.import": "bookmarks.html#method-import",
- "chrome.bookmarks.move": "bookmarks.html#method-move",
- "chrome.bookmarks.onChanged": "bookmarks.html#event-onChanged",
- "chrome.bookmarks.onChildrenReordered": "bookmarks.html#event-onChildrenReordered",
- "chrome.bookmarks.onCreated": "bookmarks.html#event-onCreated",
- "chrome.bookmarks.onImportBegan": "bookmarks.html#event-onImportBegan",
- "chrome.bookmarks.onImportEnded": "bookmarks.html#event-onImportEnded",
- "chrome.bookmarks.onMoved": "bookmarks.html#event-onMoved",
- "chrome.bookmarks.onRemoved": "bookmarks.html#event-onRemoved",
- "chrome.bookmarks.remove": "bookmarks.html#method-remove",
- "chrome.bookmarks.removeTree": "bookmarks.html#method-removeTree",
- "chrome.bookmarks.search": "bookmarks.html#method-search",
- "chrome.bookmarks.update": "bookmarks.html#method-update",
- "chrome.browserAction.onClicked": "browserAction.html#event-onClicked",
- "chrome.browserAction.setBadgeBackgroundColor": "browserAction.html#method-setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText": "browserAction.html#method-setBadgeText",
- "chrome.browserAction.setIcon": "browserAction.html#method-setIcon",
- "chrome.browserAction.setPopup": "browserAction.html#method-setPopup",
- "chrome.browserAction.setTitle": "browserAction.html#method-setTitle",
- "chrome.contextMenus.create": "contextMenus.html#method-create",
- "chrome.contextMenus.remove": "contextMenus.html#method-remove",
- "chrome.contextMenus.removeAll": "contextMenus.html#method-removeAll",
- "chrome.contextMenus.update": "contextMenus.html#method-update",
- "chrome.cookies.get": "cookies.html#method-get",
- "chrome.cookies.getAll": "cookies.html#method-getAll",
- "chrome.cookies.getAllCookieStores": "cookies.html#method-getAllCookieStores",
- "chrome.cookies.onChanged": "cookies.html#event-onChanged",
- "chrome.cookies.remove": "cookies.html#method-remove",
- "chrome.cookies.set": "cookies.html#method-set",
- "chrome.experimental.clipboard.executeCopy": "experimental.clipboard.html#method-executeCopy",
- "chrome.experimental.clipboard.executeCut": "experimental.clipboard.html#method-executeCut",
- "chrome.experimental.clipboard.executePaste": "experimental.clipboard.html#method-executePaste",
- "chrome.experimental.infobars.show": "experimental.infobars.html#method-show",
- "chrome.experimental.processes.getProcessIdForTab": "experimental.processes.html#method-getProcessIdForTab",
- "chrome.experimental.processes.onUpdated": "experimental.processes.html#event-onUpdated",
- "chrome.experimental.proxy.onProxyError": "experimental.proxy.html#event-onProxyError",
- "chrome.experimental.sidebar.collapse": "experimental.sidebar.html#method-collapse",
- "chrome.experimental.sidebar.expand": "experimental.sidebar.html#method-expand",
- "chrome.experimental.sidebar.getState": "experimental.sidebar.html#method-getState",
- "chrome.experimental.sidebar.hide": "experimental.sidebar.html#method-hide",
- "chrome.experimental.sidebar.navigate": "experimental.sidebar.html#method-navigate",
- "chrome.experimental.sidebar.onStateChanged": "experimental.sidebar.html#event-onStateChanged",
- "chrome.experimental.sidebar.setBadgeText": "experimental.sidebar.html#method-setBadgeText",
- "chrome.experimental.sidebar.setIcon": "experimental.sidebar.html#method-setIcon",
- "chrome.experimental.sidebar.setTitle": "experimental.sidebar.html#method-setTitle",
- "chrome.experimental.sidebar.show": "experimental.sidebar.html#method-show",
- "chrome.experimental.tts.isSpeaking": "experimental.tts.html#method-isSpeaking",
- "chrome.experimental.tts.onSpeak": "experimental.tts.html#event-onSpeak",
- "chrome.experimental.tts.onStop": "experimental.tts.html#event-onStop",
- "chrome.experimental.tts.speak": "experimental.tts.html#method-speak",
- "chrome.experimental.tts.speakCompleted": "experimental.tts.html#method-speakCompleted",
- "chrome.experimental.tts.stop": "experimental.tts.html#method-stop",
- "chrome.experimental.webNavigation.onBeforeNavigate": "experimental.webNavigation.html#event-onBeforeNavigate",
- "chrome.experimental.webNavigation.onBeforeRetarget": "experimental.webNavigation.html#event-onBeforeRetarget",
- "chrome.experimental.webNavigation.onCommitted": "experimental.webNavigation.html#event-onCommitted",
- "chrome.experimental.webNavigation.onCompleted": "experimental.webNavigation.html#event-onCompleted",
- "chrome.experimental.webNavigation.onDOMContentLoaded": "experimental.webNavigation.html#event-onDOMContentLoaded",
- "chrome.experimental.webNavigation.onErrorOccurred": "experimental.webNavigation.html#event-onErrorOccurred",
- "chrome.experimental.webRequest.addEventListener": "experimental.webRequest.html#method-addEventListener",
- "chrome.experimental.webRequest.onBeforeRedirect": "experimental.webRequest.html#event-onBeforeRedirect",
- "chrome.experimental.webRequest.onBeforeRequest": "experimental.webRequest.html#event-onBeforeRequest",
- "chrome.experimental.webRequest.onCompleted": "experimental.webRequest.html#event-onCompleted",
- "chrome.experimental.webRequest.onErrorOccurred": "experimental.webRequest.html#event-onErrorOccurred",
- "chrome.experimental.webRequest.onHeadersReceived": "experimental.webRequest.html#event-onHeadersReceived",
- "chrome.experimental.webRequest.onRequestSent": "experimental.webRequest.html#event-onRequestSent",
- "chrome.extension.connect": "extension.html#method-connect",
- "chrome.extension.getBackgroundPage": "extension.html#method-getBackgroundPage",
- "chrome.extension.getExtensionTabs": "extension.html#method-getExtensionTabs",
- "chrome.extension.getToolstrips": "extension.html#method-getToolstrips",
- "chrome.extension.getURL": "extension.html#method-getURL",
- "chrome.extension.getViews": "extension.html#method-getViews",
- "chrome.extension.onConnect": "extension.html#event-onConnect",
- "chrome.extension.onConnectExternal": "extension.html#event-onConnectExternal",
- "chrome.extension.onRequest": "extension.html#event-onRequest",
- "chrome.extension.onRequestExternal": "extension.html#event-onRequestExternal",
- "chrome.extension.sendRequest": "extension.html#method-sendRequest",
- "chrome.extension.setUpdateUrlData": "extension.html#method-setUpdateUrlData",
- "chrome.history.addUrl": "history.html#method-addUrl",
- "chrome.history.deleteAll": "history.html#method-deleteAll",
- "chrome.history.deleteRange": "history.html#method-deleteRange",
- "chrome.history.deleteUrl": "history.html#method-deleteUrl",
- "chrome.history.getVisits": "history.html#method-getVisits",
- "chrome.history.onVisitRemoved": "history.html#event-onVisitRemoved",
- "chrome.history.onVisited": "history.html#event-onVisited",
- "chrome.history.search": "history.html#method-search",
- "chrome.i18n.getAcceptLanguages": "i18n.html#method-getAcceptLanguages",
- "chrome.i18n.getMessage": "i18n.html#method-getMessage",
- "chrome.idle.onStateChanged": "idle.html#event-onStateChanged",
- "chrome.idle.queryState": "idle.html#method-queryState",
- "chrome.management.get": "management.html#method-get",
- "chrome.management.getAll": "management.html#method-getAll",
- "chrome.management.launchApp": "management.html#method-launchApp",
- "chrome.management.onDisabled": "management.html#event-onDisabled",
- "chrome.management.onEnabled": "management.html#event-onEnabled",
- "chrome.management.onInstalled": "management.html#event-onInstalled",
- "chrome.management.onUninstalled": "management.html#event-onUninstalled",
- "chrome.management.setEnabled": "management.html#method-setEnabled",
- "chrome.management.uninstall": "management.html#method-uninstall",
- "chrome.omnibox.onInputCancelled": "omnibox.html#event-onInputCancelled",
- "chrome.omnibox.onInputChanged": "omnibox.html#event-onInputChanged",
- "chrome.omnibox.onInputEntered": "omnibox.html#event-onInputEntered",
- "chrome.omnibox.onInputStarted": "omnibox.html#event-onInputStarted",
- "chrome.omnibox.sendSuggestions": "omnibox.html#method-sendSuggestions",
- "chrome.omnibox.setDefaultSuggestion": "omnibox.html#method-setDefaultSuggestion",
- "chrome.pageAction.hide": "pageAction.html#method-hide",
- "chrome.pageAction.onClicked": "pageAction.html#event-onClicked",
- "chrome.pageAction.setIcon": "pageAction.html#method-setIcon",
- "chrome.pageAction.setPopup": "pageAction.html#method-setPopup",
- "chrome.pageAction.setTitle": "pageAction.html#method-setTitle",
- "chrome.pageAction.show": "pageAction.html#method-show",
- "chrome.tabs.captureVisibleTab": "tabs.html#method-captureVisibleTab",
- "chrome.tabs.connect": "tabs.html#method-connect",
- "chrome.tabs.create": "tabs.html#method-create",
- "chrome.tabs.detectLanguage": "tabs.html#method-detectLanguage",
- "chrome.tabs.executeScript": "tabs.html#method-executeScript",
- "chrome.tabs.get": "tabs.html#method-get",
- "chrome.tabs.getAllInWindow": "tabs.html#method-getAllInWindow",
- "chrome.tabs.getCurrent": "tabs.html#method-getCurrent",
- "chrome.tabs.getSelected": "tabs.html#method-getSelected",
- "chrome.tabs.insertCSS": "tabs.html#method-insertCSS",
- "chrome.tabs.move": "tabs.html#method-move",
- "chrome.tabs.onAttached": "tabs.html#event-onAttached",
- "chrome.tabs.onCreated": "tabs.html#event-onCreated",
- "chrome.tabs.onDetached": "tabs.html#event-onDetached",
- "chrome.tabs.onMoved": "tabs.html#event-onMoved",
- "chrome.tabs.onRemoved": "tabs.html#event-onRemoved",
- "chrome.tabs.onSelectionChanged": "tabs.html#event-onSelectionChanged",
- "chrome.tabs.onUpdated": "tabs.html#event-onUpdated",
- "chrome.tabs.remove": "tabs.html#method-remove",
- "chrome.tabs.sendRequest": "tabs.html#method-sendRequest",
- "chrome.tabs.update": "tabs.html#method-update",
- "chrome.windows.create": "windows.html#method-create",
- "chrome.windows.get": "windows.html#method-get",
- "chrome.windows.getAll": "windows.html#method-getAll",
- "chrome.windows.getCurrent": "windows.html#method-getCurrent",
- "chrome.windows.getLastFocused": "windows.html#method-getLastFocused",
- "chrome.windows.onCreated": "windows.html#event-onCreated",
- "chrome.windows.onFocusChanged": "windows.html#event-onFocusChanged",
- "chrome.windows.onRemoved": "windows.html#event-onRemoved",
- "chrome.windows.remove": "windows.html#method-remove",
+ "chrome.bookmarks.create": "bookmarks.html#method-create",
+ "chrome.bookmarks.export": "bookmarks.html#method-export",
+ "chrome.bookmarks.get": "bookmarks.html#method-get",
+ "chrome.bookmarks.getChildren": "bookmarks.html#method-getChildren",
+ "chrome.bookmarks.getRecent": "bookmarks.html#method-getRecent",
+ "chrome.bookmarks.getTree": "bookmarks.html#method-getTree",
+ "chrome.bookmarks.import": "bookmarks.html#method-import",
+ "chrome.bookmarks.move": "bookmarks.html#method-move",
+ "chrome.bookmarks.onChanged": "bookmarks.html#event-onChanged",
+ "chrome.bookmarks.onChildrenReordered": "bookmarks.html#event-onChildrenReordered",
+ "chrome.bookmarks.onCreated": "bookmarks.html#event-onCreated",
+ "chrome.bookmarks.onImportBegan": "bookmarks.html#event-onImportBegan",
+ "chrome.bookmarks.onImportEnded": "bookmarks.html#event-onImportEnded",
+ "chrome.bookmarks.onMoved": "bookmarks.html#event-onMoved",
+ "chrome.bookmarks.onRemoved": "bookmarks.html#event-onRemoved",
+ "chrome.bookmarks.remove": "bookmarks.html#method-remove",
+ "chrome.bookmarks.removeTree": "bookmarks.html#method-removeTree",
+ "chrome.bookmarks.search": "bookmarks.html#method-search",
+ "chrome.bookmarks.update": "bookmarks.html#method-update",
+ "chrome.browserAction.onClicked": "browserAction.html#event-onClicked",
+ "chrome.browserAction.setBadgeBackgroundColor": "browserAction.html#method-setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText": "browserAction.html#method-setBadgeText",
+ "chrome.browserAction.setIcon": "browserAction.html#method-setIcon",
+ "chrome.browserAction.setPopup": "browserAction.html#method-setPopup",
+ "chrome.browserAction.setTitle": "browserAction.html#method-setTitle",
+ "chrome.contextMenus.create": "contextMenus.html#method-create",
+ "chrome.contextMenus.remove": "contextMenus.html#method-remove",
+ "chrome.contextMenus.removeAll": "contextMenus.html#method-removeAll",
+ "chrome.contextMenus.update": "contextMenus.html#method-update",
+ "chrome.cookies.get": "cookies.html#method-get",
+ "chrome.cookies.getAll": "cookies.html#method-getAll",
+ "chrome.cookies.getAllCookieStores": "cookies.html#method-getAllCookieStores",
+ "chrome.cookies.onChanged": "cookies.html#event-onChanged",
+ "chrome.cookies.remove": "cookies.html#method-remove",
+ "chrome.cookies.set": "cookies.html#method-set",
+ "chrome.experimental.clipboard.executeCopy": "experimental.clipboard.html#method-executeCopy",
+ "chrome.experimental.clipboard.executeCut": "experimental.clipboard.html#method-executeCut",
+ "chrome.experimental.clipboard.executePaste": "experimental.clipboard.html#method-executePaste",
+ "chrome.experimental.debugger.attach": "experimental.debugger.html#method-attach",
+ "chrome.experimental.debugger.detach": "experimental.debugger.html#method-detach",
+ "chrome.experimental.debugger.onDetach": "experimental.debugger.html#event-onDetach",
+ "chrome.experimental.debugger.onEvent": "experimental.debugger.html#event-onEvent",
+ "chrome.experimental.debugger.sendRequest": "experimental.debugger.html#method-sendRequest",
+ "chrome.experimental.infobars.show": "experimental.infobars.html#method-show",
+ "chrome.experimental.processes.getProcessIdForTab": "experimental.processes.html#method-getProcessIdForTab",
+ "chrome.experimental.processes.onUpdated": "experimental.processes.html#event-onUpdated",
+ "chrome.experimental.proxy.onProxyError": "experimental.proxy.html#event-onProxyError",
+ "chrome.experimental.sidebar.collapse": "experimental.sidebar.html#method-collapse",
+ "chrome.experimental.sidebar.expand": "experimental.sidebar.html#method-expand",
+ "chrome.experimental.sidebar.getState": "experimental.sidebar.html#method-getState",
+ "chrome.experimental.sidebar.hide": "experimental.sidebar.html#method-hide",
+ "chrome.experimental.sidebar.navigate": "experimental.sidebar.html#method-navigate",
+ "chrome.experimental.sidebar.onStateChanged": "experimental.sidebar.html#event-onStateChanged",
+ "chrome.experimental.sidebar.setBadgeText": "experimental.sidebar.html#method-setBadgeText",
+ "chrome.experimental.sidebar.setIcon": "experimental.sidebar.html#method-setIcon",
+ "chrome.experimental.sidebar.setTitle": "experimental.sidebar.html#method-setTitle",
+ "chrome.experimental.sidebar.show": "experimental.sidebar.html#method-show",
+ "chrome.experimental.tts.isSpeaking": "experimental.tts.html#method-isSpeaking",
+ "chrome.experimental.tts.onSpeak": "experimental.tts.html#event-onSpeak",
+ "chrome.experimental.tts.onStop": "experimental.tts.html#event-onStop",
+ "chrome.experimental.tts.speak": "experimental.tts.html#method-speak",
+ "chrome.experimental.tts.speakCompleted": "experimental.tts.html#method-speakCompleted",
+ "chrome.experimental.tts.stop": "experimental.tts.html#method-stop",
+ "chrome.experimental.webNavigation.onBeforeNavigate": "experimental.webNavigation.html#event-onBeforeNavigate",
+ "chrome.experimental.webNavigation.onBeforeRetarget": "experimental.webNavigation.html#event-onBeforeRetarget",
+ "chrome.experimental.webNavigation.onCommitted": "experimental.webNavigation.html#event-onCommitted",
+ "chrome.experimental.webNavigation.onCompleted": "experimental.webNavigation.html#event-onCompleted",
+ "chrome.experimental.webNavigation.onDOMContentLoaded": "experimental.webNavigation.html#event-onDOMContentLoaded",
+ "chrome.experimental.webNavigation.onErrorOccurred": "experimental.webNavigation.html#event-onErrorOccurred",
+ "chrome.experimental.webRequest.addEventListener": "experimental.webRequest.html#method-addEventListener",
+ "chrome.experimental.webRequest.eventHandled": "experimental.webRequest.html#method-eventHandled",
+ "chrome.experimental.webRequest.onBeforeRedirect": "experimental.webRequest.html#event-onBeforeRedirect",
+ "chrome.experimental.webRequest.onBeforeRequest": "experimental.webRequest.html#event-onBeforeRequest",
+ "chrome.experimental.webRequest.onBeforeSendHeaders": "experimental.webRequest.html#event-onBeforeSendHeaders",
+ "chrome.experimental.webRequest.onCompleted": "experimental.webRequest.html#event-onCompleted",
+ "chrome.experimental.webRequest.onErrorOccurred": "experimental.webRequest.html#event-onErrorOccurred",
+ "chrome.experimental.webRequest.onHeadersReceived": "experimental.webRequest.html#event-onHeadersReceived",
+ "chrome.experimental.webRequest.onRequestSent": "experimental.webRequest.html#event-onRequestSent",
+ "chrome.extension.connect": "extension.html#method-connect",
+ "chrome.extension.getBackgroundPage": "extension.html#method-getBackgroundPage",
+ "chrome.extension.getExtensionTabs": "extension.html#method-getExtensionTabs",
+ "chrome.extension.getToolstrips": "extension.html#method-getToolstrips",
+ "chrome.extension.getURL": "extension.html#method-getURL",
+ "chrome.extension.getViews": "extension.html#method-getViews",
+ "chrome.extension.isAllowedFileSchemeAccess": "extension.html#method-isAllowedFileSchemeAccess",
+ "chrome.extension.isAllowedIncognitoAccess": "extension.html#method-isAllowedIncognitoAccess",
+ "chrome.extension.onConnect": "extension.html#event-onConnect",
+ "chrome.extension.onConnectExternal": "extension.html#event-onConnectExternal",
+ "chrome.extension.onRequest": "extension.html#event-onRequest",
+ "chrome.extension.onRequestExternal": "extension.html#event-onRequestExternal",
+ "chrome.extension.sendRequest": "extension.html#method-sendRequest",
+ "chrome.extension.setUpdateUrlData": "extension.html#method-setUpdateUrlData",
+ "chrome.history.addUrl": "history.html#method-addUrl",
+ "chrome.history.deleteAll": "history.html#method-deleteAll",
+ "chrome.history.deleteRange": "history.html#method-deleteRange",
+ "chrome.history.deleteUrl": "history.html#method-deleteUrl",
+ "chrome.history.getVisits": "history.html#method-getVisits",
+ "chrome.history.onVisitRemoved": "history.html#event-onVisitRemoved",
+ "chrome.history.onVisited": "history.html#event-onVisited",
+ "chrome.history.search": "history.html#method-search",
+ "chrome.i18n.getAcceptLanguages": "i18n.html#method-getAcceptLanguages",
+ "chrome.i18n.getMessage": "i18n.html#method-getMessage",
+ "chrome.idle.onStateChanged": "idle.html#event-onStateChanged",
+ "chrome.idle.queryState": "idle.html#method-queryState",
+ "chrome.management.get": "management.html#method-get",
+ "chrome.management.getAll": "management.html#method-getAll",
+ "chrome.management.launchApp": "management.html#method-launchApp",
+ "chrome.management.onDisabled": "management.html#event-onDisabled",
+ "chrome.management.onEnabled": "management.html#event-onEnabled",
+ "chrome.management.onInstalled": "management.html#event-onInstalled",
+ "chrome.management.onUninstalled": "management.html#event-onUninstalled",
+ "chrome.management.setEnabled": "management.html#method-setEnabled",
+ "chrome.management.uninstall": "management.html#method-uninstall",
+ "chrome.omnibox.onInputCancelled": "omnibox.html#event-onInputCancelled",
+ "chrome.omnibox.onInputChanged": "omnibox.html#event-onInputChanged",
+ "chrome.omnibox.onInputEntered": "omnibox.html#event-onInputEntered",
+ "chrome.omnibox.onInputStarted": "omnibox.html#event-onInputStarted",
+ "chrome.omnibox.sendSuggestions": "omnibox.html#method-sendSuggestions",
+ "chrome.omnibox.setDefaultSuggestion": "omnibox.html#method-setDefaultSuggestion",
+ "chrome.pageAction.hide": "pageAction.html#method-hide",
+ "chrome.pageAction.onClicked": "pageAction.html#event-onClicked",
+ "chrome.pageAction.setIcon": "pageAction.html#method-setIcon",
+ "chrome.pageAction.setPopup": "pageAction.html#method-setPopup",
+ "chrome.pageAction.setTitle": "pageAction.html#method-setTitle",
+ "chrome.pageAction.show": "pageAction.html#method-show",
+ "chrome.tabs.captureVisibleTab": "tabs.html#method-captureVisibleTab",
+ "chrome.tabs.connect": "tabs.html#method-connect",
+ "chrome.tabs.create": "tabs.html#method-create",
+ "chrome.tabs.detectLanguage": "tabs.html#method-detectLanguage",
+ "chrome.tabs.executeScript": "tabs.html#method-executeScript",
+ "chrome.tabs.get": "tabs.html#method-get",
+ "chrome.tabs.getAllInWindow": "tabs.html#method-getAllInWindow",
+ "chrome.tabs.getCurrent": "tabs.html#method-getCurrent",
+ "chrome.tabs.getSelected": "tabs.html#method-getSelected",
+ "chrome.tabs.insertCSS": "tabs.html#method-insertCSS",
+ "chrome.tabs.move": "tabs.html#method-move",
+ "chrome.tabs.onAttached": "tabs.html#event-onAttached",
+ "chrome.tabs.onCreated": "tabs.html#event-onCreated",
+ "chrome.tabs.onDetached": "tabs.html#event-onDetached",
+ "chrome.tabs.onMoved": "tabs.html#event-onMoved",
+ "chrome.tabs.onRemoved": "tabs.html#event-onRemoved",
+ "chrome.tabs.onSelectionChanged": "tabs.html#event-onSelectionChanged",
+ "chrome.tabs.onUpdated": "tabs.html#event-onUpdated",
+ "chrome.tabs.remove": "tabs.html#method-remove",
+ "chrome.tabs.sendRequest": "tabs.html#method-sendRequest",
+ "chrome.tabs.update": "tabs.html#method-update",
+ "chrome.windows.create": "windows.html#method-create",
+ "chrome.windows.get": "windows.html#method-get",
+ "chrome.windows.getAll": "windows.html#method-getAll",
+ "chrome.windows.getCurrent": "windows.html#method-getCurrent",
+ "chrome.windows.getLastFocused": "windows.html#method-getLastFocused",
+ "chrome.windows.onCreated": "windows.html#event-onCreated",
+ "chrome.windows.onFocusChanged": "windows.html#event-onFocusChanged",
+ "chrome.windows.onRemoved": "windows.html#event-onRemoved",
+ "chrome.windows.remove": "windows.html#method-remove",
"chrome.windows.update": "windows.html#method-update"
- },
+ },
"samples": [
{
"api_calls": [
- "chrome.browserAction.onClicked",
+ "chrome.browserAction.onClicked",
"chrome.browserAction.setIcon"
- ],
- "description": "",
+ ],
+ "description": "",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "0262260daf0c8f7b28feff2ef23b05e7abf9d1e0",
- "name": "A browser action which changes its icon when clicked.",
- "path": "examples/api/browserAction/set_icon_path/",
+ ],
+ "icon": null,
+ "id": "0262260daf0c8f7b28feff2ef23b05e7abf9d1e0",
+ "name": "A browser action which changes its icon when clicked.",
+ "path": "examples/api/browserAction/set_icon_path/",
"protocols": [
"http://"
- ],
- "search_string": "A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON",
+ ],
+ "search_string": "A BROWSER ACTION WHICH CHANGES ITS ICON WHEN CLICKED. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "c5752555642e89340c57657b48440b0dcd74ee99",
+ ],
+ "source_hash": "c5752555642e89340c57657b48440b0dcd74ee99",
"zip_path": "examples/api/browserAction/set_icon_path.zip"
- },
+ },
{
"api_calls": [
"chrome.tabs.executeScript"
- ],
- "description": "",
+ ],
+ "description": "",
"features": [
- "browser_action",
- "popup",
+ "browser_action",
+ "popup",
"tabs"
- ],
- "icon": null,
- "id": "ea2894c41cb8e80a4433a3e6c5772dadce9be90d",
- "name": "A browser action with a popup that changes the page color.",
- "path": "examples/api/browserAction/set_page_color/",
+ ],
+ "icon": null,
+ "id": "ea2894c41cb8e80a4433a3e6c5772dadce9be90d",
+ "name": "A browser action with a popup that changes the page color.",
+ "path": "examples/api/browserAction/set_page_color/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT",
+ ],
+ "search_string": "A BROWSER ACTION WITH A POPUP THAT CHANGES THE PAGE COLOR. BROWSER_ACTION POPUP TABS CHROME.TABS.EXECUTESCRIPT",
"source_files": [
- "manifest.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "c8d14b6893e75a62f3bd150d5d2cc5bb785bc411",
+ ],
+ "source_hash": "c8d14b6893e75a62f3bd150d5d2cc5bb785bc411",
"zip_path": "examples/api/browserAction/set_page_color.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.browserAction.setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.onClicked",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
"chrome.tabs.executeScript"
- ],
- "description": "",
+ ],
+ "description": "",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "ede3c47b7757245be42ec33fd5ca63df4b490066",
- "name": "A browser action with no icon that makes the page red",
- "path": "examples/api/browserAction/make_page_red/",
+ ],
+ "icon": null,
+ "id": "ede3c47b7757245be42ec33fd5ca63df4b490066",
+ "name": "A browser action with no icon that makes the page red",
+ "path": "examples/api/browserAction/make_page_red/",
"protocols": [
"http://"
- ],
- "search_string": "A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT",
+ ],
+ "search_string": "A BROWSER ACTION WITH NO ICON THAT MAKES THE PAGE RED BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.EXECUTESCRIPT",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "dfbb05ead54a0228a6d2f591ce1038d5c625249a",
+ ],
+ "source_hash": "dfbb05ead54a0228a6d2f591ce1038d5c625249a",
"zip_path": "examples/api/browserAction/make_page_red.zip"
- },
+ },
{
"api_calls": [
- "chrome.i18n.getAcceptLanguages",
+ "chrome.i18n.getAcceptLanguages",
"chrome.i18n.getMessage"
- ],
- "description": "Returns accept languages of the browser",
+ ],
+ "description": "Returns accept languages of the browser",
"features": [
- "browser_action",
+ "browser_action",
"popup"
- ],
- "icon": null,
- "id": "fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a",
- "name": "AcceptLanguage",
- "path": "examples/api/i18n/getMessage/",
- "protocols": [],
- "search_string": "ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE",
+ ],
+ "icon": null,
+ "id": "fbf0aa1a09a15ff8cc4fc7de4fd176d6c663d07a",
+ "name": "AcceptLanguage",
+ "path": "examples/api/i18n/getMessage/",
+ "protocols": [],
+ "search_string": "ACCEPTLANGUAGE RETURNS ACCEPT LANGUAGES OF THE BROWSER BROWSER_ACTION POPUP CHROME.I18N.GETACCEPTLANGUAGES CHROME.I18N.GETMESSAGE",
"source_files": [
- "_locales/en_US/messages.json",
- "_locales/es/messages.json",
- "_locales/sr/messages.json",
- "manifest.json",
+ "_locales/en_US/messages.json",
+ "_locales/es/messages.json",
+ "_locales/sr/messages.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "67f203e2773eebf401d0aa0a9709d961e506d875",
+ ],
+ "source_hash": "67f203e2773eebf401d0aa0a9709d961e506d875",
"zip_path": "examples/api/i18n/getMessage.zip"
- },
+ },
{
"api_calls": [
- "chrome.pageAction.hide",
- "chrome.pageAction.onClicked",
- "chrome.pageAction.setIcon",
- "chrome.pageAction.setTitle",
- "chrome.pageAction.show",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
+ "chrome.pageAction.hide",
+ "chrome.pageAction.onClicked",
+ "chrome.pageAction.setIcon",
+ "chrome.pageAction.setTitle",
+ "chrome.pageAction.show",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
"chrome.tabs.onSelectionChanged"
- ],
- "description": "This extension adds an animated browser action to the toolbar.",
+ ],
+ "description": "This extension adds an animated browser action to the toolbar.",
"features": [
- "background_page",
- "page_action",
+ "background_page",
+ "page_action",
"tabs"
- ],
- "icon": null,
- "id": "9a6e4ec46997fb92b324974afa08a3d007e2537f",
- "name": "Animated Page Action",
- "path": "examples/api/pageAction/set_icon/",
- "protocols": [],
- "search_string": "ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED",
+ ],
+ "icon": null,
+ "id": "9a6e4ec46997fb92b324974afa08a3d007e2537f",
+ "name": "Animated Page Action",
+ "path": "examples/api/pageAction/set_icon/",
+ "protocols": [],
+ "search_string": "ANIMATED PAGE ACTION THIS EXTENSION ADDS AN ANIMATED BROWSER ACTION TO THE TOOLBAR. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.ONCLICKED CHROME.PAGEACTION.SETICON CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "9d5e9f8fd525c6d02fe03e1843041f5b0f94f690",
+ ],
+ "source_hash": "9d5e9f8fd525c6d02fe03e1843041f5b0f94f690",
"zip_path": "examples/api/pageAction/set_icon.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.getURL",
- "chrome.management.get",
- "chrome.management.getAll",
- "chrome.management.launchApp",
+ "chrome.extension.getURL",
+ "chrome.management.get",
+ "chrome.management.getAll",
+ "chrome.management.launchApp",
"chrome.tabs.create"
- ],
- "description": "",
+ ],
+ "description": "",
"features": [
- "browser_action",
+ "browser_action",
"management"
- ],
- "icon": null,
- "id": "a1f7cf79dd555b04fa8d603247a040e644996293",
- "name": "App Launcher",
- "path": "examples/extensions/app_launcher/",
- "protocols": [],
- "search_string": "APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE",
+ ],
+ "icon": null,
+ "id": "a1f7cf79dd555b04fa8d603247a040e644996293",
+ "name": "App Launcher",
+ "path": "examples/extensions/app_launcher/",
+ "protocols": [],
+ "search_string": "APP LAUNCHER BROWSER_ACTION MANAGEMENT CHROME.EXTENSION.GETURL CHROME.MANAGEMENT.GET CHROME.MANAGEMENT.GETALL CHROME.MANAGEMENT.LAUNCHAPP CHROME.TABS.CREATE",
"source_files": [
- "manifest.json",
- "popup.css",
- "popup.html",
+ "manifest.json",
+ "popup.css",
+ "popup.html",
"popup.js"
- ],
- "source_hash": "4cb1348cfca9c990117d52290f93eb5fc5081bc2",
+ ],
+ "source_hash": "4cb1348cfca9c990117d52290f93eb5fc5081bc2",
"zip_path": "examples/extensions/app_launcher.zip"
- },
+ },
{
- "api_calls": [],
- "description": "",
+ "api_calls": [],
+ "description": "",
"features": [
"chrome_url_overrides"
- ],
- "icon": null,
- "id": "9747e3d6a3eab39bc7c17f11a80573c62d44c7e5",
- "name": "Blank new tab page",
- "path": "examples/api/override/blank_ntp/",
- "protocols": [],
- "search_string": "BLANK NEW TAB PAGE CHROME_URL_OVERRIDES",
+ ],
+ "icon": null,
+ "id": "9747e3d6a3eab39bc7c17f11a80573c62d44c7e5",
+ "name": "Blank new tab page",
+ "path": "examples/api/override/blank_ntp/",
+ "protocols": [],
+ "search_string": "BLANK NEW TAB PAGE CHROME_URL_OVERRIDES",
"source_files": [
- "blank.html",
+ "blank.html",
"manifest.json"
- ],
- "source_hash": "477acf6d15e3fa252e6307e156707538b61c86db",
+ ],
+ "source_hash": "477acf6d15e3fa252e6307e156707538b61c86db",
"zip_path": "examples/api/override/blank_ntp.zip"
- },
+ },
{
"api_calls": [
- "chrome.bookmarks.onCreated",
- "chrome.bookmarks.onMoved",
- "chrome.bookmarks.onRemoved",
- "chrome.extension.getBackgroundPage",
- "chrome.extension.onRequest",
- "chrome.extension.sendRequest",
- "chrome.tabs.get",
- "chrome.tabs.onAttached",
- "chrome.tabs.onCreated",
- "chrome.tabs.onDetached",
- "chrome.tabs.onMoved",
- "chrome.tabs.onRemoved",
- "chrome.tabs.onSelectionChanged",
- "chrome.tabs.onUpdated",
- "chrome.windows.onCreated",
- "chrome.windows.onFocusChanged",
+ "chrome.bookmarks.onCreated",
+ "chrome.bookmarks.onMoved",
+ "chrome.bookmarks.onRemoved",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
+ "chrome.tabs.get",
+ "chrome.tabs.onAttached",
+ "chrome.tabs.onCreated",
+ "chrome.tabs.onDetached",
+ "chrome.tabs.onMoved",
+ "chrome.tabs.onRemoved",
+ "chrome.tabs.onSelectionChanged",
+ "chrome.tabs.onUpdated",
+ "chrome.windows.onCreated",
+ "chrome.windows.onFocusChanged",
"chrome.windows.onRemoved"
- ],
- "description": "Enjoy a more magical and immersive experience when browsing the web using the power of sound.",
+ ],
+ "description": "Enjoy a more magical and immersive experience when browsing the web using the power of sound.",
"features": [
- "background_page",
- "bookmarks",
- "options_page",
+ "background_page",
+ "bookmarks",
+ "options_page",
"tabs"
- ],
- "icon": "icon.png",
- "id": "903e7277139e1e6caec123d3319cab295d8d1b3a",
- "name": "Chrome Sounds",
- "path": "examples/extensions/fx/",
+ ],
+ "icon": "icon.png",
+ "id": "903e7277139e1e6caec123d3319cab295d8d1b3a",
+ "name": "Chrome Sounds",
+ "path": "examples/extensions/fx/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED",
+ ],
+ "search_string": "CHROME SOUNDS ENJOY A MORE MAGICAL AND IMMERSIVE EXPERIENCE WHEN BROWSING THE WEB USING THE POWER OF SOUND. BACKGROUND_PAGE BOOKMARKS OPTIONS_PAGE TABS CHROME.BOOKMARKS.ONCREATED CHROME.BOOKMARKS.ONMOVED CHROME.BOOKMARKS.ONREMOVED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED",
"source_files": [
- "bg.html",
- "bg.js",
- "content.js",
- "manifest.json",
+ "bg.html",
+ "bg.js",
+ "content.js",
+ "manifest.json",
"options.html"
- ],
- "source_hash": "4155e4e6ba7d523ba7bc3b75da352c22e534c3c3",
+ ],
+ "source_hash": "4155e4e6ba7d523ba7bc3b75da352c22e534c3c3",
"zip_path": "examples/extensions/fx.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText",
- "chrome.browserAction.setTitle",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.setTitle",
"chrome.extension.getURL"
- ],
- "description": "Displays the status of the Chromium buildbot in the toolbar. Click to see more detailed status in a popup.",
+ ],
+ "description": "Displays the status of the Chromium buildbot in the toolbar. Click to see more detailed status in a popup.",
"features": [
- "background_page",
- "browser_action",
- "notifications",
- "options_page",
+ "background_page",
+ "browser_action",
+ "notifications",
+ "options_page",
"popup"
- ],
- "icon": "icon.png",
- "id": "0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5",
- "name": "Chromium Buildbot Monitor",
- "path": "examples/extensions/buildbot/",
+ ],
+ "icon": "icon.png",
+ "id": "0e790e035a4a00b6f1def5ef9a7d7be1bce95ab5",
+ "name": "Chromium Buildbot Monitor",
+ "path": "examples/extensions/buildbot/",
"protocols": [
- "http://",
+ "http://",
"http://"
- ],
- "search_string": "CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL",
+ ],
+ "search_string": "CHROMIUM BUILDBOT MONITOR DISPLAYS THE STATUS OF THE CHROMIUM BUILDBOT IN THE TOOLBAR. CLICK TO SEE MORE DETAILED STATUS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION NOTIFICATIONS OPTIONS_PAGE POPUP CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETURL",
"source_files": [
- "bg.html",
- "manifest.json",
- "options.html",
+ "bg.html",
+ "manifest.json",
+ "options.html",
"popup.html"
- ],
- "source_hash": "ad985dc5b3e2b40826042be1d7b77c07fadfcc68",
+ ],
+ "source_hash": "ad985dc5b3e2b40826042be1d7b77c07fadfcc68",
"zip_path": "examples/extensions/buildbot.zip"
- },
+ },
{
"api_calls": [
- "chrome.omnibox.onInputCancelled",
- "chrome.omnibox.onInputChanged",
- "chrome.omnibox.onInputEntered",
- "chrome.omnibox.onInputStarted",
- "chrome.omnibox.setDefaultSuggestion",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
+ "chrome.omnibox.onInputCancelled",
+ "chrome.omnibox.onInputChanged",
+ "chrome.omnibox.onInputEntered",
+ "chrome.omnibox.onInputStarted",
+ "chrome.omnibox.setDefaultSuggestion",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
"chrome.tabs.update"
- ],
- "description": "Add support to the omnibox to search the Chromium source code.",
+ ],
+ "description": "Add support to the omnibox to search the Chromium source code.",
"features": [
- "background_page",
+ "background_page",
"tabs"
- ],
- "icon": null,
- "id": "ac31228200b41a87982e386cc90d3a6eee4ad885",
- "name": "Chromium Search",
- "path": "examples/extensions/chrome_search/",
+ ],
+ "icon": null,
+ "id": "ac31228200b41a87982e386cc90d3a6eee4ad885",
+ "name": "Chromium Search",
+ "path": "examples/extensions/chrome_search/",
"protocols": [
"http://"
- ],
- "search_string": "CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE",
+ ],
+ "search_string": "CHROMIUM SEARCH ADD SUPPORT TO THE OMNIBOX TO SEARCH THE CHROMIUM SOURCE CODE. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCANCELLED CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.OMNIBOX.ONINPUTSTARTED CHROME.OMNIBOX.SETDEFAULTSUGGESTION CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "8f9a8a4bf21102b26fa626626374cb200b2bcac0",
+ ],
+ "source_hash": "8f9a8a4bf21102b26fa626626374cb200b2bcac0",
"zip_path": "examples/extensions/chrome_search.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.setBadgeText",
- "chrome.tabs.detectLanguage",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.onSelectionChanged",
+ "chrome.browserAction.setBadgeText",
+ "chrome.tabs.detectLanguage",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.onSelectionChanged",
"chrome.tabs.onUpdated"
- ],
- "description": "Displays the language of a tab",
+ ],
+ "description": "Displays the language of a tab",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "7d5d6cf195bc25480256618e360aa38c6e6fba82",
- "name": "CLD",
- "path": "examples/api/i18n/cld/",
- "protocols": [],
- "search_string": "CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED",
+ ],
+ "icon": null,
+ "id": "7d5d6cf195bc25480256618e360aa38c6e6fba82",
+ "name": "CLD",
+ "path": "examples/api/i18n/cld/",
+ "protocols": [],
+ "search_string": "CLD DISPLAYS THE LANGUAGE OF A TAB BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.TABS.DETECTLANGUAGE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "913694d89e0b081f1ea5ad6f07b60b0141e82394",
+ ],
+ "source_hash": "913694d89e0b081f1ea5ad6f07b60b0141e82394",
"zip_path": "examples/api/i18n/cld.zip"
- },
+ },
{
"api_calls": [
"chrome.contextMenus.create"
- ],
- "description": "Shows some of the features of the Context Menus API",
+ ],
+ "description": "Shows some of the features of the Context Menus API",
"features": [
- "background_page",
+ "background_page",
"contextMenus"
- ],
- "icon": null,
- "id": "5d81304a17cf7ac2887484f730fbd2b01e51e166",
- "name": "Context Menus Sample",
- "path": "examples/api/contextMenus/basic/",
- "protocols": [],
- "search_string": "CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE",
+ ],
+ "icon": null,
+ "id": "5d81304a17cf7ac2887484f730fbd2b01e51e166",
+ "name": "Context Menus Sample",
+ "path": "examples/api/contextMenus/basic/",
+ "protocols": [],
+ "search_string": "CONTEXT MENUS SAMPLE SHOWS SOME OF THE FEATURES OF THE CONTEXT MENUS API BACKGROUND_PAGE CONTEXTMENUS CHROME.CONTEXTMENUS.CREATE",
"source_files": [
- "background.html",
- "manifest.json",
+ "background.html",
+ "manifest.json",
"sample.js"
- ],
- "source_hash": "0e35ce268b3b2cf3d9830e6411c85c5dfef2ffdf",
+ ],
+ "source_hash": "0e35ce268b3b2cf3d9830e6411c85c5dfef2ffdf",
"zip_path": "examples/api/contextMenus/basic.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.cookies.get",
- "chrome.cookies.getAll",
- "chrome.cookies.onChanged",
- "chrome.cookies.remove",
- "chrome.extension.getURL",
- "chrome.tabs.create",
- "chrome.tabs.update",
- "chrome.windows.get",
+ "chrome.browserAction.onClicked",
+ "chrome.cookies.get",
+ "chrome.cookies.getAll",
+ "chrome.cookies.onChanged",
+ "chrome.cookies.remove",
+ "chrome.extension.getURL",
+ "chrome.tabs.create",
+ "chrome.tabs.update",
+ "chrome.windows.get",
"chrome.windows.getAll"
- ],
- "description": "Testing Cookie API",
+ ],
+ "description": "Testing Cookie API",
"features": [
- "background_page",
- "browser_action",
- "cookies",
+ "background_page",
+ "browser_action",
+ "cookies",
"tabs"
- ],
- "icon": "cookie.png",
- "id": "4daa6becd0899a54776d9cf7f09613ed1a9f4d77",
- "name": "Cookie API Test Extension",
- "path": "examples/api/cookies/",
+ ],
+ "icon": "cookie.png",
+ "id": "4daa6becd0899a54776d9cf7f09613ed1a9f4d77",
+ "name": "Cookie API Test Extension",
+ "path": "examples/api/cookies/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL",
+ ],
+ "search_string": "COOKIE API TEST EXTENSION TESTING COOKIE API BACKGROUND_PAGE BROWSER_ACTION COOKIES TABS CHROME.BROWSERACTION.ONCLICKED CHROME.COOKIES.GET CHROME.COOKIES.GETALL CHROME.COOKIES.ONCHANGED CHROME.COOKIES.REMOVE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL",
"source_files": [
- "background.html",
- "manager.html",
+ "background.html",
+ "manager.html",
"manifest.json"
- ],
- "source_hash": "d0741a5ff0ce9ac38a1be3e6abc46065d74cb498",
+ ],
+ "source_hash": "d0741a5ff0ce9ac38a1be3e6abc46065d74cb498",
"zip_path": "examples/api/cookies.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.onRequest",
+ "chrome.extension.onRequest",
"chrome.extension.sendRequest"
- ],
- "description": "Demonstrates a method to make a cross-domain XMLHttpRequest fetch from a content script. This extension fetches the current trending topics from Twitter and inserts them in an overlay at the top of Google News. Visit http://news.google.com to test this extension.",
+ ],
+ "description": "Demonstrates a method to make a cross-domain XMLHttpRequest fetch from a content script. This extension fetches the current trending topics from Twitter and inserts them in an overlay at the top of Google News. Visit http://news.google.com to test this extension.",
"features": [
"background_page"
- ],
- "icon": "sample-128.png",
- "id": "6871d09f4a96bf9d4b6cc724d00e909cee0f3902",
- "name": "Cross-domain XMLHttpRequest from a content script",
- "path": "examples/howto/contentscript_xhr/",
+ ],
+ "icon": "sample-128.png",
+ "id": "6871d09f4a96bf9d4b6cc724d00e909cee0f3902",
+ "name": "Cross-domain XMLHttpRequest from a content script",
+ "path": "examples/howto/contentscript_xhr/",
"protocols": [
"http://"
- ],
- "search_string": "CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST",
+ ],
+ "search_string": "CROSS-DOMAIN XMLHTTPREQUEST FROM A CONTENT SCRIPT DEMONSTRATES A METHOD TO MAKE A CROSS-DOMAIN XMLHTTPREQUEST FETCH FROM A CONTENT SCRIPT. THIS EXTENSION FETCHES THE CURRENT TRENDING TOPICS FROM TWITTER AND INSERTS THEM IN AN OVERLAY AT THE TOP OF GOOGLE NEWS. VISIT HTTP://NEWS.GOOGLE.COM TO TEST THIS EXTENSION. BACKGROUND_PAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST",
"source_files": [
- "background.html",
- "contentscript.js",
+ "background.html",
+ "contentscript.js",
"manifest.json"
- ],
- "source_hash": "0fe56cea50dc18b7e5e31d47c383356a85d8b896",
+ ],
+ "source_hash": "0fe56cea50dc18b7e5e31d47c383356a85d8b896",
"zip_path": "examples/howto/contentscript_xhr.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.extension.connect",
- "chrome.extension.onConnect",
- "chrome.tabs.create",
- "chrome.tabs.executeScript",
+ "chrome.browserAction.onClicked",
+ "chrome.extension.connect",
+ "chrome.extension.onConnect",
+ "chrome.tabs.create",
+ "chrome.tabs.executeScript",
"chrome.tabs.update"
- ],
- "description": "This extension adds an email button to the toolbar which allows you to email the page link using your default mail client or Gmail.",
+ ],
+ "description": "This extension adds an email button to the toolbar which allows you to email the page link using your default mail client or Gmail.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
+ "background_page",
+ "browser_action",
+ "options_page",
"tabs"
- ],
- "icon": "mail_128x128.png",
- "id": "028eb5364924344029bcbe1d527f132fc72b34e5",
- "name": "Email this page (by Google)",
- "path": "examples/extensions/email_this_page/",
+ ],
+ "icon": "mail_128x128.png",
+ "id": "028eb5364924344029bcbe1d527f132fc72b34e5",
+ "name": "Email this page (by Google)",
+ "path": "examples/extensions/email_this_page/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE",
+ ],
+ "search_string": "EMAIL THIS PAGE (BY GOOGLE) THIS EXTENSION ADDS AN EMAIL BUTTON TO THE TOOLBAR WHICH ALLOWS YOU TO EMAIL THE PAGE LINK USING YOUR DEFAULT MAIL CLIENT OR GMAIL. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.CONNECT CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.UPDATE",
"source_files": [
- "background.html",
- "content_script.js",
- "manifest.json",
+ "background.html",
+ "content_script.js",
+ "manifest.json",
"options.html"
- ],
- "source_hash": "54b5469031ddcb2097f39dbaae1bcd81ae650154",
+ ],
+ "source_hash": "54b5469031ddcb2097f39dbaae1bcd81ae650154",
"zip_path": "examples/extensions/email_this_page.zip"
- },
+ },
{
- "api_calls": [],
- "description": "A sample extension which uses Google Analytics to track usage.",
+ "api_calls": [
+ "chrome.extension.isAllowedIncognitoAccess"
+ ],
+ "description": "Sample extension which demonstrates how to access a preference.",
+ "features": [
+ "browser_action",
+ "contentSettings",
+ "experimental",
+ "popup"
+ ],
+ "icon": null,
+ "id": "0bf0930a32829dfb77170535ecb27adc2de3998a",
+ "name": "Enable/disable referrers API example extension",
+ "path": "examples/api/preferences/enableReferrer/",
+ "protocols": [],
+ "search_string": "ENABLE/DISABLE REFERRERS API EXAMPLE EXTENSION SAMPLE EXTENSION WHICH DEMONSTRATES HOW TO ACCESS A PREFERENCE. BROWSER_ACTION CONTENTSETTINGS EXPERIMENTAL POPUP CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS",
+ "source_files": [
+ "manifest.json",
+ "popup.html"
+ ],
+ "source_hash": "df2a19be905672c2ced4e7108e05170175847d6b",
+ "zip_path": "examples/api/preferences/enableReferrer.zip"
+ },
+ {
+ "api_calls": [],
+ "description": "A sample extension which uses Google Analytics to track usage.",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"popup"
- ],
- "icon": "analytics-extension-icon-128.png",
- "id": "763a08e9b06595d785568a8d392b95a2f3700258",
- "name": "Event Tracking with Google Analytics",
- "path": "examples/tutorials/analytics/",
- "protocols": [],
- "search_string": "EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP",
+ ],
+ "icon": "analytics-extension-icon-128.png",
+ "id": "763a08e9b06595d785568a8d392b95a2f3700258",
+ "name": "Event Tracking with Google Analytics",
+ "path": "examples/tutorials/analytics/",
+ "protocols": [],
+ "search_string": "EVENT TRACKING WITH GOOGLE ANALYTICS A SAMPLE EXTENSION WHICH USES GOOGLE ANALYTICS TO TRACK USAGE. BACKGROUND_PAGE BROWSER_ACTION POPUP",
"source_files": [
- "analytics.js",
- "background.html",
- "manifest.json",
+ "analytics.js",
+ "background.html",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "b02f040a3eb56f8a0e780549954f69172d62dcd3",
+ ],
+ "source_hash": "b02f040a3eb56f8a0e780549954f69172d62dcd3",
"zip_path": "examples/tutorials/analytics.zip"
- },
+ },
{
"api_calls": [
- "chrome.omnibox.onInputChanged",
- "chrome.omnibox.onInputEntered",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.onRemoved",
+ "chrome.omnibox.onInputChanged",
+ "chrome.omnibox.onInputEntered",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.onRemoved",
"chrome.tabs.update"
- ],
- "description": "Search the Chrome Extensions documentation. To use, type 'crdoc' plus a search term into the Omnibox.",
+ ],
+ "description": "Search the Chrome Extensions documentation. To use, type 'crdoc' plus a search term into the Omnibox.",
"features": [
- "background_page",
+ "background_page",
"tabs"
- ],
- "icon": "icon-128.png",
- "id": "e3df888a89e35bdeb9c8bc8d03be5e1851b97c68",
- "name": "Extension Docs Search",
- "path": "examples/api/omnibox/extension-docs/",
+ ],
+ "icon": "icon-128.png",
+ "id": "e3df888a89e35bdeb9c8bc8d03be5e1851b97c68",
+ "name": "Extension Docs Search",
+ "path": "examples/api/omnibox/extension-docs/",
"protocols": [
"http://"
- ],
- "search_string": "EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE",
+ ],
+ "search_string": "EXTENSION DOCS SEARCH SEARCH THE CHROME EXTENSIONS DOCUMENTATION. TO USE, TYPE CRDOC PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE TABS CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.ONREMOVED CHROME.TABS.UPDATE",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "0aa8ec9a2c091e227661ca5010d08f6823e643a7",
+ ],
+ "source_hash": "0aa8ec9a2c091e227661ca5010d08f6823e643a7",
"zip_path": "examples/api/omnibox/extension-docs.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.browserAction.setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText",
- "chrome.browserAction.setIcon",
- "chrome.browserAction.setTitle",
- "chrome.extension.getBackgroundPage",
- "chrome.extension.onRequest",
- "chrome.extension.sendRequest",
- "chrome.i18n.getMessage",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getAllInWindow",
- "chrome.tabs.onUpdated",
+ "chrome.browserAction.onClicked",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.setIcon",
+ "chrome.browserAction.setTitle",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
+ "chrome.i18n.getMessage",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getAllInWindow",
+ "chrome.tabs.onUpdated",
"chrome.tabs.update"
- ],
- "description": "Quickly see the time until your next meeting from any of your calendars. Click on the button to be taken to your calendar.",
+ ],
+ "description": "Quickly see the time until your next meeting from any of your calendars. Click on the button to be taken to your calendar.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
+ "background_page",
+ "browser_action",
+ "options_page",
"tabs"
- ],
- "icon": "images/icon-128.gif",
- "id": "8b0dd31216235941bdd8eb33fda915ef5cf79a82",
- "name": "Google Calendar Checker (by Google)",
- "path": "examples/extensions/calendar/",
+ ],
+ "icon": "images/icon-128.gif",
+ "id": "8b0dd31216235941bdd8eb33fda915ef5cf79a82",
+ "name": "Google Calendar Checker (by Google)",
+ "path": "examples/extensions/calendar/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE",
+ ],
+ "search_string": "GOOGLE CALENDAR CHECKER (BY GOOGLE) QUICKLY SEE THE TIME UNTIL YOUR NEXT MEETING FROM ANY OF YOUR CALENDARS. CLICK ON THE BUTTON TO BE TAKEN TO YOUR CALENDAR. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE",
"source_files": [
- "_locales/en/messages.json",
- "javascript/background.js",
- "javascript/options.js",
- "javascript/util.js",
- "manifest.json",
- "views/background.html",
+ "_locales/en/messages.json",
+ "javascript/background.js",
+ "javascript/options.js",
+ "javascript/util.js",
+ "manifest.json",
+ "views/background.html",
"views/options.html"
- ],
- "source_hash": "3d9782a3e8315bbbca36c63297db2c8926df4521",
+ ],
+ "source_hash": "3d9782a3e8315bbbca36c63297db2c8926df4521",
"zip_path": "examples/extensions/calendar.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.setBadgeText",
- "chrome.extension.getBackgroundPage",
- "chrome.extension.getURL",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.onUpdated",
+ "chrome.browserAction.setBadgeText",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.getURL",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.onUpdated",
"chrome.tabs.remove"
- ],
- "description": "Demonstrates how to use OAuth to connect the Google Documents List Data API.",
+ ],
+ "description": "Demonstrates how to use OAuth to connect the Google Documents List Data API.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
- "popup",
+ "background_page",
+ "browser_action",
+ "options_page",
+ "popup",
"tabs"
- ],
- "icon": "img/docs_spreadsheets-128.gif",
- "id": "4e35caa9742fb82dbd628892d23a781614f6eff6",
- "name": "Google Document List Viewer",
- "path": "examples/extensions/gdocs/",
+ ],
+ "icon": "img/docs_spreadsheets-128.gif",
+ "id": "4e35caa9742fb82dbd628892d23a781614f6eff6",
+ "name": "Google Document List Viewer",
+ "path": "examples/extensions/gdocs/",
"protocols": [
- "https://",
- "https://",
- "https://",
+ "https://",
+ "https://",
+ "https://",
"https://"
- ],
- "search_string": "GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
+ ],
+ "search_string": "GOOGLE DOCUMENT LIST VIEWER DEMONSTRATES HOW TO USE OAUTH TO CONNECT THE GOOGLE DOCUMENTS LIST DATA API. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.BROWSERACTION.SETBADGETEXT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
"source_files": [
- "background.html",
- "chrome_ex_oauth.html",
- "chrome_ex_oauth.js",
- "chrome_ex_oauthsimple.js",
- "js/jquery-1.4.1.min.js",
- "manifest.json",
- "options.html",
+ "background.html",
+ "chrome_ex_oauth.html",
+ "chrome_ex_oauth.js",
+ "chrome_ex_oauthsimple.js",
+ "js/jquery-1.4.1.min.js",
+ "manifest.json",
+ "options.html",
"popup.html"
- ],
- "source_hash": "284e44d603a62348dd1b7e98e593f3f4b877b124",
+ ],
+ "source_hash": "284e44d603a62348dd1b7e98e593f3f4b877b124",
"zip_path": "examples/extensions/gdocs.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.browserAction.setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText",
- "chrome.browserAction.setIcon",
- "chrome.extension.getBackgroundPage",
- "chrome.i18n.getMessage",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getAllInWindow",
- "chrome.tabs.onUpdated",
+ "chrome.browserAction.onClicked",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.setIcon",
+ "chrome.extension.getBackgroundPage",
+ "chrome.i18n.getMessage",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getAllInWindow",
+ "chrome.tabs.onUpdated",
"chrome.tabs.update"
- ],
- "description": "Displays the number of unread messages in your Google Mail inbox. You can also click the button to open your inbox.",
+ ],
+ "description": "Displays the number of unread messages in your Google Mail inbox. You can also click the button to open your inbox.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
+ "background_page",
+ "browser_action",
+ "options_page",
"tabs"
- ],
- "icon": "icon_128.png",
- "id": "bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca",
- "name": "Google Mail Checker",
- "path": "examples/extensions/gmail/",
+ ],
+ "icon": "icon_128.png",
+ "id": "bb57f7a0132cbeb36ad7e7bb0ab75c21704234ca",
+ "name": "Google Mail Checker",
+ "path": "examples/extensions/gmail/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE",
+ ],
+ "search_string": "GOOGLE MAIL CHECKER DISPLAYS THE NUMBER OF UNREAD MESSAGES IN YOUR GOOGLE MAIL INBOX. YOU CAN ALSO CLICK THE BUTTON TO OPEN YOUR INBOX. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.ONUPDATED CHROME.TABS.UPDATE",
"source_files": [
- "_locales/ar/messages.json",
- "_locales/bg/messages.json",
- "_locales/ca/messages.json",
- "_locales/cs/messages.json",
- "_locales/da/messages.json",
- "_locales/de/messages.json",
- "_locales/el/messages.json",
- "_locales/en/messages.json",
- "_locales/en_GB/messages.json",
- "_locales/es/messages.json",
- "_locales/es_419/messages.json",
- "_locales/et/messages.json",
- "_locales/fi/messages.json",
- "_locales/fil/messages.json",
- "_locales/fr/messages.json",
- "_locales/he/messages.json",
- "_locales/hi/messages.json",
- "_locales/hr/messages.json",
- "_locales/hu/messages.json",
- "_locales/id/messages.json",
- "_locales/it/messages.json",
- "_locales/ja/messages.json",
- "_locales/ko/messages.json",
- "_locales/lt/messages.json",
- "_locales/lv/messages.json",
- "_locales/nb/messages.json",
- "_locales/nl/messages.json",
- "_locales/pl/messages.json",
- "_locales/pt_BR/messages.json",
- "_locales/pt_PT/messages.json",
- "_locales/ro/messages.json",
- "_locales/ru/messages.json",
- "_locales/sk/messages.json",
- "_locales/sl/messages.json",
- "_locales/sr/messages.json",
- "_locales/sv/messages.json",
- "_locales/th/messages.json",
- "_locales/tr/messages.json",
- "_locales/uk/messages.json",
- "_locales/vi/messages.json",
- "_locales/zh_CN/messages.json",
- "_locales/zh_TW/messages.json",
- "background.html",
- "manifest.json",
+ "_locales/ar/messages.json",
+ "_locales/bg/messages.json",
+ "_locales/ca/messages.json",
+ "_locales/cs/messages.json",
+ "_locales/da/messages.json",
+ "_locales/de/messages.json",
+ "_locales/el/messages.json",
+ "_locales/en/messages.json",
+ "_locales/en_GB/messages.json",
+ "_locales/es/messages.json",
+ "_locales/es_419/messages.json",
+ "_locales/et/messages.json",
+ "_locales/fi/messages.json",
+ "_locales/fil/messages.json",
+ "_locales/fr/messages.json",
+ "_locales/he/messages.json",
+ "_locales/hi/messages.json",
+ "_locales/hr/messages.json",
+ "_locales/hu/messages.json",
+ "_locales/id/messages.json",
+ "_locales/it/messages.json",
+ "_locales/ja/messages.json",
+ "_locales/ko/messages.json",
+ "_locales/lt/messages.json",
+ "_locales/lv/messages.json",
+ "_locales/nb/messages.json",
+ "_locales/nl/messages.json",
+ "_locales/pl/messages.json",
+ "_locales/pt_BR/messages.json",
+ "_locales/pt_PT/messages.json",
+ "_locales/ro/messages.json",
+ "_locales/ru/messages.json",
+ "_locales/sk/messages.json",
+ "_locales/sl/messages.json",
+ "_locales/sr/messages.json",
+ "_locales/sv/messages.json",
+ "_locales/th/messages.json",
+ "_locales/tr/messages.json",
+ "_locales/uk/messages.json",
+ "_locales/vi/messages.json",
+ "_locales/zh_CN/messages.json",
+ "_locales/zh_TW/messages.json",
+ "background.html",
+ "manifest.json",
"options.html"
- ],
- "source_hash": "030b77992ed5bbbbc18f1b717bc330b965b26aaf",
+ ],
+ "source_hash": "030b77992ed5bbbbc18f1b717bc330b965b26aaf",
"zip_path": "examples/extensions/gmail.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.getBackgroundPage",
- "chrome.extension.getURL",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.onUpdated",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.getURL",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.onUpdated",
"chrome.tabs.remove"
- ],
- "description": "Find out when you have new waves and preview them fast.",
+ ],
+ "description": "Find out when you have new waves and preview them fast.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
- "popup",
+ "background_page",
+ "browser_action",
+ "options_page",
+ "popup",
"tabs"
- ],
- "icon": "128.png",
- "id": "1682e05ea9a1bde985123b04f6f8ac50a8a64033",
- "name": "Google Wave Notifier",
- "path": "examples/extensions/wave/",
+ ],
+ "icon": "128.png",
+ "id": "1682e05ea9a1bde985123b04f6f8ac50a8a64033",
+ "name": "Google Wave Notifier",
+ "path": "examples/extensions/wave/",
"protocols": [
- "https://",
+ "https://",
"http://"
- ],
- "search_string": "GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
+ ],
+ "search_string": "GOOGLE WAVE NOTIFIER FIND OUT WHEN YOU HAVE NEW WAVES AND PREVIEW THEM FAST. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
"source_files": [
- "background.html",
- "chrome_ex_oauth.html",
- "chrome_ex_oauth.js",
- "chrome_ex_oauthsimple.js",
- "manifest.json",
- "options.html",
- "popup.html",
+ "background.html",
+ "chrome_ex_oauth.html",
+ "chrome_ex_oauth.js",
+ "chrome_ex_oauthsimple.js",
+ "manifest.json",
+ "options.html",
+ "popup.html",
"prettyload.js"
- ],
- "source_hash": "9f360bf8772e8a23862d854ea088e0bec867ba02",
+ ],
+ "source_hash": "9f360bf8772e8a23862d854ea088e0bec867ba02",
"zip_path": "examples/extensions/wave.zip"
- },
+ },
{
- "api_calls": [],
- "description": "The first extension that I made.",
+ "api_calls": [],
+ "description": "The first extension that I made.",
"features": [
- "browser_action",
+ "browser_action",
"popup"
- ],
- "icon": null,
- "id": "14b9651fda4e57b2a5914ba73a779812201b750a",
- "name": "Hello World",
- "path": "examples/tutorials/getstarted/",
+ ],
+ "icon": null,
+ "id": "14b9651fda4e57b2a5914ba73a779812201b750a",
+ "name": "Hello World",
+ "path": "examples/tutorials/getstarted/",
"protocols": [
"http://"
- ],
- "search_string": "HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP",
+ ],
+ "search_string": "HELLO WORLD THE FIRST EXTENSION THAT I MADE. BROWSER_ACTION POPUP",
"source_files": [
- "manifest.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "1a3139dcb7f3e3499023703643e7056c61235123",
+ ],
+ "source_hash": "1a3139dcb7f3e3499023703643e7056c61235123",
"zip_path": "examples/tutorials/getstarted.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.extension.getBackgroundPage",
- "chrome.idle.onStateChanged",
+ "chrome.browserAction.onClicked",
+ "chrome.extension.getBackgroundPage",
+ "chrome.idle.onStateChanged",
"chrome.idle.queryState"
- ],
- "description": "Demonstrates the Idle API",
+ ],
+ "description": "Demonstrates the Idle API",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"idle"
- ],
- "icon": "sample-128.png",
- "id": "2020d72f2577f53caf8e94e3dbac0fb849ceaa4d",
- "name": "Idle - Simple Example",
- "path": "examples/api/idle/idle_simple/",
- "protocols": [],
- "search_string": "IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE",
+ ],
+ "icon": "sample-128.png",
+ "id": "2020d72f2577f53caf8e94e3dbac0fb849ceaa4d",
+ "name": "Idle - Simple Example",
+ "path": "examples/api/idle/idle_simple/",
+ "protocols": [],
+ "search_string": "IDLE - SIMPLE EXAMPLE DEMONSTRATES THE IDLE API BACKGROUND_PAGE BROWSER_ACTION IDLE CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.IDLE.ONSTATECHANGED CHROME.IDLE.QUERYSTATE",
"source_files": [
- "background.html",
- "history.html",
+ "background.html",
+ "history.html",
"manifest.json"
- ],
- "source_hash": "1378042fee96e115d7b8003588eca369b43f772b",
+ ],
+ "source_hash": "1378042fee96e115d7b8003588eca369b43f772b",
"zip_path": "examples/api/idle/idle_simple.zip"
- },
+ },
{
- "api_calls": [],
- "description": "",
+ "api_calls": [],
+ "description": "",
"features": [
"chrome_url_overrides"
- ],
- "icon": null,
- "id": "0ea1588bd07b20338fc21f725de1542a5fdf9726",
- "name": "iGoogle new tab page",
- "path": "examples/api/override/override_igoogle/",
- "protocols": [],
- "search_string": "IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES",
+ ],
+ "icon": null,
+ "id": "0ea1588bd07b20338fc21f725de1542a5fdf9726",
+ "name": "iGoogle new tab page",
+ "path": "examples/api/override/override_igoogle/",
+ "protocols": [],
+ "search_string": "IGOOGLE NEW TAB PAGE CHROME_URL_OVERRIDES",
"source_files": [
- "manifest.json",
+ "manifest.json",
"redirect.html"
- ],
- "source_hash": "8ee76608adbf87c3260f9905e6cb1c8a45bd8e0c",
+ ],
+ "source_hash": "8ee76608adbf87c3260f9905e6cb1c8a45bd8e0c",
"zip_path": "examples/api/override/override_igoogle.zip"
- },
+ },
{
"api_calls": [
- "chrome.contextMenus.create",
- "chrome.tabs.get",
- "chrome.tabs.getCurrent",
- "chrome.windows.create",
+ "chrome.contextMenus.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getCurrent",
+ "chrome.windows.create",
"chrome.windows.update"
- ],
- "description": "Get image info for images, including EXIF data",
+ ],
+ "description": "Get image info for images, including EXIF data",
"features": [
- "background_page",
- "contextMenus",
+ "background_page",
+ "contextMenus",
"tabs"
- ],
- "icon": "imageinfo-128.png",
- "id": "646325c25f572a1d15edc73d057f821d847a4fbe",
- "name": "Imageinfo",
- "path": "examples/extensions/imageinfo/",
+ ],
+ "icon": "imageinfo-128.png",
+ "id": "646325c25f572a1d15edc73d057f821d847a4fbe",
+ "name": "Imageinfo",
+ "path": "examples/extensions/imageinfo/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE",
+ ],
+ "search_string": "IMAGEINFO GET IMAGE INFO FOR IMAGES, INCLUDING EXIF DATA BACKGROUND_PAGE CONTEXTMENUS TABS CHROME.CONTEXTMENUS.CREATE CHROME.TABS.GET CHROME.TABS.GETCURRENT CHROME.WINDOWS.CREATE CHROME.WINDOWS.UPDATE",
"source_files": [
- "background.html",
- "imageinfo/binaryajax.js",
- "imageinfo/exif.js",
- "imageinfo/imageinfo.js",
- "info.html",
+ "background.html",
+ "imageinfo/binaryajax.js",
+ "imageinfo/exif.js",
+ "imageinfo/imageinfo.js",
+ "info.html",
"manifest.json"
- ],
- "source_hash": "c746d9114348f4b414c1ec05e988e2807feb963a",
+ ],
+ "source_hash": "c746d9114348f4b414c1ec05e988e2807feb963a",
"zip_path": "examples/extensions/imageinfo.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.getBackgroundPage",
- "chrome.extension.onRequest",
- "chrome.pageAction.hide",
- "chrome.pageAction.setTitle",
- "chrome.pageAction.show",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.onSelectionChanged",
- "chrome.tabs.onUpdated",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.update"
+ ],
+ "description": "Creates a keyboard shortcut (C + Shift + P) to toggle the pinned state of the currently selected tab",
+ "features": [
+ "background_page",
+ "tabs"
+ ],
+ "icon": null,
+ "id": "65b2fe595b7ac38dddd89cca50f5efd0017b0bd4",
+ "name": "Keyboard Pin",
+ "path": "examples/api/tabs/pin/",
+ "protocols": [],
+ "search_string": "KEYBOARD PIN CREATES A KEYBOARD SHORTCUT (C + SHIFT + P) TO TOGGLE THE PINNED STATE OF THE CURRENTLY SELECTED TAB BACKGROUND_PAGE TABS CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE",
+ "source_files": [
+ "background.html",
+ "inject.js",
+ "manifest.json"
+ ],
+ "source_hash": "e7e86d83a781a8c575641cc11136bd42e15d0f67",
+ "zip_path": "examples/api/tabs/pin.zip"
+ },
+ {
+ "api_calls": [
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.onRequest",
+ "chrome.pageAction.hide",
+ "chrome.pageAction.setTitle",
+ "chrome.pageAction.show",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.onSelectionChanged",
+ "chrome.tabs.onUpdated",
"chrome.tabs.sendRequest"
- ],
- "description": "Finds addresses in the web page you're on and pops up a map window.",
+ ],
+ "description": "Finds addresses in the web page you're on and pops up a map window.",
"features": [
- "background_page",
- "page_action",
- "popup",
+ "background_page",
+ "page_action",
+ "popup",
"tabs"
- ],
- "icon": "icon.png",
- "id": "ec97ec20ca2f095d081e39f1565fc12af09ef067",
- "name": "Mappy",
- "path": "examples/extensions/mappy/",
+ ],
+ "icon": "icon.png",
+ "id": "ec97ec20ca2f095d081e39f1565fc12af09ef067",
+ "name": "Mappy",
+ "path": "examples/extensions/mappy/",
"protocols": [
"http://"
- ],
- "search_string": "MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST",
+ ],
+ "search_string": "MAPPY FINDS ADDRESSES IN THE WEB PAGE YOURE ON AND POPS UP A MAP WINDOW. BACKGROUND_PAGE PAGE_ACTION POPUP TABS CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.ONREQUEST CHROME.PAGEACTION.HIDE CHROME.PAGEACTION.SETTITLE CHROME.PAGEACTION.SHOW CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.SENDREQUEST",
"source_files": [
- "background.html",
- "manifest.json",
- "mappy_content_script.js",
+ "background.html",
+ "manifest.json",
+ "mappy_content_script.js",
"popup.html"
- ],
- "source_hash": "81cf2d3975d7df8b58e5226c5b2b6df026446511",
+ ],
+ "source_hash": "81cf2d3975d7df8b58e5226c5b2b6df026446511",
"zip_path": "examples/extensions/mappy.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.tabs.get",
- "chrome.tabs.getAllInWindow",
- "chrome.tabs.move",
- "chrome.windows.get",
- "chrome.windows.getAll",
+ "chrome.browserAction.onClicked",
+ "chrome.tabs.get",
+ "chrome.tabs.getAllInWindow",
+ "chrome.tabs.move",
+ "chrome.windows.get",
+ "chrome.windows.getAll",
"chrome.windows.getCurrent"
- ],
- "description": "Merges all of the browser's windows into the current window",
+ ],
+ "description": "Merges all of the browser's windows into the current window",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": "merge_windows_128.png",
- "id": "b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d",
- "name": "Merge Windows",
- "path": "examples/api/windows/merge_windows/",
- "protocols": [],
- "search_string": "MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT",
+ ],
+ "icon": "merge_windows_128.png",
+ "id": "b2f5f8a790e16f091a7e4e0a39b2d0a6d32e3a6d",
+ "name": "Merge Windows",
+ "path": "examples/api/windows/merge_windows/",
+ "protocols": [],
+ "search_string": "MERGE WINDOWS MERGES ALL OF THE BROWSERS WINDOWS INTO THE CURRENT WINDOW BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.MOVE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "4b5fe52788e0bef2f3871b36105eb53cc760c454",
+ ],
+ "source_hash": "4b5fe52788e0bef2f3871b36105eb53cc760c454",
"zip_path": "examples/api/windows/merge_windows.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.onConnect",
- "chrome.extension.onRequest",
- "chrome.tabs.connect",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
+ "chrome.extension.onConnect",
+ "chrome.extension.onRequest",
+ "chrome.tabs.connect",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
"chrome.tabs.sendRequest"
- ],
- "description": "Times how long it takes to send a message to a content script and back.",
+ ],
+ "description": "Times how long it takes to send a message to a content script and back.",
"features": [
- "browser_action",
- "popup",
+ "browser_action",
+ "popup",
"tabs"
- ],
- "icon": null,
- "id": "51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e",
- "name": "Message Timer",
- "path": "examples/api/messaging/timer/",
- "protocols": [],
- "search_string": "MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST",
+ ],
+ "icon": null,
+ "id": "51a83d2ba3a32e3ff1bdb624d4e18ccec4c4038e",
+ "name": "Message Timer",
+ "path": "examples/api/messaging/timer/",
+ "protocols": [],
+ "search_string": "MESSAGE TIMER TIMES HOW LONG IT TAKES TO SEND A MESSAGE TO A CONTENT SCRIPT AND BACK. BROWSER_ACTION POPUP TABS CHROME.EXTENSION.ONCONNECT CHROME.EXTENSION.ONREQUEST CHROME.TABS.CONNECT CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.SENDREQUEST",
"source_files": [
- "manifest.json",
- "page.js",
+ "manifest.json",
+ "page.js",
"popup.html"
- ],
- "source_hash": "927cf398a95a665beb64f56a4bfb791b98a8ee96",
+ ],
+ "source_hash": "927cf398a95a665beb64f56a4bfb791b98a8ee96",
"zip_path": "examples/api/messaging/timer.zip"
- },
+ },
{
"api_calls": [
- "chrome.bookmarks.create",
- "chrome.bookmarks.get",
- "chrome.bookmarks.getTree",
- "chrome.bookmarks.remove",
- "chrome.bookmarks.update",
+ "chrome.bookmarks.create",
+ "chrome.bookmarks.get",
+ "chrome.bookmarks.getTree",
+ "chrome.bookmarks.remove",
+ "chrome.bookmarks.update",
"chrome.tabs.create"
- ],
- "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.",
+ ],
+ "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.",
"features": [
- "bookmarks",
- "browser_action",
- "popup",
+ "bookmarks",
+ "browser_action",
+ "popup",
"tabs"
- ],
- "icon": null,
- "id": "4f6785ec4f937add6728615682dd37c9a42d9548",
- "name": "My Bookmarks",
- "path": "examples/api/bookmarks/basic/",
- "protocols": [],
- "search_string": "MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE",
+ ],
+ "icon": null,
+ "id": "4f6785ec4f937add6728615682dd37c9a42d9548",
+ "name": "My Bookmarks",
+ "path": "examples/api/bookmarks/basic/",
+ "protocols": [],
+ "search_string": "MY BOOKMARKS A BROWSER ACTION WITH A POPUP DUMP OF ALL BOOKMARKS, INCLUDING SEARCH, ADD, EDIT AND DELETE. BOOKMARKS BROWSER_ACTION POPUP TABS CHROME.BOOKMARKS.CREATE CHROME.BOOKMARKS.GET CHROME.BOOKMARKS.GETTREE CHROME.BOOKMARKS.REMOVE CHROME.BOOKMARKS.UPDATE CHROME.TABS.CREATE",
"source_files": [
- "manifest.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "5fd4c8e159a36d2462e9691db12d77a27684d6b7",
+ ],
+ "source_hash": "5fd4c8e159a36d2462e9691db12d77a27684d6b7",
"zip_path": "examples/api/bookmarks/basic.zip"
- },
+ },
{
"api_calls": [
"chrome.tabs.create"
- ],
- "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
+ ],
+ "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
"features": [
- "browser_action",
- "popup",
+ "browser_action",
+ "popup",
"tabs"
- ],
- "icon": "news_icon.png",
- "id": "597015d3bcce3da693b02314afd607bec4f55291",
- "name": "News Reader",
- "path": "examples/extensions/news_a11y/",
+ ],
+ "icon": "news_icon.png",
+ "id": "597015d3bcce3da693b02314afd607bec4f55291",
+ "name": "News Reader",
+ "path": "examples/extensions/news_a11y/",
"protocols": [
"http://"
- ],
- "search_string": "NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE",
+ ],
+ "search_string": "NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.TABS.CREATE",
"source_files": [
- "feed.html",
+ "feed.html",
"manifest.json"
- ],
- "source_hash": "af7474bf0d3ef1a407f27ae0900167a1408ead35",
+ ],
+ "source_hash": "af7474bf0d3ef1a407f27ae0900167a1408ead35",
"zip_path": "examples/extensions/news_a11y.zip"
- },
+ },
{
"api_calls": [
- "chrome.i18n.getMessage",
+ "chrome.i18n.getMessage",
"chrome.tabs.create"
- ],
- "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
+ ],
+ "description": "Displays the first 5 items from the 'Google News - top news' RSS feed in a popup.",
"features": [
- "browser_action",
- "popup",
+ "browser_action",
+ "popup",
"tabs"
- ],
- "icon": "news_icon.png",
- "id": "6444e5c8ae112a6a433909c5e770669cd16e2e5f",
- "name": "News Reader",
- "path": "examples/extensions/news_i18n/",
+ ],
+ "icon": "news_icon.png",
+ "id": "6444e5c8ae112a6a433909c5e770669cd16e2e5f",
+ "name": "News Reader",
+ "path": "examples/extensions/news_i18n/",
"protocols": [
- "http://",
+ "http://",
"http://"
- ],
- "search_string": "NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE",
+ ],
+ "search_string": "NEWS READER DISPLAYS THE FIRST 5 ITEMS FROM THE GOOGLE NEWS - TOP NEWS RSS FEED IN A POPUP. BROWSER_ACTION POPUP TABS CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE",
"source_files": [
- "_locales/en/messages.json",
- "_locales/es/messages.json",
- "_locales/sr/messages.json",
- "feed.html",
+ "_locales/en/messages.json",
+ "_locales/es/messages.json",
+ "_locales/sr/messages.json",
+ "feed.html",
"manifest.json"
- ],
- "source_hash": "381268f1183beaeba8d6596e736dc2c00a55fd21",
+ ],
+ "source_hash": "381268f1183beaeba8d6596e736dc2c00a55fd21",
"zip_path": "examples/extensions/news_i18n.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.getURL",
- "chrome.i18n.getMessage",
+ "chrome.extension.getURL",
+ "chrome.i18n.getMessage",
"chrome.tabs.create"
- ],
- "description": "Displays the latest stories from Google News in a popup.",
+ ],
+ "description": "Displays the latest stories from Google News in a popup.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
- "popup",
+ "background_page",
+ "browser_action",
+ "options_page",
+ "popup",
"tabs"
- ],
- "icon": "images/news_icon.png",
- "id": "3aea027164cb9b732ba4a8c51cb93708891726ef",
- "name": "News Reader (by Google)",
- "path": "examples/extensions/news/",
+ ],
+ "icon": "images/news_icon.png",
+ "id": "3aea027164cb9b732ba4a8c51cb93708891726ef",
+ "name": "News Reader (by Google)",
+ "path": "examples/extensions/news/",
"protocols": [
"http://"
- ],
- "search_string": "NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE",
+ ],
+ "search_string": "NEWS READER (BY GOOGLE) DISPLAYS THE LATEST STORIES FROM GOOGLE NEWS IN A POPUP. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE POPUP TABS CHROME.EXTENSION.GETURL CHROME.I18N.GETMESSAGE CHROME.TABS.CREATE",
"source_files": [
- "_locales/en/messages.json",
- "css/feed.css",
- "css/options.css",
- "javascript/feed.js",
- "javascript/options.js",
- "javascript/util.js",
- "manifest.json",
- "views/background.html",
- "views/feed.html",
+ "_locales/en/messages.json",
+ "css/feed.css",
+ "css/options.css",
+ "javascript/feed.js",
+ "javascript/options.js",
+ "javascript/util.js",
+ "manifest.json",
+ "views/background.html",
+ "views/feed.html",
"views/options.html"
- ],
- "source_hash": "cc21920e101dd4d4c535f4842e3f0ab4be285166",
+ ],
+ "source_hash": "cc21920e101dd4d4c535f4842e3f0ab4be285166",
"zip_path": "examples/extensions/news.zip"
- },
+ },
{
"api_calls": [
"chrome.tabs.create"
- ],
- "description": "Shows off desktop notifications, which are \"toast\" windows that pop up on the desktop.",
+ ],
+ "description": "Shows off desktop notifications, which are \"toast\" windows that pop up on the desktop.",
"features": [
- "background_page",
- "notifications",
- "options_page",
+ "background_page",
+ "notifications",
+ "options_page",
"tabs"
- ],
- "icon": "128.png",
- "id": "f799e26ceef2367cf836f24bcb47df4398b0df58",
- "name": "Notification Demo",
- "path": "examples/api/notifications/",
- "protocols": [],
- "search_string": "NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE",
+ ],
+ "icon": "128.png",
+ "id": "f799e26ceef2367cf836f24bcb47df4398b0df58",
+ "name": "Notification Demo",
+ "path": "examples/api/notifications/",
+ "protocols": [],
+ "search_string": "NOTIFICATION DEMO SHOWS OFF DESKTOP NOTIFICATIONS, WHICH ARE TOAST WINDOWS THAT POP UP ON THE DESKTOP. BACKGROUND_PAGE NOTIFICATIONS OPTIONS_PAGE TABS CHROME.TABS.CREATE",
"source_files": [
- "background.html",
- "error.html",
- "manifest.json",
+ "background.html",
+ "error.html",
+ "manifest.json",
"options.html"
- ],
- "source_hash": "bc2985ef75d717779cb6e1e523a3e063067c3494",
+ ],
+ "source_hash": "bc2985ef75d717779cb6e1e523a3e063067c3494",
"zip_path": "examples/api/notifications.zip"
- },
+ },
{
"api_calls": [
- "chrome.omnibox.onInputChanged",
+ "chrome.omnibox.onInputChanged",
"chrome.omnibox.onInputEntered"
- ],
- "description": "To use, type 'omnix' plus a search term into the Omnibox.",
+ ],
+ "description": "To use, type 'omnix' plus a search term into the Omnibox.",
"features": [
"background_page"
- ],
- "icon": null,
- "id": "e787b322bddbc6289bb31b7d7550b1bf6456a80b",
- "name": "Omnibox Example",
- "path": "examples/api/omnibox/simple-example/",
- "protocols": [],
- "search_string": "OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED",
+ ],
+ "icon": null,
+ "id": "e787b322bddbc6289bb31b7d7550b1bf6456a80b",
+ "name": "Omnibox Example",
+ "path": "examples/api/omnibox/simple-example/",
+ "protocols": [],
+ "search_string": "OMNIBOX EXAMPLE TO USE, TYPE OMNIX PLUS A SEARCH TERM INTO THE OMNIBOX. BACKGROUND_PAGE CHROME.OMNIBOX.ONINPUTCHANGED CHROME.OMNIBOX.ONINPUTENTERED",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "21f142aad0637086ec08923a11ce3dee70e42bc6",
+ ],
+ "source_hash": "21f142aad0637086ec08923a11ce3dee70e42bc6",
"zip_path": "examples/api/omnibox/simple-example.zip"
- },
+ },
{
"api_calls": [
- "chrome.extension.onRequest",
- "chrome.extension.sendRequest",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
"chrome.pageAction.show"
- ],
- "description": "Shows a page action for HTML pages containing the word 'sandwich'",
+ ],
+ "description": "Shows a page action for HTML pages containing the word 'sandwich'",
"features": [
- "background_page",
+ "background_page",
"page_action"
- ],
- "icon": "sandwich-128.png",
- "id": "8d0a50b57c26bb498be592e871001ffed91541b4",
- "name": "Page action by content",
- "path": "examples/api/pageAction/pageaction_by_content/",
- "protocols": [],
- "search_string": "PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW",
+ ],
+ "icon": "sandwich-128.png",
+ "id": "8d0a50b57c26bb498be592e871001ffed91541b4",
+ "name": "Page action by content",
+ "path": "examples/api/pageAction/pageaction_by_content/",
+ "protocols": [],
+ "search_string": "PAGE ACTION BY CONTENT SHOWS A PAGE ACTION FOR HTML PAGES CONTAINING THE WORD SANDWICH BACKGROUND_PAGE PAGE_ACTION CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.PAGEACTION.SHOW",
"source_files": [
- "background.html",
- "contentscript.js",
+ "background.html",
+ "contentscript.js",
"manifest.json"
- ],
- "source_hash": "0f4b881b1bc2e2fd6098fd219ca061b72a9654b7",
+ ],
+ "source_hash": "0f4b881b1bc2e2fd6098fd219ca061b72a9654b7",
"zip_path": "examples/api/pageAction/pageaction_by_content.zip"
- },
+ },
{
"api_calls": [
- "chrome.pageAction.show",
+ "chrome.pageAction.show",
"chrome.tabs.onUpdated"
- ],
- "description": "Shows a page action for urls which have the letter 'g' in them.",
+ ],
+ "description": "Shows a page action for urls which have the letter 'g' in them.",
"features": [
- "background_page",
- "page_action",
+ "background_page",
+ "page_action",
"tabs"
- ],
- "icon": "icon-128.png",
- "id": "80b86ccc6e8520660fa591caa565826f0ed1b12c",
- "name": "Page action by URL",
- "path": "examples/api/pageAction/pageaction_by_url/",
- "protocols": [],
- "search_string": "PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED",
+ ],
+ "icon": "icon-128.png",
+ "id": "80b86ccc6e8520660fa591caa565826f0ed1b12c",
+ "name": "Page action by URL",
+ "path": "examples/api/pageAction/pageaction_by_url/",
+ "protocols": [],
+ "search_string": "PAGE ACTION BY URL SHOWS A PAGE ACTION FOR URLS WHICH HAVE THE LETTER G IN THEM. BACKGROUND_PAGE PAGE_ACTION TABS CHROME.PAGEACTION.SHOW CHROME.TABS.ONUPDATED",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "732ef0951e1d6ff4afedb884b0e63cb342bb1499",
+ ],
+ "source_hash": "732ef0951e1d6ff4afedb884b0e63cb342bb1499",
"zip_path": "examples/api/pageAction/pageaction_by_url.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.browserAction.setBadgeBackgroundColor",
- "chrome.browserAction.setBadgeText",
- "chrome.browserAction.setTitle",
- "chrome.extension.connect",
- "chrome.extension.getBackgroundPage",
- "chrome.extension.getExtensionTabs",
- "chrome.extension.getURL",
- "chrome.extension.onConnect",
- "chrome.tabs.create",
- "chrome.tabs.executeScript",
- "chrome.tabs.get",
- "chrome.tabs.getAllInWindow",
- "chrome.tabs.getSelected",
- "chrome.tabs.remove",
- "chrome.tabs.update",
- "chrome.windows.get",
+ "chrome.browserAction.onClicked",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.setTitle",
+ "chrome.extension.connect",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.getExtensionTabs",
+ "chrome.extension.getURL",
+ "chrome.extension.onConnect",
+ "chrome.tabs.create",
+ "chrome.tabs.executeScript",
+ "chrome.tabs.get",
+ "chrome.tabs.getAllInWindow",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.remove",
+ "chrome.tabs.update",
+ "chrome.windows.get",
"chrome.windows.getCurrent"
- ],
- "description": "Chromium Page Benchmarker.",
+ ],
+ "description": "Chromium Page Benchmarker.",
"features": [
- "background_page",
- "browser_action",
- "options_page",
+ "background_page",
+ "browser_action",
+ "options_page",
"tabs"
- ],
- "icon": null,
- "id": "d74c3c18a1c1dd18b035149105a306f837c8823e",
- "name": "Page Benchmarker",
- "path": "examples/extensions/benchmark/",
+ ],
+ "icon": null,
+ "id": "d74c3c18a1c1dd18b035149105a306f837c8823e",
+ "name": "Page Benchmarker",
+ "path": "examples/extensions/benchmark/",
"protocols": [
- "https://",
+ "https://",
"http://"
- ],
- "search_string": "PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT",
+ ],
+ "search_string": "PAGE BENCHMARKER CHROMIUM PAGE BENCHMARKER. BACKGROUND_PAGE BROWSER_ACTION OPTIONS_PAGE TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXTENSION.CONNECT CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETEXTENSIONTABS CHROME.EXTENSION.GETURL CHROME.EXTENSION.ONCONNECT CHROME.TABS.CREATE CHROME.TABS.EXECUTESCRIPT CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETCURRENT",
"source_files": [
- "background.html",
- "jquery/jquery-1.4.2.min.js",
- "jquery/jquery-ui-1.8.4.custom.min.js",
- "jquery/jquery.client.js",
- "jquery/jquery.flot.dashes.js",
- "jquery/jquery.flot.js",
- "jquery/jquery.flot.min.js",
- "jquery/jquery.flot.navigate.js",
- "jquery/jquery.flot.valuelabels.js",
- "jst/jsevalcontext.js",
- "jst/jstemplate.js",
- "jst/jstemplate_test.js",
- "jst/util.js",
- "manifest.json",
- "options.html",
- "script.js",
- "util/sorttable.js",
+ "background.html",
+ "jquery/jquery-1.4.2.min.js",
+ "jquery/jquery-ui-1.8.4.custom.min.js",
+ "jquery/jquery.client.js",
+ "jquery/jquery.flot.dashes.js",
+ "jquery/jquery.flot.js",
+ "jquery/jquery.flot.min.js",
+ "jquery/jquery.flot.navigate.js",
+ "jquery/jquery.flot.valuelabels.js",
+ "jst/jsevalcontext.js",
+ "jst/jstemplate.js",
+ "jst/jstemplate_test.js",
+ "jst/util.js",
+ "manifest.json",
+ "options.html",
+ "script.js",
+ "util/sorttable.js",
"util/table2CSV.js"
- ],
- "source_hash": "7e592dbd3446353f7d98d1760f7cd773035aaaad",
+ ],
+ "source_hash": "7e592dbd3446353f7d98d1760f7cd773035aaaad",
"zip_path": "examples/extensions/benchmark.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
+ "chrome.browserAction.onClicked",
"chrome.tabs.update"
- ],
- "description": "Adds a print button to the browser.",
+ ],
+ "description": "Adds a print button to the browser.",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd",
- "name": "Print this page",
- "path": "examples/api/browserAction/print/",
+ ],
+ "icon": null,
+ "id": "e6ae17ab4ccfd7e059c8c01f25760ca5d894c7fd",
+ "name": "Print this page",
+ "path": "examples/api/browserAction/print/",
"protocols": [
- "http://",
+ "http://",
"https://"
- ],
- "search_string": "PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE",
+ ],
+ "search_string": "PRINT THIS PAGE ADDS A PRINT BUTTON TO THE BROWSER. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.TABS.UPDATE",
"source_files": [
- "background.html",
+ "background.html",
"manifest.json"
- ],
- "source_hash": "be980117222f6b041bb012c5a0793040cef747b6",
+ ],
+ "source_hash": "be980117222f6b041bb012c5a0793040cef747b6",
"zip_path": "examples/api/browserAction/print.zip"
- },
+ },
{
"api_calls": [
"chrome.experimental.processes.onUpdated"
- ],
- "description": "Adds a browser action that monitors resource usage of all browser processes.",
+ ],
+ "description": "Adds a browser action that monitors resource usage of all browser processes.",
"features": [
- "browser_action",
- "experimental",
- "popup",
+ "browser_action",
+ "experimental",
+ "popup",
"tabs"
- ],
- "icon": null,
- "id": "beff6ecd9677dea0a7c648c5042165b48bb66f09",
- "name": "Process Monitor",
- "path": "examples/api/processes/process_monitor/",
- "protocols": [],
- "search_string": "PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED",
+ ],
+ "icon": null,
+ "id": "beff6ecd9677dea0a7c648c5042165b48bb66f09",
+ "name": "Process Monitor",
+ "path": "examples/api/processes/process_monitor/",
+ "protocols": [],
+ "search_string": "PROCESS MONITOR ADDS A BROWSER ACTION THAT MONITORS RESOURCE USAGE OF ALL BROWSER PROCESSES. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.ONUPDATED",
"source_files": [
- "manifest.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "a4d002a65d5ec54ef4495f8b5552a260119df739",
+ ],
+ "source_hash": "a4d002a65d5ec54ef4495f8b5552a260119df739",
"zip_path": "examples/api/processes/process_monitor.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.browserAction.setIcon",
- "chrome.extension.getBackgroundPage",
- "chrome.extension.getURL",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.onUpdated",
+ "chrome.browserAction.setBadgeBackgroundColor",
+ "chrome.browserAction.setBadgeText",
+ "chrome.browserAction.setTitle",
+ "chrome.experimental.proxy.onProxyError",
+ "chrome.extension.isAllowedIncognitoAccess",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
+ "chrome.i18n.getMessage"
+ ],
+ "description": "Set Chrome-specific proxies; a demonstration of Chrome's Proxy API",
+ "features": [
+ "background_page",
+ "browser_action",
+ "experimental",
+ "popup",
+ "proxy"
+ ],
+ "icon": "icon128.png",
+ "id": "3e8e226d87e431296bb110b4f6eb7eec2ca7a826",
+ "name": "Proxy Settings",
+ "path": "examples/extensions/proxy_configuration/",
+ "protocols": [],
+ "search_string": "PROXY SETTINGS SET CHROME-SPECIFIC PROXIES; A DEMONSTRATION OF CHROMES PROXY API BACKGROUND_PAGE BROWSER_ACTION EXPERIMENTAL POPUP PROXY CHROME.BROWSERACTION.SETBADGEBACKGROUNDCOLOR CHROME.BROWSERACTION.SETBADGETEXT CHROME.BROWSERACTION.SETTITLE CHROME.EXPERIMENTAL.PROXY.ONPROXYERROR CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE",
+ "source_files": [
+ "_locales/en/messages.json",
+ "background.html",
+ "manifest.json",
+ "popup.html",
+ "proxy_error_handler.js",
+ "proxy_form_controller.js",
+ "test/jsunittest.js",
+ "test/proxy_form_controller_test.html",
+ "test/proxy_form_controller_test.js",
+ "test/unittest.css"
+ ],
+ "source_hash": "8f6768d78649cc4e69e595e7e43b3f06431c84e0",
+ "zip_path": "examples/extensions/proxy_configuration.zip"
+ },
+ {
+ "api_calls": [
+ "chrome.browserAction.onClicked",
+ "chrome.browserAction.setIcon",
+ "chrome.extension.getBackgroundPage",
+ "chrome.extension.getURL",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.onUpdated",
"chrome.tabs.remove"
- ],
- "description": "Uses OAuth to connect to Google's contacts service and display a list of your contacts.",
+ ],
+ "description": "Uses OAuth to connect to Google's contacts service and display a list of your contacts.",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": "img/icon-128.png",
- "id": "56a8d2ac24ca7bba78fd88ad57f43fc13c784497",
- "name": "Sample - OAuth Contacts",
- "path": "examples/extensions/oauth_contacts/",
+ ],
+ "icon": "img/icon-128.png",
+ "id": "56a8d2ac24ca7bba78fd88ad57f43fc13c784497",
+ "name": "Sample - OAuth Contacts",
+ "path": "examples/extensions/oauth_contacts/",
"protocols": [
- "http://",
- "https://",
- "https://",
+ "http://",
+ "https://",
+ "https://",
"https://"
- ],
- "search_string": "SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
+ ],
+ "search_string": "SAMPLE - OAUTH CONTACTS USES OAUTH TO CONNECT TO GOOGLES CONTACTS SERVICE AND DISPLAY A LIST OF YOUR CONTACTS. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.BROWSERACTION.SETICON CHROME.EXTENSION.GETBACKGROUNDPAGE CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE",
"source_files": [
- "background.html",
- "chrome_ex_oauth.html",
- "chrome_ex_oauth.js",
- "chrome_ex_oauthsimple.js",
- "contacts.html",
+ "background.html",
+ "chrome_ex_oauth.html",
+ "chrome_ex_oauth.js",
+ "chrome_ex_oauthsimple.js",
+ "contacts.html",
"manifest.json"
- ],
- "source_hash": "e9afbd588b1593c9d3e9b9612ac242c781871f34",
+ ],
+ "source_hash": "e9afbd588b1593c9d3e9b9612ac242c781871f34",
"zip_path": "examples/extensions/oauth_contacts.zip"
- },
+ },
{
"api_calls": [
- "chrome.experimental.infobars.show",
- "chrome.extension.onRequest",
+ "chrome.experimental.infobars.show",
+ "chrome.extension.onRequest",
"chrome.extension.sendRequest"
- ],
- "description": "Shows an infobar on pages which contain the word 'sandwich'",
+ ],
+ "description": "Shows an infobar on pages which contain the word 'sandwich'",
"features": [
- "background_page",
+ "background_page",
"experimental"
- ],
- "icon": "sandwich-128.png",
- "id": "38f6e1e17756ede38b1364c7114a738ca717dcbb",
- "name": "SandwichBar",
- "path": "examples/api/infobars/sandwichbar/",
- "protocols": [],
- "search_string": "SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST",
+ ],
+ "icon": "sandwich-128.png",
+ "id": "38f6e1e17756ede38b1364c7114a738ca717dcbb",
+ "name": "SandwichBar",
+ "path": "examples/api/infobars/sandwichbar/",
+ "protocols": [],
+ "search_string": "SANDWICHBAR SHOWS AN INFOBAR ON PAGES WHICH CONTAIN THE WORD SANDWICH BACKGROUND_PAGE EXPERIMENTAL CHROME.EXPERIMENTAL.INFOBARS.SHOW CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST",
"source_files": [
- "background.html",
- "contentscript.js",
- "infobar.html",
+ "background.html",
+ "contentscript.js",
+ "infobar.html",
"manifest.json"
- ],
- "source_hash": "890d698634e5228ef7da8ffca3008f843b9a7cab",
+ ],
+ "source_hash": "890d698634e5228ef7da8ffca3008f843b9a7cab",
"zip_path": "examples/api/infobars/sandwichbar.zip"
- },
+ },
{
"api_calls": [
- "chrome.experimental.processes.getProcessIdForTab",
- "chrome.tabs.get",
- "chrome.tabs.getSelected",
- "chrome.tabs.update",
- "chrome.windows.get",
- "chrome.windows.getAll",
- "chrome.windows.getCurrent",
+ "chrome.experimental.processes.getProcessIdForTab",
+ "chrome.tabs.get",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.update",
+ "chrome.windows.get",
+ "chrome.windows.getAll",
+ "chrome.windows.getCurrent",
"chrome.windows.update"
- ],
- "description": "Adds a browser action showing which tabs share the current tab's process.",
+ ],
+ "description": "Adds a browser action showing which tabs share the current tab's process.",
"features": [
- "browser_action",
- "experimental",
- "popup",
+ "browser_action",
+ "experimental",
+ "popup",
"tabs"
- ],
- "icon": null,
- "id": "fc89b35755483af30b66cd72cefa34a43a3e8312",
- "name": "Show Tabs in Process",
- "path": "examples/api/processes/show_tabs/",
- "protocols": [],
- "search_string": "SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE",
+ ],
+ "icon": null,
+ "id": "fc89b35755483af30b66cd72cefa34a43a3e8312",
+ "name": "Show Tabs in Process",
+ "path": "examples/api/processes/show_tabs/",
+ "protocols": [],
+ "search_string": "SHOW TABS IN PROCESS ADDS A BROWSER ACTION SHOWING WHICH TABS SHARE THE CURRENT TABS PROCESS. BROWSER_ACTION EXPERIMENTAL POPUP TABS CHROME.EXPERIMENTAL.PROCESSES.GETPROCESSIDFORTAB CHROME.TABS.GET CHROME.TABS.GETSELECTED CHROME.TABS.UPDATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.UPDATE",
"source_files": [
- "manifest.json",
+ "manifest.json",
"popup.html"
- ],
- "source_hash": "c9818c3c4c2e4fae0a7cc29588514e050356fd52",
+ ],
+ "source_hash": "c9818c3c4c2e4fae0a7cc29588514e050356fd52",
"zip_path": "examples/api/processes/show_tabs.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.extension.getURL",
- "chrome.tabs.create",
- "chrome.tabs.get",
- "chrome.tabs.getAllInWindow",
- "chrome.tabs.getSelected",
- "chrome.tabs.move",
- "chrome.tabs.onAttached",
- "chrome.tabs.onCreated",
- "chrome.tabs.onDetached",
- "chrome.tabs.onMoved",
- "chrome.tabs.onRemoved",
- "chrome.tabs.onSelectionChanged",
- "chrome.tabs.onUpdated",
- "chrome.tabs.remove",
- "chrome.tabs.update",
- "chrome.windows.create",
- "chrome.windows.get",
- "chrome.windows.getAll",
- "chrome.windows.getCurrent",
- "chrome.windows.getLastFocused",
- "chrome.windows.onCreated",
- "chrome.windows.onFocusChanged",
- "chrome.windows.onRemoved",
- "chrome.windows.remove",
+ "chrome.browserAction.onClicked",
+ "chrome.extension.getURL",
+ "chrome.tabs.create",
+ "chrome.tabs.get",
+ "chrome.tabs.getAllInWindow",
+ "chrome.tabs.getSelected",
+ "chrome.tabs.move",
+ "chrome.tabs.onAttached",
+ "chrome.tabs.onCreated",
+ "chrome.tabs.onDetached",
+ "chrome.tabs.onMoved",
+ "chrome.tabs.onRemoved",
+ "chrome.tabs.onSelectionChanged",
+ "chrome.tabs.onUpdated",
+ "chrome.tabs.remove",
+ "chrome.tabs.update",
+ "chrome.windows.create",
+ "chrome.windows.get",
+ "chrome.windows.getAll",
+ "chrome.windows.getCurrent",
+ "chrome.windows.getLastFocused",
+ "chrome.windows.onCreated",
+ "chrome.windows.onFocusChanged",
+ "chrome.windows.onRemoved",
+ "chrome.windows.remove",
"chrome.windows.update"
- ],
- "description": "Utility for working with the extension tabs api",
+ ],
+ "description": "Utility for working with the extension tabs api",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64",
- "name": "Tab Inspector",
- "path": "examples/api/tabs/inspector/",
- "protocols": [],
- "search_string": "TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE",
+ ],
+ "icon": null,
+ "id": "230463f2d5c3d4d0ca13c230e1f00f2aae0a8a64",
+ "name": "Tab Inspector",
+ "path": "examples/api/tabs/inspector/",
+ "protocols": [],
+ "search_string": "TAB INSPECTOR UTILITY FOR WORKING WITH THE EXTENSION TABS API BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.TABS.CREATE CHROME.TABS.GET CHROME.TABS.GETALLINWINDOW CHROME.TABS.GETSELECTED CHROME.TABS.MOVE CHROME.TABS.ONATTACHED CHROME.TABS.ONCREATED CHROME.TABS.ONDETACHED CHROME.TABS.ONMOVED CHROME.TABS.ONREMOVED CHROME.TABS.ONSELECTIONCHANGED CHROME.TABS.ONUPDATED CHROME.TABS.REMOVE CHROME.TABS.UPDATE CHROME.WINDOWS.CREATE CHROME.WINDOWS.GET CHROME.WINDOWS.GETALL CHROME.WINDOWS.GETCURRENT CHROME.WINDOWS.GETLASTFOCUSED CHROME.WINDOWS.ONCREATED CHROME.WINDOWS.ONFOCUSCHANGED CHROME.WINDOWS.ONREMOVED CHROME.WINDOWS.REMOVE CHROME.WINDOWS.UPDATE",
"source_files": [
- "background.html",
- "jstemplate_compiled.js",
- "manifest.json",
+ "background.html",
+ "jstemplate_compiled.js",
+ "manifest.json",
"tabs_api.html"
- ],
- "source_hash": "3076b39a4302d8e86f456e6d7367129187cce0c0",
+ ],
+ "source_hash": "3076b39a4302d8e86f456e6d7367129187cce0c0",
"zip_path": "examples/api/tabs/inspector.zip"
- },
+ },
{
"api_calls": [
- "chrome.browserAction.onClicked",
- "chrome.extension.getURL",
- "chrome.extension.getViews",
- "chrome.tabs.captureVisibleTab",
- "chrome.tabs.create",
+ "chrome.browserAction.onClicked",
+ "chrome.extension.getURL",
+ "chrome.extension.getViews",
+ "chrome.tabs.captureVisibleTab",
+ "chrome.tabs.create",
"chrome.tabs.onUpdated"
- ],
- "description": "Demonstrate screenshot functionality in the chrome.tabs api.",
+ ],
+ "description": "Demonstrate screenshot functionality in the chrome.tabs api.",
"features": [
- "background_page",
- "browser_action",
+ "background_page",
+ "browser_action",
"tabs"
- ],
- "icon": null,
- "id": "e1697cacebad05218798bf3e8a0f724517f0e8c3",
- "name": "Test Screenshot Extension",
- "path": "examples/api/tabs/screenshot/",
- "protocols": [],
- "search_string": "TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED",
+ ],
+ "icon": null,
+ "id": "e1697cacebad05218798bf3e8a0f724517f0e8c3",
+ "name": "Test Screenshot Extension",
+ "path": "examples/api/tabs/screenshot/",
+ "protocols": [],
+ "search_string": "TEST SCREENSHOT EXTENSION DEMONSTRATE SCREENSHOT FUNCTIONALITY IN THE CHROME.TABS API. BACKGROUND_PAGE BROWSER_ACTION TABS CHROME.BROWSERACTION.ONCLICKED CHROME.EXTENSION.GETURL CHROME.EXTENSION.GETVIEWS CHROME.TABS.CAPTUREVISIBLETAB CHROME.TABS.CREATE CHROME.TABS.ONUPDATED",
"source_files": [
- "background.html",
- "manifest.json",
- "screenshot.html",
+ "background.html",
+ "manifest.json",
+ "screenshot.html",
"screenshot.js"
- ],
- "source_hash": "6be9b92850e86ce311cc12a2cf0cda3b47ab5d58",
+ ],
+ "source_hash": "6be9b92850e86ce311cc12a2cf0cda3b47ab5d58",
"zip_path": "examples/api/tabs/screenshot.zip"
- },
+ },
{
"api_calls": [
- "chrome.history.getVisits",
- "chrome.history.search",
+ "chrome.history.getVisits",
+ "chrome.history.search",
"chrome.tabs.create"
- ],
- "description": "Reads your history, and shows the top ten pages you go to by typing the URL.",
+ ],
+ "description": "Reads your history, and shows the top ten pages you go to by typing the URL.",
"features": [
- "browser_action",
- "history",
+ "browser_action",
+ "history",
"tabs"
- ],
- "icon": null,
- "id": "b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6",
- "name": "Typed URL History",
- "path": "examples/api/history/showHistory/",
- "protocols": [],
- "search_string": "TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE",
+ ],
+ "icon": null,
+ "id": "b3de91ab04b7d7a2670ca7ee9d740eb42cead0b6",
+ "name": "Typed URL History",
+ "path": "examples/api/history/showHistory/",
+ "protocols": [],
+ "search_string": "TYPED URL HISTORY READS YOUR HISTORY, AND SHOWS THE TOP TEN PAGES YOU GO TO BY TYPING THE URL. BROWSER_ACTION HISTORY TABS CHROME.HISTORY.GETVISITS CHROME.HISTORY.SEARCH CHROME.TABS.CREATE",
"source_files": [
- "manifest.json",
- "typedUrls.html",
+ "manifest.json",
+ "typedUrls.html",
"typedUrls.js"
- ],
- "source_hash": "72d5c3586feefc692c63039ce8bdb5f9d366c0e2",
+ ],
+ "source_hash": "72d5c3586feefc692c63039ce8bdb5f9d366c0e2",
"zip_path": "examples/api/history/showHistory.zip"
+ },
+ {
+ "api_calls": [
+ "chrome.experimental.webNavigation.onBeforeNavigate",
+ "chrome.experimental.webNavigation.onBeforeRetarget",
+ "chrome.experimental.webNavigation.onCommitted",
+ "chrome.experimental.webNavigation.onCompleted",
+ "chrome.experimental.webNavigation.onErrorOccurred",
+ "chrome.extension.onRequest",
+ "chrome.extension.sendRequest",
+ "chrome.i18n.getMessage"
+ ],
+ "description": "Demonstration of the WebNavigation extension API.",
+ "features": [
+ "background_page",
+ "browser_action",
+ "experimental",
+ "extension",
+ "popup",
+ "webNavigation"
+ ],
+ "icon": null,
+ "id": "a3c674f7eb93621c590562ad3fa04de4f03f53a0",
+ "name": "WebNavigation Tech Demo",
+ "path": "examples/api/webNavigation/basic/",
+ "protocols": [],
+ "search_string": "WEBNAVIGATION TECH DEMO DEMONSTRATION OF THE WEBNAVIGATION EXTENSION API. BACKGROUND_PAGE BROWSER_ACTION EXPERIMENTAL EXTENSION POPUP WEBNAVIGATION CHROME.EXPERIMENTAL.WEBNAVIGATION.ONBEFORENAVIGATE CHROME.EXPERIMENTAL.WEBNAVIGATION.ONBEFORERETARGET CHROME.EXPERIMENTAL.WEBNAVIGATION.ONCOMMITTED CHROME.EXPERIMENTAL.WEBNAVIGATION.ONCOMPLETED CHROME.EXPERIMENTAL.WEBNAVIGATION.ONERROROCCURRED CHROME.EXTENSION.ONREQUEST CHROME.EXTENSION.SENDREQUEST CHROME.I18N.GETMESSAGE",
+ "source_files": [
+ "_locales/en/messages.json",
+ "background.html",
+ "manifest.json",
+ "navigation_collector.js",
+ "popup.html"
+ ],
+ "source_hash": "efa16032a02c474f9c9bafb90a964fd57c667ea2",
+ "zip_path": "examples/api/webNavigation/basic.zip"
+ },
+ {
+ "api_calls": [
+ "chrome.extension.isAllowedFileSchemeAccess",
+ "chrome.extension.isAllowedIncognitoAccess"
+ ],
+ "description": "Demonstrates the `extension.isAllowed???Access` APIs",
+ "features": [
+ "browser_action"
+ ],
+ "icon": "sample-128.png",
+ "id": "0fa4abe6545f0316fea7cfa07c53aa48c4f3d018",
+ "name": "`extension.isAllowed???Access` Example",
+ "path": "examples/api/extension/isAllowedAccess/",
+ "protocols": [
+ "file://"
+ ],
+ "search_string": "`EXTENSION.ISALLOWED???ACCESS` EXAMPLE DEMONSTRATES THE `EXTENSION.ISALLOWED???ACCESS` APIS BROWSER_ACTION CHROME.EXTENSION.ISALLOWEDFILESCHEMEACCESS CHROME.EXTENSION.ISALLOWEDINCOGNITOACCESS",
+ "source_files": [
+ "manifest.json",
+ "popup.html",
+ "sample.css"
+ ],
+ "source_hash": "c8bfc2b60f25c24dc3c5aaf75dd635c9419df66d",
+ "zip_path": "examples/api/extension/isAllowedAccess.zip"
}
]
} \ No newline at end of file
diff --git a/chrome/common/extensions/docs/static/api_index.html b/chrome/common/extensions/docs/static/api_index.html
index 3273f08..60b98e2 100644
--- a/chrome/common/extensions/docs/static/api_index.html
+++ b/chrome/common/extensions/docs/static/api_index.html
@@ -20,21 +20,24 @@ Here are the supported chrome.* APIs:
<h2 id="experimental">Experimental APIs</h2>
<p>
-Google Chrome also has some
+Google Chrome also has
<a href="experimental.html">experimental APIs</a>,
-which give you access to
-functionality such as process information and history.
+some of which will become supported APIs
+in future releases of Chrome.
</p>
<h2 id="conventions">API conventions</h2>
<p>
Unless the doc says otherwise,
-methods in the chrome.* APIs are asynchronous:
+methods in the chrome.* APIs are <b>asynchronous</b>:
they return immediately,
without waiting for the operation to finish.
If you need to know the outcome of an operation,
then you pass a callback function into the method.
-For more information, see the video
-<a href="http://www.youtube.com/watch?v=bmxr75CV36A&feature=PlayList&p=CA101D6A85FE9D4B&index=2">Extension API Design</a>.
+For more information, watch this video:
+</p>
+
+<p>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/bmxr75CV36A?rel=0" frameborder="0" allowfullscreen></iframe>
</p>
diff --git a/chrome/common/extensions/docs/static/apps.html b/chrome/common/extensions/docs/static/apps.html
index 2cf3944..394dfae 100644
--- a/chrome/common/extensions/docs/static/apps.html
+++ b/chrome/common/extensions/docs/static/apps.html
@@ -53,12 +53,14 @@ instead of a hosted app if any of the following are true:
</ul>
<p>
-The following articles can help you understand
+To learn more about
the differences between web apps and websites,
-extensions and packaged apps, and packaged apps and hosted apps:
+extensions and packaged apps, and packaged apps and hosted apps,
+read these:
</p>
<ul>
+ <li> <a href="http://code.google.com/chrome/webstore/docs/choosing.html">Choosing an App Type</a> </li>
<li> <a href="http://code.google.com/chrome/apps/articles/thinking_in_web_apps.html">Thinking in Web Apps</a> </li>
<li> <a href="http://code.google.com/chrome/webstore/articles/apps_vs_extensions.html">Extensions, Packaged Apps, and Hosted Apps in the Chrome Web Store</a> </li>
</ul>
@@ -88,11 +90,7 @@ Here is a typical manifest for a packaged app:
"icons": {
"16": "icon_16.png",
"128": "icon_128.png"
- },
- "permissions": [
- "unlimitedStorage",
- "notifications"
- ]
+ }
}
</pre>
diff --git a/chrome/common/extensions/docs/static/bookmarks.html b/chrome/common/extensions/docs/static/bookmarks.html
index 04a4376..8e9ecd5 100644
--- a/chrome/common/extensions/docs/static/bookmarks.html
+++ b/chrome/common/extensions/docs/static/bookmarks.html
@@ -30,8 +30,8 @@ For example:</p>
<p>
Bookmarks are organized in a tree,
where each node in the tree
-is either a bookmark or a group
-(a folder that can contain nodes).
+is either a bookmark or a folder
+(sometimes called a <em>group</em>).
Each node in the tree
is represented by a
<a href="#type-BookmarkTreeNode"><code>BookmarkTreeNode</code></a> object.
@@ -49,6 +49,9 @@ See <a href="#type-BookmarkTreeNode"><code>BookmarkTreeNode</code></a>
for information about the properties a node can have.
</p>
+<p class="note"><b>Note:</b> You cannot use this API to add or remove entries
+in the root folder. You also cannot rename, move, or remove the special
+"Bookmarks Bar" and "Other Bookmarks" folders.</p>
<h2 id="overview-examples">Examples</h2>
diff --git a/chrome/common/extensions/docs/static/content_scripts.html b/chrome/common/extensions/docs/static/content_scripts.html
index 9cbf0c3..d5d210a 100644
--- a/chrome/common/extensions/docs/static/content_scripts.html
+++ b/chrome/common/extensions/docs/static/content_scripts.html
@@ -434,7 +434,7 @@ The first video describes content scripts and isolated worlds.
</p>
<p>
-<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/laLudeUmXHM&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/laLudeUmXHM&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/laLudeUmXHM?rel=0" frameborder="0" allowfullscreen></iframe>
</p>
<p>
@@ -444,5 +444,5 @@ sending a request to its parent extension.
</p>
<p>
-<object width="560" height="340"><param name="movie" value="http://www.youtube.com/v/B4M_a7xejYI&hl=en_US&fs=1&"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/B4M_a7xejYI&hl=en_US&fs=1&" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="560" height="340"></embed></object>
+<iframe title="YouTube video player" width="640" height="390" src="http://www.youtube.com/embed/B4M_a7xejYI?rel=0" frameborder="0" allowfullscreen></iframe>
</p>
diff --git a/chrome/common/extensions/docs/static/docs.html b/chrome/common/extensions/docs/static/docs.html
index 5dafa68..df0b761 100644
--- a/chrome/common/extensions/docs/static/docs.html
+++ b/chrome/common/extensions/docs/static/docs.html
@@ -5,8 +5,7 @@ This documentation tells you how to write extensions
and packaged apps for the
<a href="http://www.google.com/chrome">Google Chrome browser</a>.
Because extensions came first,
-the APIs and these docs say <em>extension</em> everywhere,
-even though almost everything applies to packaged apps, as well.
+the APIs and these docs say <em>extension</em> everywhere.
</p>
<p class="caution">
diff --git a/chrome/common/extensions/docs/static/experimental.debugger.html b/chrome/common/extensions/docs/static/experimental.debugger.html
new file mode 100644
index 0000000..1794647
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.debugger.html
@@ -0,0 +1,24 @@
+<!-- BEGIN AUTHORED CONTENT -->
+
+
+<h2>Notes</h2>
+
+<p>
+Debugger API exposes Google Chrome debugging interface to the extensions.
+Debugging messages that are being sent and received are all JSON objects
+with the structure defined by the Developer Tools / Web Inspector Protocol.
+We are currently drafting this protocol, it is by no means ready and stable,
+but we can already expose the way to attach to a given tab and instrument it.
+Although not finalized, this API is feature rich. There is a proof of concept
+implementation of the Chrome Developer Tools front-end running as an extension
+using the debugger API.
+</p>
+
+<p>
+Note that attaching to the page by means of the debugger API and using embedded
+Chrome Developer Tools with it are mutually exclusive. If extension is attached
+to the page and user invokes Developer Tools, debugging session is being
+terminated. Extension can then re-establish it via attaching to a tab later.
+</p>
+
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/experimental.webInspector.audits.html b/chrome/common/extensions/docs/static/experimental.webInspector.audits.html
new file mode 100644
index 0000000..edd46f1
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webInspector.audits.html
@@ -0,0 +1,65 @@
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.audits</code> module to add new audit
+categories and rules to WebInspector's Audit panel.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API</a>.
+</p>
+
+<h2>Notes</h2>
+
+<p>
+Each audit category is represented by a line on <em>Select audits to run</em>
+screen in the Audits panel. The following example adds a category named
+<em>Readability</em>:</p>
+<pre>
+var category = webInspector.audits.addCategory("Readability", 2);
+</pre>
+<img src="images/devtools-audits-category.png"
+ style="margin-left: 20px"
+ width="489" height="342"
+ alt="Extension audit category on the launch screen of Audits panel" />
+<p>
+If the category's checkbox is checked, the <code>onAuditStarted</code> event of
+that category will be fired when user clicks the <em>Run</em> button.
+</p>
+<p>The event handler in your extension receives <code>AuditResults</code>
+as an argument and should add one or more results using <code>addResult()</code>
+method. This may be done asynchronously, i.e. after the handler returns. The
+run of the category is considered to be complete once the extension adds the
+number of results declared when adding the category with
+<code>experimental.webInspector.audits.addCategory()</code> or
+calls AuditResult's <code>done()</code> method.
+</p>
+<p>The results may include additional details visualized as an expandable
+tree by the Audits panel. You may build the details tree using
+<code>createResult()</code> and <code>addChild()</code> methods. The child node
+may include specially formatted fragments created by
+<code>auditResults.snippet()</code> or <code>auditResults.url()</code>.
+</p>
+The following example adds a handler for onAuditStarted event that creates two
+audit results and populates one of them with the additional details:
+
+<pre>
+category.onAuditStarted.addListener(function(results) {
+ var details = results.createResult("Details...");
+ var styles = details.addChild("2 styles with small font");
+ var elements = details.addChild("3 elements with small font");
+
+ results.addResult("Font Size (5)",
+ "5 elements use font size below 10pt",
+ results.Severity.Severe,
+ details);
+ results.addResult("Contrast",
+ "Text should stand out from background",
+ results.Severity.Info);
+});
+</pre>
+<p>The audit result tree produced by the snippet above will look like this:
+</p>
+<img src="images/devtools-audits-results.png"
+ style="margin-left: 20px"
+ width="330" height="169"
+ alt="Audit results example" />
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/experimental.webInspector.html b/chrome/common/extensions/docs/static/experimental.webInspector.html
new file mode 100644
index 0000000..cd34927
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webInspector.html
@@ -0,0 +1,77 @@
+<div id="pageData-name" class="pageData">experimental.webInspector.* APIs</div>
+
+<p>
+The following API modules provide support for extending
+Chrome Development Tools (aka WebInspector):
+</p>
+
+<a name="api-list"></a>
+<ul>
+ <li jsselect="webInspectorAPIs();">
+ <a jsvalues=".href: $this + '.html'" jscontent="$this"></a></li>
+</ul>
+
+<p class="warning">
+<b>Caution:</b>
+Don't depend on these experimental APIs. They might disappear, and they
+<em>will</em> change.
+Also, the Chrome Developer Dashboard doesn't allow you to
+upload extensions that use experimental APIs.
+</p>
+
+<h2 id="using">How to use WebInspector APIs</h2>
+
+<ol>
+ <li>
+ WebInspector APIs are currently experimental, so please start with
+ <a href="experimental.html">the steps for using experimental extension
+ APIs</a>.
+ </li>
+ <li>
+ Specify the "devtools_page" field in your extension's manifest and make
+ sure you have "experimental" permission:
+<pre>
+{
+ "name": ...
+ "version": "1.0",
+ "minimum_chrome_version": "10.0",
+ <b>"devtools_page": "devtools.html"</b>,
+ "permissions": [ <b>"experimental"</b> ... ],
+ ...
+}
+</pre>
+ </li>
+ <li>
+ An instance of the devtools_page specified in your extension's manifest
+ will be created for every Developer Tools window opened. The page may add
+ other extension pages as panels and sidebars to the Developer Tools window
+ using <a href="experimental.webInspector.panels"
+ >experimental.webInspector.panels</a>
+ API.
+ </li>
+ <li>The APIs available to extension pages within the Developer Tools
+ window include all <a href="#api-list">experimental.webInspector modules
+ listed above</a> and <a href="extension.html">chrome.extension</a> API.
+ Other extension APIs are not available to the Developer Tools pages, but
+ you may invoke them by sending a request to the background page of your
+ extension, similarly to how it's done in the
+ <a href="overview.html#contentScripts">content scripts</a>.
+ <li>Please note that, unlike other Chrome Extension APIs, the WebInspector
+ APIs lack "chrome" prefix. This is because the APIs, as the WebInspector
+ itself, are a part of WebKit and may eventually appear in other browsers.
+ </li>
+ <li>
+ <a href="http://groups.google.com/group/google-chrome-developer-tools/topics"
+ >Give us feedback!</a>
+ Your comments and suggestions help us improve the APIs and decide which
+ ones should move from experimental to supported.
+ </li>
+</ol>
+
+<h2 id="other">More information</h2>
+
+<p>
+For information on the standard APIs that extensions can use, see
+<a href="api_index.html">chrome.* APIs</a> and
+<a href="api_other.html">Other APIs</a>.
+</p>
diff --git a/chrome/common/extensions/docs/static/experimental.webInspector.panels.html b/chrome/common/extensions/docs/static/experimental.webInspector.panels.html
new file mode 100644
index 0000000..9c719eb
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webInspector.panels.html
@@ -0,0 +1,50 @@
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.panels</code> module to integrate your
+extension into Developer Tools window UI: create your own panels, access
+existing panels and add sidebars.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API</a>.
+</p>
+
+<h2>Notes</h2>
+
+<p>
+Each extension panel and sidebar is displayed as a separate HTML page. All
+extension pages displayed in the Developer Tools window have access to all
+modules in <code>experimental.webInspector</code> API, as well as to
+<a href="extension.html">chrome.extension</a> API. Other extension APIs are not
+available to the pages within Developer Tools window, but you may invoke them
+by sending a request to the background page of your extension, similarly to how
+it's done in the <a href="overview.html#contentScripts">content scripts</a>.
+</p>
+
+<h2 id="overview-examples">Examples</h2>
+<p>The following code adds a panel contained in <code>Panel.html</code>,
+represented by <code>FontPicker.png</code> on the Developer Tools toolbar
+and labeled as <em>Font Picker</em>:</p>
+
+<pre>
+webInspector.panels.create("Font Picker", "FontPicker.png", "Panel.html");
+</pre>
+<p>The following code adds a sidebar pane contained in
+<code>Sidebar.html</code> and titled <em>Font Properties</em> to the Elements
+panel, then sets its height to <code>8ex</code>:
+<pre>
+webInspector.panels.elements.createSidebarPane("Font Properties", "Sidebar.html",
+ function(sidebar) {
+ sidebar.setHeight("8ex");
+ }
+}));
+</pre>
+<p>
+This screenshot demonstrates the effect the above examples would have on
+Developer Tools window:
+
+<img src="images/devtools-panels.png"
+ style="margin-left: 20px"
+ width="686" height="289"
+ alt="Extension icon panel on DevTools toolbar" />
+</p>
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/experimental.webInspector.resources.html b/chrome/common/extensions/docs/static/experimental.webInspector.resources.html
new file mode 100644
index 0000000..1d88718
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webInspector.resources.html
@@ -0,0 +1,44 @@
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>experimental.webInspector.resources</code> module to retrieve the
+information about network resources displayed by DevTools' Network panel.
+</p><p>
+See <a href="experimental.webInspector.html">WebInspector API summary</a> for
+general introduction to using WebInspector API</a>.
+</p>
+
+<h2>Notes</h2>
+
+<p>
+Network resource information is represented in HTTP Archive format
+(<em>HAR</em>). The description of HAR is outside of scope of this document,
+please refer to
+<a href=
+"http://groups.google.com/group/http-archive-specification/web/har-1-2-spec">
+HAR v1.2 Specification</a>.
+</p><p>
+In terms of HAR, the <code>webInspector.resources.getHAR()</code> method
+returns entire <em>HAR log</em>, while
+<code>webInspector.resources.onFinish</code> event provides <em>HAR entry</em>
+as an argument to the event callback.
+</p>
+<p>Note that resource content is not provided as part of HAR for efficieny
+reasons. You may call resource's <code>getContent()</code> method to retrieve
+content.
+<p>Some resources may be missing in the array of entries returned by <code>
+getHAR()</code> in case WebInspector was opened after the page was loaded &mdash;
+reload the page to get all resources. In general, the list of resources returned
+by <code>getHAR()</code> should match that displayed by the Network panel.
+<h2 id="overview-examples">Examples</h2>
+
+<p>The following code logs URLs of all images larger than 40KB as they are
+loaded:</p>
+
+<pre>
+experimental.webInspector.resources.onFinished.addListener(function(resource) {
+ if (resource.response.bodySize > 40*1024)
+ webInspector.log("Large image: " + resource.request.url);
+});
+</pre>
+
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/experimental.webNavigation.html b/chrome/common/extensions/docs/static/experimental.webNavigation.html
new file mode 100644
index 0000000..3f214ad
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webNavigation.html
@@ -0,0 +1,23 @@
+<div id="pageData-name" class="pageData">WebNavigation API</div>
+
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>chrome.experimental.webNavigation</code> module to recieve
+notifications about the status of navigations requests in-flight. This
+module is still very much experimental. For information on how to use
+experimental APIs, see the <a href="experimental.html">chrome.experimental.*
+APIs</a> page.
+</p>
+
+<h2>A note about timestamps</h2>
+<p>
+It's important to note that some technical oddities in the OS's handling
+of distinct Chrome processes can cause the clock to be skewed between the
+browser itself and extension processes. That means that WebNavigation's events'
+<code>timeStamp</code> property is only guaranteed to be <i>internally</i>
+consistent. Comparing one event to another event will give you the correct
+offset between them, but comparing them to the current time inside the
+extension (via <code>(new Date()).getTime()</code>, for instance) might give
+unexpected results.
+</p>
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/experimental.webRequest.html b/chrome/common/extensions/docs/static/experimental.webRequest.html
new file mode 100644
index 0000000..43cb6b1
--- /dev/null
+++ b/chrome/common/extensions/docs/static/experimental.webRequest.html
@@ -0,0 +1,22 @@
+<div id="pageData-name" class="pageData">WebRequest API</div>
+
+<!-- BEGIN AUTHORED CONTENT -->
+<p id="classSummary">
+Use the <code>chrome.experimental.webRequest</code> module to intercept, block,
+or modify requests in-flight. This module is still very much experimental. For
+information on how to use experimental APIs, see the
+<a href="experimental.html">chrome.experimental.* APIs</a> page.
+</p>
+
+<h2>A note about timestamps</h2>
+<p>
+It's important to note that some technical oddities in the OS's handling
+of distinct Chrome processes can cause the clock to be skewed between the
+browser itself and extension processes. That means that WebRequest's events'
+<code>timeStamp</code> property is only guaranteed to be <i>internally</i>
+consistent. Comparing one event to another event will give you the correct
+offset between them, but comparing them to the current time inside the
+extension (via <code>(new Date()).getTime()</code>, for instance) might give
+unexpected results.
+</p>
+<!-- END AUTHORED CONTENT -->
diff --git a/chrome/common/extensions/docs/static/i18n.html b/chrome/common/extensions/docs/static/i18n.html
index abe5c9e..0635545 100644
--- a/chrome/common/extensions/docs/static/i18n.html
+++ b/chrome/common/extensions/docs/static/i18n.html
@@ -293,8 +293,8 @@ padding-right: 1.5em;
<h2 id="overview-locales">Locales</h2>
<p>
-Extensions can use all the locales that Google Chrome supports,
-plus a few (such as <code>en</code>)
+You can choose from many locales,
+including some (such as <code>en</code>)
that let a single translation support multiple variations of a language
(such as <code>en_GB</code> and <code>en_US</code>).
</p>
@@ -303,12 +303,8 @@ that let a single translation support multiple variations of a language
<h3 id="locales-supported">Supported locales</h3>
<p>
-Your extension can use any of the following locales:
-</p>
-
-<p>
-<code>am ar bg bn ca cs da de el en en_GB en_US es es_419 et fi fil fr gu he hi hr hu id it ja kn ko lt
-lv ml mr nb nl or pl pt pt_BR pt_PT ro ru sk sl sr sv sw ta te th tr uk vi zh zh_CN zh_TW</code>
+Extensions can use any of the
+<a href="http://code.google.com/chrome/webstore/docs/i18n.html#localeTable">locales that the Chrome Web Store supports</a>.
</p>
diff --git a/chrome/common/extensions/docs/static/index.html b/chrome/common/extensions/docs/static/index.html
index 079e37f..b72a91f 100644
--- a/chrome/common/extensions/docs/static/index.html
+++ b/chrome/common/extensions/docs/static/index.html
@@ -110,7 +110,7 @@ For more information, see the
</p>
<p>
-<object width="300" height="250"><param name="movie" value="http://www.youtube.com/p/38DF05697DE372B1&amp;hl=en_US&amp;fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/p/38DF05697DE372B1&amp;hl=en_US&amp;fs=1" type="application/x-shockwave-flash" width="300" height="250" allowscriptaccess="always" allowfullscreen="true"></embed></object>
+<iframe title="YouTube video player" width="300" height="199" src="http://www.youtube.com/embed/wRDPTnY3yO8?rel=0" frameborder="0" allowfullscreen></iframe>
</p>
</td>
</tr>
diff --git a/chrome/common/extensions/docs/static/override.html b/chrome/common/extensions/docs/static/override.html
index 83bbd5d..93f1c85 100644
--- a/chrome/common/extensions/docs/static/override.html
+++ b/chrome/common/extensions/docs/static/override.html
@@ -1,3 +1,6 @@
+<div id="pageData-name" class="pageData">Override Pages</div>
+<div id="pageData-showTOC" class="pageData">true</div>
+
<style>
#pics {
margin:2em 1em 1.5em;
@@ -18,9 +21,6 @@
}
</style>
-<div id="pageData-title" class="pageData">Override Pages</div>
-<div id="pageData-showTOC" class="pageData">true</div>
-
<p>
Override pages are a way to substitute an HTML file from your extension
for a page that Google Chrome normally provides.
@@ -60,19 +60,23 @@ An extension can replace any one of the following pages:
<p class="note">
<b>Note:</b>
A single extension can override
-only one page.
+<b>only one page</b>.
+For example, an extension can't override both
+the Bookmark Manager and History pages.
</p>
-<p class="note">
-<b>Note:</b>
-If you want to override the page in incognito windows as well, make sure to
-specify "spanning" mode for the <a href="manifest.html#incognito">incognito</a>
-manifest property.
-</p>
-
-<p class="note">
-<b>Note:</b>
-You cannot override the New Tab page in incognito windows.
+<p>
+Incognito windows are treated specially.
+New Tab pages cannot be overridden in incognito windows.
+Other override pages work in incognito windows
+as long as the
+<a href="manifest.html#incognito">incognito</a>
+manifest property is set to "spanning"
+(which is the default value for extensions
+but not for packaged apps).
+See <a href="overview.html#incognito">Saving data and incognito mode</a>
+in the Overview for more details on how you should treat
+incognito windows.
</p>
<p>
@@ -178,12 +182,6 @@ For an effective override page, follow these guidelines:
<h2 id="examples"> Examples </h2>
<p>
-You can find simple examples of defining override pages in the
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/override/">examples/api/override</a>
-directory.
-For other examples and for help in viewing the source code, see
-<a href="samples.html">Samples</a>.
+See the
+<a href="samples.html#chrome_url_overrides">override samples</a>.
</p>
-
-
-<!-- [PENDING: Maybe have a gallery of NTPs?] -->
diff --git a/chrome/common/extensions/docs/static/overview.html b/chrome/common/extensions/docs/static/overview.html
index 98ab568..dabc217 100644
--- a/chrome/common/extensions/docs/static/overview.html
+++ b/chrome/common/extensions/docs/static/overview.html
@@ -53,19 +53,19 @@ depending on the page.
<table class="columns">
<tr>
- <td>
- <img src="images/index/gmail.png"
- width="150" height="79"
+ <td width="33%">
+ <img src="images/overview/browser-action.png"
+ width="147" height="100"
alt="screenshot" />
</td>
- <td>
- <img src="images/index/news.png"
- width="150" height="79"
+ <td width="33%">
+ <img src="images/overview/page-action.png"
+ width="147" height="100"
alt="screenshot" />
</td>
<td>
- <img src="images/index/rss.png"
- width="150" height="79"
+ <img src="images/overview/browser-action-with-popup.png"
+ width="147" height="100"
alt="screenshot" />
</td>
</tr>
@@ -77,18 +77,18 @@ depending on the page.
(icon in the toolbar).
</td>
<td>
- This <a href="samples.html#news">news reader extension</a>
- features a browser action that,
- when clicked,
- shows a <em>popup</em>.
- </td>
- <td>
This <a href="samples.html#mappy">map extension</a>
uses a <em>page action</em>
(icon in the address bar)
and <em>content script</em>
(code injected into a web page).
</td>
+ <td>
+ This <a href="samples.html#news">news extension</a>
+ features a browser action that,
+ when clicked,
+ shows a <em>popup</em>.
+ </td>
</tr>
</table>
@@ -113,7 +113,7 @@ For example, the following packaged app
displays a Flash file within an HTML page.
</p>
-<img src="images/index/flashapp.png"
+<img src="images/overview/flash-app.png"
width="372" height="300"
alt="screenshot" />
@@ -223,40 +223,91 @@ For details, see
<h2 id="arch">Architecture</h2>
<p>
-Most extensions have a
-<a href="background_pages.html">background page</a>,
+Many extensions have a <em>background page</em>,
an invisible page
that holds the main logic of the extension.
+An extension can also contain other pages
+that present the extension's UI.
+If an extension needs to interact with web pages that the user loads
+(as opposed to pages that are included in the extension),
+then the extension must use a content script.
</p>
-<img src="images/arch-1.gif"
- width="232" height="168"
- alt="Two windows and a box representing a background page (background.html). One window has a yellow icon; the other has both a yellow icon and a blue icon. The yellow icons are connected to the background page." />
+
+<h3 id="background_page">The background page</h3>
<p>
-The preceding figure shows a browser
+The following figure shows a browser
that has at least two extensions installed:
a browser action (yellow icon)
and a page action (blue icon).
-The browser action's background page,
-which is defined by an HTML file
-(<code>background.html</code>),
-has JavaScript code that controls
+Both the browser action and the page action
+have background pages defined by HTML files.
+This figure shows the browser action's background page,
+which is defined by <code>background.html</code>
+and has JavaScript code that controls
the behavior of the browser action in both windows.
</p>
+<img src="images/overview/arch-1.gif"
+ width="232" height="168"
+ alt="Two windows and a box representing a background page (background.html). One window has a yellow icon; the other has both a yellow icon and a blue icon. The yellow icons are connected to the background page." />
+
+<p>
+Although background pages can be useful,
+don't use one if you don't need it.
+Background pages are always open,
+so when a user installs many extensions that have background pages,
+Chrome's performance can suffer.
+</p>
+
+<!-- PENDING: Perhaps show a picture of many background page processes.
+ This could build on a figure that shows the process architecture,
+ and perhaps the differences between packaged apps and extensions. -->
+
+<p>
+Here are some examples of extensions that usually
+<b>do not need</b> a background page:
+</p>
+
+<ul>
+ <li> An extension with a browser action that
+ presents its UI solely through a popup
+ (and perhaps an options page).
+ </li>
+ <li>
+ An extension that provides an <em>override page</em>&mdash;a
+ page that replaces a standard Chrome page.
+ </li>
+ <li>
+ An extension with a content script
+ that doesn't use cross-origin XMLHttpRequests or localStorage,
+ and that doesn't need to use
+ <a href="api_index.html">extension APIs</a>.
+ </li>
+ <li>
+ An extension that has no UI except for an options page.
+ </li>
+</ul>
+
+<p>
+See <a href="background_pages.html">Background Pages</a>
+for more details.
+</p>
-<h3 id="pages">Pages</h3>
+<h3 id="pages">UI pages</h3>
<p>
-The background page isn't the only HTML page
-that an extension can have.
+Extensions can contain ordinary HTML pages that display the extension's UI.
For example, a browser action can have a popup,
which is implemented by an HTML file.
-Extensions can also
-use <a href="tabs.html#Method-create"><code>chrome.tabs.create()</code></a>
+Any extension can have an options page,
+which lets users customize how the extension works.
+Another type of special page is the override page.
+And finally, you can
+use <a href="tabs.html#method-create"><code>chrome.tabs.create()</code></a>
or <code>window.open()</code>
-to display HTML files that are in the extension.
+to display any other HTML files that are in the extension.
</p>
<p>
@@ -265,25 +316,32 @@ have complete access to each other's DOMs,
and they can invoke functions on each other.
</p>
+<!-- PENDING: Change the following example and figure
+to use something that's not a popup?
+(It might lead people to think that popups need background pages.) -->
+
<p>
The following figure shows the architecture
of a browser action's popup.
The popup's contents are a web page
defined by an HTML file
(<code>popup.html</code>).
+This extension also happens to have a background page
+(<code>background.html</code>).
The popup doesn't need to duplicate code
that's in the background page
-(<code>background.html</code>)
because the popup can invoke functions on the background page.
</p>
-<img src="images/arch-2.gif"
+<img src="images/overview/arch-2.gif"
width="256" height="168"
alt="A browser window containing a browser action that's displaying a popup. The popup's HTML file (popup.html) can communicate with the extension's background page (background.html)." />
<p>
-See the <a href="browserAction.html">Browser Actions</a> page and
-the <a href="#pageComm">Communication between pages</a> section
+See <a href="browserAction.html">Browser Actions</a>,
+<a href="options.html">Options</a>,
+<a href="override.html">Override Pages</a>,
+and the <a href="#pageComm">Communication between pages</a> section
for more details.
</p>
@@ -320,7 +378,7 @@ the DOM for the displayed web page.
It cannot, however, modify the DOM of its parent extension's background page.
</p>
-<img src="images/arch-3.gif"
+<img src="images/overview/arch-3.gif"
width="238" height="169"
alt="A browser window with a browser action (controlled by background.html) and a content script (controlled by contentscript.js)." />
@@ -334,7 +392,7 @@ Or a background page might send a message
asking a content script to change the appearance of its browser page.
</p>
-<img src="images/arch-cs.gif"
+<img src="images/overview/arch-cs.gif"
width="238" height="194"
alt="Like the previous figure, but showing more of the parent extension's files, as well as a communication path between the content script and the parent extension." />
diff --git a/chrome/common/extensions/docs/static/permission_warnings.html b/chrome/common/extensions/docs/static/permission_warnings.html
index b70280f..9c02e08 100644
--- a/chrome/common/extensions/docs/static/permission_warnings.html
+++ b/chrome/common/extensions/docs/static/permission_warnings.html
@@ -3,7 +3,7 @@
<!--
NOTE: When this doc is updated, the online help should also be updated:
-http://www.google.com/support/chrome/bin/answer.py?hl=en&answer=186213
+http://www.google.com/support/chrome_webstore/bin/answer.py?hl=en&answer=186213
We should periodically look at
http://src.chromium.org/viewvc/chrome/trunk/src/chrome/app/generated_resources.grd?view=markup
@@ -211,17 +211,24 @@ that trigger them.
<!-- HasEffectiveAccessToAllHosts() -->
Any of the following:
<ul>
- <li> "proxy" permission (experimental) </li>
+ <li> "proxy" permission </li>
+ <li> "debugger" permission </li>
<li> A match pattern in the "permissions" field
that matches all hosts </li>
<li> A&nbsp;"content_scripts" field with a "matches" entry
that matches all hosts </li>
+ <li> "devtools_page" (experimental) </li>
</ul>
</td>
<td>
<p>
The "proxy" permission is required by the
- <a href="http://code.google.com/chrome/extensions/dev/experimental.proxy.html">experimental proxy</a> module.
+ <a href="experimental.proxy.html">experimental proxy</a> module.
+ </p>
+
+ <p>
+ The "debugger" permission is required by the
+ <a href="experimental.debugger.html">experimental debugger</a> module.
</p>
<p>
diff --git a/chrome/common/extensions/docs/static/themes.html b/chrome/common/extensions/docs/static/themes.html
index 651a74d..8be5c52 100644
--- a/chrome/common/extensions/docs/static/themes.html
+++ b/chrome/common/extensions/docs/static/themes.html
@@ -66,7 +66,7 @@ file for a theme:
Colors are in RGB format.
To find the strings you can use within the "colors" field,
look for kColor* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
</p>
<h3 id="images">images</h3>
@@ -75,7 +75,7 @@ look for kColor* strings in
Image resources use paths relative to the root of the extension.
You can override any of the images that are specified by
<code>kThemeableImages</code> in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
Just remove the "IDR_"
and convert the remaining characters to lowercase.
For example, <code>IDR_THEME_NTP_BACKGROUND</code>
@@ -92,7 +92,7 @@ properties such as background alignment,
background repeat,
and an alternate logo.
To see the properties and the values they can have, see
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
<!-- [PENDING: We should flesh this out.] -->
</p>
@@ -106,7 +106,7 @@ because images don't work across platforms
and are brittle in the case of adding new buttons.
To find the strings you can use within the "tints" field,
look for kTint* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
</p>
<p>
diff --git a/chrome/common/extensions/docs/static/whats_new.html b/chrome/common/extensions/docs/static/whats_new.html
index 438896e..437e9cd 100644
--- a/chrome/common/extensions/docs/static/whats_new.html
+++ b/chrome/common/extensions/docs/static/whats_new.html
@@ -7,6 +7,7 @@ made in recent releases.
</p>
<ul>
+ <li> <a href="#11">Google Chrome 11</a> </li>
<li> <a href="#10">Google Chrome 10</a> </li>
<li> <a href="#9">Google Chrome 9</a> </li>
<li> <a href="#8">Google Chrome 8</a> </li>
@@ -15,6 +16,42 @@ made in recent releases.
</ul>
+<h2 id="11"> Google Chrome 11 </h2>
+
+<h4> Changes to existing APIs </h4>
+ <ul>
+ <li>
+ For security reasons, you can no longer call
+ <a href="tabs.html#method-captureVisibleTab">chrome.tab.captureVisibleTab()</a>
+ on just any tab.
+ Instead, you now must have
+ <a href="manifest.html#permissions">host permission</a>
+ for the URL displayed by that tab.
+ To get the previous behavior,
+ specify <code>&lt;all_urls></code> for the host permission.
+ </li>
+ </ul>
+
+<h4> Additions to existing APIs </h4>
+ <ul>
+ <li>
+ The management API's
+ <a href="management.html#type-ExtensionInfo">ExtensionInfo</a> object
+ now has a <code>homepageUrl</code> property.
+ </li>
+ <li> The management API now lets you get the icons of
+ disabled apps and extensions.
+ Also, you can now modify the regular icon's URL
+ to get its disabled equivalent.
+ See <a href="management.html#type-IconInfo">IconInfo</a> for details.
+ </li>
+ <li> The cookies API
+ <a href="cookies.html#method-set">set()</a>
+ and <a href="cookies.html#method-remove">remove()</a> methods
+ can now take callbacks.
+ </li>
+ </ul>
+
<h2 id="10"> Google Chrome 10 </h2>
<h4> Manifest changes </h4>
@@ -34,7 +71,7 @@ made in recent releases.
<p class="note">
<b>Note:</b>
This change was incorrectly attributed to Chrome 9
- in previous versions of this page.
+ in previous release notes.
</li>
</ul>
@@ -86,10 +123,10 @@ No API or manifest changes worth noting.
<ul>
<li> All users can now install
<a href="http://code.google.com/chrome/apps/index.html">apps</a>;
- packaged apps can use extension APIs
+ packaged apps can use extension APIs.
</li>
<li> The <a href="management.html">management API</a>
- lets you work with installed apps and extensions
+ lets you work with installed apps and extensions.
</li>
</ul>
@@ -97,12 +134,12 @@ No API or manifest changes worth noting.
<ul>
<li> Introduced <a href="manifest.html#incognito">split incognito</a>
mode as the default for installable web apps
- (also available to extensions)
+ (also available to extensions).
</li>
<li> The <a href="tabs.html">tabs API</a>
<code>create()</code> and <code>update()</code> methods
no longer require the "tabs" permission, removing one common cause of
- <a href="permission_warnings.html">scary dialogs</a>
+ <a href="permission_warnings.html">scary dialogs</a>.
</li>
</ul>
@@ -124,42 +161,42 @@ No API or manifest changes worth noting.
<h4> New APIs </h4>
<ul>
<li>The <a href="contextMenus.html">context menus API</a> allows you to
- add context menus to pages or specific objects on a page </li>
+ add context menus to pages or specific objects on a page. </li>
<li>The <a href="cookies.html">cookies API</a> allows you to manage the
- browser's cookie system </li>
+ browser's cookie system. </li>
<li>The <a href="idle.html">idle API</a> allows you to detect when the
- machine's idle state changes </li>
+ machine's idle state changes. </li>
</ul>
<h4> New experimental APIs </h4>
<ul>
<li>The <a href="experimental.omnibox.html">omnibox API</a> allows you to
- add functionality to the browser's address bar </li>
+ add functionality to the browser's address bar. </li>
<li>The <a href="experimental.infobars.html">infobars API</a> allows you
- to add a UI panel across the top of a tab </li>
+ to add a UI panel across the top of a tab. </li>
</ul>
<h4> Additions to existing APIs </h4>
<ul>
<li>The <a
href="extension.html#method-getViews">chrome.extension.getViews()</a>
- method can now return popup views </li>
+ method can now return popup views. </li>
<li>A new <a
href="windows.html#property-WINDOW_ID_NONE">WINDOW_ID_NONE</a> constant
- identifies when focus shifts away from the browser </li>
+ identifies when focus shifts away from the browser. </li>
<li>The new <a
href="tabs.html#method-getCurrent">chrome.tabs.getCurrent()</a> method
- returns the tab associated with the currently executing script </li>
+ returns the tab associated with the currently executing script. </li>
</ul>
<h4> Manifest changes </h4>
<ul>
<li>The <a href="manifest.html#geolocation">geolocation</a> permission
- gives an extension access to the user's physical location </li>
+ gives an extension access to the user's physical location. </li>
<li><a href="match_patterns.html">Match patterns</a> can now select all
- schemes or all URLs </li>
+ schemes or all URLs. </li>
<li>Access to file:/// URLs no longer triggers the "access to your machine"
security warning, but now requires user opt-in from the extensions
- management page </li>
+ management page. </li>
</ul>
diff --git a/chrome/common/extensions/docs/tabs.html b/chrome/common/extensions/docs/tabs.html
index 1708562..86198b7 100644
--- a/chrome/common/extensions/docs/tabs.html
+++ b/chrome/common/extensions/docs/tabs.html
@@ -448,7 +448,7 @@ For other examples and for help in viewing the source code, see
<div class="description">
<p class="todo" style="display: none; ">Undocumented.</p>
- <p>Captures the visible area of the currently selected tab in the specified window.</p>
+ <p>Captures the visible area of the currently selected tab in the specified window. You must have <a href="manifest.html#permissions">host permission</a> for the URL displayed by the tab.</p>
<!-- PARAMETERS -->
<h4>Parameters</h4>
@@ -553,9 +553,9 @@ For other examples and for help in viewing the source code, see
Undocumented.
</dd>
<dd>Set parameters of image capture, such as the format of the resulting image.</dd>
- <dd>
+ <dd style="display: none; ">
This parameter was added in version
- <b><span>5.0.372.0</span></b>.
+ <b><span></span></b>.
You must omit this parameter in earlier versions,
and you may omit it in any version. If you require this
parameter, the manifest key
diff --git a/chrome/common/extensions/docs/themes.html b/chrome/common/extensions/docs/themes.html
index d2eafef..9bcbfec 100644
--- a/chrome/common/extensions/docs/themes.html
+++ b/chrome/common/extensions/docs/themes.html
@@ -389,7 +389,7 @@ file for a theme:
Colors are in RGB format.
To find the strings you can use within the "colors" field,
look for kColor* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
</p>
<h3 id="images">images</h3>
@@ -398,7 +398,7 @@ look for kColor* strings in
Image resources use paths relative to the root of the extension.
You can override any of the images that are specified by
<code>kThemeableImages</code> in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
Just remove the "IDR_"
and convert the remaining characters to lowercase.
For example, <code>IDR_THEME_NTP_BACKGROUND</code>
@@ -415,7 +415,7 @@ properties such as background alignment,
background repeat,
and an alternate logo.
To see the properties and the values they can have, see
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
<!-- [PENDING: We should flesh this out.] -->
</p>
@@ -429,7 +429,7 @@ because images don't work across platforms
and are brittle in the case of adding new buttons.
To find the strings you can use within the "tints" field,
look for kTint* strings in
-<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/browser_theme_provider.cc"><code>browser_theme_provider.cc</code></a>.
+<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/themes/theme_service.cc"><code>theme_service.cc</code></a>.
</p>
<p>
diff --git a/chrome/common/extensions/docs/whats_new.html b/chrome/common/extensions/docs/whats_new.html
index ac4b0f6..6e45782 100644
--- a/chrome/common/extensions/docs/whats_new.html
+++ b/chrome/common/extensions/docs/whats_new.html
@@ -321,6 +321,7 @@ made in recent releases.
</p>
<ul>
+ <li> <a href="#11">Google Chrome 11</a> </li>
<li> <a href="#10">Google Chrome 10</a> </li>
<li> <a href="#9">Google Chrome 9</a> </li>
<li> <a href="#8">Google Chrome 8</a> </li>
@@ -329,6 +330,42 @@ made in recent releases.
</ul>
+<h2 id="11"> Google Chrome 11 </h2>
+
+<h4> Changes to existing APIs </h4>
+ <ul>
+ <li>
+ For security reasons, you can no longer call
+ <a href="tabs.html#method-captureVisibleTab">chrome.tab.captureVisibleTab()</a>
+ on just any tab.
+ Instead, you now must have
+ <a href="manifest.html#permissions">host permission</a>
+ for the URL displayed by that tab.
+ To get the previous behavior,
+ specify <code>&lt;all_urls&gt;</code> for the host permission.
+ </li>
+ </ul>
+
+<h4> Additions to existing APIs </h4>
+ <ul>
+ <li>
+ The management API's
+ <a href="management.html#type-ExtensionInfo">ExtensionInfo</a> object
+ now has a <code>homepageUrl</code> property.
+ </li>
+ <li> The management API now lets you get the icons of
+ disabled apps and extensions.
+ Also, you can now modify the regular icon's URL
+ to get its disabled equivalent.
+ See <a href="management.html#type-IconInfo">IconInfo</a> for details.
+ </li>
+ <li> The cookies API
+ <a href="cookies.html#method-set">set()</a>
+ and <a href="cookies.html#method-remove">remove()</a> methods
+ can now take callbacks.
+ </li>
+ </ul>
+
<h2 id="10"> Google Chrome 10 </h2>
<h4> Manifest changes </h4>
@@ -348,7 +385,7 @@ made in recent releases.
<p class="note">
<b>Note:</b>
This change was incorrectly attributed to Chrome 9
- in previous versions of this page.
+ in previous release notes.
</p></li>
</ul>
@@ -400,10 +437,10 @@ No API or manifest changes worth noting.
<ul>
<li> All users can now install
<a href="http://code.google.com/chrome/apps/index.html">apps</a>;
- packaged apps can use extension APIs
+ packaged apps can use extension APIs.
</li>
<li> The <a href="management.html">management API</a>
- lets you work with installed apps and extensions
+ lets you work with installed apps and extensions.
</li>
</ul>
@@ -411,12 +448,12 @@ No API or manifest changes worth noting.
<ul>
<li> Introduced <a href="manifest.html#incognito">split incognito</a>
mode as the default for installable web apps
- (also available to extensions)
+ (also available to extensions).
</li>
<li> The <a href="tabs.html">tabs API</a>
<code>create()</code> and <code>update()</code> methods
no longer require the "tabs" permission, removing one common cause of
- <a href="permission_warnings.html">scary dialogs</a>
+ <a href="permission_warnings.html">scary dialogs</a>.
</li>
</ul>
@@ -438,40 +475,40 @@ No API or manifest changes worth noting.
<h4> New APIs </h4>
<ul>
<li>The <a href="contextMenus.html">context menus API</a> allows you to
- add context menus to pages or specific objects on a page </li>
+ add context menus to pages or specific objects on a page. </li>
<li>The <a href="cookies.html">cookies API</a> allows you to manage the
- browser's cookie system </li>
+ browser's cookie system. </li>
<li>The <a href="idle.html">idle API</a> allows you to detect when the
- machine's idle state changes </li>
+ machine's idle state changes. </li>
</ul>
<h4> New experimental APIs </h4>
<ul>
<li>The <a href="experimental.omnibox.html">omnibox API</a> allows you to
- add functionality to the browser's address bar </li>
+ add functionality to the browser's address bar. </li>
<li>The <a href="experimental.infobars.html">infobars API</a> allows you
- to add a UI panel across the top of a tab </li>
+ to add a UI panel across the top of a tab. </li>
</ul>
<h4> Additions to existing APIs </h4>
<ul>
<li>The <a href="extension.html#method-getViews">chrome.extension.getViews()</a>
- method can now return popup views </li>
+ method can now return popup views. </li>
<li>A new <a href="windows.html#property-WINDOW_ID_NONE">WINDOW_ID_NONE</a> constant
- identifies when focus shifts away from the browser </li>
+ identifies when focus shifts away from the browser. </li>
<li>The new <a href="tabs.html#method-getCurrent">chrome.tabs.getCurrent()</a> method
- returns the tab associated with the currently executing script </li>
+ returns the tab associated with the currently executing script. </li>
</ul>
<h4> Manifest changes </h4>
<ul>
<li>The <a href="manifest.html#geolocation">geolocation</a> permission
- gives an extension access to the user's physical location </li>
+ gives an extension access to the user's physical location. </li>
<li><a href="match_patterns.html">Match patterns</a> can now select all
- schemes or all URLs </li>
+ schemes or all URLs. </li>
<li>Access to file:/// URLs no longer triggers the "access to your machine"
security warning, but now requires user opt-in from the extensions
- management page </li>
+ management page. </li>
</ul>
</div>
diff --git a/chrome/common/extensions/docs/windows.html b/chrome/common/extensions/docs/windows.html
index a6cb357..ba96d58 100644
--- a/chrome/common/extensions/docs/windows.html
+++ b/chrome/common/extensions/docs/windows.html
@@ -986,6 +986,74 @@ For other examples and for help in viewing the source code, see
</div><div>
<div>
<dt>
+ <var>focused</var>
+ <em>
+
+ <!-- TYPE -->
+ <div style="display:inline">
+ (
+ <span class="optional">optional</span>
+ <span class="enum" style="display: none; ">enumerated</span>
+ <span id="typeTemplate">
+ <span style="display: none; ">
+ <a> Type</a>
+ </span>
+ <span>
+ <span style="display: none; ">
+ array of <span><span></span></span>
+ </span>
+ <span>boolean</span>
+ <span style="display: none; "></span>
+ </span>
+ </span>
+ )
+ </div>
+
+ </em>
+ </dt>
+ <dd class="todo" style="display: none; ">
+ Undocumented.
+ </dd>
+ <dd>If true, opens an active window. If false, opens an inactive window.</dd>
+ <dd style="display: none; ">
+ This parameter was added in version
+ <b><span></span></b>.
+ You must omit this parameter in earlier versions,
+ and you may omit it in any version. If you require this
+ parameter, the manifest key
+ <a href="manifest.html#minimum_chrome_version">minimum_chrome_version</a>
+ can ensure that your extension won't be run in an earlier browser version.
+ </dd>
+
+ <!-- OBJECT PROPERTIES -->
+ <dd style="display: none; ">
+ <dl>
+ <div>
+ <div>
+ </div>
+ </div>
+ </dl>
+ </dd>
+
+ <!-- OBJECT METHODS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- OBJECT EVENT FIELDS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ <!-- FUNCTION PARAMETERS -->
+ <dd style="display: none; ">
+ <div></div>
+ </dd>
+
+ </div>
+ </div><div>
+ <div>
+ <dt>
<var>incognito</var>
<em>
@@ -1071,7 +1139,7 @@ For other examples and for help in viewing the source code, see
array of <span><span></span></span>
</span>
<span>string</span>
- <span>["normal", "popup"]</span>
+ <span>["normal", "popup", "panel"]</span>
</span>
</span>
)
@@ -1082,7 +1150,7 @@ For other examples and for help in viewing the source code, see
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>Specifies what type of browser window to create.</dd>
+ <dd>Specifies what type of browser window to create. The 'panel' type requires the 'experimental' permission.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -2969,7 +3037,7 @@ For other examples and for help in viewing the source code, see
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>It true, brings the window to the front. If false, brings the next window in the z-order to the front.</dd>
+ <dd>If true, brings the window to the front. If false, brings the next window in the z-order to the front.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
@@ -4122,7 +4190,7 @@ For other examples and for help in viewing the source code, see
array of <span><span></span></span>
</span>
<span>string</span>
- <span>["normal", "popup", "app"]</span>
+ <span>["normal", "popup", "panel", "app"]</span>
</span>
</span>
)
@@ -4133,7 +4201,7 @@ For other examples and for help in viewing the source code, see
<dd class="todo" style="display: none; ">
Undocumented.
</dd>
- <dd>The type of browser window this is.</dd>
+ <dd>The type of browser window this is. The 'panel' type requires the 'experimental' permission.</dd>
<dd style="display: none; ">
This parameter was added in version
<b><span></span></b>.
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index ce77fa3..bd28e42 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -13,15 +13,15 @@
#include "base/file_util.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/sha2.h"
-#include "base/singleton.h"
+#include "base/memory/singleton.h"
#include "base/stl_util-inl.h"
-#include "base/third_party/nss/blapi.h"
#include "base/string16.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/version.h"
+#include "crypto/sha2.h"
+#include "crypto/third_party/nss/blapi.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_version_info.h"
@@ -32,14 +32,17 @@
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/extensions/extension_sidebar_defaults.h"
#include "chrome/common/extensions/extension_sidebar_utils.h"
+#include "chrome/common/extensions/file_browser_handler.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/url_constants.h"
#include "googleurl/src/url_util.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
#include "net/base/registry_controlled_domain.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
#include "webkit/glue/image_decoder.h"
namespace keys = extension_manifest_keys;
@@ -95,6 +98,9 @@ bool IsBaseCrxKey(const std::string& key) {
return false;
}
+// Constant used to represent an undefined l10n message id.
+const int kUndefinedMessageId = -1;
+
// Names of API modules that do not require a permission.
const char kBrowserActionModuleName[] = "browserAction";
const char kBrowserActionsModuleName[] = "browserActions";
@@ -139,7 +145,8 @@ class ExtensionConfig {
return Singleton<ExtensionConfig>::get();
}
- int GetPermissionMessageId(const std::string& permission) {
+ Extension::PermissionMessage::MessageId GetPermissionMessageId(
+ const std::string& permission) {
return Extension::kPermissions[permission_map_[permission]].message_id;
}
@@ -168,6 +175,60 @@ class ExtensionConfig {
// in the permissions field of the manifest.
static const char kWindowPermission[] = "windows";
+// Rank extension locations in a way that allows
+// Extension::GetHigherPriorityLocation() to compare locations.
+// An extension installed from two locations will have the location
+// with the higher rank, as returned by this function. The actual
+// integer values may change, and should never be persisted.
+int GetLocationRank(Extension::Location location) {
+ const int kInvalidRank = -1;
+ int rank = kInvalidRank; // Will CHECK that rank is not kInvalidRank.
+
+ switch (location) {
+ // Component extensions can not be overriden by any other type.
+ case Extension::COMPONENT:
+ rank = 6;
+ break;
+
+ // Policy controlled extensions may not be overridden by any type
+ // that is not part of chrome.
+ case Extension::EXTERNAL_POLICY_DOWNLOAD:
+ rank = 5;
+ break;
+
+ // A developer-loaded extension should override any installed type
+ // that a user can disable.
+ case Extension::LOAD:
+ rank = 4;
+ break;
+
+ // The relative priority of various external sources is not important,
+ // but having some order ensures deterministic behavior.
+ case Extension::EXTERNAL_REGISTRY:
+ rank = 3;
+ break;
+
+ case Extension::EXTERNAL_PREF:
+ rank = 2;
+ break;
+
+ case Extension::EXTERNAL_PREF_DOWNLOAD:
+ rank = 1;
+ break;
+
+ // User installed extensions are overridden by any external type.
+ case Extension::INTERNAL:
+ rank = 0;
+ break;
+
+ default:
+ NOTREACHED() << "Need to add new extension locaton " << location;
+ }
+
+ CHECK(rank != kInvalidRank);
+ return rank;
+}
+
} // namespace
const FilePath::CharType Extension::kManifestFilename[] =
@@ -205,7 +266,11 @@ const char Extension::kBookmarkPermission[] = "bookmarks";
const char Extension::kContextMenusPermission[] = "contextMenus";
const char Extension::kContentSettingsPermission[] = "contentSettings";
const char Extension::kCookiePermission[] = "cookies";
+const char Extension::kChromeosInfoPrivatePermissions[] = "chromeosInfoPrivate";
+const char Extension::kDebuggerPermission[] = "debugger";
const char Extension::kExperimentalPermission[] = "experimental";
+const char Extension::kFileBrowserHandlerPermission[] = "fileBrowserHandler";
+const char Extension::kFileBrowserPrivatePermission[] = "fileBrowserPrivate";
const char Extension::kGeolocationPermission[] = "geolocation";
const char Extension::kHistoryPermission[] = "history";
const char Extension::kIdlePermission[] = "idle";
@@ -220,21 +285,25 @@ const char Extension::kWebstorePrivatePermission[] = "webstorePrivate";
// See ExtensionsTest.PermissionMessages for an explanation of each
// exception.
const Extension::Permission Extension::kPermissions[] = {
- { kBackgroundPermission, 0 },
- { kBookmarkPermission, IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS },
- { kContentSettingsPermission, 0 },
- { kContextMenusPermission, 0 },
- { kCookiePermission, 0 },
- { kExperimentalPermission, 0 },
- { kGeolocationPermission, IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION },
- { kIdlePermission, 0 },
- { kHistoryPermission, IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY },
- { kManagementPermission, IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT },
- { kNotificationPermission, 0 },
- { kProxyPermission, 0 },
- { kTabPermission, IDS_EXTENSION_PROMPT_WARNING_TABS },
- { kUnlimitedStoragePermission, 0 },
- { kWebstorePrivatePermission, 0 },
+ { kBackgroundPermission, PermissionMessage::ID_NONE },
+ { kBookmarkPermission, PermissionMessage::ID_BOOKMARKS },
+ { kChromeosInfoPrivatePermissions, PermissionMessage::ID_NONE },
+ { kContentSettingsPermission, PermissionMessage::ID_NONE },
+ { kContextMenusPermission, PermissionMessage::ID_NONE },
+ { kCookiePermission, PermissionMessage::ID_NONE },
+ { kDebuggerPermission, PermissionMessage::ID_DEBUGGER },
+ { kExperimentalPermission, PermissionMessage::ID_NONE },
+ { kFileBrowserHandlerPermission, PermissionMessage::ID_NONE },
+ { kFileBrowserPrivatePermission, PermissionMessage::ID_NONE },
+ { kGeolocationPermission, PermissionMessage::ID_GEOLOCATION },
+ { kIdlePermission, PermissionMessage::ID_NONE },
+ { kHistoryPermission, PermissionMessage::ID_BROWSING_HISTORY },
+ { kManagementPermission, PermissionMessage::ID_MANAGEMENT },
+ { kNotificationPermission, PermissionMessage::ID_NONE },
+ { kProxyPermission, PermissionMessage::ID_NONE },
+ { kTabPermission, PermissionMessage::ID_TABS },
+ { kUnlimitedStoragePermission, PermissionMessage::ID_NONE },
+ { kWebstorePrivatePermission, PermissionMessage::ID_NONE }
};
const size_t Extension::kNumPermissions =
arraysize(Extension::kPermissions);
@@ -249,6 +318,14 @@ const char* const Extension::kHostedAppPermissionNames[] = {
const size_t Extension::kNumHostedAppPermissions =
arraysize(Extension::kHostedAppPermissionNames);
+const char* const Extension::kComponentPrivatePermissionNames[] = {
+ Extension::kFileBrowserPrivatePermission,
+ Extension::kWebstorePrivatePermission,
+ Extension::kChromeosInfoPrivatePermissions,
+};
+const size_t Extension::kNumComponentPrivatePermissions =
+ arraysize(Extension::kComponentPrivatePermissionNames);
+
// We purposefully don't put this into kPermissionNames.
const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage";
@@ -256,8 +333,84 @@ const int Extension::kValidWebExtentSchemes =
URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
const int Extension::kValidHostPermissionSchemes =
- (UserScript::kValidUserScriptSchemes |
- URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE;
+ UserScript::kValidUserScriptSchemes | URLPattern::SCHEME_CHROMEUI;
+
+//
+// PermissionMessage
+//
+
+// static
+Extension::PermissionMessage Extension::PermissionMessage::CreateFromMessageId(
+ Extension::PermissionMessage::MessageId message_id) {
+ DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
+ if (message_id <= ID_NONE)
+ return PermissionMessage(message_id, string16());
+
+ string16 message = l10n_util::GetStringUTF16(kMessageIds[message_id]);
+ return PermissionMessage(message_id, message);
+}
+
+// static
+Extension::PermissionMessage Extension::PermissionMessage::CreateFromHostList(
+ const std::vector<std::string> hosts) {
+ CHECK(hosts.size() > 0);
+
+ MessageId message_id;
+ string16 message;
+ switch (hosts.size()) {
+ case 1:
+ message_id = ID_HOSTS_1;
+ message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
+ UTF8ToUTF16(hosts[0]));
+ break;
+ case 2:
+ message_id = ID_HOSTS_2;
+ message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]));
+ break;
+ case 3:
+ message_id = ID_HOSTS_3;
+ message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]),
+ UTF8ToUTF16(hosts[2]));
+ break;
+ default:
+ message_id = ID_HOSTS_4_OR_MORE;
+ message = l10n_util::GetStringFUTF16(
+ kMessageIds[message_id],
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]),
+ base::IntToString16(hosts.size() - 2));
+ break;
+ }
+
+ return PermissionMessage(message_id, message);
+}
+
+Extension::PermissionMessage::PermissionMessage(
+ Extension::PermissionMessage::MessageId message_id, string16 message)
+ : message_id_(message_id),
+ message_(message) {
+}
+
+const int Extension::PermissionMessage::kMessageIds[] = {
+ kUndefinedMessageId, // "unknown"
+ kUndefinedMessageId, // "none"
+ IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
+ IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
+ IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
+ IDS_EXTENSION_PROMPT_WARNING_TABS,
+ IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
+ IDS_EXTENSION_PROMPT_WARNING_DEBUGGER,
+ IDS_EXTENSION_PROMPT_WARNING_1_HOST,
+ IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
+ IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
+ IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS,
+ IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
+ IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS
+};
//
// Extension
@@ -267,12 +420,11 @@ const int Extension::kValidHostPermissionSchemes =
scoped_refptr<Extension> Extension::Create(const FilePath& path,
Location location,
const DictionaryValue& value,
- bool require_key,
- bool strict_error_checks,
+ int flags,
std::string* error) {
scoped_refptr<Extension> extension = new Extension(path, location);
- if (!extension->InitFromValue(value, require_key, strict_error_checks, error))
+ if (!extension->InitFromValue(value, flags, error))
return NULL;
return extension;
}
@@ -294,35 +446,70 @@ GURL Extension::GalleryUpdateUrl(bool secure) {
}
// static
-int Extension::GetPermissionMessageId(const std::string& permission) {
+Extension::Location Extension::GetHigherPriorityLocation(
+ Extension::Location loc1, Extension::Location loc2) {
+ if (loc1 == loc2)
+ return loc1;
+
+ int loc1_rank = GetLocationRank(loc1);
+ int loc2_rank = GetLocationRank(loc2);
+
+ // If two different locations have the same rank, then we can not
+ // deterministicly choose a location.
+ CHECK(loc1_rank != loc2_rank);
+
+ // Lowest rank has highest priority.
+ return (loc1_rank > loc2_rank ? loc1 : loc2 );
+}
+
+// static
+Extension::PermissionMessage::MessageId Extension::GetPermissionMessageId(
+ const std::string& permission) {
return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission);
}
-std::vector<string16> Extension::GetPermissionMessages() const {
- std::vector<string16> messages;
+Extension::PermissionMessages Extension::GetPermissionMessages() const {
+ PermissionMessages messages;
if (!plugins().empty()) {
- messages.push_back(
- l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS));
+ messages.push_back(PermissionMessage::CreateFromMessageId(
+ PermissionMessage::ID_FULL_ACCESS));
return messages;
}
- string16 host_msg = GetHostPermissionMessage();
- if (!host_msg.empty())
- messages.push_back(host_msg);
+ if (HasEffectiveAccessToAllHosts()) {
+ messages.push_back(PermissionMessage::CreateFromMessageId(
+ PermissionMessage::ID_HOSTS_ALL));
+ } else {
+ std::vector<std::string> hosts = GetDistinctHostsForDisplay(
+ GetEffectiveHostPermissions().patterns());
+ if (!hosts.empty())
+ messages.push_back(PermissionMessage::CreateFromHostList(hosts));
+ }
- std::set<string16> simple_msgs = GetSimplePermissionMessages();
+ std::set<PermissionMessage> simple_msgs = GetSimplePermissionMessages();
messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end());
return messages;
}
-std::set<string16> Extension::GetSimplePermissionMessages() const {
- std::set<string16> messages;
+std::vector<string16> Extension::GetPermissionMessageStrings() const {
+ std::vector<string16> messages;
+ PermissionMessages permissions = GetPermissionMessages();
+ for (PermissionMessages::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i)
+ messages.push_back(i->message());
+ return messages;
+}
+
+std::set<Extension::PermissionMessage>
+ Extension::GetSimplePermissionMessages() const {
+ std::set<PermissionMessage> messages;
std::set<std::string>::const_iterator i;
for (i = api_permissions().begin(); i != api_permissions().end(); ++i) {
- int message_id = GetPermissionMessageId(*i);
- if (message_id)
- messages.insert(l10n_util::GetStringUTF16(message_id));
+ PermissionMessage::MessageId message_id = GetPermissionMessageId(*i);
+ DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
+ if (message_id > PermissionMessage::ID_NONE)
+ messages.insert(PermissionMessage::CreateFromMessageId(message_id));
}
return messages;
}
@@ -354,69 +541,67 @@ bool Extension::IsElevatedHostList(
return !new_hosts_only.empty();
}
+// Helper for GetDistinctHosts(): com > net > org > everything else.
+static bool RcdBetterThan(const std::string& a, const std::string& b) {
+ if (a == b)
+ return false;
+ if (a == "com")
+ return true;
+ if (a == "net")
+ return b != "com";
+ if (a == "org")
+ return b != "com" && b != "net";
+ return false;
+}
+
// static
std::vector<std::string> Extension::GetDistinctHosts(
const URLPatternList& host_patterns, bool include_rcd) {
- // Vector because we later want to access these by index.
- std::vector<std::string> distinct_hosts;
-
- std::set<std::string> rcd_set;
+ // Use a vector to preserve order (also faster than a map on small sets).
+ // Each item is a host split into two parts: host without RCDs and
+ // current best RCD.
+ typedef std::vector<std::pair<std::string, std::string> > HostVector;
+ HostVector hosts_best_rcd;
for (size_t i = 0; i < host_patterns.size(); ++i) {
- std::string candidate = host_patterns[i].host();
+ std::string host = host_patterns[i].host();
// Add the subdomain wildcard back to the host, if necessary.
if (host_patterns[i].match_subdomains())
- candidate = "*." + candidate;
+ host = "*." + host;
- size_t registry = net::RegistryControlledDomainService::GetRegistryLength(
- candidate, false);
- if (registry && registry != std::string::npos) {
- std::string no_rcd(candidate, 0, candidate.size() - registry);
- if (rcd_set.count(no_rcd))
- continue;
- rcd_set.insert(no_rcd);
- if (!include_rcd)
- candidate = no_rcd;
+ // If the host has an RCD, split it off so we can detect duplicates.
+ std::string rcd;
+ size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength(
+ host, false);
+ if (reg_len && reg_len != std::string::npos) {
+ if (include_rcd) // else leave rcd empty
+ rcd = host.substr(host.size() - reg_len);
+ host = host.substr(0, host.size() - reg_len);
}
- if (std::find(distinct_hosts.begin(), distinct_hosts.end(), candidate) ==
- distinct_hosts.end()) {
- distinct_hosts.push_back(candidate);
+
+ // Check if we've already seen this host.
+ HostVector::iterator it = hosts_best_rcd.begin();
+ for (; it != hosts_best_rcd.end(); ++it) {
+ if (it->first == host)
+ break;
+ }
+ // If this host was found, replace the RCD if this one is better.
+ if (it != hosts_best_rcd.end()) {
+ if (include_rcd && RcdBetterThan(rcd, it->second))
+ it->second = rcd;
+ } else { // Previously unseen host, append it.
+ hosts_best_rcd.push_back(std::make_pair(host, rcd));
}
}
+ // Build up the final vector by concatenating hosts and RCDs.
+ std::vector<std::string> distinct_hosts;
+ for (HostVector::iterator it = hosts_best_rcd.begin();
+ it != hosts_best_rcd.end(); ++it)
+ distinct_hosts.push_back(it->first + it->second);
return distinct_hosts;
}
-string16 Extension::GetHostPermissionMessage() const {
- if (HasEffectiveAccessToAllHosts())
- return l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS);
-
- std::vector<std::string> hosts = GetDistinctHostsForDisplay(
- GetEffectiveHostPermissions().patterns());
-
- if (hosts.size() == 1) {
- return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_1_HOST,
- UTF8ToUTF16(hosts[0]));
- } else if (hosts.size() == 2) {
- return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]));
- } else if (hosts.size() == 3) {
- return l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]),
- UTF8ToUTF16(hosts[2]));
- } else if (hosts.size() >= 4) {
- return l10n_util::GetStringFUTF16(
- IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS,
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]),
- base::IntToString16(hosts.size() - 2));
- }
-
- return string16();
-}
-
FilePath Extension::MaybeNormalizePath(const FilePath& path) {
#if defined(OS_WIN)
// Normalize any drive letter to upper-case. We do this for consistency with
@@ -471,8 +656,11 @@ bool Extension::IdIsValid(const std::string& id) {
// static
std::string Extension::GenerateIdForPath(const FilePath& path) {
FilePath new_path = Extension::MaybeNormalizePath(path);
+ std::string path_bytes =
+ std::string(reinterpret_cast<const char*>(new_path.value().data()),
+ new_path.value().size() * sizeof(FilePath::CharType));
std::string id;
- if (!GenerateId(WideToUTF8(new_path.ToWStringHack()), &id))
+ if (!GenerateId(path_bytes, &id))
return "";
return id;
}
@@ -503,11 +691,8 @@ GURL Extension::GetResourceURL(const GURL& extension_url,
bool Extension::GenerateId(const std::string& input, std::string* output) {
CHECK(output);
- if (input.empty())
- return false;
-
uint8 hash[Extension::kIdSize];
- base::SHA256HashString(input, hash, sizeof(hash));
+ crypto::SHA256HashString(input, hash, sizeof(hash));
*output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
ConvertHexadecimalToIDAlphabet(output);
@@ -518,9 +703,14 @@ bool Extension::GenerateId(const std::string& input, std::string* output) {
// content_script list of the manifest.
bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
int definition_index,
- URLPattern::ParseOption parse_strictness,
+ int flags,
std::string* error,
UserScript* result) {
+ // When strict error checks are enabled, make URL pattern parsing strict.
+ URLPattern::ParseOption parse_strictness =
+ (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT
+ : URLPattern::PARSE_LENIENT);
+
// run_at
if (content_script->HasKey(keys::kRunAt)) {
std::string run_location;
@@ -593,6 +783,14 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
return false;
}
+ if (pattern.MatchesScheme(chrome::kFileScheme) &&
+ !CanExecuteScriptEverywhere()) {
+ wants_file_access_ = true;
+ if (!(flags & ALLOW_FILE_ACCESS))
+ pattern.set_valid_schemes(
+ pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+ }
+
result->add_url_pattern(pattern);
}
@@ -822,6 +1020,91 @@ ExtensionAction* Extension::LoadExtensionActionHelper(
return result.release();
}
+Extension::FileBrowserHandlerList* Extension::LoadFileBrowserHandlers(
+ const ListValue* extension_actions, std::string* error) {
+ scoped_ptr<FileBrowserHandlerList> result(
+ new FileBrowserHandlerList());
+ for (ListValue::const_iterator iter = extension_actions->begin();
+ iter != extension_actions->end();
+ ++iter) {
+ if (!(*iter)->IsType(Value::TYPE_DICTIONARY)) {
+ *error = errors::kInvalidFileBrowserHandler;
+ return NULL;
+ }
+ scoped_ptr<FileBrowserHandler> action(
+ LoadFileBrowserHandler(
+ reinterpret_cast<DictionaryValue*>(*iter), error));
+ if (!action.get())
+ return NULL; // Failed to parse file browser action definition.
+ result->push_back(linked_ptr<FileBrowserHandler>(action.release()));
+ }
+ return result.release();
+}
+
+FileBrowserHandler* Extension::LoadFileBrowserHandler(
+ const DictionaryValue* file_browser_handler, std::string* error) {
+ scoped_ptr<FileBrowserHandler> result(
+ new FileBrowserHandler());
+ result->set_extension_id(id());
+
+ std::string id;
+ // Read the file action |id| (mandatory).
+ if (!file_browser_handler->HasKey(keys::kPageActionId) ||
+ !file_browser_handler->GetString(keys::kPageActionId, &id)) {
+ *error = errors::kInvalidPageActionId;
+ return NULL;
+ }
+ result->set_id(id);
+
+ // Read the page action title from |default_title| (mandatory).
+ std::string title;
+ if (!file_browser_handler->HasKey(keys::kPageActionDefaultTitle) ||
+ !file_browser_handler->GetString(keys::kPageActionDefaultTitle, &title)) {
+ *error = errors::kInvalidPageActionDefaultTitle;
+ return NULL;
+ }
+ result->set_title(title);
+
+ // Initialize file filters (mandatory).
+ ListValue* list_value = NULL;
+ if (!file_browser_handler->HasKey(keys::kFileFilters) ||
+ !file_browser_handler->GetList(keys::kFileFilters, &list_value) ||
+ list_value->empty()) {
+ *error = errors::kInvalidFileFiltersList;
+ return NULL;
+ }
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ std::string filter;
+ if (!list_value->GetString(i, &filter)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidFileFilterValue, base::IntToString(i));
+ return NULL;
+ }
+ URLPattern pattern(URLPattern::SCHEME_FILESYSTEM);
+ if (URLPattern::PARSE_SUCCESS != pattern.Parse(filter,
+ URLPattern::PARSE_STRICT)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidURLPatternError, filter);
+ return NULL;
+ }
+ result->AddPattern(pattern);
+ }
+
+ std::string default_icon;
+ // Read the file browser action |default_icon| (optional).
+ if (file_browser_handler->HasKey(keys::kPageActionDefaultIcon)) {
+ if (!file_browser_handler->GetString(
+ keys::kPageActionDefaultIcon,&default_icon) ||
+ default_icon.empty()) {
+ *error = errors::kInvalidPageActionIconPath;
+ return NULL;
+ }
+ result->set_icon_path(default_icon);
+ }
+
+ return result.release();
+}
+
ExtensionSidebarDefaults* Extension::LoadExtensionSidebarDefaults(
const DictionaryValue* extension_sidebar, std::string* error) {
scoped_ptr<ExtensionSidebarDefaults> result(new ExtensionSidebarDefaults());
@@ -995,8 +1278,10 @@ bool Extension::LoadLaunchURL(const DictionaryValue* manifest,
return false;
}
- // Ensure the launch URL is a valid absolute URL.
- if (!GURL(launch_url).is_valid()) {
+ // Ensure the launch URL is a valid absolute URL and web extent scheme.
+ GURL url(launch_url);
+ URLPattern pattern(kValidWebExtentSchemes);
+ if (!url.is_valid() || !pattern.SetScheme(url.scheme())) {
*error = errors::kInvalidLaunchWebURL;
return false;
}
@@ -1109,6 +1394,43 @@ bool Extension::LoadLaunchContainer(const DictionaryValue* manifest,
return true;
}
+bool Extension::LoadAppIsolation(const DictionaryValue* manifest,
+ std::string* error) {
+ // Only parse app isolation features if this switch is present.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalAppManifests))
+ return true;
+
+ Value* temp = NULL;
+ if (!manifest->Get(keys::kIsolation, &temp))
+ return true;
+
+ if (temp->GetType() != Value::TYPE_LIST) {
+ *error = errors::kInvalidIsolation;
+ return false;
+ }
+
+ ListValue* isolation_list = static_cast<ListValue*>(temp);
+ for (size_t i = 0; i < isolation_list->GetSize(); ++i) {
+ std::string isolation_string;
+ if (!isolation_list->GetString(i, &isolation_string)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidIsolationValue,
+ base::UintToString(i));
+ return false;
+ }
+
+ // Check for isolated storage.
+ if (isolation_string == values::kIsolatedStorage) {
+ is_storage_isolated_ = true;
+ } else {
+ LOG(WARNING) << "Did not recognize isolation type: "
+ << isolation_string;
+ }
+ }
+ return true;
+}
+
bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
std::string* error) {
if (web_extent().is_empty())
@@ -1119,8 +1441,10 @@ bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
if (!IsBaseCrxKey(*key) &&
*key != keys::kApp &&
*key != keys::kPermissions &&
- *key != keys::kOptionsPage) {
- *error = errors::kHostedAppsCannotIncludeExtensionFeatures;
+ *key != keys::kOptionsPage &&
+ *key != keys::kBackground) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kHostedAppsCannotIncludeExtensionFeatures, *key);
return false;
}
}
@@ -1134,14 +1458,18 @@ Extension::Extension(const FilePath& path, Location location)
converted_from_user_script_(false),
is_theme_(false),
is_app_(false),
+ is_storage_isolated_(false),
launch_container_(extension_misc::LAUNCH_TAB),
launch_width_(0),
- launch_height_(0) {
- DCHECK(path.IsAbsolute());
+ launch_height_(0),
+ wants_file_access_(false) {
+ DCHECK(path.empty() || path.IsAbsolute());
path_ = MaybeNormalizePath(path);
}
+
Extension::~Extension() {
}
+
ExtensionResource Extension::GetResource(
const std::string& relative_path) const {
#if defined(OS_POSIX)
@@ -1190,8 +1518,7 @@ bool Extension::ParsePEMKeyBytes(const std::string& input,
return base::Base64Decode(working, output);
}
-bool Extension::ProducePEM(const std::string& input,
- std::string* output) {
+bool Extension::ProducePEM(const std::string& input, std::string* output) {
CHECK(output);
if (input.length() == 0)
return false;
@@ -1199,7 +1526,7 @@ bool Extension::ProducePEM(const std::string& input,
return base::Base64Encode(input, output);
}
-bool Extension::FormatPEMForFileOutput(const std::string input,
+bool Extension::FormatPEMForFileOutput(const std::string& input,
std::string* output,
bool is_public) {
CHECK(output);
@@ -1266,7 +1593,8 @@ bool Extension::IsPrivilegeIncrease(const bool granted_full_access,
size_t new_api_count = 0;
for (std::set<std::string>::iterator i = new_apis_only.begin();
i != new_apis_only.end(); ++i) {
- if (GetPermissionMessageId(*i))
+ DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
+ if (GetPermissionMessageId(*i) > PermissionMessage::ID_NONE)
new_api_count++;
}
@@ -1320,17 +1648,28 @@ void Extension::DecodeIconFromPath(const FilePath& icon_path,
result->swap(decoded);
}
+// static
+const SkBitmap& Extension::GetDefaultIcon(bool is_app) {
+ if (is_app) {
+ return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_APP_DEFAULT_ICON);
+ } else {
+ return *ResourceBundle::GetSharedInstance().GetBitmapNamed(
+ IDR_EXTENSION_DEFAULT_ICON);
+ }
+}
+
GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
return GURL(std::string(chrome::kExtensionScheme) +
chrome::kStandardSchemeSeparator + extension_id + "/");
}
-bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
- bool strict_error_checks, std::string* error) {
+bool Extension::InitFromValue(const DictionaryValue& source, int flags,
+ std::string* error) {
// When strict error checks are enabled, make URL pattern parsing strict.
URLPattern::ParseOption parse_strictness =
- (strict_error_checks ? URLPattern::PARSE_STRICT
- : URLPattern::PARSE_LENIENT);
+ (flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT
+ : URLPattern::PARSE_LENIENT);
if (source.HasKey(keys::kPublicKey)) {
std::string public_key_bytes;
@@ -1342,7 +1681,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
*error = errors::kInvalidKey;
return false;
}
- } else if (require_key) {
+ } else if (flags & REQUIRE_KEY) {
*error = errors::kInvalidKey;
return false;
} else {
@@ -1510,14 +1849,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
return false;
}
- DictionaryValue* theme_value;
+ DictionaryValue* theme_value = NULL;
if (!source.GetDictionary(keys::kTheme, &theme_value)) {
*error = errors::kInvalidTheme;
return false;
}
is_theme_ = true;
- DictionaryValue* images_value;
+ DictionaryValue* images_value = NULL;
if (theme_value->GetDictionary(keys::kThemeImages, &images_value)) {
// Validate that the images are all strings
for (DictionaryValue::key_iterator iter = images_value->begin_keys();
@@ -1531,15 +1870,15 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
theme_images_.reset(images_value->DeepCopy());
}
- DictionaryValue* colors_value;
+ DictionaryValue* colors_value = NULL;
if (theme_value->GetDictionary(keys::kThemeColors, &colors_value)) {
// Validate that the colors are RGB or RGBA lists
for (DictionaryValue::key_iterator iter = colors_value->begin_keys();
iter != colors_value->end_keys(); ++iter) {
- ListValue* color_list;
- double alpha;
- int alpha_int;
- int color;
+ ListValue* color_list = NULL;
+ double alpha = 0.0;
+ int alpha_int = 0;
+ int color = 0;
// The color must be a list
if (!colors_value->GetListWithoutPathExpansion(*iter, &color_list) ||
// And either 3 items (RGB) or 4 (RGBA)
@@ -1559,14 +1898,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
theme_colors_.reset(colors_value->DeepCopy());
}
- DictionaryValue* tints_value;
+ DictionaryValue* tints_value = NULL;
if (theme_value->GetDictionary(keys::kThemeTints, &tints_value)) {
// Validate that the tints are all reals.
for (DictionaryValue::key_iterator iter = tints_value->begin_keys();
iter != tints_value->end_keys(); ++iter) {
- ListValue* tint_list;
- double v;
- int vi;
+ ListValue* tint_list = NULL;
+ double v = 0.0;
+ int vi = 0;
if (!tints_value->GetListWithoutPathExpansion(*iter, &tint_list) ||
tint_list->GetSize() != 3 ||
!(tint_list->GetDouble(0, &v) || tint_list->GetInteger(0, &vi)) ||
@@ -1579,7 +1918,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
theme_tints_.reset(tints_value->DeepCopy());
}
- DictionaryValue* display_properties_value;
+ DictionaryValue* display_properties_value = NULL;
if (theme_value->GetDictionary(keys::kThemeDisplayProperties,
&display_properties_value)) {
theme_display_properties_.reset(
@@ -1591,21 +1930,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// Initialize plugins (optional).
if (source.HasKey(keys::kPlugins)) {
- ListValue* list_value;
+ ListValue* list_value = NULL;
if (!source.GetList(keys::kPlugins, &list_value)) {
*error = errors::kInvalidPlugins;
return false;
}
-#if defined(OS_CHROMEOS)
- if (list_value->GetSize() > 0) {
- *error = errors::kIllegalPlugins;
- return false;
- }
-#endif
-
for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* plugin_value;
+ DictionaryValue* plugin_value = NULL;
std::string path_str;
bool is_public = false;
@@ -1630,20 +1962,54 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
}
+ // We don't allow extension plugins to run on Chrome OS. We still
+ // parse the manifest entry so that error messages are consistently
+ // displayed across platforms.
+#if !defined(OS_CHROMEOS)
plugins_.push_back(PluginInfo());
plugins_.back().path = path().AppendASCII(path_str);
plugins_.back().is_public = is_public;
+#endif
}
}
- // Initialize background url (optional).
- if (source.HasKey(keys::kBackground)) {
- std::string background_str;
- if (!source.GetString(keys::kBackground, &background_str)) {
- *error = errors::kInvalidBackground;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableExperimentalExtensionApis) &&
+ source.HasKey(keys::kNaClModules)) {
+ ListValue* list_value = NULL;
+ if (!source.GetList(keys::kNaClModules, &list_value)) {
+ *error = errors::kInvalidNaClModules;
return false;
}
- background_url_ = GetResourceURL(background_str);
+
+ for (size_t i = 0; i < list_value->GetSize(); ++i) {
+ DictionaryValue* module_value = NULL;
+ std::string path_str;
+ std::string mime_type;
+
+ if (!list_value->GetDictionary(i, &module_value)) {
+ *error = errors::kInvalidNaClModules;
+ return false;
+ }
+
+ // Get nacl_modules[i].path.
+ if (!module_value->GetString(keys::kNaClModulesPath, &path_str)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidNaClModulesPath, base::IntToString(i));
+ return false;
+ }
+
+ // Get nacl_modules[i].mime_type.
+ if (!module_value->GetString(keys::kNaClModulesMIMEType, &mime_type)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidNaClModulesMIMEType, base::IntToString(i));
+ return false;
+ }
+
+ nacl_modules_.push_back(NaClModuleInfo());
+ nacl_modules_.back().url = GetResourceURL(path_str);
+ nacl_modules_.back().mime_type = mime_type;
+ }
}
// Initialize toolstrips. This is deprecated for public use.
@@ -1652,7 +2018,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalExtensionApis) &&
source.HasKey(keys::kToolstrips)) {
- ListValue* list_value;
+ ListValue* list_value = NULL;
if (!source.GetList(keys::kToolstrips, &list_value)) {
*error = errors::kInvalidToolstrips;
return false;
@@ -1660,7 +2026,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
for (size_t i = 0; i < list_value->GetSize(); ++i) {
GURL toolstrip;
- DictionaryValue* toolstrip_value;
+ DictionaryValue* toolstrip_value = NULL;
std::string toolstrip_path;
if (list_value->GetString(i, &toolstrip_path)) {
// Support a simple URL value for backwards compatibility.
@@ -1691,7 +2057,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
for (size_t i = 0; i < list_value->GetSize(); ++i) {
- DictionaryValue* content_script;
+ DictionaryValue* content_script = NULL;
if (!list_value->GetDictionary(i, &content_script)) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidContentScript, base::IntToString(i));
@@ -1699,8 +2065,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
UserScript script;
- if (!LoadUserScriptHelper(content_script, i, parse_strictness, error,
- &script))
+ if (!LoadUserScriptHelper(content_script, i, flags, error, &script))
return false; // Failed to parse script context definition.
script.set_extension_id(id());
if (converted_from_user_script_) {
@@ -1715,7 +2080,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
DictionaryValue* page_action_value = NULL;
if (source.HasKey(keys::kPageActions)) {
- ListValue* list_value;
+ ListValue* list_value = NULL;
if (!source.GetList(keys::kPageActions, &list_value)) {
*error = errors::kInvalidPageActionsList;
return false;
@@ -1752,7 +2117,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// Initialize browser action (optional).
if (source.HasKey(keys::kBrowserAction)) {
- DictionaryValue* browser_action_value;
+ DictionaryValue* browser_action_value = NULL;
if (!source.GetDictionary(keys::kBrowserAction, &browser_action_value)) {
*error = errors::kInvalidBrowserAction;
return false;
@@ -1764,6 +2129,21 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
return false; // Failed to parse browser action definition.
}
+ // Initialize file browser actions (optional).
+ if (source.HasKey(keys::kFileBrowserHandlers)) {
+ ListValue* file_browser_handlers_value = NULL;
+ if (!source.GetList(keys::kFileBrowserHandlers,
+ &file_browser_handlers_value)) {
+ *error = errors::kInvalidFileBrowserHandler;
+ return false;
+ }
+
+ file_browser_handlers_.reset(
+ LoadFileBrowserHandlers(file_browser_handlers_value, error));
+ if (!file_browser_handlers_.get())
+ return false; // Failed to parse file browser actions definition.
+ }
+
// Load App settings.
if (!LoadIsApp(manifest_value_.get(), error) ||
!LoadExtent(manifest_value_.get(), keys::kWebURLs,
@@ -1772,7 +2152,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
parse_strictness, error) ||
!EnsureNotHybridApp(manifest_value_.get(), error) ||
!LoadLaunchURL(manifest_value_.get(), error) ||
- !LoadLaunchContainer(manifest_value_.get(), error)) {
+ !LoadLaunchContainer(manifest_value_.get(), error) ||
+ !LoadAppIsolation(manifest_value_.get(), error)) {
return false;
}
@@ -1794,7 +2175,6 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
return false;
}
options_url_ = options_url;
-
} else {
GURL absolute(options_str);
if (absolute.is_valid()) {
@@ -1826,11 +2206,15 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
return false;
}
- // Only COMPONENT extensions can use the webstorePrivate APIs.
+ // Only COMPONENT extensions can use private APIs.
// TODO(asargent) - We want a more general purpose mechanism for this,
// and better error messages. (http://crbug.com/54013)
- if (permission_str == kWebstorePrivatePermission &&
- location_ != Extension::COMPONENT) {
+ if (!IsComponentOnlyPermission(permission_str)
+#ifndef NDEBUG
+ && !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExposePrivateExtensionApi)
+#endif
+ ) {
continue;
}
@@ -1878,6 +2262,14 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// to match all paths.
pattern.SetPath("/*");
+ if (pattern.MatchesScheme(chrome::kFileScheme) &&
+ !CanExecuteScriptEverywhere()) {
+ wants_file_access_ = true;
+ if (!(flags & ALLOW_FILE_ACCESS))
+ pattern.set_valid_schemes(
+ pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+ }
+
host_permissions_.push_back(pattern);
}
@@ -1893,6 +2285,41 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
}
+ // Initialize background url (optional).
+ if (source.HasKey(keys::kBackground)) {
+ std::string background_str;
+ if (!source.GetString(keys::kBackground, &background_str)) {
+ *error = errors::kInvalidBackground;
+ return false;
+ }
+
+ if (is_hosted_app()) {
+ // Make sure "background" permission is set.
+ if (api_permissions_.find(kBackgroundPermission) ==
+ api_permissions_.end()) {
+ *error = errors::kBackgroundPermissionNeeded;
+ return false;
+ }
+ // Hosted apps require an absolute URL.
+ GURL bg_page(background_str);
+ if (!bg_page.is_valid()) {
+ *error = errors::kInvalidBackgroundInHostedApp;
+ return false;
+ }
+
+ if (!(bg_page.SchemeIs("https") ||
+ (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowHTTPBackgroundPage) &&
+ bg_page.SchemeIs("http")))) {
+ *error = errors::kInvalidBackgroundInHostedApp;
+ return false;
+ }
+ background_url_ = bg_page;
+ } else {
+ background_url_ = GetResourceURL(background_str);
+ }
+ }
+
if (source.HasKey(keys::kDefaultLocale)) {
if (!source.GetString(keys::kDefaultLocale, &default_locale_) ||
!l10n_util::IsValidLocaleSyntax(default_locale_)) {
@@ -1903,7 +2330,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// Chrome URL overrides (optional)
if (source.HasKey(keys::kChromeURLOverrides)) {
- DictionaryValue* overrides;
+ DictionaryValue* overrides = NULL;
if (!source.GetDictionary(keys::kChromeURLOverrides, &overrides)) {
*error = errors::kInvalidChromeURLOverrides;
return false;
@@ -1963,7 +2390,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// Initialize sidebar action (optional).
if (source.HasKey(keys::kSidebar)) {
- DictionaryValue* sidebar_value;
+ DictionaryValue* sidebar_value = NULL;
if (!source.GetDictionary(keys::kSidebar, &sidebar_value)) {
*error = errors::kInvalidSidebar;
return false;
@@ -1979,21 +2406,21 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
// Initialize text-to-speech voices (optional).
if (source.HasKey(keys::kTts)) {
- DictionaryValue* tts_dict;
+ DictionaryValue* tts_dict = NULL;
if (!source.GetDictionary(keys::kTts, &tts_dict)) {
*error = errors::kInvalidTts;
return false;
}
if (tts_dict->HasKey(keys::kTtsVoices)) {
- ListValue* tts_voices;
+ ListValue* tts_voices = NULL;
if (!tts_dict->GetList(keys::kTtsVoices, &tts_voices)) {
*error = errors::kInvalidTtsVoices;
return false;
}
for (size_t i = 0; i < tts_voices->GetSize(); i++) {
- DictionaryValue* one_tts_voice;
+ DictionaryValue* one_tts_voice = NULL;
if (!tts_voices->GetDictionary(i, &one_tts_voice)) {
*error = errors::kInvalidTtsVoices;
return false;
@@ -2237,7 +2664,7 @@ bool Extension::CanSpecifyHostPermission(const URLPattern& pattern) const {
pattern.MatchesScheme(chrome::kChromeUIScheme)) {
// Only allow access to chrome://favicon to regular extensions. Component
// extensions can have access to all of chrome://*.
- return (pattern.host() == chrome::kChromeUIFavIconHost ||
+ return (pattern.host() == chrome::kChromeUIFaviconHost ||
CanExecuteScriptEverywhere());
}
@@ -2282,6 +2709,13 @@ bool Extension::HasApiPermission(
bool Extension::HasHostPermission(const GURL& url) const {
for (URLPatternList::const_iterator host = host_permissions().begin();
host != host_permissions().end(); ++host) {
+ // Non-component extensions can only access chrome://favicon and no other
+ // chrome:// scheme urls.
+ if (url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() != chrome::kChromeUIFaviconHost &&
+ location() != Extension::COMPONENT)
+ return false;
+
if (host->MatchesUrl(url))
return true;
}
@@ -2289,6 +2723,16 @@ bool Extension::HasHostPermission(const GURL& url) const {
}
void Extension::InitEffectiveHostPermissions() {
+ // Some APIs effectively grant access to every site. New ones should be
+ // added here. (I'm looking at you, network API)
+ if (HasApiPermission(api_permissions_, kProxyPermission) ||
+ !devtools_url_.is_empty()) {
+ URLPattern all_urls(URLPattern::SCHEME_ALL);
+ all_urls.set_match_all_urls(true);
+ effective_host_permissions_.AddPattern(all_urls);
+ return;
+ }
+
for (URLPatternList::const_iterator host = host_permissions().begin();
host != host_permissions().end(); ++host)
effective_host_permissions_.AddPattern(*host);
@@ -2303,6 +2747,19 @@ void Extension::InitEffectiveHostPermissions() {
}
}
+bool Extension::IsComponentOnlyPermission
+ (const std::string& permission) const {
+ if (location() == Extension::COMPONENT)
+ return true;
+
+ // Non-component extensions are not allowed to access private apis.
+ for (size_t i = 0; i < Extension::kNumComponentPrivatePermissions; ++i) {
+ if (permission == Extension::kComponentPrivatePermissionNames[i])
+ return false;
+ }
+ return true;
+}
+
bool Extension::HasMultipleUISurfaces() const {
int num_surfaces = 0;
@@ -2319,7 +2776,7 @@ bool Extension::HasMultipleUISurfaces() const {
}
bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
- UserScript* script,
+ const UserScript* script,
std::string* error) const {
// The gallery is special-cased as a restricted URL for scripting to prevent
// access to special JS bindings we expose to the gallery (and avoid things
@@ -2335,6 +2792,10 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
return false;
}
+ if (page_url.SchemeIs(chrome::kChromeUIScheme) &&
+ !CanExecuteScriptEverywhere())
+ return false;
+
// If a script is specified, use its matches.
if (script)
return script->MatchesUrl(page_url);
@@ -2358,15 +2819,11 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
bool Extension::HasEffectiveAccessToAllHosts(
const ExtensionExtent& effective_host_permissions,
const std::set<std::string>& api_permissions) {
- // Some APIs effectively grant access to every site. New ones should be
- // added here. (I'm looking at you, network API)
- if (HasApiPermission(api_permissions, kProxyPermission))
- return true;
-
const URLPatternList patterns = effective_host_permissions.patterns();
for (URLPatternList::const_iterator host = patterns.begin();
host != patterns.end(); ++host) {
- if (host->match_subdomains() && host->host().empty())
+ if (host->match_all_urls() ||
+ (host->match_subdomains() && host->host().empty()))
return true;
}
@@ -2400,7 +2857,12 @@ bool Extension::IsAPIPermission(const std::string& str) const {
}
bool Extension::CanExecuteScriptEverywhere() const {
- if (location() == Extension::COMPONENT)
+ if (location() == Extension::COMPONENT
+#ifndef NDEBUG
+ || CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExposePrivateExtensionApi)
+#endif
+ )
return true;
ScriptingWhitelist* whitelist =
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 49850aa..d08f17e 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -13,8 +13,9 @@
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
-#include "base/scoped_ptr.h"
-#include "base/ref_counted.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_extent.h"
#include "chrome/common/extensions/extension_icon_set.h"
@@ -27,6 +28,8 @@ class DictionaryValue;
class ExtensionAction;
class ExtensionResource;
class ExtensionSidebarDefaults;
+class FileBrowserHandler;
+class ListValue;
class SkBitmap;
class Version;
@@ -35,6 +38,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
public:
typedef std::map<const std::string, GURL> URLOverrideMap;
typedef std::vector<std::string> ScriptingWhitelist;
+ typedef std::vector<linked_ptr<FileBrowserHandler> > FileBrowserHandlerList;
// What an extension was loaded from.
// NOTE: These values are stored as integers in the preferences and used
@@ -61,8 +65,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
enum State {
DISABLED = 0,
ENABLED,
- KILLBIT, // Don't install/upgrade (applies to external extensions only).
-
+ // An external extension that the user uninstalled. We should not reinstall
+ // such extensions on startup.
+ EXTERNAL_EXTENSION_UNINSTALLED,
NUM_STATES
};
@@ -101,53 +106,154 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool is_public; // False if only this extension can load this plugin.
};
+ // An NaCl module included in the extension.
+ struct NaClModuleInfo {
+ GURL url;
+ std::string mime_type;
+ };
+
struct TtsVoice {
std::string voice_name;
std::string locale;
std::string gender;
};
+ // When prompting the user to install or approve permissions, we display
+ // messages describing the effects of the permissions and not the permissions
+ // themselves. Each PermissionMessage represents one of the messages that is
+ // shown to the user.
+ class PermissionMessage {
+ public:
+ // Do not reorder or add new enumerations in this list. If you need to add a
+ // new enum, add it just prior to ID_ENUM_BOUNDARY and enter its l10n
+ // message in kMessageIds.
+ enum MessageId {
+ ID_UNKNOWN,
+ ID_NONE,
+ ID_BOOKMARKS,
+ ID_GEOLOCATION,
+ ID_BROWSING_HISTORY,
+ ID_TABS,
+ ID_MANAGEMENT,
+ ID_DEBUGGER,
+ ID_HOSTS_1,
+ ID_HOSTS_2,
+ ID_HOSTS_3,
+ ID_HOSTS_4_OR_MORE,
+ ID_HOSTS_ALL,
+ ID_FULL_ACCESS,
+ ID_ENUM_BOUNDARY
+ };
+
+ // Creates a permission message with the given |message_id| and initializes
+ // its message to the appropriate value.
+ static PermissionMessage CreateFromMessageId(MessageId message_id);
+
+ // Creates the corresponding permission message for a list of hosts. This
+ // method exists because the hosts are presented as one message that depends
+ // on what and how many hosts there are.
+ static PermissionMessage CreateFromHostList(
+ const std::vector<std::string> hosts);
+
+ // Gets the id of the permission message, which can be used in UMA
+ // histograms.
+ MessageId message_id() const { return message_id_; }
+
+ // Gets a localized message describing this permission. Please note that
+ // the message will be empty for message types TYPE_NONE and TYPE_UNKNOWN.
+ const string16& message() const { return message_; }
+
+ // Comparator to work with std::set.
+ bool operator<(const PermissionMessage& that) const {
+ return message_id_ < that.message_id_;
+ }
+
+ private:
+ PermissionMessage(MessageId message_id, string16 message_);
+
+ // The index of the id in the array is its enum value. The first two values
+ // are non-existent message ids to act as placeholders for "unknown" and
+ // "none".
+ // Note: Do not change the order of the items in this list since they
+ // are used in a histogram. The order must match the MessageId order.
+ static const int kMessageIds[];
+
+ MessageId message_id_;
+ string16 message_;
+ };
+
+ typedef std::vector<PermissionMessage> PermissionMessages;
+
// A permission is defined by its |name| (what is used in the manifest),
// and the |message_id| that's used by install/update UI.
struct Permission {
const char* const name;
- const int message_id;
+ const PermissionMessage::MessageId message_id;
+ };
+
+ enum InitFromValueFlags {
+ NO_FLAGS = 0,
+
+ // Usually, the id of an extension is generated by the "key" property of
+ // its manifest, but if |REQUIRE_KEY| is not set, a temporary ID will be
+ // generated based on the path.
+ REQUIRE_KEY = 1 << 0,
+
+ // |STRICT_ERROR_CHECKS| enables extra error checking, such as
+ // checks that URL patterns do not contain ports. This error
+ // checking may find an error that a previous version of
+ // Chrome did not flag. To avoid errors in installed extensions
+ // when Chrome is upgraded, strict error checking is only enabled
+ // when loading extensions as a developer would (such as loading
+ // an unpacked extension), or when loading an extension that is
+ // tied to a specific version of Chrome (such as a component
+ // extension). Most callers will set the |STRICT_ERROR_CHECKS| bit when
+ // Extension::ShouldDoStrictErrorChecking(location) returns true.
+ STRICT_ERROR_CHECKS = 1 << 1,
+
+ // |ALLOW_FILE_ACCESS| indicates that the user is allowing this extension
+ // to have file access. If it's not present, then permissions and content
+ // scripts that match file:/// URLs will be filtered out.
+ ALLOW_FILE_ACCESS = 1 << 2,
};
- // |strict_error_checks| enables extra error checking, such as
- // checks that URL patterns do not contain ports. This error
- // checking may find an error that a previous version of
- // chrome did not flag. To avoid errors in installed extensions
- // when chrome is upgraded, strict error checking is only enabled
- // when loading extensions as a developer would (such as loading
- // an unpacked extension), or when loading an extension that is
- // tied to a specific version of chrome (such as a component
- // extension). Most callers will set |strict_error_checks| to
- // Extension::ShouldDoStrictErrorChecking(location).
static scoped_refptr<Extension> Create(const FilePath& path,
Location location,
const DictionaryValue& value,
- bool require_key,
- bool strict_error_checks,
+ int flags,
std::string* error);
// Return the update url used by gallery/webstore extensions.
static GURL GalleryUpdateUrl(bool secure);
- // The install message id for |permission|. Returns 0 if none exists.
- static int GetPermissionMessageId(const std::string& permission);
+ // Given two install sources, return the one which should take priority
+ // over the other. If an extension is installed from two sources A and B,
+ // its install source should be set to GetHigherPriorityLocation(A, B).
+ static Location GetHigherPriorityLocation(Location loc1, Location loc2);
+
+ // Get's the install message id for |permission|. Returns
+ // MessageId::TYPE_NONE if none exists.
+ static PermissionMessage::MessageId GetPermissionMessageId(
+ const std::string& permission);
// Returns the full list of permission messages that this extension
// should display at install time.
- std::vector<string16> GetPermissionMessages() const;
+ PermissionMessages GetPermissionMessages() const;
+
+ // Returns the full list of permission messages that this extension
+ // should display at install time. The messages are returned as strings
+ // for convenience.
+ std::vector<string16> GetPermissionMessageStrings() const;
// Returns the distinct hosts that should be displayed in the install UI
// for the URL patterns |list|. This discards some of the detail that is
// present in the manifest to make it as easy as possible to process by
// users. In particular we disregard the scheme and path components of
// URLPatterns and de-dupe the result, which includes filtering out common
- // hosts with differing RCDs. (NOTE: when de-duping hosts with common RCDs,
- // the first pattern is returned and the rest discarded)
+ // hosts with differing RCDs (aka Registry Controlled Domains, most of which
+ // are Top Level Domains but also include exceptions like co.uk).
+ // NOTE: when de-duping hosts the preferred RCD will be returned, given this
+ // order of preference: .com, .net, .org, first in list.
static std::vector<std::string> GetDistinctHostsForDisplay(
const URLPatternList& list);
@@ -174,7 +280,11 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
static const char kContentSettingsPermission[];
static const char kContextMenusPermission[];
static const char kCookiePermission[];
+ static const char kChromeosInfoPrivatePermissions[];
+ static const char kDebuggerPermission[];
static const char kExperimentalPermission[];
+ static const char kFileBrowserHandlerPermission[];
+ static const char kFileBrowserPrivatePermission[];
static const char kGeolocationPermission[];
static const char kHistoryPermission[];
static const char kIdlePermission[];
@@ -189,6 +299,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
static const size_t kNumPermissions;
static const char* const kHostedAppPermissionNames[];
static const size_t kNumHostedAppPermissions;
+ static const char* const kComponentPrivatePermissionNames[];
+ static const size_t kNumComponentPrivatePermissions;
// The old name for the unlimited storage permission, which is deprecated but
// still accepted as meaning the same thing as kUnlimitedStoragePermission.
@@ -227,6 +339,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
static bool IdIsValid(const std::string& id);
// Generate an ID for an extension in the given path.
+ // Used while developing extensions, before they have a key.
static std::string GenerateIdForPath(const FilePath& file_name);
// Returns true if the specified file is an extension.
@@ -247,6 +360,14 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
IsExternalLocation(location);
}
+ // Whether extensions with |location| can be uninstalled or not. Policy
+ // controlled extensions are silently auto-installed and updated, and cannot
+ // be disabled by the user. The same applies for internal components.
+ static inline bool UserMayDisable(Location location) {
+ return location != Extension::EXTERNAL_POLICY_DOWNLOAD &&
+ location != Extension::COMPONENT;
+ }
+
// Whether extensions with |location| should be loaded with strict
// error checking. Strict error checks may flag errors older versions
// of chrome did not detect. To avoid breaking installed extensions,
@@ -258,6 +379,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
location == Extension::COMPONENT;
}
+ // Unpacked extensions start off with file access since they are a developer
+ // feature.
+ static inline bool ShouldAlwaysAllowFileAccess(Location location) {
+ return location == Extension::LOAD;
+ }
+
// See Type definition above.
Type GetType() const;
@@ -294,8 +421,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Expects base64 encoded |input| and formats into |output| including
// the appropriate header & footer.
- static bool FormatPEMForFileOutput(const std::string input,
- std::string* output, bool is_public);
+ static bool FormatPEMForFileOutput(const std::string& input,
+ std::string* output,
+ bool is_public);
// Determine whether |new_extension| has increased privileges compared to
// its previously granted permissions, specified by |granted_apis|,
@@ -321,6 +449,10 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
Icons icon_size,
scoped_ptr<SkBitmap>* result);
+ // Returns the default extension/app icon (for extensions or apps that don't
+ // have one).
+ static const SkBitmap& GetDefaultIcon(bool is_app);
+
// Returns the base extension url for a given |extension_id|.
static GURL GetBaseURLFromExtensionId(const std::string& extension_id);
@@ -414,7 +546,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// This method is also aware of certain special pages that extensions are
// usually not allowed to run script on.
bool CanExecuteScriptOnPage(const GURL& page_url,
- UserScript* script,
+ const UserScript* script,
std::string* error) const;
// Returns true if this extension is a COMPONENT extension, or if it is
@@ -454,7 +586,13 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
ExtensionSidebarDefaults* sidebar_defaults() const {
return sidebar_defaults_.get();
}
+ const FileBrowserHandlerList* file_browser_handlers() const {
+ return file_browser_handlers_.get();
+ }
const std::vector<PluginInfo>& plugins() const { return plugins_; }
+ const std::vector<NaClModuleInfo>& nacl_modules() const {
+ return nacl_modules_;
+ }
const GURL& background_url() const { return background_url_; }
const GURL& options_url() const { return options_url_; }
const GURL& devtools_url() const { return devtools_url_; }
@@ -476,10 +614,13 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
bool incognito_split_mode() const { return incognito_split_mode_; }
const std::vector<TtsVoice>& tts_voices() const { return tts_voices_; }
+ bool wants_file_access() const { return wants_file_access_; }
+
// App-related.
bool is_app() const { return is_app_; }
bool is_hosted_app() const { return is_app() && !web_extent().is_empty(); }
bool is_packaged_app() const { return is_app() && web_extent().is_empty(); }
+ bool is_storage_isolated() const { return is_app() && is_storage_isolated_; }
const ExtensionExtent& web_extent() const { return extent_; }
const std::string& launch_local_path() const { return launch_local_path_; }
const std::string& launch_web_url() const { return launch_web_url_; }
@@ -531,11 +672,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
~Extension();
// Initialize the extension from a parsed manifest.
- // Usually, the id of an extension is generated by the "key" property of
- // its manifest, but if |require_key| is |false|, a temporary ID will be
- // generated based on the path.
- bool InitFromValue(const DictionaryValue& value, bool require_key,
- bool strict_error_checks, std::string* error);
+ bool InitFromValue(const DictionaryValue& value, int flags,
+ std::string* error);
// Helper function for implementing HasCachedImage/GetCachedImage. A return
// value of NULL means there is no matching image cached (we allow caching an
@@ -547,7 +685,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// dictionary in the content_script list of the manifest.
bool LoadUserScriptHelper(const DictionaryValue* content_script,
int definition_index,
- URLPattern::ParseOption parse_strictness,
+ int flags,
std::string* error,
UserScript* result);
@@ -571,6 +709,7 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
std::string* error);
bool LoadLaunchContainer(const DictionaryValue* manifest, std::string* error);
bool LoadLaunchURL(const DictionaryValue* manifest, std::string* error);
+ bool LoadAppIsolation(const DictionaryValue* manifest, std::string* error);
bool EnsureNotHybridApp(const DictionaryValue* manifest, std::string* error);
// Helper method to load an ExtensionAction from the page_action or
@@ -578,6 +717,13 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
ExtensionAction* LoadExtensionActionHelper(
const DictionaryValue* extension_action, std::string* error);
+ // Helper method to load an FileBrowserHandlerList from the manifest.
+ FileBrowserHandlerList* LoadFileBrowserHandlers(
+ const ListValue* extension_actions, std::string* error);
+ // Helper method to load an FileBrowserHandler from manifest.
+ FileBrowserHandler* LoadFileBrowserHandler(
+ const DictionaryValue* file_browser_handlers, std::string* error);
+
// Helper method to load an ExtensionSidebarDefaults from the sidebar manifest
// entry.
ExtensionSidebarDefaults* LoadExtensionSidebarDefaults(
@@ -599,15 +745,15 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// kPermissions).
bool IsAPIPermission(const std::string& permission) const;
+ // Returns true if this is a component, or we are not attempting to access a
+ // component-private permission.
+ bool IsComponentOnlyPermission(const std::string& permission) const;
+
// The set of unique API install messages that the extension has.
// NOTE: This only includes messages related to permissions declared in the
// "permissions" key in the manifest. Permissions implied from other features
// of the manifest, like plugins and content scripts are not included.
- std::set<string16> GetSimplePermissionMessages() const;
-
- // The permission message displayed related to the host permissions for
- // this extension.
- string16 GetHostPermissionMessage() const;
+ std::set<PermissionMessage> GetSimplePermissionMessages() const;
// Cached images for this extension. This should only be touched on the UI
// thread.
@@ -676,12 +822,18 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// The extension's browser action, if any.
scoped_ptr<ExtensionAction> browser_action_;
+ // The extension's file browser actions, if any.
+ scoped_ptr<FileBrowserHandlerList> file_browser_handlers_;
+
// The extension's sidebar, if any.
scoped_ptr<ExtensionSidebarDefaults> sidebar_defaults_;
// Optional list of NPAPI plugins and associated properties.
std::vector<PluginInfo> plugins_;
+ // Optional list of NaCl modules and associated properties.
+ std::vector<NaClModuleInfo> nacl_modules_;
+
// Optional URL to a master page of which a single instance should be always
// loaded in the background.
GURL background_url_;
@@ -733,6 +885,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Whether this extension uses app features.
bool is_app_;
+ // Whether this extension requests isolated storage.
+ bool is_storage_isolated_;
+
// The local path inside the extension to use with the launcher.
std::string launch_local_path_;
@@ -758,6 +913,11 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// List of text-to-speech voices that this extension provides, if any.
std::vector<TtsVoice> tts_voices_;
+ // Whether the extension has host permissions or user script patterns that
+ // imply access to file:/// scheme URLs (the user may not have actually
+ // granted it that access).
+ bool wants_file_access_;
+
FRIEND_TEST_ALL_PREFIXES(ExtensionServiceTest,
UpdateExtensionPreservesLocation);
FRIEND_TEST_ALL_PREFIXES(ExtensionTest, LoadPageActionHelper);
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 96fd349..fc5f4ef 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -19,10 +19,13 @@ const char* kDefaultLocale = "default_locale";
const char* kDescription = "description";
const char* kDevToolsPage = "devtools_page";
const char* kExcludeGlobs = "exclude_globs";
+const char* kFileFilters = "file_filters";
+const char* kFileBrowserHandlers = "file_browser_handlers";
const char* kHomepageURL = "homepage_url";
const char* kIcons = "icons";
const char* kIncognito = "incognito";
const char* kIncludeGlobs = "include_globs";
+const char* kIsolation = "app.isolation";
const char* kJs = "js";
const char* kLaunch = "app.launch";
const char* kLaunchContainer = "app.launch.container";
@@ -33,6 +36,9 @@ const char* kLaunchWidth = "app.launch.width";
const char* kMatches = "matches";
const char* kMinimumChromeVersion = "minimum_chrome_version";
const char* kName = "name";
+const char* kNaClModules = "nacl_modules";
+const char* kNaClModulesMIMEType = "mime_type";
+const char* kNaClModulesPath = "path";
const char* kOmnibox = "omnibox";
const char* kOmniboxKeyword = "omnibox.keyword";
const char* kOptionsPage = "options_page";
@@ -80,6 +86,7 @@ const char* kWebURLs = "app.urls";
namespace extension_manifest_values {
const char* kIncognitoSplit = "split";
const char* kIncognitoSpanning = "spanning";
+const char* kIsolatedStorage = "storage";
const char* kRunAtDocumentStart = "document_start";
const char* kRunAtDocumentEnd = "document_end";
const char* kRunAtDocumentIdle = "document_idle";
@@ -97,6 +104,9 @@ const char* kLaunchContainerWindow = "window";
namespace extension_manifest_errors {
const char* kAppsNotEnabled =
"Apps are not enabled.";
+const char* kBackgroundPermissionNeeded =
+ "Hosted apps that use 'background_page' must have the 'background' "
+ "permission.";
const char* kCannotAccessPage =
"Cannot access contents of url \"*\". "
"Extension manifest must request permission to access this host.";
@@ -106,6 +116,8 @@ const char* kCannotClaimAllURLsInExtent =
"Cannot claim all URLs in an extent.";
const char* kCannotScriptGallery =
"The extensions gallery cannot be scripted.";
+const char* kCannotUninstallManagedExtension =
+ "Attempted uninstallation of an extension that is not user-manageable.";
const char* kChromeVersionTooLow =
"This extension requires * version * or greater.";
const char* kDisabledByPolicy =
@@ -117,12 +129,18 @@ const char* kExpectString = "Expect string value.";
const char* kExperimentalFlagRequired =
"Loading extensions with 'experimental' permission requires"
" --enable-experimental-extension-apis command line flag.";
+const char *kExperimentalFeature =
+ "This feature requires 'experimental' permissions and"
+ " --enable-experimental-extension-apis command line flag.";
const char* kHostedAppsCannotIncludeExtensionFeatures =
- "Hosted apps cannot use extension features.";
+ "Hosted apps cannot use the extension feature '*'.";
const char* kInvalidAllFrames =
"Invalid value for 'content_scripts[*].all_frames'.";
const char* kInvalidBackground =
"Invalid value for 'background_page'.";
+const char* kInvalidBackgroundInHostedApp =
+ "Invalid value for 'background_page'. Hosted apps must specify an "
+ "absolute HTTPS URL for the background page.";
const char* kInvalidBrowserAction =
"Invalid value for 'browser_action'.";
const char* kInvalidChromeURLOverrides =
@@ -141,6 +159,12 @@ const char* kInvalidDescription =
"Invalid value for 'description'.";
const char* kInvalidDevToolsPage =
"Invalid value for 'devtools_page'.";
+const char* kInvalidFileBrowserHandler =
+ "Invalid value for 'file_browser_handers'.";
+const char* kInvalidFileFiltersList =
+ "Invalid value for 'file_filters'.";
+const char* kInvalidFileFilterValue =
+ "Invalid value for 'file_filters[*]'.";
const char* kInvalidGlob =
"Invalid value for 'content_scripts[*].*[*]'.";
const char* kInvalidGlobList =
@@ -153,6 +177,10 @@ const char* kInvalidIcons =
"Invalid value for 'icons'.";
const char* kInvalidIncognitoBehavior =
"Invalid value for 'incognito'.";
+const char* kInvalidIsolation =
+ "Invalid value for 'app.isolation'.";
+const char* kInvalidIsolationValue =
+ "Invalid value for 'app.isolation[*]'.";
const char* kInvalidJs =
"Invalid value for 'content_scripts[*].js[*]'.";
const char* kInvalidJsList =
@@ -186,6 +214,12 @@ const char* kInvalidMinimumChromeVersion =
"Invalid value for 'minimum_chrome_version'.";
const char* kInvalidName =
"Required value 'name' is missing or invalid.";
+const char* kInvalidNaClModules =
+ "Invalid value for 'nacl_modules'.";
+const char* kInvalidNaClModulesPath =
+ "Invalid value for 'nacl_modules[*].path'.";
+const char* kInvalidNaClModulesMIMEType =
+ "Invalid value for 'nacl_modules[*].mime_type'.";
const char* kInvalidOmniboxKeyword =
"Invalid value for 'omnibox.keyword'.";
const char* kInvalidOptionsPage =
@@ -270,6 +304,8 @@ const char* kInvalidTtsVoicesVoiceName =
"Invalid value for 'tts.voices[*].voiceName'.";
const char* kInvalidUpdateURL =
"Invalid value for update url: '[*]'.";
+const char* kInvalidURLPatternError =
+ "Invalid url pattern '*'";
const char* kInvalidVersion =
"Required value 'version' is missing or invalid. It must be between 1-4 "
"dot-separated integers each between 0 and 65536.";
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index bad2a5b..6b703f3 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -24,10 +24,13 @@ namespace extension_manifest_keys {
extern const char* kDescription;
extern const char* kDevToolsPage;
extern const char* kExcludeGlobs;
+ extern const char* kFileFilters;
+ extern const char* kFileBrowserHandlers;
extern const char* kHomepageURL;
extern const char* kIcons;
extern const char* kIncognito;
extern const char* kIncludeGlobs;
+ extern const char* kIsolation;
extern const char* kJs;
extern const char* kLaunch;
extern const char* kLaunchContainer;
@@ -37,6 +40,9 @@ namespace extension_manifest_keys {
extern const char* kLaunchWidth;
extern const char* kMatches;
extern const char* kMinimumChromeVersion;
+ extern const char* kNaClModules;
+ extern const char* kNaClModulesMIMEType;
+ extern const char* kNaClModulesPath;
extern const char* kName;
extern const char* kOmnibox;
extern const char* kOmniboxKeyword;
@@ -86,6 +92,7 @@ namespace extension_manifest_keys {
namespace extension_manifest_values {
extern const char* kIncognitoSplit;
extern const char* kIncognitoSpanning;
+ extern const char* kIsolatedStorage;
extern const char* kLaunchContainerPanel;
extern const char* kLaunchContainerTab;
extern const char* kLaunchContainerWindow;
@@ -99,18 +106,22 @@ namespace extension_manifest_values {
// Error messages returned from Extension::InitFromValue().
namespace extension_manifest_errors {
extern const char* kAppsNotEnabled;
+ extern const char* kBackgroundPermissionNeeded;
extern const char* kCannotAccessPage;
extern const char* kCannotClaimAllHostsInExtent;
extern const char* kCannotClaimAllURLsInExtent;
extern const char* kCannotScriptGallery;
+ extern const char* kCannotUninstallManagedExtension;
extern const char* kChromeVersionTooLow;
extern const char* kDevToolsExperimental;
extern const char* kDisabledByPolicy;
extern const char* kExperimentalFlagRequired;
+ extern const char* kExperimentalFeature;
extern const char* kExpectString;
extern const char* kHostedAppsCannotIncludeExtensionFeatures;
extern const char* kInvalidAllFrames;
extern const char* kInvalidBackground;
+ extern const char* kInvalidBackgroundInHostedApp;
extern const char* kInvalidBrowserAction;
extern const char* kInvalidBrowseURL;
extern const char* kInvalidBrowseURLs;
@@ -122,12 +133,17 @@ namespace extension_manifest_errors {
extern const char* kInvalidDefaultLocale;
extern const char* kInvalidDescription;
extern const char* kInvalidDevToolsPage;
+ extern const char* kInvalidFileBrowserHandler;
+ extern const char* kInvalidFileFiltersList;
+ extern const char* kInvalidFileFilterValue;
extern const char* kInvalidGlob;
extern const char* kInvalidGlobList;
extern const char* kInvalidHomepageURL;
extern const char* kInvalidIconPath;
extern const char* kInvalidIcons;
extern const char* kInvalidIncognitoBehavior;
+ extern const char* kInvalidIsolation;
+ extern const char* kInvalidIsolationValue;
extern const char* kInvalidJs;
extern const char* kInvalidJsList;
extern const char* kInvalidKey;
@@ -143,6 +159,9 @@ namespace extension_manifest_errors {
extern const char* kInvalidMatchCount;
extern const char* kInvalidMatches;
extern const char* kInvalidMinimumChromeVersion;
+ extern const char* kInvalidNaClModules;
+ extern const char* kInvalidNaClModulesMIMEType;
+ extern const char* kInvalidNaClModulesPath;
extern const char* kInvalidName;
extern const char* kInvalidOmniboxKeyword;
extern const char* kInvalidOptionsPage;
@@ -185,6 +204,7 @@ namespace extension_manifest_errors {
extern const char* kInvalidTtsVoicesLocale;
extern const char* kInvalidTtsVoicesVoiceName;
extern const char* kInvalidUpdateURL;
+ extern const char* kInvalidURLPatternError;
extern const char* kInvalidVersion;
extern const char* kInvalidWebURL;
extern const char* kInvalidWebURLs;
@@ -329,6 +349,11 @@ namespace extension_misc {
// App launched after the user re-enabled it on the NTP.
APP_LAUNCH_NTP_APP_RE_ENABLE,
+ // URL launched using the --app cmd line option, but the URL does not
+ // correspond to an installed app. These launches are left over from a
+ // feature that let you make desktop shortcuts from the file menu.
+ APP_LAUNCH_CMD_LINE_APP_LEGACY,
+
APP_LAUNCH_BUCKET_BOUNDARY,
APP_LAUNCH_BUCKET_INVALID
};
diff --git a/chrome/common/extensions/extension_file_util.cc b/chrome/common/extensions/extension_file_util.cc
index 6e9a4eb..d378d85 100644
--- a/chrome/common/extensions/extension_file_util.cc
+++ b/chrome/common/extensions/extension_file_util.cc
@@ -9,9 +9,9 @@
#include "base/file_util.h"
#include "base/logging.h"
+#include "base/memory/scoped_temp_dir.h"
#include "base/metrics/histogram.h"
#include "base/path_service.h"
-#include "base/scoped_temp_dir.h"
#include "base/threading/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
@@ -21,7 +21,7 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_resource.h"
#include "chrome/common/extensions/extension_sidebar_defaults.h"
-#include "chrome/common/json_value_serializer.h"
+#include "content/common/json_value_serializer.h"
#include "grit/generated_resources.h"
#include "net/base/escape.h"
#include "net/base/file_stream.h"
@@ -88,8 +88,7 @@ void UninstallExtension(const FilePath& extensions_dir,
scoped_refptr<Extension> LoadExtension(const FilePath& extension_path,
Extension::Location location,
- bool require_key,
- bool strict_error_checks,
+ int flags,
std::string* error) {
FilePath manifest_path =
extension_path.Append(Extension::kManifestFilename);
@@ -128,8 +127,7 @@ scoped_refptr<Extension> LoadExtension(const FilePath& extension_path,
extension_path,
location,
*manifest,
- require_key,
- strict_error_checks,
+ flags,
error));
if (!extension.get())
return NULL;
@@ -247,8 +245,10 @@ bool ValidateExtension(Extension* extension, std::string* error) {
}
}
- // Validate background page location.
- if (!extension->background_url().is_empty()) {
+ // Validate background page location, except for hosted apps, which should use
+ // an external URL. Background page for hosted apps are verified when the
+ // extension is created (in Extension::InitFromValue)
+ if (!extension->background_url().is_empty() && !extension->is_hosted_app()) {
FilePath page_path = ExtensionURLToRelativeFilePath(
extension->background_url());
const FilePath path = extension->GetResource(page_path).GetFilePath();
diff --git a/chrome/common/extensions/extension_file_util.h b/chrome/common/extensions/extension_file_util.h
index 066ee80..114549f 100644
--- a/chrome/common/extensions/extension_file_util.h
+++ b/chrome/common/extensions/extension_file_util.h
@@ -39,8 +39,7 @@ void UninstallExtension(const FilePath& extensions_dir,
// on failure, with a description of the error in |error|.
scoped_refptr<Extension> LoadExtension(const FilePath& extension_root,
Extension::Location location,
- bool require_key,
- bool strict_error_checks,
+ int flags,
std::string* error);
// Returns true if the given extension object is valid and consistent.
diff --git a/chrome/common/extensions/extension_file_util_unittest.cc b/chrome/common/extensions/extension_file_util_unittest.cc
index d3cabff..5a6f782 100644
--- a/chrome/common/extensions/extension_file_util_unittest.cc
+++ b/chrome/common/extensions/extension_file_util_unittest.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#include "chrome/common/extensions/extension_file_util.h"
#include "base/file_util.h"
+#include "base/memory/scoped_temp_dir.h"
#include "base/path_service.h"
-#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
@@ -79,7 +79,7 @@ TEST(ExtensionFileUtil, LoadExtensionWithValidLocales) {
std::string error;
scoped_refptr<Extension> extension(extension_file_util::LoadExtension(
- install_dir, Extension::LOAD, false, true, &error));
+ install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_TRUE(extension != NULL);
EXPECT_EQ("The first extension that I made.", extension->description());
}
@@ -95,7 +95,7 @@ TEST(ExtensionFileUtil, LoadExtensionWithoutLocalesFolder) {
std::string error;
scoped_refptr<Extension> extension(extension_file_util::LoadExtension(
- install_dir, Extension::LOAD, false, true, &error));
+ install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_FALSE(extension == NULL);
EXPECT_TRUE(error.empty());
}
@@ -153,7 +153,7 @@ TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnMissingManifest) {
std::string error;
scoped_refptr<Extension> extension(extension_file_util::LoadExtension(
- install_dir, Extension::LOAD, false, true, &error));
+ install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_TRUE(extension == NULL);
ASSERT_FALSE(error.empty());
ASSERT_STREQ("Manifest file is missing or unreadable.", error.c_str());
@@ -170,7 +170,7 @@ TEST(ExtensionFileUtil, LoadExtensionGivesHelpfullErrorOnBadManifest) {
std::string error;
scoped_refptr<Extension> extension(extension_file_util::LoadExtension(
- install_dir, Extension::LOAD, false, true, &error));
+ install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_TRUE(extension == NULL);
ASSERT_FALSE(error.empty());
ASSERT_STREQ("Manifest is not valid JSON. "
@@ -186,7 +186,7 @@ TEST(ExtensionFileUtil, FailLoadingNonUTF8Scripts) {
std::string error;
scoped_refptr<Extension> extension(extension_file_util::LoadExtension(
- install_dir, Extension::LOAD, false, true, &error));
+ install_dir, Extension::LOAD, Extension::STRICT_ERROR_CHECKS, &error));
ASSERT_TRUE(extension == NULL);
ASSERT_STREQ("Could not load file 'bad_encoding.js' for content script. "
"It isn't UTF-8 encoded.", error.c_str());
diff --git a/chrome/common/extensions/extension_l10n_util.cc b/chrome/common/extensions/extension_l10n_util.cc
index 0874046..14b9178 100644
--- a/chrome/common/extensions/extension_l10n_util.cc
+++ b/chrome/common/extensions/extension_l10n_util.cc
@@ -1,24 +1,25 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#include "chrome/common/extensions/extension_l10n_util.h"
+#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include "base/file_util.h"
-#include "base/linked_ptr.h"
#include "base/logging.h"
+#include "base/memory/linked_ptr.h"
#include "base/string_util.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_message_bundle.h"
-#include "chrome/common/json_value_serializer.h"
#include "chrome/common/url_constants.h"
+#include "content/common/json_value_serializer.h"
#include "ui/base/l10n/l10n_util.h"
#include "unicode/uloc.h"
@@ -111,6 +112,20 @@ bool LocalizeManifest(const ExtensionMessageBundle& messages,
if (!LocalizeManifestValue(keys::kOmniboxKeyword, messages, manifest, error))
return false;
+ ListValue* file_handlers = NULL;
+ if (manifest->GetList(keys::kFileBrowserHandlers, &file_handlers)) {
+ key.assign(keys::kFileBrowserHandlers);
+ for (size_t i = 0; i < file_handlers->GetSize(); i++) {
+ DictionaryValue* handler = NULL;
+ if (!file_handlers->GetDictionary(i, &handler)) {
+ *error = errors::kInvalidFileBrowserHandler;
+ return false;
+ }
+ if (!LocalizeManifestValue(keys::kPageActionDefaultTitle, messages,
+ handler, error))
+ return false;
+ }
+ }
// Add current locale key to the manifest, so we can overwrite prefs
// with new manifest when chrome locale changes.
manifest->SetString(keys::kCurrentLocale, CurrentLocaleOrDefault());
diff --git a/chrome/common/extensions/extension_l10n_util_unittest.cc b/chrome/common/extensions/extension_l10n_util_unittest.cc
index 5a318bc..211cc9c 100644
--- a/chrome/common/extensions/extension_l10n_util_unittest.cc
+++ b/chrome/common/extensions/extension_l10n_util_unittest.cc
@@ -1,13 +1,13 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#include "base/file_path.h"
#include "base/file_util.h"
-#include "base/linked_ptr.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_temp_dir.h"
#include "base/path_service.h"
-#include "base/scoped_ptr.h"
-#include "base/scoped_temp_dir.h"
#include "base/values.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
@@ -234,6 +234,10 @@ ExtensionMessageBundle* CreateManifestBundle() {
omnibox_keyword_tree->SetString("message", "omnibox keyword");
catalog->Set("omnibox_keyword", omnibox_keyword_tree);
+ DictionaryValue* file_handler_title_tree = new DictionaryValue();
+ file_handler_title_tree->SetString("message", "file handler title");
+ catalog->Set("file_handler_title", file_handler_title_tree);
+
std::vector<linked_ptr<DictionaryValue> > catalogs;
catalogs.push_back(catalog);
@@ -365,6 +369,36 @@ TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionOmniboxMsgs) {
EXPECT_TRUE(error.empty());
}
+TEST(ExtensionL10nUtil, LocalizeManifestWithNameDescriptionFileHandlerTitle) {
+ DictionaryValue manifest;
+ manifest.SetString(keys::kName, "__MSG_name__");
+ manifest.SetString(keys::kDescription, "__MSG_description__");
+ ListValue* handlers = new ListValue();
+ manifest.Set(keys::kFileBrowserHandlers, handlers);
+ DictionaryValue* handler = new DictionaryValue();
+ handlers->Append(handler);
+ handler->SetString(keys::kPageActionDefaultTitle,
+ "__MSG_file_handler_title__");
+
+ std::string error;
+ scoped_ptr<ExtensionMessageBundle> messages(CreateManifestBundle());
+
+ EXPECT_TRUE(
+ extension_l10n_util::LocalizeManifest(*messages, &manifest, &error));
+
+ std::string result;
+ ASSERT_TRUE(manifest.GetString(keys::kName, &result));
+ EXPECT_EQ("name", result);
+
+ ASSERT_TRUE(manifest.GetString(keys::kDescription, &result));
+ EXPECT_EQ("description", result);
+
+ ASSERT_TRUE(handler->GetString(keys::kPageActionDefaultTitle, &result));
+ EXPECT_EQ("file handler title", result);
+
+ EXPECT_TRUE(error.empty());
+}
+
// Try with NULL manifest.
TEST(ExtensionL10nUtil, ShouldRelocalizeManifestWithNullManifest) {
ExtensionInfo info(NULL, "", FilePath(), Extension::LOAD);
diff --git a/chrome/common/extensions/extension_localization_peer.cc b/chrome/common/extensions/extension_localization_peer.cc
index f76ba38..dfb4f1d 100644
--- a/chrome/common/extensions/extension_localization_peer.cc
+++ b/chrome/common/extensions/extension_localization_peer.cc
@@ -4,10 +4,10 @@
#include "chrome/common/extensions/extension_localization_peer.h"
-#include "base/scoped_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/string_util.h"
#include "chrome/common/extensions/extension_message_bundle.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
#include "net/base/net_errors.h"
@@ -59,8 +59,10 @@ void ExtensionLocalizationPeer::OnReceivedResponse(
response_info_ = info;
}
-void ExtensionLocalizationPeer::OnReceivedData(const char* data, int len) {
- data_.append(data, len);
+void ExtensionLocalizationPeer::OnReceivedData(const char* data,
+ int data_length,
+ int encoded_data_length) {
+ data_.append(data, data_length);
}
void ExtensionLocalizationPeer::OnCompletedRequest(
@@ -85,7 +87,8 @@ void ExtensionLocalizationPeer::OnCompletedRequest(
original_peer_->OnReceivedResponse(response_info_);
if (!data_.empty())
original_peer_->OnReceivedData(data_.data(),
- static_cast<int>(data_.size()));
+ static_cast<int>(data_.size()),
+ -1);
original_peer_->OnCompletedRequest(status, security_info, completion_time);
}
@@ -100,7 +103,7 @@ void ExtensionLocalizationPeer::ReplaceMessages() {
L10nMessagesMap* l10n_messages = GetL10nMessagesMap(extension_id);
if (!l10n_messages) {
L10nMessagesMap messages;
- message_sender_->Send(new ViewHostMsg_GetExtensionMessageBundle(
+ message_sender_->Send(new ExtensionHostMsg_GetMessageBundle(
extension_id, &messages));
// Save messages we got, so we don't have to ask again.
diff --git a/chrome/common/extensions/extension_localization_peer.h b/chrome/common/extensions/extension_localization_peer.h
index c633933..0a33bc9 100644
--- a/chrome/common/extensions/extension_localization_peer.h
+++ b/chrome/common/extensions/extension_localization_peer.h
@@ -39,7 +39,9 @@ class ExtensionLocalizationPeer
virtual void OnReceivedResponse(
const webkit_glue::ResourceResponseInfo& info);
virtual void OnDownloadedData(int len) {}
- virtual void OnReceivedData(const char* data, int len);
+ virtual void OnReceivedData(const char* data,
+ int data_length,
+ int encoded_data_length);
virtual void OnCompletedRequest(const net::URLRequestStatus& status,
const std::string& security_info,
const base::Time& completion_time);
@@ -63,7 +65,7 @@ class ExtensionLocalizationPeer
// We just pass though the response info. This holds the copy of the original.
webkit_glue::ResourceResponseInfo response_info_;
- // Sends ViewHostMsg_GetExtensionMessageBundle message to the browser to fetch
+ // Sends ExtensionHostMsg_GetMessageBundle message to the browser to fetch
// message catalog.
IPC::Message::Sender* message_sender_;
diff --git a/chrome/common/extensions/extension_localization_peer_unittest.cc b/chrome/common/extensions/extension_localization_peer_unittest.cc
index a0205d5..df847ce 100644
--- a/chrome/common/extensions/extension_localization_peer_unittest.cc
+++ b/chrome/common/extensions/extension_localization_peer_unittest.cc
@@ -5,7 +5,7 @@
#include <map>
#include <string>
-#include "base/scoped_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/common/extensions/extension_message_bundle.h"
#include "chrome/common/extensions/extension_localization_peer.h"
#include "ipc/ipc_message.h"
@@ -66,7 +66,9 @@ class MockResourceLoaderBridgePeer
MOCK_METHOD1(OnReceivedResponse, void(
const webkit_glue::ResourceResponseInfo& info));
MOCK_METHOD1(OnDownloadedData, void(int len));
- MOCK_METHOD2(OnReceivedData, void(const char* data, int len));
+ MOCK_METHOD3(OnReceivedData, void(const char* data,
+ int data_length,
+ int encoded_data_length));
MOCK_METHOD3(OnCompletedRequest, void(
const net::URLRequestStatus& status,
const std::string& security_info,
@@ -124,11 +126,11 @@ TEST_F(ExtensionLocalizationPeerTest, OnReceivedData) {
EXPECT_TRUE(GetData(filter_peer_.get()).empty());
const std::string data_chunk("12345");
- filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length());
+ filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1);
EXPECT_EQ(data_chunk, GetData(filter_peer_.get()));
- filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length());
+ filter_peer_->OnReceivedData(data_chunk.c_str(), data_chunk.length(), -1);
EXPECT_EQ(data_chunk + data_chunk, GetData(filter_peer_.get()));
}
@@ -151,7 +153,7 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestEmptyData) {
// It will self-delete once it exits OnCompletedRequest.
ExtensionLocalizationPeer* filter_peer = filter_peer_.release();
- EXPECT_CALL(*original_peer_, OnReceivedData(_, _)).Times(0);
+ EXPECT_CALL(*original_peer_, OnReceivedData(_, _, _)).Times(0);
EXPECT_CALL(*sender_, Send(_)).Times(0);
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
@@ -173,7 +175,7 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestNoCatalogs) {
std::string data = GetData(filter_peer);
EXPECT_CALL(*original_peer_,
- OnReceivedData(StrEq(data.data()), data.length())).Times(2);
+ OnReceivedData(StrEq(data.data()), data.length(), -1)).Times(2);
EXPECT_CALL(*original_peer_, OnReceivedResponse(_)).Times(2);
EXPECT_CALL(*original_peer_, OnCompletedRequest(
@@ -211,7 +213,7 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestWithCatalogs) {
// __MSG_text__ gets replaced with "new text".
std::string data("some new text");
EXPECT_CALL(*original_peer_,
- OnReceivedData(StrEq(data.data()), data.length()));
+ OnReceivedData(StrEq(data.data()), data.length(), -1));
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
@@ -241,7 +243,7 @@ TEST_F(ExtensionLocalizationPeerTest, OnCompletedRequestReplaceMessagesFails) {
// __MSG_missing_message__ is missing, so message stays the same.
EXPECT_CALL(*original_peer_,
- OnReceivedData(StrEq(message.data()), message.length()));
+ OnReceivedData(StrEq(message.data()), message.length(), -1));
EXPECT_CALL(*original_peer_, OnReceivedResponse(_));
EXPECT_CALL(*original_peer_, OnCompletedRequest(
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index 63172a9..641cd66 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
-#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -16,7 +16,9 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/extensions/extension_sidebar_defaults.h"
-#include "chrome/common/json_value_serializer.h"
+#include "chrome/common/extensions/file_browser_handler.h"
+#include "chrome/common/extensions/url_pattern.h"
+#include "content/common/json_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace errors = extension_manifest_errors;
@@ -48,8 +50,10 @@ class ExtensionManifestTest : public testing::Test {
FilePath path;
PathService::Get(chrome::DIR_TEST_DATA, &path);
path = path.AppendASCII("extensions").AppendASCII("manifest_tests");
- return Extension::Create(path.DirName(), location, *value, false,
- strict_error_checks, error);
+ int flags = Extension::NO_FLAGS;
+ if (strict_error_checks)
+ flags |= Extension::STRICT_ERROR_CHECKS;
+ return Extension::Create(path.DirName(), location, *value, flags, error);
}
scoped_refptr<Extension> LoadExtension(const std::string& name,
@@ -252,7 +256,11 @@ TEST_F(ExtensionManifestTest, AppLaunchURL) {
errors::kInvalidLaunchLocalPath);
LoadAndExpectError("launch_path_invalid_value.json",
errors::kInvalidLaunchLocalPath);
- LoadAndExpectError("launch_url_invalid_type.json",
+ LoadAndExpectError("launch_url_invalid_type_1.json",
+ errors::kInvalidLaunchWebURL);
+ LoadAndExpectError("launch_url_invalid_type_2.json",
+ errors::kInvalidLaunchWebURL);
+ LoadAndExpectError("launch_url_invalid_type_3.json",
errors::kInvalidLaunchWebURL);
scoped_refptr<Extension> extension;
@@ -362,6 +370,8 @@ TEST_F(ExtensionManifestTest, DevToolsExtensions) {
extension = LoadAndExpectSuccess("devtools_extension.json");
EXPECT_EQ(extension->url().spec() + "devtools.html",
extension->devtools_url().spec());
+ EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
+
*CommandLine::ForCurrentProcess() = old_command_line;
}
@@ -401,9 +411,11 @@ TEST_F(ExtensionManifestTest, Sidebar) {
TEST_F(ExtensionManifestTest, DisallowHybridApps) {
LoadAndExpectError("disallow_hybrid_1.json",
- errors::kHostedAppsCannotIncludeExtensionFeatures);
+ ExtensionErrorUtils::FormatErrorMessage(
+ errors::kHostedAppsCannotIncludeExtensionFeatures,
+ keys::kBrowserAction));
LoadAndExpectError("disallow_hybrid_2.json",
- errors::kHostedAppsCannotIncludeExtensionFeatures);
+ errors::kBackgroundPermissionNeeded);
}
TEST_F(ExtensionManifestTest, OptionsPageInApps) {
@@ -547,3 +559,53 @@ TEST_F(ExtensionManifestTest, ForbidPortsInPermissions) {
// to flag this case.
LoadStrictAndExpectSuccess("forbid_ports_in_permissions.json");
}
+
+TEST_F(ExtensionManifestTest, IsolatedApps) {
+ // Requires --enable-experimental-app-manifests
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("isolated_app_valid.json"));
+ EXPECT_FALSE(extension->is_storage_isolated());
+
+ CommandLine old_command_line = *CommandLine::ForCurrentProcess();
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableExperimentalAppManifests);
+ scoped_refptr<Extension> extension2(
+ LoadAndExpectSuccess("isolated_app_valid.json"));
+ EXPECT_TRUE(extension2->is_storage_isolated());
+ *CommandLine::ForCurrentProcess() = old_command_line;
+}
+
+
+TEST_F(ExtensionManifestTest, FileBrowserHandlers) {
+ LoadAndExpectError("filebrowser_invalid_actions_1.json",
+ errors::kInvalidFileBrowserHandler);
+ LoadAndExpectError("filebrowser_invalid_actions_2.json",
+ errors::kInvalidFileBrowserHandler);
+ LoadAndExpectError("filebrowser_invalid_action_id.json",
+ errors::kInvalidPageActionId);
+ LoadAndExpectError("filebrowser_invalid_action_title.json",
+ errors::kInvalidPageActionDefaultTitle);
+ LoadAndExpectError("filebrowser_invalid_action_id.json",
+ errors::kInvalidPageActionId);
+ LoadAndExpectError("filebrowser_invalid_file_filters_1.json",
+ errors::kInvalidFileFiltersList);
+ LoadAndExpectError("filebrowser_invalid_file_filters_2.json",
+ ExtensionErrorUtils::FormatErrorMessage(
+ errors::kInvalidFileFilterValue, base::IntToString(0)));
+ LoadAndExpectError("filebrowser_invalid_file_filters_url.json",
+ ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidURLPatternError,
+ "http:*.html"));
+
+ scoped_refptr<Extension> extension(
+ LoadAndExpectSuccess("filebrowser_valid.json"));
+ ASSERT_TRUE(extension->file_browser_handlers() != NULL);
+ ASSERT_EQ(extension->file_browser_handlers()->size(), 1U);
+ const FileBrowserHandler* action =
+ extension->file_browser_handlers()->at(0).get();
+ EXPECT_EQ(action->title(), "Default title");
+ EXPECT_EQ(action->icon_path(), "icon.png");
+ const FileBrowserHandler::PatternList& patterns = action->file_url_patterns();
+ ASSERT_EQ(patterns.size(), 1U);
+ ASSERT_TRUE(action->MatchesURL(
+ GURL("filesystem:chrome-extension://foo/local/test.txt")));
+}
diff --git a/chrome/common/extensions/extension_message_bundle.cc b/chrome/common/extensions/extension_message_bundle.cc
index e6e00af..26e9c97 100644
--- a/chrome/common/extensions/extension_message_bundle.cc
+++ b/chrome/common/extensions/extension_message_bundle.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -10,8 +10,8 @@
#include "base/hash_tables.h"
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
-#include "base/linked_ptr.h"
-#include "base/scoped_ptr.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -336,7 +336,7 @@ ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap() {
return &g_extension_to_messages_map.Get().messages_map;
}
-L10nMessagesMap* GetL10nMessagesMap(const std::string extension_id) {
+L10nMessagesMap* GetL10nMessagesMap(const std::string& extension_id) {
ExtensionToL10nMessagesMap::iterator it =
g_extension_to_messages_map.Get().messages_map.find(extension_id);
if (it != g_extension_to_messages_map.Get().messages_map.end())
diff --git a/chrome/common/extensions/extension_message_bundle.h b/chrome/common/extensions/extension_message_bundle.h
index df3bf35..8f3078e 100644
--- a/chrome/common/extensions/extension_message_bundle.h
+++ b/chrome/common/extensions/extension_message_bundle.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -10,7 +10,7 @@
#include <string>
#include <vector>
-#include "base/linked_ptr.h"
+#include "base/memory/linked_ptr.h"
class DictionaryValue;
@@ -159,6 +159,6 @@ typedef std::map<std::string, L10nMessagesMap > ExtensionToL10nMessagesMap;
ExtensionToL10nMessagesMap* GetExtensionToL10nMessagesMap();
// Returns message map that matches given extension_id, or NULL.
-L10nMessagesMap* GetL10nMessagesMap(const std::string extension_id);
+L10nMessagesMap* GetL10nMessagesMap(const std::string& extension_id);
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGE_BUNDLE_H_
diff --git a/chrome/common/extensions/extension_message_bundle_unittest.cc b/chrome/common/extensions/extension_message_bundle_unittest.cc
index dd87406..082308e 100644
--- a/chrome/common/extensions/extension_message_bundle_unittest.cc
+++ b/chrome/common/extensions/extension_message_bundle_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -8,8 +8,8 @@
#include <vector>
#include "base/i18n/rtl.h"
-#include "base/linked_ptr.h"
-#include "base/scoped_ptr.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
diff --git a/chrome/common/extensions/extension_messages.cc b/chrome/common/extensions/extension_messages.cc
new file mode 100644
index 0000000..88c9492
--- /dev/null
+++ b/chrome/common/extensions/extension_messages.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2011 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.
+
+#include "chrome/common/extensions/extension_messages.h"
+
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/common/common_param_traits.h"
+
+ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params()
+ : location(Extension::INVALID) {
+}
+
+ExtensionMsg_Loaded_Params::~ExtensionMsg_Loaded_Params() {
+}
+
+ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
+ const ExtensionMsg_Loaded_Params& other)
+ : manifest(other.manifest->DeepCopy()),
+ location(other.location),
+ path(other.path),
+ id(other.id) {
+}
+
+ExtensionMsg_Loaded_Params::ExtensionMsg_Loaded_Params(
+ const Extension* extension)
+ : manifest(new DictionaryValue()),
+ location(extension->location()),
+ path(extension->path()),
+ id(extension->id()) {
+ // As we need more bits of extension data in the renderer, add more keys to
+ // this list.
+ const char* kRendererExtensionKeys[] = {
+ extension_manifest_keys::kPublicKey,
+ extension_manifest_keys::kName,
+ extension_manifest_keys::kVersion,
+ extension_manifest_keys::kIcons,
+ extension_manifest_keys::kPermissions,
+ extension_manifest_keys::kApp
+ };
+
+ // Copy only the data we need.
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kRendererExtensionKeys); ++i) {
+ Value* temp = NULL;
+ if (extension->manifest_value()->Get(kRendererExtensionKeys[i], &temp))
+ manifest->Set(kRendererExtensionKeys[i], temp->DeepCopy());
+ }
+}
+
+scoped_refptr<Extension>
+ ExtensionMsg_Loaded_Params::ConvertToExtension() const {
+ std::string error;
+
+ scoped_refptr<Extension> extension(
+ Extension::Create(path, location, *manifest, Extension::NO_FLAGS,
+ &error));
+ if (!extension.get())
+ LOG(ERROR) << "Error deserializing extension: " << error;
+
+ return extension;
+}
+
+namespace IPC {
+
+template <>
+struct ParamTraits<Extension::Location> {
+ typedef Extension::Location param_type;
+ static void Write(Message* m, const param_type& p) {
+ int val = static_cast<int>(p);
+ WriteParam(m, val);
+ }
+ static bool Read(const Message* m, void** iter, param_type* p) {
+ int val = 0;
+ if (!ReadParam(m, iter, &val) ||
+ val < Extension::INVALID ||
+ val >= Extension::NUM_LOCATIONS)
+ return false;
+ *p = static_cast<param_type>(val);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ ParamTraits<int>::Log(static_cast<int>(p), l);
+ }
+};
+
+void ParamTraits<URLPattern>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.valid_schemes());
+ WriteParam(m, p.GetAsString());
+}
+
+bool ParamTraits<URLPattern>::Read(const Message* m, void** iter,
+ param_type* p) {
+ int valid_schemes;
+ std::string spec;
+ if (!ReadParam(m, iter, &valid_schemes) ||
+ !ReadParam(m, iter, &spec))
+ return false;
+
+ p->set_valid_schemes(valid_schemes);
+ return URLPattern::PARSE_SUCCESS == p->Parse(spec, URLPattern::PARSE_LENIENT);
+}
+
+void ParamTraits<URLPattern>::Log(const param_type& p, std::string* l) {
+ LogParam(p.GetAsString(), l);
+}
+
+void ParamTraits<ExtensionExtent>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.patterns());
+}
+
+bool ParamTraits<ExtensionExtent>::Read(const Message* m, void** iter,
+ param_type* p) {
+ std::vector<URLPattern> patterns;
+ bool success =
+ ReadParam(m, iter, &patterns);
+ if (!success)
+ return false;
+
+ for (size_t i = 0; i < patterns.size(); ++i)
+ p->AddPattern(patterns[i]);
+ return true;
+}
+
+void ParamTraits<ExtensionExtent>::Log(const param_type& p, std::string* l) {
+ LogParam(p.patterns(), l);
+}
+
+void ParamTraits<ExtensionMsg_Loaded_Params>::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.location);
+ WriteParam(m, p.path);
+ WriteParam(m, *(p.manifest));
+}
+
+bool ParamTraits<ExtensionMsg_Loaded_Params>::Read(const Message* m,
+ void** iter,
+ param_type* p) {
+ p->manifest.reset(new DictionaryValue());
+ return ReadParam(m, iter, &p->location) &&
+ ReadParam(m, iter, &p->path) &&
+ ReadParam(m, iter, p->manifest.get());
+}
+
+void ParamTraits<ExtensionMsg_Loaded_Params>::Log(const param_type& p,
+ std::string* l) {
+ l->append(p.id);
+}
+
+} // namespace IPC
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
new file mode 100644
index 0000000..69575e9
--- /dev/null
+++ b/chrome/common/extensions/extension_messages.h
@@ -0,0 +1,285 @@
+// Copyright (c) 2011 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.
+
+// IPC messages for extensions.
+// Multiply-included message file, hence no include guard.
+
+#include "base/shared_memory.h"
+#include "base/values.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_extent.h"
+#include "chrome/common/extensions/url_pattern.h"
+#include "chrome/common/web_apps.h"
+#include "ipc/ipc_message_macros.h"
+
+#define IPC_MESSAGE_START ExtensionMsgStart
+
+// Parameters structure for ExtensionHostMsg_Request.
+IPC_STRUCT_BEGIN(ExtensionHostMsg_DomMessage_Params)
+ // Message name.
+ IPC_STRUCT_MEMBER(std::string, name)
+
+ // List of message arguments.
+ IPC_STRUCT_MEMBER(ListValue, arguments)
+
+ // URL of the frame request was sent from.
+ IPC_STRUCT_MEMBER(GURL, source_url)
+
+ // Unique request id to match requests and responses.
+ IPC_STRUCT_MEMBER(int, request_id)
+
+ // True if request has a callback specified.
+ IPC_STRUCT_MEMBER(bool, has_callback)
+
+ // True if request is executed in response to an explicit user gesture.
+ IPC_STRUCT_MEMBER(bool, user_gesture)
+IPC_STRUCT_END()
+
+// Allows an extension to execute code in a tab.
+IPC_STRUCT_BEGIN(ExtensionMsg_ExecuteCode_Params)
+ // The extension API request id, for responding.
+ IPC_STRUCT_MEMBER(int, request_id)
+
+ // The ID of the requesting extension. To know which isolated world to
+ // execute the code inside of.
+ IPC_STRUCT_MEMBER(std::string, extension_id)
+
+ // Whether the code is JavaScript or CSS.
+ IPC_STRUCT_MEMBER(bool, is_javascript)
+
+ // String of code to execute.
+ IPC_STRUCT_MEMBER(std::string, code)
+
+ // Whether to inject into all frames, or only the root frame.
+ IPC_STRUCT_MEMBER(bool, all_frames)
+
+ // Whether to execute code in the main world (as opposed to an isolated
+ // world).
+ IPC_STRUCT_MEMBER(bool, in_main_world)
+IPC_STRUCT_END()
+
+IPC_STRUCT_TRAITS_BEGIN(WebApplicationInfo::IconInfo)
+ IPC_STRUCT_TRAITS_MEMBER(url)
+ IPC_STRUCT_TRAITS_MEMBER(width)
+ IPC_STRUCT_TRAITS_MEMBER(height)
+ IPC_STRUCT_TRAITS_MEMBER(data)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(WebApplicationInfo)
+ IPC_STRUCT_TRAITS_MEMBER(title)
+ IPC_STRUCT_TRAITS_MEMBER(description)
+ IPC_STRUCT_TRAITS_MEMBER(app_url)
+ IPC_STRUCT_TRAITS_MEMBER(icons)
+ IPC_STRUCT_TRAITS_MEMBER(permissions)
+ IPC_STRUCT_TRAITS_MEMBER(launch_container)
+IPC_STRUCT_TRAITS_END()
+
+// Singly-included section for custom IPC traits.
+#ifndef CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
+
+// IPC_MESSAGE macros choke on extra , in the std::map, when expanding. We need
+// to typedef it to avoid that.
+// Substitution map for l10n messages.
+typedef std::map<std::string, std::string> SubstitutionMap;
+
+struct ExtensionMsg_Loaded_Params {
+ ExtensionMsg_Loaded_Params();
+ ~ExtensionMsg_Loaded_Params();
+ explicit ExtensionMsg_Loaded_Params(const Extension* extension);
+
+ // A copy constructor is needed because this structure can end up getting
+ // copied inside the IPC machinery on gcc <= 4.2.
+ ExtensionMsg_Loaded_Params(const ExtensionMsg_Loaded_Params& other);
+
+ // Creates a new extension from the data in this object.
+ scoped_refptr<Extension> ConvertToExtension() const;
+
+ // The subset of the extension manifest data we send to renderers.
+ scoped_ptr<DictionaryValue> manifest;
+
+ // The location the extension was installed from.
+ Extension::Location location;
+
+ // The path the extension was loaded from. This is used in the renderer only
+ // to generate the extension ID for extensions that are loaded unpacked.
+ FilePath path;
+
+ // We keep this separate so that it can be used in logging.
+ std::string id;
+};
+
+namespace IPC {
+
+template <>
+struct ParamTraits<URLPattern> {
+ typedef URLPattern param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<ExtensionExtent> {
+ typedef ExtensionExtent param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<ExtensionMsg_Loaded_Params> {
+ typedef ExtensionMsg_Loaded_Params param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_MESSAGES_H_
+
+// Messages sent from the browser to the renderer.
+
+// The browser sends this message in response to all extension api calls.
+IPC_MESSAGE_ROUTED4(ExtensionMsg_Response,
+ int /* request_id */,
+ bool /* success */,
+ std::string /* response */,
+ std::string /* error */)
+
+// This message is optionally routed. If used as a control message, it
+// will call a javascript function in every registered context in the
+// target process. If routed, it will be restricted to the contexts that
+// are part of the target RenderView.
+// If |extension_id| is non-empty, the function will be invoked only in
+// contexts owned by the extension. |args| is a list of primitive Value types
+// that are passed to the function.
+IPC_MESSAGE_ROUTED4(ExtensionMsg_MessageInvoke,
+ std::string /* extension_id */,
+ std::string /* function_name */,
+ ListValue /* args */,
+ GURL /* event URL */)
+
+// Tell the renderer process all known extension function names.
+IPC_MESSAGE_CONTROL1(ExtensionMsg_SetFunctionNames,
+ std::vector<std::string>)
+
+// TODO(aa): SetAPIPermissions, SetHostPermissions, and possibly
+// UpdatePageActions should be replaced with just sending additional data in
+// ExtensionLoaded. See: crbug.com/70516.
+
+// Tell the renderer process which permissions the given extension has. See
+// Extension::Permissions for which elements correspond to which permissions.
+IPC_MESSAGE_CONTROL2(ExtensionMsg_SetAPIPermissions,
+ std::string /* extension_id */,
+ std::set<std::string> /* permissions */)
+
+// Tell the renderer process which host permissions the given extension has.
+IPC_MESSAGE_CONTROL2(ExtensionMsg_SetHostPermissions,
+ GURL /* source extension's origin */,
+ /* URLPatterns the extension can access */
+ std::vector<URLPattern>)
+
+// Tell the renderer process all known page action ids for a particular
+// extension.
+IPC_MESSAGE_CONTROL2(ExtensionMsg_UpdatePageActions,
+ std::string /* extension_id */,
+ std::vector<std::string> /* page_action_ids */)
+
+// Notifies the renderer that an extension was loaded in the browser.
+IPC_MESSAGE_CONTROL1(ExtensionMsg_Loaded,
+ ExtensionMsg_Loaded_Params)
+
+// Notifies the renderer that an extension was unloaded in the browser.
+IPC_MESSAGE_CONTROL1(ExtensionMsg_Unloaded,
+ std::string)
+
+// Updates the scripting whitelist for extensions in the render process. This is
+// only used for testing.
+IPC_MESSAGE_CONTROL1(ExtensionMsg_SetScriptingWhitelist,
+ Extension::ScriptingWhitelist /* extenison ids */)
+
+// Notification that renderer should run some JavaScript code.
+IPC_MESSAGE_ROUTED1(ExtensionMsg_ExecuteCode,
+ ExtensionMsg_ExecuteCode_Params)
+
+// Notification that the user scripts have been updated. It has one
+// SharedMemoryHandle argument consisting of the pickled script data. This
+// handle is valid in the context of the renderer.
+IPC_MESSAGE_CONTROL1(ExtensionMsg_UpdateUserScripts,
+ base::SharedMemoryHandle)
+
+// Requests application info for the page. The renderer responds back with
+// ExtensionHostMsg_DidGetApplicationInfo.
+IPC_MESSAGE_ROUTED1(ExtensionMsg_GetApplicationInfo,
+ int32 /*page_id*/)
+
+// Messages sent from the renderer to the browser.
+
+// A renderer sends this message when an extension process starts an API
+// request. The browser will always respond with a ExtensionMsg_Response.
+IPC_MESSAGE_ROUTED1(ExtensionHostMsg_Request,
+ ExtensionHostMsg_DomMessage_Params)
+
+// Notify the browser that the given extension added a listener to an event.
+IPC_MESSAGE_CONTROL2(ExtensionHostMsg_AddListener,
+ std::string /* extension_id */,
+ std::string /* name */)
+
+// Notify the browser that the given extension removed a listener from an
+// event.
+IPC_MESSAGE_CONTROL2(ExtensionHostMsg_RemoveListener,
+ std::string /* extension_id */,
+ std::string /* name */)
+
+// Open a channel to all listening contexts owned by the extension with
+// the given ID. This always returns a valid port ID which can be used for
+// sending messages. If an error occurred, the opener will be notified
+// asynchronously.
+IPC_SYNC_MESSAGE_CONTROL4_1(ExtensionHostMsg_OpenChannelToExtension,
+ int /* routing_id */,
+ std::string /* source_extension_id */,
+ std::string /* target_extension_id */,
+ std::string /* channel_name */,
+ int /* port_id */)
+
+// Get a port handle to the given tab. The handle can be used for sending
+// messages to the extension.
+IPC_SYNC_MESSAGE_CONTROL4_1(ExtensionHostMsg_OpenChannelToTab,
+ int /* routing_id */,
+ int /* tab_id */,
+ std::string /* extension_id */,
+ std::string /* channel_name */,
+ int /* port_id */)
+
+// Send a message to an extension process. The handle is the value returned
+// by ViewHostMsg_OpenChannelTo*.
+IPC_MESSAGE_ROUTED2(ExtensionHostMsg_PostMessage,
+ int /* port_id */,
+ std::string /* message */)
+
+// Send a message to an extension process. The handle is the value returned
+// by ViewHostMsg_OpenChannelTo*.
+IPC_MESSAGE_CONTROL1(ExtensionHostMsg_CloseChannel,
+ int /* port_id */)
+
+// Used to get the extension message bundle.
+IPC_SYNC_MESSAGE_CONTROL1_1(ExtensionHostMsg_GetMessageBundle,
+ std::string /* extension id */,
+ SubstitutionMap /* message bundle */)
+
+// Send from the renderer to the browser to return the script running result.
+IPC_MESSAGE_ROUTED3(ExtensionHostMsg_ExecuteCodeFinished,
+ int /* request id */,
+ bool /* whether the script ran successfully */,
+ std::string /* error message */)
+
+IPC_MESSAGE_ROUTED2(ExtensionHostMsg_DidGetApplicationInfo,
+ int32 /* page_id */,
+ WebApplicationInfo)
+
+// Sent by the renderer to implement chrome.app.installApplication().
+IPC_MESSAGE_ROUTED1(ExtensionHostMsg_InstallApplication,
+ WebApplicationInfo)
diff --git a/chrome/common/extensions/extension_resource.cc b/chrome/common/extensions/extension_resource.cc
index cc88382..1b344c9 100644
--- a/chrome/common/extensions/extension_resource.cc
+++ b/chrome/common/extensions/extension_resource.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -65,15 +65,17 @@ FilePath ExtensionResource::GetFilePath(
// Unit-testing helpers.
FilePath::StringType ExtensionResource::NormalizeSeperators(
- FilePath::StringType path) const {
+ const FilePath::StringType& path) const {
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
- FilePath::StringType ret_val;
- for (size_t i = 0; i < path.length(); i++) {
- if (FilePath::IsSeparator(path[i]))
- path[i] = FilePath::kSeparators[0];
+ FilePath::StringType win_path = path;
+ for (size_t i = 0; i < win_path.length(); i++) {
+ if (FilePath::IsSeparator(win_path[i]))
+ win_path[i] = FilePath::kSeparators[0];
}
-#endif // FILE_PATH_USES_WIN_SEPARATORS
+ return win_path;
+#else
return path;
+#endif // FILE_PATH_USES_WIN_SEPARATORS
}
bool ExtensionResource::ComparePathWithDefault(const FilePath& path) const {
diff --git a/chrome/common/extensions/extension_resource.h b/chrome/common/extensions/extension_resource.h
index 6fe3773..4a7d8cf 100644
--- a/chrome/common/extensions/extension_resource.h
+++ b/chrome/common/extensions/extension_resource.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -44,7 +44,8 @@ class ExtensionResource {
bool empty() { return extension_root().empty(); }
// Unit test helpers.
- FilePath::StringType NormalizeSeperators(FilePath::StringType path) const;
+ FilePath::StringType NormalizeSeperators(
+ const FilePath::StringType& path) const;
bool ComparePathWithDefault(const FilePath& path) const;
private:
diff --git a/chrome/common/extensions/extension_resource_unittest.cc b/chrome/common/extensions/extension_resource_unittest.cc
index 9f47666..e22f288 100644
--- a/chrome/common/extensions/extension_resource_unittest.cc
+++ b/chrome/common/extensions/extension_resource_unittest.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#include <algorithm>
#include "base/file_util.h"
+#include "base/memory/scoped_temp_dir.h"
#include "base/path_service.h"
-#include "base/scoped_temp_dir.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_l10n_util.h"
diff --git a/chrome/common/extensions/extension_set.h b/chrome/common/extensions/extension_set.h
index 9d00d1d..dbd16ad 100644
--- a/chrome/common/extensions/extension_set.h
+++ b/chrome/common/extensions/extension_set.h
@@ -10,7 +10,7 @@
#include <vector>
#include "base/gtest_prod_util.h"
-#include "base/ref_counted.h"
+#include "base/memory/ref_counted.h"
#include "chrome/common/extensions/extension.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/common/extensions/extension_set_unittest.cc b/chrome/common/extensions/extension_set_unittest.cc
index a68e1d7..e51d571 100644
--- a/chrome/common/extensions/extension_set_unittest.cc
+++ b/chrome/common/extensions/extension_set_unittest.cc
@@ -4,8 +4,8 @@
#include "base/file_path.h"
#include "base/logging.h"
-#include "base/ref_counted.h"
-#include "base/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_set.h"
@@ -36,12 +36,10 @@ scoped_refptr<Extension> CreateTestExtension(const std::string& name,
urls->Append(Value::CreateStringValue(extent));
}
- const bool kRequireKey = false;
- const bool kStrictErrorChecks = true;
std::string error;
scoped_refptr<Extension> extension(
- Extension::Create(path, Extension::INTERNAL, manifest, kRequireKey,
- kStrictErrorChecks, &error));
+ Extension::Create(path, Extension::INTERNAL, manifest,
+ Extension::STRICT_ERROR_CHECKS, &error));
EXPECT_TRUE(extension.get()) << error;
return extension;
}
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index ab3c3a2..d493672 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -21,8 +21,8 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_error_utils.h"
#include "chrome/common/extensions/extension_resource.h"
-#include "chrome/common/json_value_serializer.h"
#include "chrome/common/url_constants.h"
+#include "content/common/json_value_serializer.h"
#include "googleurl/src/gurl.h"
#include "net/base/mime_sniffer.h"
#include "skia/ext/image_operations.h"
@@ -67,6 +67,45 @@ TEST(ExtensionTest, LocationValuesTest) {
ASSERT_EQ(3, Extension::EXTERNAL_REGISTRY);
ASSERT_EQ(4, Extension::LOAD);
ASSERT_EQ(5, Extension::COMPONENT);
+ ASSERT_EQ(6, Extension::EXTERNAL_PREF_DOWNLOAD);
+ ASSERT_EQ(7, Extension::EXTERNAL_POLICY_DOWNLOAD);
+}
+
+TEST(ExtensionTest, LocationPriorityTest) {
+ for (int i = 0; i < Extension::NUM_LOCATIONS; i++) {
+ Extension::Location loc = static_cast<Extension::Location>(i);
+
+ // INVALID is not a valid location.
+ if (loc == Extension::INVALID)
+ continue;
+
+ // Comparing a location that has no rank will hit a CHECK. Do a
+ // compare with every valid location, to be sure each one is covered.
+
+ // Check that no install source can override a componenet extension.
+ ASSERT_EQ(Extension::COMPONENT,
+ Extension::GetHigherPriorityLocation(Extension::COMPONENT, loc));
+ ASSERT_EQ(Extension::COMPONENT,
+ Extension::GetHigherPriorityLocation(loc, Extension::COMPONENT));
+
+ // Check that any source can override a user install. This might change
+ // in the future, in which case this test should be updated.
+ ASSERT_EQ(loc,
+ Extension::GetHigherPriorityLocation(Extension::INTERNAL, loc));
+ ASSERT_EQ(loc,
+ Extension::GetHigherPriorityLocation(loc, Extension::INTERNAL));
+ }
+
+ // Check a few interesting cases that we know can happen:
+ ASSERT_EQ(Extension::EXTERNAL_POLICY_DOWNLOAD,
+ Extension::GetHigherPriorityLocation(
+ Extension::EXTERNAL_POLICY_DOWNLOAD,
+ Extension::EXTERNAL_PREF));
+
+ ASSERT_EQ(Extension::EXTERNAL_PREF,
+ Extension::GetHigherPriorityLocation(
+ Extension::INTERNAL,
+ Extension::EXTERNAL_PREF));
}
@@ -105,7 +144,8 @@ TEST(ExtensionTest, InitFromValueInvalid) {
EXPECT_EQ("", error);
EXPECT_EQ(0, error_code);
ASSERT_TRUE(valid_value.get());
- ASSERT_TRUE(extension.InitFromValue(*valid_value, true, false, &error));
+ ASSERT_TRUE(extension.InitFromValue(*valid_value, Extension::REQUIRE_KEY,
+ &error));
ASSERT_EQ("", error);
EXPECT_EQ("en_US", extension.default_locale());
@@ -114,33 +154,39 @@ TEST(ExtensionTest, InitFromValueInvalid) {
// Test missing and invalid versions
input_value.reset(valid_value->DeepCopy());
input_value->Remove(keys::kVersion, NULL);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidVersion, error);
input_value->SetInteger(keys::kVersion, 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidVersion, error);
// Test missing and invalid names.
input_value.reset(valid_value->DeepCopy());
input_value->Remove(keys::kName, NULL);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidName, error);
input_value->SetInteger(keys::kName, 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidName, error);
// Test invalid description
input_value.reset(valid_value->DeepCopy());
input_value->SetInteger(keys::kDescription, 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidDescription, error);
// Test invalid icons
input_value.reset(valid_value->DeepCopy());
input_value->SetInteger(keys::kIcons, 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidIcons, error);
// Test invalid icon paths
@@ -149,13 +195,15 @@ TEST(ExtensionTest, InitFromValueInvalid) {
input_value->GetDictionary(keys::kIcons, &icons);
ASSERT_FALSE(NULL == icons);
icons->SetInteger(base::IntToString(128), 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidIconPath));
// Test invalid user scripts list
input_value.reset(valid_value->DeepCopy());
input_value->SetInteger(keys::kContentScripts, 42);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_EQ(errors::kInvalidContentScriptsList, error);
// Test invalid user script item
@@ -164,7 +212,8 @@ TEST(ExtensionTest, InitFromValueInvalid) {
input_value->GetList(keys::kContentScripts, &content_scripts);
ASSERT_FALSE(NULL == content_scripts);
content_scripts->Set(0, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidContentScript));
// Test missing and invalid matches array
@@ -173,25 +222,30 @@ TEST(ExtensionTest, InitFromValueInvalid) {
DictionaryValue* user_script = NULL;
content_scripts->GetDictionary(0, &user_script);
user_script->Remove(keys::kMatches, NULL);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
user_script->Set(keys::kMatches, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatches));
ListValue* matches = new ListValue;
user_script->Set(keys::kMatches, matches);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatchCount));
// Test invalid match element
matches->Set(0, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch));
matches->Set(0, Value::CreateStringValue("chrome://*/*"));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMatch));
// Test missing and invalid files array
@@ -200,45 +254,53 @@ TEST(ExtensionTest, InitFromValueInvalid) {
content_scripts->GetDictionary(0, &user_script);
user_script->Remove(keys::kJs, NULL);
user_script->Remove(keys::kCss, NULL);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
user_script->Set(keys::kJs, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidJsList));
user_script->Set(keys::kCss, new ListValue);
user_script->Set(keys::kJs, new ListValue);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
user_script->Remove(keys::kCss, NULL);
ListValue* files = new ListValue;
user_script->Set(keys::kJs, files);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kMissingFile));
// Test invalid file element
files->Set(0, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidJs));
user_script->Remove(keys::kJs, NULL);
// Test the css element
user_script->Set(keys::kCss, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidCssList));
// Test invalid file element
ListValue* css_files = new ListValue;
user_script->Set(keys::kCss, css_files);
css_files->Set(0, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidCss));
// Test missing and invalid permissions array
input_value.reset(valid_value->DeepCopy());
- EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
ListValue* permissions = NULL;
input_value->GetList(keys::kPermissions, &permissions);
@@ -246,22 +308,26 @@ TEST(ExtensionTest, InitFromValueInvalid) {
permissions = new ListValue;
input_value->Set(keys::kPermissions, permissions);
- EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
input_value->Set(keys::kPermissions, Value::CreateIntegerValue(9));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermissions));
input_value.reset(valid_value->DeepCopy());
input_value->GetList(keys::kPermissions, &permissions);
permissions->Set(0, Value::CreateIntegerValue(24));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidPermission));
// We allow unknown API permissions, so this will be valid until we better
// distinguish between API and host permissions.
permissions->Set(0, Value::CreateStringValue("www.google.com"));
- EXPECT_TRUE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
// Multiple page actions are not allowed.
input_value.reset(valid_value->DeepCopy());
@@ -272,36 +338,42 @@ TEST(ExtensionTest, InitFromValueInvalid) {
action_list->Append(action->DeepCopy());
action_list->Append(action);
input_value->Set(keys::kPageActions, action_list);
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_STREQ(errors::kInvalidPageActionsListSize, error.c_str());
// Test invalid options page url.
input_value.reset(valid_value->DeepCopy());
input_value->Set(keys::kOptionsPage, Value::CreateNullValue());
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidOptionsPage));
// Test invalid/empty default locale.
input_value.reset(valid_value->DeepCopy());
input_value->Set(keys::kDefaultLocale, Value::CreateIntegerValue(5));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
input_value->Set(keys::kDefaultLocale, Value::CreateStringValue(""));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidDefaultLocale));
// Test invalid minimum_chrome_version.
input_value.reset(valid_value->DeepCopy());
input_value->Set(keys::kMinimumChromeVersion, Value::CreateIntegerValue(42));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kInvalidMinimumChromeVersion));
#if !defined(OS_MACOSX)
// TODO(aa): The version isn't stamped into the unit test binary on mac.
input_value->Set(keys::kMinimumChromeVersion,
Value::CreateStringValue("88.8"));
- EXPECT_FALSE(extension.InitFromValue(*input_value, true, false, &error));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, Extension::REQUIRE_KEY,
+ &error));
EXPECT_TRUE(MatchPattern(error, errors::kChromeVersionTooLow));
#endif
}
@@ -322,7 +394,8 @@ TEST(ExtensionTest, InitFromValueValid) {
input_value.SetString(keys::kVersion, "1.0.0.0");
input_value.SetString(keys::kName, "my extension");
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
EXPECT_TRUE(Extension::IdIsValid(extension.id()));
EXPECT_EQ("1.0.0.0", extension.VersionString());
@@ -337,12 +410,14 @@ TEST(ExtensionTest, InitFromValueValid) {
// We allow unknown API permissions, so this will be valid until we better
// distinguish between API and host permissions.
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
input_value.Remove(keys::kPermissions, NULL);
// Test with an options page.
input_value.SetString(keys::kOptionsPage, "options.html");
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
EXPECT_EQ("chrome-extension", extension.options_url().scheme());
EXPECT_EQ("/options.html", extension.options_url().path());
@@ -351,14 +426,16 @@ TEST(ExtensionTest, InitFromValueValid) {
// from being loaded.
ListValue* empty_list = new ListValue;
input_value.Set(keys::kPageActions, empty_list);
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
#if !defined(OS_MACOSX)
// TODO(aa): The version isn't stamped into the unit test binary on mac.
// Test with a minimum_chrome_version.
input_value.SetString(keys::kMinimumChromeVersion, "1.0");
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
// The minimum chrome version is not stored in the Extension object.
#endif
@@ -388,7 +465,8 @@ TEST(ExtensionTest, InitFromValueValidNameInRTL) {
// No strong RTL characters in name.
std::wstring name(L"Dictionary (by Google)");
input_value.SetString(keys::kName, WideToUTF16Hack(name));
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
std::wstring localized_name(name);
base::i18n::AdjustStringForLocaleDirection(&localized_name);
@@ -397,7 +475,8 @@ TEST(ExtensionTest, InitFromValueValidNameInRTL) {
// Strong RTL characters in name.
name = L"Dictionary (\x05D1\x05D2"L" Google)";
input_value.SetString(keys::kName, WideToUTF16Hack(name));
- EXPECT_TRUE(extension.InitFromValue(input_value, false, false, &error));
+ EXPECT_TRUE(extension.InitFromValue(input_value, Extension::NO_FLAGS,
+ &error));
EXPECT_EQ("", error);
localized_name = name;
base::i18n::AdjustStringForLocaleDirection(&localized_name);
@@ -420,8 +499,8 @@ TEST(ExtensionTest, GetResourceURLAndPath) {
DictionaryValue input_value;
input_value.SetString(keys::kVersion, "1.0.0.0");
input_value.SetString(keys::kName, "my extension");
- scoped_refptr<Extension> extension(Extension::Create(
- path, Extension::INVALID, input_value, false, true, NULL));
+ scoped_refptr<Extension> extension(Extension::Create(path,
+ Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS, NULL));
EXPECT_TRUE(extension.get());
EXPECT_EQ(extension->url().spec() + "bar/baz.js",
@@ -680,7 +759,8 @@ TEST(ExtensionTest, UpdateUrls) {
input_value.SetString(keys::kUpdateURL, url.spec());
scoped_refptr<Extension> extension(Extension::Create(
- path, Extension::INVALID, input_value, false, true, &error));
+ path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS,
+ &error));
EXPECT_TRUE(extension.get()) << error;
}
@@ -704,7 +784,8 @@ TEST(ExtensionTest, UpdateUrls) {
input_value.SetString(keys::kUpdateURL, invalid[i]);
scoped_refptr<Extension> extension(Extension::Create(
- path, Extension::INVALID, input_value, false, true, &error));
+ path, Extension::INVALID, input_value, Extension::STRICT_ERROR_CHECKS,
+ &error));
EXPECT_FALSE(extension.get());
EXPECT_TRUE(MatchPattern(error, errors::kInvalidUpdateURL));
}
@@ -735,7 +816,8 @@ TEST(ExtensionTest, MimeTypeSniffing) {
}
static scoped_refptr<Extension> LoadManifest(const std::string& dir,
- const std::string& test_file) {
+ const std::string& test_file,
+ int extra_flags) {
FilePath path;
PathService::Get(chrome::DIR_TEST_DATA, &path);
path = path.AppendASCII("extensions")
@@ -752,11 +834,17 @@ static scoped_refptr<Extension> LoadManifest(const std::string& dir,
scoped_refptr<Extension> extension = Extension::Create(
path.DirName(), Extension::INVALID,
- *static_cast<DictionaryValue*>(result.get()), false, true, &error);
+ *static_cast<DictionaryValue*>(result.get()),
+ Extension::STRICT_ERROR_CHECKS | extra_flags, &error);
EXPECT_TRUE(extension) << error;
return extension;
}
+static scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file) {
+ return LoadManifest(dir, test_file, Extension::NO_FLAGS);
+}
+
TEST(ExtensionTest, EffectiveHostPermissions) {
scoped_refptr<Extension> extension;
ExtensionExtent hosts;
@@ -933,20 +1021,31 @@ TEST(ExtensionTest, PermissionMessages) {
// The proxy permission is warned as part of host permission checks.
skip.insert(Extension::kProxyPermission);
+ // This permission requires explicit user action (context menu handler)
+ // so we won't prompt for it for now.
+ skip.insert(Extension::kFileBrowserHandlerPermission);
+
// If you've turned on the experimental command-line flag, we don't need
// to warn you further.
skip.insert(Extension::kExperimentalPermission);
- // This is only usable by component extensions.
+ // These are only usable by component extensions.
skip.insert(Extension::kWebstorePrivatePermission);
+ skip.insert(Extension::kFileBrowserPrivatePermission);
+ skip.insert(Extension::kChromeosInfoPrivatePermissions);
+
+ const Extension::PermissionMessage::MessageId ID_NONE =
+ Extension::PermissionMessage::ID_NONE;
for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
- int message_id = Extension::kPermissions[i].message_id;
- std::string name = Extension::kPermissions[i].name;
- if (skip.count(name))
- EXPECT_EQ(0, message_id) << "unexpected message_id for " << name;
- else
- EXPECT_NE(0, message_id) << "missing message_id for " << name;
+ Extension::Permission permission = Extension::kPermissions[i];
+ if (skip.count(permission.name)) {
+ EXPECT_EQ(ID_NONE, permission.message_id)
+ << "unexpected message_id for " << permission.name;
+ } else {
+ EXPECT_NE(ID_NONE, permission.message_id)
+ << "missing message_id for " << permission.name;
+ }
}
}
@@ -973,7 +1072,8 @@ TEST(ExtensionTest, ImageCaching) {
values.SetString(keys::kName, "test");
values.SetString(keys::kVersion, "0.1");
scoped_refptr<Extension> extension(Extension::Create(
- path, Extension::INVALID, values, false, true, &errors));
+ path, Extension::INVALID, values, Extension::STRICT_ERROR_CHECKS,
+ &errors));
ASSERT_TRUE(extension.get());
// Create an ExtensionResource pointing at an icon.
@@ -1057,7 +1157,8 @@ TEST(ExtensionTest, OldUnlimitedStoragePermission) {
// is present.
std::string errors;
scoped_refptr<Extension> extension(Extension::Create(
- extension_path, Extension::INVALID, dictionary, false, true, &errors));
+ extension_path, Extension::INVALID, dictionary,
+ Extension::STRICT_ERROR_CHECKS, &errors));
EXPECT_TRUE(extension.get());
EXPECT_TRUE(extension->HasApiPermission(
Extension::kUnlimitedStoragePermission));
@@ -1105,6 +1206,243 @@ TEST(ExtensionTest, ApiPermissions) {
}
}
+TEST(ExtensionTest, GetHostPermissionMessages_ManyHosts) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "many-hosts.json");
+ std::vector<string16> warnings = extension->GetPermissionMessageStrings();
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("Your data on www.google.com and encrypted.google.com",
+ UTF16ToUTF8(warnings[0]));
+}
+
+TEST(ExtensionTest, GetPermissionMessages_Plugins) {
+ scoped_refptr<Extension> extension;
+ extension = LoadManifest("permissions", "plugins.json");
+ std::vector<string16> warnings = extension->GetPermissionMessageStrings();
+ // We don't parse the plugins key on Chrome OS, so it should not ask for any
+ // permissions.
+#if defined(OS_CHROMEOS)
+ ASSERT_EQ(0u, warnings.size());
+#else
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("All data on your computer and the websites you visit",
+ UTF16ToUTF8(warnings[0]));
+#endif
+}
+
+TEST(ExtensionTest, WantsFileAccess) {
+ scoped_refptr<Extension> extension;
+ GURL file_url("file:///etc/passwd");
+
+ // <all_urls> permission
+ extension = LoadManifest("permissions", "permissions_all_urls.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+ extension = LoadManifest(
+ "permissions", "permissions_all_urls.json", Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+
+ // file:///* permission
+ extension = LoadManifest("permissions", "permissions_file_scheme.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+ extension = LoadManifest("permissions", "permissions_file_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+
+ // http://* permission
+ extension = LoadManifest("permissions", "permissions_http_scheme.json");
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+ extension = LoadManifest("permissions", "permissions_http_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(file_url, NULL, NULL));
+
+ // <all_urls> content script match
+ extension = LoadManifest("permissions", "content_script_all_urls.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+ extension = LoadManifest("permissions", "content_script_all_urls.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+
+ // file:///* content script match
+ extension = LoadManifest("permissions", "content_script_file_scheme.json");
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+ extension = LoadManifest("permissions", "content_script_file_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_TRUE(extension->wants_file_access());
+ EXPECT_TRUE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+
+ // http://* content script match
+ extension = LoadManifest("permissions", "content_script_http_scheme.json");
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+ extension = LoadManifest("permissions", "content_script_http_scheme.json",
+ Extension::ALLOW_FILE_ACCESS);
+ EXPECT_FALSE(extension->wants_file_access());
+ EXPECT_FALSE(extension->CanExecuteScriptOnPage(
+ file_url, &extension->content_scripts()[0], NULL));
+}
+
+// Base class for testing the CanExecuteScriptOnPage and CanCaptureVisiblePage
+// methods of Extension for extensions with various permissions.
+class ExtensionScriptAndCaptureVisibleTest : public testing::Test {
+ public:
+ ExtensionScriptAndCaptureVisibleTest() {
+ PathService::Get(chrome::DIR_TEST_DATA, &dirpath_);
+ }
+
+ scoped_refptr<Extension> MakeExtension(const std::string& permissions,
+ Extension::Location location) {
+ // Replace single-quotes with double-quotes in permissions, since JSON
+ // mandates double-quotes.
+ std::string munged_permissions = permissions;
+ ReplaceSubstringsAfterOffset(&munged_permissions, 0, "'", "\"");
+
+ DictionaryValue dictionary;
+ dictionary.SetString(keys::kName, "permission test");
+ dictionary.SetString(keys::kVersion, "1");
+ std::string error;
+ JSONStringValueSerializer serializer(munged_permissions);
+ scoped_ptr<Value> permission_value(serializer.Deserialize(NULL, &error));
+ EXPECT_EQ("", error);
+ if (!permission_value.get())
+ return NULL;
+ EXPECT_TRUE(permission_value->IsType(Value::TYPE_LIST));
+ dictionary.Set(keys::kPermissions, permission_value.release());
+
+ FilePath dirpath;
+ PathService::Get(chrome::DIR_TEST_DATA, &dirpath);
+ dirpath = dirpath.AppendASCII("extensions").AppendASCII("permissions");
+
+ scoped_refptr<Extension> extension = Extension::Create(
+ dirpath,
+ location,
+ dictionary,
+ Extension::STRICT_ERROR_CHECKS,
+ &error);
+ if (!extension)
+ VLOG(1) << error;
+ return extension;
+ }
+
+ bool Allowed(const Extension* extension, const GURL& url) {
+ return (extension->CanExecuteScriptOnPage(url, NULL, NULL) &&
+ extension->CanCaptureVisiblePage(url, NULL));
+ }
+
+ bool CaptureOnly(const Extension* extension, const GURL& url) {
+ return !extension->CanExecuteScriptOnPage(url, NULL, NULL) &&
+ extension->CanCaptureVisiblePage(url, NULL);
+ }
+
+ bool Blocked(const Extension* extension, const GURL& url) {
+ return !(extension->CanExecuteScriptOnPage(url, NULL, NULL) ||
+ extension->CanCaptureVisiblePage(url, NULL));
+ }
+
+ protected:
+ FilePath dirpath_;
+};
+
+TEST_F(ExtensionScriptAndCaptureVisibleTest, Permissions) {
+ scoped_refptr<Extension> extension;
+ // URLs that are "safe" to provide scripting and capture visible tab access
+ // to if the permissions allow it.
+ GURL http_url("http://www.google.com");
+ GURL https_url("https://www.google.com");
+ GURL file_url("file:///foo/bar");
+
+ // We should allow host permission but not scripting permission for favicon
+ // urls.
+ GURL favicon_url("chrome://favicon/http://www.google.com");
+
+ std::string dummy_id =
+ Extension::GenerateIdForPath(FilePath(FILE_PATH_LITERAL("whatever")));
+
+ // URLs that regular extensions should never get access to.
+ GURL extension_url("chrome-extension://" + dummy_id);
+ GURL settings_url("chrome://settings");
+ GURL about_url("about:flags");
+
+ // Test <all_urls> for regular extensions.
+ extension = MakeExtension("['tabs','<all_urls>']", Extension::INTERNAL);
+ EXPECT_TRUE(Allowed(extension, http_url));
+ EXPECT_TRUE(Allowed(extension, https_url));
+ EXPECT_TRUE(Blocked(extension, file_url));
+ EXPECT_TRUE(Blocked(extension, settings_url));
+ EXPECT_TRUE(CaptureOnly(extension, favicon_url));
+ EXPECT_TRUE(Blocked(extension, about_url));
+ EXPECT_TRUE(Blocked(extension, extension_url));
+
+ EXPECT_FALSE(extension->HasHostPermission(settings_url));
+ EXPECT_FALSE(extension->HasHostPermission(about_url));
+ EXPECT_TRUE(extension->HasHostPermission(favicon_url));
+
+ // Test * for scheme, which implies just the http/https schemes.
+ extension = MakeExtension("['tabs','*://*/']", Extension::INTERNAL);
+ EXPECT_TRUE(Allowed(extension, http_url));
+ EXPECT_TRUE(Allowed(extension, https_url));
+ EXPECT_TRUE(Blocked(extension, settings_url));
+ EXPECT_TRUE(Blocked(extension, about_url));
+ EXPECT_TRUE(Blocked(extension, file_url));
+ EXPECT_TRUE(Blocked(extension, favicon_url));
+ extension = MakeExtension("['tabs','*://settings/*']", Extension::INTERNAL);
+ EXPECT_TRUE(Blocked(extension, settings_url));
+
+ // Having chrome://*/ should not work for regular extensions. Note that
+ // for favicon access, we require the explicit pattern chrome://favicon/*.
+ extension = MakeExtension("['tabs','chrome://*/']",
+ Extension::INTERNAL);
+ EXPECT_TRUE(extension == NULL);
+
+ // Having chrome://favicon/* should not give you chrome://*
+ extension = MakeExtension("['tabs','chrome://favicon/*']",
+ Extension::INTERNAL);
+ EXPECT_TRUE(Blocked(extension, settings_url));
+ EXPECT_TRUE(CaptureOnly(extension, favicon_url));
+ EXPECT_TRUE(Blocked(extension, about_url));
+ EXPECT_TRUE(extension->HasHostPermission(favicon_url));
+
+ // Having http://favicon should not give you chrome://favicon
+ extension = MakeExtension("['tabs', 'http://favicon/']", Extension::INTERNAL);
+ EXPECT_TRUE(Blocked(extension, settings_url));
+ EXPECT_TRUE(Blocked(extension, favicon_url));
+
+ // Component extensions with <all_urls> should get everything.
+ extension = MakeExtension("['tabs','<all_urls>']", Extension::COMPONENT);
+ EXPECT_TRUE(Allowed(extension, http_url));
+ EXPECT_TRUE(Allowed(extension, https_url));
+ EXPECT_TRUE(Allowed(extension, settings_url));
+ EXPECT_TRUE(Allowed(extension, about_url));
+ EXPECT_TRUE(Allowed(extension, favicon_url));
+ EXPECT_TRUE(extension->HasHostPermission(favicon_url));
+
+ // Component extensions should only get access to what they ask for.
+ extension = MakeExtension("['tabs', 'http://www.google.com/']",
+ Extension::COMPONENT);
+ EXPECT_TRUE(Allowed(extension, http_url));
+ EXPECT_TRUE(Blocked(extension, https_url));
+ EXPECT_TRUE(Blocked(extension, file_url));
+ EXPECT_TRUE(Blocked(extension, settings_url));
+ EXPECT_TRUE(Blocked(extension, favicon_url));
+ EXPECT_TRUE(Blocked(extension, about_url));
+ EXPECT_TRUE(Blocked(extension, extension_url));
+ EXPECT_FALSE(extension->HasHostPermission(settings_url));
+}
+
+
TEST(ExtensionTest, GetDistinctHostsForDisplay) {
std::vector<std::string> expected;
expected.push_back("www.foo.com");
@@ -1194,6 +1532,9 @@ TEST(ExtensionTest, GetDistinctHostsForDisplay) {
// This is an unknown RCD, which shouldn't be uniqued out.
actual.push_back(
URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
+ // But it should only occur once.
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
expected.push_back("www.foo.xyzzy");
@@ -1214,6 +1555,88 @@ TEST(ExtensionTest, GetDistinctHostsForDisplay) {
}
}
+TEST(ExtensionTest, GetDistinctHostsForDisplay_ComIsBestRcd) {
+ URLPatternList actual;
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.com");
+
+ CompareLists(expected,
+ Extension::GetDistinctHostsForDisplay(actual));
+}
+
+TEST(ExtensionTest, GetDistinctHostsForDisplay_NetIs2ndBestRcd) {
+ URLPatternList actual;
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.net");
+
+ CompareLists(expected,
+ Extension::GetDistinctHostsForDisplay(actual));
+}
+
+TEST(ExtensionTest, GetDistinctHostsForDisplay_OrgIs3rdBestRcd) {
+ URLPatternList actual;
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ // No http://www.foo.net/path
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.org");
+
+ CompareLists(expected,
+ Extension::GetDistinctHostsForDisplay(actual));
+}
+
+TEST(ExtensionTest, GetDistinctHostsForDisplay_FirstInListIs4thBestRcd) {
+ URLPatternList actual;
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ // No http://www.foo.org/path
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ // No http://www.foo.net/path
+ actual.push_back(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.ca");
+
+ CompareLists(expected,
+ Extension::GetDistinctHostsForDisplay(actual));
+}
+
TEST(ExtensionTest, IsElevatedHostList) {
URLPatternList list1;
URLPatternList list2;
@@ -1273,7 +1696,7 @@ TEST(ExtensionTest, IsElevatedHostList) {
TEST(ExtensionTest, GenerateId) {
std::string result;
- EXPECT_FALSE(Extension::GenerateId("", &result));
+ EXPECT_TRUE(Extension::GenerateId("", &result));
EXPECT_TRUE(Extension::GenerateId("test", &result));
EXPECT_EQ(result, "jpignaibiiemhngfjkcpokkamffknabf");
diff --git a/chrome/common/extensions/extension_unpacker.cc b/chrome/common/extensions/extension_unpacker.cc
index fee4b54..4c5f30f 100644
--- a/chrome/common/extensions/extension_unpacker.cc
+++ b/chrome/common/extensions/extension_unpacker.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -7,21 +7,21 @@
#include <set>
#include "base/file_util.h"
-#include "base/scoped_handle.h"
-#include "base/scoped_temp_dir.h"
+#include "base/memory/scoped_handle.h"
+#include "base/memory/scoped_temp_dir.h"
#include "base/string_util.h"
#include "base/threading/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "net/base/file_stream.h"
-#include "chrome/common/common_param_traits.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/extension_l10n_util.h"
-#include "chrome/common/json_value_serializer.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/zip.h"
+#include "content/common/common_param_traits.h"
+#include "content/common/json_value_serializer.h"
#include "ipc/ipc_message_utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "webkit/glue/image_decoder.h"
@@ -180,8 +180,7 @@ bool ExtensionUnpacker::Run() {
temp_install_dir_,
Extension::INVALID,
*parsed_manifest_,
- false, // Do not require a key
- false, // Do not enable strict error checks
+ Extension::NO_FLAGS,
&error));
if (!extension.get()) {
SetError(error);
diff --git a/chrome/common/extensions/extension_unpacker.h b/chrome/common/extensions/extension_unpacker.h
index 6883597..0282718 100644
--- a/chrome/common/extensions/extension_unpacker.h
+++ b/chrome/common/extensions/extension_unpacker.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -10,7 +10,7 @@
#include <vector>
#include "base/file_path.h"
-#include "base/scoped_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/tuple.h"
class DictionaryValue;
diff --git a/chrome/common/extensions/extension_unpacker_unittest.cc b/chrome/common/extensions/extension_unpacker_unittest.cc
index 930c271..80ed7a5 100644
--- a/chrome/common/extensions/extension_unpacker_unittest.cc
+++ b/chrome/common/extensions/extension_unpacker_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -6,6 +6,7 @@
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/values.h"
+#include "base/memory/scoped_temp_dir.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_unpacker.h"
@@ -27,12 +28,9 @@ public:
// Try bots won't let us write into DIR_TEST_DATA, so we have to create
// a temp folder to play in.
- ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &install_dir_));
- install_dir_ = install_dir_.AppendASCII("extension_unpacker_test");
- file_util::Delete(install_dir_, true);
- file_util::CreateDirectory(install_dir_);
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- FilePath crx_path = install_dir_.AppendASCII(crx_name);
+ FilePath crx_path = temp_dir_.path().AppendASCII(crx_name);
ASSERT_TRUE(file_util::CopyFile(original_path, crx_path)) <<
"Original path " << original_path.value() <<
", Crx path " << crx_path.value();
@@ -40,13 +38,8 @@ public:
unpacker_.reset(new ExtensionUnpacker(crx_path));
}
- virtual void TearDown() {
- ASSERT_TRUE(file_util::Delete(install_dir_, true)) <<
- install_dir_.value();
- }
-
protected:
- FilePath install_dir_;
+ ScopedTempDir temp_dir_;
scoped_ptr<ExtensionUnpacker> unpacker_;
};
diff --git a/chrome/common/extensions/file_browser_handler.cc b/chrome/common/extensions/file_browser_handler.cc
new file mode 100644
index 0000000..ea270b4
--- /dev/null
+++ b/chrome/common/extensions/file_browser_handler.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 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.
+
+#include "chrome/common/extensions/file_browser_handler.h"
+
+#include "chrome/common/extensions/url_pattern.h"
+#include "googleurl/src/gurl.h"
+
+FileBrowserHandler::FileBrowserHandler() {
+}
+
+FileBrowserHandler::~FileBrowserHandler() {
+}
+
+void FileBrowserHandler::AddPattern(const URLPattern& pattern) {
+ patterns_.push_back(pattern);
+}
+
+void FileBrowserHandler::ClearPatterns() {
+ patterns_.clear();
+}
+
+bool FileBrowserHandler::MatchesURL(const GURL& url) const {
+ for (PatternList::const_iterator pattern = patterns_.begin();
+ pattern != patterns_.end(); ++pattern) {
+ if (pattern->MatchesUrl(url))
+ return true;
+ }
+ return false;
+}
+
diff --git a/chrome/common/extensions/file_browser_handler.h b/chrome/common/extensions/file_browser_handler.h
new file mode 100644
index 0000000..420be17
--- /dev/null
+++ b/chrome/common/extensions/file_browser_handler.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 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.
+
+#ifndef CHROME_COMMON_EXTENSIONS_FILE_BROWSER_HANDLER_H_
+#define CHROME_COMMON_EXTENSIONS_FILE_BROWSER_HANDLER_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "chrome/common/extensions/url_pattern.h"
+#include "googleurl/src/gurl.h"
+
+class URLPattern;
+
+// FileBrowserHandler encapsulates the state of a file browser action.
+class FileBrowserHandler {
+ public:
+ typedef std::vector<URLPattern> PatternList;
+
+ FileBrowserHandler();
+ ~FileBrowserHandler();
+
+ // extension id
+ std::string extension_id() const { return extension_id_; }
+ void set_extension_id(const std::string& extension_id) {
+ extension_id_ = extension_id;
+ }
+
+ // action id
+ const std::string& id() const { return id_; }
+ void set_id(const std::string& id) { id_ = id; }
+
+ // default title
+ const std::string& title() const { return title_; }
+ void set_title(const std::string& title) { title_ = title; }
+
+ // File schema URL patterns.
+ const PatternList& file_url_patterns() const { return patterns_; }
+ void AddPattern(const URLPattern& pattern);
+ bool MatchesURL(const GURL& url) const;
+ void ClearPatterns();
+
+ // Action icon path.
+ const std::string icon_path() const { return default_icon_path_; }
+ void set_icon_path(const std::string& path) {
+ default_icon_path_ = path;
+ }
+
+ private:
+ // The id for the extension this action belongs to (as defined in the
+ // extension manifest).
+ std::string extension_id_;
+ std::string title_;
+ std::string default_icon_path_;
+ // The id for the FileBrowserHandler, for example: "PdfFileAction".
+ std::string id_;
+ // A list of file filters.
+ PatternList patterns_;
+};
+
+#endif // CHROME_COMMON_EXTENSIONS_FILE_BROWSER_HANDLER_H_
diff --git a/chrome/common/extensions/update_manifest.cc b/chrome/common/extensions/update_manifest.cc
index 8970aa5..713898f 100644
--- a/chrome/common/extensions/update_manifest.cc
+++ b/chrome/common/extensions/update_manifest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -6,7 +6,7 @@
#include <algorithm>
-#include "base/scoped_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
diff --git a/chrome/common/extensions/update_manifest_unittest.cc b/chrome/common/extensions/update_manifest_unittest.cc
index 0de8df0..9af11df 100644
--- a/chrome/common/extensions/update_manifest_unittest.cc
+++ b/chrome/common/extensions/update_manifest_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
-#include "base/scoped_vector.h"
+#include "base/memory/scoped_vector.h"
#include "chrome/common/extensions/update_manifest.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "libxml/globals.h"
diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc
index 5eb0beb..986487a 100644
--- a/chrome/common/extensions/url_pattern.cc
+++ b/chrome/common/extensions/url_pattern.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -24,6 +24,7 @@ const char* kValidSchemes[] = {
chrome::kFileScheme,
chrome::kFtpScheme,
chrome::kChromeUIScheme,
+ chrome::kFileSystemScheme,
};
const int kValidSchemeMasks[] = {
@@ -32,6 +33,7 @@ const int kValidSchemeMasks[] = {
URLPattern::SCHEME_FILE,
URLPattern::SCHEME_FTP,
URLPattern::SCHEME_CHROMEUI,
+ URLPattern::SCHEME_FILESYSTEM,
};
COMPILE_ASSERT(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks),
@@ -230,10 +232,10 @@ bool URLPattern::MatchesUrl(const GURL &test) const {
}
bool URLPattern::MatchesScheme(const std::string& test) const {
- if (scheme_ == "*")
- return IsValidScheme(test);
+ if (!IsValidScheme(test))
+ return false;
- return test == scheme_;
+ return scheme_ == "*" || test == scheme_;
}
bool URLPattern::MatchesHost(const std::string& host) const {
@@ -333,7 +335,7 @@ bool URLPattern::OverlapsWith(const URLPattern& other) const {
std::vector<URLPattern> URLPattern::ConvertToExplicitSchemes() const {
std::vector<URLPattern> result;
- if (scheme_ != "*" && !match_all_urls_) {
+ if (scheme_ != "*" && !match_all_urls_ && IsValidScheme(scheme_)) {
result.push_back(*this);
return result;
}
diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h
index edd92d4..cf89382 100644
--- a/chrome/common/extensions/url_pattern.h
+++ b/chrome/common/extensions/url_pattern.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
#ifndef CHROME_COMMON_EXTENSIONS_URL_PATTERN_H_
@@ -77,12 +77,13 @@ class URLPattern {
public:
// A collection of scheme bitmasks for use with valid_schemes.
enum SchemeMasks {
- SCHEME_NONE = 0,
- SCHEME_HTTP = 1 << 0,
- SCHEME_HTTPS = 1 << 1,
- SCHEME_FILE = 1 << 2,
- SCHEME_FTP = 1 << 3,
- SCHEME_CHROMEUI = 1 << 4,
+ SCHEME_NONE = 0,
+ SCHEME_HTTP = 1 << 0,
+ SCHEME_HTTPS = 1 << 1,
+ SCHEME_FILE = 1 << 2,
+ SCHEME_FTP = 1 << 3,
+ SCHEME_CHROMEUI = 1 << 4,
+ SCHEME_FILESYSTEM = 1 << 5,
// SCHEME_ALL will match every scheme, including chrome://, chrome-
// extension://, about:, etc. Because this has lots of security
// implications, third-party extensions should never be able to get access
diff --git a/chrome/common/extensions/url_pattern_unittest.cc b/chrome/common/extensions/url_pattern_unittest.cc
index cc9c605..ef1406b 100644
--- a/chrome/common/extensions/url_pattern_unittest.cc
+++ b/chrome/common/extensions/url_pattern_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
-#include "base/scoped_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "chrome/common/extensions/url_pattern.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/common/extensions/user_script.cc b/chrome/common/extensions/user_script.cc
index a73b65b..6439338 100644
--- a/chrome/common/extensions/user_script.cc
+++ b/chrome/common/extensions/user_script.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -61,8 +61,7 @@ UserScript::File::~File() {}
UserScript::UserScript()
: run_location_(DOCUMENT_IDLE), emulate_greasemonkey_(false),
- match_all_frames_(false), incognito_enabled_(false),
- allow_file_access_(false) {
+ match_all_frames_(false), incognito_enabled_(false) {
}
UserScript::~UserScript() {
@@ -72,8 +71,6 @@ void UserScript::add_url_pattern(const URLPattern& pattern) {
url_patterns_.push_back(pattern);
}
-void UserScript::clear_url_patterns() { url_patterns_.clear(); }
-
bool UserScript::MatchesUrl(const GURL& url) const {
if (!url_patterns_.empty()) {
if (!UrlMatchesPatterns(&url_patterns_, url))
@@ -113,7 +110,6 @@ void UserScript::Pickle(::Pickle* pickle) const {
pickle->WriteBool(emulate_greasemonkey());
pickle->WriteBool(match_all_frames());
pickle->WriteBool(is_incognito_enabled());
- pickle->WriteBool(allow_file_access());
// Write globs.
std::vector<std::string>::const_iterator glob;
@@ -160,7 +156,6 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) {
CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_));
CHECK(pickle.ReadBool(iter, &match_all_frames_));
CHECK(pickle.ReadBool(iter, &incognito_enabled_));
- CHECK(pickle.ReadBool(iter, &allow_file_access_));
// Read globs.
size_t num_globs = 0;
@@ -191,8 +186,18 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) {
std::string pattern_str;
URLPattern pattern(valid_schemes);
CHECK(pickle.ReadString(iter, &pattern_str));
+
+ // We remove the file scheme if it's not actually allowed (see Extension::
+ // LoadUserScriptHelper), but we need it temporarily while loading the
+ // pattern so that it's valid.
+ bool had_file_scheme = (valid_schemes & URLPattern::SCHEME_FILE) != 0;
+ if (!had_file_scheme)
+ pattern.set_valid_schemes(valid_schemes | URLPattern::SCHEME_FILE);
CHECK(URLPattern::PARSE_SUCCESS ==
pattern.Parse(pattern_str, URLPattern::PARSE_LENIENT));
+ if (!had_file_scheme)
+ pattern.set_valid_schemes(valid_schemes);
+
url_patterns_.push_back(pattern);
}
diff --git a/chrome/common/extensions/user_script.h b/chrome/common/extensions/user_script.h
index 3be2f11..3d91de1 100644
--- a/chrome/common/extensions/user_script.h
+++ b/chrome/common/extensions/user_script.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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.
@@ -152,7 +152,6 @@ class UserScript {
// against.
const PatternList& url_patterns() const { return url_patterns_; }
void add_url_pattern(const URLPattern& pattern);
- void clear_url_patterns();
// List of js scripts for this user script
FileList& js_scripts() { return js_scripts_; }
@@ -168,9 +167,6 @@ class UserScript {
bool is_incognito_enabled() const { return incognito_enabled_; }
void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
- bool allow_file_access() const { return allow_file_access_; }
- void set_allow_file_access(bool allowed) { allow_file_access_ = allowed; }
-
bool is_standalone() const { return extension_id_.empty(); }
// Returns true if the script should be applied to the specified URL, false
@@ -233,9 +229,6 @@ class UserScript {
// True if the script should be injected into an incognito tab.
bool incognito_enabled_;
-
- // True if the user agreed to allow this script access to file URLs.
- bool allow_file_access_;
};
typedef std::vector<UserScript> UserScriptList;