- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / renderer / resources / extensions / web_view_experimental.js
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
3 // found in the LICENSE file.
4
5 // Shim extension to provide permission request API (and possibly other future
6 // experimental APIs) for <webview> tag.
7 // See web_view.js for details.
8 //
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
11 // permission API would only be available for channels CHANNEL_DEV and
12 // CHANNEL_CANARY.
13
14 var CreateEvent = require('webView').CreateEvent;
15 var MessagingNatives = requireNative('messaging_natives');
16 var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
17 var WebRequestSchema =
18     requireNative('schema_registry').GetSchema('webRequest');
19 var WebViewInternal = require('webView').WebViewInternal;
20 var WebView = require('webView').WebView;
21
22 var WEB_VIEW_EXPERIMENTAL_EVENTS = {
23   'dialog': {
24     cancelable: true,
25     customHandler: function(webViewInternal, event, webViewEvent) {
26       webViewInternal.handleDialogEvent_(event, webViewEvent);
27     },
28     evt: CreateEvent('webview.onDialog'),
29     fields: ['defaultPromptText', 'messageText', 'messageType', 'url']
30   }
31 };
32
33 /**
34  * @private
35  */
36 WebViewInternal.prototype.maybeAttachWebRequestEventToWebview_ =
37     function(eventName, webRequestEvent) {
38   Object.defineProperty(
39       this.webviewNode_,
40       eventName,
41       {
42         get: webRequestEvent,
43         enumerable: true
44       }
45   );
46 };
47
48 /**
49  * @private
50  */
51 WebViewInternal.prototype.handleDialogEvent_ =
52     function(event, webViewEvent) {
53   var showWarningMessage = function(dialogType) {
54     var VOWELS = ['a', 'e', 'i', 'o', 'u'];
55     var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.';
56     var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A';
57     var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article);
58     output = output.replace('%2', dialogType);
59     window.console.warn(output);
60   };
61
62   var self = this;
63   var browserPluginNode = this.browserPluginNode_;
64   var webviewNode = this.webviewNode_;
65
66   var requestId = event.requestId;
67   var actionTaken = false;
68
69   var validateCall = function() {
70     var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' +
71         'An action has already been taken for this "dialog" event.';
72
73     if (actionTaken) {
74       throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN);
75     }
76     actionTaken = true;
77   };
78
79   var dialog = {
80     ok: function(user_input) {
81       validateCall();
82       user_input = user_input || '';
83       WebView.setPermission(self.instanceId_, requestId, 'allow', user_input);
84     },
85     cancel: function() {
86       validateCall();
87       WebView.setPermission(self.instanceId_, requestId, 'deny');
88     }
89   };
90   webViewEvent.dialog = dialog;
91
92   var defaultPrevented = !webviewNode.dispatchEvent(webViewEvent);
93   if (actionTaken) {
94     return;
95   }
96
97   if (defaultPrevented) {
98     // Tell the JavaScript garbage collector to track lifetime of |dialog| and
99     // call back when the dialog object has been collected.
100     MessagingNatives.BindToGC(dialog, function() {
101       // Avoid showing a warning message if the decision has already been made.
102       if (actionTaken) {
103         return;
104       }
105       WebView.setPermission(
106           self.instanceId_, requestId, 'default', '', function(allowed) {
107         if (allowed) {
108           return;
109         }
110         showWarningMessage(event.messageType);
111       });
112     });
113   } else {
114     actionTaken = true;
115     // The default action is equivalent to canceling the dialog.
116     WebView.setPermission(
117         self.instanceId_, requestId, 'default', '', function(allowed) {
118       if (allowed) {
119         return;
120       }
121       showWarningMessage(event.messageType);
122     });
123   }
124 };
125
126 /** @private */
127 WebViewInternal.prototype.maybeGetExperimentalEvents_ = function() {
128   return WEB_VIEW_EXPERIMENTAL_EVENTS;
129 };
130
131 WebViewInternal.prototype.maybeGetExperimentalPermissions_ = function() {
132   return ['loadplugin'];
133 };
134
135 /** @private */
136 WebViewInternal.prototype.clearData_ = function(var_args) {
137   if (!this.instanceId_) {
138     return;
139   }
140   var args = $Array.concat([this.instanceId_], $Array.slice(arguments));
141   $Function.apply(WebView.clearData, null, args);
142 };
143
144 /** @private */
145 WebViewInternal.prototype.getUserAgent_ = function() {
146   return this.userAgentOverride_ || navigator.userAgent;
147 };
148
149 /** @private */
150 WebViewInternal.prototype.isUserAgentOverridden_ = function() {
151   return !!this.userAgentOverride_ &&
152       this.userAgentOverride_ != navigator.userAgent;
153 };
154
155 /** @private */
156 WebViewInternal.prototype.setUserAgentOverride_ = function(userAgentOverride) {
157   this.userAgentOverride_ = userAgentOverride;
158   if (!this.instanceId_) {
159     // If we are not attached yet, then we will pick up the user agent on
160     // attachment.
161     return;
162   }
163   WebView.overrideUserAgent(this.instanceId_, userAgentOverride);
164 };
165
166 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto, secret) {
167   proto.clearData = function(var_args) {
168     var internal = this.internal_(secret);
169     $Function.apply(internal.clearData_, internal, arguments);
170   };
171
172   proto.getUserAgent = function() {
173     return this.internal_(secret).getUserAgent_();
174   };
175
176   proto.isUserAgentOverridden = function() {
177     return this.internal_(secret).isUserAgentOverridden_();
178   };
179
180   proto.setUserAgentOverride = function(userAgentOverride) {
181     this.internal_(secret).setUserAgentOverride_(userAgentOverride);
182   };
183 };