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