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 EventBindings = require('event_bindings'); | 10 var EventBindings = require('event_bindings'); |
| 11 var IdGenerator = requireNative('id_generator'); | 11 var IdGenerator = requireNative('id_generator'); |
| 12 var MessagingNatives = requireNative('messaging_natives'); | 12 var MessagingNatives = requireNative('messaging_natives'); |
| 13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; | 13 var WebRequestEvent = require('webRequestInternal').WebRequestEvent; |
| 14 var WebRequestSchema = | 14 var WebRequestSchema = |
| 15 requireNative('schema_registry').GetSchema('webRequest'); | 15 requireNative('schema_registry').GetSchema('webRequest'); |
| 16 var DeclarativeWebRequestSchema = | 16 var DeclarativeWebRequestSchema = |
| 17 requireNative('schema_registry').GetSchema('declarativeWebRequest'); | 17 requireNative('schema_registry').GetSchema('declarativeWebRequest'); |
| 18 var WebView = require('webview').WebView; | 18 var WebView = require('webview').WebView; |
| 19 | 19 |
| 20 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; | 20 var WEB_VIEW_ATTRIBUTE_MAXHEIGHT = 'maxheight'; |
| 21 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; | 21 var WEB_VIEW_ATTRIBUTE_MAXWIDTH = 'maxwidth'; |
| 22 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; | 22 var WEB_VIEW_ATTRIBUTE_MINHEIGHT = 'minheight'; |
| 23 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; | 23 var WEB_VIEW_ATTRIBUTE_MINWIDTH = 'minwidth'; |
|
Fady Samuel
2014/05/27 14:19:06
I think we might start needing to think about refa
lazyboy
2014/05/27 20:43:00
Right, I was going in that direction by starting t
| |
| 24 var WEB_VIEW_ATTRIBUTE_PARTITION = 'partition'; | |
| 25 | |
| 26 var ERROR_MSG_ALREADY_NAVIGATED = | |
| 27 'The object has already navigated, so its partition cannot be changed.'; | |
| 28 var ERROR_MSG_INVALID_PARTITION_ATTRIBUTE = | |
| 29 'Invalid partition attribute.'; | |
| 30 | |
| 31 var LOG = function(msg) { | |
| 32 window.console.log(msg); | |
| 33 }; | |
| 24 | 34 |
| 25 /** @type {Array.<string>} */ | 35 /** @type {Array.<string>} */ |
| 26 var WEB_VIEW_ATTRIBUTES = [ | 36 var WEB_VIEW_ATTRIBUTES = [ |
| 27 'allowtransparency', | 37 'allowtransparency', |
| 28 'autosize', | 38 'autosize', |
| 29 'partition', | |
| 30 WEB_VIEW_ATTRIBUTE_MINHEIGHT, | 39 WEB_VIEW_ATTRIBUTE_MINHEIGHT, |
| 31 WEB_VIEW_ATTRIBUTE_MINWIDTH, | 40 WEB_VIEW_ATTRIBUTE_MINWIDTH, |
| 32 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, | 41 WEB_VIEW_ATTRIBUTE_MAXHEIGHT, |
| 33 WEB_VIEW_ATTRIBUTE_MAXWIDTH | 42 WEB_VIEW_ATTRIBUTE_MAXWIDTH |
| 34 ]; | 43 ]; |
| 35 | 44 |
| 45 /** @class representing state of storage partition. */ | |
| 46 function Partition() { | |
| 47 this.validPartitionId_ = true; | |
| 48 this.persist_storage_ = false; | |
| 49 this.storage_partition_id_ = ''; | |
| 50 }; | |
| 51 | |
| 52 Partition.prototype.toAttribute = function() { | |
| 53 LOG('Partition.toAttribute'); | |
| 54 if (!this.validPartitionId_) { | |
| 55 LOG('Warning we have invalid partition id'); | |
| 56 return ''; | |
| 57 } | |
| 58 return (this.persist_storage_ ? 'persist:' : '') + this.storage_partition_id_; | |
| 59 }; | |
| 60 | |
| 61 Partition.prototype.fromAttribute = function(value, hasNavigated) { | |
| 62 LOG('Partition.fromAttribute'); | |
| 63 LOG('value: ' + value + ', hasNavigated: ' + hasNavigated); | |
| 64 var result = {}; | |
| 65 if (hasNavigated) { | |
| 66 result.error = ERROR_MSG_ALREADY_NAVIGATED; | |
| 67 return result; | |
| 68 } | |
| 69 if (!value) { | |
| 70 LOG('Partition.fromAttribute got empty value'); | |
| 71 value = ''; | |
| 72 } | |
| 73 | |
| 74 var LEN = 'persist:'.length; | |
| 75 if (value.substr(0, LEN) == 'persist:') { | |
| 76 value = value.substr(LEN); | |
| 77 if (!value) { | |
| 78 this.validPartitionId_ = false; | |
| 79 result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | |
| 80 return result; | |
| 81 } | |
| 82 this.persist_storage_ = true; | |
| 83 } else { | |
| 84 this.persist_storage_ = false; | |
| 85 } | |
| 86 | |
| 87 this.storage_partition_id_ = value; | |
| 88 return result; | |
| 89 }; | |
| 90 | |
| 36 var CreateEvent = function(name) { | 91 var CreateEvent = function(name) { |
| 37 var eventOpts = {supportsListeners: true, supportsFilters: true}; | 92 var eventOpts = {supportsListeners: true, supportsFilters: true}; |
| 38 return new EventBindings.Event(name, undefined, eventOpts); | 93 return new EventBindings.Event(name, undefined, eventOpts); |
| 39 }; | 94 }; |
| 40 | 95 |
| 41 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their | 96 // WEB_VIEW_EVENTS is a map of stable <webview> DOM event names to their |
| 42 // associated extension event descriptor objects. | 97 // associated extension event descriptor objects. |
| 43 // An event listener will be attached to the extension event |evt| specified in | 98 // An event listener will be attached to the extension event |evt| specified in |
| 44 // the descriptor. | 99 // the descriptor. |
| 45 // |fields| specifies the public-facing fields in the DOM event that are | 100 // |fields| specifies the public-facing fields in the DOM event that are |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 166 } | 221 } |
| 167 }; | 222 }; |
| 168 | 223 |
| 169 // Implemented when the experimental API is available. | 224 // Implemented when the experimental API is available. |
| 170 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} | 225 WebViewInternal.maybeRegisterExperimentalAPIs = function(proto) {} |
| 171 | 226 |
| 172 /** | 227 /** |
| 173 * @constructor | 228 * @constructor |
| 174 */ | 229 */ |
| 175 function WebViewInternal(webviewNode) { | 230 function WebViewInternal(webviewNode) { |
| 231 LOG('WebViewInternal.constructor'); | |
| 176 privates(webviewNode).internal = this; | 232 privates(webviewNode).internal = this; |
| 177 this.webviewNode = webviewNode; | 233 this.webviewNode = webviewNode; |
| 178 this.attached = false; | 234 this.attached = false; |
| 235 | |
| 236 this.beforeFirstNavigation_ = true; | |
| 237 this.validPartitionId_ = true; | |
| 238 | |
| 179 this.browserPluginNode = this.createBrowserPluginNode(); | 239 this.browserPluginNode = this.createBrowserPluginNode(); |
| 180 var shadowRoot = this.webviewNode.createShadowRoot(); | 240 var shadowRoot = this.webviewNode.createShadowRoot(); |
| 181 shadowRoot.appendChild(this.browserPluginNode); | 241 shadowRoot.appendChild(this.browserPluginNode); |
| 182 | 242 |
| 183 this.setupWebviewNodeAttributes(); | 243 this.setupWebviewNodeAttributes(); |
| 184 this.setupFocusPropagation(); | 244 this.setupFocusPropagation(); |
| 185 this.setupWebviewNodeProperties(); | 245 this.setupWebviewNodeProperties(); |
| 246 | |
| 247 this.viewInstanceId = IdGenerator.GetNextId(); | |
| 248 | |
| 249 //this.allocateInstanceId(); | |
| 250 this.partition_ = new Partition(); | |
| 251 this.parseAttributes(); | |
| 252 | |
| 186 this.setupWebviewNodeEvents(); | 253 this.setupWebviewNodeEvents(); |
| 187 } | 254 } |
| 188 | 255 |
| 189 /** | 256 /** |
| 190 * @private | 257 * @private |
| 191 */ | 258 */ |
| 192 WebViewInternal.prototype.createBrowserPluginNode = function() { | 259 WebViewInternal.prototype.createBrowserPluginNode = function() { |
| 193 // We create BrowserPlugin as a custom element in order to observe changes | 260 // We create BrowserPlugin as a custom element in order to observe changes |
| 194 // to attributes synchronously. | 261 // to attributes synchronously. |
| 195 var browserPluginNode = new WebViewInternal.BrowserPlugin(); | 262 var browserPluginNode = new WebViewInternal.BrowserPlugin(); |
| 196 privates(browserPluginNode).internal = this; | 263 privates(browserPluginNode).internal = this; |
| 197 | 264 |
| 198 var ALL_ATTRIBUTES = WEB_VIEW_ATTRIBUTES.concat(['src']); | 265 var ALL_ATTRIBUTES = WEB_VIEW_ATTRIBUTES; |
|
Fady Samuel
2014/05/27 14:19:06
No point in having this at all.
lazyboy
2014/05/27 20:43:00
Done.
| |
| 199 $Array.forEach(ALL_ATTRIBUTES, function(attributeName) { | 266 $Array.forEach(ALL_ATTRIBUTES, function(attributeName) { |
| 200 // Only copy attributes that have been assigned values, rather than copying | 267 // Only copy attributes that have been assigned values, rather than copying |
| 201 // a series of undefined attributes to BrowserPlugin. | 268 // a series of undefined attributes to BrowserPlugin. |
| 202 if (this.webviewNode.hasAttribute(attributeName)) { | 269 if (this.webviewNode.hasAttribute(attributeName)) { |
| 203 browserPluginNode.setAttribute( | 270 browserPluginNode.setAttribute( |
| 204 attributeName, this.webviewNode.getAttribute(attributeName)); | 271 attributeName, this.webviewNode.getAttribute(attributeName)); |
| 205 } else if (this.webviewNode[attributeName]){ | 272 } else if (this.webviewNode[attributeName]){ |
| 206 // Reading property using has/getAttribute does not work on | 273 // Reading property using has/getAttribute does not work on |
| 207 // document.DOMContentLoaded event (but works on | 274 // document.DOMContentLoaded event (but works on |
| 208 // window.DOMContentLoaded event). | 275 // window.DOMContentLoaded event). |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 392 Object.defineProperty(this.webviewNode, 'name', { | 459 Object.defineProperty(this.webviewNode, 'name', { |
| 393 get: function() { | 460 get: function() { |
| 394 return self.name; | 461 return self.name; |
| 395 }, | 462 }, |
| 396 set: function(value) { | 463 set: function(value) { |
| 397 self.webviewNode.setAttribute('name', value); | 464 self.webviewNode.setAttribute('name', value); |
| 398 }, | 465 }, |
| 399 enumerable: true | 466 enumerable: true |
| 400 }); | 467 }); |
| 401 | 468 |
| 469 Object.defineProperty(this.webviewNode, 'partition', { | |
| 470 get: function() { | |
| 471 window.console.log('getter.partition'); | |
| 472 var ret = self.partition_.toAttribute(); | |
| 473 window.console.log('returning: ' + ret); | |
| 474 return ret; | |
| 475 }, | |
| 476 set: function(value) { | |
| 477 window.console.log('setter.partition, value: ' + value); | |
| 478 var result = self.partition_.fromAttribute(value, self.hasNavigated()); | |
| 479 if (result.error) { | |
| 480 throw result.error; | |
| 481 } | |
| 482 self.webviewNode.setAttribute('partition', value); | |
| 483 | |
| 484 // TODO(lazyboy): CanRemovePartitionAttribute() when removeAttribute(). | |
| 485 }, | |
| 486 enumerable: true | |
| 487 }); | |
| 488 | |
| 402 // We cannot use {writable: true} property descriptor because we want a | 489 // We cannot use {writable: true} property descriptor because we want a |
| 403 // dynamic getter value. | 490 // dynamic getter value. |
| 404 Object.defineProperty(this.webviewNode, 'contentWindow', { | 491 Object.defineProperty(this.webviewNode, 'contentWindow', { |
| 405 get: function() { | 492 get: function() { |
| 406 if (browserPluginNode.contentWindow) | 493 if (browserPluginNode.contentWindow) |
| 407 return browserPluginNode.contentWindow; | 494 return browserPluginNode.contentWindow; |
| 408 window.console.error(ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); | 495 window.console.error(ERROR_MSG_CONTENTWINDOW_NOT_AVAILABLE); |
| 409 }, | 496 }, |
| 410 // No setter. | 497 // No setter. |
| 411 enumerable: true | 498 enumerable: true |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 422 /** | 509 /** |
| 423 * @private | 510 * @private |
| 424 */ | 511 */ |
| 425 WebViewInternal.prototype.setupWebViewSrcAttributeMutationObserver = | 512 WebViewInternal.prototype.setupWebViewSrcAttributeMutationObserver = |
| 426 function() { | 513 function() { |
| 427 // The purpose of this mutation observer is to catch assignment to the src | 514 // The purpose of this mutation observer is to catch assignment to the src |
| 428 // attribute without any changes to its value. This is useful in the case | 515 // attribute without any changes to its value. This is useful in the case |
| 429 // where the webview guest has crashed and navigating to the same address | 516 // where the webview guest has crashed and navigating to the same address |
| 430 // spawns off a new process. | 517 // spawns off a new process. |
| 431 var self = this; | 518 var self = this; |
| 432 this.srcObserver = new MutationObserver(function(mutations) { | 519 this.srcAndPartitionObserver = new MutationObserver(function(mutations) { |
| 433 $Array.forEach(mutations, function(mutation) { | 520 $Array.forEach(mutations, function(mutation) { |
| 434 var oldValue = mutation.oldValue; | 521 var oldValue = mutation.oldValue; |
| 435 var newValue = self.webviewNode.getAttribute(mutation.attributeName); | 522 var newValue = self.webviewNode.getAttribute(mutation.attributeName); |
| 436 if (oldValue != newValue) { | 523 if (oldValue != newValue) { |
| 437 return; | 524 return; |
| 438 } | 525 } |
| 439 self.handleWebviewAttributeMutation( | 526 self.handleWebviewAttributeMutation( |
| 440 mutation.attributeName, oldValue, newValue); | 527 mutation.attributeName, oldValue, newValue); |
| 441 }); | 528 }); |
| 442 }); | 529 }); |
| 443 var params = { | 530 var params = { |
| 444 attributes: true, | 531 attributes: true, |
| 445 attributeOldValue: true, | 532 attributeOldValue: true, |
| 446 attributeFilter: ['src'] | 533 attributeFilter: ['src', 'partition'] |
| 447 }; | 534 }; |
| 448 this.srcObserver.observe(this.webviewNode, params); | 535 this.srcAndPartitionObserver.observe(this.webviewNode, params); |
| 449 }; | 536 }; |
| 450 | 537 |
| 451 /** | 538 /** |
| 452 * @private | 539 * @private |
| 453 */ | 540 */ |
| 454 WebViewInternal.prototype.handleWebviewAttributeMutation = | 541 WebViewInternal.prototype.handleWebviewAttributeMutation = |
| 455 function(name, oldValue, newValue) { | 542 function(name, oldValue, newValue) { |
| 543 window.console.log('handleWebviewAttributeMutation, name = ' + name); | |
| 456 // This observer monitors mutations to attributes of the <webview> and | 544 // This observer monitors mutations to attributes of the <webview> and |
| 457 // updates the BrowserPlugin properties accordingly. In turn, updating | 545 // updates the BrowserPlugin properties accordingly. In turn, updating |
| 458 // a BrowserPlugin property will update the corresponding BrowserPlugin | 546 // a BrowserPlugin property will update the corresponding BrowserPlugin |
| 459 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more | 547 // attribute, if necessary. See BrowserPlugin::UpdateDOMAttribute for more |
| 460 // details. | 548 // details. |
| 461 if (name == 'name') { | 549 if (name == 'name') { |
| 462 // We treat null attribute (attribute removed) and the empty string as | 550 // We treat null attribute (attribute removed) and the empty string as |
| 463 // one case. | 551 // one case. |
| 464 oldValue = oldValue || ''; | 552 oldValue = oldValue || ''; |
| 465 newValue = newValue || ''; | 553 newValue = newValue || ''; |
| 466 | 554 |
| 467 if (oldValue === newValue) { | 555 if (oldValue === newValue) { |
| 468 return; | 556 return; |
| 469 } | 557 } |
| 470 this.name = newValue; | 558 this.name = newValue; |
| 471 if (!this.instanceId) { | 559 if (!this.instanceId) { |
| 472 return; | 560 return; |
| 473 } | 561 } |
| 474 WebView.setName(this.instanceId, newValue); | 562 WebView.setName(this.instanceId, newValue); |
| 475 return; | 563 return; |
| 476 } else if (name == 'src') { | 564 } else if (name == 'src') { |
| 477 // We treat null attribute (attribute removed) and the empty string as | 565 // We treat null attribute (attribute removed) and the empty string as |
| 478 // one case. | 566 // one case. |
| 479 oldValue = oldValue || ''; | 567 oldValue = oldValue || ''; |
| 480 newValue = newValue || ''; | 568 newValue = newValue || ''; |
| 569 LOG('WebViewInternal.handleWebviewAttributeMutation, old = ' + oldValue + ', new = ' + newValue); | |
| 481 // Once we have navigated, we don't allow clearing the src attribute. | 570 // Once we have navigated, we don't allow clearing the src attribute. |
| 482 // Once <webview> enters a navigated state, it cannot be return back to a | 571 // Once <webview> enters a navigated state, it cannot be return back to a |
| 483 // placeholder state. | 572 // placeholder state. |
| 484 if (newValue == '' && oldValue != '') { | 573 if (newValue == '' && oldValue != '') { |
| 485 // src attribute changes normally initiate a navigation. We suppress | 574 // src attribute changes normally initiate a navigation. We suppress |
| 486 // the next src attribute handler call to avoid reloading the page | 575 // the next src attribute handler call to avoid reloading the page |
| 487 // on every guest-initiated navigation. | 576 // on every guest-initiated navigation. |
| 488 this.ignoreNextSrcAttributeChange = true; | 577 this.ignoreNextSrcAttributeChange = true; |
| 489 this.webviewNode.setAttribute('src', oldValue); | 578 this.webviewNode.setAttribute('src', oldValue); |
| 490 return; | 579 return; |
| 491 } | 580 } |
| 492 this.src = newValue; | 581 this.src = newValue; |
| 493 if (this.ignoreNextSrcAttributeChange) { | 582 if (this.ignoreNextSrcAttributeChange) { |
| 494 // Don't allow the src mutation observer to see this change. | 583 // Don't allow the src mutation observer to see this change. |
| 495 this.srcObserver.takeRecords(); | 584 this.srcAndPartitionObserver.takeRecords(); |
| 496 this.ignoreNextSrcAttributeChange = false; | 585 this.ignoreNextSrcAttributeChange = false; |
| 497 return; | 586 return; |
| 498 } | 587 } |
| 588 LOG('srcAttributeChanged'); | |
| 589 var result = {}; | |
| 590 this.parseSrcAttribute(result); | |
| 591 | |
| 592 if (result.error) { | |
| 593 throw result.error; | |
| 594 } | |
| 595 } else if (name == 'partition') { | |
| 596 LOG('handleWebviewAttributeMutation.partition'); | |
| 597 LOG('newValue: ' + newValue + ', oldValue: ' + oldValue); | |
| 598 // TODO(lazyboy): Do we do extra work here if we get here from | |
| 599 // Object.set.partition? | |
| 600 this.partition_.fromAttribute(newValue, this.hasNavigated()); | |
| 499 } | 601 } |
| 500 if (this.browserPluginNode.hasOwnProperty(name)) { | 602 |
| 501 this.browserPluginNode[name] = newValue; | 603 // No <webview> -> <object> mutation propagation for these attributes. |
| 502 } else { | 604 if (name != 'src' && name != 'partition') { |
| 503 this.browserPluginNode.setAttribute(name, newValue); | 605 if (this.browserPluginNode.hasOwnProperty(name)) { |
| 606 this.browserPluginNode[name] = newValue; | |
| 607 } else { | |
| 608 this.browserPluginNode.setAttribute(name, newValue); | |
| 609 } | |
| 504 } | 610 } |
| 505 }; | 611 }; |
| 506 | 612 |
| 507 /** | 613 /** |
| 508 * @private | 614 * @private |
| 509 */ | 615 */ |
| 510 WebViewInternal.prototype.handleBrowserPluginAttributeMutation = | 616 WebViewInternal.prototype.handleBrowserPluginAttributeMutation = |
| 511 function(name, newValue) { | 617 function(name, newValue) { |
| 618 if (name == 'src') { | |
| 619 // name == 'src' here implies autoNavigate = true; | |
| 620 this.autoNavigate_ = true; | |
| 621 this.partition_.fromAttribute('persist:custom_plugin', this.hasNavigated()); | |
| 622 } | |
| 623 | |
| 512 // This observer monitors mutations to attributes of the BrowserPlugin and | 624 // This observer monitors mutations to attributes of the BrowserPlugin and |
| 513 // updates the <webview> attributes accordingly. | 625 // updates the <webview> attributes accordingly. |
| 514 // |newValue| is null if the attribute |name| has been removed. | 626 // |newValue| is null if the attribute |name| has been removed. |
| 515 if (newValue != null) { | 627 if (newValue != null) { |
| 516 // Update the <webview> attribute to match the BrowserPlugin attribute. | 628 // Update the <webview> attribute to match the BrowserPlugin attribute. |
| 517 // Note: Calling setAttribute on <webview> will trigger its mutation | 629 // Note: Calling setAttribute on <webview> will trigger its mutation |
| 518 // observer which will then propagate that attribute to BrowserPlugin. In | 630 // observer which will then propagate that attribute to BrowserPlugin. In |
| 519 // cases where we permit assigning a BrowserPlugin attribute the same value | 631 // cases where we permit assigning a BrowserPlugin attribute the same value |
| 520 // again (such as navigation when crashed), this could end up in an infinite | 632 // again (such as navigation when crashed), this could end up in an infinite |
| 521 // loop. Thus, we avoid this loop by only updating the <webview> attribute | 633 // loop. Thus, we avoid this loop by only updating the <webview> attribute |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 if (webViewEvent.newWidth >= minWidth && | 702 if (webViewEvent.newWidth >= minWidth && |
| 591 webViewEvent.newWidth <= maxWidth && | 703 webViewEvent.newWidth <= maxWidth && |
| 592 webViewEvent.newHeight >= minHeight && | 704 webViewEvent.newHeight >= minHeight && |
| 593 webViewEvent.newHeight <= maxHeight) { | 705 webViewEvent.newHeight <= maxHeight) { |
| 594 node.style.width = webViewEvent.newWidth + 'px'; | 706 node.style.width = webViewEvent.newWidth + 'px'; |
| 595 node.style.height = webViewEvent.newHeight + 'px'; | 707 node.style.height = webViewEvent.newHeight + 'px'; |
| 596 } | 708 } |
| 597 node.dispatchEvent(webViewEvent); | 709 node.dispatchEvent(webViewEvent); |
| 598 }; | 710 }; |
| 599 | 711 |
| 712 WebViewInternal.prototype.hasNavigated = function() { | |
| 713 return !this.beforeFirstNavigation_; | |
| 714 }; | |
| 715 | |
| 716 /** @return {boolean} */ | |
| 717 WebViewInternal.prototype.parseSrcAttribute = function(result) { | |
| 718 LOG('parseSrcAttribute'); | |
| 719 if (!this.partition_.validPartitionId_) { | |
| 720 LOG('ERROR_MSG_INVALID_PARTITION_ATTRIBUTE'); | |
| 721 result.error = ERROR_MSG_INVALID_PARTITION_ATTRIBUTE; | |
| 722 return false; | |
| 723 } | |
| 724 | |
| 725 this.src = this.webviewNode.getAttribute('src'); | |
| 726 LOG('parseSrcAttribute, srcAttribute: ' + this.src); | |
| 727 | |
| 728 if (!this.src) { | |
| 729 LOG('src empty'); | |
| 730 return true; | |
| 731 } | |
| 732 | |
| 733 LOG('hasGuestInstanceID: ' + this.hasGuestInstanceID()); | |
| 734 LOG('beforeFirstNavigation_: ' + this.beforeFirstNavigation_); | |
| 735 if (!this.hasGuestInstanceID()) { | |
| 736 if (this.beforeFirstNavigation_) { | |
| 737 this.beforeFirstNavigation_ = false; | |
| 738 this.allocateInstanceId(); | |
| 739 } | |
| 740 return true; | |
| 741 } | |
| 742 | |
| 743 LOG('Webview.navigate, i: ' + this.instanceId + ', src = ' + this.src); | |
| 744 | |
| 745 // Navigate to this.src. | |
| 746 WebView.navigate(this.instanceId, this.src); | |
| 747 return true; | |
| 748 }; | |
| 749 | |
| 750 /** @return {boolean} */ | |
| 751 WebViewInternal.prototype.parseAttributes = function() { | |
| 752 LOG('parseAttributes'); | |
| 753 var hasNavigated = this.hasNavigated(); | |
| 754 | |
| 755 var attributeValue = this.webviewNode.getAttribute('partition'); | |
| 756 LOG('parseAttributes, partition.ttributeValue: ' + attributeValue); | |
| 757 var result = this.partition_.fromAttribute(attributeValue, hasNavigated); | |
| 758 return this.parseSrcAttribute(result); | |
| 759 }; | |
| 760 | |
| 761 WebViewInternal.prototype.hasGuestInstanceID = function() { | |
| 762 return this.instanceId != undefined; | |
| 763 }; | |
| 764 | |
| 765 WebViewInternal.prototype.allocateInstanceId = function() { | |
| 766 LOG('allocateInstanceId'); | |
| 767 //this.viewInstanceId = IdGenerator.GetNextId(); | |
| 768 LOG('cur partition: ' + this.webviewNode.getAttribute('partition')); | |
| 769 LOG('cur partition prop: ' + this.webviewNode['partition']); | |
| 770 | |
| 771 // Parse .src and .partition. | |
| 772 | |
| 773 var self = this; | |
| 774 WebView.allocateInstanceId( | |
|
Fady Samuel
2014/05/27 14:19:06
Let's make it GuestView.allocateInstanceId
lazyboy
2014/05/27 20:43:00
Done.
| |
| 775 'webview', | |
| 776 this.viewInstanceId, | |
| 777 function(info) { | |
| 778 LOG('allocateInstanceId.callback.info: ' + info); | |
| 779 self.instanceId = info; | |
| 780 // TODO(lazyboy): Make sure this.autoNavigate_ stuff correctly updated | |
| 781 // |self.src| at this point. | |
| 782 self.attachWindowAndSetUpEvents(self.instanceId, self.src); | |
| 783 }); | |
| 784 }; | |
| 785 | |
| 600 /** | 786 /** |
| 601 * @private | 787 * @private |
| 602 */ | 788 */ |
| 603 WebViewInternal.prototype.setupWebviewNodeEvents = function() { | 789 WebViewInternal.prototype.setupWebviewNodeEvents = function() { |
| 604 var self = this; | |
| 605 this.viewInstanceId = IdGenerator.GetNextId(); | |
| 606 var onInstanceIdAllocated = function(e) { | |
| 607 var detail = e.detail ? JSON.parse(e.detail) : {}; | |
| 608 self.attachWindowAndSetUpEvents(detail.windowId); | |
| 609 }; | |
| 610 this.browserPluginNode.addEventListener('-internal-instanceid-allocated', | |
| 611 onInstanceIdAllocated); | |
| 612 this.setupWebRequestEvents(); | 790 this.setupWebRequestEvents(); |
| 613 this.setupExperimentalContextMenus_(); | 791 this.setupExperimentalContextMenus_(); |
| 614 | 792 |
| 615 this.on = {}; | 793 this.on = {}; |
| 616 var events = self.getEvents(); | 794 var events = this.getEvents(); |
| 617 for (var eventName in events) { | 795 for (var eventName in events) { |
| 618 this.setupEventProperty(eventName); | 796 this.setupEventProperty(eventName); |
| 619 } | 797 } |
| 620 }; | 798 }; |
| 621 | 799 |
| 622 /** | 800 /** |
| 623 * @private | 801 * @private |
| 624 */ | 802 */ |
| 625 WebViewInternal.prototype.setupNameAttribute = function() { | 803 WebViewInternal.prototype.setupNameAttribute = function() { |
| 626 var self = this; | 804 var self = this; |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 841 validateCall(); | 1019 validateCall(); |
| 842 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') | 1020 if (!webview || !webview.tagName || webview.tagName != 'WEBVIEW') |
| 843 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); | 1021 throw new Error(ERROR_MSG_WEBVIEW_EXPECTED); |
| 844 // Attach happens asynchronously to give the tagWatcher an opportunity | 1022 // Attach happens asynchronously to give the tagWatcher an opportunity |
| 845 // to pick up the new webview before attach operates on it, if it hasn't | 1023 // to pick up the new webview before attach operates on it, if it hasn't |
| 846 // been attached to the DOM already. | 1024 // been attached to the DOM already. |
| 847 // Note: Any subsequent errors cannot be exceptions because they happen | 1025 // Note: Any subsequent errors cannot be exceptions because they happen |
| 848 // asynchronously. | 1026 // asynchronously. |
| 849 setTimeout(function() { | 1027 setTimeout(function() { |
| 850 var webViewInternal = privates(webview).internal; | 1028 var webViewInternal = privates(webview).internal; |
| 1029 LOG('=== Attach w/o a src'); | |
| 1030 | |
| 1031 if (event.storagePartitionId) { | |
| 1032 LOG('read partition string: ' + event.storagePartitionId); | |
| 1033 webViewInternal.webviewNode.setAttribute( | |
| 1034 'partition', event.storagePartitionId); | |
| 1035 var partition = new Partition(); | |
| 1036 partition.fromAttribute(event.storagePartitionId, | |
| 1037 webViewInternal.hasNavigated()); | |
| 1038 webViewInternal.partition_ = partition; | |
| 1039 } | |
| 1040 | |
| 851 var attached = | 1041 var attached = |
| 852 webViewInternal.attachWindowAndSetUpEvents(event.windowId); | 1042 webViewInternal.attachWindowAndSetUpEvents( |
| 1043 event.windowId, undefined, event.storagePartitionId); | |
| 853 | 1044 |
| 854 if (!attached) { | 1045 if (!attached) { |
| 855 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); | 1046 window.console.error(ERROR_MSG_NEWWINDOW_UNABLE_TO_ATTACH); |
| 856 } | 1047 } |
| 857 // If the object being passed into attach is not a valid <webview> | 1048 // If the object being passed into attach is not a valid <webview> |
| 858 // then we will fail and it will be treated as if the new window | 1049 // then we will fail and it will be treated as if the new window |
| 859 // was rejected. The permission API plumbing is used here to clean | 1050 // was rejected. The permission API plumbing is used here to clean |
| 860 // up the state created for the new window if attaching fails. | 1051 // up the state created for the new window if attaching fails. |
| 861 WebView.setPermission( | 1052 WebView.setPermission( |
| 862 self.instanceId, requestId, attached ? 'allow' : 'deny'); | 1053 self.instanceId, requestId, attached ? 'allow' : 'deny'); |
| (...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1055 this.userAgentOverride = userAgentOverride; | 1246 this.userAgentOverride = userAgentOverride; |
| 1056 if (!this.instanceId) { | 1247 if (!this.instanceId) { |
| 1057 // If we are not attached yet, then we will pick up the user agent on | 1248 // If we are not attached yet, then we will pick up the user agent on |
| 1058 // attachment. | 1249 // attachment. |
| 1059 return; | 1250 return; |
| 1060 } | 1251 } |
| 1061 WebView.overrideUserAgent(this.instanceId, userAgentOverride); | 1252 WebView.overrideUserAgent(this.instanceId, userAgentOverride); |
| 1062 }; | 1253 }; |
| 1063 | 1254 |
| 1064 /** @private */ | 1255 /** @private */ |
| 1065 WebViewInternal.prototype.attachWindowAndSetUpEvents = function(instanceId) { | 1256 WebViewInternal.prototype.attachWindowAndSetUpEvents = function( |
| 1257 instanceId, opt_src, opt_partitionId) { | |
| 1066 this.instanceId = instanceId; | 1258 this.instanceId = instanceId; |
| 1067 var params = { | 1259 var params = { |
| 1068 'api': 'webview', | 1260 'api': 'webview', |
| 1069 'instanceId': this.viewInstanceId, | 1261 'instanceId': this.viewInstanceId, |
| 1070 'name': this.name | 1262 'name': this.name |
| 1071 }; | 1263 }; |
| 1264 if (!!opt_src) { | |
| 1265 params.src = opt_src; | |
|
Fady Samuel
2014/05/27 14:19:06
For consistency, ca we simply make this and userAg
lazyboy
2014/05/27 20:43:00
There's a bit of difference between this and what
| |
| 1266 } | |
| 1072 if (this.userAgentOverride) { | 1267 if (this.userAgentOverride) { |
| 1073 params['userAgentOverride'] = this.userAgentOverride; | 1268 params['userAgentOverride'] = this.userAgentOverride; |
| 1074 } | 1269 } |
| 1270 | |
| 1271 // If we have a partition from the opener, use that instead. | |
| 1272 if (!!opt_partitionId) { | |
| 1273 LOG("******* use from opener *****"); | |
| 1274 params['storagePartitionId'] = opt_partitionId; | |
| 1275 } else { | |
| 1276 LOG('starting to get partitionAttr'); | |
| 1277 // TODO(lazyboy): Tidy this up. | |
| 1278 var partitionAttr = this.webviewNode.getAttribute('partition') || | |
| 1279 this.webviewNode['partition']; | |
| 1280 LOG('partitionAttr: ' + partitionAttr); | |
| 1281 params['storagePartitionId'] = partitionAttr; | |
| 1282 } | |
| 1075 this.setupNameAttribute(); | 1283 this.setupNameAttribute(); |
| 1076 var events = this.getEvents(); | 1284 var events = this.getEvents(); |
| 1077 for (var eventName in events) { | 1285 for (var eventName in events) { |
| 1078 this.setupEvent(eventName, events[eventName]); | 1286 this.setupEvent(eventName, events[eventName]); |
| 1079 } | 1287 } |
| 1080 | 1288 |
| 1081 this.browserPluginNode['-internal-attach'](this.instanceId, params); | 1289 this.browserPluginNode['-internal-attach'](this.instanceId, params); |
| 1082 | 1290 |
| 1083 return true; | 1291 return true; |
| 1084 }; | 1292 }; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1118 } | 1326 } |
| 1119 | 1327 |
| 1120 // Registers <webview> custom element. | 1328 // Registers <webview> custom element. |
| 1121 function registerWebViewElement() { | 1329 function registerWebViewElement() { |
| 1122 var proto = Object.create(HTMLElement.prototype); | 1330 var proto = Object.create(HTMLElement.prototype); |
| 1123 | 1331 |
| 1124 proto.createdCallback = function() { | 1332 proto.createdCallback = function() { |
| 1125 new WebViewInternal(this); | 1333 new WebViewInternal(this); |
| 1126 }; | 1334 }; |
| 1127 | 1335 |
| 1336 proto.customElementDetached = false; | |
|
Fady Samuel
2014/05/27 14:19:06
What is the purpose of this flag? Debugging? Can w
lazyboy
2014/05/27 20:43:00
This is for detecting an attach after detach.
| |
| 1337 | |
| 1128 proto.attributeChangedCallback = function(name, oldValue, newValue) { | 1338 proto.attributeChangedCallback = function(name, oldValue, newValue) { |
| 1129 var internal = privates(this).internal; | 1339 var internal = privates(this).internal; |
| 1130 if (!internal) { | 1340 if (!internal) { |
| 1131 return; | 1341 return; |
| 1132 } | 1342 } |
| 1133 internal.handleWebviewAttributeMutation(name, oldValue, newValue); | 1343 internal.handleWebviewAttributeMutation(name, oldValue, newValue); |
| 1134 }; | 1344 }; |
| 1135 | 1345 |
| 1346 proto.detachedCallback = function() { | |
| 1347 LOG('<webview> got detached'); | |
| 1348 LOG('this.customElementDetached was: ' + this.customElementDetached); | |
|
Fady Samuel
2014/05/27 14:19:06
Let's remove all the listeners here.
lazyboy
2014/05/27 20:43:00
I need this to allocate new instanceId on attachin
| |
| 1349 this.customElementDetached = true; | |
| 1350 }; | |
| 1351 proto.attachedCallback = function() { | |
| 1352 LOG('attached, for the first time or subsequent, must init later'); | |
| 1353 LOG('this.customElementDetached was: ' + this.customElementDetached); | |
| 1354 if (this.customElementDetached) { | |
| 1355 var otherThis = privates(this).internal; | |
| 1356 LOG('allocateInstanceId again'); | |
| 1357 otherThis.instanceId = undefined; | |
| 1358 otherThis.beforeFirstNavigation_ = true; | |
| 1359 otherThis.validPartitionId_ = true; | |
| 1360 otherThis.partition_.validPartitionId_ = true; | |
| 1361 | |
| 1362 otherThis.allocateInstanceId(); | |
| 1363 } | |
| 1364 this.customElementDetached = false; | |
| 1365 }; | |
| 1366 | |
| 1136 proto.back = function() { | 1367 proto.back = function() { |
| 1137 this.go(-1); | 1368 this.go(-1); |
| 1138 }; | 1369 }; |
| 1139 | 1370 |
| 1140 proto.forward = function() { | 1371 proto.forward = function() { |
| 1141 this.go(1); | 1372 this.go(1); |
| 1142 }; | 1373 }; |
| 1143 | 1374 |
| 1144 proto.canGoBack = function() { | 1375 proto.canGoBack = function() { |
| 1145 return privates(this).internal.canGoBack(); | 1376 return privates(this).internal.canGoBack(); |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1255 | 1486 |
| 1256 /** | 1487 /** |
| 1257 * Implemented when the experimental API is available. | 1488 * Implemented when the experimental API is available. |
| 1258 * @private | 1489 * @private |
| 1259 */ | 1490 */ |
| 1260 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; | 1491 WebViewInternal.prototype.setupExperimentalContextMenus_ = function() {}; |
| 1261 | 1492 |
| 1262 exports.WebView = WebView; | 1493 exports.WebView = WebView; |
| 1263 exports.WebViewInternal = WebViewInternal; | 1494 exports.WebViewInternal = WebViewInternal; |
| 1264 exports.CreateEvent = CreateEvent; | 1495 exports.CreateEvent = CreateEvent; |
| OLD | NEW |