| 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 = |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 // Implemented when the experimental API is available. | 80 // Implemented when the experimental API is available. |
| 81 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} | 81 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} |
| 82 | 82 |
| 83 /** | 83 /** |
| 84 * @constructor | 84 * @constructor |
| 85 */ | 85 */ |
| 86 function WebViewInternal(webviewNode) { | 86 function WebViewInternal(webviewNode) { |
| 87 privates(webviewNode).internal = this; | 87 privates(webviewNode).internal = this; |
| 88 this.webviewNode = webviewNode; | 88 this.webviewNode = webviewNode; |
| 89 this.attached = false; | 89 this.attached = false; |
| 90 this.pendingGuestCreation = false; |
| 90 this.elementAttached = false; | 91 this.elementAttached = false; |
| 91 | 92 |
| 92 this.beforeFirstNavigation = true; | 93 this.beforeFirstNavigation = true; |
| 93 this.contentWindow = null; | 94 this.contentWindow = null; |
| 94 this.validPartitionId = true; | 95 this.validPartitionId = true; |
| 95 // Used to save some state upon deferred attachment. | 96 // Used to save some state upon deferred attachment. |
| 96 // If <object> bindings is not available, we defer attachment. | 97 // If <object> bindings is not available, we defer attachment. |
| 97 // This state contains whether or not the attachment request was for | 98 // This state contains whether or not the attachment request was for |
| 98 // newwindow. | 99 // newwindow. |
| 99 this.deferredAttachState = null; | 100 this.deferredAttachState = null; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 * Resets some state upon reattaching <webview> element to the DOM. | 136 * Resets some state upon reattaching <webview> element to the DOM. |
| 136 */ | 137 */ |
| 137 WebViewInternal.prototype.reset = function() { | 138 WebViewInternal.prototype.reset = function() { |
| 138 // If guestInstanceId is defined then the <webview> has navigated and has | 139 // If guestInstanceId is defined then the <webview> has navigated and has |
| 139 // already picked up a partition ID. Thus, we need to reset the initialization | 140 // already picked up a partition ID. Thus, we need to reset the initialization |
| 140 // state. However, it may be the case that beforeFirstNavigation is false BUT | 141 // state. However, it may be the case that beforeFirstNavigation is false BUT |
| 141 // guestInstanceId has yet to be initialized. This means that we have not | 142 // guestInstanceId has yet to be initialized. This means that we have not |
| 142 // heard back from createGuest yet. We will not reset the flag in this case so | 143 // heard back from createGuest yet. We will not reset the flag in this case so |
| 143 // that we don't end up allocating a second guest. | 144 // that we don't end up allocating a second guest. |
| 144 if (this.guestInstanceId) { | 145 if (this.guestInstanceId) { |
| 146 GuestViewInternal.destroyGuest(this.guestInstanceId); |
| 145 this.guestInstanceId = undefined; | 147 this.guestInstanceId = undefined; |
| 146 this.beforeFirstNavigation = true; | 148 this.beforeFirstNavigation = true; |
| 147 this.validPartitionId = true; | 149 this.validPartitionId = true; |
| 148 this.partition.validPartitionId = true; | 150 this.partition.validPartitionId = true; |
| 149 this.contentWindow = null; | 151 this.contentWindow = null; |
| 150 } | 152 } |
| 151 this.internalInstanceId = 0; | 153 this.internalInstanceId = 0; |
| 152 }; | 154 }; |
| 153 | 155 |
| 154 // Sets <webview>.request property. | 156 // Sets <webview>.request property. |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 535 | 537 |
| 536 /** | 538 /** |
| 537 * @private | 539 * @private |
| 538 */ | 540 */ |
| 539 WebViewInternal.prototype.handleBrowserPluginAttributeMutation = | 541 WebViewInternal.prototype.handleBrowserPluginAttributeMutation = |
| 540 function(name, oldValue, newValue) { | 542 function(name, oldValue, newValue) { |
| 541 if (name == 'internalinstanceid' && !oldValue && !!newValue) { | 543 if (name == 'internalinstanceid' && !oldValue && !!newValue) { |
| 542 this.browserPluginNode.removeAttribute('internalinstanceid'); | 544 this.browserPluginNode.removeAttribute('internalinstanceid'); |
| 543 this.internalInstanceId = parseInt(newValue); | 545 this.internalInstanceId = parseInt(newValue); |
| 544 | 546 |
| 545 if (!this.deferredAttachState) { | |
| 546 this.parseAttributes(); | |
| 547 return; | |
| 548 } | |
| 549 | |
| 550 if (!!this.guestInstanceId && this.guestInstanceId != 0) { | 547 if (!!this.guestInstanceId && this.guestInstanceId != 0) { |
| 551 window.setTimeout(function() { | 548 var isNewWindow = this.deferredAttachState ? |
| 552 var isNewWindow = this.deferredAttachState ? | 549 this.deferredAttachState.isNewWindow : false; |
| 553 this.deferredAttachState.isNewWindow : false; | 550 var params = this.buildAttachParams(isNewWindow); |
| 554 var params = this.buildAttachParams(isNewWindow); | 551 guestViewInternalNatives.AttachGuest( |
| 555 guestViewInternalNatives.AttachGuest( | 552 this.internalInstanceId, |
| 556 this.internalInstanceId, | 553 this.guestInstanceId, |
| 557 this.guestInstanceId, | 554 params, |
| 558 params, | 555 function(w) { |
| 559 function(w) { | 556 this.contentWindow = w; |
| 560 this.contentWindow = w; | 557 }.bind(this) |
| 561 }.bind(this) | 558 ); |
| 562 ); | |
| 563 }.bind(this), 0); | |
| 564 } | 559 } |
| 565 | 560 |
| 566 return; | 561 return; |
| 567 } | 562 } |
| 568 }; | 563 }; |
| 569 | 564 |
| 570 WebViewInternal.prototype.onSizeChanged = function(webViewEvent) { | 565 WebViewInternal.prototype.onSizeChanged = function(webViewEvent) { |
| 571 var newWidth = webViewEvent.newWidth; | 566 var newWidth = webViewEvent.newWidth; |
| 572 var newHeight = webViewEvent.newHeight; | 567 var newHeight = webViewEvent.newHeight; |
| 573 | 568 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 }; | 629 }; |
| 635 | 630 |
| 636 WebViewInternal.prototype.hasNavigated = function() { | 631 WebViewInternal.prototype.hasNavigated = function() { |
| 637 return !this.beforeFirstNavigation; | 632 return !this.beforeFirstNavigation; |
| 638 }; | 633 }; |
| 639 | 634 |
| 640 /** @return {boolean} */ | 635 /** @return {boolean} */ |
| 641 WebViewInternal.prototype.parseSrcAttribute = function(result) { | 636 WebViewInternal.prototype.parseSrcAttribute = function(result) { |
| 642 if (!this.partition.validPartitionId) { | 637 if (!this.partition.validPartitionId) { |
| 643 result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | 638 result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; |
| 644 return false; | 639 return; |
| 645 } | 640 } |
| 646 this.src = this.webviewNode.getAttribute('src'); | 641 this.src = this.webviewNode.getAttribute('src'); |
| 647 | 642 |
| 648 if (!this.src) { | 643 if (!this.src) { |
| 649 return true; | 644 return; |
| 650 } | |
| 651 | |
| 652 if (!this.elementAttached) { | |
| 653 return true; | |
| 654 } | 645 } |
| 655 | 646 |
| 656 if (!this.hasGuestInstanceID()) { | 647 if (!this.hasGuestInstanceID()) { |
| 657 if (this.beforeFirstNavigation) { | 648 if (this.beforeFirstNavigation) { |
| 658 this.beforeFirstNavigation = false; | 649 this.beforeFirstNavigation = false; |
| 659 this.allocateInstanceId(); | 650 this.createGuest(); |
| 660 } | 651 } |
| 661 return true; | 652 return; |
| 662 } | 653 } |
| 663 | 654 |
| 664 // Navigate to this.src. | 655 // Navigate to this.src. |
| 665 WebView.navigate(this.guestInstanceId, this.src); | 656 WebView.navigate(this.guestInstanceId, this.src); |
| 666 return true; | 657 return true; |
| 667 }; | 658 }; |
| 668 | 659 |
| 669 /** @return {boolean} */ | 660 /** @return {boolean} */ |
| 670 WebViewInternal.prototype.parseAttributes = function() { | 661 WebViewInternal.prototype.parseAttributes = function() { |
| 662 if (!this.elementAttached) { |
| 663 return; |
| 664 } |
| 671 var hasNavigated = this.hasNavigated(); | 665 var hasNavigated = this.hasNavigated(); |
| 672 var attributeValue = this.webviewNode.getAttribute('partition'); | 666 var attributeValue = this.webviewNode.getAttribute('partition'); |
| 673 var result = this.partition.fromAttribute(attributeValue, hasNavigated); | 667 var result = this.partition.fromAttribute(attributeValue, hasNavigated); |
| 674 return this.parseSrcAttribute(result); | 668 this.parseSrcAttribute(result); |
| 675 }; | 669 }; |
| 676 | 670 |
| 677 WebViewInternal.prototype.hasGuestInstanceID = function() { | 671 WebViewInternal.prototype.hasGuestInstanceID = function() { |
| 678 return this.guestInstanceId != undefined; | 672 return this.guestInstanceId != undefined; |
| 679 }; | 673 }; |
| 680 | 674 |
| 681 WebViewInternal.prototype.allocateInstanceId = function() { | 675 WebViewInternal.prototype.createGuest = function() { |
| 676 if (this.pendingGuestCreation) { |
| 677 return; |
| 678 } |
| 682 var storagePartitionId = | 679 var storagePartitionId = |
| 683 this.webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) || | 680 this.webviewNode.getAttribute(WEB_VIEW_ATTRIBUTE_PARTITION) || |
| 684 this.webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION]; | 681 this.webviewNode[WEB_VIEW_ATTRIBUTE_PARTITION]; |
| 685 var params = { | 682 var params = { |
| 686 'storagePartitionId': storagePartitionId, | 683 'storagePartitionId': storagePartitionId, |
| 687 }; | 684 }; |
| 688 GuestViewInternal.createGuest( | 685 GuestViewInternal.createGuest( |
| 689 'webview', | 686 'webview', |
| 690 params, | 687 params, |
| 691 function(guestInstanceId) { | 688 function(guestInstanceId) { |
| 689 this.pendingGuestCreation = false; |
| 690 if (!this.elementAttached) { |
| 691 GuestViewInternal.destroyGuest(this.guestInstanceId); |
| 692 return; |
| 693 } |
| 692 this.attachWindow(guestInstanceId, false); | 694 this.attachWindow(guestInstanceId, false); |
| 693 }.bind(this) | 695 }.bind(this) |
| 694 ); | 696 ); |
| 697 this.pendingGuestCreation = true; |
| 695 }; | 698 }; |
| 696 | 699 |
| 697 WebViewInternal.prototype.onFrameNameChanged = function(name) { | 700 WebViewInternal.prototype.onFrameNameChanged = function(name) { |
| 698 this.name = name || ''; | 701 this.name = name || ''; |
| 699 if (this.name === '') { | 702 if (this.name === '') { |
| 700 this.webviewNode.removeAttribute('name'); | 703 this.webviewNode.removeAttribute('name'); |
| 701 } else { | 704 } else { |
| 702 this.webviewNode.setAttribute('name', this.name); | 705 this.webviewNode.setAttribute('name', this.name); |
| 703 } | 706 } |
| 704 }; | 707 }; |
| 705 | 708 |
| 706 WebViewInternal.prototype.onPluginDestroyed = function() { | |
| 707 this.reset(); | |
| 708 }; | |
| 709 | |
| 710 WebViewInternal.prototype.dispatchEvent = function(webViewEvent) { | 709 WebViewInternal.prototype.dispatchEvent = function(webViewEvent) { |
| 711 return this.webviewNode.dispatchEvent(webViewEvent); | 710 return this.webviewNode.dispatchEvent(webViewEvent); |
| 712 }; | 711 }; |
| 713 | 712 |
| 714 /** | 713 /** |
| 715 * Adds an 'on<event>' property on the webview, which can be used to set/unset | 714 * Adds an 'on<event>' property on the webview, which can be used to set/unset |
| 716 * an event handler. | 715 * an event handler. |
| 717 */ | 716 */ |
| 718 WebViewInternal.prototype.setupEventProperty = function(eventName) { | 717 WebViewInternal.prototype.setupEventProperty = function(eventName) { |
| 719 var propertyName = 'on' + eventName.toLowerCase(); | 718 var propertyName = 'on' + eventName.toLowerCase(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 749 this.ignoreNextSrcAttributeChange = true; | 748 this.ignoreNextSrcAttributeChange = true; |
| 750 this.webviewNode.setAttribute('src', newValue); | 749 this.webviewNode.setAttribute('src', newValue); |
| 751 } | 750 } |
| 752 }; | 751 }; |
| 753 | 752 |
| 754 WebViewInternal.prototype.onAttach = function(storagePartitionId) { | 753 WebViewInternal.prototype.onAttach = function(storagePartitionId) { |
| 755 this.webviewNode.setAttribute('partition', storagePartitionId); | 754 this.webviewNode.setAttribute('partition', storagePartitionId); |
| 756 this.partition.fromAttribute(storagePartitionId, this.hasNavigated()); | 755 this.partition.fromAttribute(storagePartitionId, this.hasNavigated()); |
| 757 }; | 756 }; |
| 758 | 757 |
| 759 | |
| 760 /** @private */ | 758 /** @private */ |
| 761 WebViewInternal.prototype.getUserAgent = function() { | 759 WebViewInternal.prototype.getUserAgent = function() { |
| 762 return this.userAgentOverride || navigator.userAgent; | 760 return this.userAgentOverride || navigator.userAgent; |
| 763 }; | 761 }; |
| 764 | 762 |
| 765 /** @private */ | 763 /** @private */ |
| 766 WebViewInternal.prototype.isUserAgentOverridden = function() { | 764 WebViewInternal.prototype.isUserAgentOverridden = function() { |
| 767 return !!this.userAgentOverride && | 765 return !!this.userAgentOverride && |
| 768 this.userAgentOverride != navigator.userAgent; | 766 this.userAgentOverride != navigator.userAgent; |
| 769 }; | 767 }; |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 | 998 |
| 1001 /** | 999 /** |
| 1002 * Implemented when the experimental API is available. | 1000 * Implemented when the experimental API is available. |
| 1003 * @private | 1001 * @private |
| 1004 */ | 1002 */ |
| 1005 WebViewInternal.prototype.setupExperimentalContextMenus = function() { | 1003 WebViewInternal.prototype.setupExperimentalContextMenus = function() { |
| 1006 }; | 1004 }; |
| 1007 | 1005 |
| 1008 exports.WebView = WebView; | 1006 exports.WebView = WebView; |
| 1009 exports.WebViewInternal = WebViewInternal; | 1007 exports.WebViewInternal = WebViewInternal; |
| OLD | NEW |