OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // This module implements Webview (<webview>) as a custom element that wraps a | 5 // This module implements Webview (<webview>) as a custom element that wraps a |
6 // BrowserPlugin object element. The object element is hidden within | 6 // BrowserPlugin object element. The object element is hidden within |
7 // the shadow DOM of the Webview element. | 7 // the shadow DOM of the Webview element. |
8 | 8 |
9 var DocumentNatives = requireNative('document_natives'); | 9 var DocumentNatives = requireNative('document_natives'); |
10 var EventBindings = require('event_bindings'); | 10 var EventBindings = require('event_bindings'); |
11 var IdGenerator = requireNative('id_generator'); | 11 var IdGenerator = requireNative('id_generator'); |
12 var MessagingNatives = requireNative('messaging_natives'); | 12 var MessagingNatives = requireNative('messaging_natives'); |
13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | 13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; |
14 var WebRequestSchema = | 14 var WebRequestSchema = |
15 requireNative('schema_registry').GetSchema('webRequest'); | 15 requireNative('schema_registry').GetSchema('webRequest'); |
16 var DeclarativeWebRequestSchema = | 16 var DeclarativeWebRequestSchema = |
17 requireNative('schema_registry').GetSchema('declarativeWebRequest'); | 17 requireNative('schema_registry').GetSchema('declarativeWebRequest'); |
18 var WebView = require('webview').WebView; | 18 var WebView = require('webview').WebView; |
19 | 19 |
20 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; | 20 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; |
21 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; | 21 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; |
22 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; | 22 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; |
23 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; | 23 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; |
24 | 24 |
25 /** @type {Array.<string>} */ | 25 /** @type {Array.<string>} */ |
26 var WEB_VIEW_ATTRIBUTES = [ | 26 var WEB_VIEW_ATTRIBUTES = [ |
27 'allowtransparency', | 27 'allowtransparency', |
28 'autosize', | 28 'autosize', |
29 'name', | |
30 'partition', | 29 'partition', |
31 WEB_VIEW_ATTRIBUTE_MINHEIGHT, | 30 WEB_VIEW_ATTRIBUTE_MINHEIGHT, |
32 WEB_VIEW_ATTRIBUTE_MINWIDTH, | 31 WEB_VIEW_ATTRIBUTE_MINWIDTH, |
33 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, | 32 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, |
34 WEB_VIEW_ATTRIBUTE_MAXWIDTH | 33 WEB_VIEW_ATTRIBUTE_MAXWIDTH |
35 ]; | 34 ]; |
36 | 35 |
37 var CreateEvent = function(name) { | 36 var CreateEvent = function(name) { |
38 var eventOpts = {supportsListeners: true, supportsFilters: true}; | 37 var eventOpts = {supportsListeners: true, supportsFilters: true}; |
39 return new EventBindings.Event(name, undefined, eventOpts); | 38 return new EventBindings.Event(name, undefined, eventOpts); |
40 }; | 39 }; |
41 | 40 |
42 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their | 41 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their |
43 // associated extension event descriptor objects. | 42 // associated extension event descriptor objects. |
44 // An event listener will be attached to the extension event |evt| specified in | 43 // An event listener will be attached to the extension event |evt| specified in |
45 // the descriptor. | 44 // the descriptor. |
46 // |fields| specifies the public-facing fields in the DOM event that are | 45 // |fields| specifies the public-facing fields in the DOM event that are |
47 // accessible to <webview> developers. | 46 // accessible to <webview> developers. |
48 // |customHandler| allows a handler function to be called each time an extension | 47 // |customHandler| allows a handler function to be called each time an extension |
49 // event is caught by its event listener. The DOM event should be dispatched | 48 // event is caught by its event listener. The DOM event should be dispatched |
50 // within this handler function. With no handler function, the DOM event | 49 // within this handler function. With no handler function, the DOM event |
51 // will be dispatched by default each time the extension event is caught. | 50 // will be dispatched by default each time the extension event is caught. |
52 // |cancelable| (default: false) specifies whether the event's default | 51 // |cancelable| (default: false) specifies whether the event's default |
53 // behavior can be canceled. If the default action associated with the event | 52 // behavior can be canceled. If the default action associated with the event |
54 // is prevented, then its dispatch function will return false in its event | 53 // is prevented, then its dispatch function will return false in its event |
55 // handler. The event must have a custom handler for this to be meaningful. | 54 // handler. The event must have a custom handler for this to be meaningful. |
| 55 |
| 56 var FrameNameChangedEvent = CreateEvent('webview.onFrameNameChanged'); |
| 57 |
56 var WEB_VIEW_EVENTS = { | 58 var WEB_VIEW_EVENTS = { |
57 'close': { | 59 'close': { |
58 evt: CreateEvent('webview.onClose'), | 60 evt: CreateEvent('webview.onClose'), |
59 fields: [] | 61 fields: [] |
60 }, | 62 }, |
61 'consolemessage': { | 63 'consolemessage': { |
62 evt: CreateEvent('webview.onConsoleMessage'), | 64 evt: CreateEvent('webview.onConsoleMessage'), |
63 fields: ['level', 'message', 'line', 'sourceId'] | 65 fields: ['level', 'message', 'line', 'sourceId'] |
64 }, | 66 }, |
65 'contentload': { | 67 'contentload': { |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 get: function() { | 382 get: function() { |
381 return self.src; | 383 return self.src; |
382 }, | 384 }, |
383 set: function(value) { | 385 set: function(value) { |
384 self.webviewNode.setAttribute('src', value); | 386 self.webviewNode.setAttribute('src', value); |
385 }, | 387 }, |
386 // No setter. | 388 // No setter. |
387 enumerable: true | 389 enumerable: true |
388 }); | 390 }); |
389 | 391 |
| 392 Object.defineProperty(this.webviewNode, 'name', { |
| 393 get: function() { |
| 394 return self.name; |
| 395 }, |
| 396 set: function(value) { |
| 397 self.webviewNode.setAttribute('name', value); |
| 398 }, |
| 399 enumerable: true |
| 400 }); |
| 401 |
390 // We cannot use {writable: true} property descriptor because we want a | 402 // We cannot use {writable: true} property descriptor because we want a |
391 // dynamic getter value. | 403 // dynamic getter value. |
392 Object.defineProperty(this.webviewNode, 'contentWindow', { | 404 Object.defineProperty(this.webviewNode, 'contentWindow', { |
393 get: function() { | 405 get: function() { |
394 if (browserPluginNode.contentWindow) | 406 if (browserPluginNode.contentWindow) |
395 return browserPluginNode.contentWindow; | 407 return browserPluginNode.contentWindow; |
396 window.console.error(ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); | 408 window.console.error(ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); |
397 }, | 409 }, |
398 // No setter. | 410 // No setter. |
399 enumerable: true | 411 enumerable: true |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 /** | 451 /** |
440 * @private | 452 * @private |
441 */ | 453 */ |
442 WebViewInternal.prototype.handleWebviewAttributeMutation = | 454 WebViewInternal.prototype.handleWebviewAttributeMutation = |
443 function(name, oldValue, newValue) { | 455 function(name, oldValue, newValue) { |
444 // This observer monitors mutations to attributes of the <webview> and | 456 // This observer monitors mutations to attributes of the <webview> and |
445 // updates the BrowserPlugin properties accordingly. In turn, updating | 457 // updates the BrowserPlugin properties accordingly. In turn, updating |
446 // a BrowserPlugin property will update the corresponding BrowserPlugin | 458 // a BrowserPlugin property will update the corresponding BrowserPlugin |
447 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more | 459 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more |
448 // details. | 460 // details. |
449 if (name == 'src') { | 461 if (name == 'name') { |
450 // We treat null attribute (attribute removed) and the empty string as | 462 // We treat null attribute (attribute removed) and the empty string as |
451 // one case. | 463 // one case. |
452 oldValue = oldValue || ''; | 464 oldValue = oldValue || ''; |
| 465 newValue = newValue || ''; |
| 466 |
| 467 if (oldValue === newValue) { |
| 468 return; |
| 469 } |
| 470 this.name = newValue; |
| 471 if (!this.instanceId) { |
| 472 return; |
| 473 } |
| 474 WebView.setName(this.instanceId, newValue); |
| 475 return; |
| 476 } else if (name == 'src') { |
| 477 // We treat null attribute (attribute removed) and the empty string as |
| 478 // one case. |
| 479 oldValue = oldValue || ''; |
453 newValue = newValue || ''; | 480 newValue = newValue || ''; |
454 // Once we have navigated, we don't allow clearing the src attribute. | 481 // Once we have navigated, we don't allow clearing the src attribute. |
455 // Once <webview> enters a navigated state, it cannot be return back to a | 482 // Once <webview> enters a navigated state, it cannot be return back to a |
456 // placeholder state. | 483 // placeholder state. |
457 if (newValue == '' && oldValue != '') { | 484 if (newValue == '' && oldValue != '') { |
458 // src attribute changes normally initiate a navigation. We suppress | 485 // src attribute changes normally initiate a navigation. We suppress |
459 // the next src attribute handler call to avoid reloading the page | 486 // the next src attribute handler call to avoid reloading the page |
460 // on every guest-initiated navigation. | 487 // on every guest-initiated navigation. |
461 this.ignoreNextSrcAttributeChange = true; | 488 this.ignoreNextSrcAttributeChange = true; |
462 this.webviewNode.setAttribute('src', oldValue); | 489 this.webviewNode.setAttribute('src', oldValue); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
588 this.on = {}; | 615 this.on = {}; |
589 var events = self.getEvents(); | 616 var events = self.getEvents(); |
590 for (var eventName in events) { | 617 for (var eventName in events) { |
591 this.setupEventProperty(eventName); | 618 this.setupEventProperty(eventName); |
592 } | 619 } |
593 }; | 620 }; |
594 | 621 |
595 /** | 622 /** |
596 * @private | 623 * @private |
597 */ | 624 */ |
| 625 WebViewInternal.prototype.setupNameAttribute = function() { |
| 626 var self = this; |
| 627 FrameNameChangedEvent.addListener(function(event) { |
| 628 self.name = event.name || ''; |
| 629 if (self.name === '') { |
| 630 self.webviewNode.removeAttribute('name'); |
| 631 } else { |
| 632 self.webviewNode.setAttribute('name', self.name); |
| 633 } |
| 634 }, {instanceId: self.instanceId}); |
| 635 }; |
| 636 |
| 637 /** |
| 638 * @private |
| 639 */ |
598 WebViewInternal.prototype.setupEvent = function(eventName, eventInfo) { | 640 WebViewInternal.prototype.setupEvent = function(eventName, eventInfo) { |
599 var self = this; | 641 var self = this; |
600 var webviewNode = this.webviewNode; | 642 var webviewNode = this.webviewNode; |
601 eventInfo.evt.addListener(function(event) { | 643 eventInfo.evt.addListener(function(event) { |
602 var details = {bubbles:true}; | 644 var details = {bubbles:true}; |
603 if (eventInfo.cancelable) | 645 if (eventInfo.cancelable) |
604 details.cancelable = true; | 646 details.cancelable = true; |
605 var webViewEvent = new Event(eventName, details); | 647 var webViewEvent = new Event(eventName, details); |
606 $Array.forEach(eventInfo.fields, function(field) { | 648 $Array.forEach(eventInfo.fields, function(field) { |
607 if (event[field] !== undefined) { | 649 if (event[field] !== undefined) { |
(...skipping 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1017 return; | 1059 return; |
1018 } | 1060 } |
1019 WebView.overrideUserAgent(this.instanceId, userAgentOverride); | 1061 WebView.overrideUserAgent(this.instanceId, userAgentOverride); |
1020 }; | 1062 }; |
1021 | 1063 |
1022 /** @private */ | 1064 /** @private */ |
1023 WebViewInternal.prototype.attachWindowAndSetUpEvents = function(instanceId) { | 1065 WebViewInternal.prototype.attachWindowAndSetUpEvents = function(instanceId) { |
1024 this.instanceId = instanceId; | 1066 this.instanceId = instanceId; |
1025 var params = { | 1067 var params = { |
1026 'api': 'webview', | 1068 'api': 'webview', |
1027 'instanceId': this.viewInstanceId | 1069 'instanceId': this.viewInstanceId, |
| 1070 'name': this.name |
1028 }; | 1071 }; |
1029 if (this.userAgentOverride) { | 1072 if (this.userAgentOverride) { |
1030 params['userAgentOverride'] = this.userAgentOverride; | 1073 params['userAgentOverride'] = this.userAgentOverride; |
1031 } | 1074 } |
1032 this.browserPluginNode['-internal-attach'](this.instanceId, params); | 1075 this.setupNameAttribute(); |
1033 | |
1034 var events = this.getEvents(); | 1076 var events = this.getEvents(); |
1035 for (var eventName in events) { | 1077 for (var eventName in events) { |
1036 this.setupEvent(eventName, events[eventName]); | 1078 this.setupEvent(eventName, events[eventName]); |
1037 } | 1079 } |
| 1080 |
| 1081 this.browserPluginNode['-internal-attach'](this.instanceId, params); |
| 1082 |
1038 return true; | 1083 return true; |
1039 }; | 1084 }; |
1040 | 1085 |
1041 // Registers browser plugin <object> custom element. | 1086 // Registers browser plugin <object> custom element. |
1042 function registerBrowserPluginElement() { | 1087 function registerBrowserPluginElement() { |
1043 var proto = Object.create(HTMLObjectElement.prototype); | 1088 var proto = Object.create(HTMLObjectElement.prototype); |
1044 | 1089 |
1045 proto.createdCallback = function() { | 1090 proto.createdCallback = function() { |
1046 this.setAttribute('type', 'application/browser-plugin'); | 1091 this.setAttribute('type', 'application/browser-plugin'); |
1047 // The <object> node fills in the <webview> container. | 1092 // The <object> node fills in the <webview> container. |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1210 | 1255 |
1211 /** | 1256 /** |
1212 * Implemented when the experimental API is available. | 1257 * Implemented when the experimental API is available. |
1213 * @private | 1258 * @private |
1214 */ | 1259 */ |
1215 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; | 1260 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; |
1216 | 1261 |
1217 exports.WebView = WebView; | 1262 exports.WebView = WebView; |
1218 exports.WebViewInternal = WebViewInternal; | 1263 exports.WebViewInternal = WebViewInternal; |
1219 exports.CreateEvent = CreateEvent; | 1264 exports.CreateEvent = CreateEvent; |
OLD | NEW |