| Index: chrome/renderer/resources/extensions/web_view/chrome_web_view.js
|
| diff --git a/chrome/renderer/resources/extensions/web_view/chrome_web_view.js b/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
|
| index 14eca5be49ab88a9f1aab0dae8b64685c5cff4d4..a91a239c79133d234774fe7759f4cc421a044458 100644
|
| --- a/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
|
| +++ b/chrome/renderer/resources/extensions/web_view/chrome_web_view.js
|
| @@ -3,11 +3,17 @@
|
| // found in the LICENSE file.
|
|
|
| // This module implements chrome-specific <webview> API.
|
| +// See web_view_api_methods.js for details.
|
|
|
| var ChromeWebView = require('chromeWebViewInternal').ChromeWebView;
|
| +var ChromeWebViewSchema =
|
| + requireNative('schema_registry').GetSchema('chromeWebViewInternal');
|
| var CreateEvent = require('guestViewEvents').CreateEvent;
|
| var EventBindings = require('event_bindings');
|
| +var idGeneratorNatives = requireNative('id_generator');
|
| +var Utils = require('utils');
|
| var WebViewEvents = require('webViewEvents').WebViewEvents;
|
| +var WebViewImpl = require('webView').WebViewImpl;
|
|
|
| var CHROME_WEB_VIEW_EVENTS = {
|
| 'contextmenushown': {
|
| @@ -18,20 +24,161 @@ var CHROME_WEB_VIEW_EVENTS = {
|
| }
|
| };
|
|
|
| -/**
|
| - * Calls to show contextmenu right away instead of dispatching a 'contextmenu'
|
| - * event.
|
| - * This will be overridden in chrome_web_view_experimental.js to implement
|
| - * contextmenu API.
|
| - */
|
| -WebViewEvents.prototype.handleContextMenu = function(event) {
|
| +// This is the only "webViewInternal.onClicked" named event for this renderer.
|
| +//
|
| +// Since we need an event per <webview>, we define events with suffix
|
| +// (subEventName) in each of the <webview>. Behind the scenes, this event is
|
| +// registered as a ContextMenusEvent, with filter set to the webview's
|
| +// |viewInstanceId|. Any time a ContextMenusEvent is dispatched, we re-dispatch
|
| +// it to the subEvent's listeners. This way
|
| +// <webview>.contextMenus.onClicked behave as a regular chrome Event type.
|
| +var ContextMenusEvent = CreateEvent('chromeWebViewInternal.onClicked');
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// ContextMenusOnClickedEvent object.
|
| +
|
| +// This event is exposed as <webview>.contextMenus.onClicked.
|
| +function ContextMenusOnClickedEvent(opt_eventName,
|
| + opt_argSchemas,
|
| + opt_eventOptions,
|
| + opt_webViewInstanceId) {
|
| + var subEventName = GetUniqueSubEventName(opt_eventName);
|
| + EventBindings.Event.call(this,
|
| + subEventName,
|
| + opt_argSchemas,
|
| + opt_eventOptions,
|
| + opt_webViewInstanceId);
|
| +
|
| + // TODO(lazyboy): When do we dispose this listener?
|
| + ContextMenusEvent.addListener(function() {
|
| + // Re-dispatch to subEvent's listeners.
|
| + $Function.apply(this.dispatch, this, $Array.slice(arguments));
|
| + }.bind(this), {instanceId: opt_webViewInstanceId || 0});
|
| +}
|
| +
|
| +ContextMenusOnClickedEvent.prototype.__proto__ = EventBindings.Event.prototype;
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +// WebViewContextMenusImpl object.
|
| +
|
| +// An instance of this class is exposed as <webview>.contextMenus.
|
| +function WebViewContextMenusImpl(viewInstanceId) {
|
| + this.viewInstanceId_ = viewInstanceId;
|
| +}
|
| +
|
| +WebViewContextMenusImpl.prototype.create = function() {
|
| + var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
|
| + return $Function.apply(ChromeWebView.contextMenusCreate, null, args);
|
| +};
|
| +
|
| +WebViewContextMenusImpl.prototype.remove = function() {
|
| + var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
|
| + return $Function.apply(ChromeWebView.contextMenusRemove, null, args);
|
| +};
|
| +
|
| +WebViewContextMenusImpl.prototype.removeAll = function() {
|
| + var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
|
| + return $Function.apply(ChromeWebView.contextMenusRemoveAll, null, args);
|
| +};
|
| +
|
| +WebViewContextMenusImpl.prototype.update = function() {
|
| + var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments));
|
| + return $Function.apply(ChromeWebView.contextMenusUpdate, null, args);
|
| +};
|
| +
|
| +var WebViewContextMenus = Utils.expose(
|
| + 'WebViewContextMenus', WebViewContextMenusImpl,
|
| + { functions: ['create', 'remove', 'removeAll', 'update'] });
|
| +
|
| +// -----------------------------------------------------------------------------
|
| +
|
| +WebViewImpl.prototype.maybeSetupContextMenus = function() {
|
| + var createContextMenus = function() {
|
| + return function() {
|
| + if (this.contextMenus_) {
|
| + return this.contextMenus_;
|
| + }
|
| +
|
| + this.contextMenus_ = new WebViewContextMenus(this.viewInstanceId);
|
| +
|
| + // Define 'onClicked' event property on |this.contextMenus_|.
|
| + var getOnClickedEvent = function() {
|
| + return function() {
|
| + if (!this.contextMenusOnClickedEvent_) {
|
| + var eventName = 'chromeWebViewInternal.onClicked';
|
| + // TODO(lazyboy): Find event by name instead of events[0].
|
| + var eventSchema = ChromeWebViewSchema.events[0];
|
| + var eventOptions = {supportsListeners: true};
|
| + var onClickedEvent = new ContextMenusOnClickedEvent(
|
| + eventName, eventSchema, eventOptions, this.viewInstanceId);
|
| + this.contextMenusOnClickedEvent_ = onClickedEvent;
|
| + return onClickedEvent;
|
| + }
|
| + return this.contextMenusOnClickedEvent_;
|
| + }.bind(this);
|
| + }.bind(this);
|
| + Object.defineProperty(
|
| + this.contextMenus_,
|
| + 'onClicked',
|
| + {get: getOnClickedEvent(), enumerable: true});
|
| +
|
| + return this.contextMenus_;
|
| + }.bind(this);
|
| + }.bind(this);
|
| +
|
| + // Expose <webview>.contextMenus object.
|
| + Object.defineProperty(
|
| + this.element,
|
| + 'contextMenus',
|
| + {
|
| + get: createContextMenus(),
|
| + enumerable: true
|
| + });
|
| +};
|
| +
|
| +WebViewEvents.prototype.handleContextMenu = function(event, eventName) {
|
| + var webViewEvent = this.makeDomEvent(event, eventName);
|
| var requestId = event.requestId;
|
| - // Setting |params| = undefined will show the context menu unmodified, hence
|
| - // the 'contextmenu' API is disabled for stable channel.
|
| - var params = undefined;
|
| - ChromeWebView.showContextMenu(this.view.guest.getId(), requestId, params);
|
| + // Construct the event.menu object.
|
| + var actionTaken = false;
|
| + var validateCall = function() {
|
| + var ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN = '<webview>: ' +
|
| + 'An action has already been taken for this "contextmenu" event.';
|
| +
|
| + if (actionTaken) {
|
| + throw new Error(ERROR_MSG_CONTEXT_MENU_ACTION_ALREADY_TAKEN);
|
| + }
|
| + actionTaken = true;
|
| + };
|
| + var menu = {
|
| + show: function(items) {
|
| + validateCall();
|
| + // TODO(lazyboy): WebViewShowContextFunction doesn't do anything useful
|
| + // with |items|, implement.
|
| + ChromeWebView.showContextMenu(this.view.guest.getId(), requestId, items);
|
| + }.bind(this)
|
| + };
|
| + webViewEvent.menu = menu;
|
| + var element = this.view.element;
|
| + var defaultPrevented = !element.dispatchEvent(webViewEvent);
|
| + if (actionTaken) {
|
| + return;
|
| + }
|
| + if (!defaultPrevented) {
|
| + actionTaken = true;
|
| + // The default action is equivalent to just showing the context menu as is.
|
| + ChromeWebView.showContextMenu(
|
| + this.view.guest.getId(), requestId, undefined);
|
| +
|
| + // TODO(lazyboy): Figure out a way to show warning message only when
|
| + // listeners are registered for this event.
|
| + } // else we will ignore showing the context menu completely.
|
| };
|
|
|
| +function GetUniqueSubEventName(eventName) {
|
| + return eventName + '/' + idGeneratorNatives.GetNextId();
|
| +}
|
| +
|
| // Exposes |CHROME_WEB_VIEW_EVENTS| when the ChromeWebView API is available.
|
| (function() {
|
| for (var eventName in CHROME_WEB_VIEW_EVENTS) {
|
|
|