diff options
16 files changed, 743 insertions, 484 deletions
diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd index aa8c83a..2597d14 100644 --- a/chrome/common/common_resources.grd +++ b/chrome/common/common_resources.grd @@ -11,6 +11,7 @@ <includes> <include name="IDR_JSTEMPLATE_JS" file="..\third_party\jstemplate\jstemplate_compiled.js" type="BINDATA" /> <include name="IDR_I18N_TEMPLATE_JS" file="..\browser\resources\i18n_template.js" type="BINDATA" /> + <include name="IDR_EXTENSION_API_JSON" file="extensions\api\extension_api.json" type="BINDATA" /> </includes> </release> </grit>
\ No newline at end of file diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json new file mode 100755 index 0000000..b2c30a3 --- /dev/null +++ b/chrome/common/extensions/api/extension_api.json @@ -0,0 +1,486 @@ +[ + { + namespace: "windows", + types: [], + functions: [ + { + name: "get", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0}, + {type: "function", name: "callback"} + ] + }, + { + name: "getCurrent", + type: "function", + description: "", + parameters: [ + {type: "function", name: "callback"} + ] + }, + { + name: "getLastFocused", + type: "function", + description: "", + parameters: [ + {type: "function", name: "callback"} + ] + }, + { + name: "getAll", + type: "function", + description: "", + parameters: [ + {type: "boolean", name: "populate", optional: true}, + {type: "function", name: "callback"} + ] + }, + { + name: "create", + type: "function", + description: "", + parameters: [ + { + type: "object", + name: "CreateData", + properties: { + url: {type: "string", optional: true}, + left: {type: "integer", optional: true}, + top: {type: "integer", optional: true}, + width: {type: "integer", minimum: 0, optional: true}, + height: {type: "integer", minimum: 0, optional: true} + }, + optional: true + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "update", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0}, + { + type: "object", + name: "UpdateInfo", + properties: { + left: {type: "integer", optional: true}, + top: {type: "integer", optional: true}, + width: {type: "integer", minimum: 0, optional: true}, + height: {type: "integer", minimum: 0, optional: true} + }, + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "remove", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0}, + {type: "function", name: "callback", optional: true} + ] + }, + ], + events: [ + { + name: "onCreated", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0} + ] + }, + { + name: "onRemoved", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0} + ] + }, + { + name: "onFocusChanged", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0} + ] + } + ] + }, + { + namespace: "tabs", + types: [], + functions: [ + { + name: "get", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "function", name: "callback"} + ] + }, + { + name: "getSelected", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0, optional: true}, + {type: "function", name: "callback"} + ] + }, + { + name: "getAllInWindow", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "windowId", minimum: 0, optional: true}, + {type: "function", name: "callback"} + ] + }, + { + name: "create", + type: "function", + description: "", + parameters: [ + { + type: "object", + name: "CreateProperties", + properties: { + windowId: {type: "integer", minimum: 0, optional: true}, + index: {type: "integer", minimum: 0, optional: true}, + url: {type: "string", optional: true}, + selected: {type: "boolean", optional: true} + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "update", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + { + type: "object", + name: "UpdateProperties", + properties: { + url: {type: "string", optional: true}, + selected: {type: "boolean", optional: true} + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "move", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + { + type: "object", + name: "MoveProperties", + properties: { + windowId: {type: "integer", minimum: 0, optional: true}, + index: {type: "integer", minimum: 0} + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "remove", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0, optional: true}, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "detectLanguage", + type: "function", + description: "detect language of tab.", + parameters: [ + {type: "integer", name: "tabId", minimum: 0, optional: true}, + {type: "function", name: "callback"} + ] + } + ], + events: [ + { + name: "onCreated", + type: "function", + description: "", + parameters: [ + {type: "Object", name: "Tab"} + ] + }, + { + name: "onUpdated", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "Object", name: "ChangedProps"} + ] + }, + { + name: "onMoved", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "Object", name: "MoveInfo"} + ] + }, + { + name: "onSelectionChanged", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "Object", name: "SelectionInfo"} + ] + }, + { + name: "onAttached", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "Object", name: "AttachInfo"} + ] + }, + { + name: "onDetached", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0}, + {type: "Object", name: "DetachInfo"} + ] + }, + { + name: "onRemoved", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "tabId", minimum: 0} + ] + } + ] + }, + { + namespace: "pageActions", + types: [], + functions: [ + { + name: "enableForTab", + type: "function", + description: "", + parameters: [ + {type: "string", name: "pageActionId"}, + { + type: "object", + name: "action", + properties: { + tabId: {type: "integer", minimum: 0}, + url: {type: "string"}, + title: {type: "string", optional: true}, + iconId: {type: "integer", minimum: 0, optional: true} + }, + optional: false + } + ] + }, + { + name: "disableForTab", + type: "function", + description: "", + parameters: [ + {type: "string", name: "pageActionId"}, + { + type: "object", + name: "action", + properties: { + tabId: {type: "integer", minimum: 0}, + url: {type: "string"} + }, + optional: false + } + ] + } + ], + events: [ + ] + }, + { + namespace: "bookmarks", + types: [], + functions: [ + { + name: "get", + type: "function", + description: "", + parameters: [ + { + name: "idOrIdList", + choice : [ + {type: "integer", minimum: 0}, + {type: "array", item: {type: "integer", minimum: 0}, minItems: 1} + ] + }, + {type: "function", name: "callback"} + ] + }, + { + name: "getChildren", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + {type: "function", name: "callback"} + ] + }, + { + name: "getTree", + type: "function", + description: "", + parameters: [ + {type: "function", name: "callback"} + ] + }, + { + name: "search", + type: "function", + description: "", + parameters: [ + {type: "string", name: "query"}, + {type: "function", name: "callback"} + ] + }, + { + name: "create", + type: "function", + description: "", + parameters: [ + { + type: "object", + name: "bookmark", + properties: { + parentId: {type: "integer", minimum: 0, optional: true}, + index: {type: "integer", minimum: 0, optional: true}, + title: {type: "string", optional: true}, + url: {type: "string", optional: true}, + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "move", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "object", + name: "destination", + properties: { + parentId: {type: "integer", minimum: 0, optional: true}, + index: {type: "integer", minimum: 0, optional: true} + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + { + name: "update", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "object", + name: "changes", + properties: { + title: {type: "string", optional: true} + } + }, + {type: "function", name: "callback", optional: true} + ] + }, + ], + events: [ + { + name: "onAdded", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "Object", + name: "bookmark", + } + ] + }, + { + name: "onRemoved", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "Object", + name: "RemoveInfo", + } + ] + }, + { + name: "onChanged", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "Object", + name: "ChangeInfo", + } + ] + }, + { + name: "onMoved", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "Object", + name: "MoveInfo", + } + ] + }, + { + name: "onChildrenReordered", + type: "function", + description: "", + parameters: [ + {type: "integer", name: "id", minimum: 0}, + { + type: "Object", + name: "childIds", + } + ] + } + ] + } +] diff --git a/chrome/common/extensions/docs/css/ApiRefStyles.css b/chrome/common/extensions/docs/css/ApiRefStyles.css index d781b7d..2626359 100755 --- a/chrome/common/extensions/docs/css/ApiRefStyles.css +++ b/chrome/common/extensions/docs/css/ApiRefStyles.css @@ -3,6 +3,10 @@ body { font-size: 13px; } +.todo { + color: red; +} + h2,h3 { margin-top: 2em; } diff --git a/chrome/common/extensions/docs/js/api_page_generator.js b/chrome/common/extensions/docs/js/api_page_generator.js index 3aa87bf..01ff9e2d 100755 --- a/chrome/common/extensions/docs/js/api_page_generator.js +++ b/chrome/common/extensions/docs/js/api_page_generator.js @@ -9,9 +9,8 @@ * * - To have available via XHR (relative path): * 1) API_TEMPLATE which is the main template for the api pages. - * 2) A file located at SCHEMA_PATH + |apiName| + SCHEMA_EXTENSION - * which is shared with the extension system and defines the methods and - * events contained in one api. + * 2) A file located at SCHEMA which is shared with the extension system and + * defines the methods and events contained in one api. * 3) An |apiName| + OVERVIEW_EXTENSION file which contains static authored * content that is inserted into the "overview" slot in the API_TEMPLATE. * @@ -23,8 +22,7 @@ */ var API_TEMPLATE = "../template/api_template.html"; -var SCHEMA_PATH = "../../api/"; -var SCHEMA_EXTENSION = ".json"; +var SCHEMA = "../../api/extension_api.json"; var OVERVIEW_EXTENSION = "_overview.html"; var REQUEST_TIMEOUT = 2000; @@ -34,24 +32,25 @@ Array.prototype.each = function(f) { } } +// name of the api this reference page is describing. i.e. "bookmarks", "tabs". +var apiName; + window.onload = function() { // Determine api module being rendered. Expect ".../<apiName>.html" var pathParts = document.location.href.split(/\/|\./); - var apiName = pathParts[pathParts.length - 2]; - var apiOverviewName = apiName + OVERVIEW_EXTENSION; - var apiSchemaName = SCHEMA_PATH + apiName + SCHEMA_EXTENSION; + apiName = pathParts[pathParts.length - 2]; // Fetch the api template and insert into the <body>. fetchContent(API_TEMPLATE, function(templateContent) { document.getElementsByTagName("body")[0].innerHTML = templateContent; // Fetch the overview and insert into the "overview" <div>. - fetchContent(apiOverviewName, function(overviewContent) { + fetchContent(apiName + OVERVIEW_EXTENSION, function(overviewContent) { document.getElementById("overview").innerHTML = overviewContent; // Now the page is composed with the authored content, we fetch the schema // and populate the templates. - fetchContent(apiSchemaName, renderTemplate); + fetchContent(SCHEMA, renderTemplate); }); }); } @@ -96,12 +95,19 @@ function fetchContent(url, onSuccess) { } /** - * Parses the content in |module| to json, adds any additional required values, - * renders to html via JSTemplate, and unhides the <body>. + * Parses the content in |schema| to json, find appropriate api, adds any + * additional required values, renders to html via JSTemplate, and unhides the + * <body>. * This uses the root <html> element (the entire document) as the template. */ -function renderTemplate(module) { - var apiDefinition = JSON.parse(module); +function renderTemplate(schema) { + var apiDefinition; + + JSON.parse(schema).each(function(module) { + if (module.namespace == apiName) + apiDefinition = module; + }); + preprocessApi(apiDefinition); // Render to template @@ -119,17 +125,58 @@ function renderTemplate(module) { */ function preprocessApi(schema) { schema.functions.each(function(f) { - f.fullName = schema.namespace + "." + f.name; - if (f.callbackParameters) { - f.callbackSignature = generateSignatureString(f.callbackParameters); + f.fullName = "chrome." + schema.namespace + "." + f.name; + assignTypeNames(f); + + // Look for a callback that defines parameters. + if (f.parameters.length > 0) { + var lastParam = f.parameters[f.parameters.length - 1]; + if (lastParam.type == "function" && lastParam.parameters) { + assignTypeNames(lastParam); + f.callbackParameters = lastParam.parameters; + f.callbackSignature = generateSignatureString(lastParam.parameters); + } } }); schema.events.each(function(e) { + assignTypeNames(e); e.callSignature = generateSignatureString(e.parameters); }); } +/** + * Assigns a typeName(param) to each of the parameters of |f|. + */ +function assignTypeNames(f) { + f.parameters.each(function(p) { + p.typeName = typeName(p); + }); +} + +/** + * Generates a short text summary of the |schema| type + */ +function typeName(schema) { + if (schema.$ref) + return schema.$ref; + + if (schema.choice) { + var typeNames = []; + schema.choice.each(function(c) { + typeNames.push(typeName(c)); + }); + + return typeNames.join(" or "); + } + + if (schema.type == "array") { + return "array of " + typeName(schema.item); + } + + return schema.type; +} + /** * Generates a simple string representation of the signature of a function * whose |parameters| are json schemas. @@ -137,7 +184,7 @@ function preprocessApi(schema) { function generateSignatureString(parameters) { var retval = []; parameters.each(function(param, i) { - retval.push(param.type + " " + (param.type ? param.type : param["$ref"])); + retval.push(param.typeName + " " + param.name); }); return retval.join(", "); diff --git a/chrome/common/extensions/docs/reference/bookmarks.html b/chrome/common/extensions/docs/reference/bookmarks.html index 092ef1f..c771bc1 100755 --- a/chrome/common/extensions/docs/reference/bookmarks.html +++ b/chrome/common/extensions/docs/reference/bookmarks.html @@ -29,4 +29,4 @@ and rewritten. --> <body class="hidden"> </body> -</html>
\ No newline at end of file +</html> diff --git a/chrome/common/extensions/docs/reference/pageActions.html b/chrome/common/extensions/docs/reference/pageActions.html new file mode 100755 index 0000000..c05e097 --- /dev/null +++ b/chrome/common/extensions/docs/reference/pageActions.html @@ -0,0 +1,33 @@ +<!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. + 2) The <body> tag *must* retain id="body" + 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. + + TODO(rafaelw): Abstract this into a "pageshell" that becomes the single + version of page template shell and the "instance" pages (bookmarks.html, + etc...) can be generated with a build step. +--> +<!-- <html> must retain id="template --> +<html xmlns="http://www.w3.org/1999/xhtml"> + <!-- <head> data is significant and loads the needed libraries and styles --> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title jscontent="namespace">chrome.apiname</title> + <link href="../css/ApiRefStyles.css" rel="stylesheet" type="text/css"> + <script type="text/javascript" + src="../../../../third_party/jstemplate/jstemplate_compiled.js"> + </script> + <script type="text/javascript" src="../js/api_page_generator.js"></script> + </head> + <!-- <body> content is completely generated. Do not edit, as it will be + and rewritten. --> + <body class="hidden"> + </body> +</html> diff --git a/chrome/common/extensions/docs/reference/pageActions_overview.html b/chrome/common/extensions/docs/reference/pageActions_overview.html new file mode 100755 index 0000000..997b579 --- /dev/null +++ b/chrome/common/extensions/docs/reference/pageActions_overview.html @@ -0,0 +1,5 @@ +<!-- BEGIN AUTHORED CONTENT --> +<p class="todo"> +[PENDING: API Module Overview Goes Here] +</p> +<!-- END AUTHORED CONTENT --> diff --git a/chrome/common/extensions/docs/reference/tabs.html b/chrome/common/extensions/docs/reference/tabs.html index a2f8a82..c05e097 100755 --- a/chrome/common/extensions/docs/reference/tabs.html +++ b/chrome/common/extensions/docs/reference/tabs.html @@ -30,4 +30,4 @@ and rewritten. --> <body class="hidden"> </body> -</html>
\ No newline at end of file +</html> diff --git a/chrome/common/extensions/docs/reference/tabs_overview.html b/chrome/common/extensions/docs/reference/tabs_overview.html index de647ae..997b579 100755 --- a/chrome/common/extensions/docs/reference/tabs_overview.html +++ b/chrome/common/extensions/docs/reference/tabs_overview.html @@ -1,11 +1,5 @@ <!-- BEGIN AUTHORED CONTENT --> -<p id="classSummary"> -Use the <code>chrome.tabs</code> API to create, organize, and otherwise manipulate bookmarks. -</p> - -<h2 id="description">Description</h2> - -<p> -[PENDING: intro goes here...] +<p class="todo"> +[PENDING: API Module Overview Goes Here] </p> <!-- END AUTHORED CONTENT --> diff --git a/chrome/common/extensions/docs/reference/windows.html b/chrome/common/extensions/docs/reference/windows.html new file mode 100755 index 0000000..c05e097 --- /dev/null +++ b/chrome/common/extensions/docs/reference/windows.html @@ -0,0 +1,33 @@ +<!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. + 2) The <body> tag *must* retain id="body" + 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. + + TODO(rafaelw): Abstract this into a "pageshell" that becomes the single + version of page template shell and the "instance" pages (bookmarks.html, + etc...) can be generated with a build step. +--> +<!-- <html> must retain id="template --> +<html xmlns="http://www.w3.org/1999/xhtml"> + <!-- <head> data is significant and loads the needed libraries and styles --> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> + <title jscontent="namespace">chrome.apiname</title> + <link href="../css/ApiRefStyles.css" rel="stylesheet" type="text/css"> + <script type="text/javascript" + src="../../../../third_party/jstemplate/jstemplate_compiled.js"> + </script> + <script type="text/javascript" src="../js/api_page_generator.js"></script> + </head> + <!-- <body> content is completely generated. Do not edit, as it will be + and rewritten. --> + <body class="hidden"> + </body> +</html> diff --git a/chrome/common/extensions/docs/reference/windows_overview.html b/chrome/common/extensions/docs/reference/windows_overview.html new file mode 100755 index 0000000..997b579 --- /dev/null +++ b/chrome/common/extensions/docs/reference/windows_overview.html @@ -0,0 +1,5 @@ +<!-- BEGIN AUTHORED CONTENT --> +<p class="todo"> +[PENDING: API Module Overview Goes Here] +</p> +<!-- END AUTHORED CONTENT --> diff --git a/chrome/common/extensions/docs/template/api_template.html b/chrome/common/extensions/docs/template/api_template.html index afa599d..0aa613d 100755 --- a/chrome/common/extensions/docs/template/api_template.html +++ b/chrome/common/extensions/docs/template/api_template.html @@ -69,13 +69,14 @@ <div class="summary">void <!-- Note: intentionally longer 80 columns --> - <span jscontent="fullName">chrome.module.methodName</span>(<span jsselect="parameters" jsvalues="class:optional ? 'optional' : ''"><span jsdisplay="$index">, </span><span jscontent="type"></span> + <span jscontent="fullName">chrome.module.methodName</span>(<span jsselect="parameters" jsvalues="class:optional ? 'optional' : ''"><span jsdisplay="$index">, </span><span jscontent="typeName"></span> <var><span jscontent="name"></span></var></span>)</div> <div class="description"> - <div jsvalues=".innerHTML:description"> + <p class="todo" jsdisplay="!description">Undocumented.</p> + <p jsdisplay="description" jsvalues=".innerHTML:description"> A description from the json schema def of the function goes here. - </div> + </p> <!-- PARAMETERS --> <h4>Parameters</h4> @@ -84,9 +85,10 @@ <dt> <!-- Note: intentionally longer 80 columns --> <var jscontent="name">paramName</var><em> - (<span class="optional" jsdisplay="optional">optional </span><span jsdisplay="$ref" jscontent="$ref">paramType</span><span jsdisplay="type" jscontent="type">paramType</span>)</em> + (<span class="optional" jsdisplay="optional">optional </span><span jscontent="typeName">paramType</span>)</em> </dt> - <dd jsvalues=".innerHTML:description"> + <dd class="todo" jsdisplay="!$this.description">Undocumented.</dd> + <dd jsdisplay="$this.description" jsvalues=".innerHTML:$this.description"> Description of this parameter from the json schema. </dd> </div> @@ -107,9 +109,10 @@ <dt> <!-- Note: intentionally longer 80 columns --> <var jscontent="name">paramName</var><em> - (<span jsdisplay="$ref" jscontent="$ref">paramType</span><span jsdisplay="type" jscontent="type">paramType</span>)</em> + (<span jscontent="typeName">paramType</span>)</em> </dt> - <dd jsvalues=".innerHMTL:description"> + <dd class="todo" jsdisplay="!$this.description">Undocumented.</dd> + <dd jsdisplay="$this.description" jsvalues=".innerHTML:$this.description"> Description of this parameter from the json schema. </dd> </div> @@ -138,8 +141,9 @@ </div> <div class="description"> - <p jsvalues=".innerHTML:description"> - A description from the json schema def of the function goes here. + <p class="todo" jsdisplay="!description">Undocumented.</p> + <p jsdisplay="description" jsvalues=".innerHTML:description"> + A description from the json schema def of the event goes here. </p> <!-- PARAMETERS --> @@ -148,9 +152,10 @@ <div jsselect="parameters"> <dt> <!-- Note: intentionally longer 80 columns --> - <var jscontent="name">paramName</var><em> (<span jsdisplay="$ref" jscontent="$ref">paramType</span><span jsdisplay="type" jscontent="type">paramType</span>)</em> + <var jscontent="name">paramName</var><em> (<span jscontent="typeName">paramType</span>)</em> </dt> - <dd jsvalues=".innerHTML:description"> + <dd class="todo" jsdisplay="!$this.description">Undocumented.</dd> + <dd jsdisplay="$this.description" jsvalues=".innerHTML:$this.description"> Description of this parameter from the json schema. </dd> </div> diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc index 1e4bafe1..fd92481 100644 --- a/chrome/renderer/extensions/extension_process_bindings.cc +++ b/chrome/renderer/extensions/extension_process_bindings.cc @@ -12,6 +12,7 @@ #include "chrome/renderer/extensions/renderer_extension_bindings.h" #include "chrome/renderer/js_only_v8_extensions.h" #include "chrome/renderer/render_view.h" +#include "grit/common_resources.h" #include "grit/renderer_resources.h" #include "webkit/glue/webframe.h" @@ -64,7 +65,9 @@ class ExtensionImpl : public ExtensionBase { virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( v8::Handle<v8::String> name) { - if (name->Equals(v8::String::New("GetViews"))) { + if (name->Equals(v8::String::New("GetExtensionAPIDefinition"))) { + return v8::FunctionTemplate::New(GetExtensionAPIDefinition); + } else if (name->Equals(v8::String::New("GetViews"))) { return v8::FunctionTemplate::New(GetViews); } else if (name->Equals(v8::String::New("GetNextRequestId"))) { return v8::FunctionTemplate::New(GetNextRequestId); @@ -87,6 +90,11 @@ class ExtensionImpl : public ExtensionBase { return url.host(); } + static v8::Handle<v8::Value> GetExtensionAPIDefinition( + const v8::Arguments& args) { + return v8::String::New(GetStringResource<IDR_EXTENSION_API_JSON>()); + } + static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) { std::string extension_id = ExtensionIdFromCurrentContext(); diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd index ac2e6de..5ec2309 100644 --- a/chrome/renderer/renderer_resources.grd +++ b/chrome/renderer/renderer_resources.grd @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- This comment is only here because changes to resources are not picked up -without changes to the corresponding grd file. mp2 --> +without changes to the corresponding grd file. rw --> <grit latest_public_release="0" current_release="1"> <outputs> <output filename="grit/renderer_resources.h" type="rc_header"> diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index e702744..dd01214 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -12,6 +12,7 @@ var chrome = chrome || {}; (function() { + native function GetExtensionAPIDefinition(); native function StartRequest(); native function GetCurrentPageActions(); native function GetViews(); @@ -93,298 +94,71 @@ var chrome = chrome || {}; } StartRequest(functionName, sargs, requestId, hasCallback); } - - //---------------------------------------------------------------------------- - - // Windows. - chrome.windows = {}; - - chrome.windows.get = function(windowId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.get", windowId, callback); - }; - - chrome.windows.get.params = [ - chrome.types.pInt, - chrome.types.fun - ]; - - chrome.windows.getCurrent = function(callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.getCurrent", null, callback); - }; - - chrome.windows.getCurrent.params = [ - chrome.types.fun - ]; - - chrome.windows.getLastFocused = function(callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.getLastFocused", null, callback); - }; - - chrome.windows.getLastFocused.params = [ - chrome.types.fun - ]; - - chrome.windows.getAll = function(populate, callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.getAll", populate, callback); - }; - - chrome.windows.getAll.params = [ - chrome.types.optBool, - chrome.types.fun - ]; - - chrome.windows.create = function(createData, callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.create", createData, callback); - }; - chrome.windows.create.params = [ - { - type: "object", - properties: { - url: chrome.types.optStr, - left: chrome.types.optInt, - top: chrome.types.optInt, - width: chrome.types.optPInt, - height: chrome.types.optPInt - }, - optional: true - }, - chrome.types.optFun - ]; - - chrome.windows.update = function(windowId, updateData, callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.update", [windowId, updateData], callback); - }; - chrome.windows.update.params = [ - chrome.types.pInt, - { - type: "object", - properties: { - left: chrome.types.optInt, - top: chrome.types.optInt, - width: chrome.types.optPInt, - height: chrome.types.optPInt - }, - }, - chrome.types.optFun - ]; - - chrome.windows.remove = function(windowId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("windows.remove", windowId, callback); - }; - - chrome.windows.remove.params = [ - chrome.types.pInt, - chrome.types.optFun - ]; - - // sends (windowId). - // *WILL* be followed by tab-attached AND then tab-selection-changed. - chrome.windows.onCreated = new chrome.Event("windows.onCreated"); - - // sends (windowId). - // *WILL* be preceded by sequences of tab-removed AND then - // tab-selection-changed -- one for each tab that was contained in the window - // that closed - chrome.windows.onRemoved = new chrome.Event("windows.onRemoved"); - - // sends (windowId). - chrome.windows.onFocusChanged = - new chrome.Event("windows.onFocusChanged"); - - //---------------------------------------------------------------------------- - - // Tabs - chrome.tabs = {}; - - chrome.tabs.get = function(tabId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.get", tabId, callback); - }; - - chrome.tabs.get.params = [ - chrome.types.pInt, - chrome.types.fun - ]; - - chrome.tabs.getSelected = function(windowId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.getSelected", windowId, callback); - }; - - chrome.tabs.getSelected.params = [ - chrome.types.optPInt, - chrome.types.fun - ]; - - chrome.tabs.getAllInWindow = function(windowId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.getAllInWindow", windowId, callback); - }; - - chrome.tabs.getAllInWindow.params = [ - chrome.types.optPInt, - chrome.types.fun - ]; - - chrome.tabs.create = function(tab, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.create", tab, callback); - }; - - chrome.tabs.create.params = [ - { - type: "object", - properties: { - windowId: chrome.types.optPInt, - index: chrome.types.optPInt, - url: chrome.types.optStr, - selected: chrome.types.optBool - } - }, - chrome.types.optFun - ]; - - chrome.tabs.update = function(tabId, updates, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.update", [tabId, updates], callback); - }; - - chrome.tabs.update.params = [ - chrome.types.pInt, - { - type: "object", - properties: { - url: chrome.types.optStr, - selected: chrome.types.optBool - } - }, - chrome.types.optFun - ]; - - chrome.tabs.move = function(tabId, moveProps, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.move", [tabId, moveProps], callback); - }; - - chrome.tabs.move.params = [ - chrome.types.pInt, - { - type: "object", - properties: { - windowId: chrome.types.optPInt, - index: chrome.types.pInt - } - }, - chrome.types.optFun - ]; - - chrome.tabs.remove = function(tabId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.remove", tabId, callback); - }; - - chrome.tabs.remove.params = [ - chrome.types.pInt, - chrome.types.optFun - ]; - - chrome.tabs.detectLanguage = function(tabId, callback) { - validate(arguments, arguments.callee.params); - sendRequest("tabs.detectLanguage", tabId, callback); - }; - - chrome.tabs.detectLanguage.params = [ - chrome.types.optPInt, - chrome.types.optFun - ]; - - chrome.tabs.connect = function(tabId, opt_name) { - validate(arguments, arguments.callee.params); - var portId = OpenChannelToTab(tabId, chrome.extension.id_, opt_name || ""); - return chromeHidden.Port.createPort(portId, opt_name); - }; - - chrome.tabs.connect.params = [ - chrome.types.pInt, - chrome.types.optStr - ]; - - // Sends ({Tab}). - // Will *NOT* be followed by tab-attached - it is implied. - // *MAY* be followed by tab-selection-changed. - chrome.tabs.onCreated = new chrome.Event("tabs.onCreated"); - - // Sends (tabId, {ChangedProps}). - chrome.tabs.onUpdated = new chrome.Event("tabs.onUpdated"); - - // Sends (tabId, {windowId, fromIndex, toIndex}). - // Tabs can only "move" within a window. - chrome.tabs.onMoved = new chrome.Event("tabs.onMoved"); - - // Sends (tabId, {windowId}). - chrome.tabs.onSelectionChanged = - new chrome.Event("tabs.onSelectionChanged"); - - // Sends (tabId, {newWindowId, newPosition}). - // *MAY* be followed by tab-selection-changed. - chrome.tabs.onAttached = new chrome.Event("tabs.onAttached"); - - // Sends (tabId, {oldWindowId, oldPosition}). - // *WILL* be followed by tab-selection-changed. - chrome.tabs.onDetached = new chrome.Event("tabs.onDetached"); - - // Sends (tabId). - // *WILL* be followed by tab-selection-changed. - // Will *NOT* be followed or preceded by tab-detached. - chrome.tabs.onRemoved = new chrome.Event("tabs.onRemoved"); - - //---------------------------------------------------------------------------- - - // PageActions. - chrome.pageActions = {}; - - chrome.pageActions.enableForTab = function(pageActionId, action) { - validate(arguments, arguments.callee.params); - sendRequest("pageActions.enableForTab", [pageActionId, action]); - } - - chrome.pageActions.enableForTab.params = [ - chrome.types.str, - { - type: "object", - properties: { - tabId: chrome.types.pInt, - url: chrome.types.str, - title: chrome.types.optStr, - iconId: chrome.types.optPInt, - }, - optional: false + + // Read api definitions and setup api functions in the chrome namespace. + // TODO(rafaelw): Consider defining a json schema for an api definition + // and validating either here, in a unit_test or both. + // TODO(rafaelw): Handle synchronous functions. + // TOOD(rafaelw): Consider providing some convenient override points + // for api functions that wish to insert themselves into the call. + var apiDefinitions = JSON.parse(GetExtensionAPIDefinition()); + + // Using forEach for convenience, and to bind |module|s & |apiDefs|s via + // closures. + function forEach(a, f) { + for (var i = 0; i < a.length; i++) { + f(a[i], i); } - ]; - - chrome.pageActions.disableForTab = function(pageActionId, action) { - validate(arguments, arguments.callee.params); - sendRequest("pageActions.disableForTab", [pageActionId, action]); } - chrome.pageActions.disableForTab.params = [ - chrome.types.str, - { - type: "object", - properties: { - tabId: chrome.types.pInt, - url: chrome.types.str - }, - optional: false - } - ]; + forEach(apiDefinitions, function(apiDef) { + var module = {}; + chrome[apiDef.namespace] = module; + + // Setup Functions. + forEach(apiDef.functions, function(functionDef) { + var paramSchemas = functionDef.parameters; + + module[functionDef.name] = function() { + validate(arguments, paramSchemas); + + var functionName = apiDef.namespace + "." + functionDef.name; + var args = null; + var callback = null; + var argCount = arguments.length; + + // Look for callback param. + if (paramSchemas.length > 0 && + arguments.length == paramSchemas.length && + paramSchemas[paramSchemas.length - 1].type == "function") { + callback = arguments[paramSchemas.length - 1]; + --argCount; + } + + // Calls with one argument expect singular argument. Calls with multiple + // expect a list. + if (argCount == 1) + args = arguments[0]; + if (argCount > 1) { + args = []; + for (var k = 0; k < argCount; k++) { + args[k] = arguments[k]; + } + } + + // Make the request. + sendRequest(functionName, args, callback); + } + }); + + // Setup Events + forEach(apiDef.events, function(eventDef) { + var eventName = apiDef.namespace + "." + eventDef.name; + module[eventDef.name] = new chrome.Event(eventName); + }); + }); + + // --- Setup additional api's not currently handled in common/extensions/api // Page action events send (pageActionId, {tabId, tabUrl}). function setupPageActionEvents(extensionId) { @@ -397,59 +171,20 @@ var chrome = chrome || {}; } } - //---------------------------------------------------------------------------- - // Bookmarks - chrome.bookmarks = {}; - - chrome.bookmarks.get = function(ids, callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.get", ids, callback); - }; - - chrome.bookmarks.get.params = [ - chrome.types.singleOrListOf(chrome.types.pInt), - chrome.types.fun - ]; - - chrome.bookmarks.getChildren = function(id, callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.getChildren", id, callback); - }; - - chrome.bookmarks.getChildren.params = [ - chrome.types.pInt, - chrome.types.fun - ]; - - chrome.bookmarks.getTree = function(callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.getTree", null, callback); - }; - - // TODO(erikkay): allow it to take an optional id as a starting point - // BUG=13727 - chrome.bookmarks.getTree.params = [ - chrome.types.fun - ]; - - chrome.bookmarks.search = function(query, callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.search", query, callback); - }; - - chrome.bookmarks.search.params = [ - chrome.types.str, - chrome.types.fun - ]; - + // Bookmarks custom parameter handling. chrome.bookmarks.remove = function(id, callback) { validate(arguments, arguments.callee.params); sendRequest("bookmarks.remove", [id, false], callback); }; chrome.bookmarks.remove.params = [ - chrome.types.singleOrListOf(chrome.types.pInt), - chrome.types.optFun + { + choice : [ + {type: "integer", minimum: 0}, + {type: "array", item: {type: "integer", minimum: 0}, minItems: 1} + ] + }, + {type: "function", optional: true} ]; chrome.bookmarks.removeTree = function(id, callback) { @@ -458,85 +193,23 @@ var chrome = chrome || {}; }; chrome.bookmarks.removeTree.params = [ - chrome.types.pInt, - chrome.types.optFun + {type: "integer", minimum: 0}, + {type: "function", optional: true} ]; - chrome.bookmarks.create = function(bookmark, callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.create", bookmark, callback); - }; - - chrome.bookmarks.create.params = [ - { - type: "object", - properties: { - parentId: chrome.types.optPInt, - index: chrome.types.optPInt, - title: chrome.types.optStr, - url: chrome.types.optStr, - } - }, - chrome.types.optFun - ]; - - chrome.bookmarks.move = function(id, destination, callback) { - validate(arguments, arguments.callee.params); - sendRequest("bookmarks.move", [id, destination], callback); - }; - - chrome.bookmarks.move.params = [ - chrome.types.pInt, - { - type: "object", - properties: { - parentId: chrome.types.optPInt, - index: chrome.types.optPInt - } - }, - chrome.types.optFun - ]; - - chrome.bookmarks.update = function(id, changes, callback) { + // Tabs connect() + chrome.tabs.connect = function(tabId, opt_name) { validate(arguments, arguments.callee.params); - sendRequest("bookmarks.update", [id, changes], callback); + var portId = OpenChannelToTab(tabId, chrome.extension.id_, opt_name || ""); + return chromeHidden.Port.createPort(portId, opt_name); }; - chrome.bookmarks.update.params = [ - chrome.types.pInt, - { - type: "object", - properties: { - title: chrome.types.optStr - } - }, - chrome.types.optFun + chrome.tabs.connect.params = [ + {type: "integer", optional: true, minimum: 0}, + {type: "string", optional: true} ]; - // bookmark events - - // Sends (id, {title, url, parentId, index, dateAdded, dateGroupModified}) - // date values are milliseconds since the UTC epoch. - chrome.bookmarks.onAdded = new chrome.Event("bookmarks.onAdded"); - - // Sends (id, {parentId, index}) - chrome.bookmarks.onRemoved = new chrome.Event("bookmarks.onRemoved"); - - // Sends (id, object) where object has list of properties that have changed. - // Currently, this only ever includes 'title'. - chrome.bookmarks.onChanged = new chrome.Event("bookmarks.onChanged"); - - // Sends (id, {parentId, index, oldParentId, oldIndex}) - chrome.bookmarks.onMoved = new chrome.Event("bookmarks.onMoved"); - - // Sends (id, [childrenIds]) - chrome.bookmarks.onChildrenReordered = - new chrome.Event("bookmarks.onChildrenReordered"); - - - //---------------------------------------------------------------------------- - - // Self. + // chrome.self / chrome.extension. chrome.self = chrome.self || {}; chromeHidden.onLoad.addListener(function (extensionId) { diff --git a/chrome/renderer/resources/json_schema.js b/chrome/renderer/resources/json_schema.js index 4973990..f5d06c6 100644 --- a/chrome/renderer/resources/json_schema.js +++ b/chrome/renderer/resources/json_schema.js @@ -348,38 +348,3 @@ chrome.JSONSchemaValidator.prototype.addError = function(path, key, message: chrome.JSONSchemaValidator.formatError(key, replacements) }); }; - -// Set up chrome.types with some commonly used types... -(function() { - function extend(base, ext) { - var result = {}; - for (var p in base) - result[p] = base[p]; - for (var p in ext) - result[p] = ext[p]; - return result; - } - - var types = {}; - types.opt = {optional: true}; - types.bool = {type: "boolean"}; - types.int = {type: "integer"}; - types.str = {type: "string"}; - types.fun = {type: "function"}; - types.pInt = extend(types.int, {minimum: 0}); - types.optBool = extend(types.bool, types.opt); - types.optInt = extend(types.int, types.opt); - types.optStr = extend(types.str, types.opt); - types.optFun = extend(types.fun, types.opt); - types.optPInt = extend(types.pInt, types.opt); - types.singleOrListOf = function(type) { - return { - choice: [ - type, - { type: "array", item: type, minItems: 1 } - ] - }; - }; - - chrome.types = types; -})(); |