1 // Copyright (c) 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.
5 // This module implements the attributes of the <webview> tag.
7 var GuestViewInternal =
8 require('binding').Binding.create('guestViewInternal').generate();
9 var WebViewImpl = require('webView').WebViewImpl;
10 var WebViewConstants = require('webViewConstants').WebViewConstants;
11 var WebViewInternal = require('webViewInternal').WebViewInternal;
13 // -----------------------------------------------------------------------------
16 // Default implementation of a WebView attribute.
17 function WebViewAttribute(name, webViewImpl) {
19 this.webViewImpl = webViewImpl;
20 this.ignoreMutation = false;
22 this.defineProperty();
25 // Retrieves and returns the attribute's value.
26 WebViewAttribute.prototype.getValue = function() {
27 return this.webViewImpl.element.getAttribute(this.name) || '';
30 // Sets the attribute's value.
31 WebViewAttribute.prototype.setValue = function(value) {
32 this.webViewImpl.element.setAttribute(this.name, value || '');
35 // Changes the attribute's value without triggering its mutation handler.
36 WebViewAttribute.prototype.setValueIgnoreMutation = function(value) {
37 this.ignoreMutation = true;
38 this.webViewImpl.element.setAttribute(this.name, value || '');
39 this.ignoreMutation = false;
42 // Defines this attribute as a property on the webview node.
43 WebViewAttribute.prototype.defineProperty = function() {
44 Object.defineProperty(this.webViewImpl.element, this.name, {
46 return this.getValue();
48 set: function(value) {
55 // Called when the attribute's value changes.
56 WebViewAttribute.prototype.handleMutation = function(oldValue, newValue) {};
58 // An attribute that is treated as a Boolean.
59 function BooleanAttribute(name, webViewImpl) {
60 WebViewAttribute.call(this, name, webViewImpl);
63 BooleanAttribute.prototype.__proto__ = WebViewAttribute.prototype;
65 BooleanAttribute.prototype.getValue = function() {
66 return this.webViewImpl.element.hasAttribute(this.name);
69 BooleanAttribute.prototype.setValue = function(value) {
71 this.webViewImpl.element.removeAttribute(this.name);
73 this.webViewImpl.element.setAttribute(this.name, '');
77 // Attribute that specifies whether transparency is allowed in the webview.
78 function AllowTransparencyAttribute(webViewImpl) {
79 BooleanAttribute.call(
80 this, WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, webViewImpl);
83 AllowTransparencyAttribute.prototype.__proto__ = BooleanAttribute.prototype;
85 AllowTransparencyAttribute.prototype.handleMutation = function(oldValue,
87 if (!this.webViewImpl.guest.getId()) {
91 WebViewInternal.setAllowTransparency(
92 this.webViewImpl.guest.getId(),
93 this.webViewImpl.attributes[
94 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue());
97 // Attribute used to define the demension limits of autosizing.
98 function AutosizeDimensionAttribute(name, webViewImpl) {
99 WebViewAttribute.call(this, name, webViewImpl);
102 AutosizeDimensionAttribute.prototype.__proto__ = WebViewAttribute.prototype;
104 AutosizeDimensionAttribute.prototype.getValue = function() {
105 return parseInt(this.webViewImpl.element.getAttribute(this.name)) || 0;
108 AutosizeDimensionAttribute.prototype.handleMutation = function(
109 oldValue, newValue) {
110 if (!this.webViewImpl.guest.getId()) {
113 GuestViewInternal.setAutoSize(this.webViewImpl.guest.getId(), {
114 'enableAutoSize': this.webViewImpl.attributes[
115 WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue(),
117 'width': this.webViewImpl.attributes[
118 WebViewConstants.ATTRIBUTE_MINWIDTH].getValue(),
119 'height': this.webViewImpl.attributes[
120 WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue()
123 'width': this.webViewImpl.attributes[
124 WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue(),
125 'height': this.webViewImpl.attributes[
126 WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue()
132 // Attribute that specifies whether the webview should be autosized.
133 function AutosizeAttribute(webViewImpl) {
134 BooleanAttribute.call(this, WebViewConstants.ATTRIBUTE_AUTOSIZE, webViewImpl);
137 AutosizeAttribute.prototype.__proto__ = BooleanAttribute.prototype;
139 AutosizeAttribute.prototype.handleMutation =
140 AutosizeDimensionAttribute.prototype.handleMutation;
142 // Attribute that sets the guest content's window.name object.
143 function NameAttribute(webViewImpl) {
144 WebViewAttribute.call(this, WebViewConstants.ATTRIBUTE_NAME, webViewImpl);
147 NameAttribute.prototype.__proto__ = WebViewAttribute.prototype
149 NameAttribute.prototype.handleMutation = function(oldValue, newValue) {
150 oldValue = oldValue || '';
151 newValue = newValue || '';
152 if (oldValue === newValue || !this.webViewImpl.guest.getId()) {
156 WebViewInternal.setName(this.webViewImpl.guest.getId(), newValue);
159 // Attribute representing the state of the storage partition.
160 function PartitionAttribute(webViewImpl) {
161 WebViewAttribute.call(
162 this, WebViewConstants.ATTRIBUTE_PARTITION, webViewImpl);
163 this.validPartitionId = true;
166 PartitionAttribute.prototype.__proto__ = WebViewAttribute.prototype;
168 PartitionAttribute.prototype.handleMutation = function(oldValue, newValue) {
169 newValue = newValue || '';
171 // The partition cannot change if the webview has already navigated.
172 if (!this.webViewImpl.beforeFirstNavigation) {
173 window.console.error(WebViewConstants.ERROR_MSG_ALREADY_NAVIGATED);
174 this.setValueIgnoreMutation(oldValue);
177 if (newValue == 'persist:') {
178 this.validPartitionId = false;
179 window.console.error(
180 WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE);
184 // Attribute that handles the location and navigation of the webview.
185 function SrcAttribute(webViewImpl) {
186 WebViewAttribute.call(this, WebViewConstants.ATTRIBUTE_SRC, webViewImpl);
187 this.setupMutationObserver();
190 SrcAttribute.prototype.__proto__ = WebViewAttribute.prototype;
192 SrcAttribute.prototype.setValueIgnoreMutation = function(value) {
193 // takeRecords() is needed to clear queued up src mutations. Without it, it is
194 // possible for this change to get picked up asyncronously by src's mutation
195 // observer |observer|, and then get handled even though we do not want to
196 // handle this mutation.
197 this.observer.takeRecords();
198 this.ignoreMutation = true;
199 this.webViewImpl.element.setAttribute(this.name, value || '');
200 this.ignoreMutation = false;
203 SrcAttribute.prototype.handleMutation = function(oldValue, newValue) {
204 // Once we have navigated, we don't allow clearing the src attribute.
205 // Once <webview> enters a navigated state, it cannot return to a
206 // placeholder state.
207 if (!newValue && oldValue) {
208 // src attribute changes normally initiate a navigation. We suppress
209 // the next src attribute handler call to avoid reloading the page
210 // on every guest-initiated navigation.
211 this.setValueIgnoreMutation(oldValue);
214 this.webViewImpl.parseSrcAttribute();
217 // The purpose of this mutation observer is to catch assignment to the src
218 // attribute without any changes to its value. This is useful in the case
219 // where the webview guest has crashed and navigating to the same address
220 // spawns off a new process.
221 SrcAttribute.prototype.setupMutationObserver =
223 this.observer = new MutationObserver(function(mutations) {
224 $Array.forEach(mutations, function(mutation) {
225 var oldValue = mutation.oldValue;
226 var newValue = this.getValue();
227 if (oldValue != newValue) {
230 this.handleMutation(oldValue, newValue);
235 attributeOldValue: true,
236 attributeFilter: [this.name]
238 this.observer.observe(this.webViewImpl.element, params);
241 // -----------------------------------------------------------------------------
243 // Sets up all of the webview attributes.
244 WebViewImpl.prototype.setupWebViewAttributes = function() {
245 this.attributes = {};
247 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY] =
248 new AllowTransparencyAttribute(this);
249 this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE] =
250 new AutosizeAttribute(this);
251 this.attributes[WebViewConstants.ATTRIBUTE_NAME] =
252 new NameAttribute(this);
253 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION] =
254 new PartitionAttribute(this);
255 this.attributes[WebViewConstants.ATTRIBUTE_SRC] =
256 new SrcAttribute(this);
258 var autosizeAttributes = [WebViewConstants.ATTRIBUTE_MAXHEIGHT,
259 WebViewConstants.ATTRIBUTE_MAXWIDTH,
260 WebViewConstants.ATTRIBUTE_MINHEIGHT,
261 WebViewConstants.ATTRIBUTE_MINWIDTH];
262 for (var i = 0; autosizeAttributes[i]; ++i) {
263 this.attributes[autosizeAttributes[i]] =
264 new AutosizeDimensionAttribute(autosizeAttributes[i], this);