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',
20 // -----------------------------------------------------------------------------
21 // WebViewActionRequest object.
23 // Default partial implementation of a webview action request.
24 function WebViewActionRequest(webViewImpl
, event
, webViewEvent
, interfaceName
) {
25 this.webViewImpl
= webViewImpl
;
27 this.webViewEvent
= webViewEvent
;
28 this.interfaceName
= interfaceName
;
29 this.guestInstanceId
= this.webViewImpl
.guest
.getId();
30 this.requestId
= event
.requestId
;
31 this.actionTaken
= false;
34 // Performs the default action for the request.
35 WebViewActionRequest
.prototype.defaultAction = function() {
36 // Do nothing if the action has already been taken or the requester is
37 // already gone (in which case its guestInstanceId will be stale).
38 if (this.actionTaken
||
39 this.guestInstanceId
!= this.webViewImpl
.guest
.getId()) {
43 this.actionTaken
= true;
44 WebViewInternal
.setPermission(this.guestInstanceId
, this.requestId
,
45 'default', '', function(allowed
) {
49 this.showWarningMessage();
53 // Called to handle the action request's event.
54 WebViewActionRequest
.prototype.handleActionRequestEvent = function() {
55 // Construct the interface object and attach it to |webViewEvent|.
56 var request
= this.getInterfaceObject();
57 this.webViewEvent
[this.interfaceName
] = request
;
59 var defaultPrevented
= !this.webViewImpl
.dispatchEvent(this.webViewEvent
);
60 // Set |webViewEvent| to null to break the circular reference to |request| so
61 // that the garbage collector can eventually collect it.
62 this.webViewEvent
= null;
63 if (this.actionTaken
) {
67 if (defaultPrevented
) {
68 // Track the lifetime of |request| with the garbage collector.
69 MessagingNatives
.BindToGC(request
, this.defaultAction
.bind(this));
75 // Displays a warning message when an action request is blocked by default.
76 WebViewActionRequest
.prototype.showWarningMessage = function() {
77 window
.console
.warn(this.WARNING_MSG_REQUEST_BLOCKED
);
80 // This function ensures that each action is taken at most once.
81 WebViewActionRequest
.prototype.validateCall = function() {
82 if (this.actionTaken
) {
83 throw new Error(this.ERROR_MSG_ACTION_ALREADY_TAKEN
);
85 this.actionTaken
= true;
88 // The following are implemented by the specific action request.
90 // Returns the interface object for this action request.
91 WebViewActionRequest
.prototype.getInterfaceObject
= undefined;
93 // Error/warning messages.
94 WebViewActionRequest
.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN
= undefined;
95 WebViewActionRequest
.prototype.WARNING_MSG_REQUEST_BLOCKED
= undefined;
97 // -----------------------------------------------------------------------------
100 // Represents a dialog box request (e.g. alert()).
101 function Dialog(webViewImpl
, event
, webViewEvent
) {
102 WebViewActionRequest
.call(this, webViewImpl
, event
, webViewEvent
, 'dialog');
104 this.handleActionRequestEvent();
107 Dialog
.prototype.__proto__
= WebViewActionRequest
.prototype;
109 Dialog
.prototype.getInterfaceObject = function() {
111 ok: function(user_input
) {
113 user_input
= user_input
|| '';
114 WebViewInternal
.setPermission(
115 this.guestInstanceId
, this.requestId
, 'allow', user_input
);
119 WebViewInternal
.setPermission(
120 this.guestInstanceId
, this.requestId
, 'deny');
125 Dialog
.prototype.showWarningMessage = function() {
126 var VOWELS
= ['a', 'e', 'i', 'o', 'u'];
127 var dialogType
= this.event
.messageType
;
128 var article
= (VOWELS
.indexOf(dialogType
.charAt(0)) >= 0) ? 'An' : 'A';
129 this.WARNING_MSG_REQUEST_BLOCKED
= this.WARNING_MSG_REQUEST_BLOCKED
.
130 replace('%1', article
).replace('%2', dialogType
);
131 window
.console
.warn(this.WARNING_MSG_REQUEST_BLOCKED
);
134 Dialog
.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN
=
135 WebViewConstants
.ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN
;
136 Dialog
.prototype.WARNING_MSG_REQUEST_BLOCKED
=
137 WebViewConstants
.WARNING_MSG_DIALOG_REQUEST_BLOCKED
;
139 // -----------------------------------------------------------------------------
142 // Represents a new window request.
143 function NewWindow(webViewImpl
, event
, webViewEvent
) {
144 WebViewActionRequest
.call(this, webViewImpl
, event
, webViewEvent
, 'window');
146 this.handleActionRequestEvent();
149 NewWindow
.prototype.__proto__
= WebViewActionRequest
.prototype;
151 NewWindow
.prototype.getInterfaceObject = function() {
153 attach: function(webview
) {
155 if (!webview
|| !webview
.tagName
|| webview
.tagName
!= 'WEBVIEW') {
156 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED
);
159 var webViewImpl
= privates(webview
).internal;
160 // Update the partition.
161 if (this.event
.partition
) {
162 webViewImpl
.onAttach(this.event
.partition
);
165 var attached
= webViewImpl
.attachWindow(this.event
.windowId
);
167 window
.console
.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH
);
170 if (this.guestInstanceId
!= this.webViewImpl
.guest
.getId()) {
171 // If the opener is already gone, then its guestInstanceId will be
176 // If the object being passed into attach is not a valid <webview>
177 // then we will fail and it will be treated as if the new window
178 // was rejected. The permission API plumbing is used here to clean
179 // up the state created for the new window if attaching fails.
180 WebViewInternal
.setPermission(this.guestInstanceId
, this.requestId
,
181 attached
? 'allow' : 'deny');
183 discard: function() {
185 if (!this.guestInstanceId
) {
186 // If the opener is already gone, then we won't have its
190 WebViewInternal
.setPermission(
191 this.guestInstanceId
, this.requestId
, 'deny');
196 NewWindow
.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN
=
197 WebViewConstants
.ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN
;
198 NewWindow
.prototype.WARNING_MSG_REQUEST_BLOCKED
=
199 WebViewConstants
.WARNING_MSG_NEWWINDOW_REQUEST_BLOCKED
;
201 // -----------------------------------------------------------------------------
202 // PermissionRequest object.
204 // Represents a permission request (e.g. to access the filesystem).
205 function PermissionRequest(webViewImpl
, event
, webViewEvent
) {
206 WebViewActionRequest
.call(this, webViewImpl
, event
, webViewEvent
, 'request');
208 if (!this.validPermissionCheck()) {
212 this.handleActionRequestEvent();
215 PermissionRequest
.prototype.__proto__
= WebViewActionRequest
.prototype;
217 PermissionRequest
.prototype.getInterfaceObject = function() {
221 WebViewInternal
.setPermission(
222 this.guestInstanceId
, this.requestId
, 'allow');
226 WebViewInternal
.setPermission(
227 this.guestInstanceId
, this.requestId
, 'deny');
232 PermissionRequest
.prototype.showWarningMessage = function() {
234 this.WARNING_MSG_REQUEST_BLOCKED
.replace('%1', this.event
.permission
));
237 // Checks that the requested permission is valid. Returns true if valid.
238 PermissionRequest
.prototype.validPermissionCheck = function() {
239 if (PERMISSION_TYPES
.indexOf(this.event
.permission
) < 0) {
240 // The permission type is not allowed. Trigger the default response.
241 this.defaultAction();
247 PermissionRequest
.prototype.ERROR_MSG_ACTION_ALREADY_TAKEN
=
248 WebViewConstants
.ERROR_MSG_PERMISSION_ACTION_ALREADY_TAKEN
;
249 PermissionRequest
.prototype.WARNING_MSG_REQUEST_BLOCKED
=
250 WebViewConstants
.WARNING_MSG_PERMISSION_REQUEST_BLOCKED
;
252 // -----------------------------------------------------------------------------
254 // FullscreenPermissionRequest object.
256 // Represents a fullscreen permission request.
257 function FullscreenPermissionRequest(webViewImpl
, event
, webViewEvent
) {
258 PermissionRequest
.call(this, webViewImpl
, event
, webViewEvent
);
261 FullscreenPermissionRequest
.prototype.__proto__
= PermissionRequest
.prototype;
263 FullscreenPermissionRequest
.prototype.getInterfaceObject = function() {
267 WebViewInternal
.setPermission(
268 this.guestInstanceId
, this.requestId
, 'allow');
269 // Now make the <webview> element go fullscreen.
270 this.webViewImpl
.makeElementFullscreen();
274 WebViewInternal
.setPermission(
275 this.guestInstanceId
, this.requestId
, 'deny');
280 var WebViewActionRequests
= {
281 WebViewActionRequest
: WebViewActionRequest
,
283 NewWindow
: NewWindow
,
284 PermissionRequest
: PermissionRequest
,
285 FullscreenPermissionRequest
: FullscreenPermissionRequest
289 exports
.WebViewActionRequests
= WebViewActionRequests
;