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
3 // found in the LICENSE file.
5 // This module implements WebView (<webview>) as a custom element that wraps a
6 // BrowserPlugin object element. The object element is hidden within
7 // the shadow DOM of the WebView element.
9 var DocumentNatives = requireNative('document_natives');
10 var GuestView = require('guestView').GuestView;
11 var GuestViewContainer = require('guestViewContainer').GuestViewContainer;
12 var GuestViewInternalNatives = requireNative('guest_view_internal');
13 var WebViewConstants = require('webViewConstants').WebViewConstants;
14 var WebViewEvents = require('webViewEvents').WebViewEvents;
15 var WebViewInternal = require('webViewInternal').WebViewInternal;
17 // Represents the internal state of <webview>.
18 function WebViewImpl(webviewElement) {
19 GuestViewContainer.call(this, webviewElement, 'webview');
21 this.setupElementProperties();
22 new WebViewEvents(this, this.viewInstanceId);
25 WebViewImpl.prototype.__proto__ = GuestViewContainer.prototype;
27 WebViewImpl.VIEW_TYPE = 'WebView';
29 // Add extra functionality to |this.element|.
30 WebViewImpl.setupElement = function(proto) {
31 // Public-facing API methods.
32 var apiMethods = WebViewImpl.getApiMethods();
34 // Create default implementations for undefined API methods.
35 var createDefaultApiMethod = function(m) {
36 return function(var_args) {
37 if (!this.guest.getId()) {
40 var args = $Array.concat([this.guest.getId()], $Array.slice(arguments));
41 $Function.apply(WebViewInternal[m], null, args);
45 for (var i = 0; i != apiMethods.length; ++i) {
46 if (WebViewImpl.prototype[apiMethods[i]] == undefined) {
47 WebViewImpl.prototype[apiMethods[i]] =
48 createDefaultApiMethod(apiMethods[i]);
52 // Forward proto.foo* method calls to WebViewImpl.foo*.
53 GuestViewContainer.forwardApiMethods(proto, apiMethods);
56 // Initiates navigation once the <webview> element is attached to the DOM.
57 WebViewImpl.prototype.onElementAttached = function() {
58 for (var i in this.attributes) {
59 this.attributes[i].attach();
63 // Resets some state upon detaching <webview> element from the DOM.
64 WebViewImpl.prototype.onElementDetached = function() {
66 for (var i in this.attributes) {
67 this.attributes[i].detach();
71 // Sets the <webview>.request property.
72 WebViewImpl.prototype.setRequestPropertyOnWebViewElement = function(request) {
73 Object.defineProperty(
83 WebViewImpl.prototype.setupElementProperties = function() {
84 // We cannot use {writable: true} property descriptor because we want a
85 // dynamic getter value.
86 Object.defineProperty(this.element, 'contentWindow', {
88 if (this.guest.getContentWindow()) {
89 return this.guest.getContentWindow();
92 WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE);
99 WebViewImpl.prototype.onSizeChanged = function(webViewEvent) {
100 var newWidth = webViewEvent.newWidth;
101 var newHeight = webViewEvent.newHeight;
103 var element = this.element;
105 var width = element.offsetWidth;
106 var height = element.offsetHeight;
108 // Check the current bounds to make sure we do not resize <webview>
109 // outside of current constraints.
110 var maxWidth = this.attributes[
111 WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || width;
112 var minWidth = this.attributes[
113 WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || width;
114 var maxHeight = this.attributes[
115 WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || height;
116 var minHeight = this.attributes[
117 WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || height;
119 minWidth = Math.min(minWidth, maxWidth);
120 minHeight = Math.min(minHeight, maxHeight);
122 if (!this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue() ||
123 (newWidth >= minWidth &&
124 newWidth <= maxWidth &&
125 newHeight >= minHeight &&
126 newHeight <= maxHeight)) {
127 element.style.width = newWidth + 'px';
128 element.style.height = newHeight + 'px';
129 // Only fire the DOM event if the size of the <webview> has actually
131 this.dispatchEvent(webViewEvent);
135 WebViewImpl.prototype.createGuest = function() {
136 this.guest.create(this.buildParams(), function() {
141 WebViewImpl.prototype.onFrameNameChanged = function(name) {
142 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValueIgnoreMutation(name);
145 // Updates state upon loadcommit.
146 WebViewImpl.prototype.onLoadCommit = function(
147 baseUrlForDataUrl, currentEntryIndex, entryCount,
148 processId, url, isTopLevel) {
149 this.baseUrlForDataUrl = baseUrlForDataUrl;
150 this.currentEntryIndex = currentEntryIndex;
151 this.entryCount = entryCount;
152 this.processId = processId;
154 // Touching the src attribute triggers a navigation. To avoid
155 // triggering a page reload on every guest-initiated navigation,
156 // we do not handle this mutation.
158 WebViewConstants.ATTRIBUTE_SRC].setValueIgnoreMutation(url);
162 WebViewImpl.prototype.onAttach = function(storagePartitionId) {
163 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValueIgnoreMutation(
167 WebViewImpl.prototype.buildContainerParams = function() {
168 var params = { 'userAgentOverride': this.userAgentOverride };
169 for (var i in this.attributes) {
170 params[i] = this.attributes[i].getValue();
175 WebViewImpl.prototype.attachWindow = function(opt_guestInstanceId) {
176 // If |opt_guestInstanceId| was provided, then a different existing guest is
177 // being attached to this webview, and the current one will get destroyed.
178 if (opt_guestInstanceId) {
179 if (this.guest.getId() == opt_guestInstanceId) {
182 this.guest.destroy();
183 this.guest = new GuestView('webview', opt_guestInstanceId);
186 return GuestViewContainer.prototype.attachWindow.call(this);
189 // Shared implementation of executeScript() and insertCSS().
190 WebViewImpl.prototype.executeCode = function(func, args) {
191 if (!this.guest.getId()) {
192 window.console.error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT);
196 var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue();
197 if (this.baseUrlForDataUrl) {
198 webviewSrc = this.baseUrlForDataUrl;
201 args = $Array.concat([this.guest.getId(), webviewSrc],
203 $Function.apply(func, null, args);
207 // Requests the <webview> element wihtin the embedder to enter fullscreen.
208 WebViewImpl.prototype.makeElementFullscreen = function() {
209 GuestViewInternalNatives.RunWithGesture(function() {
210 this.element.webkitRequestFullScreen();
214 // Implemented when the ChromeWebView API is available.
215 WebViewImpl.prototype.maybeSetupContextMenus = function() {};
217 GuestViewContainer.registerElement(WebViewImpl);
220 exports.WebViewImpl = WebViewImpl;