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> Experimental API is only available on canary and dev channels of
11 var ContextMenusSchema =
12 requireNative('schema_registry').GetSchema('contextMenus');
13 var CreateEvent = require('webView').CreateEvent;
14 var EventBindings = require('event_bindings');
15 var MessagingNatives = requireNative('messaging_natives');
16 var WebView = require('webView').WebView;
17 var WebViewInternal = require('webView').WebViewInternal;
18 var WebViewSchema = requireNative('schema_registry').GetSchema('webview');
19 var idGeneratorNatives = requireNative('id_generator');
20 var utils = require('utils');
22 // WEB_VIEW_EXPERIMENTAL_EVENTS is a map of experimental <webview> DOM event
23 // names to their associated extension event descriptor objects.
24 // An event listener will be attached to the extension event |evt| specified in
26 // |fields| specifies the public-facing fields in the DOM event that are
27 // accessible to <webview> developers.
28 // |customHandler| allows a handler function to be called each time an extension
29 // event is caught by its event listener. The DOM event should be dispatched
30 // within this handler function. With no handler function, the DOM event
31 // will be dispatched by default each time the extension event is caught.
32 // |cancelable| (default: false) specifies whether the event's default
33 // behavior can be canceled. If the default action associated with the event
34 // is prevented, then its dispatch function will return false in its event
35 // handler. The event must have a custom handler for this to be meaningful.
36 var WEB_VIEW_EXPERIMENTAL_EVENTS = {
38 evt: CreateEvent('webview.onFindReply'),
49 evt: CreateEvent('webview.onZoomChange'),
50 fields: ['oldZoomFactor', 'newZoomFactor']
54 function GetUniqueSubEventName(eventName) {
55 return eventName + "/" + idGeneratorNatives.GetNextId();
58 // This is the only "webview.onClicked" named event for this renderer.
60 // Since we need an event per <webview>, we define events with suffix
61 // (subEventName) in each of the <webview>. Behind the scenes, this event is
62 // registered as a ContextMenusEvent, with filter set to the webview's
63 // |viewInstanceId|. Any time a ContextMenusEvent is dispatched, we re-dispatch
64 // it to the subEvent's listeners. This way
65 // <webview>.contextMenus.onClicked behave as a regular chrome Event type.
66 var ContextMenusEvent = CreateEvent('webview.onClicked');
69 * This event is exposed as <webview>.contextMenus.onClicked.
73 function ContextMenusOnClickedEvent(opt_eventName,
76 opt_webViewInstanceId) {
77 var subEventName = GetUniqueSubEventName(opt_eventName);
78 EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions,
79 opt_webViewInstanceId);
82 // TODO(lazyboy): When do we dispose this listener?
83 ContextMenusEvent.addListener(function() {
84 // Re-dispatch to subEvent's listeners.
85 $Function.apply(self.dispatch, self, $Array.slice(arguments));
86 }, {instanceId: opt_webViewInstanceId || 0});
89 ContextMenusOnClickedEvent.prototype = {
90 __proto__: EventBindings.Event.prototype
94 * An instance of this class is exposed as <webview>.contextMenus.
97 function WebViewContextMenusImpl(viewInstanceId) {
98 this.viewInstanceId_ = viewInstanceId;
101 WebViewContextMenusImpl.prototype.create = function() {
102 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
103 return $Function.apply(WebView.contextMenusCreate, null, args);
106 WebViewContextMenusImpl.prototype.remove = function() {
107 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
108 return $Function.apply(WebView.contextMenusRemove, null, args);
111 WebViewContextMenusImpl.prototype.removeAll = function() {
112 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
113 return $Function.apply(WebView.contextMenusRemoveAll, null, args);
116 WebViewContextMenusImpl.prototype.update = function() {
117 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
118 return $Function.apply(WebView.contextMenusUpdate, null, args);
121 var WebViewContextMenus = utils.expose(
122 'WebViewContextMenus', WebViewContextMenusImpl,
123 ['create', 'remove', 'removeAll', 'update']);
128 WebViewInternal.prototype.maybeAttachWebRequestEventToObject =
129 function(obj, eventName, webRequestEvent) {
130 Object.defineProperty(
134 get: webRequestEvent,
143 WebViewInternal.prototype.setZoom = function(zoomFactor) {
144 if (!this.instanceId) {
147 WebView.setZoom(this.instanceId, zoomFactor);
150 WebViewInternal.prototype.maybeGetExperimentalEvents = function() {
151 return WEB_VIEW_EXPERIMENTAL_EVENTS;
155 WebViewInternal.prototype.maybeGetExperimentalPermissions = function() {
160 WebViewInternal.prototype.maybeSetCurrentZoomFactor =
161 function(zoomFactor) {
162 this.currentZoomFactor = zoomFactor;
166 WebViewInternal.prototype.clearData = function() {
167 if (!this.instanceId) {
170 var args = $Array.concat([this.instanceId], $Array.slice(arguments));
171 $Function.apply(WebView.clearData, null, args);
175 WebViewInternal.prototype.setZoom = function(zoomFactor, callback) {
176 if (!this.instanceId) {
179 WebView.setZoom(this.instanceId, zoomFactor, callback);
182 WebViewInternal.prototype.getZoom = function(callback) {
183 if (!this.instanceId) {
186 WebView.getZoom(this.instanceId, callback);
190 WebViewInternal.prototype.captureVisibleRegion = function(spec, callback) {
191 WebView.captureVisibleRegion(this.instanceId, spec, callback);
195 WebViewInternal.prototype.find = function(search_text, options, callback) {
196 if (!this.instanceId) {
199 WebView.find(this.instanceId, search_text, options, callback);
203 WebViewInternal.prototype.stopFinding = function(action) {
204 if (!this.instanceId) {
207 WebView.stopFinding(this.instanceId, action);
210 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {
211 proto.clearData = function() {
212 var internal = privates(this).internal;
213 $Function.apply(internal.clearData, internal, arguments);
216 proto.setZoom = function(zoomFactor, callback) {
217 privates(this).internal.setZoom(zoomFactor, callback);
220 proto.getZoom = function(callback) {
221 return privates(this).internal.getZoom(callback);
224 proto.captureVisibleRegion = function(spec, callback) {
225 privates(this).internal.captureVisibleRegion(spec, callback);
228 proto.find = function(search_text, options, callback) {
229 privates(this).internal.find(search_text, options, callback);
232 proto.stopFinding = function(action) {
233 privates(this).internal.stopFinding(action);
238 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {
240 var createContextMenus = function() {
242 if (self.contextMenus_) {
243 return self.contextMenus_;
246 self.contextMenus_ = new WebViewContextMenus(self.viewInstanceId);
248 // Define 'onClicked' event property on |self.contextMenus_|.
249 var getOnClickedEvent = function() {
251 if (!self.contextMenusOnClickedEvent_) {
252 var eventName = 'webview.onClicked';
253 // TODO(lazyboy): Find event by name instead of events[0].
254 var eventSchema = WebViewSchema.events[0];
255 var eventOptions = {supportsListeners: true};
256 var onClickedEvent = new ContextMenusOnClickedEvent(
257 eventName, eventSchema, eventOptions, self.viewInstanceId);
258 self.contextMenusOnClickedEvent_ = onClickedEvent;
259 return onClickedEvent;
261 return self.contextMenusOnClickedEvent_;
264 Object.defineProperty(
267 {get: getOnClickedEvent(), enumerable: true});
269 return self.contextMenus_;
273 // Expose <webview>.contextMenus object.
274 Object.defineProperty(
278 get: createContextMenus(),