1 // Copyright 2014 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 // Event management for WebView.
7 var CreateEvent = require('guestViewEvents').CreateEvent;
8 var DeclarativeWebRequestSchema =
9 requireNative('schema_registry').GetSchema('declarativeWebRequest');
10 var EventBindings = require('event_bindings');
11 var GuestViewEvents = require('guestViewEvents').GuestViewEvents;
12 var IdGenerator = requireNative('id_generator');
13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent;
14 var WebRequestSchema =
15 requireNative('schema_registry').GetSchema('webRequest');
16 var WebViewActionRequests =
17 require('webViewActionRequests').WebViewActionRequests;
19 var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage');
21 function WebViewEvents(webViewImpl) {
22 GuestViewEvents.call(this, webViewImpl);
24 this.setupWebRequestEvents();
25 this.view.maybeSetupContextMenus();
28 WebViewEvents.prototype.__proto__ = GuestViewEvents.prototype;
30 // A dictionary of <webview> extension events to be listened for. This
31 // dictionary augments |GuestViewEvents.EVENTS| in guest_view_events.js. See the
32 // documentation there for details.
33 WebViewEvents.EVENTS = {
35 evt: CreateEvent('webViewInternal.onClose')
38 evt: CreateEvent('webViewInternal.onConsoleMessage'),
39 fields: ['level', 'message', 'line', 'sourceId']
42 evt: CreateEvent('webViewInternal.onContentLoad')
46 evt: CreateEvent('webViewInternal.onDialog'),
47 fields: ['defaultPromptText', 'messageText', 'messageType', 'url'],
48 handler: 'handleDialogEvent'
51 evt: CreateEvent('webViewInternal.onDropLink'),
55 evt: CreateEvent('webViewInternal.onExit'),
56 fields: ['processId', 'reason']
59 evt: CreateEvent('webViewInternal.onExitFullscreen'),
61 handler: 'handleFullscreenExitEvent',
65 evt: CreateEvent('webViewInternal.onFindReply'),
76 evt: CreateEvent('webViewInternal.onFrameNameChanged'),
77 handler: 'handleFrameNameChangedEvent',
82 evt: CreateEvent('webViewInternal.onLoadAbort'),
83 fields: ['url', 'isTopLevel', 'code', 'reason'],
84 handler: 'handleLoadAbortEvent'
87 evt: CreateEvent('webViewInternal.onLoadCommit'),
88 fields: ['url', 'isTopLevel'],
89 handler: 'handleLoadCommitEvent'
92 evt: CreateEvent('webViewInternal.onLoadProgress'),
93 fields: ['url', 'progress']
96 evt: CreateEvent('webViewInternal.onLoadRedirect'),
97 fields: ['isTopLevel', 'oldUrl', 'newUrl']
100 evt: CreateEvent('webViewInternal.onLoadStart'),
101 fields: ['url', 'isTopLevel']
104 evt: CreateEvent('webViewInternal.onLoadStop')
108 evt: CreateEvent('webViewInternal.onNewWindow'),
113 'windowOpenDisposition',
116 handler: 'handleNewWindowEvent'
118 'permissionrequest': {
120 evt: CreateEvent('webViewInternal.onPermissionRequest'),
123 'lastUnlockedBySelf',
130 handler: 'handlePermissionEvent'
133 evt: CreateEvent('webViewInternal.onResponsive'),
134 fields: ['processId']
137 evt: CreateEvent('webViewInternal.onSizeChanged'),
138 fields: ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'],
139 handler: 'handleSizeChangedEvent'
142 evt: CreateEvent('webViewInternal.onUnresponsive'),
143 fields: ['processId']
146 evt: CreateEvent('webViewInternal.onZoomChange'),
147 fields: ['oldZoomFactor', 'newZoomFactor']
151 WebViewEvents.prototype.setupWebRequestEvents = function() {
153 var createWebRequestEvent = function(webRequestEvent) {
155 if (!this[webRequestEvent.name]) {
156 this[webRequestEvent.name] =
158 'webViewInternal.' + webRequestEvent.name,
159 webRequestEvent.parameters,
160 webRequestEvent.extraParameters, webRequestEvent.options,
161 this.view.viewInstanceId);
163 return this[webRequestEvent.name];
167 var createDeclarativeWebRequestEvent = function(webRequestEvent) {
169 if (!this[webRequestEvent.name]) {
170 // The onMessage event gets a special event type because we want
171 // the listener to fire only for messages targeted for this particular
173 var EventClass = webRequestEvent.name === 'onMessage' ?
174 DeclarativeWebRequestEvent : EventBindings.Event;
175 this[webRequestEvent.name] =
177 'webViewInternal.declarativeWebRequest.' + webRequestEvent.name,
178 webRequestEvent.parameters,
179 webRequestEvent.options,
180 this.view.viewInstanceId);
182 return this[webRequestEvent.name];
186 for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) {
187 var eventSchema = DeclarativeWebRequestSchema.events[i];
188 var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema);
189 Object.defineProperty(
193 get: webRequestEvent,
199 // Populate the WebRequest events from the API definition.
200 for (var i = 0; i < WebRequestSchema.events.length; ++i) {
201 var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]);
202 Object.defineProperty(
204 WebRequestSchema.events[i].name,
206 get: webRequestEvent,
212 this.view.setRequestPropertyOnWebViewElement(request);
215 WebViewEvents.prototype.getEvents = function() {
216 return WebViewEvents.EVENTS;
219 WebViewEvents.prototype.handleDialogEvent = function(event, eventName) {
220 var webViewEvent = this.makeDomEvent(event, eventName);
221 new WebViewActionRequests.Dialog(this.view, event, webViewEvent);
224 WebViewEvents.prototype.handleFrameNameChangedEvent = function(event) {
225 this.view.onFrameNameChanged(event.name);
228 WebViewEvents.prototype.handleFullscreenExitEvent = function(event, eventName) {
229 document.webkitCancelFullScreen();
232 WebViewEvents.prototype.handleLoadAbortEvent = function(event, eventName) {
233 var showWarningMessage = function(code, reason) {
234 var WARNING_MSG_LOAD_ABORTED = '<webview>: ' +
235 'The load has aborted with error %1: %2.';
237 WARNING_MSG_LOAD_ABORTED.replace('%1', code).replace('%2', reason));
239 var webViewEvent = this.makeDomEvent(event, eventName);
240 if (this.view.dispatchEvent(webViewEvent)) {
241 showWarningMessage(event.code, event.reason);
245 WebViewEvents.prototype.handleLoadCommitEvent = function(event, eventName) {
246 this.view.onLoadCommit(event.baseUrlForDataUrl,
247 event.currentEntryIndex,
252 var webViewEvent = this.makeDomEvent(event, eventName);
253 this.view.dispatchEvent(webViewEvent);
256 WebViewEvents.prototype.handleNewWindowEvent = function(event, eventName) {
257 var webViewEvent = this.makeDomEvent(event, eventName);
258 new WebViewActionRequests.NewWindow(this.view, event, webViewEvent);
261 WebViewEvents.prototype.handlePermissionEvent = function(event, eventName) {
262 var webViewEvent = this.makeDomEvent(event, eventName);
263 if (event.permission === 'fullscreen') {
264 new WebViewActionRequests.FullscreenPermissionRequest(
265 this.view, event, webViewEvent);
267 new WebViewActionRequests.PermissionRequest(this.view, event, webViewEvent);
271 WebViewEvents.prototype.handleSizeChangedEvent = function(event, eventName) {
272 var webViewEvent = this.makeDomEvent(event, eventName);
273 this.view.onSizeChanged(webViewEvent);
276 function DeclarativeWebRequestEvent(opt_eventName,
279 opt_webViewInstanceId) {
280 var subEventName = opt_eventName + '/' + IdGenerator.GetNextId();
281 EventBindings.Event.call(this,
285 opt_webViewInstanceId);
287 // TODO(lazyboy): When do we dispose this listener?
288 WebRequestMessageEvent.addListener(function() {
289 // Re-dispatch to subEvent's listeners.
290 $Function.apply(this.dispatch, this, $Array.slice(arguments));
291 }.bind(this), {instanceId: opt_webViewInstanceId || 0});
294 DeclarativeWebRequestEvent.prototype.__proto__ = EventBindings.Event.prototype;
297 exports.WebViewEvents = WebViewEvents;