Chromium Code Reviews| 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 // Shim that simulates a <webview> tag via Mutation Observers. | 5 // Shim that simulates a <webview> tag via Mutation Observers. |
| 6 // | 6 // |
| 7 // The actual tag is implemented via the browser plugin. The internals of this | 7 // The actual tag is implemented via the browser plugin. The internals of this |
| 8 // are hidden via Shadow DOM. | 8 // are hidden via Shadow DOM. |
| 9 | 9 |
| 10 var addTagWatcher = require('tagWatcher').addTagWatcher; | 10 var addTagWatcher = require('tagWatcher').addTagWatcher; |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 29 fields: [] | 29 fields: [] |
| 30 }, | 30 }, |
| 31 'consolemessage': { | 31 'consolemessage': { |
| 32 evt: createEvent('webview.onConsoleMessage'), | 32 evt: createEvent('webview.onConsoleMessage'), |
| 33 fields: ['level', 'message', 'line', 'sourceId'] | 33 fields: ['level', 'message', 'line', 'sourceId'] |
| 34 }, | 34 }, |
| 35 'contentload': { | 35 'contentload': { |
| 36 evt: createEvent('webview.onContentLoad'), | 36 evt: createEvent('webview.onContentLoad'), |
| 37 fields: [] | 37 fields: [] |
| 38 }, | 38 }, |
| 39 'dialog': { | |
|
lazyboy
2013/08/05 09:26:58
mixing this up with stable here seems a bit unclea
Fady Samuel
2013/08/06 07:14:40
Done.
| |
| 40 cancelable: true, | |
| 41 customHandler: function(webview, event, webviewEvent) { | |
| 42 webview.maybeSetupExtDialogEvent_(event, webviewEvent); | |
| 43 }, | |
| 44 evt: createEvent('webview.onDialog'), | |
| 45 fields: ['defaultPromptText', 'messageText', 'messageType', 'url'] | |
| 46 }, | |
| 39 'exit': { | 47 'exit': { |
| 40 evt: createEvent('webview.onExit'), | 48 evt: createEvent('webview.onExit'), |
| 41 fields: ['processId', 'reason'] | 49 fields: ['processId', 'reason'] |
| 42 }, | 50 }, |
| 43 'loadabort': { | 51 'loadabort': { |
| 44 evt: createEvent('webview.onLoadAbort'), | 52 evt: createEvent('webview.onLoadAbort'), |
| 45 fields: ['url', 'isTopLevel', 'reason'] | 53 fields: ['url', 'isTopLevel', 'reason'] |
| 46 }, | 54 }, |
| 47 'loadcommit': { | 55 'loadcommit': { |
| 48 customHandler: function(webview, event) { | 56 customHandler: function(webview, event, webviewEvent) { |
| 49 webview.currentEntryIndex_ = event.currentEntryIndex; | 57 webview.currentEntryIndex_ = event.currentEntryIndex; |
| 50 webview.entryCount_ = event.entryCount; | 58 webview.entryCount_ = event.entryCount; |
| 51 webview.processId_ = event.processId; | 59 webview.processId_ = event.processId; |
| 52 if (event.isTopLevel) { | 60 if (event.isTopLevel) { |
| 53 webview.browserPluginNode_.setAttribute('src', event.url); | 61 webview.browserPluginNode_.setAttribute('src', event.url); |
| 54 } | 62 } |
| 63 webview.webviewNode_.dispatchEvent(webviewEvent); | |
| 55 }, | 64 }, |
| 56 evt: createEvent('webview.onLoadCommit'), | 65 evt: createEvent('webview.onLoadCommit'), |
| 57 fields: ['url', 'isTopLevel'] | 66 fields: ['url', 'isTopLevel'] |
| 58 }, | 67 }, |
| 59 'loadredirect': { | 68 'loadredirect': { |
| 60 evt: createEvent('webview.onLoadRedirect'), | 69 evt: createEvent('webview.onLoadRedirect'), |
| 61 fields: ['isTopLevel', 'oldUrl', 'newUrl'] | 70 fields: ['isTopLevel', 'oldUrl', 'newUrl'] |
| 62 }, | 71 }, |
| 63 'loadstart': { | 72 'loadstart': { |
| 64 evt: createEvent('webview.onLoadStart'), | 73 evt: createEvent('webview.onLoadStart'), |
| 65 fields: ['url', 'isTopLevel'] | 74 fields: ['url', 'isTopLevel'] |
| 66 }, | 75 }, |
| 67 'loadstop': { | 76 'loadstop': { |
| 68 evt: createEvent('webview.onLoadStop'), | 77 evt: createEvent('webview.onLoadStop'), |
| 69 fields: [] | 78 fields: [] |
| 70 }, | 79 }, |
| 80 'newwindow': { | |
| 81 cancelable: true, | |
| 82 customHandler: function(webview, event, webviewEvent) { | |
| 83 webview.setupExtNewWindowEvent_(event, webviewEvent); | |
| 84 }, | |
| 85 evt: createEvent('webview.onNewWindow'), | |
| 86 fields: ['initialHeight', 'initialWidth', 'targetUrl', | |
|
lazyboy
2013/08/05 09:26:58
nit: here and below, since these don't fit in one
Fady Samuel
2013/08/06 07:14:40
Done.
| |
| 87 'windowOpenDisposition', 'name'] | |
| 88 }, | |
| 89 'permissionrequest': { | |
| 90 cancelable: true, | |
| 91 customHandler: function(webview, event, webviewEvent) { | |
| 92 webview.setupExtPermissionEvent_(event, webviewEvent); | |
| 93 }, | |
| 94 evt: createEvent('webview.onPermissionRequest'), | |
| 95 fields: ['lastUnlockedBySelf', 'permission', 'requestMethod', 'url', | |
| 96 'userGesture'] | |
| 97 }, | |
| 71 'responsive': { | 98 'responsive': { |
| 72 evt: createEvent('webview.onResponsive'), | 99 evt: createEvent('webview.onResponsive'), |
| 73 fields: ['processId'] | 100 fields: ['processId'] |
| 74 }, | 101 }, |
| 75 'unresponsive': { | 102 'unresponsive': { |
| 76 evt: createEvent('webview.onUnresponsive'), | 103 evt: createEvent('webview.onUnresponsive'), |
| 77 fields: ['processId'] | 104 fields: ['processId'] |
| 78 } | 105 } |
| 79 }; | 106 }; |
| 80 | 107 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 354 for (var eventName in WEB_VIEW_EXT_EVENTS) { | 381 for (var eventName in WEB_VIEW_EXT_EVENTS) { |
| 355 self.setupExtEvent_(eventName, WEB_VIEW_EXT_EVENTS[eventName]); | 382 self.setupExtEvent_(eventName, WEB_VIEW_EXT_EVENTS[eventName]); |
| 356 } | 383 } |
| 357 }; | 384 }; |
| 358 this.browserPluginNode_.addEventListener('-internal-instanceid-allocated', | 385 this.browserPluginNode_.addEventListener('-internal-instanceid-allocated', |
| 359 onInstanceIdAllocated); | 386 onInstanceIdAllocated); |
| 360 | 387 |
| 361 for (var eventName in WEB_VIEW_EVENTS) { | 388 for (var eventName in WEB_VIEW_EVENTS) { |
| 362 this.setupEvent_(eventName, WEB_VIEW_EVENTS[eventName]); | 389 this.setupEvent_(eventName, WEB_VIEW_EVENTS[eventName]); |
| 363 } | 390 } |
| 364 this.setupNewWindowEvent_(); | |
| 365 this.setupPermissionEvent_(); | |
| 366 }; | 391 }; |
| 367 | 392 |
| 368 /** | 393 /** |
| 369 * @private | 394 * @private |
| 370 */ | 395 */ |
| 371 WebView.prototype.setupExtEvent_ = function(eventName, eventInfo) { | 396 WebView.prototype.setupExtEvent_ = function(eventName, eventInfo) { |
| 372 var self = this; | 397 var self = this; |
| 373 var webviewNode = this.webviewNode_; | 398 var webviewNode = this.webviewNode_; |
| 374 eventInfo.evt.addListener(function(event) { | 399 eventInfo.evt.addListener(function(event) { |
| 375 var webviewEvent = new Event(eventName, {bubbles: true}); | 400 var details = {bubbles:true}; |
| 401 if (eventInfo.cancelable) | |
| 402 details.cancelable = true; | |
| 403 var webviewEvent = new Event(eventName, details); | |
| 376 $Array.forEach(eventInfo.fields, function(field) { | 404 $Array.forEach(eventInfo.fields, function(field) { |
| 377 webviewEvent[field] = event[field]; | 405 if (event[field] != undefined) { |
|
lazyboy
2013/08/05 09:26:58
use !== undefined
Fady Samuel
2013/08/06 07:14:40
Done.
| |
| 406 webviewEvent[field] = event[field]; | |
| 407 } | |
| 378 }); | 408 }); |
| 379 if (eventInfo.customHandler) { | 409 if (eventInfo.customHandler) { |
| 380 eventInfo.customHandler(self, event); | 410 eventInfo.customHandler(self, event, webviewEvent); |
| 411 return; | |
| 381 } | 412 } |
| 382 webviewNode.dispatchEvent(webviewEvent); | 413 webviewNode.dispatchEvent(webviewEvent); |
| 383 }, {instanceId: self.instanceId_}); | 414 }, {instanceId: self.instanceId_}); |
| 384 }; | 415 }; |
| 385 | 416 |
| 386 /** | 417 /** |
| 387 * @private | 418 * @private |
| 388 */ | 419 */ |
| 389 WebView.prototype.setupEvent_ = function(eventName, attribs) { | 420 WebView.prototype.setupEvent_ = function(eventName, attribs) { |
| 390 var webviewNode = this.webviewNode_; | 421 var webviewNode = this.webviewNode_; |
| 391 var internalname = '-internal-' + eventName; | 422 var internalname = '-internal-' + eventName; |
| 392 this.browserPluginNode_.addEventListener(internalname, function(e) { | 423 this.browserPluginNode_.addEventListener(internalname, function(e) { |
| 393 var evt = new Event(eventName, { bubbles: true }); | 424 var evt = new Event(eventName, { bubbles: true }); |
| 394 var detail = e.detail ? JSON.parse(e.detail) : {}; | 425 var detail = e.detail ? JSON.parse(e.detail) : {}; |
| 395 $Array.forEach(attribs, function(attribName) { | 426 $Array.forEach(attribs, function(attribName) { |
| 396 evt[attribName] = detail[attribName]; | 427 evt[attribName] = detail[attribName]; |
| 397 }); | 428 }); |
| 398 webviewNode.dispatchEvent(evt); | 429 webviewNode.dispatchEvent(evt); |
| 399 }); | 430 }); |
| 400 }; | 431 }; |
| 401 | 432 |
| 402 /** | 433 /** |
| 403 * @private | 434 * @private |
| 404 */ | 435 */ |
| 405 WebView.prototype.setupNewWindowEvent_ = function() { | 436 WebView.prototype.setupExtNewWindowEvent_ = function(event, webviewEvent) { |
| 406 var ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN = '<webview>: ' + | 437 var ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN = '<webview>: ' + |
| 407 'An action has already been taken for this "newwindow" event.'; | 438 'An action has already been taken for this "newwindow" event.'; |
| 408 | 439 |
| 409 var ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH = '<webview>: ' + | 440 var ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH = '<webview>: ' + |
| 410 'Unable to attach the new window to the provided webview.'; | 441 'Unable to attach the new window to the provided webview.'; |
| 411 | 442 |
| 412 var ERROR_MSG_WEBVIEW_EXPECTED = '<webview> element expected.'; | 443 var ERROR_MSG_WEBVIEW_EXPECTED = '<webview> element expected.'; |
| 413 | 444 |
| 414 var showWarningMessage = function() { | 445 var showWarningMessage = function() { |
| 415 var WARNING_MSG_NEWWINDOW_BLOCKED = '<webview>: A new window was blocked.'; | 446 var WARNING_MSG_NEWWINDOW_BLOCKED = '<webview>: A new window was blocked.'; |
| 416 console.warn(WARNING_MSG_NEWWINDOW_BLOCKED); | 447 console.warn(WARNING_MSG_NEWWINDOW_BLOCKED); |
| 417 }; | 448 }; |
| 418 | 449 |
| 419 var NEW_WINDOW_EVENT_ATTRIBUTES = [ | 450 var self = this; |
| 420 'initialHeight', | 451 var browserPluginNode = this.browserPluginNode_; |
| 421 'initialWidth', | 452 var webviewNode = this.webviewNode_; |
| 422 'targetUrl', | |
| 423 'windowOpenDisposition', | |
| 424 'name' | |
| 425 ]; | |
| 426 | 453 |
| 427 var self = this; | 454 var requestId = event.requestId; |
| 428 var node = this.webviewNode_; | 455 var actionTaken = false; |
| 429 var browserPluginNode = this.browserPluginNode_; | |
| 430 | 456 |
| 431 var onTrackedObjectGone = function(requestId, e) { | 457 var onTrackedObjectGone = function(requestId, e) { |
| 432 var detail = e.detail ? JSON.parse(e.detail) : {}; | 458 var detail = e.detail ? JSON.parse(e.detail) : {}; |
| 433 if (detail.id != requestId) { | 459 if (detail.id != requestId) { |
| 434 return; | 460 return; |
| 435 } | 461 } |
| 436 // If the request was pending then show a warning indiciating that a dialog | |
| 437 // was blocked. | |
| 438 if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { | |
| 439 showWarningMessage(); | |
| 440 } | |
| 441 }; | |
| 442 | 462 |
| 443 browserPluginNode.addEventListener('-internal-newwindow', function(e) { | 463 // Avoid showing a warning message if the decision has already been made. |
| 444 var evt = new Event('newwindow', { bubbles: true, cancelable: true }); | |
| 445 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
| 446 | |
| 447 $Array.forEach(NEW_WINDOW_EVENT_ATTRIBUTES, function(attribName) { | |
| 448 evt[attribName] = detail[attribName]; | |
| 449 }); | |
| 450 var requestId = detail.requestId; | |
| 451 var actionTaken = false; | |
| 452 | |
| 453 var validateCall = function () { | |
| 454 if (actionTaken) { | |
| 455 throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN); | |
| 456 } | |
| 457 actionTaken = true; | |
| 458 }; | |
| 459 | |
| 460 var window = { | |
| 461 attach: function(webview) { | |
| 462 validateCall(); | |
| 463 if (!webview) | |
| 464 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | |
| 465 // Attach happens asynchronously to give the tagWatcher an opportunity | |
| 466 // to pick up the new webview before attach operates on it, if it hasn't | |
| 467 // been attached to the DOM already. | |
| 468 // Note: Any subsequent errors cannot be exceptions because they happen | |
| 469 // asynchronously. | |
| 470 setTimeout(function() { | |
| 471 var attached = | |
| 472 browserPluginNode['-internal-attachWindowTo'](webview, | |
| 473 detail.windowId); | |
| 474 if (!attached) { | |
| 475 console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | |
| 476 } | |
| 477 // If the object being passed into attach is not a valid <webview> | |
| 478 // then we will fail and it will be treated as if the new window | |
| 479 // was rejected. The permission API plumbing is used here to clean | |
| 480 // up the state created for the new window if attaching fails. | |
| 481 browserPluginNode['-internal-setPermission'](requestId, attached, ''); | |
| 482 }, 0); | |
| 483 }, | |
| 484 discard: function() { | |
| 485 validateCall(); | |
| 486 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 487 } | |
| 488 }; | |
| 489 evt.window = window; | |
| 490 | |
| 491 var defaultPrevented = !node.dispatchEvent(evt); | |
| 492 if (actionTaken) { | 464 if (actionTaken) { |
| 493 return; | 465 return; |
| 494 } | 466 } |
| 495 | 467 |
| 496 if (defaultPrevented) { | 468 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 497 // Make browser plugin track lifetime of |window|. | 469 showWarningMessage(); |
| 498 var onTrackedObjectGoneWithRequestId = | 470 }; |
| 499 $Function.bind(onTrackedObjectGone, self, requestId); | 471 |
| 500 browserPluginNode.addEventListener('-internal-trackedobjectgone', | 472 |
| 501 onTrackedObjectGoneWithRequestId); | 473 var validateCall = function () { |
| 502 browserPluginNode['-internal-trackObjectLifetime'](window, requestId); | 474 if (actionTaken) { |
| 503 } else { | 475 throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN); |
| 504 actionTaken = true; | |
| 505 // The default action is to discard the window. | |
| 506 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 507 showWarningMessage(); | |
| 508 } | 476 } |
| 477 actionTaken = true; | |
| 478 }; | |
| 509 | 479 |
| 510 }); | 480 var window = { |
| 481 attach: function(webview) { | |
| 482 validateCall(); | |
| 483 if (!webview) | |
| 484 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | |
| 485 // Attach happens asynchronously to give the tagWatcher an opportunity | |
| 486 // to pick up the new webview before attach operates on it, if it hasn't | |
| 487 // been attached to the DOM already. | |
| 488 // Note: Any subsequent errors cannot be exceptions because they happen | |
| 489 // asynchronously. | |
| 490 setTimeout(function() { | |
| 491 var attached = | |
| 492 browserPluginNode['-internal-attachWindowTo'](webview, | |
| 493 event.windowId); | |
| 494 if (!attached) { | |
| 495 console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | |
| 496 } | |
| 497 // If the object being passed into attach is not a valid <webview> | |
| 498 // then we will fail and it will be treated as if the new window | |
| 499 // was rejected. The permission API plumbing is used here to clean | |
| 500 // up the state created for the new window if attaching fails. | |
| 501 chrome.webview.setPermission(self.instanceId_, requestId, attached, ''); | |
| 502 }, 0); | |
| 503 }, | |
| 504 discard: function() { | |
| 505 validateCall(); | |
| 506 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 507 } | |
| 508 }; | |
| 509 webviewEvent.window = window; | |
| 510 | |
| 511 var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); | |
| 512 if (actionTaken) { | |
| 513 return; | |
| 514 } | |
| 515 | |
| 516 if (defaultPrevented) { | |
| 517 // Make browser plugin track lifetime of |window|. | |
| 518 var onTrackedObjectGoneWithRequestId = | |
| 519 $Function.bind(onTrackedObjectGone, self, requestId); | |
| 520 browserPluginNode.addEventListener('-internal-trackedobjectgone', | |
| 521 onTrackedObjectGoneWithRequestId); | |
| 522 browserPluginNode['-internal-trackObjectLifetime'](window, requestId); | |
| 523 } else { | |
| 524 actionTaken = true; | |
| 525 // The default action is to discard the window. | |
| 526 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 527 showWarningMessage(); | |
| 528 } | |
| 511 }; | 529 }; |
| 512 | 530 |
| 513 /** | 531 /** |
| 514 * @private | 532 * @private |
| 515 */ | 533 */ |
| 516 WebView.prototype.setupExecuteCodeAPI_ = function() { | 534 WebView.prototype.setupExecuteCodeAPI_ = function() { |
| 517 var ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' + | 535 var ERROR_MSG_CANNOT_INJECT_SCRIPT = '<webview>: ' + |
| 518 'Script cannot be injected into content until the page has loaded.'; | 536 'Script cannot be injected into content until the page has loaded.'; |
| 519 | 537 |
| 520 var self = this; | 538 var self = this; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 532 } | 550 } |
| 533 this.webviewNode_['insertCSS'] = function(var_args) { | 551 this.webviewNode_['insertCSS'] = function(var_args) { |
| 534 validateCall(); | 552 validateCall(); |
| 535 var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()], | 553 var args = $Array.concat([self.browserPluginNode_.getGuestInstanceId()], |
| 536 $Array.slice(arguments)); | 554 $Array.slice(arguments)); |
| 537 $Function.apply(chrome.webview.insertCSS, null, args); | 555 $Function.apply(chrome.webview.insertCSS, null, args); |
| 538 } | 556 } |
| 539 }; | 557 }; |
| 540 | 558 |
| 541 /** | 559 /** |
| 542 * @param {!Object} detail The event details, originated from <object>. | |
| 543 * @private | 560 * @private |
| 544 */ | 561 */ |
| 545 WebView.prototype.setupPermissionEvent_ = function() { | 562 WebView.prototype.getPermissionTypes_ = function() { |
| 563 return ['media', 'geolocation', 'pointerLock', 'download']; | |
| 564 }; | |
| 565 | |
| 566 WebView.prototype.setupExtPermissionEvent_ = function(event, webviewEvent) { | |
| 546 var ERROR_MSG_PERMISSION_ALREADY_DECIDED = '<webview>: ' + | 567 var ERROR_MSG_PERMISSION_ALREADY_DECIDED = '<webview>: ' + |
| 547 'Permission has already been decided for this "permissionrequest" event.'; | 568 'Permission has already been decided for this "permissionrequest" event.'; |
| 548 | 569 |
| 549 var showWarningMessage = function(permission) { | 570 var showWarningMessage = function(permission) { |
| 550 var WARNING_MSG_PERMISSION_DENIED = '<webview>: ' + | 571 var WARNING_MSG_PERMISSION_DENIED = '<webview>: ' + |
| 551 'The permission request for "%1" has been denied.'; | 572 'The permission request for "%1" has been denied.'; |
| 552 console.warn(WARNING_MSG_PERMISSION_DENIED.replace('%1', permission)); | 573 console.warn(WARNING_MSG_PERMISSION_DENIED.replace('%1', permission)); |
| 553 }; | 574 }; |
| 554 | 575 |
| 555 var PERMISSION_TYPES = ['media', 'geolocation', 'pointerLock', 'download']; | 576 var PERMISSION_TYPES = this.getPermissionTypes_(); |
| 556 | |
| 557 var EXPOSED_PERMISSION_EVENT_ATTRIBS = [ | |
| 558 'lastUnlockedBySelf', | |
| 559 'permission', | |
| 560 'requestMethod', | |
| 561 'url', | |
| 562 'userGesture' | |
| 563 ]; | |
| 564 | 577 |
| 565 var self = this; | 578 var self = this; |
| 566 var node = this.webviewNode_; | |
| 567 var browserPluginNode = this.browserPluginNode_; | 579 var browserPluginNode = this.browserPluginNode_; |
| 568 var internalevent = '-internal-permissionrequest'; | 580 var webviewNode = this.webviewNode_; |
| 581 | |
| 582 var requestId = event.requestId; | |
| 583 var decisionMade = false; | |
| 569 | 584 |
| 570 var onTrackedObjectGone = function(requestId, permission, e) { | 585 var onTrackedObjectGone = function(requestId, permission, e) { |
| 571 var detail = e.detail ? JSON.parse(e.detail) : {}; | 586 var detail = e.detail ? JSON.parse(e.detail) : {}; |
| 572 if (detail.id != requestId) | 587 if (detail.id != requestId) { |
| 573 return; | |
| 574 // If the request was pending then show a warning indiciating that the | |
| 575 // permission was denied. | |
| 576 if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { | |
| 577 showWarningMessage(permission); | |
| 578 } | |
| 579 }; | |
| 580 | |
| 581 browserPluginNode.addEventListener(internalevent, function(e) { | |
| 582 var evt = new Event('permissionrequest', {bubbles: true, cancelable: true}); | |
| 583 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
| 584 $Array.forEach(EXPOSED_PERMISSION_EVENT_ATTRIBS, function(attribName) { | |
| 585 if (detail[attribName] !== undefined) | |
| 586 evt[attribName] = detail[attribName]; | |
| 587 }); | |
| 588 var requestId = detail.requestId; | |
| 589 | |
| 590 if (detail.requestId == undefined || | |
| 591 PERMISSION_TYPES.indexOf(detail.permission) < 0) { | |
| 592 return; | 588 return; |
| 593 } | 589 } |
| 594 | 590 |
| 595 // TODO(lazyboy): Also fill in evt.details (see webview specs). | 591 // Avoid showing a warning message if the decision has already been made. |
| 596 // http://crbug.com/141197. | |
| 597 var decisionMade = false; | |
| 598 | |
| 599 var validateCall = function() { | |
| 600 if (decisionMade) { | |
| 601 throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED); | |
| 602 } | |
| 603 decisionMade = true; | |
| 604 }; | |
| 605 | |
| 606 // Construct the event.request object. | |
| 607 var request = { | |
| 608 allow: function() { | |
| 609 validateCall(); | |
| 610 browserPluginNode['-internal-setPermission'](requestId, true, ''); | |
| 611 }, | |
| 612 deny: function() { | |
| 613 validateCall(); | |
| 614 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 615 } | |
| 616 }; | |
| 617 evt.request = request; | |
| 618 | |
| 619 var defaultPrevented = !node.dispatchEvent(evt); | |
| 620 if (decisionMade) { | 592 if (decisionMade) { |
| 621 return; | 593 return; |
| 622 } | 594 } |
| 623 | 595 |
| 624 if (defaultPrevented) { | 596 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 625 // Make browser plugin track lifetime of |request|. | 597 showWarningMessage(permission); |
| 626 var onTrackedObjectGoneWithRequestId = | 598 }; |
| 627 $Function.bind( | 599 |
| 628 onTrackedObjectGone, self, requestId, detail.permission); | 600 var validateCall = function() { |
| 629 browserPluginNode.addEventListener('-internal-trackedobjectgone', | 601 if (decisionMade) { |
| 630 onTrackedObjectGoneWithRequestId); | 602 throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED); |
| 631 browserPluginNode['-internal-trackObjectLifetime'](request, requestId); | |
| 632 } else { | |
| 633 decisionMade = true; | |
| 634 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 635 showWarningMessage(detail.permission); | |
| 636 } | 603 } |
| 637 }); | 604 decisionMade = true; |
| 605 }; | |
| 606 | |
| 607 // Construct the event.request object. | |
| 608 var request = { | |
| 609 allow: function() { | |
| 610 validateCall(); | |
| 611 chrome.webview.setPermission(self.instanceId_, requestId, true, ''); | |
| 612 }, | |
| 613 deny: function() { | |
| 614 validateCall(); | |
| 615 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 616 } | |
| 617 }; | |
| 618 webviewEvent.request = request; | |
| 619 | |
| 620 var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); | |
| 621 if (decisionMade) { | |
| 622 return; | |
| 623 } | |
| 624 | |
| 625 if (defaultPrevented) { | |
| 626 // Make browser plugin track lifetime of |request|. | |
| 627 var onTrackedObjectGoneWithRequestId = | |
| 628 $Function.bind( | |
| 629 onTrackedObjectGone, self, requestId, event.permission); | |
| 630 browserPluginNode.addEventListener('-internal-trackedobjectgone', | |
| 631 onTrackedObjectGoneWithRequestId); | |
| 632 browserPluginNode['-internal-trackObjectLifetime'](request, requestId); | |
| 633 } else { | |
| 634 decisionMade = true; | |
| 635 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 636 showWarningMessage(event.permission); | |
| 637 } | |
| 638 }; | 638 }; |
| 639 | 639 |
| 640 /** | 640 /** |
| 641 * Implemented when the experimental API is available. | 641 * Implemented when the experimental API is available. |
| 642 * @private | 642 * @private |
| 643 */ | 643 */ |
| 644 WebView.prototype.maybeSetupExperimentalAPI_ = function() {}; | 644 WebView.prototype.maybeSetupExperimentalAPI_ = function() {}; |
| 645 | 645 |
| 646 /** | |
| 647 * Implemented when the experimental API is available. | |
| 648 * @private | |
| 649 */ | |
| 650 WebView.prototype.maybeSetupExtDialogEvent_ = function() {}; | |
| 651 | |
| 646 exports.WebView = WebView; | 652 exports.WebView = WebView; |
| OLD | NEW |