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 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
344 // Setup Functions. | 344 // Setup Functions. |
345 if (apiDef.functions) { | 345 if (apiDef.functions) { |
346 apiDef.functions.forEach(function(functionDef) { | 346 apiDef.functions.forEach(function(functionDef) { |
347 // Module functions may have been defined earlier by hand. Don't | 347 // Module functions may have been defined earlier by hand. Don't |
348 // clobber them. | 348 // clobber them. |
349 if (module[functionDef.name]) | 349 if (module[functionDef.name]) |
350 return; | 350 return; |
351 | 351 |
352 var apiFunction = {}; | 352 var apiFunction = {}; |
353 apiFunction.definition = functionDef; | 353 apiFunction.definition = functionDef; |
354 apiFunction.name = apiDef.namespace + "." + functionDef.name;; | 354 apiFunction.name = apiDef.namespace + "." + functionDef.name; |
355 apiFunctions[apiFunction.name] = apiFunction; | 355 apiFunctions[apiFunction.name] = apiFunction; |
356 | 356 |
357 module[functionDef.name] = bind(apiFunction, function() { | 357 module[functionDef.name] = bind(apiFunction, function() { |
358 chromeHidden.validate(arguments, this.definition.parameters); | 358 var args = arguments; |
| 359 if (this.updateArguments) { |
| 360 // Functions whose signature has changed can define an |
| 361 // |updateArguments| function to transform old argument lists |
| 362 // into the new form, preserving compatibility. |
| 363 // TODO(skerner): Once optional args can be omitted (crbug/29215), |
| 364 // this mechanism will become unnecessary. Consider removing it |
| 365 // when crbug/29215 is fixed. |
| 366 args = this.updateArguments.apply(this, args); |
| 367 } |
| 368 chromeHidden.validate(args, this.definition.parameters); |
359 | 369 |
360 var retval; | 370 var retval; |
361 if (this.handleRequest) { | 371 if (this.handleRequest) { |
362 retval = this.handleRequest.apply(this, arguments); | 372 retval = this.handleRequest.apply(this, args); |
363 } else { | 373 } else { |
364 retval = sendRequest(this.name, arguments, | 374 retval = sendRequest(this.name, args, |
365 this.definition.parameters, | 375 this.definition.parameters, |
366 this.customCallback); | 376 this.customCallback); |
367 } | 377 } |
368 | 378 |
369 // Validate return value if defined - only in debug. | 379 // Validate return value if defined - only in debug. |
370 if (chromeHidden.validateCallbacks && | 380 if (chromeHidden.validateCallbacks && |
371 chromeHidden.validate && | 381 chromeHidden.validate && |
372 this.definition.returns) { | 382 this.definition.returns) { |
373 chromeHidden.validate([retval], [this.definition.returns]); | 383 chromeHidden.validate([retval], [this.definition.returns]); |
374 } | 384 } |
(...skipping 23 matching lines...) Expand all Loading... |
398 }); | 408 }); |
399 | 409 |
400 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { | 410 apiFunctions["tabs.connect"].handleRequest = function(tabId, connectInfo) { |
401 var name = ""; | 411 var name = ""; |
402 if (connectInfo) { | 412 if (connectInfo) { |
403 name = connectInfo.name || name; | 413 name = connectInfo.name || name; |
404 } | 414 } |
405 var portId = OpenChannelToTab( | 415 var portId = OpenChannelToTab( |
406 tabId, chromeHidden.extensionId, name); | 416 tabId, chromeHidden.extensionId, name); |
407 return chromeHidden.Port.createPort(portId, name); | 417 return chromeHidden.Port.createPort(portId, name); |
408 } | 418 }; |
409 | 419 |
410 apiFunctions["tabs.sendRequest"].handleRequest = | 420 apiFunctions["tabs.sendRequest"].handleRequest = |
411 function(tabId, request, responseCallback) { | 421 function(tabId, request, responseCallback) { |
412 var port = chrome.tabs.connect(tabId, | 422 var port = chrome.tabs.connect(tabId, |
413 {name: chromeHidden.kRequestChannel}); | 423 {name: chromeHidden.kRequestChannel}); |
414 port.postMessage(request); | 424 port.postMessage(request); |
415 port.onMessage.addListener(function(response) { | 425 port.onMessage.addListener(function(response) { |
416 if (responseCallback) | 426 if (responseCallback) |
417 responseCallback(response); | 427 responseCallback(response); |
418 port.disconnect(); | 428 port.disconnect(); |
419 }); | 429 }); |
420 } | 430 }; |
421 | 431 |
422 apiFunctions["extension.getViews"].handleRequest = function(properties) { | 432 apiFunctions["extension.getViews"].handleRequest = function(properties) { |
423 var windowId = -1; | 433 var windowId = -1; |
424 var type = "ALL"; | 434 var type = "ALL"; |
425 if (typeof(properties) != "undefined") { | 435 if (typeof(properties) != "undefined") { |
426 if (typeof(properties.type) != "undefined") { | 436 if (typeof(properties.type) != "undefined") { |
427 type = properties.type; | 437 type = properties.type; |
428 } | 438 } |
429 if (typeof(properties.windowId) != "undefined") { | 439 if (typeof(properties.windowId) != "undefined") { |
430 windowId = properties.windowId; | 440 windowId = properties.windowId; |
431 } | 441 } |
432 } | 442 } |
433 return GetExtensionViews(windowId, type) || null; | 443 return GetExtensionViews(windowId, type) || null; |
434 } | 444 }; |
435 | 445 |
436 apiFunctions["extension.getBackgroundPage"].handleRequest = function() { | 446 apiFunctions["extension.getBackgroundPage"].handleRequest = function() { |
437 return GetExtensionViews(-1, "BACKGROUND")[0] || null; | 447 return GetExtensionViews(-1, "BACKGROUND")[0] || null; |
438 } | 448 }; |
439 | 449 |
440 apiFunctions["extension.getToolstrips"].handleRequest = | 450 apiFunctions["extension.getToolstrips"].handleRequest = |
441 function(windowId) { | 451 function(windowId) { |
442 if (typeof(windowId) == "undefined") | 452 if (typeof(windowId) == "undefined") |
443 windowId = -1; | 453 windowId = -1; |
444 return GetExtensionViews(windowId, "TOOLSTRIP"); | 454 return GetExtensionViews(windowId, "TOOLSTRIP"); |
445 } | 455 }; |
446 | 456 |
447 apiFunctions["extension.getExtensionTabs"].handleRequest = | 457 apiFunctions["extension.getExtensionTabs"].handleRequest = |
448 function(windowId) { | 458 function(windowId) { |
449 if (typeof(windowId) == "undefined") | 459 if (typeof(windowId) == "undefined") |
450 windowId = -1; | 460 windowId = -1; |
451 return GetExtensionViews(windowId, "TAB"); | 461 return GetExtensionViews(windowId, "TAB"); |
452 } | 462 }; |
453 | 463 |
454 apiFunctions["devtools.getTabEvents"].handleRequest = function(tabId) { | 464 apiFunctions["devtools.getTabEvents"].handleRequest = function(tabId) { |
455 var tabIdProxy = {}; | 465 var tabIdProxy = {}; |
456 var functions = ["onPageEvent", "onTabClose"]; | 466 var functions = ["onPageEvent", "onTabClose"]; |
457 functions.forEach(function(name) { | 467 functions.forEach(function(name) { |
458 // Event disambiguation is handled by name munging. See | 468 // Event disambiguation is handled by name munging. See |
459 // chrome/browser/extensions/extension_devtools_events.h for the C++ | 469 // chrome/browser/extensions/extension_devtools_events.h for the C++ |
460 // equivalent of this logic. | 470 // equivalent of this logic. |
461 tabIdProxy[name] = new chrome.Event("devtools." + tabId + "." + name); | 471 tabIdProxy[name] = new chrome.Event("devtools." + tabId + "." + name); |
462 }); | 472 }); |
463 return tabIdProxy; | 473 return tabIdProxy; |
464 } | 474 }; |
465 | 475 |
466 apiFunctions["experimental.popup.show"].handleRequest = | 476 apiFunctions["experimental.popup.show"].handleRequest = |
467 function(url, showDetails, callback) { | 477 function(url, showDetails, callback) { |
468 // Second argument is a transform from HTMLElement to Rect. | 478 // Second argument is a transform from HTMLElement to Rect. |
469 var internalSchema = [ | 479 var internalSchema = [ |
470 this.definition.parameters[0], | 480 this.definition.parameters[0], |
471 { | 481 { |
472 type: "object", | 482 type: "object", |
473 name: "showDetails", | 483 name: "showDetails", |
474 properties: { | 484 properties: { |
(...skipping 21 matching lines...) Expand all Loading... |
496 ]; | 506 ]; |
497 return sendRequest(this.name, | 507 return sendRequest(this.name, |
498 [url, | 508 [url, |
499 { | 509 { |
500 domAnchor: getAbsoluteRect(showDetails.relativeTo), | 510 domAnchor: getAbsoluteRect(showDetails.relativeTo), |
501 giveFocus: showDetails.giveFocus, | 511 giveFocus: showDetails.giveFocus, |
502 borderStyle: showDetails.borderStyle | 512 borderStyle: showDetails.borderStyle |
503 }, | 513 }, |
504 callback], | 514 callback], |
505 internalSchema); | 515 internalSchema); |
506 } | 516 }; |
507 | 517 |
508 apiFunctions["experimental.extension.getPopupView"].handleRequest = | 518 apiFunctions["experimental.extension.getPopupView"].handleRequest = |
509 function() { | 519 function() { |
510 return GetPopupView(); | 520 return GetPopupView(); |
511 } | 521 }; |
512 | 522 |
513 apiFunctions["experimental.popup.getParentWindow"].handleRequest = | 523 apiFunctions["experimental.popup.getParentWindow"].handleRequest = |
514 function() { | 524 function() { |
515 return GetPopupParentWindow(); | 525 return GetPopupParentWindow(); |
516 } | 526 }; |
517 | 527 |
518 var canvas; | 528 var canvas; |
519 function setIconCommon(details, name, parameters, actionType) { | 529 function setIconCommon(details, name, parameters, actionType) { |
520 var EXTENSION_ACTION_ICON_SIZE = 19; | 530 var EXTENSION_ACTION_ICON_SIZE = 19; |
521 | 531 |
522 if ("iconIndex" in details) { | 532 if ("iconIndex" in details) { |
523 sendRequest(name, [details], parameters); | 533 sendRequest(name, [details], parameters); |
524 } else if ("imageData" in details) { | 534 } else if ("imageData" in details) { |
525 // Verify that this at least looks like an ImageData element. | 535 // Verify that this at least looks like an ImageData element. |
526 // Unfortunately, we cannot use instanceof because the ImageData | 536 // Unfortunately, we cannot use instanceof because the ImageData |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 } | 604 } |
595 }; | 605 }; |
596 | 606 |
597 apiFunctions["experimental.contextMenu.remove"].customCallback = | 607 apiFunctions["experimental.contextMenu.remove"].customCallback = |
598 function(name, request, response) { | 608 function(name, request, response) { |
599 // Remove any onclick handler we had registered for this menu item. | 609 // Remove any onclick handler we had registered for this menu item. |
600 if (request.args.length > 0) { | 610 if (request.args.length > 0) { |
601 var menuItemId = request.args[0]; | 611 var menuItemId = request.args[0]; |
602 delete chromeHidden.contextMenuHandlers[menuItemId]; | 612 delete chromeHidden.contextMenuHandlers[menuItemId]; |
603 } | 613 } |
604 } | 614 }; |
| 615 |
| 616 apiFunctions["tabs.captureVisibleTab"].updateArguments = function() { |
| 617 // Old signature: |
| 618 // captureVisibleTab(int windowId, function callback); |
| 619 // New signature: |
| 620 // captureVisibleTab(int windowId, object details, function callback); |
| 621 // |
| 622 // TODO(skerner): The next step to omitting optional arguments is the |
| 623 // replacement of this code with code that matches arguments by type. |
| 624 // Once this is working for captureVisibleTab() it can be enabled for |
| 625 // the rest of the API. See crbug/29215 . |
| 626 if (arguments.length == 2 && typeof(arguments[1]) == "function") { |
| 627 // If the old signature is used, add a null details object. |
| 628 newArgs = [arguments[0], null, arguments[1]]; |
| 629 } else { |
| 630 newArgs = arguments; |
| 631 } |
| 632 return newArgs; |
| 633 }; |
605 | 634 |
606 if (chrome.test) { | 635 if (chrome.test) { |
607 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; | 636 chrome.test.getApiDefinitions = GetExtensionAPIDefinition; |
608 } | 637 } |
609 | 638 |
610 setupBrowserActionEvent(extensionId); | 639 setupBrowserActionEvent(extensionId); |
611 setupPageActionEvents(extensionId); | 640 setupPageActionEvents(extensionId); |
612 setupToolstripEvents(GetRenderViewId()); | 641 setupToolstripEvents(GetRenderViewId()); |
613 setupPopupEvents(GetRenderViewId()); | 642 setupPopupEvents(GetRenderViewId()); |
614 setupHiddenContextMenuEvent(extensionId); | 643 setupHiddenContextMenuEvent(extensionId); |
615 }); | 644 }); |
616 | 645 |
617 if (!chrome.experimental) | 646 if (!chrome.experimental) |
618 chrome.experimental = {}; | 647 chrome.experimental = {}; |
619 | 648 |
620 if (!chrome.experimental.accessibility) | 649 if (!chrome.experimental.accessibility) |
621 chrome.experimental.accessibility = {}; | 650 chrome.experimental.accessibility = {}; |
622 })(); | 651 })(); |
OLD | NEW |