Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 GetExtensionAPIDefinition(); | 10 native function GetExtensionAPIDefinition(); | 
| (...skipping 20 matching lines...) Expand all Loading... | |
| 31 return; | 31 return; | 
| 32 } | 32 } | 
| 33 chrome.initExtension(extensionId, false); | 33 chrome.initExtension(extensionId, false); | 
| 34 }); | 34 }); | 
| 35 return; | 35 return; | 
| 36 } | 36 } | 
| 37 | 37 | 
| 38 if (!chrome) | 38 if (!chrome) | 
| 39 chrome = {}; | 39 chrome = {}; | 
| 40 | 40 | 
| 41 function forEach(dict, f) { | |
| 42 for (key in dict) { | |
| 43 if (dict.hasOwnProperty(key)) | |
| 44 f(key, dict[key]); | |
| 45 } | |
| 46 } | |
| 47 | |
| 41 // Validate arguments. | 48 // Validate arguments. | 
| 42 chromeHidden.validationTypes = []; | 49 chromeHidden.validationTypes = {}; | 
| 43 chromeHidden.validate = function(args, schemas) { | 50 chromeHidden.validate = function(args, schemas) { | 
| 44 if (args.length > schemas.length) | 51 if (args.length > schemas.length) | 
| 45 throw new Error("Too many arguments."); | 52 throw new Error("Too many arguments."); | 
| 46 | 53 | 
| 47 for (var i = 0; i < schemas.length; i++) { | 54 for (var i = 0; i < schemas.length; i++) { | 
| 48 if (i in args && args[i] !== null && args[i] !== undefined) { | 55 if (i in args && args[i] !== null && args[i] !== undefined) { | 
| 49 var validator = new chromeHidden.JSONSchemaValidator(); | 56 var validator = new chromeHidden.JSONSchemaValidator(); | 
| 50 validator.addTypes(chromeHidden.validationTypes); | 57 forEach(chromeHidden.validationTypes, function(id, type) { | 
| 58 validator.addTypes(type); | |
| 59 }); | |
| 51 validator.validate(args[i], schemas[i]); | 60 validator.validate(args[i], schemas[i]); | 
| 52 if (validator.errors.length == 0) | 61 if (validator.errors.length == 0) | 
| 53 continue; | 62 continue; | 
| 54 | 63 | 
| 55 var message = "Invalid value for argument " + (i + 1) + ". "; | 64 var message = "Invalid value for argument " + (i + 1) + ". "; | 
| 56 for (var i = 0, err; err = validator.errors[i]; i++) { | 65 for (var i = 0, err; err = validator.errors[i]; i++) { | 
| 57 if (err.path) { | 66 if (err.path) { | 
| 58 message += "Property '" + err.path + "': "; | 67 message += "Property '" + err.path + "': "; | 
| 59 } | 68 } | 
| 60 message += err.message; | 69 message += err.message; | 
| (...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 409 var callback = function(errorMessage) { | 418 var callback = function(errorMessage) { | 
| 410 if (errorMessage) | 419 if (errorMessage) | 
| 411 chrome.experimental.tts.speakCompleted(requestId, errorMessage); | 420 chrome.experimental.tts.speakCompleted(requestId, errorMessage); | 
| 412 else | 421 else | 
| 413 chrome.experimental.tts.speakCompleted(requestId); | 422 chrome.experimental.tts.speakCompleted(requestId); | 
| 414 }; | 423 }; | 
| 415 chrome.Event.prototype.dispatch.apply(this, [text, options, callback]); | 424 chrome.Event.prototype.dispatch.apply(this, [text, options, callback]); | 
| 416 }; | 425 }; | 
| 417 } | 426 } | 
| 418 | 427 | 
| 428 var customInitializers = {}; | |
| 429 | |
| 430 function setupPreferences() { | |
| 431 var parameters = {}; | |
| 432 chromeHidden.validationTypes['Preference'].functions.forEach(function(f) { | |
| 433 parameters[f.name] = f.parameters; | |
| 434 }); | |
| 435 | |
| 436 customInitializers['Preference'] = function(prefKey, valueSchema) { | |
| 437 var getSchema = parameters.get; | |
| 438 var extendedGetSchema = getSchema.slice(); | |
| 
 
Aaron Boodman
2011/02/23 01:17:26
Can you find a way to generalize this such that ev
 
Bernhard Bauer
2011/02/23 17:33:27
Done. I pulled out a function |extendSchema|.
 
 | |
| 439 extendedGetSchema.unshift({'type': 'string'}); | |
| 440 this.get = function(details, callback) { | |
| 441 chromeHidden.validate([details, callback], getSchema); | |
| 442 return sendRequest('experimental.preferences.get', | |
| 443 [prefKey, details, callback], | |
| 444 extendedGetSchema); | |
| 445 }; | |
| 446 var setSchema = parameters.set.slice(); | |
| 447 setSchema[0].properties.value = valueSchema; | |
| 448 var extendedSetSchema = setSchema.slice(); | |
| 449 extendedSetSchema.unshift({'type': 'string'}); | |
| 450 this.set = function(details, callback) { | |
| 451 chromeHidden.validate([details, callback], setSchema); | |
| 452 return sendRequest('experimental.preferences.set', | |
| 453 [prefKey, details, callback], | |
| 454 extendedSetSchema); | |
| 455 }; | |
| 456 }; | |
| 457 } | |
| 458 | |
| 419 chromeHidden.onLoad.addListener(function (extensionId) { | 459 chromeHidden.onLoad.addListener(function (extensionId) { | 
| 420 if (!extensionId) { | 460 if (!extensionId) { | 
| 421 return; | 461 return; | 
| 422 } | 462 } | 
| 423 chrome.initExtension(extensionId, false, IsIncognitoProcess()); | 463 chrome.initExtension(extensionId, false, IsIncognitoProcess()); | 
| 424 | 464 | 
| 425 // |apiFunctions| is a hash of name -> object that stores the | 465 // |apiFunctions| is a hash of name -> object that stores the | 
| 426 // name & definition of the apiFunction. Custom handling of api functions | 466 // name & definition of the apiFunction. Custom handling of api functions | 
| 427 // is implemented by adding a "handleRequest" function to the object. | 467 // is implemented by adding a "handleRequest" function to the object. | 
| 428 var apiFunctions = {}; | 468 var apiFunctions = {}; | 
| 429 | 469 | 
| 470 var customObjects = {}; | |
| 471 | |
| 430 // Read api definitions and setup api functions in the chrome namespace. | 472 // Read api definitions and setup api functions in the chrome namespace. | 
| 431 // TODO(rafaelw): Consider defining a json schema for an api definition | 473 // TODO(rafaelw): Consider defining a json schema for an api definition | 
| 432 // and validating either here, in a unit_test or both. | 474 // and validating either here, in a unit_test or both. | 
| 433 // TODO(rafaelw): Handle synchronous functions. | 475 // TODO(rafaelw): Handle synchronous functions. | 
| 434 // TOOD(rafaelw): Consider providing some convenient override points | 476 // TOOD(rafaelw): Consider providing some convenient override points | 
| 435 // for api functions that wish to insert themselves into the call. | 477 // for api functions that wish to insert themselves into the call. | 
| 436 var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition()); | 478 var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition()); | 
| 437 | 479 | 
| 438 apiDefinitions.forEach(function(apiDef) { | 480 apiDefinitions.forEach(function(apiDef) { | 
| 439 var module = chrome; | 481 var module = chrome; | 
| 440 var namespaces = apiDef.namespace.split('.'); | 482 var namespaces = apiDef.namespace.split('.'); | 
| 441 for (var index = 0, name; name = namespaces[index]; index++) { | 483 for (var index = 0, name; name = namespaces[index]; index++) { | 
| 442 module[name] = module[name] || {}; | 484 module[name] = module[name] || {}; | 
| 443 module = module[name]; | 485 module = module[name]; | 
| 444 } | 486 } | 
| 445 | 487 | 
| 446 // Add types to global validationTypes | 488 // Add types to global validationTypes | 
| 447 if (apiDef.types) { | 489 if (apiDef.types) { | 
| 448 apiDef.types.forEach(function(t) { | 490 apiDef.types.forEach(function(t) { | 
| 449 chromeHidden.validationTypes.push(t); | 491 chromeHidden.validationTypes[t.id] = t; | 
| 492 if (t.type == 'object' && t.customBindings) { | |
| 
 
Aaron Boodman
2011/02/23 01:17:26
The customBindings flag seems unnecessary since yo
 
Bernhard Bauer
2011/02/23 17:33:27
Done.
 
 | |
| 493 function CustomBindingsObject(args) { | |
| 
 
Aaron Boodman
2011/02/23 01:17:26
This object doesn't seem to do a lot right now. I
 
Bernhard Bauer
2011/02/23 17:33:27
Done. I'm still using CustomBindingsObject as a ba
 
 | |
| 494 this.initArgs = args; | |
| 495 } | |
| 496 customObjects[t.id] = CustomBindingsObject; | |
| 497 | |
| 498 t.functions.forEach(function(f) { | |
| 499 CustomBindingsObject.prototype[f.name] = function() { | |
| 500 customInitializers[t.customBindings].apply(this, this.initArgs); | |
| 501 delete this.initArgs; | |
| 502 this[f.name].apply(this, arguments); | |
| 503 }; | |
| 504 }); | |
| 505 } | |
| 450 }); | 506 }); | 
| 451 } | 507 } | 
| 452 | 508 | 
| 453 // Setup Functions. | 509 // Setup Functions. | 
| 454 if (apiDef.functions) { | 510 if (apiDef.functions) { | 
| 455 apiDef.functions.forEach(function(functionDef) { | 511 apiDef.functions.forEach(function(functionDef) { | 
| 456 // Module functions may have been defined earlier by hand. Don't | 512 // Module functions may have been defined earlier by hand. Don't | 
| 457 // clobber them. | 513 // clobber them. | 
| 458 if (module[functionDef.name]) | 514 if (module[functionDef.name]) | 
| 459 return; | 515 return; | 
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 } else { | 563 } else { | 
| 508 module[eventDef.name] = new chrome.Event(eventName, | 564 module[eventDef.name] = new chrome.Event(eventName, | 
| 509 eventDef.parameters); | 565 eventDef.parameters); | 
| 510 } | 566 } | 
| 511 }); | 567 }); | 
| 512 } | 568 } | 
| 513 | 569 | 
| 514 | 570 | 
| 515 // Parse any values defined for properties. | 571 // Parse any values defined for properties. | 
| 516 if (apiDef.properties) { | 572 if (apiDef.properties) { | 
| 517 for (var prop in apiDef.properties) { | 573 forEach(apiDef.properties, function(prop, property) { | 
| 518 if (!apiDef.properties.hasOwnProperty(prop)) | |
| 519 continue; | |
| 520 | |
| 521 var property = apiDef.properties[prop]; | |
| 522 if (property.value) { | 574 if (property.value) { | 
| 523 var value = property.value; | 575 var value = property.value; | 
| 524 if (property.type === 'integer') { | 576 if (property.type === 'integer') { | 
| 525 value = parseInt(value); | 577 value = parseInt(value); | 
| 526 } else if (property.type === 'boolean') { | 578 } else if (property.type === 'boolean') { | 
| 527 value = value === "true"; | 579 value = value === "true"; | 
| 580 } else if (property["$ref"]) { | |
| 581 var proto = customObjects[property["$ref"]]; | |
| 
 
Aaron Boodman
2011/02/23 01:17:26
naming nit: I think this should really be 'ctor' o
 
Bernhard Bauer
2011/02/23 17:33:27
Done. I think constructor only has a special meani
 
 | |
| 582 value = new proto(value); | |
| 528 } else if (property.type !== 'string') { | 583 } else if (property.type !== 'string') { | 
| 529 throw "NOT IMPLEMENTED (extension_api.json error): Cannot " + | 584 throw "NOT IMPLEMENTED (extension_api.json error): Cannot " + | 
| 530 "parse values for type \"" + property.type + "\""; | 585 "parse values for type \"" + property.type + "\""; | 
| 531 } | 586 } | 
| 532 module[prop] = value; | 587 module[prop] = value; | 
| 533 } | 588 } | 
| 534 } | 589 }); | 
| 535 } | 590 } | 
| 536 | 591 | 
| 537 // getTabContentses is retained for backwards compatibility | 592 // getTabContentses is retained for backwards compatibility | 
| 538 // See http://crbug.com/21433 | 593 // See http://crbug.com/21433 | 
| 539 chrome.extension.getTabContentses = chrome.extension.getExtensionTabs; | 594 chrome.extension.getTabContentses = chrome.extension.getExtensionTabs; | 
| 540 }); | 595 }); | 
| 541 | 596 | 
| 542 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { | 597 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { | 
| 543 var name = ""; | 598 var name = ""; | 
| 544 if (connectInfo) { | 599 if (connectInfo) { | 
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 781 | 836 | 
| 782 if (chrome.test) { | 837 if (chrome.test) { | 
| 783 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 838 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 
| 784 } | 839 } | 
| 785 | 840 | 
| 786 setupPageActionEvents(extensionId); | 841 setupPageActionEvents(extensionId); | 
| 787 setupToolstripEvents(GetRenderViewId()); | 842 setupToolstripEvents(GetRenderViewId()); | 
| 788 setupHiddenContextMenuEvent(extensionId); | 843 setupHiddenContextMenuEvent(extensionId); | 
| 789 setupOmniboxEvents(); | 844 setupOmniboxEvents(); | 
| 790 setupTtsEvents(); | 845 setupTtsEvents(); | 
| 846 setupPreferences(); | |
| 791 }); | 847 }); | 
| 792 | 848 | 
| 793 if (!chrome.experimental) | 849 if (!chrome.experimental) | 
| 794 chrome.experimental = {}; | 850 chrome.experimental = {}; | 
| 795 | 851 | 
| 796 if (!chrome.experimental.accessibility) | 852 if (!chrome.experimental.accessibility) | 
| 797 chrome.experimental.accessibility = {}; | 853 chrome.experimental.accessibility = {}; | 
| 798 | 854 | 
| 799 if (!chrome.experimental.tts) | 855 if (!chrome.experimental.tts) | 
| 800 chrome.experimental.tts = {}; | 856 chrome.experimental.tts = {}; | 
| 801 })(); | 857 })(); | 
| OLD | NEW |