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