Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / extensions / renderer / resources / guest_view / web_view_action_requests.js
blob21cc7b1723244282ef42c9d6650985fe9ba4a4b2
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'];
19 // -----------------------------------------------------------------------------
20 // WebViewActionRequest object.
22 // Default partial implementation of a webview action request.
23 function WebViewActionRequest(webViewImpl, event, webViewEvent, interfaceName) {
24   this.webViewImpl = webViewImpl;
25   this.event = event;
26   this.webViewEvent = webViewEvent;
27   this.interfaceName = interfaceName;
28   this.guestInstanceId = this.webViewImpl.guest.getId();
29   this.requestId = event.requestId;
30   this.actionTaken = false;
33 // Performs the default action for the request.
34 WebViewActionRequest.prototype.defaultAction = function() {
35   // Do nothing if the action has already been taken or the requester is
36   // already gone (in which case its guestInstanceId will be stale).
37   if (this.actionTaken ||
38       this.guestInstanceId != this.webViewImpl.guest.getId()) {
39     return;
40   }
42   this.actionTaken = true;
43   WebViewInternal.setPermission(this.guestInstanceId, this.requestId,
44                                 'default', '', function(allowed) {
45     if (allowed) {
46       return;
47     }
48     this.showWarningMessage();
49   }.bind(this));
52 // Called to handle the action request's event.
53 WebViewActionRequest.prototype.handleActionRequestEvent = function() {
54   // Construct the interface object and attach it to |webViewEvent|.
55   var request = this.getInterfaceObject();
56   this.webViewEvent[this.interfaceName] = request;
58   var defaultPrevented = !this.webViewImpl.dispatchEvent(this.webViewEvent);
59   // Set |webViewEvent| to null to break the circular reference to |request| so
60   // that the garbage collector can eventually collect it.
61   this.webViewEvent = null;
62   if (this.actionTaken) {
63     return;
64   }
66   if (defaultPrevented) {
67     // Track the lifetime of |request| with the garbage collector.
68     MessagingNatives.BindToGC(request, this.defaultAction.bind(this));
69   } else {
70     this.defaultAction();
71   }
74 // Displays a warning message when an action request is blocked by default.
75 WebViewActionRequest.prototype.showWarningMessage = function() {
76   window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED);
79 // This function ensures that each action is taken at most once.
80 WebViewActionRequest.prototype.validateCall = function() {
81   if (this.actionTaken) {
82     throw new Error(this.ERROR_MSG_ACTION_ALREADY_TAKEN);
83   }
84   this.actionTaken = true;
87 // The following are implemented by the specific action request.
89 // Returns the interface object for this action request.
90 WebViewActionRequest.prototype.getInterfaceObject = undefined;
92 // Error/warning messages.
93 WebViewActionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN = undefined;
94 WebViewActionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED = undefined;
96 // -----------------------------------------------------------------------------
97 // Dialog object.
99 // Represents a dialog box request (e.g. alert()).
100 function Dialog(webViewImpl, event, webViewEvent) {
101   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'dialog');
103   this.handleActionRequestEvent();
106 Dialog.prototype.__proto__ = WebViewActionRequest.prototype;
108 Dialog.prototype.getInterfaceObject = function() {
109   return {
110     ok: function(user_input) {
111       this.validateCall();
112       user_input = user_input || '';
113       WebViewInternal.setPermission(
114           this.guestInstanceId, this.requestId, 'allow', user_input);
115     }.bind(this),
116     cancel: function() {
117       this.validateCall();
118       WebViewInternal.setPermission(
119           this.guestInstanceId, this.requestId, 'deny');
120     }.bind(this)
121   };
124 Dialog.prototype.showWarningMessage = function() {
125   var VOWELS = ['a', 'e', 'i', 'o', 'u'];
126   var dialogType = this.event.messageType;
127   var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A';
128   this.WARNING_MSG_REQUEST_BLOCKED = this.WARNING_MSG_REQUEST_BLOCKED.
129       replace('%1', article).replace('%2', dialogType);
130   window.console.warn(this.WARNING_MSG_REQUEST_BLOCKED);
133 Dialog.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
134     WebViewConstants.ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN;
135 Dialog.prototype.WARNING_MSG_REQUEST_BLOCKED =
136     WebViewConstants.WARNING_MSG_DIALOG_REQUEST_BLOCKED;
138 // -----------------------------------------------------------------------------
139 // NewWindow object.
141 // Represents a new window request.
142 function NewWindow(webViewImpl, event, webViewEvent) {
143   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'window');
145   this.handleActionRequestEvent();
148 NewWindow.prototype.__proto__ = WebViewActionRequest.prototype;
150 NewWindow.prototype.getInterfaceObject = function() {
151   return {
152     attach: function(webview) {
153       this.validateCall();
154       if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') {
155         throw new Error(ERROR_MSG_WEBVIEW_EXPECTED);
156       }
158       var webViewImpl = privates(webview).internal;
159       // Update the partition.
160       if (this.event.partition) {
161         webViewImpl.onAttach(this.event.partition);
162       }
164       var attached = webViewImpl.attachWindow(this.event.windowId);
165       if (!attached) {
166         window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH);
167       }
169       if (this.guestInstanceId != this.webViewImpl.guest.getId()) {
170         // If the opener is already gone, then its guestInstanceId will be
171         // stale.
172         return;
173       }
175       // If the object being passed into attach is not a valid <webview>
176       // then we will fail and it will be treated as if the new window
177       // was rejected. The permission API plumbing is used here to clean
178       // up the state created for the new window if attaching fails.
179       WebViewInternal.setPermission(this.guestInstanceId, this.requestId,
180                                     attached ? 'allow' : 'deny');
181     }.bind(this),
182     discard: function() {
183       this.validateCall();
184       if (!this.guestInstanceId) {
185         // If the opener is already gone, then we won't have its
186         // guestInstanceId.
187         return;
188       }
189       WebViewInternal.setPermission(
190           this.guestInstanceId, this.requestId, 'deny');
191     }.bind(this)
192   };
195 NewWindow.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
196     WebViewConstants.ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN;
197 NewWindow.prototype.WARNING_MSG_REQUEST_BLOCKED =
198     WebViewConstants.WARNING_MSG_NEWWINDOW_REQUEST_BLOCKED;
200 // -----------------------------------------------------------------------------
201 // PermissionRequest object.
203 // Represents a permission request (e.g. to access the filesystem).
204 function PermissionRequest(webViewImpl, event, webViewEvent) {
205   WebViewActionRequest.call(this, webViewImpl, event, webViewEvent, 'request');
207   if (!this.validPermissionCheck()) {
208     return;
209   }
211   this.handleActionRequestEvent();
214 PermissionRequest.prototype.__proto__ = WebViewActionRequest.prototype;
216 PermissionRequest.prototype.getInterfaceObject = function() {
217   return {
218     allow: function() {
219       this.validateCall();
220       WebViewInternal.setPermission(
221           this.guestInstanceId, this.requestId, 'allow');
222     }.bind(this),
223     deny: function() {
224       this.validateCall();
225       WebViewInternal.setPermission(
226           this.guestInstanceId, this.requestId, 'deny');
227     }.bind(this)
228   };
231 PermissionRequest.prototype.showWarningMessage = function() {
232   window.console.warn(
233       this.WARNING_MSG_REQUEST_BLOCKED.replace('%1', this.event.permission));
236 // Checks that the requested permission is valid. Returns true if valid.
237 PermissionRequest.prototype.validPermissionCheck = function() {
238   if (PERMISSION_TYPES.indexOf(this.event.permission) < 0) {
239     // The permission type is not allowed. Trigger the default response.
240     this.defaultAction();
241     return false;
242   }
243   return true;
246 PermissionRequest.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN =
247     WebViewConstants.ERROR_MSG_PERMISSION_ACTION_ALREADY_TAKEN;
248 PermissionRequest.prototype.WARNING_MSG_REQUEST_BLOCKED =
249     WebViewConstants.WARNING_MSG_PERMISSION_REQUEST_BLOCKED;
251 // -----------------------------------------------------------------------------
253 var WebViewActionRequests = {
254   WebViewActionRequest: WebViewActionRequest,
255   Dialog: Dialog,
256   NewWindow: NewWindow,
257   PermissionRequest: PermissionRequest
260 exports.WebViewActionRequests = WebViewActionRequests;