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 | 18 |
19 /** | 19 /** |
20 * @private | 20 * @private |
21 */ | 21 */ |
22 WebView.prototype.maybeSetupExperimentalAPI_ = function() { | 22 WebView.prototype.maybeSetupExperimentalAPI_ = function() { |
23 this.setupWebRequestEvents_(); | 23 this.setupWebRequestEvents_(); |
24 this.setupDialogEvent_(); | |
25 }; | 24 }; |
26 | 25 |
27 /** | 26 /** |
28 * @private | 27 * @private |
29 */ | 28 */ |
30 WebView.prototype.setupWebRequestEvents_ = function() { | 29 WebView.prototype.setupWebRequestEvents_ = function() { |
31 var self = this; | 30 var self = this; |
32 // Populate the WebRequest events from the API definition. | 31 // Populate the WebRequest events from the API definition. |
33 for (var i = 0; i < webRequestSchema.events.length; ++i) { | 32 for (var i = 0; i < webRequestSchema.events.length; ++i) { |
34 Object.defineProperty(self.webviewNode_, | 33 Object.defineProperty(self.webviewNode_, |
(...skipping 13 matching lines...) Expand all Loading... |
48 }(webRequestSchema.events[i]), | 47 }(webRequestSchema.events[i]), |
49 // No setter. | 48 // No setter. |
50 enumerable: true | 49 enumerable: true |
51 }); | 50 }); |
52 } | 51 } |
53 }; | 52 }; |
54 | 53 |
55 /** | 54 /** |
56 * @private | 55 * @private |
57 */ | 56 */ |
58 WebView.prototype.setupDialogEvent_ = function() { | 57 WebView.prototype.maybeSetupExtDialogEvent_ = function(event, webviewEvent) { |
59 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + | 58 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + |
60 'An action has already been taken for this "dialog" event.'; | 59 'An action has already been taken for this "dialog" event.'; |
61 | 60 |
62 var showWarningMessage = function(dialogType) { | 61 var showWarningMessage = function(dialogType) { |
63 var VOWELS = ['a', 'e', 'i', 'o', 'u']; | 62 var VOWELS = ['a', 'e', 'i', 'o', 'u']; |
64 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; | 63 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; |
65 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; | 64 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; |
66 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); | 65 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); |
67 output = output.replace('%2', dialogType); | 66 output = output.replace('%2', dialogType); |
68 console.log(output); | 67 console.log(output); |
69 }; | 68 }; |
70 | 69 |
71 var DIALOG_EVENT_ATTRIBUTES = [ | 70 var self = this; |
72 'defaultPromptText', | 71 var browserPluginNode = this.browserPluginNode_; |
73 'messageText', | 72 var webviewNode = this.webviewNode_; |
74 'messageType', | |
75 'url' | |
76 ]; | |
77 | 73 |
78 var self = this; | 74 var requestId = event.requestId; |
79 var node = this.webviewNode_; | 75 var actionTaken = false; |
80 var browserPluginNode = this.browserPluginNode_; | |
81 | 76 |
82 var onTrackedObjectGone = function(requestId, dialogType, e) { | 77 var onTrackedObjectGone = function(requestId, dialogType, e) { |
83 var detail = e.detail ? JSON.parse(e.detail) : {}; | 78 var detail = e.detail ? JSON.parse(e.detail) : {}; |
84 if (detail.id != requestId) | 79 if (detail.id != requestId) { |
85 return; | 80 return; |
86 // If the request was pending then show a warning indiciating that a new | |
87 // window was blocked. | |
88 if (browserPluginNode['-internal-setPermission'](requestId, false, '')) { | |
89 showWarningMessage(dialogType); | |
90 } | 81 } |
91 } | |
92 | 82 |
93 browserPluginNode.addEventListener('-internal-dialog', function(e) { | 83 // Avoid showing a warning message if the decision has already been made. |
94 var evt = new Event('dialog', { bubbles: true, cancelable: true }); | |
95 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
96 | |
97 $Array.forEach(DIALOG_EVENT_ATTRIBUTES, function(attribName) { | |
98 evt[attribName] = detail[attribName]; | |
99 }); | |
100 var requestId = detail.requestId; | |
101 var actionTaken = false; | |
102 | |
103 var validateCall = function() { | |
104 if (actionTaken) { | |
105 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); | |
106 } | |
107 actionTaken = true; | |
108 }; | |
109 | |
110 var dialog = { | |
111 ok: function(user_input) { | |
112 validateCall(); | |
113 browserPluginNode['-internal-setPermission']( | |
114 requestId, true, user_input); | |
115 }, | |
116 cancel: function() { | |
117 validateCall(); | |
118 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
119 } | |
120 }; | |
121 evt.dialog = dialog; | |
122 | |
123 var defaultPrevented = !node.dispatchEvent(evt); | |
124 if (actionTaken) { | 84 if (actionTaken) { |
125 return; | 85 return; |
126 } | 86 } |
127 | 87 |
128 if (defaultPrevented) { | 88 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
129 // Tell the JavaScript garbage collector to track lifetime of |dialog| and | 89 showWarningMessage(dialogType); |
130 // call back when the dialog object has been collected. | 90 } |
131 var onTrackedObjectGoneWithRequestId = | 91 |
132 $Function.bind( | 92 var validateCall = function() { |
133 onTrackedObjectGone, self, requestId, detail.messageType); | 93 if (actionTaken) { |
134 browserPluginNode.addEventListener('-internal-trackedobjectgone', | 94 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); |
135 onTrackedObjectGoneWithRequestId); | |
136 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); | |
137 } else { | |
138 actionTaken = true; | |
139 // The default action is equivalent to canceling the dialog. | |
140 browserPluginNode['-internal-setPermission'](requestId, false, ''); | |
141 showWarningMessage(detail.messageType); | |
142 } | 95 } |
143 }); | 96 actionTaken = true; |
| 97 }; |
| 98 |
| 99 var dialog = { |
| 100 ok: function(user_input) { |
| 101 validateCall(); |
| 102 user_input = user_input || ''; |
| 103 chrome.webview.setPermission( |
| 104 self.instanceId_, requestId, true, user_input); |
| 105 }, |
| 106 cancel: function() { |
| 107 validateCall(); |
| 108 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 109 } |
| 110 }; |
| 111 webviewEvent.dialog = dialog; |
| 112 |
| 113 var defaultPrevented = !webviewNode.dispatchEvent(webviewEvent); |
| 114 if (actionTaken) { |
| 115 return; |
| 116 } |
| 117 |
| 118 if (defaultPrevented) { |
| 119 // Tell the JavaScript garbage collector to track lifetime of |dialog| and |
| 120 // call back when the dialog object has been collected. |
| 121 var onTrackedObjectGoneWithRequestId = |
| 122 $Function.bind( |
| 123 onTrackedObjectGone, self, requestId, event.messageType); |
| 124 browserPluginNode.addEventListener('-internal-trackedobjectgone', |
| 125 onTrackedObjectGoneWithRequestId); |
| 126 browserPluginNode['-internal-trackObjectLifetime'](dialog, requestId); |
| 127 } else { |
| 128 actionTaken = true; |
| 129 // The default action is equivalent to canceling the dialog. |
| 130 chrome.webview.setPermission(self.instanceId_, requestId, false, ''); |
| 131 showWarningMessage(event.messageType); |
| 132 } |
144 }; | 133 }; |
OLD | NEW |