Moving web_view.js to extensions.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / chrome_web_view_experimental.js
blob6b3961d2569fb2a7dca125d5f86bafba2cb904e4
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.
5 // This module implements experimental API for <webview>.
6 // See web_view.js for details.
7 //
8 // <webview> Chrome Experimental API is only available on canary and dev
9 // channels of Chrome.
11 var ContextMenusSchema =
12     requireNative('schema_registry').GetSchema('contextMenus');
13 var CreateEvent = require('webViewEvents').CreateEvent;
14 var EventBindings = require('event_bindings');
15 var MessagingNatives = requireNative('messaging_natives');
16 //var WebView = require('webViewInternal').WebView;
17 var ChromeWebView = require('chromeWebViewInternal').ChromeWebView;
18 var WebViewInternal = require('webView').WebViewInternal;
19 var ChromeWebViewSchema =
20     requireNative('schema_registry').GetSchema('chromeWebViewInternal');
21 var idGeneratorNatives = requireNative('id_generator');
22 var utils = require('utils');
24 function GetUniqueSubEventName(eventName) {
25   return eventName + "/" + idGeneratorNatives.GetNextId();
28 // This is the only "webViewInternal.onClicked" named event for this renderer.
30 // Since we need an event per <webview>, we define events with suffix
31 // (subEventName) in each of the <webview>. Behind the scenes, this event is
32 // registered as a ContextMenusEvent, with filter set to the webview's
33 // |viewInstanceId|. Any time a ContextMenusEvent is dispatched, we re-dispatch
34 // it to the subEvent's listeners. This way
35 // <webview>.contextMenus.onClicked behave as a regular chrome Event type.
36 var ContextMenusEvent = CreateEvent('chromeWebViewInternal.onClicked');
38 /**
39  * This event is exposed as <webview>.contextMenus.onClicked.
40  *
41  * @constructor
42  */
43 function ContextMenusOnClickedEvent(opt_eventName,
44                                     opt_argSchemas,
45                                     opt_eventOptions,
46                                     opt_webViewInstanceId) {
47   var subEventName = GetUniqueSubEventName(opt_eventName);
48   EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions,
49       opt_webViewInstanceId);
51   // TODO(lazyboy): When do we dispose this listener?
52   ContextMenusEvent.addListener(function() {
53     // Re-dispatch to subEvent's listeners.
54     $Function.apply(this.dispatch, this, $Array.slice(arguments));
55   }.bind(this), {instanceId: opt_webViewInstanceId || 0});
58 ContextMenusOnClickedEvent.prototype = {
59   __proto__: EventBindings.Event.prototype
62 /**
63  * An instance of this class is exposed as <webview>.contextMenus.
64  * @constructor
65  */
66 function WebViewContextMenusImpl(viewInstanceId) {
67   this.viewInstanceId_ = viewInstanceId;
70 WebViewContextMenusImpl.prototype.create = function() {
71   var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
72   return $Function.apply(ChromeWebView.contextMenusCreate, null, args);
75 WebViewContextMenusImpl.prototype.remove = function() {
76   var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
77   return $Function.apply(ChromeWebView.contextMenusRemove, null, args);
80 WebViewContextMenusImpl.prototype.removeAll = function() {
81   var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
82   return $Function.apply(ChromeWebView.contextMenusRemoveAll, null, args);
85 WebViewContextMenusImpl.prototype.update = function() {
86   var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
87   return $Function.apply(ChromeWebView.contextMenusUpdate, null, args);
90 var WebViewContextMenus = utils.expose(
91     'WebViewContextMenus', WebViewContextMenusImpl,
92     { functions: ['create', 'remove', 'removeAll', 'update'] });
94 /** @private */
95 WebViewInternal.prototype.maybeHandleContextMenu = function(e, webViewEvent) {
96   var requestId = e.requestId;
97   // Construct the event.menu object.
98   var actionTaken = false;
99   var validateCall = function() {
100     var ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN = '<webview>: ' +
101         'An action has already been taken for this "contextmenu" event.';
103     if (actionTaken) {
104       throw new Error(ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN);
105     }
106     actionTaken = true;
107   };
108   var menu = {
109     show: function(items) {
110       validateCall();
111       // TODO(lazyboy): WebViewShowContextFunction doesn't do anything useful
112       // with |items|, implement.
113       ChromeWebView.showContextMenu(this.guestInstanceId, requestId, items);
114     }.bind(this)
115   };
116   webViewEvent.menu = menu;
117   var webviewNode = this.webviewNode;
118   var defaultPrevented = !webviewNode.dispatchEvent(webViewEvent);
119   if (actionTaken) {
120     return;
121   }
122   if (!defaultPrevented) {
123     actionTaken = true;
124     // The default action is equivalent to just showing the context menu as is.
125     ChromeWebView.showContextMenu(this.guestInstanceId, requestId, undefined);
127     // TODO(lazyboy): Figure out a way to show warning message only when
128     // listeners are registered for this event.
129   } //  else we will ignore showing the context menu completely.
132 /** @private */
133 WebViewInternal.prototype.setupExperimentalContextMenus = function() {
134   var createContextMenus = function() {
135     return function() {
136       if (this.contextMenus_) {
137         return this.contextMenus_;
138       }
140       this.contextMenus_ = new WebViewContextMenus(this.viewInstanceId);
142       // Define 'onClicked' event property on |this.contextMenus_|.
143       var getOnClickedEvent = function() {
144         return function() {
145           if (!this.contextMenusOnClickedEvent_) {
146             var eventName = 'chromeWebViewInternal.onClicked';
147             // TODO(lazyboy): Find event by name instead of events[0].
148             var eventSchema = ChromeWebViewSchema.events[0];
149             var eventOptions = {supportsListeners: true};
150             var onClickedEvent = new ContextMenusOnClickedEvent(
151                 eventName, eventSchema, eventOptions, this.viewInstanceId);
152             this.contextMenusOnClickedEvent_ = onClickedEvent;
153             return onClickedEvent;
154           }
155           return this.contextMenusOnClickedEvent_;
156         }.bind(this);
157       }.bind(this);
158       Object.defineProperty(
159           this.contextMenus_,
160           'onClicked',
161           {get: getOnClickedEvent(), enumerable: true});
163       return this.contextMenus_;
164     }.bind(this);
165   }.bind(this);
167   // Expose <webview>.contextMenus object.
168   Object.defineProperty(
169       this.webviewNode,
170       'contextMenus',
171       {
172         get: createContextMenus(),
173         enumerable: true
174       });