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.
8 // <webview> Chrome Experimental API is only available on canary and dev
11 var ChromeWebView
= require('chromeWebViewInternal').ChromeWebView
;
12 var ChromeWebViewSchema
=
13 requireNative('schema_registry').GetSchema('chromeWebViewInternal');
14 var ContextMenusSchema
=
15 requireNative('schema_registry').GetSchema('contextMenus');
16 var CreateEvent
= require('webViewEvents').CreateEvent
;
17 var EventBindings
= require('event_bindings');
18 var idGeneratorNatives
= requireNative('id_generator');
19 var MessagingNatives
= requireNative('messaging_natives');
20 var utils
= require('utils');
21 var WebViewImpl
= require('webView').WebViewImpl
;
23 function GetUniqueSubEventName(eventName
) {
24 return eventName
+ '/' + idGeneratorNatives
.GetNextId();
27 // This is the only "webViewInternal.onClicked" named event for this renderer.
29 // Since we need an event per <webview>, we define events with suffix
30 // (subEventName) in each of the <webview>. Behind the scenes, this event is
31 // registered as a ContextMenusEvent, with filter set to the webview's
32 // |viewInstanceId|. Any time a ContextMenusEvent is dispatched, we re-dispatch
33 // it to the subEvent's listeners. This way
34 // <webview>.contextMenus.onClicked behave as a regular chrome Event type.
35 var ContextMenusEvent
= CreateEvent('chromeWebViewInternal.onClicked');
38 * This event is exposed as <webview>.contextMenus.onClicked.
42 function ContextMenusOnClickedEvent(opt_eventName
,
45 opt_webViewInstanceId
) {
46 var subEventName
= GetUniqueSubEventName(opt_eventName
);
47 EventBindings
.Event
.call(this,
51 opt_webViewInstanceId
);
53 // TODO(lazyboy): When do we dispose this listener?
54 ContextMenusEvent
.addListener(function() {
55 // Re-dispatch to subEvent's listeners.
56 $Function
.apply(this.dispatch
, this, $Array
.slice(arguments
));
57 }.bind(this), {instanceId
: opt_webViewInstanceId
|| 0});
60 ContextMenusOnClickedEvent
.prototype = {
61 __proto__
: EventBindings
.Event
.prototype
65 * An instance of this class is exposed as <webview>.contextMenus.
68 function WebViewContextMenusImpl(viewInstanceId
) {
69 this.viewInstanceId_
= viewInstanceId
;
72 WebViewContextMenusImpl
.prototype.create = function() {
73 var args
= $Array
.concat([this.viewInstanceId_
], $Array
.slice(arguments
));
74 return $Function
.apply(ChromeWebView
.contextMenusCreate
, null, args
);
77 WebViewContextMenusImpl
.prototype.remove = function() {
78 var args
= $Array
.concat([this.viewInstanceId_
], $Array
.slice(arguments
));
79 return $Function
.apply(ChromeWebView
.contextMenusRemove
, null, args
);
82 WebViewContextMenusImpl
.prototype.removeAll = function() {
83 var args
= $Array
.concat([this.viewInstanceId_
], $Array
.slice(arguments
));
84 return $Function
.apply(ChromeWebView
.contextMenusRemoveAll
, null, args
);
87 WebViewContextMenusImpl
.prototype.update = function() {
88 var args
= $Array
.concat([this.viewInstanceId_
], $Array
.slice(arguments
));
89 return $Function
.apply(ChromeWebView
.contextMenusUpdate
, null, args
);
92 var WebViewContextMenus
= utils
.expose(
93 'WebViewContextMenus', WebViewContextMenusImpl
,
94 { functions
: ['create', 'remove', 'removeAll', 'update'] });
97 WebViewImpl
.prototype.maybeHandleContextMenu = function(e
, webViewEvent
) {
98 var requestId
= e
.requestId
;
99 // Construct the event.menu object.
100 var actionTaken
= false;
101 var validateCall = function() {
102 var ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN
= '<webview>: ' +
103 'An action has already been taken for this "contextmenu" event.';
106 throw new Error(ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN
);
111 show: function(items
) {
113 // TODO(lazyboy): WebViewShowContextFunction doesn't do anything useful
114 // with |items|, implement.
115 ChromeWebView
.showContextMenu(this.guestInstanceId
, requestId
, items
);
118 webViewEvent
.menu
= menu
;
119 var webviewNode
= this.webviewNode
;
120 var defaultPrevented
= !webviewNode
.dispatchEvent(webViewEvent
);
124 if (!defaultPrevented
) {
126 // The default action is equivalent to just showing the context menu as is.
127 ChromeWebView
.showContextMenu(this.guestInstanceId
, requestId
, undefined);
129 // TODO(lazyboy): Figure out a way to show warning message only when
130 // listeners are registered for this event.
131 } // else we will ignore showing the context menu completely.
135 WebViewImpl
.prototype.setupExperimentalContextMenus = function() {
136 var createContextMenus = function() {
138 if (this.contextMenus_
) {
139 return this.contextMenus_
;
142 this.contextMenus_
= new WebViewContextMenus(this.viewInstanceId
);
144 // Define 'onClicked' event property on |this.contextMenus_|.
145 var getOnClickedEvent = function() {
147 if (!this.contextMenusOnClickedEvent_
) {
148 var eventName
= 'chromeWebViewInternal.onClicked';
149 // TODO(lazyboy): Find event by name instead of events[0].
150 var eventSchema
= ChromeWebViewSchema
.events
[0];
151 var eventOptions
= {supportsListeners
: true};
152 var onClickedEvent
= new ContextMenusOnClickedEvent(
153 eventName
, eventSchema
, eventOptions
, this.viewInstanceId
);
154 this.contextMenusOnClickedEvent_
= onClickedEvent
;
155 return onClickedEvent
;
157 return this.contextMenusOnClickedEvent_
;
160 Object
.defineProperty(
163 {get: getOnClickedEvent(), enumerable
: true});
165 return this.contextMenus_
;
169 // Expose <webview>.contextMenus object.
170 Object
.defineProperty(
174 get: createContextMenus(),