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 16 matching lines...) Expand all Loading... |
27 // Represents the internal state of the WebView node. | 27 // Represents the internal state of the WebView node. |
28 function WebView(webviewNode) { | 28 function WebView(webviewNode) { |
29 privates(webviewNode).internal = this; | 29 privates(webviewNode).internal = this; |
30 this.webviewNode = webviewNode; | 30 this.webviewNode = webviewNode; |
31 this.attached = false; | 31 this.attached = false; |
32 this.pendingGuestCreation = false; | 32 this.pendingGuestCreation = false; |
33 this.elementAttached = false; | 33 this.elementAttached = false; |
34 | 34 |
35 this.beforeFirstNavigation = true; | 35 this.beforeFirstNavigation = true; |
36 this.contentWindow = null; | 36 this.contentWindow = null; |
37 this.validPartitionId = true; | |
38 // Used to save some state upon deferred attachment. | 37 // Used to save some state upon deferred attachment. |
39 // If <object> bindings is not available, we defer attachment. | 38 // If <object> bindings is not available, we defer attachment. |
40 // This state contains whether or not the attachment request was for | 39 // This state contains whether or not the attachment request was for |
41 // newwindow. | 40 // newwindow. |
42 this.deferredAttachState = null; | 41 this.deferredAttachState = null; |
43 | 42 |
44 // on* Event handlers. | 43 // on* Event handlers. |
45 this.on = {}; | 44 this.on = {}; |
46 | 45 |
47 this.browserPluginNode = this.createBrowserPluginNode(); | 46 this.browserPluginNode = this.createBrowserPluginNode(); |
(...skipping 27 matching lines...) Expand all Loading... |
75 // If guestInstanceId is defined then the <webview> has navigated and has | 74 // If guestInstanceId is defined then the <webview> has navigated and has |
76 // already picked up a partition ID. Thus, we need to reset the initialization | 75 // already picked up a partition ID. Thus, we need to reset the initialization |
77 // state. However, it may be the case that beforeFirstNavigation is false BUT | 76 // state. However, it may be the case that beforeFirstNavigation is false BUT |
78 // guestInstanceId has yet to be initialized. This means that we have not | 77 // guestInstanceId has yet to be initialized. This means that we have not |
79 // heard back from createGuest yet. We will not reset the flag in this case so | 78 // heard back from createGuest yet. We will not reset the flag in this case so |
80 // that we don't end up allocating a second guest. | 79 // that we don't end up allocating a second guest. |
81 if (this.guestInstanceId) { | 80 if (this.guestInstanceId) { |
82 GuestViewInternal.destroyGuest(this.guestInstanceId); | 81 GuestViewInternal.destroyGuest(this.guestInstanceId); |
83 this.guestInstanceId = undefined; | 82 this.guestInstanceId = undefined; |
84 this.beforeFirstNavigation = true; | 83 this.beforeFirstNavigation = true; |
85 this.validPartitionId = true; | |
86 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = | 84 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = |
87 true; | 85 true; |
88 this.contentWindow = null; | 86 this.contentWindow = null; |
89 } | 87 } |
90 this.internalInstanceId = 0; | 88 this.internalInstanceId = 0; |
91 }; | 89 }; |
92 | 90 |
93 // Sets the <webview>.request property. | 91 // Sets the <webview>.request property. |
94 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { | 92 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { |
95 Object.defineProperty( | 93 Object.defineProperty( |
(...skipping 26 matching lines...) Expand all Loading... |
122 | 120 |
123 // Validation helper function for executeScript() and insertCSS(). | 121 // Validation helper function for executeScript() and insertCSS(). |
124 WebView.prototype.validateExecuteCodeCall = function() { | 122 WebView.prototype.validateExecuteCodeCall = function() { |
125 if (!this.guestInstanceId) { | 123 if (!this.guestInstanceId) { |
126 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); | 124 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); |
127 } | 125 } |
128 }; | 126 }; |
129 | 127 |
130 WebView.prototype.setupAutoSizeProperties = function() { | 128 WebView.prototype.setupAutoSizeProperties = function() { |
131 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { | 129 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { |
132 this.attributes[attributeName].setValue( | |
133 this.webviewNode.getAttribute(attributeName)); | |
134 Object.defineProperty(this.webviewNode, attributeName, { | 130 Object.defineProperty(this.webviewNode, attributeName, { |
135 get: function() { | 131 get: function() { |
136 return this.attributes[attributeName].getValue(); | 132 return this.attributes[attributeName].getValue(); |
137 }.bind(this), | 133 }.bind(this), |
138 set: function(value) { | 134 set: function(value) { |
139 this.webviewNode.setAttribute(attributeName, value); | 135 this.attributes[attributeName].setValue(value); |
140 }.bind(this), | 136 }.bind(this), |
141 enumerable: true | 137 enumerable: true |
142 }); | 138 }); |
143 }.bind(this), this); | 139 }.bind(this), this); |
144 }; | 140 }; |
145 | 141 |
146 WebView.prototype.setupWebviewNodeProperties = function() { | 142 WebView.prototype.setupWebviewNodeProperties = function() { |
147 this.setupAutoSizeProperties(); | 143 this.setupAutoSizeProperties(); |
148 | 144 |
149 Object.defineProperty(this.webviewNode, | 145 Object.defineProperty(this.webviewNode, |
150 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, { | 146 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, { |
151 get: function() { | 147 get: function() { |
152 return this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. | 148 return this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
153 getValue(); | 149 getValue(); |
154 }.bind(this), | 150 }.bind(this), |
155 set: function(value) { | 151 set: function(value) { |
156 this.webviewNode.setAttribute( | 152 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
157 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY, | 153 setValue(value); |
158 value); | |
159 }.bind(this), | 154 }.bind(this), |
160 enumerable: true | 155 enumerable: true |
161 }); | 156 }); |
162 | 157 |
163 // We cannot use {writable: true} property descriptor because we want a | 158 // We cannot use {writable: true} property descriptor because we want a |
164 // dynamic getter value. | 159 // dynamic getter value. |
165 Object.defineProperty(this.webviewNode, 'contentWindow', { | 160 Object.defineProperty(this.webviewNode, 'contentWindow', { |
166 get: function() { | 161 get: function() { |
167 if (this.contentWindow) { | 162 if (this.contentWindow) { |
168 return this.contentWindow; | 163 return this.contentWindow; |
169 } | 164 } |
170 window.console.error( | 165 window.console.error( |
171 WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); | 166 WebViewConstants.ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); |
172 }.bind(this), | 167 }.bind(this), |
173 // No setter. | 168 // No setter. |
174 enumerable: true | 169 enumerable: true |
175 }); | 170 }); |
176 | 171 |
177 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_NAME, { | 172 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_NAME, { |
178 get: function() { | 173 get: function() { |
179 return this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(); | 174 return this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(); |
180 }.bind(this), | 175 }.bind(this), |
181 set: function(value) { | 176 set: function(value) { |
182 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_NAME, value); | 177 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(value); |
183 }.bind(this), | 178 }.bind(this), |
184 enumerable: true | 179 enumerable: true |
185 }); | 180 }); |
186 | 181 |
187 Object.defineProperty(this.webviewNode, | 182 Object.defineProperty(this.webviewNode, |
188 WebViewConstants.ATTRIBUTE_PARTITION, { | 183 WebViewConstants.ATTRIBUTE_PARTITION, { |
189 get: function() { | 184 get: function() { |
190 return this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].getValue(); | 185 return this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].getValue(); |
191 }.bind(this), | 186 }.bind(this), |
192 set: function(value) { | 187 set: function(value) { |
193 var result = this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. | 188 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue(value); |
194 setValue(value); | |
195 if (result.error) { | |
196 throw result.error; | |
197 } | |
198 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_PARTITION, | |
199 value); | |
200 }.bind(this), | 189 }.bind(this), |
201 enumerable: true | 190 enumerable: true |
202 }); | 191 }); |
203 | 192 |
204 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue( | |
205 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC)); | |
206 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_SRC, { | 193 Object.defineProperty(this.webviewNode, WebViewConstants.ATTRIBUTE_SRC, { |
207 get: function() { | 194 get: function() { |
208 return this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); | 195 return this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
209 }.bind(this), | 196 }.bind(this), |
210 set: function(value) { | 197 set: function(value) { |
211 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, value); | 198 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue(value); |
212 }.bind(this), | 199 }.bind(this), |
213 enumerable: true | 200 enumerable: true |
214 }); | 201 }); |
215 }; | 202 }; |
216 | 203 |
217 // The purpose of this mutation observer is to catch assignment to the src | 204 // 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 | 205 // 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 | 206 // where the webview guest has crashed and navigating to the same address |
220 // spawns off a new process. | 207 // spawns off a new process. |
221 WebView.prototype.setupWebViewSrcAttributeMutationObserver = | 208 WebView.prototype.setupWebViewSrcAttributeMutationObserver = |
222 function() { | 209 function() { |
223 this.srcAndPartitionObserver = new MutationObserver(function(mutations) { | 210 this.srcAndPartitionObserver = new MutationObserver(function(mutations) { |
224 $Array.forEach(mutations, function(mutation) { | 211 $Array.forEach(mutations, function(mutation) { |
225 var oldValue = mutation.oldValue; | 212 var oldValue = mutation.oldValue; |
226 var newValue = this.webviewNode.getAttribute(mutation.attributeName); | 213 var newValue = this.attributes[mutation.attributeName].getValue(); |
227 if (oldValue != newValue) { | 214 if (oldValue != newValue) { |
228 return; | 215 return; |
229 } | 216 } |
230 this.handleWebviewAttributeMutation( | 217 this.handleWebviewAttributeMutation( |
231 mutation.attributeName, oldValue, newValue); | 218 mutation.attributeName, oldValue, newValue); |
232 }.bind(this)); | 219 }.bind(this)); |
233 }.bind(this)); | 220 }.bind(this)); |
234 var params = { | 221 var params = { |
235 attributes: true, | 222 attributes: true, |
236 attributeOldValue: true, | 223 attributeOldValue: true, |
237 attributeFilter: [WebViewConstants.ATTRIBUTE_SRC, | 224 attributeFilter: [WebViewConstants.ATTRIBUTE_SRC, |
238 WebViewConstants.ATTRIBUTE_PARTITION] | 225 WebViewConstants.ATTRIBUTE_PARTITION] |
239 }; | 226 }; |
240 this.srcAndPartitionObserver.observe(this.webviewNode, params); | 227 this.srcAndPartitionObserver.observe(this.webviewNode, params); |
241 }; | 228 }; |
242 | 229 |
243 // This observer monitors mutations to attributes of the <webview> and | 230 // This observer monitors mutations to attributes of the <webview> and |
244 // updates the BrowserPlugin properties accordingly. In turn, updating | 231 // updates the BrowserPlugin properties accordingly. In turn, updating |
245 // a BrowserPlugin property will update the corresponding BrowserPlugin | 232 // a BrowserPlugin property will update the corresponding BrowserPlugin |
246 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more | 233 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more |
247 // details. | 234 // details. |
248 WebView.prototype.handleWebviewAttributeMutation = | 235 WebView.prototype.handleWebviewAttributeMutation = |
249 function(name, oldValue, newValue) { | 236 function(attributeName, oldValue, newValue) { |
250 if (AUTO_SIZE_ATTRIBUTES.indexOf(name) > -1) { | 237 // Certain changes (such as internally-initiated changes) to attributes should |
251 this.attributes[name].setValue(newValue); | 238 // not be handled normally. |
| 239 if (this.attributes[attributeName] && |
| 240 this.attributes[attributeName].ignoreNextMutation) { |
| 241 this.attributes[attributeName].ignoreNextMutation = false; |
| 242 return; |
| 243 } |
| 244 |
| 245 if (AUTO_SIZE_ATTRIBUTES.indexOf(attributeName) > -1) { |
252 if (!this.guestInstanceId) { | 246 if (!this.guestInstanceId) { |
253 return; | 247 return; |
254 } | 248 } |
255 // Convert autosize attribute to boolean. | |
256 var autosize = this.webviewNode.hasAttribute( | |
257 WebViewConstants.ATTRIBUTE_AUTOSIZE); | |
258 GuestViewInternal.setAutoSize(this.guestInstanceId, { | 249 GuestViewInternal.setAutoSize(this.guestInstanceId, { |
259 'enableAutoSize': autosize, | 250 'enableAutoSize': this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE]. |
| 251 getValue(), |
260 'min': { | 252 'min': { |
261 'width': parseInt(this. | 253 'width': parseInt(this. |
262 attributes[WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), | 254 attributes[WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), |
263 'height': parseInt(this. | 255 'height': parseInt(this. |
264 attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) | 256 attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) |
265 }, | 257 }, |
266 'max': { | 258 'max': { |
267 'width': parseInt(this. | 259 'width': parseInt(this. |
268 attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), | 260 attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), |
269 'height': parseInt(this. | 261 'height': parseInt(this. |
270 attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) | 262 attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) |
271 } | 263 } |
272 }); | 264 }); |
273 return; | 265 return; |
274 } else if (name == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { | 266 } else if (attributeName == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { |
275 // We treat null attribute (attribute removed) and the empty string as | 267 // We treat null attribute (attribute removed) and the empty string as |
276 // one case. | 268 // one case. |
277 oldValue = oldValue || ''; | 269 oldValue = oldValue || ''; |
278 newValue = newValue || ''; | 270 newValue = newValue || ''; |
279 | 271 |
280 if (oldValue === newValue) { | 272 if (oldValue === newValue || !this.guestInstanceId) { |
281 return; | |
282 } | |
283 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. | |
284 setValue(newValue != ''); | |
285 | |
286 if (!this.guestInstanceId) { | |
287 return; | 273 return; |
288 } | 274 } |
289 | 275 |
290 WebViewInternal.setAllowTransparency( | 276 WebViewInternal.setAllowTransparency( |
291 this.guestInstanceId, | 277 this.guestInstanceId, |
292 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. | 278 this.attributes[WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY]. |
293 getValue()); | 279 getValue()); |
294 return; | 280 return; |
295 } else if (name == WebViewConstants.ATTRIBUTE_NAME) { | 281 } else if (attributeName == WebViewConstants.ATTRIBUTE_NAME) { |
296 // We treat null attribute (attribute removed) and the empty string as | 282 // We treat null attribute (attribute removed) and the empty string as |
297 // one case. | 283 // one case. |
298 oldValue = oldValue || ''; | 284 oldValue = oldValue || ''; |
299 newValue = newValue || ''; | 285 newValue = newValue || ''; |
300 | 286 |
301 if (oldValue === newValue) { | 287 if (oldValue === newValue) { |
302 return; | 288 return; |
303 } | 289 } |
304 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(newValue); | 290 |
305 if (!this.guestInstanceId) { | 291 if (!this.guestInstanceId) { |
306 return; | 292 return; |
307 } | 293 } |
308 WebViewInternal.setName(this.guestInstanceId, newValue); | 294 WebViewInternal.setName(this.guestInstanceId, newValue); |
309 return; | 295 return; |
310 } else if (name == WebViewConstants.ATTRIBUTE_SRC) { | 296 } else if (attributeName == WebViewConstants.ATTRIBUTE_SRC) { |
311 // We treat null attribute (attribute removed) and the empty string as | 297 // We treat null attribute (attribute removed) and the empty string as |
312 // one case. | 298 // one case. |
313 oldValue = oldValue || ''; | 299 oldValue = oldValue || ''; |
314 newValue = newValue || ''; | 300 newValue = newValue || ''; |
315 // Once we have navigated, we don't allow clearing the src attribute. | 301 // Once we have navigated, we don't allow clearing the src attribute. |
316 // Once <webview> enters a navigated state, it cannot be return back to a | 302 // Once <webview> enters a navigated state, it cannot return to a |
317 // placeholder state. | 303 // placeholder state. |
318 if (newValue == '' && oldValue != '') { | 304 if (newValue == '' && oldValue != '') { |
319 // src attribute changes normally initiate a navigation. We suppress | 305 // src attribute changes normally initiate a navigation. We suppress |
320 // the next src attribute handler call to avoid reloading the page | 306 // the next src attribute handler call to avoid reloading the page |
321 // on every guest-initiated navigation. | 307 // on every guest-initiated navigation. |
322 this.ignoreNextSrcAttributeChange = true; | 308 this.ignoreNextSrcAttributeChange = true; |
323 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, oldValue); | 309 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, oldValue); |
324 return; | 310 return; |
325 } | 311 } |
326 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue(newValue); | 312 |
327 if (this.ignoreNextSrcAttributeChange) { | 313 if (this.ignoreNextSrcAttributeChange) { |
328 // Don't allow the src mutation observer to see this change. | 314 // Don't allow the src mutation observer to see this change. |
329 this.srcAndPartitionObserver.takeRecords(); | 315 this.srcAndPartitionObserver.takeRecords(); |
330 this.ignoreNextSrcAttributeChange = false; | 316 this.ignoreNextSrcAttributeChange = false; |
331 return; | 317 return; |
332 } | 318 } |
333 var result = {}; | 319 this.parseSrcAttribute(); |
334 this.parseSrcAttribute(result); | 320 } else if (attributeName == WebViewConstants.ATTRIBUTE_PARTITION) { |
335 | 321 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].handleMutation( |
336 if (result.error) { | 322 oldValue, newValue); |
337 throw result.error; | |
338 } | |
339 } else if (name == WebViewConstants.ATTRIBUTE_PARTITION) { | |
340 // Note that throwing error here won't synchronously propagate. | |
341 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue(newValue); | |
342 } | 323 } |
343 }; | 324 }; |
344 | 325 |
345 WebView.prototype.handleBrowserPluginAttributeMutation = | 326 WebView.prototype.handleBrowserPluginAttributeMutation = |
346 function(name, oldValue, newValue) { | 327 function(attributeName, oldValue, newValue) { |
347 if (name == WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID && | 328 if (attributeName == WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID && |
348 !oldValue && !!newValue) { | 329 !oldValue && !!newValue) { |
349 this.browserPluginNode.removeAttribute( | 330 this.browserPluginNode.removeAttribute( |
350 WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID); | 331 WebViewConstants.ATTRIBUTE_INTERNALINSTANCEID); |
351 this.internalInstanceId = parseInt(newValue); | 332 this.internalInstanceId = parseInt(newValue); |
352 | 333 |
353 if (!!this.guestInstanceId && this.guestInstanceId != 0) { | 334 if (!!this.guestInstanceId && this.guestInstanceId != 0) { |
354 var isNewWindow = this.deferredAttachState ? | 335 var isNewWindow = this.deferredAttachState ? |
355 this.deferredAttachState.isNewWindow : false; | 336 this.deferredAttachState.isNewWindow : false; |
356 var params = this.buildAttachParams(isNewWindow); | 337 var params = this.buildAttachParams(isNewWindow); |
357 guestViewInternalNatives.AttachGuest( | 338 guestViewInternalNatives.AttachGuest( |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 if (node.hasAttribute(WebViewConstants.ATTRIBUTE_MINHEIGHT) && | 391 if (node.hasAttribute(WebViewConstants.ATTRIBUTE_MINHEIGHT) && |
411 node[WebViewConstants.ATTRIBUTE_MINHEIGHT]) { | 392 node[WebViewConstants.ATTRIBUTE_MINHEIGHT]) { |
412 minHeight = node[WebViewConstants.ATTRIBUTE_MINHEIGHT]; | 393 minHeight = node[WebViewConstants.ATTRIBUTE_MINHEIGHT]; |
413 } else { | 394 } else { |
414 minHeight = height; | 395 minHeight = height; |
415 } | 396 } |
416 if (minHeight > maxHeight) { | 397 if (minHeight > maxHeight) { |
417 minHeight = maxHeight; | 398 minHeight = maxHeight; |
418 } | 399 } |
419 | 400 |
420 if (!this.webviewNode.hasAttribute(WebViewConstants.ATTRIBUTE_AUTOSIZE) || | 401 if (!this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue() || |
421 (newWidth >= minWidth && | 402 (newWidth >= minWidth && |
422 newWidth <= maxWidth && | 403 newWidth <= maxWidth && |
423 newHeight >= minHeight && | 404 newHeight >= minHeight && |
424 newHeight <= maxHeight)) { | 405 newHeight <= maxHeight)) { |
425 node.style.width = newWidth + 'px'; | 406 node.style.width = newWidth + 'px'; |
426 node.style.height = newHeight + 'px'; | 407 node.style.height = newHeight + 'px'; |
427 // Only fire the DOM event if the size of the <webview> has actually | 408 // Only fire the DOM event if the size of the <webview> has actually |
428 // changed. | 409 // changed. |
429 this.dispatchEvent(webViewEvent); | 410 this.dispatchEvent(webViewEvent); |
430 } | 411 } |
431 }; | 412 }; |
432 | 413 |
433 // Returns if <object> is in the render tree. | 414 // Returns if <object> is in the render tree. |
434 WebView.prototype.isPluginInRenderTree = function() { | 415 WebView.prototype.isPluginInRenderTree = function() { |
435 return !!this.internalInstanceId && this.internalInstanceId != 0; | 416 return !!this.internalInstanceId && this.internalInstanceId != 0; |
436 }; | 417 }; |
437 | 418 |
438 WebView.prototype.hasNavigated = function() { | 419 WebView.prototype.hasNavigated = function() { |
439 return !this.beforeFirstNavigation; | 420 return !this.beforeFirstNavigation; |
440 }; | 421 }; |
441 | 422 |
442 WebView.prototype.parseSrcAttribute = function(result) { | 423 WebView.prototype.parseSrcAttribute = function() { |
443 if (!this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId) { | 424 if (!this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId || |
444 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | 425 !this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()) { |
445 return; | |
446 } | |
447 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue( | |
448 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC)); | |
449 | |
450 if (!this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()) { | |
451 return; | 426 return; |
452 } | 427 } |
453 | 428 |
454 if (this.guestInstanceId == undefined) { | 429 if (this.guestInstanceId == undefined) { |
455 if (this.beforeFirstNavigation) { | 430 if (this.beforeFirstNavigation) { |
456 this.beforeFirstNavigation = false; | 431 this.beforeFirstNavigation = false; |
457 this.createGuest(); | 432 this.createGuest(); |
458 } | 433 } |
459 return; | 434 return; |
460 } | 435 } |
461 | 436 |
462 // Navigate to |this.src|. | 437 // Navigate to |this.src|. |
463 WebViewInternal.navigate( | 438 WebViewInternal.navigate( |
464 this.guestInstanceId, | 439 this.guestInstanceId, |
465 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()); | 440 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()); |
466 }; | 441 }; |
467 | 442 |
468 WebView.prototype.parseAttributes = function() { | 443 WebView.prototype.parseAttributes = function() { |
469 if (!this.elementAttached) { | 444 if (!this.elementAttached) { |
470 return; | 445 return; |
471 } | 446 } |
472 var attributeValue = this.webviewNode.getAttribute( | 447 this.parseSrcAttribute(); |
473 WebViewConstants.ATTRIBUTE_PARTITION); | |
474 var result = this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( | |
475 attributeValue); | |
476 this.parseSrcAttribute(result); | |
477 }; | 448 }; |
478 | 449 |
479 WebView.prototype.createGuest = function() { | 450 WebView.prototype.createGuest = function() { |
480 if (this.pendingGuestCreation) { | 451 if (this.pendingGuestCreation) { |
481 return; | 452 return; |
482 } | 453 } |
483 var storagePartitionId = | |
484 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_PARTITION) || | |
485 this.webviewNode[WebViewConstants.ATTRIBUTE_PARTITION]; | |
486 var params = { | 454 var params = { |
487 'storagePartitionId': storagePartitionId | 455 'storagePartitionId': this.attributes[ |
| 456 WebViewConstants.ATTRIBUTE_PARTITION].getValue() |
488 }; | 457 }; |
489 GuestViewInternal.createGuest( | 458 GuestViewInternal.createGuest( |
490 'webview', | 459 'webview', |
491 params, | 460 params, |
492 function(guestInstanceId) { | 461 function(guestInstanceId) { |
493 this.pendingGuestCreation = false; | 462 this.pendingGuestCreation = false; |
494 if (!this.elementAttached) { | 463 if (!this.elementAttached) { |
495 GuestViewInternal.destroyGuest(guestInstanceId); | 464 GuestViewInternal.destroyGuest(guestInstanceId); |
496 return; | 465 return; |
497 } | 466 } |
498 this.attachWindow(guestInstanceId, false); | 467 this.attachWindow(guestInstanceId, false); |
499 }.bind(this) | 468 }.bind(this) |
500 ); | 469 ); |
501 this.pendingGuestCreation = true; | 470 this.pendingGuestCreation = true; |
502 }; | 471 }; |
503 | 472 |
504 WebView.prototype.onFrameNameChanged = function(name) { | 473 WebView.prototype.onFrameNameChanged = function(name) { |
505 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(name || ''); | 474 name = name || ''; |
506 if (this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue() === '') { | 475 if (name === '') { |
507 this.webviewNode.removeAttribute(WebViewConstants.ATTRIBUTE_NAME); | 476 this.webviewNode.removeAttribute(WebViewConstants.ATTRIBUTE_NAME); |
508 } else { | 477 } else { |
509 this.webviewNode.setAttribute( | 478 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(name); |
510 WebViewConstants.ATTRIBUTE_NAME, | |
511 this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue()); | |
512 } | 479 } |
513 }; | 480 }; |
514 | 481 |
515 WebView.prototype.dispatchEvent = function(webViewEvent) { | 482 WebView.prototype.dispatchEvent = function(webViewEvent) { |
516 return this.webviewNode.dispatchEvent(webViewEvent); | 483 return this.webviewNode.dispatchEvent(webViewEvent); |
517 }; | 484 }; |
518 | 485 |
519 // Adds an 'on<event>' property on the webview, which can be used to set/unset | 486 // Adds an 'on<event>' property on the webview, which can be used to set/unset |
520 // an event handler. | 487 // an event handler. |
521 WebView.prototype.setupEventProperty = function(eventName) { | 488 WebView.prototype.setupEventProperty = function(eventName) { |
(...skipping 14 matching lines...) Expand all Loading... |
536 }; | 503 }; |
537 | 504 |
538 // Updates state upon loadcommit. | 505 // Updates state upon loadcommit. |
539 WebView.prototype.onLoadCommit = function( | 506 WebView.prototype.onLoadCommit = function( |
540 baseUrlForDataUrl, currentEntryIndex, entryCount, | 507 baseUrlForDataUrl, currentEntryIndex, entryCount, |
541 processId, url, isTopLevel) { | 508 processId, url, isTopLevel) { |
542 this.baseUrlForDataUrl = baseUrlForDataUrl; | 509 this.baseUrlForDataUrl = baseUrlForDataUrl; |
543 this.currentEntryIndex = currentEntryIndex; | 510 this.currentEntryIndex = currentEntryIndex; |
544 this.entryCount = entryCount; | 511 this.entryCount = entryCount; |
545 this.processId = processId; | 512 this.processId = processId; |
546 var oldValue = this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC); | 513 var oldValue = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
547 var newValue = url; | 514 var newValue = url; |
548 if (isTopLevel && (oldValue != newValue)) { | 515 if (isTopLevel && (oldValue != newValue)) { |
549 // Touching the src attribute triggers a navigation. To avoid | 516 // Touching the src attribute triggers a navigation. To avoid |
550 // triggering a page reload on every guest-initiated navigation, | 517 // triggering a page reload on every guest-initiated navigation, |
551 // we use the flag ignoreNextSrcAttributeChange here. | 518 // we use the flag ignoreNextSrcAttributeChange here. |
552 this.ignoreNextSrcAttributeChange = true; | 519 this.ignoreNextSrcAttributeChange = true; |
553 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, newValue); | 520 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, newValue); |
554 } | 521 } |
555 }; | 522 }; |
556 | 523 |
557 WebView.prototype.onAttach = function(storagePartitionId) { | 524 WebView.prototype.onAttach = function(storagePartitionId) { |
558 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_PARTITION, | |
559 storagePartitionId); | |
560 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( | 525 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( |
561 storagePartitionId); | 526 storagePartitionId); |
562 }; | 527 }; |
563 | 528 |
564 WebView.prototype.buildAttachParams = function(isNewWindow) { | 529 WebView.prototype.buildAttachParams = function(isNewWindow) { |
565 var params = { | 530 var params = { |
566 'allowtransparency': this.attributes[ | 531 'allowtransparency': this.attributes[ |
567 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue() || false, | 532 WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY].getValue(), |
568 'autosize': this.webviewNode.hasAttribute( | 533 'autosize': this.attributes[WebViewConstants.ATTRIBUTE_AUTOSIZE].getValue(), |
569 WebViewConstants.ATTRIBUTE_AUTOSIZE), | |
570 'instanceId': this.viewInstanceId, | 534 'instanceId': this.viewInstanceId, |
571 'maxheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT]. | 535 'maxheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT]. |
572 getValue() || 0), | 536 getValue() || 0), |
573 'maxwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH]. | 537 'maxwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH]. |
574 getValue() || 0), | 538 getValue() || 0), |
575 'minheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT]. | 539 'minheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT]. |
576 getValue() || 0), | 540 getValue() || 0), |
577 'minwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINWIDTH]. | 541 'minwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINWIDTH]. |
578 getValue() || 0), | 542 getValue() || 0), |
579 'name': this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(), | 543 'name': this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(), |
580 // We don't need to navigate new window from here. | 544 // We don't need to navigate new window from here. |
581 'src': isNewWindow ? undefined : | 545 'src': isNewWindow ? undefined : |
582 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(), | 546 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(), |
583 // If we have a partition from the opener, that will also be already | 547 // If we have a partition from the opener, that will also be already |
584 // set via this.onAttach(). | 548 // set via this.onAttach(). |
585 'storagePartitionId': this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. | 549 'storagePartitionId': this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. |
586 getValue(), | 550 getValue(), |
587 'userAgentOverride': this.userAgentOverride | 551 'userAgentOverride': this.userAgentOverride |
588 }; | 552 }; |
589 return params; | 553 return params; |
590 }; | 554 }; |
591 | 555 |
592 WebView.prototype.attachWindow = function(guestInstanceId, | 556 WebView.prototype.attachWindow = function(guestInstanceId, |
593 isNewWindow) { | 557 isNewWindow) { |
594 this.guestInstanceId = guestInstanceId; | 558 this.guestInstanceId = guestInstanceId; |
595 var params = this.buildAttachParams(isNewWindow); | 559 var params = this.buildAttachParams(isNewWindow); |
596 | 560 |
597 if (!this.isPluginInRenderTree()) { | 561 if (!this.isPluginInRenderTree()) { |
598 this.deferredAttachState = {isNewWindow: isNewWindow}; | 562 this.deferredAttachState = {isNewWindow: isNewWindow}; |
599 return true; | 563 return true; |
600 } | 564 } |
601 | 565 |
602 this.deferredAttachState = null; | 566 this.deferredAttachState = null; |
603 return guestViewInternalNatives.AttachGuest( | 567 return guestViewInternalNatives.AttachGuest( |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
903 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; | 867 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; |
904 | 868 |
905 // Implemented when the experimental WebView API is available. | 869 // Implemented when the experimental WebView API is available. |
906 WebView.maybeGetExperimentalAPIs = function() {}; | 870 WebView.maybeGetExperimentalAPIs = function() {}; |
907 WebView.prototype.maybeGetExperimentalEvents = function() {}; | 871 WebView.prototype.maybeGetExperimentalEvents = function() {}; |
908 WebView.prototype.setupExperimentalContextMenus = function() {}; | 872 WebView.prototype.setupExperimentalContextMenus = function() {}; |
909 | 873 |
910 // Exports. | 874 // Exports. |
911 exports.WebView = WebView; | 875 exports.WebView = WebView; |
912 exports.WebViewInternal = WebViewInternal; | 876 exports.WebViewInternal = WebViewInternal; |
OLD | NEW |