Add the ability to code generated prepopulated static nested structs
[chromium-blink-merge.git] / extensions / renderer / resources / guest_view / web_view / web_view_action_requests.js
blobc3cc28e4a1f5300aa9caa95e7c424d9eb1f6c617
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // This module implements helper objects for the dialog, newwindow, and
6 // permissionrequest <webview> events.
8 var MessagingNatives = requireNative('messaging_natives');
9 var WebViewConstants = require('webViewConstants').WebViewConstants;
10 var WebViewInternal = require('webViewInternal').WebViewInternal;
12 var PERMISSION_TYPES = ['media',
13                         'geolocation',
14                         'pointerLock',
15                         'download',
16                         'loadplugin',
17                         'filesystem',
18                         'fullscreen'];
20 // -----------------------------------------------------------------------------
21 // WebViewActionRequest object.
23 // Default partial implementation of a webview action request.
24 function WebViewActionRequest(webViewImpl, event, webViewEvent, interfaceName) {
25   this.webViewImpl = webViewImpl;
26   this.event = event;
27   this.webViewEvent = webViewEvent;
28   this.interfaceName = interfaceName;
29   this.guestInstanceId = this.webViewImpl.guest.getId();
30   this.requestId = event.requestId;
31   this.actionTaken = false;
33   // Add on the request information specific to the request type.
34   for (var infoName in this.event.requestInfo) {
35     this.event[infoName] = this.event.requestInfo[infoName];
36     this.webViewEvent[infoName] = this.event.requestInfo[infoName];
37   }
40 // Performs the default action for the request.
41 WebViewActionRequest.prototype.defaultAction = function() {
42   // Do nothing if the action has already been taken or the requester is
43   // already gone (in which case its guestInstanceId will be stale).
44   if (this.actionTaken ||
45       this.guestInstanceId != this.webViewImpl.guest.getId()) {
46     return;
47   }
49   this.actionTaken = true;
50   WebViewInternal.setPermission(this.guestInstanceId, this.requestId,
51                                 'default', '', function(allowed) {
52     if (allowed) {
53       return;
54     }
55     this.showWarningMessage();
56   }.bind(this));
59 // Called to handle the action request's event.
60 WebViewActionRequest.prototype.handleActionRequestEvent = function() {
61   // Construct the interface object and attach it to |webViewEvent|.
62   var request = this.getInterfaceObject();
63   this.webViewEvent[this.interfaceName] = request;
65   var defaultPrevented = !this.webViewImpl.dispatchEvent(this.webViewEvent);
66   // Set |webViewEvent| to null to break the circular reference to |request| so
67   // that the garbage collector can eventually collect it.
68   this.webViewEvent = null;
69   if (this.actionTaken) {
70     return;
71   }
73   if (defaultPrevented) {
74     // Track the lifetime of |request| with the garbage collector.
75     var portId = -1;  // (hack) there is no Extension Port to release
76     MessagingNatives.BindToGC(request, this.defaultAction.bind(this), portId);
77   } else {
78     this.defaultAction();
79   }
82 // Displays a warning message when an action request is blocked by default.
83 WebViewActionRequest.prototype.showWarningMessage = function() {
84   window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED);
87 // This function ensures that each action is taken at most once.
88 WebViewActionRequest.prototype.validateCall = function() {
89   if (this.actionTaken) {
90     throw new Error(this.ERROR_MSG_ACTION_ALREADY_TAKEN);
91   }
92   this.actionTaken = true;
95 // The following are implemented by the specific action request.
97 // Returns the interface object for this action request.
98 WebViewActionRequest.prototype.getInterfaceObject = undefined;
100 // Error/warning messages.
101 WebViewActionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = undefined;
102 WebViewActionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED = undefined;
104 // -----------------------------------------------------------------------------
105 // Dialog object.
107 // Represents a dialog box request (e.g. alert()).
108 function Dialog(webViewImpl, event, webViewEvent) {
109   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'dialog');
111   this.handleActionRequestEvent();
114 Dialog.prototype.__proto__ = WebViewActionRequest.prototype;
116 Dialog.prototype.getInterfaceObject = function() {
117   return {
118     ok: function(user_input) {
119       this.validateCall();
120       user_input = user_input || '';
121       WebViewInternal.setPermission(
122           this.guestInstanceId, this.requestId, 'allow', user_input);
123     }.bind(this),
124     cancel: function() {
125       this.validateCall();
126       WebViewInternal.setPermission(
127           this.guestInstanceId, this.requestId, 'deny');
128     }.bind(this)
129   };
132 Dialog.prototype.showWarningMessage = function() {
133   var VOWELS = ['a', 'e', 'i', 'o', 'u'];
134   var dialogType = this.event.messageType;
135   var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A';
136   this.WARNING_MSG_REQUEST_BLOCKED = this.WARNING_MSG_REQUEST_BLOCKED.
137       replace('%1', article).replace('%2', dialogType);
138   window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED);
141 Dialog.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
142     WebViewConstants.ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN;
143 Dialog.prototype.WARNING_MSG_REQUEST_BLOCKED =
144     WebViewConstants.WARNING_MSG_DIALOG_REQUEST_BLOCKED;
146 // -----------------------------------------------------------------------------
147 // NewWindow object.
149 // Represents a new window request.
150 function NewWindow(webViewImpl, event, webViewEvent) {
151   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'window');
153   this.handleActionRequestEvent();
156 NewWindow.prototype.__proto__ = WebViewActionRequest.prototype;
158 NewWindow.prototype.getInterfaceObject = function() {
159   return {
160     attach: function(webview) {
161       this.validateCall();
162       if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') {
163         throw new Error(ERROR_MSG_WEBVIEW_EXPECTED);
164       }
166       var webViewImpl = privates(webview).internal;
167       // Update the partition.
168       if (this.event.partition) {
169         webViewImpl.onAttach(this.event.partition);
170       }
172       var attached = webViewImpl.attachWindow$(this.event.windowId);
173       if (!attached) {
174         window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH);
175       }
177       if (this.guestInstanceId != this.webViewImpl.guest.getId()) {
178         // If the opener is already gone, then its guestInstanceId will be
179         // stale.
180         return;
181       }
183       // If the object being passed into attach is not a valid <webview>
184       // then we will fail and it will be treated as if the new window
185       // was rejected. The permission API plumbing is used here to clean
186       // up the state created for the new window if attaching fails.
187       WebViewInternal.setPermission(this.guestInstanceId, this.requestId,
188                                     attached ? 'allow' : 'deny');
189     }.bind(this),
190     discard: function() {
191       this.validateCall();
192       if (!this.guestInstanceId) {
193         // If the opener is already gone, then we won't have its
194         // guestInstanceId.
195         return;
196       }
197       WebViewInternal.setPermission(
198           this.guestInstanceId, this.requestId, 'deny');
199     }.bind(this)
200   };
203 NewWindow.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
204     WebViewConstants.ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN;
205 NewWindow.prototype.WARNING_MSG_REQUEST_BLOCKED =
206     WebViewConstants.WARNING_MSG_NEWWINDOW_REQUEST_BLOCKED;
208 // -----------------------------------------------------------------------------
209 // PermissionRequest object.
211 // Represents a permission request (e.g. to access the filesystem).
212 function PermissionRequest(webViewImpl, event, webViewEvent) {
213   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'request');
215   if (!this.validPermissionCheck()) {
216     return;
217   }
219   this.handleActionRequestEvent();
222 PermissionRequest.prototype.__proto__ = WebViewActionRequest.prototype;
224 PermissionRequest.prototype.allow = function() {
225   this.validateCall();
226   WebViewInternal.setPermission(this.guestInstanceId, this.requestId, 'allow');
229 PermissionRequest.prototype.deny = function() {
230   this.validateCall();
231   WebViewInternal.setPermission(this.guestInstanceId, this.requestId, 'deny');
234 PermissionRequest.prototype.getInterfaceObject = function() {
235   var request = {
236     allow: this.allow.bind(this),
237     deny: this.deny.bind(this)
238   };
240   // Add on the request information specific to the request type.
241   for (var infoName in this.event.requestInfo) {
242     request[infoName] = this.event.requestInfo[infoName];
243   }
245   return $Object.freeze(request);
248 PermissionRequest.prototype.showWarningMessage = function() {
249   window.console.warn(
250       this.WARNING_MSG_REQUEST_BLOCKED.replace('%1', this.event.permission));
253 // Checks that the requested permission is valid. Returns true if valid.
254 PermissionRequest.prototype.validPermissionCheck = function() {
255   if (PERMISSION_TYPES.indexOf(this.event.permission) < 0) {
256     // The permission type is not allowed. Trigger the default response.
257     this.defaultAction();
258     return false;
259   }
260   return true;
263 PermissionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
264     WebViewConstants.ERROR_MSG_PERMISSION_ACTION_ALREADY_TAKEN;
265 PermissionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED =
266     WebViewConstants.WARNING_MSG_PERMISSION_REQUEST_BLOCKED;
268 // -----------------------------------------------------------------------------
270 // FullscreenPermissionRequest object.
272 // Represents a fullscreen permission request.
273 function FullscreenPermissionRequest(webViewImpl, event, webViewEvent) {
274   PermissionRequest.call(this, webViewImpl, event, webViewEvent);
277 FullscreenPermissionRequest.prototype.__proto__ = PermissionRequest.prototype;
279 FullscreenPermissionRequest.prototype.allow = function() {
280   PermissionRequest.prototype.allow.call(this);
281   // Now make the <webview> element go fullscreen.
282   this.webViewImpl.makeElementFullscreen();
285 // -----------------------------------------------------------------------------
287 var WebViewActionRequests = {
288   WebViewActionRequest: WebViewActionRequest,
289   Dialog: Dialog,
290   NewWindow: NewWindow,
291   PermissionRequest: PermissionRequest,
292   FullscreenPermissionRequest: FullscreenPermissionRequest
295 // Exports.
296 exports.WebViewActionRequests = WebViewActionRequests;