OLD | NEW |
| (Empty) |
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. | |
4 | |
5 // Event management for WebView. | |
6 | |
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; | |
18 | |
19 var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage'); | |
20 | |
21 function WebViewEvents(webViewImpl) { | |
22 GuestViewEvents.call(this, webViewImpl); | |
23 | |
24 this.setupWebRequestEvents(); | |
25 this.view.setupExperimentalContextMenus(); | |
26 } | |
27 | |
28 WebViewEvents.prototype.__proto__ = GuestViewEvents.prototype; | |
29 | |
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 = { | |
34 'close': { | |
35 evt: CreateEvent('webViewInternal.onClose') | |
36 }, | |
37 'consolemessage': { | |
38 evt: CreateEvent('webViewInternal.onConsoleMessage'), | |
39 fields: ['level', 'message', 'line', 'sourceId'] | |
40 }, | |
41 'contentload': { | |
42 evt: CreateEvent('webViewInternal.onContentLoad') | |
43 }, | |
44 'dialog': { | |
45 cancelable: true, | |
46 evt: CreateEvent('webViewInternal.onDialog'), | |
47 fields: ['defaultPromptText', 'messageText', 'messageType', 'url'], | |
48 handler: 'handleDialogEvent' | |
49 }, | |
50 'droplink': { | |
51 evt: CreateEvent('webViewInternal.onDropLink'), | |
52 fields: ['url'] | |
53 }, | |
54 'exit': { | |
55 evt: CreateEvent('webViewInternal.onExit'), | |
56 fields: ['processId', 'reason'] | |
57 }, | |
58 'findupdate': { | |
59 evt: CreateEvent('webViewInternal.onFindReply'), | |
60 fields: [ | |
61 'searchText', | |
62 'numberOfMatches', | |
63 'activeMatchOrdinal', | |
64 'selectionRect', | |
65 'canceled', | |
66 'finalUpdate' | |
67 ] | |
68 }, | |
69 'framenamechanged': { | |
70 evt: CreateEvent('webViewInternal.onFrameNameChanged'), | |
71 handler: 'handleFrameNameChangedEvent' | |
72 }, | |
73 'loadabort': { | |
74 cancelable: true, | |
75 evt: CreateEvent('webViewInternal.onLoadAbort'), | |
76 fields: ['url', 'isTopLevel', 'reason'], | |
77 handler: 'handleLoadAbortEvent' | |
78 }, | |
79 'loadcommit': { | |
80 evt: CreateEvent('webViewInternal.onLoadCommit'), | |
81 fields: ['url', 'isTopLevel'], | |
82 handler: 'handleLoadCommitEvent' | |
83 }, | |
84 'loadprogress': { | |
85 evt: CreateEvent('webViewInternal.onLoadProgress'), | |
86 fields: ['url', 'progress'] | |
87 }, | |
88 'loadredirect': { | |
89 evt: CreateEvent('webViewInternal.onLoadRedirect'), | |
90 fields: ['isTopLevel', 'oldUrl', 'newUrl'] | |
91 }, | |
92 'loadstart': { | |
93 evt: CreateEvent('webViewInternal.onLoadStart'), | |
94 fields: ['url', 'isTopLevel'] | |
95 }, | |
96 'loadstop': { | |
97 evt: CreateEvent('webViewInternal.onLoadStop') | |
98 }, | |
99 'newwindow': { | |
100 cancelable: true, | |
101 evt: CreateEvent('webViewInternal.onNewWindow'), | |
102 fields: [ | |
103 'initialHeight', | |
104 'initialWidth', | |
105 'targetUrl', | |
106 'windowOpenDisposition', | |
107 'name' | |
108 ], | |
109 handler: 'handleNewWindowEvent' | |
110 }, | |
111 'permissionrequest': { | |
112 cancelable: true, | |
113 evt: CreateEvent('webViewInternal.onPermissionRequest'), | |
114 fields: [ | |
115 'identifier', | |
116 'lastUnlockedBySelf', | |
117 'name', | |
118 'permission', | |
119 'requestMethod', | |
120 'url', | |
121 'userGesture' | |
122 ], | |
123 handler: 'handlePermissionEvent' | |
124 }, | |
125 'responsive': { | |
126 evt: CreateEvent('webViewInternal.onResponsive'), | |
127 fields: ['processId'] | |
128 }, | |
129 'sizechanged': { | |
130 evt: CreateEvent('webViewInternal.onSizeChanged'), | |
131 fields: ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'], | |
132 handler: 'handleSizeChangedEvent' | |
133 }, | |
134 'unresponsive': { | |
135 evt: CreateEvent('webViewInternal.onUnresponsive'), | |
136 fields: ['processId'] | |
137 }, | |
138 'zoomchange': { | |
139 evt: CreateEvent('webViewInternal.onZoomChange'), | |
140 fields: ['oldZoomFactor', 'newZoomFactor'] | |
141 } | |
142 }; | |
143 | |
144 WebViewEvents.prototype.setupWebRequestEvents = function() { | |
145 var request = {}; | |
146 var createWebRequestEvent = function(webRequestEvent) { | |
147 return function() { | |
148 if (!this[webRequestEvent.name]) { | |
149 this[webRequestEvent.name] = | |
150 new WebRequestEvent( | |
151 'webViewInternal.' + webRequestEvent.name, | |
152 webRequestEvent.parameters, | |
153 webRequestEvent.extraParameters, webRequestEvent.options, | |
154 this.view.viewInstanceId); | |
155 } | |
156 return this[webRequestEvent.name]; | |
157 }.bind(this); | |
158 }.bind(this); | |
159 | |
160 var createDeclarativeWebRequestEvent = function(webRequestEvent) { | |
161 return function() { | |
162 if (!this[webRequestEvent.name]) { | |
163 // The onMessage event gets a special event type because we want | |
164 // the listener to fire only for messages targeted for this particular | |
165 // <webview>. | |
166 var EventClass = webRequestEvent.name === 'onMessage' ? | |
167 DeclarativeWebRequestEvent : EventBindings.Event; | |
168 this[webRequestEvent.name] = | |
169 new EventClass( | |
170 'webViewInternal.declarativeWebRequest.' + webRequestEvent.name, | |
171 webRequestEvent.parameters, | |
172 webRequestEvent.options, | |
173 this.view.viewInstanceId); | |
174 } | |
175 return this[webRequestEvent.name]; | |
176 }.bind(this); | |
177 }.bind(this); | |
178 | |
179 for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) { | |
180 var eventSchema = DeclarativeWebRequestSchema.events[i]; | |
181 var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema); | |
182 Object.defineProperty( | |
183 request, | |
184 eventSchema.name, | |
185 { | |
186 get: webRequestEvent, | |
187 enumerable: true | |
188 } | |
189 ); | |
190 } | |
191 | |
192 // Populate the WebRequest events from the API definition. | |
193 for (var i = 0; i < WebRequestSchema.events.length; ++i) { | |
194 var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]); | |
195 Object.defineProperty( | |
196 request, | |
197 WebRequestSchema.events[i].name, | |
198 { | |
199 get: webRequestEvent, | |
200 enumerable: true | |
201 } | |
202 ); | |
203 } | |
204 | |
205 this.view.setRequestPropertyOnWebViewElement(request); | |
206 }; | |
207 | |
208 WebViewEvents.prototype.getEvents = function() { | |
209 return WebViewEvents.EVENTS; | |
210 }; | |
211 | |
212 WebViewEvents.prototype.handleDialogEvent = function(event, eventName) { | |
213 var webViewEvent = this.makeDomEvent(event, eventName); | |
214 new WebViewActionRequests.Dialog(this.view, event, webViewEvent); | |
215 }; | |
216 | |
217 WebViewEvents.prototype.handleFrameNameChangedEvent = function(event) { | |
218 this.view.onFrameNameChanged(event.name); | |
219 }; | |
220 | |
221 WebViewEvents.prototype.handleLoadAbortEvent = function(event, eventName) { | |
222 var showWarningMessage = function(reason) { | |
223 var WARNING_MSG_LOAD_ABORTED = '<webview>: ' + | |
224 'The load has aborted with reason "%1".'; | |
225 window.console.warn(WARNING_MSG_LOAD_ABORTED.replace('%1', reason)); | |
226 }; | |
227 var webViewEvent = this.makeDomEvent(event, eventName); | |
228 if (this.view.dispatchEvent(webViewEvent)) { | |
229 showWarningMessage(event.reason); | |
230 } | |
231 }; | |
232 | |
233 WebViewEvents.prototype.handleLoadCommitEvent = function(event, eventName) { | |
234 this.view.onLoadCommit(event.baseUrlForDataUrl, | |
235 event.currentEntryIndex, | |
236 event.entryCount, | |
237 event.processId, | |
238 event.url, | |
239 event.isTopLevel); | |
240 var webViewEvent = this.makeDomEvent(event, eventName); | |
241 this.view.dispatchEvent(webViewEvent); | |
242 }; | |
243 | |
244 WebViewEvents.prototype.handleNewWindowEvent = function(event, eventName) { | |
245 var webViewEvent = this.makeDomEvent(event, eventName); | |
246 new WebViewActionRequests.NewWindow(this.view, event, webViewEvent); | |
247 }; | |
248 | |
249 WebViewEvents.prototype.handlePermissionEvent = function(event, eventName) { | |
250 var webViewEvent = this.makeDomEvent(event, eventName); | |
251 new WebViewActionRequests.PermissionRequest(this.view, event, webViewEvent); | |
252 }; | |
253 | |
254 WebViewEvents.prototype.handleSizeChangedEvent = function(event, eventName) { | |
255 var webViewEvent = this.makeDomEvent(event, eventName); | |
256 this.view.onSizeChanged(webViewEvent); | |
257 }; | |
258 | |
259 function DeclarativeWebRequestEvent(opt_eventName, | |
260 opt_argSchemas, | |
261 opt_eventOptions, | |
262 opt_webViewInstanceId) { | |
263 var subEventName = opt_eventName + '/' + IdGenerator.GetNextId(); | |
264 EventBindings.Event.call(this, | |
265 subEventName, | |
266 opt_argSchemas, | |
267 opt_eventOptions, | |
268 opt_webViewInstanceId); | |
269 | |
270 // TODO(lazyboy): When do we dispose this listener? | |
271 WebRequestMessageEvent.addListener(function() { | |
272 // Re-dispatch to subEvent's listeners. | |
273 $Function.apply(this.dispatch, this, $Array.slice(arguments)); | |
274 }.bind(this), {instanceId: opt_webViewInstanceId || 0}); | |
275 } | |
276 | |
277 DeclarativeWebRequestEvent.prototype.__proto__ = EventBindings.Event.prototype; | |
278 | |
279 // Exports. | |
280 exports.WebViewEvents = WebViewEvents; | |
OLD | NEW |