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