Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 extension to provide permission request API (and possibly other future | 5 // Shim extension to provide permission request API (and possibly other future |
| 6 // experimental APIs) for <webview> tag. | 6 // experimental APIs) for <webview> tag. |
| 7 // See web_view.js for details. | 7 // See web_view.js for details. |
| 8 // | 8 // |
| 9 // We want to control the permission API feature in <webview> separately from | 9 // We want to control the permission API feature in <webview> separately from |
| 10 // the <webview> feature itself. <webview> is available in stable channel, but | 10 // the <webview> feature itself. <webview> is available in stable channel, but |
| 11 // permission API would only be available for channels CHANNEL_DEV and | 11 // permission API would only be available for channels CHANNEL_DEV and |
| 12 // CHANNEL_CANARY. | 12 // CHANNEL_CANARY. |
| 13 | 13 |
| 14 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | 14 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; |
| 15 var webRequestSchema = | 15 var webRequestSchema = |
| 16 requireNative('schema_registry').GetSchema('webRequest'); | 16 requireNative('schema_registry').GetSchema('webRequest'); |
| 17 var WebView = require('webView').WebView; | 17 var WebView = require('webView').WebView; |
| 18 var createEvent = require('webView').CreateEvent; | |
|
lazyboy
2013/08/08 19:58:01
nit: can sort these.
Fady Samuel
2013/08/08 20:13:45
Done.
| |
| 19 | |
| 20 var WEB_VIEW_EXPERIMENTAL_EXT_EVENTS = { | |
| 21 'dialog': { | |
| 22 cancelable: true, | |
| 23 customHandler: function(webview, event, webviewEvent) { | |
| 24 webview.maybeSetupExtDialogEvent_(event, webviewEvent); | |
| 25 }, | |
| 26 evt: createEvent('webview.onDialog'), | |
| 27 fields: ['defaultPromptText', 'messageText', 'messageType', 'url'] | |
| 28 } | |
| 29 }; | |
| 18 | 30 |
| 19 /** | 31 /** |
| 20 * @private | 32 * @private |
| 21 */ | 33 */ |
| 22 WebView.prototype.maybeSetupExperimentalAPI_ = function() { | 34 WebView.prototype.maybeSetupExperimentalAPI_ = function() { |
| 23 this.setupWebRequestEvents_(); | 35 this.setupWebRequestEvents_(); |
| 24 this.setupDialogEvent_(); | |
| 25 }; | 36 }; |
| 26 | 37 |
| 27 /** | 38 /** |
| 28 * @private | 39 * @private |
| 29 */ | 40 */ |
| 30 WebView.prototype.setupWebRequestEvents_ = function() { | 41 WebView.prototype.setupWebRequestEvents_ = function() { |
| 31 var self = this; | 42 var self = this; |
| 32 var request = {}; | 43 var request = {}; |
| 33 var createWebRequestEvent = function(webRequestEvent) { | 44 var createWebRequestEvent = function(webRequestEvent) { |
| 34 return function() { | 45 return function() { |
| 35 if (!self[webRequestEvent.name + '_']) { | 46 if (!self[webRequestEvent.name + '_']) { |
| 36 self[webRequestEvent.name + '_'] = | 47 self[webRequestEvent.name + '_'] = |
| 37 new WebRequestEvent( | 48 new WebRequestEvent( |
| 38 'webview.' + webRequestEvent.name, | 49 'webview.' + webRequestEvent.name, |
| 39 webRequestEvent.parameters, | 50 webRequestEvent.parameters, |
| 40 webRequestEvent.extraParameters, null, | 51 webRequestEvent.extraParameters, null, |
| 41 self.viewInstanceId_); | 52 self.viewInstanceId_); |
| 42 } | 53 } |
| 43 return self[webRequestEvent.name + '_']; | 54 return self[webRequestEvent.name + '_']; |
| 44 } | 55 }; |
| 45 }; | 56 }; |
| 46 | 57 |
| 47 // Populate the WebRequest events from the API definition. | 58 // Populate the WebRequest events from the API definition. |
| 48 for (var i = 0; i < webRequestSchema.events.length; ++i) { | 59 for (var i = 0; i < webRequestSchema.events.length; ++i) { |
| 49 var webRequestEvent = createWebRequestEvent(webRequestSchema.events[i]); | 60 var webRequestEvent = createWebRequestEvent(webRequestSchema.events[i]); |
| 50 Object.defineProperty( | 61 Object.defineProperty( |
| 51 request, | 62 request, |
| 52 webRequestSchema.events[i].name, | 63 webRequestSchema.events[i].name, |
| 53 { | 64 { |
| 54 get: webRequestEvent, | 65 get: webRequestEvent, |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 74 configurable: false, | 85 configurable: false, |
| 75 enumerable: true, | 86 enumerable: true, |
| 76 writable: false | 87 writable: false |
| 77 } | 88 } |
| 78 ); | 89 ); |
| 79 }; | 90 }; |
| 80 | 91 |
| 81 /** | 92 /** |
| 82 * @private | 93 * @private |
| 83 */ | 94 */ |
| 84 WebView.prototype.setupDialogEvent_ = function() { | 95 WebView.prototype.maybeSetupExtDialogEvent_ = function(event, webviewEvent) { |
| 85 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + | 96 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + |
| 86 'An action has already been taken for this "dialog" event.'; | 97 'An action has already been taken for this "dialog" event.'; |
| 87 | 98 |
| 88 var showWarningMessage = function(dialogType) { | 99 var showWarningMessage = function(dialogType) { |
| 89 var VOWELS = ['a', 'e', 'i', 'o', 'u']; | 100 var VOWELS = ['a', 'e', 'i', 'o', 'u']; |
| 90 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; | 101 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; |
| 91 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; | 102 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; |
| 92 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); | 103 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); |
| 93 output = output.replace('%2', dialogType); | 104 output = output.replace('%2', dialogType); |
| 94 console.log(output); | 105 console.log(output); |
| 95 }; | 106 }; |
| 96 | 107 |
| 97 var DIALOG_EVENT_ATTRIBUTES = [ | 108 var self = this; |
| 98 'defaultPromptText', | 109 var browserPluginNode = this.browserPluginNode_; |
| 99 'messageText', | 110 var webviewNode = this.webviewNode_; |
| 100 'messageType', | |
| 101 'url' | |
| 102 ]; | |
| 103 | 111 |
| 104 var self = this; | 112 var requestId = event.requestId; |
| 105 var node = this.webviewNode_; | 113 var actionTaken = false; |
| 106 var browserPluginNode = this.browserPluginNode_; | |
| 107 | 114 |
| 108 var onTrackedObjectGone = function(requestId, dialogType, e) { | 115 var onTrackedObjectGone = function(requestId, dialogType, e) { |
| 109 var detail = e.detail ? JSON.parse(e.detail) : {}; | 116 var detail = e.detail ? JSON.parse(e.detail) : {}; |
| 110 if (detail.id != requestId) | 117 if (detail.id != requestId) { |
| 111 return; | 118 return; |
| 112 // If the request was pending then show a warning indiciating that a new | |
| 113 // window was blocked. | |
| 114 if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { | |
| 115 showWarningMessage(dialogType); | |
| 116 } | 119 } |
| 117 } | |
| 118 | 120 |
| 119 browserPluginNode.addEventListener('-internal-dialog', function(e) { | 121 // Avoid showing a warning message if the decision has already been made. |
| 120 var evt = new Event('dialog', { bubbles: true, cancelable: true }); | |
| 121 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
| 122 | |
| 123 $Array.forEach(DIALOG_EVENT_ATTRIBUTES, function(attribName) { | |
| 124 evt[attribName] = detail[attribName]; | |
| 125 }); | |
| 126 var requestId = detail.requestId; | |
| 127 var actionTaken = false; | |
| 128 | |
| 129 var validateCall = function() { | |
| 130 if (actionTaken) { | |
| 131 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); | |
| 132 } | |
| 133 actionTaken = true; | |
| 134 }; | |
| 135 | |
| 136 var dialog = { | |
| 137 ok: function(user_input) { | |
| 138 validateCall(); | |
| 139 browserPluginNode['-internal-setPermission']( | |
| 140 requestId, true, user_input); | |
| 141 }, | |
| 142 cancel: function() { | |
| 143 validateCall(); | |
| 144 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 145 } | |
| 146 }; | |
| 147 evt.dialog = dialog; | |
| 148 | |
| 149 var defaultPrevented = !node.dispatchEvent(evt); | |
| 150 if (actionTaken) { | 122 if (actionTaken) { |
| 151 return; | 123 return; |
| 152 } | 124 } |
| 153 | 125 |
| 154 if (defaultPrevented) { | 126 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 155 // Tell the JavaScript garbage collector to track lifetime of |dialog| and | 127 showWarningMessage(dialogType); |
| 156 // call back when the dialog object has been collected. | 128 } |
| 157 var onTrackedObjectGoneWithRequestId = | 129 |
| 158 $Function.bind( | 130 var validateCall = function() { |
| 159 onTrackedObjectGone, self, requestId, detail.messageType); | 131 if (actionTaken) { |
| 160 browserPluginNode.addEventListener('-internal-trackedobjectgone', | 132 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); |
| 161 onTrackedObjectGoneWithRequestId); | |
| 162 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); | |
| 163 } else { | |
| 164 actionTaken = true; | |
| 165 // The default action is equivalent to canceling the dialog. | |
| 166 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
| 167 showWarningMessage(detail.messageType); | |
| 168 } | 133 } |
| 169 }); | 134 actionTaken = true; |
| 135 }; | |
| 136 | |
| 137 var dialog = { | |
| 138 ok: function(user_input) { | |
| 139 validateCall(); | |
| 140 user_input = user_input || ''; | |
| 141 chrome.webview.setPermission( | |
| 142 self.instanceId_, requestId, true, user_input); | |
| 143 }, | |
| 144 cancel: function() { | |
| 145 validateCall(); | |
| 146 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 147 } | |
| 148 }; | |
| 149 webviewEvent.dialog = dialog; | |
| 150 | |
| 151 var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); | |
| 152 if (actionTaken) { | |
| 153 return; | |
| 154 } | |
| 155 | |
| 156 if (defaultPrevented) { | |
| 157 // Tell the JavaScript garbage collector to track lifetime of |dialog| and | |
| 158 // call back when the dialog object has been collected. | |
| 159 var onTrackedObjectGoneWithRequestId = | |
| 160 $Function.bind( | |
| 161 onTrackedObjectGone, self, requestId, event.messageType); | |
| 162 browserPluginNode.addEventListener('-internal-trackedobjectgone', | |
| 163 onTrackedObjectGoneWithRequestId); | |
| 164 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); | |
| 165 } else { | |
| 166 actionTaken = true; | |
| 167 // The default action is equivalent to canceling the dialog. | |
| 168 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); | |
| 169 showWarningMessage(event.messageType); | |
| 170 } | |
| 170 }; | 171 }; |
| 172 | |
| 173 /** | |
| 174 * @private | |
| 175 */ | |
| 176 WebView.prototype.maybeGetWebviewExperimentalExtEvents_ = function() { | |
| 177 return WEB_VIEW_EXPERIMENTAL_EXT_EVENTS; | |
| 178 }; | |
| OLD | NEW |