Home | History | Annotate | Download | only in extensions
      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.
      4 
      5 // This module implements chrome-specific <webview> API.
      6 
      7 var ChromeWebView = require('chromeWebViewInternal').ChromeWebView;
      8 var CreateEvent = require('webViewEvents').CreateEvent;
      9 var DeclarativeWebRequestSchema =
     10     requireNative('schema_registry').GetSchema('declarativeWebRequest');
     11 var EventBindings = require('event_bindings');
     12 var IdGenerator = requireNative('id_generator');
     13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
     14 var WebRequestSchema =
     15     requireNative('schema_registry').GetSchema('webRequest');
     16 var WebViewInternal = require('webView').WebViewInternal
     17 
     18 var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage');
     19 
     20 var CHROME_WEB_VIEW_EVENTS = {
     21   'contextmenu': {
     22     evt: CreateEvent('chromeWebViewInternal.contextmenu'),
     23     cancelable: true,
     24     customHandler: function(handler, event, webViewEvent) {
     25       handler.webViewInternal.maybeHandleContextMenu(event, webViewEvent);
     26     },
     27     fields: ['items']
     28   }
     29 };
     30 
     31 function DeclarativeWebRequestEvent(opt_eventName,
     32                                     opt_argSchemas,
     33                                     opt_eventOptions,
     34                                     opt_webViewInstanceId) {
     35   var subEventName = opt_eventName + '/' + IdGenerator.GetNextId();
     36   EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions,
     37       opt_webViewInstanceId);
     38 
     39   // TODO(lazyboy): When do we dispose this listener?
     40   WebRequestMessageEvent.addListener(function() {
     41     // Re-dispatch to subEvent's listeners.
     42     $Function.apply(this.dispatch, this, $Array.slice(arguments));
     43   }.bind(this), {instanceId: opt_webViewInstanceId || 0});
     44 }
     45 
     46 DeclarativeWebRequestEvent.prototype = {
     47   __proto__: EventBindings.Event.prototype
     48 };
     49 
     50 /**
     51  * Implemented when the ChromeWebView API is available.
     52  * @private
     53  */
     54 WebViewInternal.prototype.maybeGetChromeWebViewEvents = function() {
     55   return CHROME_WEB_VIEW_EVENTS;
     56 };
     57 
     58 /**
     59  * Calls to show contextmenu right away instead of dispatching a 'contextmenu'
     60  * event.
     61  * This will be overridden in chrome_web_view_experimental.js to implement
     62  * contextmenu  API.
     63  */
     64 WebViewInternal.prototype.maybeHandleContextMenu = function(e, webViewEvent) {
     65   var requestId = e.requestId;
     66   // Setting |params| = undefined will show the context menu unmodified, hence
     67   // the 'contextmenu' API is disabled for stable channel.
     68   var params = undefined;
     69   ChromeWebView.showContextMenu(this.guestInstanceId, requestId, params);
     70 };
     71 
     72 WebViewInternal.prototype.maybeSetupChromeWebViewEvents = function() {
     73   var request = {};
     74   var createWebRequestEvent = function(webRequestEvent) {
     75     return function() {
     76       if (!this[webRequestEvent.name]) {
     77         this[webRequestEvent.name] =
     78             new WebRequestEvent(
     79                 'webViewInternal.' + webRequestEvent.name,
     80                 webRequestEvent.parameters,
     81                 webRequestEvent.extraParameters, webRequestEvent.options,
     82                 this.viewInstanceId);
     83       }
     84       return this[webRequestEvent.name];
     85     }.bind(this);
     86   }.bind(this);
     87 
     88   var createDeclarativeWebRequestEvent = function(webRequestEvent) {
     89     return function() {
     90       if (!this[webRequestEvent.name]) {
     91         // The onMessage event gets a special event type because we want
     92         // the listener to fire only for messages targeted for this particular
     93         // <webview>.
     94         var EventClass = webRequestEvent.name === 'onMessage' ?
     95             DeclarativeWebRequestEvent : EventBindings.Event;
     96         this[webRequestEvent.name] =
     97             new EventClass(
     98                 'webViewInternal.' + webRequestEvent.name,
     99                 webRequestEvent.parameters,
    100                 webRequestEvent.options,
    101                 this.viewInstanceId);
    102       }
    103       return this[webRequestEvent.name];
    104     }.bind(this);
    105   }.bind(this);
    106 
    107   for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) {
    108     var eventSchema = DeclarativeWebRequestSchema.events[i];
    109     var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema);
    110     Object.defineProperty(
    111         request,
    112         eventSchema.name,
    113         {
    114           get: webRequestEvent,
    115           enumerable: true
    116         }
    117     );
    118   }
    119 
    120   // Populate the WebRequest events from the API definition.
    121   for (var i = 0; i < WebRequestSchema.events.length; ++i) {
    122     var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]);
    123     Object.defineProperty(
    124         request,
    125         WebRequestSchema.events[i].name,
    126         {
    127           get: webRequestEvent,
    128           enumerable: true
    129         }
    130     );
    131   }
    132 
    133   this.setRequestPropertyOnWebViewNode(request);
    134 };
    135