| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // This script contains privileged chrome extension related javascript APIs. | 5 // This script contains privileged chrome extension related javascript APIs. |
| 6 // It is loaded by pages whose URL has the chrome-extension protocol. | 6 // It is loaded by pages whose URL has the chrome-extension protocol. |
| 7 | 7 |
| 8 var chrome = chrome || {}; | 8 var chrome = chrome || {}; |
| 9 (function() { | 9 (function() { |
| 10 native function GetChromeHidden(); | 10 native function GetChromeHidden(); |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 throw new Error( | 237 throw new Error( |
| 238 "Either the path or imageData property must be specified."); | 238 "Either the path or imageData property must be specified."); |
| 239 } | 239 } |
| 240 } | 240 } |
| 241 | 241 |
| 242 // Stores the name and definition of each API function, with methods to | 242 // Stores the name and definition of each API function, with methods to |
| 243 // modify their behaviour (such as a custom way to handle requests to the | 243 // modify their behaviour (such as a custom way to handle requests to the |
| 244 // API, a custom callback, etc). | 244 // API, a custom callback, etc). |
| 245 function APIFunctions() { | 245 function APIFunctions() { |
| 246 this._apiFunctions = {}; | 246 this._apiFunctions = {}; |
| 247 this._unavailableApiFunctions = {}; |
| 247 } | 248 } |
| 248 APIFunctions.prototype.register = function(apiName, apiFunction) { | 249 APIFunctions.prototype.register = function(apiName, apiFunction) { |
| 249 this._apiFunctions[apiName] = apiFunction; | 250 this._apiFunctions[apiName] = apiFunction; |
| 250 }; | 251 }; |
| 252 // Registers a function as existing but not available, meaning that calls to |
| 253 // the set* methods that reference this function should be ignored rather |
| 254 // than throwing Errors. |
| 255 APIFunctions.prototype.registerUnavailable = function(apiName) { |
| 256 this._unavailableApiFunctions[apiName] = apiName; |
| 257 }; |
| 251 APIFunctions.prototype._setHook = | 258 APIFunctions.prototype._setHook = |
| 252 function(apiName, propertyName, customizedFunction) { | 259 function(apiName, propertyName, customizedFunction) { |
| 253 if (this._apiFunctions.hasOwnProperty(apiName)) | 260 if (this._unavailableApiFunctions.hasOwnProperty(apiName)) |
| 254 this._apiFunctions[apiName][propertyName] = customizedFunction; | 261 return; |
| 262 if (!this._apiFunctions.hasOwnProperty(apiName)) |
| 263 throw new Error('Tried to set hook for unknown API "' + apiName + '"'); |
| 264 this._apiFunctions[apiName][propertyName] = customizedFunction; |
| 255 }; | 265 }; |
| 256 APIFunctions.prototype.setHandleRequest = | 266 APIFunctions.prototype.setHandleRequest = |
| 257 function(apiName, customizedFunction) { | 267 function(apiName, customizedFunction) { |
| 258 return this._setHook(apiName, 'handleRequest', customizedFunction); | 268 return this._setHook(apiName, 'handleRequest', customizedFunction); |
| 259 }; | 269 }; |
| 260 APIFunctions.prototype.setUpdateArgumentsPostValidate = | 270 APIFunctions.prototype.setUpdateArgumentsPostValidate = |
| 261 function(apiName, customizedFunction) { | 271 function(apiName, customizedFunction) { |
| 262 return this._setHook( | 272 return this._setHook( |
| 263 apiName, 'updateArgumentsPostValidate', customizedFunction); | 273 apiName, 'updateArgumentsPostValidate', customizedFunction); |
| 264 }; | 274 }; |
| 265 APIFunctions.prototype.setUpdateArgumentsPreValidate = | 275 APIFunctions.prototype.setUpdateArgumentsPreValidate = |
| 266 function(apiName, customizedFunction) { | 276 function(apiName, customizedFunction) { |
| 267 return this._setHook( | 277 return this._setHook( |
| 268 apiName, 'updateArgumentsPreValidate', customizedFunction); | 278 apiName, 'updateArgumentsPreValidate', customizedFunction); |
| 269 }; | 279 }; |
| 270 APIFunctions.prototype.setCustomCallback = | 280 APIFunctions.prototype.setCustomCallback = |
| 271 function(apiName, customizedFunction) { | 281 function(apiName, customizedFunction) { |
| 272 return this._setHook(apiName, 'customCallback', customizedFunction); | 282 return this._setHook(apiName, 'customCallback', customizedFunction); |
| 273 }; | 283 }; |
| 274 | 284 |
| 275 var apiFunctions = new APIFunctions(); | 285 var apiFunctions = new APIFunctions(); |
| 276 | 286 |
| 287 // Wraps the calls to the set* methods of APIFunctions with the namespace of |
| 288 // an API, and validates that all calls to set* methods aren't prefixed with |
| 289 // a namespace. |
| 290 // |
| 291 // For example, if constructed with 'browserAction', a call to |
| 292 // handleRequest('foo') will be transformed into |
| 293 // handleRequest('browserAction.foo'). |
| 294 // |
| 295 // Likewise, if a call to handleRequest is called with 'browserAction.foo', |
| 296 // it will throw an error. |
| 297 // |
| 298 // These help with isolating custom bindings from each other. |
| 299 function NamespacedAPIFunctions(namespace, delegate) { |
| 300 var self = this; |
| 301 function wrap(methodName) { |
| 302 self[methodName] = function(apiName, customizedFunction) { |
| 303 var prefix = namespace + '.'; |
| 304 if (apiName.indexOf(prefix) === 0) { |
| 305 throw new Error(methodName + ' called with "' + apiName + |
| 306 '" which has a "' + prefix + '" prefix. ' + |
| 307 'This is unnecessary and must be left out.'); |
| 308 } |
| 309 return delegate[methodName].call(delegate, |
| 310 prefix + apiName, customizedFunction); |
| 311 }; |
| 312 } |
| 313 |
| 314 wrap('contains'); |
| 315 wrap('setHandleRequest'); |
| 316 wrap('setUpdateArgumentsPostValidate'); |
| 317 wrap('setUpdateArgumentsPreValidate'); |
| 318 wrap('setCustomCallback'); |
| 319 } |
| 320 |
| 277 // | 321 // |
| 278 // The API through which the ${api_name}_custom_bindings.js files customize | 322 // The API through which the ${api_name}_custom_bindings.js files customize |
| 279 // their API bindings beyond what can be generated. | 323 // their API bindings beyond what can be generated. |
| 280 // | 324 // |
| 281 // There are 2 types of customizations available: those which are required in | 325 // There are 2 types of customizations available: those which are required in |
| 282 // order to do the schema generation (registerCustomEvent and | 326 // order to do the schema generation (registerCustomEvent and |
| 283 // registerCustomType), and those which can only run after the bindings have | 327 // registerCustomType), and those which can only run after the bindings have |
| 284 // been generated (registerCustomHook). | 328 // been generated (registerCustomHook). |
| 285 // | 329 // |
| 286 | 330 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 }); | 467 }); |
| 424 } | 468 } |
| 425 | 469 |
| 426 // Setup Functions. | 470 // Setup Functions. |
| 427 if (apiDef.functions) { | 471 if (apiDef.functions) { |
| 428 apiDef.functions.forEach(function(functionDef) { | 472 apiDef.functions.forEach(function(functionDef) { |
| 429 if (functionDef.name in mod) { | 473 if (functionDef.name in mod) { |
| 430 throw new Error('Function ' + functionDef.name + | 474 throw new Error('Function ' + functionDef.name + |
| 431 ' already defined in ' + apiDef.namespace); | 475 ' already defined in ' + apiDef.namespace); |
| 432 } | 476 } |
| 433 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) | 477 |
| 478 var apiFunctionName = apiDef.namespace + "." + functionDef.name; |
| 479 |
| 480 if (!isSchemaNodeSupported(functionDef, platform, manifestVersion)) { |
| 481 apiFunctions.registerUnavailable(apiFunctionName); |
| 434 return; | 482 return; |
| 483 } |
| 435 if (!isSchemaAccessAllowed(functionDef)) { | 484 if (!isSchemaAccessAllowed(functionDef)) { |
| 485 apiFunctions.registerUnavailable(apiFunctionName); |
| 436 addUnprivilegedAccessGetter(mod, functionDef.name); | 486 addUnprivilegedAccessGetter(mod, functionDef.name); |
| 437 return; | 487 return; |
| 438 } | 488 } |
| 439 | 489 |
| 440 var apiFunction = {}; | 490 var apiFunction = {}; |
| 441 apiFunction.definition = functionDef; | 491 apiFunction.definition = functionDef; |
| 442 apiFunction.name = apiDef.namespace + "." + functionDef.name; | 492 apiFunction.name = apiFunctionName; |
| 443 apiFunctions.register(apiFunction.name, apiFunction); | 493 apiFunctions.register(apiFunctionName, apiFunction); |
| 444 | 494 |
| 445 mod[functionDef.name] = (function() { | 495 mod[functionDef.name] = (function() { |
| 446 var args = arguments; | 496 var args = arguments; |
| 447 if (this.updateArgumentsPreValidate) | 497 if (this.updateArgumentsPreValidate) |
| 448 args = this.updateArgumentsPreValidate.apply(this, args); | 498 args = this.updateArgumentsPreValidate.apply(this, args); |
| 449 chromeHidden.validate(args, this.definition.parameters); | 499 chromeHidden.validate(args, this.definition.parameters); |
| 450 if (this.updateArgumentsPostValidate) | 500 if (this.updateArgumentsPostValidate) |
| 451 args = this.updateArgumentsPostValidate.apply(this, args); | 501 args = this.updateArgumentsPostValidate.apply(this, args); |
| 452 | 502 |
| 453 var retval; | 503 var retval; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 return; | 607 return; |
| 558 | 608 |
| 559 var hook = customHooks[apiDef.namespace]; | 609 var hook = customHooks[apiDef.namespace]; |
| 560 if (!hook) | 610 if (!hook) |
| 561 return; | 611 return; |
| 562 | 612 |
| 563 // Pass through the public API of schema_generated_bindings, to be used | 613 // Pass through the public API of schema_generated_bindings, to be used |
| 564 // by custom bindings JS files. Create a new one so that bindings can't | 614 // by custom bindings JS files. Create a new one so that bindings can't |
| 565 // interfere with each other. | 615 // interfere with each other. |
| 566 hook({ | 616 hook({ |
| 567 apiFunctions: apiFunctions, | 617 apiFunctions: new NamespacedAPIFunctions(apiDef.namespace, |
| 618 apiFunctions), |
| 568 sendRequest: sendRequest, | 619 sendRequest: sendRequest, |
| 569 setIcon: setIcon, | 620 setIcon: setIcon, |
| 570 apiDefinitions: apiDefinitions, | 621 apiDefinitions: apiDefinitions, |
| 571 }, extensionId); | 622 }, extensionId); |
| 572 }); | 623 }); |
| 573 | 624 |
| 574 // TODO(mihaip): remove this alias once the webstore stops calling | 625 // TODO(mihaip): remove this alias once the webstore stops calling |
| 575 // beginInstallWithManifest2. | 626 // beginInstallWithManifest2. |
| 576 // See http://crbug.com/100242 | 627 // See http://crbug.com/100242 |
| 577 if (chrome.webstorePrivate) { | 628 if (chrome.webstorePrivate) { |
| 578 chrome.webstorePrivate.beginInstallWithManifest2 = | 629 chrome.webstorePrivate.beginInstallWithManifest2 = |
| 579 chrome.webstorePrivate.beginInstallWithManifest3; | 630 chrome.webstorePrivate.beginInstallWithManifest3; |
| 580 } | 631 } |
| 581 | 632 |
| 582 if (chrome.test) | 633 if (chrome.test) |
| 583 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 634 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
| 584 }); | 635 }); |
| 585 })(); | 636 })(); |
| OLD | NEW |