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