Chromium Code Reviews| Index: chrome/renderer/resources/extensions/web_view.js |
| diff --git a/chrome/renderer/resources/extensions/web_view.js b/chrome/renderer/resources/extensions/web_view.js |
| index 52126d45df008521d26c95737d4d621032970560..7ec4e56d0e580e4e79189e5bb7aaec5b09600051 100644 |
| --- a/chrome/renderer/resources/extensions/web_view.js |
| +++ b/chrome/renderer/resources/extensions/web_view.js |
| @@ -36,6 +36,14 @@ var WEB_VIEW_EXT_EVENTS = { |
| evt: createEvent('webview.onContentLoad'), |
| fields: [] |
| }, |
| + '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.
|
| + cancelable: true, |
| + customHandler: function(webview, event, webviewEvent) { |
| + webview.maybeSetupExtDialogEvent_(event, webviewEvent); |
| + }, |
| + evt: createEvent('webview.onDialog'), |
| + fields: ['defaultPromptText', 'messageText', 'messageType', 'url'] |
| + }, |
| 'exit': { |
| evt: createEvent('webview.onExit'), |
| fields: ['processId', 'reason'] |
| @@ -45,13 +53,14 @@ var WEB_VIEW_EXT_EVENTS = { |
| fields: ['url', 'isTopLevel', 'reason'] |
| }, |
| 'loadcommit': { |
| - customHandler: function(webview, event) { |
| + customHandler: function(webview, event, webviewEvent) { |
| webview.currentEntryIndex_ = event.currentEntryIndex; |
| webview.entryCount_ = event.entryCount; |
| webview.processId_ = event.processId; |
| if (event.isTopLevel) { |
| webview.browserPluginNode_.setAttribute('src', event.url); |
| } |
| + webview.webviewNode_.dispatchEvent(webviewEvent); |
| }, |
| evt: createEvent('webview.onLoadCommit'), |
| fields: ['url', 'isTopLevel'] |
| @@ -68,6 +77,24 @@ var WEB_VIEW_EXT_EVENTS = { |
| evt: createEvent('webview.onLoadStop'), |
| fields: [] |
| }, |
| + 'newwindow': { |
| + cancelable: true, |
| + customHandler: function(webview, event, webviewEvent) { |
| + webview.setupExtNewWindowEvent_(event, webviewEvent); |
| + }, |
| + evt: createEvent('webview.onNewWindow'), |
| + 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.
|
| + 'windowOpenDisposition', 'name'] |
| + }, |
| + 'permissionrequest': { |
| + cancelable: true, |
| + customHandler: function(webview, event, webviewEvent) { |
| + webview.setupExtPermissionEvent_(event, webviewEvent); |
| + }, |
| + evt: createEvent('webview.onPermissionRequest'), |
| + fields: ['lastUnlockedBySelf', 'permission', 'requestMethod', 'url', |
| + 'userGesture'] |
| + }, |
| 'responsive': { |
| evt: createEvent('webview.onResponsive'), |
| fields: ['processId'] |
| @@ -361,8 +388,6 @@ WebView.prototype.setupWebviewNodeEvents_ = function() { |
| for (var eventName in WEB_VIEW_EVENTS) { |
| this.setupEvent_(eventName, WEB_VIEW_EVENTS[eventName]); |
| } |
| - this.setupNewWindowEvent_(); |
| - this.setupPermissionEvent_(); |
| }; |
| /** |
| @@ -372,12 +397,18 @@ WebView.prototype.setupExtEvent_ = function(eventName, eventInfo) { |
| var self = this; |
| var webviewNode = this.webviewNode_; |
| eventInfo.evt.addListener(function(event) { |
| - var webviewEvent = new Event(eventName, {bubbles: true}); |
| + var details = {bubbles:true}; |
| + if (eventInfo.cancelable) |
| + details.cancelable = true; |
| + var webviewEvent = new Event(eventName, details); |
| $Array.forEach(eventInfo.fields, function(field) { |
| - webviewEvent[field] = event[field]; |
| + if (event[field] != undefined) { |
|
lazyboy
2013/08/05 09:26:58
use !== undefined
Fady Samuel
2013/08/06 07:14:40
Done.
|
| + webviewEvent[field] = event[field]; |
| + } |
| }); |
| if (eventInfo.customHandler) { |
| - eventInfo.customHandler(self, event); |
| + eventInfo.customHandler(self, event, webviewEvent); |
| + return; |
| } |
| webviewNode.dispatchEvent(webviewEvent); |
| }, {instanceId: self.instanceId_}); |
| @@ -402,7 +433,7 @@ WebView.prototype.setupEvent_ = function(eventName, attribs) { |
| /** |
| * @private |
| */ |
| -WebView.prototype.setupNewWindowEvent_ = function() { |
| +WebView.prototype.setupExtNewWindowEvent_ = function(event, webviewEvent) { |
| var ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN = '<webview>: ' + |
| 'An action has already been taken for this "newwindow" event.'; |
| @@ -416,98 +447,85 @@ WebView.prototype.setupNewWindowEvent_ = function() { |
| console.warn(WARNING_MSG_NEWWINDOW_BLOCKED); |
| }; |
| - var NEW_WINDOW_EVENT_ATTRIBUTES = [ |
| - 'initialHeight', |
| - 'initialWidth', |
| - 'targetUrl', |
| - 'windowOpenDisposition', |
| - 'name' |
| - ]; |
| - |
| var self = this; |
| - var node = this.webviewNode_; |
| var browserPluginNode = this.browserPluginNode_; |
| + var webviewNode = this.webviewNode_; |
| + |
| + var requestId = event.requestId; |
| + var actionTaken = false; |
| var onTrackedObjectGone = function(requestId, e) { |
| var detail = e.detail ? JSON.parse(e.detail) : {}; |
| if (detail.id != requestId) { |
| return; |
| } |
| - // If the request was pending then show a warning indiciating that a dialog |
| - // was blocked. |
| - if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { |
| - showWarningMessage(); |
| - } |
| - }; |
| - browserPluginNode.addEventListener('-internal-newwindow', function(e) { |
| - var evt = new Event('newwindow', { bubbles: true, cancelable: true }); |
| - var detail = e.detail ? JSON.parse(e.detail) : {}; |
| - |
| - $Array.forEach(NEW_WINDOW_EVENT_ATTRIBUTES, function(attribName) { |
| - evt[attribName] = detail[attribName]; |
| - }); |
| - var requestId = detail.requestId; |
| - var actionTaken = false; |
| + // Avoid showing a warning message if the decision has already been made. |
| + if (actionTaken) { |
| + return; |
| + } |
| - var validateCall = function () { |
| - if (actionTaken) { |
| - throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN); |
| - } |
| - actionTaken = true; |
| - }; |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| + showWarningMessage(); |
| + }; |
| - var window = { |
| - attach: function(webview) { |
| - validateCall(); |
| - if (!webview) |
| - throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); |
| - // Attach happens asynchronously to give the tagWatcher an opportunity |
| - // to pick up the new webview before attach operates on it, if it hasn't |
| - // been attached to the DOM already. |
| - // Note: Any subsequent errors cannot be exceptions because they happen |
| - // asynchronously. |
| - setTimeout(function() { |
| - var attached = |
| - browserPluginNode['-internal-attachWindowTo'](webview, |
| - detail.windowId); |
| - if (!attached) { |
| - console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); |
| - } |
| - // If the object being passed into attach is not a valid <webview> |
| - // then we will fail and it will be treated as if the new window |
| - // was rejected. The permission API plumbing is used here to clean |
| - // up the state created for the new window if attaching fails. |
| - browserPluginNode['-internal-setPermission'](requestId, attached, ''); |
| - }, 0); |
| - }, |
| - discard: function() { |
| - validateCall(); |
| - browserPluginNode['-internal-setPermission'](requestId, false, ''); |
| - } |
| - }; |
| - evt.window = window; |
| - var defaultPrevented = !node.dispatchEvent(evt); |
| + var validateCall = function () { |
| if (actionTaken) { |
| - return; |
| + throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN); |
| } |
| + actionTaken = true; |
| + }; |
| - if (defaultPrevented) { |
| - // Make browser plugin track lifetime of |window|. |
| - var onTrackedObjectGoneWithRequestId = |
| - $Function.bind(onTrackedObjectGone, self, requestId); |
| - browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| - onTrackedObjectGoneWithRequestId); |
| - browserPluginNode['-internal-trackObjectLifetime'](window, requestId); |
| - } else { |
| - actionTaken = true; |
| - // The default action is to discard the window. |
| - browserPluginNode['-internal-setPermission'](requestId, false, ''); |
| - showWarningMessage(); |
| + var window = { |
| + attach: function(webview) { |
| + validateCall(); |
| + if (!webview) |
| + throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); |
| + // Attach happens asynchronously to give the tagWatcher an opportunity |
| + // to pick up the new webview before attach operates on it, if it hasn't |
| + // been attached to the DOM already. |
| + // Note: Any subsequent errors cannot be exceptions because they happen |
| + // asynchronously. |
| + setTimeout(function() { |
| + var attached = |
| + browserPluginNode['-internal-attachWindowTo'](webview, |
| + event.windowId); |
| + if (!attached) { |
| + console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); |
| + } |
| + // If the object being passed into attach is not a valid <webview> |
| + // then we will fail and it will be treated as if the new window |
| + // was rejected. The permission API plumbing is used here to clean |
| + // up the state created for the new window if attaching fails. |
| + chrome.webview.setPermission(self.instanceId_, requestId, attached, ''); |
| + }, 0); |
| + }, |
| + discard: function() { |
| + validateCall(); |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| } |
| + }; |
| + webviewEvent.window = window; |
| - }); |
| + var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); |
| + if (actionTaken) { |
| + return; |
| + } |
| + |
| + if (defaultPrevented) { |
| + // Make browser plugin track lifetime of |window|. |
| + var onTrackedObjectGoneWithRequestId = |
| + $Function.bind(onTrackedObjectGone, self, requestId); |
| + browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| + onTrackedObjectGoneWithRequestId); |
| + browserPluginNode['-internal-trackObjectLifetime'](window, requestId); |
| + } else { |
| + actionTaken = true; |
| + // The default action is to discard the window. |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| + showWarningMessage(); |
| + } |
| }; |
| /** |
| @@ -539,10 +557,13 @@ WebView.prototype.setupExecuteCodeAPI_ = function() { |
| }; |
| /** |
| - * @param {!Object} detail The event details, originated from <object>. |
| * @private |
| */ |
| -WebView.prototype.setupPermissionEvent_ = function() { |
| +WebView.prototype.getPermissionTypes_ = function() { |
| + return ['media', 'geolocation', 'pointerLock', 'download']; |
| +}; |
| + |
| +WebView.prototype.setupExtPermissionEvent_ = function(event, webviewEvent) { |
| var ERROR_MSG_PERMISSION_ALREADY_DECIDED = '<webview>: ' + |
| 'Permission has already been decided for this "permissionrequest" event.'; |
| @@ -552,89 +573,68 @@ WebView.prototype.setupPermissionEvent_ = function() { |
| console.warn(WARNING_MSG_PERMISSION_DENIED.replace('%1', permission)); |
| }; |
| - var PERMISSION_TYPES = ['media', 'geolocation', 'pointerLock', 'download']; |
| - |
| - var EXPOSED_PERMISSION_EVENT_ATTRIBS = [ |
| - 'lastUnlockedBySelf', |
| - 'permission', |
| - 'requestMethod', |
| - 'url', |
| - 'userGesture' |
| - ]; |
| + var PERMISSION_TYPES = this.getPermissionTypes_(); |
| var self = this; |
| - var node = this.webviewNode_; |
| var browserPluginNode = this.browserPluginNode_; |
| - var internalevent = '-internal-permissionrequest'; |
| + var webviewNode = this.webviewNode_; |
| + |
| + var requestId = event.requestId; |
| + var decisionMade = false; |
| var onTrackedObjectGone = function(requestId, permission, e) { |
| var detail = e.detail ? JSON.parse(e.detail) : {}; |
| - if (detail.id != requestId) |
| + if (detail.id != requestId) { |
| return; |
| - // If the request was pending then show a warning indiciating that the |
| - // permission was denied. |
| - if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { |
| - showWarningMessage(permission); |
| } |
| - }; |
| - |
| - browserPluginNode.addEventListener(internalevent, function(e) { |
| - var evt = new Event('permissionrequest', {bubbles: true, cancelable: true}); |
| - var detail = e.detail ? JSON.parse(e.detail) : {}; |
| - $Array.forEach(EXPOSED_PERMISSION_EVENT_ATTRIBS, function(attribName) { |
| - if (detail[attribName] !== undefined) |
| - evt[attribName] = detail[attribName]; |
| - }); |
| - var requestId = detail.requestId; |
| - if (detail.requestId == undefined || |
| - PERMISSION_TYPES.indexOf(detail.permission) < 0) { |
| + // Avoid showing a warning message if the decision has already been made. |
| + if (decisionMade) { |
| return; |
| } |
| - // TODO(lazyboy): Also fill in evt.details (see webview specs). |
| - // http://crbug.com/141197. |
| - var decisionMade = false; |
| - |
| - var validateCall = function() { |
| - if (decisionMade) { |
| - throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED); |
| - } |
| - decisionMade = true; |
| - }; |
| - |
| - // Construct the event.request object. |
| - var request = { |
| - allow: function() { |
| - validateCall(); |
| - browserPluginNode['-internal-setPermission'](requestId, true, ''); |
| - }, |
| - deny: function() { |
| - validateCall(); |
| - browserPluginNode['-internal-setPermission'](requestId, false, ''); |
| - } |
| - }; |
| - evt.request = request; |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| + showWarningMessage(permission); |
| + }; |
| - var defaultPrevented = !node.dispatchEvent(evt); |
| + var validateCall = function() { |
| if (decisionMade) { |
| - return; |
| + throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED); |
| } |
| + decisionMade = true; |
| + }; |
| - if (defaultPrevented) { |
| - // Make browser plugin track lifetime of |request|. |
| - var onTrackedObjectGoneWithRequestId = |
| - $Function.bind( |
| - onTrackedObjectGone, self, requestId, detail.permission); |
| - browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| - onTrackedObjectGoneWithRequestId); |
| - browserPluginNode['-internal-trackObjectLifetime'](request, requestId); |
| - } else { |
| - decisionMade = true; |
| - browserPluginNode['-internal-setPermission'](requestId, false, ''); |
| - showWarningMessage(detail.permission); |
| + // Construct the event.request object. |
| + var request = { |
| + allow: function() { |
| + validateCall(); |
| + chrome.webview.setPermission(self.instanceId_, requestId, true, ''); |
| + }, |
| + deny: function() { |
| + validateCall(); |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| } |
| - }); |
| + }; |
| + webviewEvent.request = request; |
| + |
| + var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); |
| + if (decisionMade) { |
| + return; |
| + } |
| + |
| + if (defaultPrevented) { |
| + // Make browser plugin track lifetime of |request|. |
| + var onTrackedObjectGoneWithRequestId = |
| + $Function.bind( |
| + onTrackedObjectGone, self, requestId, event.permission); |
| + browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| + onTrackedObjectGoneWithRequestId); |
| + browserPluginNode['-internal-trackObjectLifetime'](request, requestId); |
| + } else { |
| + decisionMade = true; |
| + chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| + showWarningMessage(event.permission); |
| + } |
| }; |
| /** |
| @@ -643,4 +643,10 @@ WebView.prototype.setupPermissionEvent_ = function() { |
| */ |
| WebView.prototype.maybeSetupExperimentalAPI_ = function() {}; |
| +/** |
| + * Implemented when the experimental API is available. |
| + * @private |
| + */ |
| +WebView.prototype.maybeSetupExtDialogEvent_ = function() {}; |
| + |
| exports.WebView = WebView; |