| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 // This module implements experimental API for <webview>. | |
| 6 // See web_view.js for details. | |
| 7 // | |
| 8 // <webview> Experimental API is only available on canary and dev channels of | |
| 9 // Chrome. | |
| 10 | |
| 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'); | |
| 23 | |
| 24 function GetUniqueSubEventName(eventName) { | |
| 25 return eventName + "/" + idGeneratorNatives.GetNextId(); | |
| 26 } | |
| 27 | |
| 28 // This is the only "webViewInternal.onClicked" named event for this renderer. | |
| 29 // | |
| 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'); | |
| 37 | |
| 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); | |
| 50 | |
| 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}); | |
| 56 } | |
| 57 | |
| 58 ContextMenusOnClickedEvent.prototype = { | |
| 59 __proto__: EventBindings.Event.prototype | |
| 60 }; | |
| 61 | |
| 62 /** | |
| 63 * An instance of this class is exposed as <webview>.contextMenus. | |
| 64 * @constructor | |
| 65 */ | |
| 66 function WebViewContextMenusImpl(viewInstanceId) { | |
| 67 this.viewInstanceId_ = viewInstanceId; | |
| 68 }; | |
| 69 | |
| 70 WebViewContextMenusImpl.prototype.create = function() { | |
| 71 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments)); | |
| 72 return $Function.apply(ChromeWebView.contextMenusCreate, null, args); | |
| 73 }; | |
| 74 | |
| 75 WebViewContextMenusImpl.prototype.remove = function() { | |
| 76 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments)); | |
| 77 return $Function.apply(ChromeWebView.contextMenusRemove, null, args); | |
| 78 }; | |
| 79 | |
| 80 WebViewContextMenusImpl.prototype.removeAll = function() { | |
| 81 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments)); | |
| 82 return $Function.apply(ChromeWebView.contextMenusRemoveAll, null, args); | |
| 83 }; | |
| 84 | |
| 85 WebViewContextMenusImpl.prototype.update = function() { | |
| 86 var args = $Array.concat([this.viewInstanceId_], $Array.slice(arguments)); | |
| 87 return $Function.apply(ChromeWebView.contextMenusUpdate, null, args); | |
| 88 }; | |
| 89 | |
| 90 var WebViewContextMenus = utils.expose( | |
| 91 'WebViewContextMenus', WebViewContextMenusImpl, | |
| 92 { functions: ['create', 'remove', 'removeAll', 'update'] }); | |
| 93 | |
| 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.'; | |
| 102 | |
| 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); | |
| 126 | |
| 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. | |
| 130 }; | |
| 131 | |
| 132 WebViewInternal.prototype.maybeGetExperimentalEvents = function() { | |
| 133 return {}; | |
| 134 }; | |
| 135 | |
| 136 /** @private */ | |
| 137 WebViewInternal.prototype.maybeGetExperimentalPermissions = function() { | |
| 138 return []; | |
| 139 }; | |
| 140 | |
| 141 /** @private */ | |
| 142 WebViewInternal.prototype.captureVisibleRegion = function(spec, callback) { | |
| 143 WebView.captureVisibleRegion(this.guestInstanceId, spec, callback); | |
| 144 }; | |
| 145 | |
| 146 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) { | |
| 147 proto.captureVisibleRegion = function(spec, callback) { | |
| 148 privates(this).internal.captureVisibleRegion(spec, callback); | |
| 149 }; | |
| 150 }; | |
| 151 | |
| 152 /** @private */ | |
| 153 WebViewInternal.prototype.setupExperimentalContextMenus = function() { | |
| 154 var createContextMenus = function() { | |
| 155 return function() { | |
| 156 if (this.contextMenus_) { | |
| 157 return this.contextMenus_; | |
| 158 } | |
| 159 | |
| 160 this.contextMenus_ = new WebViewContextMenus(this.viewInstanceId); | |
| 161 | |
| 162 // Define 'onClicked' event property on |this.contextMenus_|. | |
| 163 var getOnClickedEvent = function() { | |
| 164 return function() { | |
| 165 if (!this.contextMenusOnClickedEvent_) { | |
| 166 var eventName = 'chromeWebViewInternal.onClicked'; | |
| 167 // TODO(lazyboy): Find event by name instead of events[0]. | |
| 168 var eventSchema = ChromeWebViewSchema.events[0]; | |
| 169 var eventOptions = {supportsListeners: true}; | |
| 170 var onClickedEvent = new ContextMenusOnClickedEvent( | |
| 171 eventName, eventSchema, eventOptions, this.viewInstanceId); | |
| 172 this.contextMenusOnClickedEvent_ = onClickedEvent; | |
| 173 return onClickedEvent; | |
| 174 } | |
| 175 return this.contextMenusOnClickedEvent_; | |
| 176 }.bind(this); | |
| 177 }.bind(this); | |
| 178 Object.defineProperty( | |
| 179 this.contextMenus_, | |
| 180 'onClicked', | |
| 181 {get: getOnClickedEvent(), enumerable: true}); | |
| 182 | |
| 183 return this.contextMenus_; | |
| 184 }.bind(this); | |
| 185 }.bind(this); | |
| 186 | |
| 187 // Expose <webview>.contextMenus object. | |
| 188 Object.defineProperty( | |
| 189 this.webviewNode, | |
| 190 'contextMenus', | |
| 191 { | |
| 192 get: createContextMenus(), | |
| 193 enumerable: true | |
| 194 }); | |
| 195 }; | |
| OLD | NEW |