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 createEvent = require('webView').CreateEvent; |
14 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | 15 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; |
15 var webRequestSchema = | 16 var webRequestSchema = |
16 requireNative('schema_registry').GetSchema('webRequest'); | 17 requireNative('schema_registry').GetSchema('webRequest'); |
17 var WebView = require('webView').WebView; | 18 var WebView = require('webView').WebView; |
18 | 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 }; |
| 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() { |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 value: request, | 82 value: request, |
72 enumerable: true, | 83 enumerable: true, |
73 writable: false | 84 writable: false |
74 } | 85 } |
75 ); | 86 ); |
76 }; | 87 }; |
77 | 88 |
78 /** | 89 /** |
79 * @private | 90 * @private |
80 */ | 91 */ |
81 WebView.prototype.setupDialogEvent_ = function() { | 92 WebView.prototype.maybeSetupExtDialogEvent_ = function(event, webviewEvent) { |
82 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + | |
83 'An action has already been taken for this "dialog" event.'; | |
84 | |
85 var showWarningMessage = function(dialogType) { | 93 var showWarningMessage = function(dialogType) { |
86 var VOWELS = ['a', 'e', 'i', 'o', 'u']; | 94 var VOWELS = ['a', 'e', 'i', 'o', 'u']; |
87 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; | 95 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; |
88 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; | 96 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; |
89 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); | 97 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); |
90 output = output.replace('%2', dialogType); | 98 output = output.replace('%2', dialogType); |
91 console.log(output); | 99 console.warn(output); |
92 }; | 100 }; |
93 | 101 |
94 var DIALOG_EVENT_ATTRIBUTES = [ | 102 var self = this; |
95 'defaultPromptText', | 103 var browserPluginNode = this.browserPluginNode_; |
96 'messageText', | 104 var webviewNode = this.webviewNode_; |
97 'messageType', | |
98 'url' | |
99 ]; | |
100 | 105 |
101 var self = this; | 106 var requestId = event.requestId; |
102 var node = this.webviewNode_; | 107 var actionTaken = false; |
103 var browserPluginNode = this.browserPluginNode_; | |
104 | 108 |
105 var onTrackedObjectGone = function(requestId, dialogType, e) { | 109 var onTrackedObjectGone = function(requestId, dialogType, e) { |
106 var detail = e.detail ? JSON.parse(e.detail) : {}; | 110 var detail = e.detail ? JSON.parse(e.detail) : {}; |
107 if (detail.id != requestId) | 111 if (detail.id != requestId) { |
108 return; | 112 return; |
109 // If the request was pending then show a warning indiciating that a new | |
110 // window was blocked. | |
111 if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { | |
112 showWarningMessage(dialogType); | |
113 } | 113 } |
114 }; | |
115 | 114 |
116 browserPluginNode.addEventListener('-internal-dialog', function(e) { | 115 // Avoid showing a warning message if the decision has already been made. |
117 var evt = new Event('dialog', { bubbles: true, cancelable: true }); | |
118 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
119 | |
120 $Array.forEach(DIALOG_EVENT_ATTRIBUTES, function(attribName) { | |
121 evt[attribName] = detail[attribName]; | |
122 }); | |
123 var requestId = detail.requestId; | |
124 var actionTaken = false; | |
125 | |
126 var validateCall = function() { | |
127 if (actionTaken) { | |
128 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); | |
129 } | |
130 actionTaken = true; | |
131 }; | |
132 | |
133 var dialog = { | |
134 ok: function(user_input) { | |
135 validateCall(); | |
136 browserPluginNode['-internal-setPermission']( | |
137 requestId, true, user_input); | |
138 }, | |
139 cancel: function() { | |
140 validateCall(); | |
141 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
142 } | |
143 }; | |
144 evt.dialog = dialog; | |
145 | |
146 var defaultPrevented = !node.dispatchEvent(evt); | |
147 if (actionTaken) { | 116 if (actionTaken) { |
148 return; | 117 return; |
149 } | 118 } |
150 | 119 |
151 if (defaultPrevented) { | 120 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
152 // Tell the JavaScript garbage collector to track lifetime of |dialog| and | 121 showWarningMessage(dialogType); |
153 // call back when the dialog object has been collected. | 122 } |
154 var onTrackedObjectGoneWithRequestId = | 123 |
155 $Function.bind( | 124 var validateCall = function() { |
156 onTrackedObjectGone, self, requestId, detail.messageType); | 125 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + |
157 browserPluginNode.addEventListener('-internal-trackedobjectgone', | 126 'An action has already been taken for this "dialog" event.'; |
158 onTrackedObjectGoneWithRequestId); | 127 |
159 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); | 128 if (actionTaken) { |
160 } else { | 129 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); |
161 actionTaken = true; | |
162 // The default action is equivalent to canceling the dialog. | |
163 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
164 showWarningMessage(detail.messageType); | |
165 } | 130 } |
166 }); | 131 actionTaken = true; |
| 132 }; |
| 133 |
| 134 var dialog = { |
| 135 ok: function(user_input) { |
| 136 validateCall(); |
| 137 user_input = user_input || ''; |
| 138 chrome.webview.setPermission( |
| 139 self.instanceId_, requestId, true, user_input); |
| 140 }, |
| 141 cancel: function() { |
| 142 validateCall(); |
| 143 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 144 } |
| 145 }; |
| 146 webviewEvent.dialog = dialog; |
| 147 |
| 148 var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); |
| 149 if (actionTaken) { |
| 150 return; |
| 151 } |
| 152 |
| 153 if (defaultPrevented) { |
| 154 // Tell the JavaScript garbage collector to track lifetime of |dialog| and |
| 155 // call back when the dialog object has been collected. |
| 156 var onTrackedObjectGoneWithRequestId = |
| 157 $Function.bind( |
| 158 onTrackedObjectGone, self, requestId, event.messageType); |
| 159 browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| 160 onTrackedObjectGoneWithRequestId); |
| 161 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); |
| 162 } else { |
| 163 actionTaken = true; |
| 164 // The default action is equivalent to canceling the dialog. |
| 165 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 166 showWarningMessage(event.messageType); |
| 167 } |
167 }; | 168 }; |
| 169 |
| 170 /** |
| 171 * @private |
| 172 */ |
| 173 WebView.prototype.maybeGetWebviewExperimentalExtEvents_ = function() { |
| 174 return WEB_VIEW_EXPERIMENTAL_EXT_EVENTS; |
| 175 }; |
OLD | NEW |