Chromium Code Reviews| 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. | |
| 19 var BROWSER_PLUGIN_ATTRIBUTE_INTERNALINSTANCEID = 'internalinstanceid' | |
|
Fady Samuel
2014/10/22 21:48:26
Move to WebViewConstants?
paulmeyer
2014/10/23 21:39:56
Done.
| |
| 18 var AUTO_SIZE_ATTRIBUTES = [ | 20 var AUTO_SIZE_ATTRIBUTES = [ |
| 19 WebViewConstants.ATTRIBUTE_AUTOSIZE, | 21 WebViewConstants.ATTRIBUTE_AUTOSIZE, |
| 20 WebViewConstants.ATTRIBUTE_MAXHEIGHT, | 22 WebViewConstants.ATTRIBUTE_MAXHEIGHT, |
| 21 WebViewConstants.ATTRIBUTE_MAXWIDTH, | 23 WebViewConstants.ATTRIBUTE_MAXWIDTH, |
| 22 WebViewConstants.ATTRIBUTE_MINHEIGHT, | 24 WebViewConstants.ATTRIBUTE_MINHEIGHT, |
| 23 WebViewConstants.ATTRIBUTE_MINWIDTH | 25 WebViewConstants.ATTRIBUTE_MINWIDTH |
| 24 ]; | 26 ]; |
| 25 | 27 |
| 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. | 28 // Represents the internal state of the WebView node. |
| 68 function WebView(webviewNode) { | 29 function WebView(webviewNode) { |
| 69 privates(webviewNode).internal = this; | 30 privates(webviewNode).internal = this; |
| 70 this.webviewNode = webviewNode; | 31 this.webviewNode = webviewNode; |
| 71 this.attached = false; | 32 this.attached = false; |
| 72 this.pendingGuestCreation = false; | 33 this.pendingGuestCreation = false; |
| 73 this.elementAttached = false; | 34 this.elementAttached = false; |
| 74 | 35 |
| 75 this.beforeFirstNavigation = true; | 36 this.beforeFirstNavigation = true; |
| 76 this.contentWindow = null; | 37 this.contentWindow = null; |
| 77 this.validPartitionId = true; | 38 this.validPartitionId = true; |
| 78 // Used to save some state upon deferred attachment. | 39 // Used to save some state upon deferred attachment. |
| 79 // If <object> bindings is not available, we defer attachment. | 40 // If <object> bindings is not available, we defer attachment. |
| 80 // This state contains whether or not the attachment request was for | 41 // This state contains whether or not the attachment request was for |
| 81 // newwindow. | 42 // newwindow. |
| 82 this.deferredAttachState = null; | 43 this.deferredAttachState = null; |
| 83 | 44 |
| 84 // on* Event handlers. | 45 // on* Event handlers. |
| 85 this.on = {}; | 46 this.on = {}; |
| 86 | 47 |
| 87 this.browserPluginNode = this.createBrowserPluginNode(); | 48 this.browserPluginNode = this.createBrowserPluginNode(); |
| 88 var shadowRoot = this.webviewNode.createShadowRoot(); | 49 var shadowRoot = this.webviewNode.createShadowRoot(); |
| 89 this.partition = new Partition(); | 50 this.setupWebViewAttributes(); |
| 90 | |
| 91 this.setupWebViewSrcAttributeMutationObserver(); | 51 this.setupWebViewSrcAttributeMutationObserver(); |
| 92 this.setupFocusPropagation(); | 52 this.setupFocusPropagation(); |
| 93 this.setupWebviewNodeProperties(); | 53 this.setupWebviewNodeProperties(); |
| 94 | 54 |
| 95 this.viewInstanceId = IdGenerator.GetNextId(); | 55 this.viewInstanceId = IdGenerator.GetNextId(); |
| 96 | 56 |
| 97 new WebViewEvents(this, this.viewInstanceId); | 57 new WebViewEvents(this, this.viewInstanceId); |
| 98 | 58 |
| 99 shadowRoot.appendChild(this.browserPluginNode); | 59 shadowRoot.appendChild(this.browserPluginNode); |
| 100 } | 60 } |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 117 // already picked up a partition ID. Thus, we need to reset the initialization | 77 // 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 | 78 // 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 | 79 // 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 | 80 // 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. | 81 // that we don't end up allocating a second guest. |
| 122 if (this.guestInstanceId) { | 82 if (this.guestInstanceId) { |
| 123 GuestViewInternal.destroyGuest(this.guestInstanceId); | 83 GuestViewInternal.destroyGuest(this.guestInstanceId); |
| 124 this.guestInstanceId = undefined; | 84 this.guestInstanceId = undefined; |
| 125 this.beforeFirstNavigation = true; | 85 this.beforeFirstNavigation = true; |
| 126 this.validPartitionId = true; | 86 this.validPartitionId = true; |
| 127 this.partition.validPartitionId = true; | 87 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId = |
| 88 true; | |
| 128 this.contentWindow = null; | 89 this.contentWindow = null; |
| 129 } | 90 } |
| 130 this.internalInstanceId = 0; | 91 this.internalInstanceId = 0; |
| 131 }; | 92 }; |
| 132 | 93 |
| 133 // Sets the <webview>.request property. | 94 // Sets the <webview>.request property. |
| 134 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { | 95 WebView.prototype.setRequestPropertyOnWebViewNode = function(request) { |
| 135 Object.defineProperty( | 96 Object.defineProperty( |
| 136 this.webviewNode, | 97 this.webviewNode, |
| 137 'request', | 98 'request', |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 162 | 123 |
| 163 // Validation helper function for executeScript() and insertCSS(). | 124 // Validation helper function for executeScript() and insertCSS(). |
| 164 WebView.prototype.validateExecuteCodeCall = function() { | 125 WebView.prototype.validateExecuteCodeCall = function() { |
| 165 if (!this.guestInstanceId) { | 126 if (!this.guestInstanceId) { |
| 166 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); | 127 throw new Error(WebViewConstants.ERROR_MSG_CANNOT_INJECT_SCRIPT); |
| 167 } | 128 } |
| 168 }; | 129 }; |
| 169 | 130 |
| 170 WebView.prototype.setupAutoSizeProperties = function() { | 131 WebView.prototype.setupAutoSizeProperties = function() { |
| 171 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { | 132 $Array.forEach(AUTO_SIZE_ATTRIBUTES, function(attributeName) { |
| 172 this[attributeName] = this.webviewNode.getAttribute(attributeName); | 133 this.attributes[attributeName].setValue( |
| 134 this.webviewNode.getAttribute(attributeName)); | |
| 173 Object.defineProperty(this.webviewNode, attributeName, { | 135 Object.defineProperty(this.webviewNode, attributeName, { |
| 174 get: function() { | 136 get: function() { |
| 175 return this[attributeName]; | 137 return this.attributes[attributeName]; |
| 176 }.bind(this), | 138 }.bind(this), |
| 177 set: function(value) { | 139 set: function(value) { |
| 178 this.webviewNode.setAttribute(attributeName, value); | 140 this.webviewNode.setAttribute(attributeName, value); |
| 179 }.bind(this), | 141 }.bind(this), |
| 180 enumerable: true | 142 enumerable: true |
| 181 }); | 143 }); |
| 182 }.bind(this), this); | 144 }.bind(this), this); |
| 183 }; | 145 }; |
| 184 | 146 |
| 185 WebView.prototype.setupWebviewNodeProperties = function() { | 147 WebView.prototype.setupWebviewNodeProperties = function() { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 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] = 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. |
| 256 // TODO(paulmeyer) is this right? | |
|
Fady Samuel
2014/10/22 21:48:26
Yes, we're not looking specifically for any value
paulmeyer
2014/10/23 21:39:56
Acknowledged.
| |
| 290 var autosize = this.webviewNode.hasAttribute( | 257 var autosize = this.webviewNode.hasAttribute( |
| 291 WebViewConstants.ATTRIBUTE_AUTOSIZE); | 258 WebViewConstants.ATTRIBUTE_AUTOSIZE); |
| 292 GuestViewInternal.setAutoSize(this.guestInstanceId, { | 259 GuestViewInternal.setAutoSize(this.guestInstanceId, { |
| 293 'enableAutoSize': autosize, | 260 'enableAutoSize': autosize, |
| 294 'min': { | 261 'min': { |
| 295 'width': parseInt(this.minwidth || 0), | 262 'width': parseInt(this. |
| 296 'height': parseInt(this.minheight || 0) | 263 attributes[WebViewConstants.ATTRIBUTE_MINWIDTH].getValue() || 0), |
| 264 'height': parseInt(this. | |
| 265 attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT].getValue() || 0) | |
| 297 }, | 266 }, |
| 298 'max': { | 267 'max': { |
| 299 'width': parseInt(this.maxwidth || 0), | 268 'width': parseInt(this. |
| 300 'height': parseInt(this.maxheight || 0) | 269 attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH].getValue() || 0), |
| 270 'height': parseInt(this. | |
| 271 attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT].getValue() || 0) | |
| 301 } | 272 } |
| 302 }); | 273 }); |
| 303 return; | 274 return; |
| 304 } else if (name == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { | 275 } else if (name == WebViewConstants.ATTRIBUTE_ALLOWTRANSPARENCY) { |
| 305 // We treat null attribute (attribute removed) and the empty string as | 276 // We treat null attribute (attribute removed) and the empty string as |
| 306 // one case. | 277 // one case. |
| 307 oldValue = oldValue || ''; | 278 oldValue = oldValue || ''; |
| 308 newValue = newValue || ''; | 279 newValue = newValue || ''; |
| 309 | 280 |
| 310 if (oldValue === newValue) { | 281 if (oldValue === newValue) { |
| 311 return; | 282 return; |
| 312 } | 283 } |
| 313 this.allowtransparency = newValue != ''; | 284 this.allowtransparency = 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(this.guestInstanceId, |
| 320 this.allowtransparency); | 291 this.allowtransparency); |
| 321 return; | 292 return; |
| 322 } else if (name == 'name') { | 293 } else if (name == WebViewConstants.ATTRIBUTE_NAME) { |
| 323 // We treat null attribute (attribute removed) and the empty string as | 294 // We treat null attribute (attribute removed) and the empty string as |
| 324 // one case. | 295 // one case. |
| 325 oldValue = oldValue || ''; | 296 oldValue = oldValue || ''; |
| 326 newValue = newValue || ''; | 297 newValue = newValue || ''; |
| 327 | 298 |
| 328 if (oldValue === newValue) { | 299 if (oldValue === newValue) { |
| 329 return; | 300 return; |
| 330 } | 301 } |
| 331 this.name = newValue; | 302 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(newValue); |
| 332 if (!this.guestInstanceId) { | 303 if (!this.guestInstanceId) { |
| 333 return; | 304 return; |
| 334 } | 305 } |
| 335 WebViewInternal.setName(this.guestInstanceId, newValue); | 306 WebViewInternal.setName(this.guestInstanceId, newValue); |
| 336 return; | 307 return; |
| 337 } else if (name == 'src') { | 308 } else if (name == WebViewConstants.ATTRIBUTE_SRC) { |
| 338 // We treat null attribute (attribute removed) and the empty string as | 309 // We treat null attribute (attribute removed) and the empty string as |
| 339 // one case. | 310 // one case. |
| 340 oldValue = oldValue || ''; | 311 oldValue = oldValue || ''; |
| 341 newValue = newValue || ''; | 312 newValue = newValue || ''; |
| 342 // Once we have navigated, we don't allow clearing the src attribute. | 313 // 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 | 314 // Once <webview> enters a navigated state, it cannot be return back to a |
| 344 // placeholder state. | 315 // placeholder state. |
| 345 if (newValue == '' && oldValue != '') { | 316 if (newValue == '' && oldValue != '') { |
| 346 // src attribute changes normally initiate a navigation. We suppress | 317 // src attribute changes normally initiate a navigation. We suppress |
| 347 // the next src attribute handler call to avoid reloading the page | 318 // the next src attribute handler call to avoid reloading the page |
| 348 // on every guest-initiated navigation. | 319 // on every guest-initiated navigation. |
| 349 this.ignoreNextSrcAttributeChange = true; | 320 this.ignoreNextSrcAttributeChange = true; |
| 350 this.webviewNode.setAttribute('src', oldValue); | 321 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, oldValue); |
| 351 return; | 322 return; |
| 352 } | 323 } |
| 353 this.src = newValue; | 324 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue(newValue); |
| 354 if (this.ignoreNextSrcAttributeChange) { | 325 if (this.ignoreNextSrcAttributeChange) { |
| 355 // Don't allow the src mutation observer to see this change. | 326 // Don't allow the src mutation observer to see this change. |
| 356 this.srcAndPartitionObserver.takeRecords(); | 327 this.srcAndPartitionObserver.takeRecords(); |
| 357 this.ignoreNextSrcAttributeChange = false; | 328 this.ignoreNextSrcAttributeChange = false; |
| 358 return; | 329 return; |
| 359 } | 330 } |
| 360 var result = {}; | 331 var result = {}; |
| 361 this.parseSrcAttribute(result); | 332 this.parseSrcAttribute(result); |
| 362 | 333 |
| 363 if (result.error) { | 334 if (result.error) { |
| 364 throw result.error; | 335 throw result.error; |
| 365 } | 336 } |
| 366 } else if (name == 'partition') { | 337 } else if (name == WebViewConstants.ATTRIBUTE_PARTITION) { |
| 367 // Note that throwing error here won't synchronously propagate. | 338 // Note that throwing error here won't synchronously propagate. |
| 368 this.partition.fromAttribute(newValue, this.hasNavigated()); | 339 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue(newValue); |
| 369 } | 340 } |
| 370 }; | 341 }; |
| 371 | 342 |
| 372 WebView.prototype.handleBrowserPluginAttributeMutation = | 343 WebView.prototype.handleBrowserPluginAttributeMutation = |
| 373 function(name, oldValue, newValue) { | 344 function(name, oldValue, newValue) { |
| 374 if (name == 'internalinstanceid' && !oldValue && !!newValue) { | 345 if (name == BROWSER_PLUGIN_ATTRIBUTE_INTERNALINSTANCEID && |
| 375 this.browserPluginNode.removeAttribute('internalinstanceid'); | 346 !oldValue && !!newValue) { |
| 347 this.browserPluginNode.removeAttribute( | |
| 348 BROWSER_PLUGIN_ATTRIBUTE_INTERNALINSTANCEID); | |
| 376 this.internalInstanceId = parseInt(newValue); | 349 this.internalInstanceId = parseInt(newValue); |
| 377 | 350 |
| 378 if (!!this.guestInstanceId && this.guestInstanceId != 0) { | 351 if (!!this.guestInstanceId && this.guestInstanceId != 0) { |
| 379 var isNewWindow = this.deferredAttachState ? | 352 var isNewWindow = this.deferredAttachState ? |
| 380 this.deferredAttachState.isNewWindow : false; | 353 this.deferredAttachState.isNewWindow : false; |
| 381 var params = this.buildAttachParams(isNewWindow); | 354 var params = this.buildAttachParams(isNewWindow); |
| 382 guestViewInternalNatives.AttachGuest( | 355 guestViewInternalNatives.AttachGuest( |
| 383 this.internalInstanceId, | 356 this.internalInstanceId, |
| 384 this.guestInstanceId, | 357 this.guestInstanceId, |
| 385 params, | 358 params, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 // Returns if <object> is in the render tree. | 431 // Returns if <object> is in the render tree. |
| 459 WebView.prototype.isPluginInRenderTree = function() { | 432 WebView.prototype.isPluginInRenderTree = function() { |
| 460 return !!this.internalInstanceId && this.internalInstanceId != 0; | 433 return !!this.internalInstanceId && this.internalInstanceId != 0; |
| 461 }; | 434 }; |
| 462 | 435 |
| 463 WebView.prototype.hasNavigated = function() { | 436 WebView.prototype.hasNavigated = function() { |
| 464 return !this.beforeFirstNavigation; | 437 return !this.beforeFirstNavigation; |
| 465 }; | 438 }; |
| 466 | 439 |
| 467 WebView.prototype.parseSrcAttribute = function(result) { | 440 WebView.prototype.parseSrcAttribute = function(result) { |
| 468 if (!this.partition.validPartitionId) { | 441 if (!this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].validPartitionId) { |
| 469 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | 442 result.error = WebViewConstants.ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; |
| 470 return; | 443 return; |
| 471 } | 444 } |
| 472 this.src = this.webviewNode.getAttribute('src'); | 445 this.attributes[WebViewConstants.ATTRIBUTE_SRC].setValue( |
| 446 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC)); | |
| 473 | 447 |
| 474 if (!this.src) { | 448 if (!this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()) { |
| 475 return; | 449 return; |
| 476 } | 450 } |
| 477 | 451 |
| 478 if (this.guestInstanceId == undefined) { | 452 if (this.guestInstanceId == undefined) { |
| 479 if (this.beforeFirstNavigation) { | 453 if (this.beforeFirstNavigation) { |
| 480 this.beforeFirstNavigation = false; | 454 this.beforeFirstNavigation = false; |
| 481 this.createGuest(); | 455 this.createGuest(); |
| 482 } | 456 } |
| 483 return; | 457 return; |
| 484 } | 458 } |
| 485 | 459 |
| 486 // Navigate to |this.src|. | 460 // Navigate to |this.src|. |
| 487 WebViewInternal.navigate(this.guestInstanceId, this.src); | 461 WebViewInternal.navigate( |
| 462 this.guestInstanceId, | |
| 463 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue()); | |
| 488 }; | 464 }; |
| 489 | 465 |
| 490 WebView.prototype.parseAttributes = function() { | 466 WebView.prototype.parseAttributes = function() { |
| 491 if (!this.elementAttached) { | 467 if (!this.elementAttached) { |
| 492 return; | 468 return; |
| 493 } | 469 } |
| 494 var hasNavigated = this.hasNavigated(); | 470 var attributeValue = this.webviewNode.getAttribute( |
| 495 var attributeValue = this.webviewNode.getAttribute('partition'); | 471 WebViewConstants.ATTRIBUTE_PARTITION); |
| 496 var result = this.partition.fromAttribute(attributeValue, hasNavigated); | 472 var result = this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( |
| 473 attributeValue); | |
| 497 this.parseSrcAttribute(result); | 474 this.parseSrcAttribute(result); |
| 498 }; | 475 }; |
| 499 | 476 |
| 500 WebView.prototype.createGuest = function() { | 477 WebView.prototype.createGuest = function() { |
| 501 if (this.pendingGuestCreation) { | 478 if (this.pendingGuestCreation) { |
| 502 return; | 479 return; |
| 503 } | 480 } |
| 481 // TODO(paulmeyer) this looks wacky. | |
|
Fady Samuel
2014/10/22 21:48:26
Please ask Istiaque about this. I'm not sure why t
paulmeyer
2014/10/23 21:39:55
This will get cleaned up when I unify the storage/
| |
| 504 var storagePartitionId = | 482 var storagePartitionId = |
| 505 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_PARTITION) || | 483 this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_PARTITION) || |
| 506 this.webviewNode[WebViewConstants.ATTRIBUTE_PARTITION]; | 484 this.webviewNode[WebViewConstants.ATTRIBUTE_PARTITION]; |
| 507 var params = { | 485 var params = { |
| 508 'storagePartitionId': storagePartitionId | 486 'storagePartitionId': storagePartitionId |
| 509 }; | 487 }; |
| 510 GuestViewInternal.createGuest( | 488 GuestViewInternal.createGuest( |
| 511 'webview', | 489 'webview', |
| 512 params, | 490 params, |
| 513 function(guestInstanceId) { | 491 function(guestInstanceId) { |
| 514 this.pendingGuestCreation = false; | 492 this.pendingGuestCreation = false; |
| 515 if (!this.elementAttached) { | 493 if (!this.elementAttached) { |
| 516 GuestViewInternal.destroyGuest(guestInstanceId); | 494 GuestViewInternal.destroyGuest(guestInstanceId); |
| 517 return; | 495 return; |
| 518 } | 496 } |
| 519 this.attachWindow(guestInstanceId, false); | 497 this.attachWindow(guestInstanceId, false); |
| 520 }.bind(this) | 498 }.bind(this) |
| 521 ); | 499 ); |
| 522 this.pendingGuestCreation = true; | 500 this.pendingGuestCreation = true; |
| 523 }; | 501 }; |
| 524 | 502 |
| 525 WebView.prototype.onFrameNameChanged = function(name) { | 503 WebView.prototype.onFrameNameChanged = function(name) { |
| 526 this.name = name || ''; | 504 this.attributes[WebViewConstants.ATTRIBUTE_NAME].setValue(name || ''); |
| 527 if (this.name === '') { | 505 if (this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue() === '') { |
| 528 this.webviewNode.removeAttribute('name'); | 506 this.webviewNode.removeAttribute(WebViewConstants.ATTRIBUTE_NAME); |
| 529 } else { | 507 } else { |
| 530 this.webviewNode.setAttribute('name', this.name); | 508 this.webviewNode.setAttribute( |
| 509 WebViewConstants.ATTRIBUTE_NAME, | |
| 510 this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue()); | |
| 531 } | 511 } |
| 532 }; | 512 }; |
| 533 | 513 |
| 534 WebView.prototype.dispatchEvent = function(webViewEvent) { | 514 WebView.prototype.dispatchEvent = function(webViewEvent) { |
| 535 return this.webviewNode.dispatchEvent(webViewEvent); | 515 return this.webviewNode.dispatchEvent(webViewEvent); |
| 536 }; | 516 }; |
| 537 | 517 |
| 538 // Adds an 'on<event>' property on the webview, which can be used to set/unset | 518 // Adds an 'on<event>' property on the webview, which can be used to set/unset |
| 539 // an event handler. | 519 // an event handler. |
| 540 WebView.prototype.setupEventProperty = function(eventName) { | 520 WebView.prototype.setupEventProperty = function(eventName) { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 555 }; | 535 }; |
| 556 | 536 |
| 557 // Updates state upon loadcommit. | 537 // Updates state upon loadcommit. |
| 558 WebView.prototype.onLoadCommit = function( | 538 WebView.prototype.onLoadCommit = function( |
| 559 baseUrlForDataUrl, currentEntryIndex, entryCount, | 539 baseUrlForDataUrl, currentEntryIndex, entryCount, |
| 560 processId, url, isTopLevel) { | 540 processId, url, isTopLevel) { |
| 561 this.baseUrlForDataUrl = baseUrlForDataUrl; | 541 this.baseUrlForDataUrl = baseUrlForDataUrl; |
| 562 this.currentEntryIndex = currentEntryIndex; | 542 this.currentEntryIndex = currentEntryIndex; |
| 563 this.entryCount = entryCount; | 543 this.entryCount = entryCount; |
| 564 this.processId = processId; | 544 this.processId = processId; |
| 565 var oldValue = this.webviewNode.getAttribute('src'); | 545 var oldValue = this.webviewNode.getAttribute(WebViewConstants.ATTRIBUTE_SRC); |
| 566 var newValue = url; | 546 var newValue = url; |
| 567 if (isTopLevel && (oldValue != newValue)) { | 547 if (isTopLevel && (oldValue != newValue)) { |
| 568 // Touching the src attribute triggers a navigation. To avoid | 548 // Touching the src attribute triggers a navigation. To avoid |
| 569 // triggering a page reload on every guest-initiated navigation, | 549 // triggering a page reload on every guest-initiated navigation, |
| 570 // we use the flag ignoreNextSrcAttributeChange here. | 550 // we use the flag ignoreNextSrcAttributeChange here. |
| 571 this.ignoreNextSrcAttributeChange = true; | 551 this.ignoreNextSrcAttributeChange = true; |
| 572 this.webviewNode.setAttribute('src', newValue); | 552 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_SRC, newValue); |
| 573 } | 553 } |
| 574 }; | 554 }; |
| 575 | 555 |
| 576 WebView.prototype.onAttach = function(storagePartitionId) { | 556 WebView.prototype.onAttach = function(storagePartitionId) { |
| 577 this.webviewNode.setAttribute('partition', storagePartitionId); | 557 this.webviewNode.setAttribute(WebViewConstants.ATTRIBUTE_PARTITION, |
| 578 this.partition.fromAttribute(storagePartitionId, this.hasNavigated()); | 558 storagePartitionId); |
| 559 this.attributes[WebViewConstants.ATTRIBUTE_PARTITION].setValue( | |
| 560 storagePartitionId); | |
| 579 }; | 561 }; |
| 580 | 562 |
| 581 WebView.prototype.buildAttachParams = function(isNewWindow) { | 563 WebView.prototype.buildAttachParams = function(isNewWindow) { |
| 582 var params = { | 564 var params = { |
| 583 'allowtransparency': this.allowtransparency || false, | 565 'allowtransparency': this.allowtransparency || false, |
| 584 'autosize': this.webviewNode.hasAttribute( | 566 'autosize': this.webviewNode.hasAttribute( |
| 585 WebViewConstants.ATTRIBUTE_AUTOSIZE), | 567 WebViewConstants.ATTRIBUTE_AUTOSIZE), |
| 586 'instanceId': this.viewInstanceId, | 568 'instanceId': this.viewInstanceId, |
| 587 'maxheight': parseInt(this.maxheight || 0), | 569 'maxheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXHEIGHT]. |
|
Fady Samuel
2014/10/22 21:48:26
I feel like the key names should probably also mat
paulmeyer
2014/10/23 21:39:56
I agree, and hopefully there will be a nice concis
| |
| 588 'maxwidth': parseInt(this.maxwidth || 0), | 570 getValue() || 0), |
| 589 'minheight': parseInt(this.minheight || 0), | 571 'maxwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MAXWIDTH]. |
| 590 'minwidth': parseInt(this.minwidth || 0), | 572 getValue() || 0), |
| 591 'name': this.name, | 573 'minheight': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINHEIGHT]. |
| 574 getValue() || 0), | |
| 575 'minwidth': parseInt(this.attributes[WebViewConstants.ATTRIBUTE_MINWIDTH]. | |
| 576 getValue() || 0), | |
| 577 'name': this.attributes[WebViewConstants.ATTRIBUTE_NAME].getValue(), | |
| 592 // We don't need to navigate new window from here. | 578 // We don't need to navigate new window from here. |
| 593 'src': isNewWindow ? undefined : this.src, | 579 'src': isNewWindow ? undefined : |
| 580 this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(), | |
| 594 // If we have a partition from the opener, that will also be already | 581 // If we have a partition from the opener, that will also be already |
| 595 // set via this.onAttach(). | 582 // set via this.onAttach(). |
| 596 'storagePartitionId': this.partition.toAttribute(), | 583 'storagePartitionId': this.attributes[WebViewConstants.ATTRIBUTE_PARTITION]. |
| 584 getValue(), | |
| 597 'userAgentOverride': this.userAgentOverride | 585 'userAgentOverride': this.userAgentOverride |
| 598 }; | 586 }; |
| 599 return params; | 587 return params; |
| 600 }; | 588 }; |
| 601 | 589 |
| 602 WebView.prototype.attachWindow = function(guestInstanceId, | 590 WebView.prototype.attachWindow = function(guestInstanceId, |
| 603 isNewWindow) { | 591 isNewWindow) { |
| 604 this.guestInstanceId = guestInstanceId; | 592 this.guestInstanceId = guestInstanceId; |
| 605 var params = this.buildAttachParams(isNewWindow); | 593 var params = this.buildAttachParams(isNewWindow); |
| 606 | 594 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 644 if (!this.guestInstanceId) { | 632 if (!this.guestInstanceId) { |
| 645 return; | 633 return; |
| 646 } | 634 } |
| 647 var args = $Array.concat([this.guestInstanceId], $Array.slice(arguments)); | 635 var args = $Array.concat([this.guestInstanceId], $Array.slice(arguments)); |
| 648 $Function.apply(WebViewInternal.clearData, null, args); | 636 $Function.apply(WebViewInternal.clearData, null, args); |
| 649 }; | 637 }; |
| 650 | 638 |
| 651 // Injects JavaScript code into the guest page. | 639 // Injects JavaScript code into the guest page. |
| 652 WebView.prototype.executeScript = function(var_args) { | 640 WebView.prototype.executeScript = function(var_args) { |
| 653 this.validateExecuteCodeCall(); | 641 this.validateExecuteCodeCall(); |
| 654 var webviewSrc = this.src; | 642 var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
| 655 if (this.baseUrlForDataUrl != '') { | 643 if (this.baseUrlForDataUrl != '') { |
| 656 webviewSrc = this.baseUrlForDataUrl; | 644 webviewSrc = this.baseUrlForDataUrl; |
| 657 } | 645 } |
| 658 var args = $Array.concat([this.guestInstanceId, webviewSrc], | 646 var args = $Array.concat([this.guestInstanceId, webviewSrc], |
| 659 $Array.slice(arguments)); | 647 $Array.slice(arguments)); |
| 660 $Function.apply(WebViewInternal.executeScript, null, args); | 648 $Function.apply(WebViewInternal.executeScript, null, args); |
| 661 }; | 649 }; |
| 662 | 650 |
| 663 // Initiates a find-in-page request. | 651 // Initiates a find-in-page request. |
| 664 WebView.prototype.find = function(search_text, options, callback) { | 652 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) { | 685 WebView.prototype.go = function(relativeIndex, callback) { |
| 698 if (!this.guestInstanceId) { | 686 if (!this.guestInstanceId) { |
| 699 return; | 687 return; |
| 700 } | 688 } |
| 701 WebViewInternal.go(this.guestInstanceId, relativeIndex, callback); | 689 WebViewInternal.go(this.guestInstanceId, relativeIndex, callback); |
| 702 }; | 690 }; |
| 703 | 691 |
| 704 // Injects CSS into the guest page. | 692 // Injects CSS into the guest page. |
| 705 WebView.prototype.insertCSS = function(var_args) { | 693 WebView.prototype.insertCSS = function(var_args) { |
| 706 this.validateExecuteCodeCall(); | 694 this.validateExecuteCodeCall(); |
| 707 var webviewSrc = this.src; | 695 var webviewSrc = this.attributes[WebViewConstants.ATTRIBUTE_SRC].getValue(); |
| 708 if (this.baseUrlForDataUrl != '') { | 696 if (this.baseUrlForDataUrl != '') { |
| 709 webviewSrc = this.baseUrlForDataUrl; | 697 webviewSrc = this.baseUrlForDataUrl; |
| 710 } | 698 } |
| 711 var args = $Array.concat([this.guestInstanceId, webviewSrc], | 699 var args = $Array.concat([this.guestInstanceId, webviewSrc], |
| 712 $Array.slice(arguments)); | 700 $Array.slice(arguments)); |
| 713 $Function.apply(WebViewInternal.insertCSS, null, args); | 701 $Function.apply(WebViewInternal.insertCSS, null, args); |
| 714 }; | 702 }; |
| 715 | 703 |
| 716 // Indicates whether or not the webview's user agent string has been overridden. | 704 // Indicates whether or not the webview's user agent string has been overridden. |
| 717 WebView.prototype.isUserAgentOverridden = function() { | 705 WebView.prototype.isUserAgentOverridden = function() { |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; | 901 WebView.prototype.maybeGetChromeWebViewEvents = function() {}; |
| 914 | 902 |
| 915 // Implemented when the experimental WebView API is available. | 903 // Implemented when the experimental WebView API is available. |
| 916 WebView.maybeGetExperimentalAPIs = function() {}; | 904 WebView.maybeGetExperimentalAPIs = function() {}; |
| 917 WebView.prototype.maybeGetExperimentalEvents = function() {}; | 905 WebView.prototype.maybeGetExperimentalEvents = function() {}; |
| 918 WebView.prototype.setupExperimentalContextMenus = function() {}; | 906 WebView.prototype.setupExperimentalContextMenus = function() {}; |
| 919 | 907 |
| 920 // Exports. | 908 // Exports. |
| 921 exports.WebView = WebView; | 909 exports.WebView = WebView; |
| 922 exports.WebViewInternal = WebViewInternal; | 910 exports.WebViewInternal = WebViewInternal; |
| OLD | NEW |