| 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 |