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 validator.addTypes(chromeHidden.validationTypes); |
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 | 292 |
286 chrome.WebRequestEvent.prototype.findListener_ = function(cb) { | 293 chrome.WebRequestEvent.prototype.findListener_ = function(cb) { |
287 for (var i = 0; i < this.subEvents_.length; i++) { | 294 for (var i = 0; i < this.subEvents_.length; i++) { |
288 if (this.subEvents_[i].findListener_(cb) > -1) | 295 if (this.subEvents_[i].findListener_(cb) > -1) |
289 return i; | 296 return i; |
290 } | 297 } |
291 | 298 |
292 return -1; | 299 return -1; |
293 }; | 300 }; |
294 | 301 |
| 302 function CustomBindingsObject() { |
| 303 } |
| 304 CustomBindingsObject.prototype.setSchema = function(schema) { |
| 305 // The functions in the schema are in list form, so we move them into a |
| 306 // dictionary for easier access. |
| 307 var self = this; |
| 308 self.parameters = {}; |
| 309 schema.functions.forEach(function(f) { |
| 310 self.parameters[f.name] = f.parameters; |
| 311 }); |
| 312 }; |
| 313 |
| 314 function extendSchema(schema) { |
| 315 var extendedSchema = schema.slice(); |
| 316 extendedSchema.unshift({'type': 'string'}); |
| 317 return extendedSchema; |
| 318 } |
| 319 |
| 320 var customBindings = {}; |
| 321 |
| 322 function setupPreferences() { |
| 323 customBindings['Preference'] = function(prefKey, valueSchema) { |
| 324 var getSchema = this.parameters.get; |
| 325 var extendedGetSchema = extendSchema(getSchema); |
| 326 this.get = function(details, callback) { |
| 327 chromeHidden.validate([details, callback], getSchema); |
| 328 return sendRequest('experimental.preferences.get', |
| 329 [prefKey, details, callback], |
| 330 extendedGetSchema); |
| 331 }; |
| 332 var setSchema = this.parameters.set.slice(); |
| 333 setSchema[0].properties.value = valueSchema; |
| 334 var extendedSetSchema = extendSchema(setSchema); |
| 335 this.set = function(details, callback) { |
| 336 chromeHidden.validate([details, callback], setSchema); |
| 337 return sendRequest('experimental.preferences.set', |
| 338 [prefKey, details, callback], |
| 339 extendedSetSchema); |
| 340 }; |
| 341 }; |
| 342 customBindings['Preference'].prototype = new CustomBindingsObject(); |
| 343 } |
| 344 |
295 // Page action events send (pageActionId, {tabId, tabUrl}). | 345 // Page action events send (pageActionId, {tabId, tabUrl}). |
296 function setupPageActionEvents(extensionId) { | 346 function setupPageActionEvents(extensionId) { |
297 var pageActions = GetCurrentPageActions(extensionId); | 347 var pageActions = GetCurrentPageActions(extensionId); |
298 | 348 |
299 var oldStyleEventName = "pageActions"; | 349 var oldStyleEventName = "pageActions"; |
300 // TODO(EXTENSIONS_DEPRECATED): only one page action | 350 // TODO(EXTENSIONS_DEPRECATED): only one page action |
301 for (var i = 0; i < pageActions.length; ++i) { | 351 for (var i = 0; i < pageActions.length; ++i) { |
302 // Setup events for each extension_id/page_action_id string we find. | 352 // Setup events for each extension_id/page_action_id string we find. |
303 chrome.pageActions[pageActions[i]] = new chrome.Event(oldStyleEventName); | 353 chrome.pageActions[pageActions[i]] = new chrome.Event(oldStyleEventName); |
304 } | 354 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
415 chrome.Event.prototype.dispatch.apply(this, [text, options, callback]); | 465 chrome.Event.prototype.dispatch.apply(this, [text, options, callback]); |
416 }; | 466 }; |
417 } | 467 } |
418 | 468 |
419 chromeHidden.onLoad.addListener(function (extensionId) { | 469 chromeHidden.onLoad.addListener(function (extensionId) { |
420 if (!extensionId) { | 470 if (!extensionId) { |
421 return; | 471 return; |
422 } | 472 } |
423 chrome.initExtension(extensionId, false, IsIncognitoProcess()); | 473 chrome.initExtension(extensionId, false, IsIncognitoProcess()); |
424 | 474 |
| 475 // Setup the Preference class so we can use it to construct Preference |
| 476 // objects from the API definition. |
| 477 setupPreferences(); |
| 478 |
425 // |apiFunctions| is a hash of name -> object that stores the | 479 // |apiFunctions| is a hash of name -> object that stores the |
426 // name & definition of the apiFunction. Custom handling of api functions | 480 // name & definition of the apiFunction. Custom handling of api functions |
427 // is implemented by adding a "handleRequest" function to the object. | 481 // is implemented by adding a "handleRequest" function to the object. |
428 var apiFunctions = {}; | 482 var apiFunctions = {}; |
429 | 483 |
430 // Read api definitions and setup api functions in the chrome namespace. | 484 // Read api definitions and setup api functions in the chrome namespace. |
431 // TODO(rafaelw): Consider defining a json schema for an api definition | 485 // TODO(rafaelw): Consider defining a json schema for an api definition |
432 // and validating either here, in a unit_test or both. | 486 // and validating either here, in a unit_test or both. |
433 // TODO(rafaelw): Handle synchronous functions. | 487 // TODO(rafaelw): Handle synchronous functions. |
434 // TOOD(rafaelw): Consider providing some convenient override points | 488 // TOOD(rafaelw): Consider providing some convenient override points |
435 // for api functions that wish to insert themselves into the call. | 489 // for api functions that wish to insert themselves into the call. |
436 var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition()); | 490 var apiDefinitions = chromeHidden.JSON.parse(GetExtensionAPIDefinition()); |
437 | 491 |
438 apiDefinitions.forEach(function(apiDef) { | 492 apiDefinitions.forEach(function(apiDef) { |
439 var module = chrome; | 493 var module = chrome; |
440 var namespaces = apiDef.namespace.split('.'); | 494 var namespaces = apiDef.namespace.split('.'); |
441 for (var index = 0, name; name = namespaces[index]; index++) { | 495 for (var index = 0, name; name = namespaces[index]; index++) { |
442 module[name] = module[name] || {}; | 496 module[name] = module[name] || {}; |
443 module = module[name]; | 497 module = module[name]; |
444 } | 498 } |
445 | 499 |
446 // Add types to global validationTypes | 500 // Add types to global validationTypes |
447 if (apiDef.types) { | 501 if (apiDef.types) { |
448 apiDef.types.forEach(function(t) { | 502 apiDef.types.forEach(function(t) { |
449 chromeHidden.validationTypes.push(t); | 503 chromeHidden.validationTypes.push(t); |
| 504 if (t.type == 'object' && customBindings[t.id]) { |
| 505 customBindings[t.id].prototype.setSchema(t); |
| 506 } |
450 }); | 507 }); |
451 } | 508 } |
452 | 509 |
453 // Setup Functions. | 510 // Setup Functions. |
454 if (apiDef.functions) { | 511 if (apiDef.functions) { |
455 apiDef.functions.forEach(function(functionDef) { | 512 apiDef.functions.forEach(function(functionDef) { |
456 // Module functions may have been defined earlier by hand. Don't | 513 // Module functions may have been defined earlier by hand. Don't |
457 // clobber them. | 514 // clobber them. |
458 if (module[functionDef.name]) | 515 if (module[functionDef.name]) |
459 return; | 516 return; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
507 } else { | 564 } else { |
508 module[eventDef.name] = new chrome.Event(eventName, | 565 module[eventDef.name] = new chrome.Event(eventName, |
509 eventDef.parameters); | 566 eventDef.parameters); |
510 } | 567 } |
511 }); | 568 }); |
512 } | 569 } |
513 | 570 |
514 | 571 |
515 // Parse any values defined for properties. | 572 // Parse any values defined for properties. |
516 if (apiDef.properties) { | 573 if (apiDef.properties) { |
517 for (var prop in apiDef.properties) { | 574 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) { | 575 if (property.value) { |
523 var value = property.value; | 576 var value = property.value; |
524 if (property.type === 'integer') { | 577 if (property.type === 'integer') { |
525 value = parseInt(value); | 578 value = parseInt(value); |
526 } else if (property.type === 'boolean') { | 579 } else if (property.type === 'boolean') { |
527 value = value === "true"; | 580 value = value === "true"; |
| 581 } else if (property["$ref"]) { |
| 582 var constructor = customBindings[property["$ref"]]; |
| 583 var args = value; |
| 584 // For an object property, |value| is an array of constructor |
| 585 // arguments, but we want to pass the arguments directly |
| 586 // (i.e. not as an array), so we have to fake calling |new| on the |
| 587 // constructor. |
| 588 value = { __proto__: constructor.prototype }; |
| 589 constructor.apply(value, args); |
528 } else if (property.type !== 'string') { | 590 } else if (property.type !== 'string') { |
529 throw "NOT IMPLEMENTED (extension_api.json error): Cannot " + | 591 throw "NOT IMPLEMENTED (extension_api.json error): Cannot " + |
530 "parse values for type \"" + property.type + "\""; | 592 "parse values for type \"" + property.type + "\""; |
531 } | 593 } |
532 module[prop] = value; | 594 module[prop] = value; |
533 } | 595 } |
534 } | 596 }); |
535 } | 597 } |
536 | 598 |
537 // getTabContentses is retained for backwards compatibility | 599 // getTabContentses is retained for backwards compatibility |
538 // See http://crbug.com/21433 | 600 // See http://crbug.com/21433 |
539 chrome.extension.getTabContentses = chrome.extension.getExtensionTabs; | 601 chrome.extension.getTabContentses = chrome.extension.getExtensionTabs; |
540 }); | 602 }); |
541 | 603 |
542 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { | 604 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { |
543 var name = ""; | 605 var name = ""; |
544 if (connectInfo) { | 606 if (connectInfo) { |
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 | 854 |
793 if (!chrome.experimental) | 855 if (!chrome.experimental) |
794 chrome.experimental = {}; | 856 chrome.experimental = {}; |
795 | 857 |
796 if (!chrome.experimental.accessibility) | 858 if (!chrome.experimental.accessibility) |
797 chrome.experimental.accessibility = {}; | 859 chrome.experimental.accessibility = {}; |
798 | 860 |
799 if (!chrome.experimental.tts) | 861 if (!chrome.experimental.tts) |
800 chrome.experimental.tts = {}; | 862 chrome.experimental.tts = {}; |
801 })(); | 863 })(); |
OLD | NEW |