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 GuestViewInternal = | 10 var GuestViewInternal = |
11 require('binding').Binding.create('guestViewInternal').generate(); | 11 require('binding').Binding.create('guestViewInternal').generate(); |
12 var IdGenerator = requireNative('id_generator'); | 12 var IdGenerator = requireNative('id_generator'); |
13 // TODO(lazyboy): Rename this to WebViewInternal and call WebViewInternal | 13 // TODO(lazyboy): Rename this to WebViewInternal and call WebViewInternal |
14 // something else. | 14 // something else. |
15 var WebView = require('webViewInternal').WebView; | 15 var WebView = require('webViewInternal').WebView; |
16 var WebViewEvents = require('webViewEvents').WebViewEvents; | 16 var WebViewEvents = require('webViewEvents').WebViewEvents; |
17 | 17 |
| 18 var WEB_VIEW_ATTRIBUTE_AUTOSIZE = 'autosize'; |
18 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; | 19 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; |
19 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; | 20 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; |
20 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; | 21 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; |
21 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; | 22 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; |
| 23 var AUTO_SIZE_ATTRIBUTES = [ |
| 24 WEB_VIEW_ATTRIBUTE_AUTOSIZE, |
| 25 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, |
| 26 WEB_VIEW_ATTRIBUTE_MAXWIDTH, |
| 27 WEB_VIEW_ATTRIBUTE_MINHEIGHT, |
| 28 WEB_VIEW_ATTRIBUTE_MINWIDTH |
| 29 ]; |
| 30 |
22 var WEB_VIEW_ATTRIBUTE_PARTITION = 'partition'; | 31 var WEB_VIEW_ATTRIBUTE_PARTITION = 'partition'; |
23 | 32 |
24 var PLUGIN_METHOD_ATTACH = '-internal-attach'; | 33 var PLUGIN_METHOD_ATTACH = '-internal-attach'; |
25 | 34 |
26 var ERROR_MSG_ALREADY_NAVIGATED = | 35 var ERROR_MSG_ALREADY_NAVIGATED = |
27 'The object has already navigated, so its partition cannot be changed.'; | 36 'The object has already navigated, so its partition cannot be changed.'; |
28 var ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.'; | 37 var ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = 'Invalid partition attribute.'; |
29 | 38 |
30 /** @type {Array.<string>} */ | 39 /** @type {Array.<string>} */ |
31 var WEB_VIEW_ATTRIBUTES = [ | 40 var WEB_VIEW_ATTRIBUTES = [ |
32 'allowtransparency', | 41 'allowtransparency', |
33 'autosize', | |
34 WEB_VIEW_ATTRIBUTE_MINHEIGHT, | |
35 WEB_VIEW_ATTRIBUTE_MINWIDTH, | |
36 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, | |
37 WEB_VIEW_ATTRIBUTE_MAXWIDTH | |
38 ]; | 42 ]; |
39 | 43 |
40 /** @class representing state of storage partition. */ | 44 /** @class representing state of storage partition. */ |
41 function Partition() { | 45 function Partition() { |
42 this.validPartitionId = true; | 46 this.validPartitionId = true; |
43 this.persistStorage = false; | 47 this.persistStorage = false; |
44 this.storagePartitionId = ''; | 48 this.storagePartitionId = ''; |
45 }; | 49 }; |
46 | 50 |
47 Partition.prototype.toAttribute = function() { | 51 Partition.prototype.toAttribute = function() { |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 /** | 311 /** |
308 * @private | 312 * @private |
309 */ | 313 */ |
310 WebViewInternal.prototype.insertCSS = function(var_args) { | 314 WebViewInternal.prototype.insertCSS = function(var_args) { |
311 this.validateExecuteCodeCall(); | 315 this.validateExecuteCodeCall(); |
312 var args = $Array.concat([this.instanceId, this.src], | 316 var args = $Array.concat([this.instanceId, this.src], |
313 $Array.slice(arguments)); | 317 $Array.slice(arguments)); |
314 $Function.apply(WebView.insertCSS, null, args); | 318 $Function.apply(WebView.insertCSS, null, args); |
315 }; | 319 }; |
316 | 320 |
| 321 WebViewInternal.prototype.setupAutoSizeProperties = function() { |
| 322 var self = this; |
| 323 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { |
| 324 this[attributeName] = this.webviewNode.getAttribute(attributeName); |
| 325 Object.defineProperty(this.webviewNode, attributeName, { |
| 326 get: function() { |
| 327 return self[attributeName]; |
| 328 }, |
| 329 set: function(value) { |
| 330 self.webviewNode.setAttribute(attributeName, value); |
| 331 }, |
| 332 enumerable: true |
| 333 }); |
| 334 }, this); |
| 335 }; |
| 336 |
317 /** | 337 /** |
318 * @private | 338 * @private |
319 */ | 339 */ |
320 WebViewInternal.prototype.setupWebviewNodeProperties = function() { | 340 WebViewInternal.prototype.setupWebviewNodeProperties = function() { |
321 var ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' + | 341 var ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE = '<webview>: ' + |
322 'contentWindow is not available at this time. It will become available ' + | 342 'contentWindow is not available at this time. It will become available ' + |
323 'when the page has finished loading.'; | 343 'when the page has finished loading.'; |
324 | 344 |
| 345 this.setupAutoSizeProperties(); |
325 var self = this; | 346 var self = this; |
326 var browserPluginNode = this.browserPluginNode; | 347 var browserPluginNode = this.browserPluginNode; |
327 // Expose getters and setters for the attributes. | 348 // Expose getters and setters for the attributes. |
328 $Array.forEach(WEB_VIEW_ATTRIBUTES, function(attributeName) { | 349 $Array.forEach(WEB_VIEW_ATTRIBUTES, function(attributeName) { |
329 Object.defineProperty(this.webviewNode, attributeName, { | 350 Object.defineProperty(this.webviewNode, attributeName, { |
330 get: function() { | 351 get: function() { |
331 if (browserPluginNode.hasOwnProperty(attributeName)) { | 352 if (browserPluginNode.hasOwnProperty(attributeName)) { |
332 return browserPluginNode[attributeName]; | 353 return browserPluginNode[attributeName]; |
333 } else { | 354 } else { |
334 return browserPluginNode.getAttribute(attributeName); | 355 return browserPluginNode.getAttribute(attributeName); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
438 /** | 459 /** |
439 * @private | 460 * @private |
440 */ | 461 */ |
441 WebViewInternal.prototype.handleWebviewAttributeMutation = | 462 WebViewInternal.prototype.handleWebviewAttributeMutation = |
442 function(name, oldValue, newValue) { | 463 function(name, oldValue, newValue) { |
443 // This observer monitors mutations to attributes of the <webview> and | 464 // This observer monitors mutations to attributes of the <webview> and |
444 // updates the BrowserPlugin properties accordingly. In turn, updating | 465 // updates the BrowserPlugin properties accordingly. In turn, updating |
445 // a BrowserPlugin property will update the corresponding BrowserPlugin | 466 // a BrowserPlugin property will update the corresponding BrowserPlugin |
446 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more | 467 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more |
447 // details. | 468 // details. |
448 if (name == 'name') { | 469 if (AUTO_SIZE_ATTRIBUTES.indexOf(name) > -1) { |
| 470 this[name] = newValue; |
| 471 if (!this.instanceId) { |
| 472 return; |
| 473 } |
| 474 // Convert autosize attribute to boolean. |
| 475 var autosize = this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE); |
| 476 GuestViewInternal.setAutoSize(this.instanceId, { |
| 477 'enableAutoSize': autosize, |
| 478 'min': { |
| 479 'width': parseInt(this.minwidth || 0), |
| 480 'height': parseInt(this.minheight || 0) |
| 481 }, |
| 482 'max': { |
| 483 'width': parseInt(this.maxwidth || 0), |
| 484 'height': parseInt(this.maxheight || 0) |
| 485 } |
| 486 }); |
| 487 return; |
| 488 } else if (name == 'name') { |
449 // We treat null attribute (attribute removed) and the empty string as | 489 // We treat null attribute (attribute removed) and the empty string as |
450 // one case. | 490 // one case. |
451 oldValue = oldValue || ''; | 491 oldValue = oldValue || ''; |
452 newValue = newValue || ''; | 492 newValue = newValue || ''; |
453 | 493 |
454 if (oldValue === newValue) { | 494 if (oldValue === newValue) { |
455 return; | 495 return; |
456 } | 496 } |
457 this.name = newValue; | 497 this.name = newValue; |
458 if (!this.instanceId) { | 498 if (!this.instanceId) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 if (newValue != this.webviewNode.getAttribute(name)) { | 583 if (newValue != this.webviewNode.getAttribute(name)) { |
544 this.webviewNode.setAttribute(name, newValue); | 584 this.webviewNode.setAttribute(name, newValue); |
545 } | 585 } |
546 } else { | 586 } else { |
547 // If an attribute is removed from the BrowserPlugin, then remove it | 587 // If an attribute is removed from the BrowserPlugin, then remove it |
548 // from the <webview> as well. | 588 // from the <webview> as well. |
549 this.webviewNode.removeAttribute(name); | 589 this.webviewNode.removeAttribute(name); |
550 } | 590 } |
551 }; | 591 }; |
552 | 592 |
553 WebViewInternal.prototype.onSizeChanged = function(newWidth, newHeight) { | 593 WebViewInternal.prototype.onSizeChanged = function(webViewEvent) { |
| 594 var newWidth = webViewEvent.newWidth; |
| 595 var newHeight = webViewEvent.newHeight; |
| 596 |
554 var node = this.webviewNode; | 597 var node = this.webviewNode; |
555 | 598 |
556 var width = node.offsetWidth; | 599 var width = node.offsetWidth; |
557 var height = node.offsetHeight; | 600 var height = node.offsetHeight; |
558 | 601 |
559 // Check the current bounds to make sure we do not resize <webview> | 602 // Check the current bounds to make sure we do not resize <webview> |
560 // outside of current constraints. | 603 // outside of current constraints. |
561 var maxWidth; | 604 var maxWidth; |
562 if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXWIDTH) && | 605 if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MAXWIDTH) && |
563 node[WEB_VIEW_ATTRIBUTE_MAXWIDTH]) { | 606 node[WEB_VIEW_ATTRIBUTE_MAXWIDTH]) { |
(...skipping 24 matching lines...) Expand all Loading... |
588 if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINHEIGHT) && | 631 if (node.hasAttribute(WEB_VIEW_ATTRIBUTE_MINHEIGHT) && |
589 node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]) { | 632 node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]) { |
590 minHeight = node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]; | 633 minHeight = node[WEB_VIEW_ATTRIBUTE_MINHEIGHT]; |
591 } else { | 634 } else { |
592 minHeight = height; | 635 minHeight = height; |
593 } | 636 } |
594 if (minHeight > maxHeight) { | 637 if (minHeight > maxHeight) { |
595 minHeight = maxHeight; | 638 minHeight = maxHeight; |
596 } | 639 } |
597 | 640 |
598 if (newWidth >= minWidth && | 641 if (!this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE) || |
599 newWidth <= maxWidth && | 642 (newWidth >= minWidth && |
600 newHeight >= minHeight && | 643 newWidth <= maxWidth && |
601 newHeight <= maxHeight) { | 644 newHeight >= minHeight && |
| 645 newHeight <= maxHeight)) { |
602 node.style.width = newWidth + 'px'; | 646 node.style.width = newWidth + 'px'; |
603 node.style.height = newHeight + 'px'; | 647 node.style.height = newHeight + 'px'; |
| 648 // Only fire the DOM event if the size of the <webview> has actually |
| 649 // changed. |
| 650 this.dispatchEvent(webViewEvent); |
604 } | 651 } |
605 }; | 652 }; |
606 | 653 |
607 // Returns true if Browser Plugin bindings is available. | 654 // Returns true if Browser Plugin bindings is available. |
608 // Bindings are unavailable if <object> is not in the render tree. | 655 // Bindings are unavailable if <object> is not in the render tree. |
609 WebViewInternal.prototype.hasBindings = function() { | 656 WebViewInternal.prototype.hasBindings = function() { |
610 return 'function' == typeof this.browserPluginNode[PLUGIN_METHOD_ATTACH]; | 657 return 'function' == typeof this.browserPluginNode[PLUGIN_METHOD_ATTACH]; |
611 }; | 658 }; |
612 | 659 |
613 WebViewInternal.prototype.hasNavigated = function() { | 660 WebViewInternal.prototype.hasNavigated = function() { |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
776 | 823 |
777 WebViewInternal.prototype.getZoom = function(callback) { | 824 WebViewInternal.prototype.getZoom = function(callback) { |
778 if (!this.instanceId) { | 825 if (!this.instanceId) { |
779 return; | 826 return; |
780 } | 827 } |
781 WebView.getZoom(this.instanceId, callback); | 828 WebView.getZoom(this.instanceId, callback); |
782 }; | 829 }; |
783 | 830 |
784 WebViewInternal.prototype.buildAttachParams = function(isNewWindow) { | 831 WebViewInternal.prototype.buildAttachParams = function(isNewWindow) { |
785 var params = { | 832 var params = { |
786 'api': 'webview', | 833 'autosize': this.webviewNode.hasAttribute(WEB_VIEW_ATTRIBUTE_AUTOSIZE), |
787 'instanceId': this.viewInstanceId, | 834 'instanceId': this.viewInstanceId, |
| 835 'maxheight': parseInt(this.maxheight || 0), |
| 836 'maxwidth': parseInt(this.maxwidth || 0), |
| 837 'minheight': parseInt(this.minheight || 0), |
| 838 'minwidth': parseInt(this.minwidth || 0), |
788 'name': this.name, | 839 'name': this.name, |
789 // We don't need to navigate new window from here. | 840 // We don't need to navigate new window from here. |
790 'src': isNewWindow ? undefined : this.src, | 841 'src': isNewWindow ? undefined : this.src, |
791 // If we have a partition from the opener, that will also be already | 842 // If we have a partition from the opener, that will also be already |
792 // set via this.onAttach(). | 843 // set via this.onAttach(). |
793 'storagePartitionId': this.partition.toAttribute(), | 844 'storagePartitionId': this.partition.toAttribute(), |
794 'userAgentOverride': this.userAgentOverride | 845 'userAgentOverride': this.userAgentOverride |
795 }; | 846 }; |
796 return params; | 847 return params; |
797 }; | 848 }; |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
962 }; | 1013 }; |
963 | 1014 |
964 /** | 1015 /** |
965 * Implemented when the experimental API is available. | 1016 * Implemented when the experimental API is available. |
966 * @private | 1017 * @private |
967 */ | 1018 */ |
968 WebViewInternal.prototype.setupExperimentalContextMenus = function() {}; | 1019 WebViewInternal.prototype.setupExperimentalContextMenus = function() {}; |
969 | 1020 |
970 exports.WebView = WebView; | 1021 exports.WebView = WebView; |
971 exports.WebViewInternal = WebViewInternal; | 1022 exports.WebViewInternal = WebViewInternal; |
OLD | NEW |