web_view_experimental.js revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Shim extension to provide permission request API (and possibly other future
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// experimental APIs) for <webview> tag.
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// See web_view.js for details.
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)//
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// We want to control the permission API feature in <webview> separately from
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the <webview> feature itself. <webview> is available in stable channel, but
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// permission API would only be available for channels CHANNEL_DEV and
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// CHANNEL_CANARY.
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
14424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)var CreateEvent = require('webView').CreateEvent;
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)var MessagingNatives = requireNative('messaging_natives');
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)var WebRequestSchema =
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    requireNative('schema_registry').GetSchema('webRequest');
193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)var WebViewInternal = require('webView').WebViewInternal;
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)var WebView = require('webView').WebView;
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
22424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)var WEB_VIEW_EXPERIMENTAL_EVENTS = {
23c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  'dialog': {
24c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    cancelable: true,
25424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    customHandler: function(webViewInternal, event, webViewEvent) {
26424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      webViewInternal.handleDialogEvent_(event, webViewEvent);
27c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    },
28424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    evt: CreateEvent('webview.onDialog'),
29c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    fields: ['defaultPromptText', 'messageText', 'messageType', 'url']
30c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
31c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
32c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)/**
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * @private
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) */
363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)WebViewInternal.prototype.maybeAttachWebRequestEventToWebview_ =
373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    function(eventName, webRequestEvent) {
382385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  Object.defineProperty(
392385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      this.webviewNode_,
403551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      eventName,
412385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      {
423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        get: webRequestEvent,
433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        enumerable: true
442385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch      }
452385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch  );
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
47a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
48a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch/**
49a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch * @private
50a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch */
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)WebViewInternal.prototype.handleDialogEvent_ =
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    function(event, webViewEvent) {
53558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  var showWarningMessage = function(dialogType) {
54558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    var VOWELS = ['a', 'e', 'i', 'o', 'u'];
55558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.';
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A';
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article);
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    output = output.replace('%2', dialogType);
59c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    console.warn(output);
60558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  };
61a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
62a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var self = this;
63a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch  var browserPluginNode = this.browserPluginNode_;
64c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  var webviewNode = this.webviewNode_;
65c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
66c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  var requestId = event.requestId;
67c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  var actionTaken = false;
68a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
69c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  var validateCall = function() {
70c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' +
71c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch        'An action has already been taken for this "dialog" event.';
72a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if (actionTaken) {
74c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN);
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    }
76c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    actionTaken = true;
77c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  };
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
79c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  var dialog = {
80c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    ok: function(user_input) {
81c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      validateCall();
82c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      user_input = user_input || '';
83424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      WebView.setPermission(self.instanceId_, requestId, true, user_input);
84c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    },
85c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    cancel: function() {
86c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch      validateCall();
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      WebView.setPermission(self.instanceId_, requestId, false, '');
88a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch    }
89c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  };
90424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  webViewEvent.dialog = dialog;
91c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
92424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  var defaultPrevented = !webviewNode.dispatchEvent(webViewEvent);
93c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (actionTaken) {
94c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    return;
95c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
96c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
97c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  if (defaultPrevented) {
98c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // Tell the JavaScript garbage collector to track lifetime of |dialog| and
99c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // call back when the dialog object has been collected.
100424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    MessagingNatives.BindToGC(dialog, function() {
1013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      // Avoid showing a warning message if the decision has already been made.
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      if (actionTaken) {
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        return;
1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      }
105424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      WebView.setPermission(self.instanceId_, requestId, false, '');
1063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      showWarningMessage(event.messageType);
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    });
108c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  } else {
109c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    actionTaken = true;
110c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    // The default action is equivalent to canceling the dialog.
111424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    WebView.setPermission(self.instanceId_, requestId, false, '');
112c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch    showWarningMessage(event.messageType);
113c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch  }
114c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch};
115c2db58bd994c04d98e4ee2cd7565b71548655fe3Ben Murdoch
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/** @private */
117424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)WebViewInternal.prototype.maybeGetExperimentalEvents_ = function() {
118424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return WEB_VIEW_EXPERIMENTAL_EVENTS;
119a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch};
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/** @private */
1223551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)WebViewInternal.prototype.clearData_ = function(var_args) {
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!this.instanceId_) {
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return;
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  var args = $Array.concat([this.instanceId_], $Array.slice(arguments));
127424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  $Function.apply(WebView.clearData, null, args);
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
1293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
13068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/** @private */
13168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)WebViewInternal.prototype.getUserAgent_ = function() {
13268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return this.userAgentOverride_ || navigator.userAgent;
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
13568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/** @private */
13668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)WebViewInternal.prototype.isUserAgentOverridden_ = function() {
13768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  return !!this.userAgentOverride_ &&
13868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      this.userAgentOverride_ != navigator.userAgent;
13968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
14068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
14168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)/** @private */
14268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)WebViewInternal.prototype.setUserAgentOverride_ = function(userAgentOverride) {
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  this.userAgentOverride_ = userAgentOverride;
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  if (!this.instanceId_) {
14568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // If we are not attached yet, then we will pick up the user agent on
14668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // attachment.
14768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return;
14868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  }
14968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  WebView.overrideUserAgent(this.instanceId_, userAgentOverride);
15068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)};
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)WebViewInternal.maybeRegisterExperimentalAPIs = function(proto, secret) {
1533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  proto.clearData = function(var_args) {
1543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    var internal = this.internal_(secret);
1553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    $Function.apply(internal.clearData_, internal, arguments);
1563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  };
15768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
15868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  proto.getUserAgent = function() {
15968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return this.internal_(secret).getUserAgent_();
16068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  };
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  proto.isUserAgentOverridden = function() {
16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return this.internal_(secret).isUserAgentOverridden_();
16468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  };
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  proto.setUserAgentOverride = function(userAgentOverride) {
16768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    this.internal_(secret).setUserAgentOverride_(userAgentOverride);
16868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  };
1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
170