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 WebViewInternal. | |
6 | |
7 var DeclarativeWebRequestSchema = | |
8 requireNative('schema_registry').GetSchema('declarativeWebRequest'); | |
9 var EventBindings = require('event_bindings'); | |
10 var IdGenerator = requireNative('id_generator'); | |
11 var MessagingNatives = requireNative('messaging_natives'); | |
12 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | |
13 var WebRequestSchema = | |
14 requireNative('schema_registry').GetSchema('webRequest'); | |
15 var WebView = require('webViewInternal').WebView; | |
16 | |
17 var CreateEvent = function(name) { | |
18 var eventOpts = {supportsListeners: true, supportsFilters: true}; | |
19 return new EventBindings.Event(name, undefined, eventOpts); | |
20 }; | |
21 | |
22 var FrameNameChangedEvent = CreateEvent('webViewInternal.onFrameNameChanged'); | |
23 var PluginDestroyedEvent = CreateEvent('webViewInternal.onPluginDestroyed'); | |
24 var WebRequestMessageEvent = CreateEvent('webViewInternal.onMessage'); | |
25 | |
26 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their | |
27 // associated extension event descriptor objects. | |
28 // An event listener will be attached to the extension event |evt| specified in | |
29 // the descriptor. | |
30 // |fields| specifies the public-facing fields in the DOM event that are | |
31 // accessible to <webview> developers. | |
32 // |customHandler| allows a handler function to be called each time an extension | |
33 // event is caught by its event listener. The DOM event should be dispatched | |
34 // within this handler function. With no handler function, the DOM event | |
35 // will be dispatched by default each time the extension event is caught. | |
36 // |cancelable| (default: false) specifies whether the event's default | |
37 // behavior can be canceled. If the default action associated with the event | |
38 // is prevented, then its dispatch function will return false in its event | |
39 // handler. The event must have a custom handler for this to be meaningful. | |
40 var WEB_VIEW_EVENTS = { | |
41 'close': { | |
42 evt: CreateEvent('webViewInternal.onClose'), | |
43 fields: [] | |
44 }, | |
45 'consolemessage': { | |
46 evt: CreateEvent('webViewInternal.onConsoleMessage'), | |
47 fields: ['level', 'message', 'line', 'sourceId'] | |
48 }, | |
49 'contentload': { | |
50 evt: CreateEvent('webViewInternal.onContentLoad'), | |
51 fields: [] | |
52 }, | |
53 'contextmenu': { | |
54 evt: CreateEvent('chromeWebViewInternal.contextmenu'), | |
55 cancelable: true, | |
56 customHandler: function(handler, event, webViewEvent) { | |
57 handler.handleContextMenu(event, webViewEvent); | |
58 }, | |
59 fields: ['items'] | |
60 }, | |
61 'dialog': { | |
62 cancelable: true, | |
63 customHandler: function(handler, event, webViewEvent) { | |
64 handler.handleDialogEvent(event, webViewEvent); | |
65 }, | |
66 evt: CreateEvent('webViewInternal.onDialog'), | |
67 fields: ['defaultPromptText', 'messageText', 'messageType', 'url'] | |
68 }, | |
69 'exit': { | |
70 evt: CreateEvent('webViewInternal.onExit'), | |
71 fields: ['processId', 'reason'] | |
72 }, | |
73 'findupdate': { | |
74 evt: CreateEvent('webViewInternal.onFindReply'), | |
75 fields: [ | |
76 'searchText', | |
77 'numberOfMatches', | |
78 'activeMatchOrdinal', | |
79 'selectionRect', | |
80 'canceled', | |
81 'finalUpdate' | |
82 ] | |
83 }, | |
84 'loadabort': { | |
85 cancelable: true, | |
86 customHandler: function(handler, event, webViewEvent) { | |
87 handler.handleLoadAbortEvent(event, webViewEvent); | |
88 }, | |
89 evt: CreateEvent('webViewInternal.onLoadAbort'), | |
90 fields: ['url', 'isTopLevel', 'reason'] | |
91 }, | |
92 'loadcommit': { | |
93 customHandler: function(handler, event, webViewEvent) { | |
94 handler.handleLoadCommitEvent(event, webViewEvent); | |
95 }, | |
96 evt: CreateEvent('webViewInternal.onLoadCommit'), | |
97 fields: ['url', 'isTopLevel'] | |
98 }, | |
99 'loadprogress': { | |
100 evt: CreateEvent('webViewInternal.onLoadProgress'), | |
101 fields: ['url', 'progress'] | |
102 }, | |
103 'loadredirect': { | |
104 evt: CreateEvent('webViewInternal.onLoadRedirect'), | |
105 fields: ['isTopLevel', 'oldUrl', 'newUrl'] | |
106 }, | |
107 'loadstart': { | |
108 evt: CreateEvent('webViewInternal.onLoadStart'), | |
109 fields: ['url', 'isTopLevel'] | |
110 }, | |
111 'loadstop': { | |
112 evt: CreateEvent('webViewInternal.onLoadStop'), | |
113 fields: [] | |
114 }, | |
115 'newwindow': { | |
116 cancelable: true, | |
117 customHandler: function(handler, event, webViewEvent) { | |
118 handler.handleNewWindowEvent(event, webViewEvent); | |
119 }, | |
120 evt: CreateEvent('webViewInternal.onNewWindow'), | |
121 fields: [ | |
122 'initialHeight', | |
123 'initialWidth', | |
124 'targetUrl', | |
125 'windowOpenDisposition', | |
126 'name' | |
127 ] | |
128 }, | |
129 'permissionrequest': { | |
130 cancelable: true, | |
131 customHandler: function(handler, event, webViewEvent) { | |
132 handler.handlePermissionEvent(event, webViewEvent); | |
133 }, | |
134 evt: CreateEvent('webViewInternal.onPermissionRequest'), | |
135 fields: [ | |
136 'identifier', | |
137 'lastUnlockedBySelf', | |
138 'name', | |
139 'permission', | |
140 'requestMethod', | |
141 'url', | |
142 'userGesture' | |
143 ] | |
144 }, | |
145 'responsive': { | |
146 evt: CreateEvent('webViewInternal.onResponsive'), | |
147 fields: ['processId'] | |
148 }, | |
149 'sizechanged': { | |
150 evt: CreateEvent('webViewInternal.onSizeChanged'), | |
151 customHandler: function(handler, event, webViewEvent) { | |
152 handler.handleSizeChangedEvent(event, webViewEvent); | |
153 }, | |
154 fields: ['oldHeight', 'oldWidth', 'newHeight', 'newWidth'] | |
155 }, | |
156 'unresponsive': { | |
157 evt: CreateEvent('webViewInternal.onUnresponsive'), | |
158 fields: ['processId'] | |
159 }, | |
160 'zoomchange': { | |
161 evt: CreateEvent('webViewInternal.onZoomChange'), | |
162 fields: ['oldZoomFactor', 'newZoomFactor'] | |
163 } | |
164 }; | |
165 | |
166 function DeclarativeWebRequestEvent(opt_eventName, | |
167 opt_argSchemas, | |
168 opt_eventOptions, | |
169 opt_webViewInstanceId) { | |
170 var subEventName = opt_eventName + '/' + IdGenerator.GetNextId(); | |
171 EventBindings.Event.call(this, subEventName, opt_argSchemas, opt_eventOptions, | |
172 opt_webViewInstanceId); | |
173 | |
174 // TODO(lazyboy): When do we dispose this listener? | |
175 WebRequestMessageEvent.addListener(function() { | |
176 // Re-dispatch to subEvent's listeners. | |
177 $Function.apply(this.dispatch, this, $Array.slice(arguments)); | |
178 }.bind(this), {instanceId: opt_webViewInstanceId || 0}); | |
179 } | |
180 | |
181 DeclarativeWebRequestEvent.prototype = { | |
182 __proto__: EventBindings.Event.prototype | |
183 }; | |
184 | |
185 // Constructor. | |
186 function WebViewEvents(webViewInternal, viewInstanceId) { | |
187 this.webViewInternal = webViewInternal; | |
188 this.viewInstanceId = viewInstanceId; | |
189 this.setup(); | |
190 } | |
191 | |
192 // Sets up events. | |
193 WebViewEvents.prototype.setup = function() { | |
194 this.setupFrameNameChangedEvent(); | |
195 this.setupPluginDestroyedEvent(); | |
196 this.setupWebRequestEvents(); | |
197 this.webViewInternal.setupExperimentalContextMenus(); | |
198 | |
199 var events = this.getEvents(); | |
200 for (var eventName in events) { | |
201 this.setupEvent(eventName, events[eventName]); | |
202 } | |
203 }; | |
204 | |
205 WebViewEvents.prototype.setupFrameNameChangedEvent = function() { | |
206 FrameNameChangedEvent.addListener(function(e) { | |
207 this.webViewInternal.onFrameNameChanged(e.name); | |
208 }.bind(this), {instanceId: this.viewInstanceId}); | |
209 }; | |
210 | |
211 WebViewEvents.prototype.setupPluginDestroyedEvent = function() { | |
212 PluginDestroyedEvent.addListener(function(e) { | |
213 this.webViewInternal.onPluginDestroyed(); | |
214 }.bind(this), {instanceId: this.viewInstanceId}); | |
215 }; | |
216 | |
217 WebViewEvents.prototype.setupWebRequestEvents = function() { | |
218 var request = {}; | |
219 var createWebRequestEvent = function(webRequestEvent) { | |
220 return function() { | |
221 if (!this[webRequestEvent.name]) { | |
222 this[webRequestEvent.name] = | |
223 new WebRequestEvent( | |
224 'webViewInternal.' + webRequestEvent.name, | |
225 webRequestEvent.parameters, | |
226 webRequestEvent.extraParameters, webRequestEvent.options, | |
227 this.viewInstanceId); | |
228 } | |
229 return this[webRequestEvent.name]; | |
230 }.bind(this); | |
231 }.bind(this); | |
232 | |
233 var createDeclarativeWebRequestEvent = function(webRequestEvent) { | |
234 return function() { | |
235 if (!this[webRequestEvent.name]) { | |
236 // The onMessage event gets a special event type because we want | |
237 // the listener to fire only for messages targeted for this particular | |
238 // <webview>. | |
239 var EventClass = webRequestEvent.name === 'onMessage' ? | |
240 DeclarativeWebRequestEvent : EventBindings.Event; | |
241 this[webRequestEvent.name] = | |
242 new EventClass( | |
243 'webViewInternal.' + webRequestEvent.name, | |
244 webRequestEvent.parameters, | |
245 webRequestEvent.options, | |
246 this.viewInstanceId); | |
247 } | |
248 return this[webRequestEvent.name]; | |
249 }.bind(this); | |
250 }.bind(this); | |
251 | |
252 for (var i = 0; i < DeclarativeWebRequestSchema.events.length; ++i) { | |
253 var eventSchema = DeclarativeWebRequestSchema.events[i]; | |
254 var webRequestEvent = createDeclarativeWebRequestEvent(eventSchema); | |
255 Object.defineProperty( | |
256 request, | |
257 eventSchema.name, | |
258 { | |
259 get: webRequestEvent, | |
260 enumerable: true | |
261 } | |
262 ); | |
263 } | |
264 | |
265 // Populate the WebRequest events from the API definition. | |
266 for (var i = 0; i < WebRequestSchema.events.length; ++i) { | |
267 var webRequestEvent = createWebRequestEvent(WebRequestSchema.events[i]); | |
268 Object.defineProperty( | |
269 request, | |
270 WebRequestSchema.events[i].name, | |
271 { | |
272 get: webRequestEvent, | |
273 enumerable: true | |
274 } | |
275 ); | |
276 } | |
277 | |
278 this.webViewInternal.setRequestPropertyOnWebViewNode(request); | |
279 }; | |
280 | |
281 WebViewEvents.prototype.getEvents = function() { | |
282 var experimentalEvents = this.webViewInternal.maybeGetExperimentalEvents(); | |
283 for (var eventName in experimentalEvents) { | |
284 WEB_VIEW_EVENTS[eventName] = experimentalEvents[eventName]; | |
285 } | |
286 return WEB_VIEW_EVENTS; | |
287 }; | |
288 | |
289 WebViewEvents.prototype.setupEvent = function(name, info) { | |
290 info.evt.addListener(function(e) { | |
291 var details = {bubbles:true}; | |
292 if (info.cancelable) { | |
293 details.cancelable = true; | |
294 } | |
295 var webViewEvent = new Event(name, details); | |
296 $Array.forEach(info.fields, function(field) { | |
297 if (e[field] !== undefined) { | |
298 webViewEvent[field] = e[field]; | |
299 } | |
300 }.bind(this)); | |
301 if (info.customHandler) { | |
302 info.customHandler(this, e, webViewEvent); | |
303 return; | |
304 } | |
305 this.webViewInternal.dispatchEvent(webViewEvent); | |
306 }.bind(this), {instanceId: this.viewInstanceId}); | |
307 | |
308 this.webViewInternal.setupEventProperty(name); | |
309 }; | |
310 | |
311 | |
312 // Event handlers. | |
313 WebViewEvents.prototype.handleContextMenu = function(e, webViewEvent) { | |
314 this.webViewInternal.maybeHandleContextMenu(e, webViewEvent); | |
315 }; | |
316 | |
317 WebViewEvents.prototype.handleDialogEvent = function(event, webViewEvent) { | |
318 var showWarningMessage = function(dialogType) { | |
319 var VOWELS = ['a', 'e', 'i', 'o', 'u']; | |
320 var WARNING_MSG_DIALOG_BLOCKED = '<webview>: %1 %2 dialog was blocked.'; | |
321 var article = (VOWELS.indexOf(dialogType.charAt(0)) >= 0) ? 'An' : 'A'; | |
322 var output = WARNING_MSG_DIALOG_BLOCKED.replace('%1', article); | |
323 output = output.replace('%2', dialogType); | |
324 window.console.warn(output); | |
325 }; | |
326 | |
327 var requestId = event.requestId; | |
328 var actionTaken = false; | |
329 | |
330 var validateCall = function() { | |
331 var ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN = '<webview>: ' + | |
332 'An action has already been taken for this "dialog" event.'; | |
333 | |
334 if (actionTaken) { | |
335 throw new Error(ERROR_MSG_DIALOG_ACTION_ALREADY_TAKEN); | |
336 } | |
337 actionTaken = true; | |
338 }; | |
339 | |
340 var getGuestInstanceId = function() { | |
341 return this.webViewInternal.getGuestInstanceId(); | |
342 }.bind(this); | |
343 | |
344 var dialog = { | |
345 ok: function(user_input) { | |
346 validateCall(); | |
347 user_input = user_input || ''; | |
348 WebView.setPermission(getGuestInstanceId(), requestId, 'allow', | |
349 user_input); | |
350 }, | |
351 cancel: function() { | |
352 validateCall(); | |
353 WebView.setPermission(getGuestInstanceId(), requestId, 'deny'); | |
354 } | |
355 }; | |
356 webViewEvent.dialog = dialog; | |
357 | |
358 var defaultPrevented = !this.webViewInternal.dispatchEvent(webViewEvent); | |
359 if (actionTaken) { | |
360 return; | |
361 } | |
362 | |
363 if (defaultPrevented) { | |
364 // Tell the JavaScript garbage collector to track lifetime of |dialog| and | |
365 // call back when the dialog object has been collected. | |
366 MessagingNatives.BindToGC(dialog, function() { | |
367 // Avoid showing a warning message if the decision has already been made. | |
368 if (actionTaken) { | |
369 return; | |
370 } | |
371 WebView.setPermission( | |
372 getGuestInstanceId(), requestId, 'default', '', function(allowed) { | |
373 if (allowed) { | |
374 return; | |
375 } | |
376 showWarningMessage(event.messageType); | |
377 }); | |
378 }); | |
379 } else { | |
380 actionTaken = true; | |
381 // The default action is equivalent to canceling the dialog. | |
382 WebView.setPermission( | |
383 getGuestInstanceId(), requestId, 'default', '', function(allowed) { | |
384 if (allowed) { | |
385 return; | |
386 } | |
387 showWarningMessage(event.messageType); | |
388 }); | |
389 } | |
390 }; | |
391 | |
392 WebViewEvents.prototype.handleLoadAbortEvent = function(event, webViewEvent) { | |
393 var showWarningMessage = function(reason) { | |
394 var WARNING_MSG_LOAD_ABORTED = '<webview>: ' + | |
395 'The load has aborted with reason "%1".'; | |
396 window.console.warn(WARNING_MSG_LOAD_ABORTED.replace('%1', reason)); | |
397 }; | |
398 if (this.webViewInternal.dispatchEvent(webViewEvent)) { | |
399 showWarningMessage(event.reason); | |
400 } | |
401 }; | |
402 | |
403 WebViewEvents.prototype.handleLoadCommitEvent = function(event, webViewEvent) { | |
404 this.webViewInternal.onLoadCommit(event.currentEntryIndex, event.entryCount, | |
405 event.processId, event.url, | |
406 event.isTopLevel); | |
407 this.webViewInternal.dispatchEvent(webViewEvent); | |
408 }; | |
409 | |
410 WebViewEvents.prototype.handleNewWindowEvent = function(event, webViewEvent) { | |
411 var ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN = '<webview>: ' + | |
412 'An action has already been taken for this "newwindow" event.'; | |
413 | |
414 var ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH = '<webview>: ' + | |
415 'Unable to attach the new window to the provided webViewInternal.'; | |
416 | |
417 var ERROR_MSG_WEBVIEW_EXPECTED = '<webview> element expected.'; | |
418 | |
419 var showWarningMessage = function() { | |
420 var WARNING_MSG_NEWWINDOW_BLOCKED = '<webview>: A new window was blocked.'; | |
421 window.console.warn(WARNING_MSG_NEWWINDOW_BLOCKED); | |
422 }; | |
423 | |
424 var requestId = event.requestId; | |
425 var actionTaken = false; | |
426 var getGuestInstanceId = function() { | |
427 return this.webViewInternal.getGuestInstanceId(); | |
428 }.bind(this); | |
429 | |
430 var validateCall = function () { | |
431 if (actionTaken) { | |
432 throw new Error(ERROR_MSG_NEWWINDOW_ACTION_ALREADY_TAKEN); | |
433 } | |
434 actionTaken = true; | |
435 }; | |
436 | |
437 var windowObj = { | |
438 attach: function(webview) { | |
439 validateCall(); | |
440 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') | |
441 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | |
442 // Attach happens asynchronously to give the tagWatcher an opportunity | |
443 // to pick up the new webview before attach operates on it, if it hasn't | |
444 // been attached to the DOM already. | |
445 // Note: Any subsequent errors cannot be exceptions because they happen | |
446 // asynchronously. | |
447 setTimeout(function() { | |
448 var webViewInternal = privates(webview).internal; | |
449 // Update the partition. | |
450 if (event.storagePartitionId) { | |
451 webViewInternal.onAttach(event.storagePartitionId); | |
452 } | |
453 | |
454 var attached = webViewInternal.attachWindow(event.windowId, true); | |
455 | |
456 if (!attached) { | |
457 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | |
458 } | |
459 | |
460 var guestInstanceId = getGuestInstanceId(); | |
461 if (!guestInstanceId) { | |
462 // If the opener is already gone, then we won't have its | |
463 // guestInstanceId. | |
464 return; | |
465 } | |
466 | |
467 // If the object being passed into attach is not a valid <webview> | |
468 // then we will fail and it will be treated as if the new window | |
469 // was rejected. The permission API plumbing is used here to clean | |
470 // up the state created for the new window if attaching fails. | |
471 WebView.setPermission( | |
472 guestInstanceId, requestId, attached ? 'allow' : 'deny'); | |
473 }, 0); | |
474 }, | |
475 discard: function() { | |
476 validateCall(); | |
477 var guestInstanceId = getGuestInstanceId(); | |
478 if (!guestInstanceId) { | |
479 // If the opener is already gone, then we won't have its | |
480 // guestInstanceId. | |
481 return; | |
482 } | |
483 WebView.setPermission(guestInstanceId, requestId, 'deny'); | |
484 } | |
485 }; | |
486 webViewEvent.window = windowObj; | |
487 | |
488 var defaultPrevented = !this.webViewInternal.dispatchEvent(webViewEvent); | |
489 if (actionTaken) { | |
490 return; | |
491 } | |
492 | |
493 if (defaultPrevented) { | |
494 // Make browser plugin track lifetime of |windowObj|. | |
495 MessagingNatives.BindToGC(windowObj, function() { | |
496 // Avoid showing a warning message if the decision has already been made. | |
497 if (actionTaken) { | |
498 return; | |
499 } | |
500 | |
501 var guestInstanceId = getGuestInstanceId(); | |
502 if (!guestInstanceId) { | |
503 // If the opener is already gone, then we won't have its | |
504 // guestInstanceId. | |
505 return; | |
506 } | |
507 | |
508 WebView.setPermission( | |
509 guestInstanceId, requestId, 'default', '', function(allowed) { | |
510 if (allowed) { | |
511 return; | |
512 } | |
513 showWarningMessage(); | |
514 }); | |
515 }); | |
516 } else { | |
517 actionTaken = true; | |
518 // The default action is to discard the window. | |
519 WebView.setPermission( | |
520 getGuestInstanceId(), requestId, 'default', '', function(allowed) { | |
521 if (allowed) { | |
522 return; | |
523 } | |
524 showWarningMessage(); | |
525 }); | |
526 } | |
527 }; | |
528 | |
529 WebViewEvents.prototype.getPermissionTypes = function() { | |
530 var permissions = | |
531 ['media', | |
532 'geolocation', | |
533 'pointerLock', | |
534 'download', | |
535 'loadplugin', | |
536 'filesystem']; | |
537 return permissions.concat( | |
538 this.webViewInternal.maybeGetExperimentalPermissions()); | |
539 }; | |
540 | |
541 WebViewEvents.prototype.handlePermissionEvent = | |
542 function(event, webViewEvent) { | |
543 var ERROR_MSG_PERMISSION_ALREADY_DECIDED = '<webview>: ' + | |
544 'Permission has already been decided for this "permissionrequest" event.'; | |
545 | |
546 var showWarningMessage = function(permission) { | |
547 var WARNING_MSG_PERMISSION_DENIED = '<webview>: ' + | |
548 'The permission request for "%1" has been denied.'; | |
549 window.console.warn( | |
550 WARNING_MSG_PERMISSION_DENIED.replace('%1', permission)); | |
551 }; | |
552 | |
553 var requestId = event.requestId; | |
554 var getGuestInstanceId = function() { | |
555 return this.webViewInternal.getGuestInstanceId(); | |
556 }.bind(this); | |
557 | |
558 if (this.getPermissionTypes().indexOf(event.permission) < 0) { | |
559 // The permission type is not allowed. Trigger the default response. | |
560 WebView.setPermission( | |
561 getGuestInstanceId(), requestId, 'default', '', function(allowed) { | |
562 if (allowed) { | |
563 return; | |
564 } | |
565 showWarningMessage(event.permission); | |
566 }); | |
567 return; | |
568 } | |
569 | |
570 var decisionMade = false; | |
571 var validateCall = function() { | |
572 if (decisionMade) { | |
573 throw new Error(ERROR_MSG_PERMISSION_ALREADY_DECIDED); | |
574 } | |
575 decisionMade = true; | |
576 }; | |
577 | |
578 // Construct the event.request object. | |
579 var request = { | |
580 allow: function() { | |
581 validateCall(); | |
582 WebView.setPermission(getGuestInstanceId(), requestId, 'allow'); | |
583 }, | |
584 deny: function() { | |
585 validateCall(); | |
586 WebView.setPermission(getGuestInstanceId(), requestId, 'deny'); | |
587 } | |
588 }; | |
589 webViewEvent.request = request; | |
590 | |
591 var defaultPrevented = !this.webViewInternal.dispatchEvent(webViewEvent); | |
592 if (decisionMade) { | |
593 return; | |
594 } | |
595 | |
596 if (defaultPrevented) { | |
597 // Make browser plugin track lifetime of |request|. | |
598 MessagingNatives.BindToGC(request, function() { | |
599 // Avoid showing a warning message if the decision has already been made. | |
600 if (decisionMade) { | |
601 return; | |
602 } | |
603 WebView.setPermission( | |
604 getGuestInstanceId(), requestId, 'default', '', function(allowed) { | |
605 if (allowed) { | |
606 return; | |
607 } | |
608 showWarningMessage(event.permission); | |
609 }); | |
610 }); | |
611 } else { | |
612 decisionMade = true; | |
613 WebView.setPermission( | |
614 getGuestInstanceId(), requestId, 'default', '', | |
615 function(allowed) { | |
616 if (allowed) { | |
617 return; | |
618 } | |
619 showWarningMessage(event.permission); | |
620 }); | |
621 } | |
622 }; | |
623 | |
624 WebViewEvents.prototype.handleSizeChangedEvent = function( | |
625 event, webViewEvent) { | |
626 this.webViewInternal.onSizeChanged(webViewEvent); | |
627 }; | |
628 | |
629 exports.WebViewEvents = WebViewEvents; | |
630 exports.CreateEvent = CreateEvent; | |
OLD | NEW |