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 guestViewInternalNatives = requireNative('guest_view_internal'); | 12 var guestViewInternalNatives = requireNative('guest_view_internal'); |
13 var IdGenerator = requireNative('id_generator'); | 13 var IdGenerator = requireNative('id_generator'); |
14 var WebViewConstants = require('webViewConstants').WebViewConstants; | 14 var WebViewConstants = require('webViewConstants').WebViewConstants; |
15 var WebViewEvents = require('webViewEvents').WebViewEvents; | 15 var WebViewEvents = require('webViewEvents').WebViewEvents; |
16 var WebViewInternal = require('webViewInternal').WebViewInternal; | 16 var WebViewInternal = require('webViewInternal').WebViewInternal; |
17 | 17 |
| 18 // Attributes. |
18 var AUTO_SIZE_ATTRIBUTES = [ | 19 var AUTO_SIZE_ATTRIBUTES = [ |
19 WebViewConstants.ATTRIBUTE_AUTOSIZE, | 20 WebViewConstants.ATTRIBUTE_AUTOSIZE, |
20 WebViewConstants.ATTRIBUTE_MAXHEIGHT, | 21 WebViewConstants.ATTRIBUTE_MAXHEIGHT, |
21 WebViewConstants.ATTRIBUTE_MAXWIDTH, | 22 WebViewConstants.ATTRIBUTE_MAXWIDTH, |
22 WebViewConstants.ATTRIBUTE_MINHEIGHT, | 23 WebViewConstants.ATTRIBUTE_MINHEIGHT, |
23 WebViewConstants.ATTRIBUTE_MINWIDTH | 24 WebViewConstants.ATTRIBUTE_MINWIDTH |
24 ]; | 25 ]; |
25 | 26 |
26 // Represents the state of the storage partition. | |
27 function Partition() { | |
28 this.validPartitionId = true; | |
29 this.persistStorage = false; | |
30 this.storagePartitionId = ''; | |
31 } | |
32 | |
33 Partition.prototype.toAttribute = function() { | |
34 if (!this.validPartitionId) { | |
35 return ''; | |
36 } | |
37 return (this.persistStorage ? 'persist:' : '') + this.storagePartitionId; | |
38 }; | |
39 | |
40 Partition.prototype.fromAttribute = function(value, hasNavigated) { | |
41 var result = {}; | |
42 if (hasNavigated) { | |
43 result.error = WebViewConstants.ERROR_MSG_ALREADY_NAVIGATED; | |
44 return result; | |
45 } | |
46 if (!value) { | |
47 value = ''; | |
48 } | |
49 | |
50 var LEN = 'persist:'.length; | |
51 if (value.substr(0, LEN) == 'persist:') { | |
52 value = value.substr(LEN); | |
53 if (!value) { | |
54 this.validPartitionId = false; | |
55 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | |
56 return result; | |
57 } | |
58 this.persistStorage = true; | |
59 } else { | |
60 this.persistStorage = false; | |
61 } | |
62 | |
63 this.storagePartitionId = value; | |
64 return result; | |
65 }; | |
66 | |
67 // Represents the internal state of the WebView node. | 27 // Represents the internal state of the WebView node. |
68 function WebView(webviewNode) { | 28 function WebView(webviewNode) { |
69 privates(webviewNode).internal = this; | 29 privates(webviewNode).internal = this; |
70 this.webviewNode = webviewNode; | 30 this.webviewNode = webviewNode; |
71 this.attached = false; | 31 this.attached = false; |
72 this.pendingGuestCreation = false; | 32 this.pendingGuestCreation = false; |
73 this.elementAttached = false; | 33 this.elementAttached = false; |
74 | 34 |
75 this.beforeFirstNavigation = true; | 35 this.beforeFirstNavigation = true; |
76 this.contentWindow = null; | 36 this.contentWindow = null; |
77 this.validPartitionId = true; | 37 this.validPartitionId = true; |
78 // Used to save some state upon deferred attachment. | 38 // Used to save some state upon deferred attachment. |
79 // If <object> bindings is not available, we defer attachment. | 39 // If <object> bindings is not available, we defer attachment. |
80 // This state contains whether or not the attachment request was for | 40 // This state contains whether or not the attachment request was for |
81 // newwindow. | 41 // newwindow. |
82 this.deferredAttachState = null; | 42 this.deferredAttachState = null; |
83 | 43 |
84 // on* Event handlers. | 44 // on* Event handlers. |
85 this.on = {}; | 45 this.on = {}; |
86 | 46 |
87 this.browserPluginNode = this.createBrowserPluginNode(); | 47 this.browserPluginNode = this.createBrowserPluginNode(); |
88 var shadowRoot = this.webviewNode.createShadowRoot(); | 48 var shadowRoot = this.webviewNode.createShadowRoot(); |
89 this.partition = new Partition(); | 49 this.setupWebViewAttributes(); |
90 | |
91 this.setupWebViewSrcAttributeMutationObserver(); | 50 this.setupWebViewSrcAttributeMutationObserver(); |
92 this.setupFocusPropagation(); | 51 this.setupFocusPropagation(); |
93 this.setupWebviewNodeProperties(); | 52 this.setupWebviewNodeProperties(); |
94 | 53 |
95 this.viewInstanceId = IdGenerator.GetNextId(); | 54 this.viewInstanceId = IdGenerator.GetNextId(); |
96 | 55 |
97 new WebViewEvents(this, this.viewInstanceId); | 56 new WebViewEvents(this, this.viewInstanceId); |
98 | 57 |
99 shadowRoot.appendChild(this.browserPluginNode); | 58 shadowRoot.appendChild(this.browserPluginNode); |
100 } | 59 } |
(...skipping 16 matching lines...) Expand all Loading... |
117 // already picked up a partition ID. Thus, we need to reset the initialization | 76 // already picked up a partition ID. Thus, we need to reset the initialization |
118 // state. However, it may be the case that beforeFirstNavigation is false BUT | 77 // state. However, it may be the case that beforeFirstNavigation is false BUT |
119 // guestInstanceId has yet to be initialized. This means that we have not | 78 // guestInstanceId has yet to be initialized. This means that we have not |
120 // heard back from createGuest yet. We will not reset the flag in this case so | 79 // heard back from createGuest yet. We will not reset the flag in this case so |
121 // that we don't end up allocating a second guest. | 80 // that we don't end up allocating a second guest. |
122 if (this.guestInstanceId) { | 81 if (this.guestInstanceId) { |
123 GuestViewInternal.destroyGuest(this.guestInstanceId); | 82 GuestViewInternal.destroyGuest(this.guestInstanceId); |
124 this.guestInstanceId = undefined; | 83 this.guestInstanceId = undefined; |
125 this.beforeFirstNavigation = true; | 84 this.beforeFirstNavigation = true; |
126 this.validPartitionId = true; | 85 this.validPartitionId = true; |
127 this.partition.validPartitionId = true; | 86 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = |
| 87 true; |
128 this.contentWindow = null; | 88 this.contentWindow = null; |
129 } | 89 } |
130 this.internalInstanceId = 0; | 90 this.internalInstanceId = 0; |
131 }; | 91 }; |
132 | 92 |
133 // Sets the <webview>.request property. | 93 // Sets the <webview>.request property. |
134 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { | 94 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { |
135 Object.defineProperty( | 95 Object.defineProperty( |
136 this.webviewNode, | 96 this.webviewNode, |
137 'request', | 97 'request', |
(...skipping 24 matching lines...) Expand all Loading... |
162 | 122 |
163 // Validation helper function for executeScript() and insertCSS(). | 123 // Validation helper function for executeScript() and insertCSS(). |
164 WebView.prototype.validateExecuteCodeCall = function() { | 124 WebView.prototype.validateExecuteCodeCall = function() { |
165 if (!this.guestInstanceId) { | 125 if (!this.guestInstanceId) { |
166 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); | 126 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); |
167 } | 127 } |
168 }; | 128 }; |
169 | 129 |
170 WebView.prototype.setupAutoSizeProperties = function() { | 130 WebView.prototype.setupAutoSizeProperties = function() { |
171 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { | 131 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { |
172 this[attributeName] = this.webviewNode.getAttribute(attributeName); | 132 this.attributes[attributeName].setValue( |
| 133 this.webviewNode.getAttribute(attributeName)); |
173 Object.defineProperty(this.webviewNode, attributeName, { | 134 Object.defineProperty(this.webviewNode, attributeName, { |
174 get: function() { | 135 get: function() { |
175 return this[attributeName]; | 136 return this.attributes[attributeName].getValue(); |
176 }.bind(this), | 137 }.bind(this), |
177 set: function(value) { | 138 set: function(value) { |
178 this.webviewNode.setAttribute(attributeName, value); | 139 this.webviewNode.setAttribute(attributeName, value); |
179 }.bind(this), | 140 }.bind(this), |
180 enumerable: true | 141 enumerable: true |
181 }); | 142 }); |
182 }.bind(this), this); | 143 }.bind(this), this); |
183 }; | 144 }; |
184 | 145 |
185 WebView.prototype.setupWebviewNodeProperties = function() { | 146 WebView.prototype.setupWebviewNodeProperties = function() { |
186 this.setupAutoSizeProperties(); | 147 this.setupAutoSizeProperties(); |
187 | 148 |
188 Object.defineProperty(this.webviewNode, | 149 Object.defineProperty(this.webviewNode, |
189 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, { | 150 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, { |
190 get: function() { | 151 get: function() { |
191 return this.allowtransparency; | 152 return this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
| 153 getValue(); |
192 }.bind(this), | 154 }.bind(this), |
193 set: function(value) { | 155 set: function(value) { |
194 this.webviewNode.setAttribute( | 156 this.webviewNode.setAttribute( |
195 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, | 157 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, |
196 value); | 158 value); |
197 }.bind(this), | 159 }.bind(this), |
198 enumerable: true | 160 enumerable: true |
199 }); | 161 }); |
200 | 162 |
201 // We cannot use {writable: true} property descriptor because we want a | 163 // We cannot use {writable: true} property descriptor because we want a |
202 // dynamic getter value. | 164 // dynamic getter value. |
203 Object.defineProperty(this.webviewNode, 'contentWindow', { | 165 Object.defineProperty(this.webviewNode, 'contentWindow', { |
204 get: function() { | 166 get: function() { |
205 if (this.contentWindow) { | 167 if (this.contentWindow) { |
206 return this.contentWindow; | 168 return this.contentWindow; |
207 } | 169 } |
208 window.console.error( | 170 window.console.error( |
209 WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); | 171 WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); |
210 }.bind(this), | 172 }.bind(this), |
211 // No setter. | 173 // No setter. |
212 enumerable: true | 174 enumerable: true |
213 }); | 175 }); |
214 | 176 |
215 Object.defineProperty(this.webviewNode, 'name', { | 177 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_NAME, { |
216 get: function() { | 178 get: function() { |
217 return this.name; | 179 return this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(); |
218 }.bind(this), | 180 }.bind(this), |
219 set: function(value) { | 181 set: function(value) { |
220 this.webviewNode.setAttribute('name', value); | 182 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_NAME, value); |
221 }.bind(this), | 183 }.bind(this), |
222 enumerable: true | 184 enumerable: true |
223 }); | 185 }); |
224 | 186 |
225 Object.defineProperty(this.webviewNode, 'partition', { | 187 Object.defineProperty(this.webviewNode, |
| 188 WebViewConstants.ATTRIBUTE_PARTITION, { |
226 get: function() { | 189 get: function() { |
227 return this.partition.toAttribute(); | 190 return this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].getValue(); |
228 }.bind(this), | 191 }.bind(this), |
229 set: function(value) { | 192 set: function(value) { |
230 var result = this.partition.fromAttribute(value, this.hasNavigated()); | 193 var result = this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. |
| 194 setValue(value); |
231 if (result.error) { | 195 if (result.error) { |
232 throw result.error; | 196 throw result.error; |
233 } | 197 } |
234 this.webviewNode.setAttribute('partition', value); | 198 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_PARTITION, |
| 199 value); |
235 }.bind(this), | 200 }.bind(this), |
236 enumerable: true | 201 enumerable: true |
237 }); | 202 }); |
238 | 203 |
239 this.src = this.webviewNode.getAttribute('src'); | 204 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue( |
240 Object.defineProperty(this.webviewNode, 'src', { | 205 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC)); |
| 206 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_SRC, { |
241 get: function() { | 207 get: function() { |
242 return this.src; | 208 return this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
243 }.bind(this), | 209 }.bind(this), |
244 set: function(value) { | 210 set: function(value) { |
245 this.webviewNode.setAttribute('src', value); | 211 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, value); |
246 }.bind(this), | 212 }.bind(this), |
247 // No setter. | |
248 enumerable: true | 213 enumerable: true |
249 }); | 214 }); |
250 }; | 215 }; |
251 | 216 |
252 // The purpose of this mutation observer is to catch assignment to the src | 217 // The purpose of this mutation observer is to catch assignment to the src |
253 // attribute without any changes to its value. This is useful in the case | 218 // attribute without any changes to its value. This is useful in the case |
254 // where the webview guest has crashed and navigating to the same address | 219 // where the webview guest has crashed and navigating to the same address |
255 // spawns off a new process. | 220 // spawns off a new process. |
256 WebView.prototype.setupWebViewSrcAttributeMutationObserver = | 221 WebView.prototype.setupWebViewSrcAttributeMutationObserver = |
257 function() { | 222 function() { |
258 this.srcAndPartitionObserver = new MutationObserver(function(mutations) { | 223 this.srcAndPartitionObserver = new MutationObserver(function(mutations) { |
259 $Array.forEach(mutations, function(mutation) { | 224 $Array.forEach(mutations, function(mutation) { |
260 var oldValue = mutation.oldValue; | 225 var oldValue = mutation.oldValue; |
261 var newValue = this.webviewNode.getAttribute(mutation.attributeName); | 226 var newValue = this.webviewNode.getAttribute(mutation.attributeName); |
262 if (oldValue != newValue) { | 227 if (oldValue != newValue) { |
263 return; | 228 return; |
264 } | 229 } |
265 this.handleWebviewAttributeMutation( | 230 this.handleWebviewAttributeMutation( |
266 mutation.attributeName, oldValue, newValue); | 231 mutation.attributeName, oldValue, newValue); |
267 }.bind(this)); | 232 }.bind(this)); |
268 }.bind(this)); | 233 }.bind(this)); |
269 var params = { | 234 var params = { |
270 attributes: true, | 235 attributes: true, |
271 attributeOldValue: true, | 236 attributeOldValue: true, |
272 attributeFilter: ['src', 'partition'] | 237 attributeFilter: [WebViewConstants.ATTRIBUTE_SRC, |
| 238 WebViewConstants.ATTRIBUTE_PARTITION] |
273 }; | 239 }; |
274 this.srcAndPartitionObserver.observe(this.webviewNode, params); | 240 this.srcAndPartitionObserver.observe(this.webviewNode, params); |
275 }; | 241 }; |
276 | 242 |
277 // This observer monitors mutations to attributes of the <webview> and | 243 // This observer monitors mutations to attributes of the <webview> and |
278 // updates the BrowserPlugin properties accordingly. In turn, updating | 244 // updates the BrowserPlugin properties accordingly. In turn, updating |
279 // a BrowserPlugin property will update the corresponding BrowserPlugin | 245 // a BrowserPlugin property will update the corresponding BrowserPlugin |
280 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more | 246 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more |
281 // details. | 247 // details. |
282 WebView.prototype.handleWebviewAttributeMutation = | 248 WebView.prototype.handleWebviewAttributeMutation = |
283 function(name, oldValue, newValue) { | 249 function(name, oldValue, newValue) { |
284 if (AUTO_SIZE_ATTRIBUTES.indexOf(name) > -1) { | 250 if (AUTO_SIZE_ATTRIBUTES.indexOf(name) > -1) { |
285 this[name] = newValue; | 251 this.attributes[name].setValue(newValue); |
286 if (!this.guestInstanceId) { | 252 if (!this.guestInstanceId) { |
287 return; | 253 return; |
288 } | 254 } |
289 // Convert autosize attribute to boolean. | 255 // Convert autosize attribute to boolean. |
290 var autosize = this.webviewNode.hasAttribute( | 256 var autosize = this.webviewNode.hasAttribute( |
291 WebViewConstants.ATTRIBUTE_AUTOSIZE); | 257 WebViewConstants.ATTRIBUTE_AUTOSIZE); |
292 GuestViewInternal.setAutoSize(this.guestInstanceId, { | 258 GuestViewInternal.setAutoSize(this.guestInstanceId, { |
293 'enableAutoSize': autosize, | 259 'enableAutoSize': autosize, |
294 'min': { | 260 'min': { |
295 'width': parseInt(this.minwidth || 0), | 261 'width': parseInt(this. |
296 'height': parseInt(this.minheight || 0) | 262 attributes[WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), |
| 263 'height': parseInt(this. |
| 264 attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) |
297 }, | 265 }, |
298 'max': { | 266 'max': { |
299 'width': parseInt(this.maxwidth || 0), | 267 'width': parseInt(this. |
300 'height': parseInt(this.maxheight || 0) | 268 attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), |
| 269 'height': parseInt(this. |
| 270 attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) |
301 } | 271 } |
302 }); | 272 }); |
303 return; | 273 return; |
304 } else if (name == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { | 274 } else if (name == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { |
305 // We treat null attribute (attribute removed) and the empty string as | 275 // We treat null attribute (attribute removed) and the empty string as |
306 // one case. | 276 // one case. |
307 oldValue = oldValue || ''; | 277 oldValue = oldValue || ''; |
308 newValue = newValue || ''; | 278 newValue = newValue || ''; |
309 | 279 |
310 if (oldValue === newValue) { | 280 if (oldValue === newValue) { |
311 return; | 281 return; |
312 } | 282 } |
313 this.allowtransparency = newValue != ''; | 283 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
| 284 setValue(newValue != ''); |
314 | 285 |
315 if (!this.guestInstanceId) { | 286 if (!this.guestInstanceId) { |
316 return; | 287 return; |
317 } | 288 } |
318 | 289 |
319 WebViewInternal.setAllowTransparency(this.guestInstanceId, | 290 WebViewInternal.setAllowTransparency( |
320 this.allowtransparency); | 291 this.guestInstanceId, |
| 292 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
| 293 getValue()); |
321 return; | 294 return; |
322 } else if (name == 'name') { | 295 } else if (name == WebViewConstants.ATTRIBUTE_NAME) { |
323 // We treat null attribute (attribute removed) and the empty string as | 296 // We treat null attribute (attribute removed) and the empty string as |
324 // one case. | 297 // one case. |
325 oldValue = oldValue || ''; | 298 oldValue = oldValue || ''; |
326 newValue = newValue || ''; | 299 newValue = newValue || ''; |
327 | 300 |
328 if (oldValue === newValue) { | 301 if (oldValue === newValue) { |
329 return; | 302 return; |
330 } | 303 } |
331 this.name = newValue; | 304 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(newValue); |
332 if (!this.guestInstanceId) { | 305 if (!this.guestInstanceId) { |
333 return; | 306 return; |
334 } | 307 } |
335 WebViewInternal.setName(this.guestInstanceId, newValue); | 308 WebViewInternal.setName(this.guestInstanceId, newValue); |
336 return; | 309 return; |
337 } else if (name == 'src') { | 310 } else if (name == WebViewConstants.ATTRIBUTE_SRC) { |
338 // We treat null attribute (attribute removed) and the empty string as | 311 // We treat null attribute (attribute removed) and the empty string as |
339 // one case. | 312 // one case. |
340 oldValue = oldValue || ''; | 313 oldValue = oldValue || ''; |
341 newValue = newValue || ''; | 314 newValue = newValue || ''; |
342 // Once we have navigated, we don't allow clearing the src attribute. | 315 // Once we have navigated, we don't allow clearing the src attribute. |
343 // Once <webview> enters a navigated state, it cannot be return back to a | 316 // Once <webview> enters a navigated state, it cannot be return back to a |
344 // placeholder state. | 317 // placeholder state. |
345 if (newValue == '' && oldValue != '') { | 318 if (newValue == '' && oldValue != '') { |
346 // src attribute changes normally initiate a navigation. We suppress | 319 // src attribute changes normally initiate a navigation. We suppress |
347 // the next src attribute handler call to avoid reloading the page | 320 // the next src attribute handler call to avoid reloading the page |
348 // on every guest-initiated navigation. | 321 // on every guest-initiated navigation. |
349 this.ignoreNextSrcAttributeChange = true; | 322 this.ignoreNextSrcAttributeChange = true; |
350 this.webviewNode.setAttribute('src', oldValue); | 323 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, oldValue); |
351 return; | 324 return; |
352 } | 325 } |
353 this.src = newValue; | 326 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue(newValue); |
354 if (this.ignoreNextSrcAttributeChange) { | 327 if (this.ignoreNextSrcAttributeChange) { |
355 // Don't allow the src mutation observer to see this change. | 328 // Don't allow the src mutation observer to see this change. |
356 this.srcAndPartitionObserver.takeRecords(); | 329 this.srcAndPartitionObserver.takeRecords(); |
357 this.ignoreNextSrcAttributeChange = false; | 330 this.ignoreNextSrcAttributeChange = false; |
358 return; | 331 return; |
359 } | 332 } |
360 var result = {}; | 333 var result = {}; |
361 this.parseSrcAttribute(result); | 334 this.parseSrcAttribute(result); |
362 | 335 |
363 if (result.error) { | 336 if (result.error) { |
364 throw result.error; | 337 throw result.error; |
365 } | 338 } |
366 } else if (name == 'partition') { | 339 } else if (name == WebViewConstants.ATTRIBUTE_PARTITION) { |
367 // Note that throwing error here won't synchronously propagate. | 340 // Note that throwing error here won't synchronously propagate. |
368 this.partition.fromAttribute(newValue, this.hasNavigated()); | 341 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue(newValue); |
369 } | 342 } |
370 }; | 343 }; |
371 | 344 |
372 WebView.prototype.handleBrowserPluginAttributeMutation = | 345 WebView.prototype.handleBrowserPluginAttributeMutation = |
373 function(name, oldValue, newValue) { | 346 function(name, oldValue, newValue) { |
374 if (name == 'internalinstanceid' && !oldValue && !!newValue) { | 347 if (name == WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID && |
375 this.browserPluginNode.removeAttribute('internalinstanceid'); | 348 !oldValue && !!newValue) { |
| 349 this.browserPluginNode.removeAttribute( |
| 350 WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID); |
376 this.internalInstanceId = parseInt(newValue); | 351 this.internalInstanceId = parseInt(newValue); |
377 | 352 |
378 if (!!this.guestInstanceId && this.guestInstanceId != 0) { | 353 if (!!this.guestInstanceId && this.guestInstanceId != 0) { |
379 var isNewWindow = this.deferredAttachState ? | 354 var isNewWindow = this.deferredAttachState ? |
380 this.deferredAttachState.isNewWindow : false; | 355 this.deferredAttachState.isNewWindow : false; |
381 var params = this.buildAttachParams(isNewWindow); | 356 var params = this.buildAttachParams(isNewWindow); |
382 guestViewInternalNatives.AttachGuest( | 357 guestViewInternalNatives.AttachGuest( |
383 this.internalInstanceId, | 358 this.internalInstanceId, |
384 this.guestInstanceId, | 359 this.guestInstanceId, |
385 params, | 360 params, |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
458 // Returns if <object> is in the render tree. | 433 // Returns if <object> is in the render tree. |
459 WebView.prototype.isPluginInRenderTree = function() { | 434 WebView.prototype.isPluginInRenderTree = function() { |
460 return !!this.internalInstanceId && this.internalInstanceId != 0; | 435 return !!this.internalInstanceId && this.internalInstanceId != 0; |
461 }; | 436 }; |
462 | 437 |
463 WebView.prototype.hasNavigated = function() { | 438 WebView.prototype.hasNavigated = function() { |
464 return !this.beforeFirstNavigation; | 439 return !this.beforeFirstNavigation; |
465 }; | 440 }; |
466 | 441 |
467 WebView.prototype.parseSrcAttribute = function(result) { | 442 WebView.prototype.parseSrcAttribute = function(result) { |
468 if (!this.partition.validPartitionId) { | 443 if (!this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId) { |
469 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | 444 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; |
470 return; | 445 return; |
471 } | 446 } |
472 this.src = this.webviewNode.getAttribute('src'); | 447 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue( |
| 448 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC)); |
473 | 449 |
474 if (!this.src) { | 450 if (!this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()) { |
475 return; | 451 return; |
476 } | 452 } |
477 | 453 |
478 if (this.guestInstanceId == undefined) { | 454 if (this.guestInstanceId == undefined) { |
479 if (this.beforeFirstNavigation) { | 455 if (this.beforeFirstNavigation) { |
480 this.beforeFirstNavigation = false; | 456 this.beforeFirstNavigation = false; |
481 this.createGuest(); | 457 this.createGuest(); |
482 } | 458 } |
483 return; | 459 return; |
484 } | 460 } |
485 | 461 |
486 // Navigate to |this.src|. | 462 // Navigate to |this.src|. |
487 WebViewInternal.navigate(this.guestInstanceId, this.src); | 463 WebViewInternal.navigate( |
| 464 this.guestInstanceId, |
| 465 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()); |
488 }; | 466 }; |
489 | 467 |
490 WebView.prototype.parseAttributes = function() { | 468 WebView.prototype.parseAttributes = function() { |
491 if (!this.elementAttached) { | 469 if (!this.elementAttached) { |
492 return; | 470 return; |
493 } | 471 } |
494 var hasNavigated = this.hasNavigated(); | 472 var attributeValue = this.webviewNode.getAttribute( |
495 var attributeValue = this.webviewNode.getAttribute('partition'); | 473 WebViewConstants.ATTRIBUTE_PARTITION); |
496 var result = this.partition.fromAttribute(attributeValue, hasNavigated); | 474 var result = this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( |
| 475 attributeValue); |
497 this.parseSrcAttribute(result); | 476 this.parseSrcAttribute(result); |
498 }; | 477 }; |
499 | 478 |
500 WebView.prototype.createGuest = function() { | 479 WebView.prototype.createGuest = function() { |
501 if (this.pendingGuestCreation) { | 480 if (this.pendingGuestCreation) { |
502 return; | 481 return; |
503 } | 482 } |
504 var storagePartitionId = | 483 var storagePartitionId = |
505 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_PARTITION) || | 484 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_PARTITION) || |
506 this.webviewNode[WebViewConstants.ATTRIBUTE_PARTITION]; | 485 this.webviewNode[WebViewConstants.ATTRIBUTE_PARTITION]; |
507 var params = { | 486 var params = { |
508 'storagePartitionId': storagePartitionId | 487 'storagePartitionId': storagePartitionId |
509 }; | 488 }; |
510 GuestViewInternal.createGuest( | 489 GuestViewInternal.createGuest( |
511 'webview', | 490 'webview', |
512 params, | 491 params, |
513 function(guestInstanceId) { | 492 function(guestInstanceId) { |
514 this.pendingGuestCreation = false; | 493 this.pendingGuestCreation = false; |
515 if (!this.elementAttached) { | 494 if (!this.elementAttached) { |
516 GuestViewInternal.destroyGuest(guestInstanceId); | 495 GuestViewInternal.destroyGuest(guestInstanceId); |
517 return; | 496 return; |
518 } | 497 } |
519 this.attachWindow(guestInstanceId, false); | 498 this.attachWindow(guestInstanceId, false); |
520 }.bind(this) | 499 }.bind(this) |
521 ); | 500 ); |
522 this.pendingGuestCreation = true; | 501 this.pendingGuestCreation = true; |
523 }; | 502 }; |
524 | 503 |
525 WebView.prototype.onFrameNameChanged = function(name) { | 504 WebView.prototype.onFrameNameChanged = function(name) { |
526 this.name = name || ''; | 505 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(name || ''); |
527 if (this.name === '') { | 506 if (this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue() === '') { |
528 this.webviewNode.removeAttribute('name'); | 507 this.webviewNode.removeAttribute(WebViewConstants.ATTRIBUTE_NAME); |
529 } else { | 508 } else { |
530 this.webviewNode.setAttribute('name', this.name); | 509 this.webviewNode.setAttribute( |
| 510 WebViewConstants.ATTRIBUTE_NAME, |
| 511 this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue()); |
531 } | 512 } |
532 }; | 513 }; |
533 | 514 |
534 WebView.prototype.dispatchEvent = function(webViewEvent) { | 515 WebView.prototype.dispatchEvent = function(webViewEvent) { |
535 return this.webviewNode.dispatchEvent(webViewEvent); | 516 return this.webviewNode.dispatchEvent(webViewEvent); |
536 }; | 517 }; |
537 | 518 |
538 // Adds an 'on<event>' property on the webview, which can be used to set/unset | 519 // Adds an 'on<event>' property on the webview, which can be used to set/unset |
539 // an event handler. | 520 // an event handler. |
540 WebView.prototype.setupEventProperty = function(eventName) { | 521 WebView.prototype.setupEventProperty = function(eventName) { |
(...skipping 14 matching lines...) Expand all Loading... |
555 }; | 536 }; |
556 | 537 |
557 // Updates state upon loadcommit. | 538 // Updates state upon loadcommit. |
558 WebView.prototype.onLoadCommit = function( | 539 WebView.prototype.onLoadCommit = function( |
559 baseUrlForDataUrl, currentEntryIndex, entryCount, | 540 baseUrlForDataUrl, currentEntryIndex, entryCount, |
560 processId, url, isTopLevel) { | 541 processId, url, isTopLevel) { |
561 this.baseUrlForDataUrl = baseUrlForDataUrl; | 542 this.baseUrlForDataUrl = baseUrlForDataUrl; |
562 this.currentEntryIndex = currentEntryIndex; | 543 this.currentEntryIndex = currentEntryIndex; |
563 this.entryCount = entryCount; | 544 this.entryCount = entryCount; |
564 this.processId = processId; | 545 this.processId = processId; |
565 var oldValue = this.webviewNode.getAttribute('src'); | 546 var oldValue = this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC); |
566 var newValue = url; | 547 var newValue = url; |
567 if (isTopLevel && (oldValue != newValue)) { | 548 if (isTopLevel && (oldValue != newValue)) { |
568 // Touching the src attribute triggers a navigation. To avoid | 549 // Touching the src attribute triggers a navigation. To avoid |
569 // triggering a page reload on every guest-initiated navigation, | 550 // triggering a page reload on every guest-initiated navigation, |
570 // we use the flag ignoreNextSrcAttributeChange here. | 551 // we use the flag ignoreNextSrcAttributeChange here. |
571 this.ignoreNextSrcAttributeChange = true; | 552 this.ignoreNextSrcAttributeChange = true; |
572 this.webviewNode.setAttribute('src', newValue); | 553 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, newValue); |
573 } | 554 } |
574 }; | 555 }; |
575 | 556 |
576 WebView.prototype.onAttach = function(storagePartitionId) { | 557 WebView.prototype.onAttach = function(storagePartitionId) { |
577 this.webviewNode.setAttribute('partition', storagePartitionId); | 558 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_PARTITION, |
578 this.partition.fromAttribute(storagePartitionId, this.hasNavigated()); | 559 storagePartitionId); |
| 560 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( |
| 561 storagePartitionId); |
579 }; | 562 }; |
580 | 563 |
581 WebView.prototype.buildAttachParams = function(isNewWindow) { | 564 WebView.prototype.buildAttachParams = function(isNewWindow) { |
582 var params = { | 565 var params = { |
583 'allowtransparency': this.allowtransparency || false, | 566 'allowtransparency': this.attributes[ |
| 567 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue() || false, |
584 'autosize': this.webviewNode.hasAttribute( | 568 'autosize': this.webviewNode.hasAttribute( |
585 WebViewConstants.ATTRIBUTE_AUTOSIZE), | 569 WebViewConstants.ATTRIBUTE_AUTOSIZE), |
586 'instanceId': this.viewInstanceId, | 570 'instanceId': this.viewInstanceId, |
587 'maxheight': parseInt(this.maxheight || 0), | 571 'maxheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT]. |
588 'maxwidth': parseInt(this.maxwidth || 0), | 572 getValue() || 0), |
589 'minheight': parseInt(this.minheight || 0), | 573 'maxwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH]. |
590 'minwidth': parseInt(this.minwidth || 0), | 574 getValue() || 0), |
591 'name': this.name, | 575 'minheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT]. |
| 576 getValue() || 0), |
| 577 'minwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINWIDTH]. |
| 578 getValue() || 0), |
| 579 'name': this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(), |
592 // We don't need to navigate new window from here. | 580 // We don't need to navigate new window from here. |
593 'src': isNewWindow ? undefined : this.src, | 581 'src': isNewWindow ? undefined : |
| 582 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(), |
594 // If we have a partition from the opener, that will also be already | 583 // If we have a partition from the opener, that will also be already |
595 // set via this.onAttach(). | 584 // set via this.onAttach(). |
596 'storagePartitionId': this.partition.toAttribute(), | 585 'storagePartitionId': this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. |
| 586 getValue(), |
597 'userAgentOverride': this.userAgentOverride | 587 'userAgentOverride': this.userAgentOverride |
598 }; | 588 }; |
599 return params; | 589 return params; |
600 }; | 590 }; |
601 | 591 |
602 WebView.prototype.attachWindow = function(guestInstanceId, | 592 WebView.prototype.attachWindow = function(guestInstanceId, |
603 isNewWindow) { | 593 isNewWindow) { |
604 this.guestInstanceId = guestInstanceId; | 594 this.guestInstanceId = guestInstanceId; |
605 var params = this.buildAttachParams(isNewWindow); | 595 var params = this.buildAttachParams(isNewWindow); |
606 | 596 |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 if (!this.guestInstanceId) { | 634 if (!this.guestInstanceId) { |
645 return; | 635 return; |
646 } | 636 } |
647 var args = $Array.concat([this.guestInstanceId], $Array.slice(arguments)); | 637 var args = $Array.concat([this.guestInstanceId], $Array.slice(arguments)); |
648 $Function.apply(WebViewInternal.clearData, null, args); | 638 $Function.apply(WebViewInternal.clearData, null, args); |
649 }; | 639 }; |
650 | 640 |
651 // Injects JavaScript code into the guest page. | 641 // Injects JavaScript code into the guest page. |
652 WebView.prototype.executeScript = function(var_args) { | 642 WebView.prototype.executeScript = function(var_args) { |
653 this.validateExecuteCodeCall(); | 643 this.validateExecuteCodeCall(); |
654 var webviewSrc = this.src; | 644 var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
655 if (this.baseUrlForDataUrl != '') { | 645 if (this.baseUrlForDataUrl != '') { |
656 webviewSrc = this.baseUrlForDataUrl; | 646 webviewSrc = this.baseUrlForDataUrl; |
657 } | 647 } |
658 var args = $Array.concat([this.guestInstanceId, webviewSrc], | 648 var args = $Array.concat([this.guestInstanceId, webviewSrc], |
659 $Array.slice(arguments)); | 649 $Array.slice(arguments)); |
660 $Function.apply(WebViewInternal.executeScript, null, args); | 650 $Function.apply(WebViewInternal.executeScript, null, args); |
661 }; | 651 }; |
662 | 652 |
663 // Initiates a find-in-page request. | 653 // Initiates a find-in-page request. |
664 WebView.prototype.find = function(search_text, options, callback) { | 654 WebView.prototype.find = function(search_text, options, callback) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
697 WebView.prototype.go = function(relativeIndex, callback) { | 687 WebView.prototype.go = function(relativeIndex, callback) { |
698 if (!this.guestInstanceId) { | 688 if (!this.guestInstanceId) { |
699 return; | 689 return; |
700 } | 690 } |
701 WebViewInternal.go(this.guestInstanceId, relativeIndex, callback); | 691 WebViewInternal.go(this.guestInstanceId, relativeIndex, callback); |
702 }; | 692 }; |
703 | 693 |
704 // Injects CSS into the guest page. | 694 // Injects CSS into the guest page. |
705 WebView.prototype.insertCSS = function(var_args) { | 695 WebView.prototype.insertCSS = function(var_args) { |
706 this.validateExecuteCodeCall(); | 696 this.validateExecuteCodeCall(); |
707 var webviewSrc = this.src; | 697 var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
708 if (this.baseUrlForDataUrl != '') { | 698 if (this.baseUrlForDataUrl != '') { |
709 webviewSrc = this.baseUrlForDataUrl; | 699 webviewSrc = this.baseUrlForDataUrl; |
710 } | 700 } |
711 var args = $Array.concat([this.guestInstanceId, webviewSrc], | 701 var args = $Array.concat([this.guestInstanceId, webviewSrc], |
712 $Array.slice(arguments)); | 702 $Array.slice(arguments)); |
713 $Function.apply(WebViewInternal.insertCSS, null, args); | 703 $Function.apply(WebViewInternal.insertCSS, null, args); |
714 }; | 704 }; |
715 | 705 |
716 // Indicates whether or not the webview's user agent string has been overridden. | 706 // Indicates whether or not the webview's user agent string has been overridden. |
717 WebView.prototype.isUserAgentOverridden = function() { | 707 WebView.prototype.isUserAgentOverridden = function() { |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
913 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; | 903 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; |
914 | 904 |
915 // Implemented when the experimental WebView API is available. | 905 // Implemented when the experimental WebView API is available. |
916 WebView.maybeGetExperimentalAPIs = function() {}; | 906 WebView.maybeGetExperimentalAPIs = function() {}; |
917 WebView.prototype.maybeGetExperimentalEvents = function() {}; | 907 WebView.prototype.maybeGetExperimentalEvents = function() {}; |
918 WebView.prototype.setupExperimentalContextMenus = function() {}; | 908 WebView.prototype.setupExperimentalContextMenus = function() {}; |
919 | 909 |
920 // Exports. | 910 // Exports. |
921 exports.WebView = WebView; | 911 exports.WebView = WebView; |
922 exports.WebViewInternal = WebViewInternal; | 912 exports.WebViewInternal = WebViewInternal; |
OLD | NEW |